VPP CLI 原理分析

1.命令注册

1.1 VLIB_CLI_COMMAND 宏

static clib_error_t *
upf_show_ha_command_fn (vlib_main_t *vm, unformat_input_t *main_input,
                        vlib_cli_command_t *cmd)
{
  upf_main_t *um = &upf_main;

  vlib_cli_output (vm, "UPF HA Status: %s\n",
                   um->ha_status == HA_STATUS_ACTIVE ? "ACTIVE" : "BACKUP");

  return NULL;
}

/* *INDENT-OFF* */
VLIB_CLI_COMMAND (upf_show_ha_command, static) = {
    .path = "show upf ha status",
    .short_help = "show upf ha status",
    .function = upf_show_ha_command_fn,
};
/* *INDENT-ON* */

VLIB_CLI_COMMAND 将命令 upf_show_ha_command 注册到 vm->cli_main->cli_command_registrations 链表

命令名定义: .path = “show upf ha status”,

命令格式定义:.short_help = “show upf ha status”,

命令对应的钩子函数,实现命令的功能:.function = upf_show_ha_command_fn。

1.2 VLIB_INIT_FUNCTION宏

VLIB_INIT_FUNCTION (upf_init);

VLIB_INIT_FUNCTION (upf_init) 中的 upf_init 遍历 vm->cli_main->cli_command_registrations 链表,对 upf 的每个命令调 vlib_cli_register 函数。

1.3 vlib_cli_register函数

四要素:命令、标准化命令(normalized_path),命令索引链表(command_index_by_path)、命令向量链表(commands)。

注册大致过程:查看 vm->cli_main->command_index_by_path 的 hash 链表,是否存在标准化命令 normalized_path。如果对应的命令索引存在,则把注册命令时向量结点的参数覆盖原有的向量结点的值。如果命令向量不存在,则创建。把命令添加到命令向量链表里,首先检查下标ci是否越界,如果没有越界则获取向量值。

2. VPP CLI 机制之客户端 vppctl 和服务端 vpp

2.1 vpp与vppctl交互的关键文件

/run/vpp/cli.sock

VPPCTL

vppctl 端创建与 /run/vpp/cli.sock 路径服务端进行通信的本地套接字 client 端,从标准输入读取命令,发送给服务端,并从服务端读取返回值。

VPP

vpp 端创建监听 /run/vpp/cli.sock 路径的服务端,创建权限为 755。服务端通过 epoll 实现多并发过程。

与客户端交互,当客户端发送数据来时,file_main 接收到 epoll_in 事件调客户端注册的 read_function(unix_cli_read_ready),从描述符读数据存放到 cf->input_vector,并发送 UNIX_CLI_PROCESS_EVENT_READ_READY 事件交 unix_cli_process 结点处理,unix_cli_process_input 进行命令解析和处理;

unix_cli_process_input -> unix_cli_line_edit -> unix_cli_line_process_one 逐字读取字符并回显 -> 然后判断 unix_cli_match_action 是否是 telnet -> 然后调 unix_cli_process_telnet 或 unix_cli_process_one 进行输入的字符串读取 -> 读取完成调 vlib_cli_input 进行关键字匹配 -> 匹配到后通过命令执行函数 -> vlib_cli_output 函数将需要发送或回复 cli 客户端的信息通过 output_function: unix_vlib_cli_output;将数据 send 发到 cli 客户端。

2.2 VLIB_EARLY_CONFIG_FUNCTION 宏

VLIB_EARLY_CONFIG_FUNCTION (unix_config, "unix") 读取 startup.conf 中 unix 相关配置,对应 cli 默认配置了 cli socket 的路径(cli-listen /run/vpp/cli.sock)。

2.3 VLIB_CONFIG_FUNCTION 宏

VLIB_CONFIG_FUNCTION (unix_cli_config, "unix-cli") cli 默认配置是非交互模式。cli 配置成交互式,则将标准输入作为客户端进行监听(startup.conf 配置文件中默认未配置)。