利用DPDK,给程序添加命令行代码,添加一个命令由四部分组成:命令行参数的数据结构、调用命令行的功能实现函数、命令行解析和命令行初始化;
(1)命令行数据结构,如下:
struct cmd_obj_add_result {
cmdline_fixed_string_t action; //cmdline_fixed_string_t字符数组类型的别名;
cmdline_fixed_string_t name; //
cmdline_ipaddr_t ip; //
};
static void cmd_obj_add_parsed(void *parsed_result,struct cmdline *cl, __attribute__((unused)) void *data)//参数貌似固定 ????
{
struct cmd_obj_add_result *res = parsed_result; //初始化命令行的结构体;
struct object *o;
char ip_str[INET6_ADDRSTRLEN];
SLIST_FOREACH(o, &global_obj_list, next) { //SLIST_FOREACH什么意思?????????????????
if (!strcmp(res->name, o->name)) {
cmdline_printf(cl, "Object %s already exist\n", res->name);
return;
}
break;
}
o = malloc(sizeof(*o));
if (!o) {
cmdline_printf(cl, "mem error\n");
return;
}
snprintf(o->name, sizeof(o->name), "%s", res->name);
o->ip = res->ip;
SLIST_INSERT_HEAD(&global_obj_list, o, next);
if (o->ip.family == AF_INET)
snprintf(ip_str, sizeof(ip_str), NIPQUAD_FMT,
NIPQUAD(o->ip.addr.ipv4));
else
snprintf(ip_str, sizeof(ip_str), NIP6_FMT,
NIP6(o->ip.addr.ipv6));
cmdline_printf(cl, "Object %s added, ip=%s\n",
o->name, ip_str);
}
(3)对命令行中的每个参数进行校验解析,如下:
cmdline_parse_token_string_t cmd_obj_action_add = //add zxw 10.190.3.19---说明需要三个token
TOKEN_STRING_INITIALIZER(struct cmd_obj_add_result, action, "add");
cmdline_parse_token_string_t cmd_obj_name = //这里需要字符串;
TOKEN_STRING_INITIALIZER(struct cmd_obj_add_result, name, NULL); //所有字符串都可以
cmdline_parse_token_ipaddr_t cmd_obj_ip = //这里需要ip;
TOKEN_IPADDR_INITIALIZER(struct cmd_obj_add_result, ip);
cmdline_parse_inst_t cmd_obj_add = {
.f = cmd_obj_add_parsed, /* function to call */
.data = NULL, /* 2nd arg of func */
.help_str = "Add an object (name, val)",
.tokens = { /* token列表, NULL结束 */
(void *)&cmd_obj_action_add,
(void *)&cmd_obj_name,
(void *)&cmd_obj_ip,
NULL,
},
};
上面都实现完以后,需要将初始化的命令行添加到一个保存命令行的数组中,数组以NULL结束;
cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_obj_add,
NULL,
};
然后在mian( )函数中创建命令行对象,通过控制台和用户交互,具体实现如下:
int main(int argc, char **argv)
{
int ret;
struct cmdline *cl; //命令行对象cl;
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
cl = cmdline_stdin_new(main_ctx, "example> "); //创建一个命令行对象并且通过控制台和用户交互;
//将命令行模块初始化,其中main_ctx是一个结构体指针,在commands.c中;
if (cl == NULL)
rte_panic("Cannot create cmdline instance\n");
cmdline_interact(cl);
cmdline_stdin_exit(cl); //上面这两行,是命令行模块的运行和退出函数;
//当用户键入ctrl - d时,cmd line_interact()函数返回,在本例中是应用程序退出。
return 0;
}
上面是一个简答的命令行,根据需要可以添加自己需要的命令行,我目前给设备添加的部分命令行代码如下(不包含头文件):
extern int fwd_get_port_mac(uint16_t port);
extern int fwd_set_port_mac(uint16_t port, uint32_t hmac, uint32_t lmac);
/*******************************************************************/
struct cmd_help_result {
cmdline_fixed_string_t help;
};
static void cmd_help_parsed(__attribute__((unused)) void *parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
cmdline_printf(cl,
"\n\nDemo example of command line interface in RTE\n"
"This is a readline-like interface that can be used to\n"
"debug your RTE application. It supports some features\n"
"of GNU readline like completion, cut/paste, and some\n"
"other special bindings.\n\n"
"This demo shows how rte_cmdline library can be\n"
"extended to handle a list of objects. There are\n"
"3 commands:\n"
"- fwd_log_level_set level\n"
"- fwd_tbl_set_phy2lport entryId slot_id logical_port nat_flag\n"
"- fwd_set_port_mac port hmac lmac\n"
"- fwd_get_port_mac port\n"
"- fwd_get_shortflow src_phy_port svlan cvlan\n");
}
cmdline_parse_token_string_t cmd_help_help =
TOKEN_STRING_INITIALIZER(struct cmd_help_result, help, "help");
cmdline_parse_inst_t cmd_help = {
.f = cmd_help_parsed, /* function to call */
.data = NULL, /* 2nd arg of func */
.help_str = "show help",
.tokens = { /* token list, NULL terminated */
(void *)&cmd_help_help,
NULL,
},
};
/***************************************************************/
/************************(1)*******************************/
struct cmd_fwd_log_level_set_result //在DPDK_fwd_debug.c中
{
cmdline_fixed_string_t action;
int level;
};
static void cmd_fwd_log_level_set_parased(void*parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_fwd_log_level_set_result * res=parsed_result;
fwd_log_level_set(res->level);
cmdline_printf(cl,"cmd_obj_math_parased() is called!\n");
}
cmdline_parse_token_string_t cmd_fwd_log_level_set_action=
TOKEN_STRING_INITIALIZER(struct cmd_fwd_log_level_set_result, action, "fwd_log_level_set");
cmdline_parse_token_num_t cmd_fwd_log_level_set_level=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_log_level_set_result, level,INT32);
cmdline_parse_inst_t cmd_fwd_log_level_set = {
.f = cmd_fwd_log_level_set_parased, /* function to call */
.data = NULL, /* 2nd arg of func */
.help_str = "cmd_fwd_log_level_set level",
.tokens = { /* token list, NULL terminated */
(void *)&cmd_fwd_log_level_set_action,
(void *)&cmd_fwd_log_level_set_level,
NULL,
},
};
/************************ (1)**********************************/
/************************(2)*******************************/
struct cmd_fwd_tbl_set_phy2lport_result //在DPDK_fwd_debug.c中
{
cmdline_fixed_string_t action;
uint32_t entryId;
int slot_id;
int logical_port;
int nat_flag;
};
static void cmd_fwd_tbl_set_phy2lport_parased(void*parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_fwd_tbl_set_phy2lport_result *res=parsed_result;
fwd_tbl_set_phy2lport(res->entryId, res->slot_id, res->logical_port, res->nat_flag);
cmdline_printf(cl,"fwd_tbl_set_phy2lport() is called!\n");
}
cmdline_parse_token_string_t cmd_fwd_tbl_set_phy2lport_action=
TOKEN_STRING_INITIALIZER(struct cmd_fwd_tbl_set_phy2lport_result, action, "fwd_tbl_set_phy2lport");
cmdline_parse_token_num_t cmd_fwd_tbl_set_phy2lport_entryId=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_tbl_set_phy2lport_result, entryId,INT32);
cmdline_parse_token_num_t cmd_fwd_tbl_set_phy2lport_slot_id=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_tbl_set_phy2lport_result, slot_id,INT32);
cmdline_parse_token_num_t cmd_fwd_tbl_set_phy2lport_logical_port=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_tbl_set_phy2lport_result, logical_port,INT32);
cmdline_parse_token_num_t cmd_fwd_tbl_set_phy2lport_nat_flag=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_tbl_set_phy2lport_result, nat_flag,INT32);
cmdline_parse_inst_t cmd_fwd_tbl_set_phy2lport= {
.f = cmd_fwd_tbl_set_phy2lport_parased, /* function to call */
.data = NULL, /* 2nd arg of func */
.help_str = "fwd_tbl_set_phy2lport entryId slot_id logical_port nat_flag",
.tokens = { /* token list, NULL terminated */
(void *)&cmd_fwd_tbl_set_phy2lport_action,
(void *)&cmd_fwd_tbl_set_phy2lport_entryId,
(void *)&cmd_fwd_tbl_set_phy2lport_slot_id,
(void *)&cmd_fwd_tbl_set_phy2lport_logical_port,
(void *)&cmd_fwd_tbl_set_phy2lport_nat_flag,
NULL,
},
};
/************************(2)*******************************/
/************************(3)*******************************/
struct cmd_fwd_set_port_mac_resuct //在Netdev_api.c中
{
cmdline_fixed_string_t action;
int port;
int hmac;
int lmac;
};
static void cmd_fwd_set_port_mac_parased(void*parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_fwd_set_port_mac_resuct *res=parsed_result;
fwd_set_port_mac(res->port, res->hmac, res->lmac);
cmdline_printf(cl,"fwd_set_port_mac() is called!\n");
}
cmdline_parse_token_string_t cmd_fwd_set_port_mac_action=
TOKEN_STRING_INITIALIZER(struct cmd_fwd_set_port_mac_resuct, action, "fwd_set_port_mac");
cmdline_parse_token_num_t cmd_fwd_set_port_mac_port=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_set_port_mac_resuct,port,INT32);
cmdline_parse_token_num_t cmd_fwd_set_port_mac_hmac=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_set_port_mac_resuct,hmac,INT64);
cmdline_parse_token_num_t cmd_fwd_set_port_mac_lmac=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_set_port_mac_resuct,lmac,INT64);
cmdline_parse_inst_t cmd_fwd_set_port_mac={
.f = cmd_fwd_set_port_mac_parased,
.data = NULL,
.help_str = "cmd_fwd_set_port_mac port hmac lmac",
.tokens = {
(void *)&cmd_fwd_set_port_mac_action,
(void *)&cmd_fwd_set_port_mac_port,
(void *)&cmd_fwd_set_port_mac_hmac,
(void *)&cmd_fwd_set_port_mac_lmac,
NULL,
},
};
/************************(3)*******************************/
/************************(4)*******************************/
struct cmd_fwd_get_port_mac_resuct{ //同上
cmdline_fixed_string_t action;
int port;
};
static void cmd_fwd_get_port_mac_parased(void*parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_fwd_get_port_mac_resuct *res=parsed_result;
fwd_get_port_mac(res->port);
cmdline_printf(cl,"fwd_get_port_mac() is called!\n");
}
cmdline_parse_token_string_t cmd_fwd_get_port_mac_action=
TOKEN_STRING_INITIALIZER(struct cmd_fwd_get_port_mac_resuct, action, "fwd_get_port_mac");
cmdline_parse_token_num_t cmd_fwd_get_port_mac_port=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_get_port_mac_resuct,port,INT32);
cmdline_parse_inst_t cmd_fwd_get_port_mac={
.f = cmd_fwd_get_port_mac_parased,
.data = NULL,
.help_str = "cmd_fwd_get_port_mac port",
.tokens = {
(void *)&cmd_fwd_get_port_mac_action,
(void *)&cmd_fwd_get_port_mac_port,
NULL,
},
};
/************************(4)*******************************/
/************************(5)*******************************/
//fwd_get_shortflow
struct cmd_fwd_get_shortflow_resuct{
cmdline_fixed_string_t action;
int src_phy_port;
int svlan;
int cvlan;
};
static void cmd_fwd_get_shortflow_parased(void*parsed_result,
struct cmdline *cl,
__attribute__((unused)) void *data)
{
struct cmd_fwd_get_shortflow_resuct *res=parsed_result;
fwd_get_shortflow(res->src_phy_port, res->svlan, res->cvlan);
cmdline_printf(cl,"fwd_fwd_get_shortflow() is called!\n");
}
cmdline_parse_token_string_t cmd_fwd_get_shortflow_action=
TOKEN_STRING_INITIALIZER(struct cmd_fwd_get_shortflow_resuct, action, "fwd_get_shortflow");
cmdline_parse_token_num_t cmd_fwd_get_shortflow_src_phy_port=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_get_shortflow_resuct,src_phy_port,INT32);
cmdline_parse_token_num_t cmd_fwd_get_shortflow_src_svlan=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_get_shortflow_resuct,svlan,INT32);
cmdline_parse_token_num_t cmd_fwd_get_shortflow_src_cvlan=
TOKEN_NUM_INITIALIZER(struct cmd_fwd_get_shortflow_resuct,cvlan,INT32);
cmdline_parse_inst_t cmd_fwd_get_shortflow={
.f = cmd_fwd_get_shortflow_parased,
.data = NULL,
.help_str = "fwd_get_shortflow_parased src_phy_port svlan cvlan",
.tokens = {
(void *)&cmd_fwd_get_shortflow_action,
(void *)&cmd_fwd_get_shortflow_src_phy_port,
(void *)&cmd_fwd_get_shortflow_src_svlan,
(void *)&cmd_fwd_get_shortflow_src_cvlan,
NULL,
},
};
/************************(5)*******************************/
/**********************************************************/
/****** CONTEXT (list of instruction) */
cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_help,
(cmdline_parse_inst_t *)&cmd_fwd_log_level_set,
(cmdline_parse_inst_t *)&cmd_fwd_tbl_set_phy2lport,
(cmdline_parse_inst_t *)&cmd_fwd_set_port_mac,
(cmdline_parse_inst_t *)&cmd_fwd_get_port_mac,
(cmdline_parse_inst_t *)&cmd_fwd_get_shortflow,
NULL,
};