NES CLIENT 命令行使用及开发步骤
一 nes client 命令
1 启停命令
connect
功能:连接 UPGW 服务端口
connect [ip_address] [port] # 当没有参数时,默认连接 # [ip_address] - 要连接的 UPGW 的 server ip 地址 # [port] - server 端口
quit
功能:退出命令行
quit
help
功能:帮助用户快速查看可用命令有哪些。
help
2 接口命令
KNI devices
功能:KNI 设备相关操作
# 添加 KNI 设备 kni add [kni_dev_name] # 删除 KNI 设备 kni del [kni_dev_name]
device state
功能:接口相关操作
# 查看所有接口及其收发包信息 show all # 查看接口列表 show list # 查看某一接口收发包信息 show [device_id] # [device_id] - dpdk 定义的接口 ID ,可通过 show all 第一列看到 # 查看接口 mac 地址 show mac [device_id] # 清除接口收发包计数 clear all
Bypass
功能:bypass 网卡相关操作 (待补充)
# bypass
3 ring 命令
ring stats
功能:查看 ring 相关信息
# 列出所有 ring 收发包个数 show rings # 查看某一个 ring 的收发包个数 show ring [ring_id] # [ring_id] - ring 列表的 ID 值,可通过 show rings 查到
4 转发命令
clear
功能:清理 ring 环数据包
clear all
route
功能:对 NTS 转发规则的操作
# 列出分流表的所有内容 route list # 查看某一条分流规则的具体内容 route show [uuid] # [uuid] - 分流表中的唯一 ID 值 # 添加分流规则 route add [mac_addr] [route_rule_uuid] [lookup fields] # [mac_addr] - mac 地址 # [route_rule_uuid] - 分流表唯一标识 ID # [lookup fields] - 分流规则域,格式是“域名:域值”,多个域间用逗号分隔。可用的域有:[encap_proto] [ue_ip] [src_ip] [enb_ip] [epc_ip] [ue_port] [srv_port] [teid] [qci] [spid] ## lookup fields [encap_proto] - 协议类型,参数为 gtpu 或者 noencap ,分别表示 gtp 或 ip 协议 ## lookup fields [ue_ip] - 针对 ue 的 ip 做分流(需要加上子网掩码标识) ## lookup fields [src_ip] - 数据包中的源 ip (需要加上子网掩码标识) ## lookup fields [enb_ip] - 基站 ip (需要加上子网掩码标识) ## lookup fields [epc_ip] - EPC ip(需要加上子网掩码标识) ## lookup fields [ue_port] - ## lookup fields [srv_port] - ## lookup fields [teid] - 隧道 ID ## lookup fields [qci] - ## lookup fields [spid] - # 删除分流规则 route del [uuid] # [uuid] - 分流表中的唯一 ID 值 # 刷新分流表 route flush
QCI / SPID data (暂无实现)
功能:对 NIS 转发规则的操作
# 查看分流信息 route-data show [eNB IP] [teid] [direction] # [eNB IP] - # [teid] - 隧道 ID # [direction] - N3 接口或 N6 接口,取值为 upstream/downstream # 添加分流规则,由 teid-eNBip-direction 组成 key 标识不同的 qci 和 spid route-data add [teid] [eNB IP] [direction] [qci] [spid] # [teid] - 隧道 ID # [eNB IP] - # [direction] - N3 接口或 N6 接口,取值为 upstream/downstream # [qci] - 质量等级指标 # [spid] - 用户标识 # 删除分流规则 route-data del [eNB IP] [teid] [direction] # [eNB IP] - # [teid] - 用户面隧道 ID # [direction] - N3 接口或 N6 接口,取值为 upstream/downstream
flow (暂无实现)
功能:对 NIS ACL 规则的操作
# 查看 ACL 规则 flow show [protocol] [src_ip] [mask] [dst_ip] [mask] [src_port_min] [src_por_max] [dst_port_min] [dst_port_max] [tos] [mask] # [protocol] - 协议 # [src_ip] - # [mask] - # [dst_ip] - # [mask] - # [src_port_min] - 源端口范围起始值 # [src_port_max] - 源端口范围最大值 # [dst_port_min] - 目的端口范围起始值 # [dst_port_max] - 目的端口范围最大值 # 添加 ACL 规则 flow add [teid] [sid] [qci] [protocol] [src_ip] [mask] [dst_ip] [mask] [src_port_min] [src_por_max] [dst_port_min] [dst_port_max] [tos] [mask] # [teid] - 用户面隧道 ID # [sid] - # [qci] - # [protocol] - 协议 # [src_ip] - # [mask] - # [dst_ip] - # [mask] - # [src_port_min] - 源端口范围起始值 # [src_port_max] - 源端口范围最大值 # [dst_port_min] - 目的端口范围起始值 # [dst_port_max] - 目的端口范围最大值 # [tos] - # [mask] - # 删除 ACL 规则 flow del [protocol] [src_ip] [mask] [dst_ip] [mask] [src_port_min] [src_por_max] [dst_port_min] [dst_port_max] [tos] [mask] # [protocol] - 协议 # [src_ip] - # [mask] - # [dst_ip] - # [mask] - # [src_port_min] - 源端口范围起始值 # [src_port_max] - 源端口范围最大值 # [dst_port_min] - 目的端口范围起始值 # [dst_port_max] - 目的端口范围最大值 # [tos] - # [mask] -
dns
功能:DNS 相关操作
# 查看 DNS 规则 dns list # 查看某一个 DNS 规则 dns show [uuid] # [uuid] - DNS 规则中的唯一 ID 值 # 添加 DNS 规则 dns add [uuid] [dns_rule] # [uuid] # [dns_rule] - dns 规则 # 删除 DNS 规则 dns del [uuid] # [uuid] - DNS 规则中的唯一 ID 值
二 cmdline 命令行开发步骤
main_ctx 数组中存放了所有命令的指针,新增命令需在此添加指针:
/* file: nes_cli.c */ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *) & cmd_ctrl_help, (cmdline_parse_inst_t *) & cmd_conn_init, (cmdline_parse_inst_t *) & cmd_conn_default_init, (cmdline_parse_inst_t *) & cmd_quit, (cmdline_parse_inst_t *) & cmd_ctrl_show_stats, (cmdline_parse_inst_t *) & cmd_ctrl_show_all, (cmdline_parse_inst_t *) & cmd_ctrl_show_list, (cmdline_parse_inst_t *) & cmd_ctrl_show_ring, (cmdline_parse_inst_t *) & cmd_ctrl_show_rings, (cmdline_parse_inst_t *) & cmd_ctrl_route_data_add, (cmdline_parse_inst_t *) & cmd_ctrl_route_data_del, (cmdline_parse_inst_t *) & cmd_ctrl_route_data_show, (cmdline_parse_inst_t *) & cmd_ctrl_enc_entry_show, (cmdline_parse_inst_t *) & cmd_ctrl_mac_show, (cmdline_parse_inst_t *) & cmd_ctrl_flow_add, (cmdline_parse_inst_t *) & cmd_ctrl_flow_show, (cmdline_parse_inst_t *) & cmd_ctrl_flow_del, (cmdline_parse_inst_t *) & cmd_ctrl_route_add, (cmdline_parse_inst_t *) & cmd_ctrl_route_add_mirror, (cmdline_parse_inst_t *) & cmd_ctrl_route_show, (cmdline_parse_inst_t *) & cmd_ctrl_route_show_all, (cmdline_parse_inst_t *) & cmd_ctrl_route_flush, (cmdline_parse_inst_t *) & cmd_ctrl_route_show_mirror, (cmdline_parse_inst_t *) & cmd_ctrl_route_del, (cmdline_parse_inst_t *) & cmd_ctrl_route_del_mirror, (cmdline_parse_inst_t *) & cmd_ctrl_clear_all, (cmdline_parse_inst_t *) & cmd_ctrl_kni_del, (cmdline_parse_inst_t *) & cmd_ctrl_kni_add, (cmdline_parse_inst_t *) & cmd_ctrl_domain_name_add, (cmdline_parse_inst_t *) & cmd_ctrl_domain_name_show_all, (cmdline_parse_inst_t *) & cmd_ctrl_domain_name_del, (cmdline_parse_inst_t *) & cmd_ctrl_domain_name_show, NULL, };
cmdline_parse_ctx_t 数据类型定义如下:
// 命令行变量数据结构 struct cmdline_inst { /* f(parsed_struct, data) */ void (*f)(void *, struct cmdline *, void *); // 回调函数 void *data; // data 数据指针 const char *help_str; // help 字符串 cmdline_parse_token_hdr_t *tokens[]; // token 类型 }; typedef struct cmdline_inst cmdline_parse_inst_t; typedef cmdline_parse_inst_t *cmdline_parse_ctx_t;
依据 cmdline_inst 定义新命令行数据类型:
例如:
// 定义命令行数据类型 cmdline_parse_inst_t cmd_ctrl_flow_show = { .f = nes_flow_show_parsed, .data = NULL, .help_str = "flow show [protocol] [src_ip] [mask] [dst_ip] [mask] [src_port_min]" \ " [src_por_max] [dst_port_min] [dst_port_max] [tos] [mask]", .tokens = { (void *) &cmd_ctrl_flow_show_string, (void *) &cmd_ctrl_flow_show_show_string, (void *) &cmd_ctrl_flow_show_protocol, (void *) &cmd_ctrl_flow_show_ip_src, (void *) &cmd_ctrl_flow_show_ip_src_mask, (void *) &cmd_ctrl_flow_show_ip_dst, (void *) &cmd_ctrl_flow_show_ip_dst_mask, (void *) &cmd_ctrl_flow_show_port_src, (void *) &cmd_ctrl_flow_show_port_src_max, (void *) &cmd_ctrl_flow_show_port_dst, (void *) &cmd_ctrl_flow_show_port_dst_max, (void *) &cmd_ctrl_flow_show_tos, (void *) &cmd_ctrl_flow_show_tos_mask, NULL, }, }; // 定义 tokens 令牌 cmdline_parse_token_string_t cmd_ctrl_flow_show_string = TOKEN_STRING_INITIALIZER(struct cmd_ctrl_flow_show_result, flow_string, "flow"); cmdline_parse_token_string_t cmd_ctrl_flow_show_show_string = TOKEN_STRING_INITIALIZER(struct cmd_ctrl_flow_show_result, flow_string, "show"); cmdline_parse_token_num_t cmd_ctrl_flow_show_protocol = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, protocol, UINT8); cmdline_parse_token_ipaddr_t cmd_ctrl_flow_show_ip_src = TOKEN_IPADDR_INITIALIZER(struct cmd_ctrl_flow_show_result, ip_addr_src); cmdline_parse_token_num_t cmd_ctrl_flow_show_ip_src_mask = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, ip_addr_src_mask, UINT32); cmdline_parse_token_ipaddr_t cmd_ctrl_flow_show_ip_dst = TOKEN_IPADDR_INITIALIZER(struct cmd_ctrl_flow_show_result, ip_addr_dst); cmdline_parse_token_num_t cmd_ctrl_flow_show_ip_dst_mask = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, ip_addr_dst_mask, UINT32); cmdline_parse_token_num_t cmd_ctrl_flow_show_port_src = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, port_src, UINT16); cmdline_parse_token_num_t cmd_ctrl_flow_show_port_src_max = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, port_src_max, UINT16); cmdline_parse_token_num_t cmd_ctrl_flow_show_port_dst = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, port_dst, UINT16); cmdline_parse_token_num_t cmd_ctrl_flow_show_port_dst_max = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, port_dst_max, UINT16); cmdline_parse_token_num_t cmd_ctrl_flow_show_tos = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, tos, UINT8); cmdline_parse_token_num_t cmd_ctrl_flow_show_tos_mask = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, tos_mask, UINT8);
在 cmdline_parse_inst_t 中 token 令牌有4种类型:
字符串令牌:匹配静态字符串,静态字符串列表或任何字符串。 例:
cmdline_parse_token_string_t cmd_ctrl_flow_show_show_string = TOKEN_STRING_INITIALIZER(struct cmd_ctrl_flow_show_result, flow_string, "show");
数字令牌:匹配一个有符号或无符号数字,从8位到32位。例:
cmdline_parse_token_num_t cmd_ctrl_flow_show_protocol = TOKEN_NUM_INITIALIZER(struct cmd_ctrl_flow_show_result, protocol, UINT8);
IP 地址令牌:匹配 IPv4 或 IPv6 地址或网络。例:
cmdline_parse_token_ipaddr_t cmd_ctrl_flow_show_ip_src = TOKEN_IPADDR_INITIALIZER(struct cmd_ctrl_flow_show_result, ip_addr_src);
以太网地址令牌:匹配 MAC 地址。例:
cmdline_parse_token_etheraddr_t cmd_ctrl_route_add_mac_addr = TOKEN_ETHERADDR_INITIALIZER(struct cmd_ctrl_route_add_result, mac_addr);
定义 result 结构,将需要命令行输入的令牌全部填充到一个结构体中:
例如:
typedef struct cmd_ctrl_flow_show_result { cmdline_fixed_string_t flow_string; cmdline_fixed_string_t show_string; uint8_t protocol; cmdline_ipaddr_t ip_addr_src; uint32_t ip_addr_src_mask; cmdline_ipaddr_t ip_addr_dst; uint32_t ip_addr_dst_mask; uint16_t port_src; uint16_t port_src_max; uint16_t port_dst; uint16_t port_dst_max; uint8_t tos; uint8_t tos_mask; } cmd_ctrl_flow_show_result;
token 令牌中指明匹配了 result 结构体中的哪个成员变量,及具体的参数(如字符串 “add” ),所以当命令行输入相应类型的字节流,就会找到 cmdline_parse_inst_t 命令行结构,并执行其中的回调函数 f 。
编写回调函数,通过 socket 方式发送命令给服务端:
例:
static void nes_flow_show_parsed(void *parsed_result, __attribute__((unused)) struct cmdline *nes_cmdline, __attribute__((unused)) void *data) // parsed_result 即输入 { struct cmd_ctrl_flow_show_result *res = parsed_result; flow_param.proto = res->protocol; // 使用 cmd_ctrl_flow_show_result 指针获取输入内容 /* …… */ if(NES_SUCCESS != nes_send_api_msg(&remote_NEV, api_msg, &api_response)) //通过socket发送服务端 { /*……*/ } cmdline_printf(nes_cmdline,"Flow: TEID: %"PRIu32", SPID: %"PRIu8", QCI: %"PRIu8".\n", rab_param_ptr->teid, rab_param_ptr->spid, rab_param_ptr->qci); // 输出到终端 /* …… */ }
Reference
cmdline 分析: https://blog.csdn.net/u011551613/article/details/109050381