dpdk cmdline 例子解析

dpdk 官方第三个例子介绍了如何使用cmdline相关接口实现一个命令行工具
效果还是比较不错的,可以实现tab补全,前缀匹配的功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-52nQGoeZ-1655814968513)(https://asciinema.org/a/gE1fuJykrE3mDqjtmMqacGon3.svg)]

官方文档

在此梳理几个关键的函数的结构,说明一下cmdline接口的使用方法

int main(int argc, char **argv)
{
    ...
    struct cmdline *cl;

    ...
    cl = cmdline_stdin_new(main_ctx, "example> ");
    ...
    cmdline_interact(cl);
    cmdline_stdin_exit(cl);

    ...

    return 0;
}

核心结构是struct cmdline *cl;
cl是一个cmdline实例的句柄,通过cmdline_stdin_new创建并关联了自定义上下文main_ctx

之后的交互逻辑cmdline_interact和释放逻辑cmdline_stdin_exit都使用这个句柄
对使用者来讲只要正确的传递cl即可,最关键的结构是main_ctx

我们来看一下main_ctx的定义

cmdline_parse_ctx_t main_ctx[] = {
    (cmdline_parse_inst_t *)&cmd_obj_del_show,
    (cmdline_parse_inst_t *)&cmd_obj_add,
    (cmdline_parse_inst_t *)&cmd_help,
    NULL,
};

可以看到main_ctx是一个数组,用来存放所有支持的命令,每一个命令的类型是cmdline_parse_inst_t *
cmd_obj_del_show的初始化来举例

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 list, NULL terminated */
		(void *)&cmd_obj_action_add,
		(void *)&cmd_obj_name,
		(void *)&cmd_obj_ip,
		NULL,
	},
};

.f 字段是错有参数解析完成之后的回调函数
.data是一个透传参数
.help_str是帮助信息字符串
.token是最关键的,包含了所有参数的类型声明
每一个token的声明都被转换成了void *放在tokens数组中,转换之前的类型是dpdk已经帮我们定义好的一些token类型

cmdline_parse_token_string_t cmd_obj_action_add =
    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 =
    TOKEN_IPADDR_INITIALIZER(struct cmd_obj_add_result, ip);

可以看到前两个类型是string,最后一个类型是ip

我们用cmd_obj_ip类型举例, 它的类型是cmdline_parse_token_ipaddr_t

struct cmdline_token_ipaddr_data {
    uint8_t flags;
};

struct cmdline_token_ipaddr {
    struct cmdline_token_hdr hdr;
    struct cmdline_token_ipaddr_data ipaddr_data;
};
typedef struct cmdline_token_ipaddr cmdline_parse_token_ipaddr_t;

再看一下初始化宏TOKEN_IPADDR_INITIALIZER的定义

#define TOKEN_IPADDR_INITIALIZER(structure, field)      \
{                                                       \
    /* hdr */                                           \
    {                                                   \
        cmdline_token_ipaddr_ops,      /* ops */       \
        offsetof(structure, field),     /* offset */    \
    },                                                  \
    /* ipaddr_data */                                   \
    {                                                   \
        CMDLINE_IPADDR_V4 |             /* flags */     \
        CMDLINE_IPADDR_V6,                              \
    },                                                  \
}

这里先关注/*hdr*/注释下面的内容,cmdline_token_ipaddr_ops 用来初始化 cmdline_token_hdr结构体中的hdr

我们会发现,所有dpdk预定义的token结构体都有一个公用的部分,是cmdline_token_hdr

struct cmdline_token_hdr {
    struct cmdline_token_ops *ops;
    unsigned int offset;
};

ops 是用来对输入做parse操作的一个集合
offset 表示parse操作要将解析数据之后的内容存放到临时buffer的偏移量

cmdline内部逻辑会串行的解析tokens数组中的参数,并按照注册的offset放到临时buffer中

那么offset是什么呢
可以看到,在初始化宏TOKEN_IPADDR_INITIALIZER中是这样实现的

offsetof(structure, field)

我们将这句话展开

TOKEN_IPADDR_INITIALIZER(struct cmd_obj_add_result, ip);

就是

offsetof(cmd_obj_add_result, ip)

也就是求ip字段在cmd_obj_add_result结构体中的偏移

cmd_obj_add_result结构体定义如下

struct cmd_obj_add_result {
    cmdline_fixed_string_t action;
    cmdline_fixed_string_t name;
    cmdline_ipaddr_t ip;
};

对应三个初始化宏,可以发现,三个token的offset正好是按照结构题中的字段排布累加出来的,也就是说,最终传递给回调函数的buffer中,刚好是一个cmd_obj_add_result的内存排布

我们看 cmd_obj_add_parsed的实现,也能够看出来,dpdk实现的通用逻辑并不关心各个parse之后要放入一个具体什么结构,而只是傻傻的将解析的内容填写到一个临时buffer 指定的offset地址,用一些宏定义巧妙的传输了结构体的内存布局信息,并且还让通用逻辑不关心这个信息

static void cmd_obj_add_parsed(void *parsed_result,
                   struct cmdline *cl,
                   __rte_unused void *data)
{
    struct cmd_obj_add_result *res = parsed_result;
    ...
}

最终的parse逻辑之需要拿到这个buffer强转成需要的指针即可

总结一下

dpdk cmdline接口靠ctx获取所有命令字种类
靠每个命令字的tokens列表获得解析方法
将解析的结果放入命令字的回调函数

使用dpdk cmdline相关的接口函数,我们要提供以下几个内容

  • 命令字列表(元素为cmdline_parse_inst_t*的数组)
  • 每个命令字的详细token的解析方式(回调函数,各个token定义)
  • 对于每个token,定义解析后存放在结构题中的相对内存地址
  • 如果要自定义token类型,需要一同自定义token的parse方法,初始化宏(参考parse_obj_list.h)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值