Pktgen CLI样例程序
之前介绍了pktgen的命令使用,已经pktgen命令的组织,即目录的组织结构,具体是怎么实现的,后期再看代码
目前,我们怎么在这个目录结构中,添加自己的命令呢?
这就是Pktgen的CLI command line interface命令行接口
这节介绍pktgen的命令行接口,以及与CLI相关的概念,和CLI的一个样例程序
CLI是command line interface的简写
CLI样例程序是DPDK的一部分(其实不是),CLI很像DPDK的cmdline库,拥有相似的
编程接口和编程模型
CLI的主要目的是让开发者只用少量的代码和配置也能快速的创建命令
使用开发者熟悉的类Unix系统结构
允许开发者为应用和部署开发许多的命令
CLI被设计成了目录结构,而不是单层的命令行接口
CLI允许开发者使用目录风格的解决方案去控制DPDK应用程序
目录风格的设计不是什么新鲜的,但是他有很多优点
其中一个优点是目录路径对于命令来说可以成为命令的一部分
另一个优点就是使用目录结构可以创建分层的命令
而且开发者还可以动态的添加删除命令
CLI还有一下几个优点:
CLI没有全局变量,除了唯一一个线程变量this_cli, this_cli只能被创建CLI实例的线程访问
CLI支持命令,文件,别名,目录
变量的别名就是用一个简单的字符串替换别的命令,就像shell的alias
文件可以是静态或则动态的信息,可以在线进行修改,保存。
文件支持简单的回调函数让开发者更新其中的内容
如果开发者需要,可以添加支持彩色和鼠标
CLI就像DPDK的cmdline库,在程序用两者都是可以使用的
为命令和文件使用一个简单的,伪造的,像目录一样的布局。命令可以分层,而且命令的路径
可以用来作为具体的目标的标识,而不需要在命令行上声明它(意思就是,路径可以区分命令)
命令能够自动补全,就像shell的命令行一样
命令回调函数很简单,就像普通的 argc/argv函数一样
CLI不会为开发者转换参数,需要开发者来对argv进行解码
当前的命令行,很多的参数转换是很难用的,或则不符合开发的要求,仅仅只是摘取了字符串的
类型,而且没有进行转换(好像是说,别动东西不好用,我这东西好用)
可以动态的添加删除命令,目录,文件和别名,不需要静态的编译到应用程序(MD命令删除倒是可以,不知道怎么添加)
没有变态的数据结构,可以将testpmd的代码行数从12K优化到4.5K,可以为testpmd支持
CMDLINE和CLI,而且是使用相同的命令行选项(估计一个是DPDK自带的,一个是PKTGEN的)
提供两种解析命令行参数的方法,第一种是标准的argc/argv函数
第二种方法是使用一种字符串集合映射就像printf格式一样,检测出用户输入的命令行
一个ID值将会被返回,用来指示那个映射的字符串被查找到了,然后让命令行能够
使用switch语句
使用env命令或则API可以支持环境变量
可以提供关键的帮助
这翻译,没谁了,理解大概意思就行,之后看代码,一看就明白的
概述
CLI样例程序是一个简单的应用,示范了如何在DPDK中使用命令行接口,这个应用程序是按行读取的,
以此来控制DPDK程序。
CLI基于命令行的好处是动态的,意思是,节点或则条目可以在线添加删除
允许添加一个新的目录,文件或命令,或则删除他们
CLI没有全局可修改的变量,除了一个全局指针是一个基于线程的变量
它允许开发者在一个线程中有多个CLI命令
另一个优点是使用开发者熟悉的后台函数来处理命令,而且是基于argc/argv的,开发者
能够获取整个命令行。
还有一个优点是使用MAP结构,用来识别命令;
允许开发定义新版本的命令,而且能通过简单的ID值识别这些新版本的命令
最后一个优点是CLI添加目录,文件和命令非常简单。
基本的概念就是使用标准的Unix设计(anything is file?)
MD,一个发包程序,这么高端,不亏是开源项目啊。
为了添加一个命令,开发者需要添加一个项到cli_tree_t的结构,而且需要创建一个
函数,使用下面的原型
int user_cmd(int argc, char **argv);
argc/argv 就像标准unix系统那样使用。(比如咋们的a.out)
可以使用getopt()函数进行解析,还有别的都可以
命令行结构和文本转换是在编译的时候定义的。
在CLI处理时,argc/argv需要进行传递,进行转换
The cli variable being a thread Local Storage (TLS) all user routines
a CLI routine only need to access the thread variable to
eliminate needing a global variable to reference the specific
CLI instance and passing the value in the API
所有用户的处理线路的CLI变量是基于线程本地存储的,每个CLI线路只需要访问本
线程的变量,以此来消除全局变量需要关联到特定的CLI实例,通过API进行
传递(可恶:大概就是全局变量使用需要API麻烦,用本地变量)
用户可以设置环境变量通过env命令,这些变量也在命令行中进行了解析,直接替换完成
CLI系统也支持简单的文件通过像alias命令一样。如果用户有更多的参数,
则将这些参数附加到别名字符串上,并像在命令行上输入一样进行处理。
CLI样例程序支持一些CMDLINE库的特性,比如
补全,剪切/粘贴,和一些其它的特殊功能,是配置和debug faster and easier
CLI设计使用了一些非常简单的VT100控制字符串用来显示数据和接收输入
一些控制字符串用来clear屏幕或则行,定位光标,在VT100支持的终端上
CLI屏幕代码也支持基本的颜色和许多其他的VT100命令
这个应用程序也展示了怎么扩展,来处理用户输出的命令
这个样例程序有一个简单的命令提示,DPDK-cli:/> 就像unix shell命令
CLI有一些默认的命令:
ls: list the current or provided directory files/commands.
cd: Change directory command.
pwd: print out the current working directory.
history: List the current command line history if enabled.
more: A simple command to page contents of files.
help: display a the help screen.
quit: exit the CLI application, also Ctrl-x will exit as well.
mkdir: add a directory to the current directory.
delay: wait for a given number of microseconds.
sleep: wait for a given number of seconds.
rm: remove a directory, file or command. Removing a file will delete the data.
cls: clear the screen and redisplay the prompt.
version: Display the current DPDK version being used.
path: display the current search path for executable commands.
cmap: Display the current system core and socket information.
hugepages: Display the current hugepage information.
sizes: a collection system structure and buffer sizes for debugging.
copyright: a file containing DPDK copyright information.
env: a command show/set/modify the environment variables.
Some example commands under /bin directory are:
ll: an alias command to display long ls listing ls -l
h: alias command for history
hello: a simple Hello World! command.
show: has a number of commands using the map feature.
Under the /data directory is:
pci: a simple example file for displaying the lspci command in CLI.
自动补全
The CLI auto completion works similar to the standard Unix* system
by expanding commands and directory paths
特殊命令
! 和shell 一样
@ 使用Linux系统命令
编译这个程序
1. Go to example directory:
export RTE_SDK=/path/to/rte_sdk
cd ${RTE_SDK}/examples/cli
1. Set the target (a default target is used if not specified). For example:
export RTE_TARGET=x86_64-native-linuxapp-gcc
1.Build the application:
make
解释:
后面的章节为这些代码提供了一些解释
EAL Initialization and cmdline Start
cli_start(): 一直运行,直到Ctrl+x 或 输入quit
cli_create(): 需要四个参数,如果没提供,每个参数都有默认值
int cli_create(cli_prompt_t prompt_func, cli_tree_t tree_func,
int nb_entries, uint32_t nb_hist);
cli_create_with_tree(): 会调用cli_create(),用了其中的三个默认参数
int cli_create_with_tree(cli_tree_t tree)
{
return cli_create(NULL, tree, CLI_DEFAULT_NODES, CLI_DEFAULT_HIST_LINES);
}
int
main(int argc, char **argv)
{
if (cli_create_with_tree(init_tree) ==0) {
cli_start(NULL, 0); /* NULL is some init message done only once */
/* 0 means do not use color themes */
cli_destroy();
}
...
}
The tree init routine is defined like:
static struct cli_tree my_tree[] = {
c_dir("/data"),
c_file("pci", pci_file, "display lspci information"),
c_dir("/bin"),
c_cmd("hello", hello_cmd, "Hello-World!!"),
c_alias("h", "history", "display history commands"),
c_alias("ll", "ls -l", "long directory listing alias"),
c_end()
};
static int
init_tree(void)
{
/*
* Root is created already and using system default cmds and dirs, the
* developer is not required to use the system default cmds/dirs.
*/
if (cli_default_tree_init())
return -1;
/* Using NULL here to start at root directory */
if (cli_add_tree(NULL, my_tree))
return -1;
cli_help_add("Show", show_map, show_help);
return cli_add_bin_path("/bin");
}
上面的结构用来创建树结构体,cli_tree可以用来创建一个新的目录树
可以使用这些宏定义: c_dir, c_file, c_cmd, c_alias and c_end
用户可以创建自己需要的命令,通过cli_default_tree_init() 可以得到默认命令
如果开发者不想调用默认命令函数,那么必须调用cli_create_root()先,在添加
其他节点之前。其余的都是动态的了。
——————————————————————————————————————————————————————————————————————————————
上面的代码都是老版本的了,最后一个要求也是。但具有参考价值哈。。。。
新代码附上
不上了,source insight 不能复制粘贴?
我是3.3.3版本的
->main()
-> pktgen_cli_create()
-> cli_create(my_prompt, init_tree)
->my_prompt()
->cli_create_root()
->init_tree()
->cli_default_tree_init()
->cli_add_tree()
->cli_help_add()
->cli_add_bin_path()
到这里,基本就能添加自己的命令了。照猫画虎
添加修改命令很容易,关键是这个命令行架构怎么做的?