NES CLIENT 命令行使用及开发步骤

一 nes client 命令

1 启停命令

  1. connect

    • 功能:连接 UPGW 服务端口

    connect [ip_address] [port]
    # 当没有参数时,默认连接
    # [ip_address] - 要连接的 UPGW 的 server ip 地址
    # [port]       - server 端口
    
  2. quit

    • 功能:退出命令行

    quit
    
  3. help

    • 功能:帮助用户快速查看可用命令有哪些。

    help
    

2 接口命令

  1. KNI devices

    • 功能:KNI 设备相关操作

    # 添加 KNI 设备
    kni add [kni_dev_name]
    
    # 删除 KNI 设备
    kni del [kni_dev_name]
    
  2. device state

    • 功能:接口相关操作

    # 查看所有接口及其收发包信息
    show all
    
    # 查看接口列表
    show list
    
    # 查看某一接口收发包信息
    show [device_id]
    # [device_id] - dpdk 定义的接口 ID ,可通过 show all 第一列看到
    
    # 查看接口 mac 地址
    show mac [device_id]
    
    # 清除接口收发包计数
    clear all
    
  3. Bypass

    • 功能:bypass 网卡相关操作 (待补充)

    # 
    bypass 
    

3 ring 命令

  1. ring stats

    • 功能:查看 ring 相关信息

    # 列出所有 ring 收发包个数
    show rings
    
    # 查看某一个 ring 的收发包个数
    show ring [ring_id]
    # [ring_id] - ring 列表的 ID 值,可通过 show rings 查到
    

4 转发命令

  1. clear

    • 功能:清理 ring 环数据包

    clear all
    
  2. 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
    
  3. 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
    
  4. 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]          -  
    
  5. 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 命令行开发步骤

  1. 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;
    
  2. 依据 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);
      
  3. 定义 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 。

  4. 编写回调函数,通过 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