思科VPP源码分析(CLI支持分析)
来源:互联网 发布:wps是什么软件下载 编辑:程序博客网 时间:2024/06/05 09:03
基本概念
这个只是辅助部分,大多数人不关系,我就随便写写
核心函数
//主线程会调用unix_cli_config,开始cli部分的初始化工作VLIB_CONFIG_FUNCTION (unix_cli_config, "unix-cli");
/** Handle configuration directives in the @em unix section. */static clib_error_t *unix_cli_config (vlib_main_t * vm, unformat_input_t * input){ unix_main_t *um = &unix_main; unix_cli_main_t *cm = &unix_cli_main; int flags; clib_error_t *error = 0; unix_cli_file_t *cf; u32 cf_index; struct termios tio; struct sigaction sa; struct winsize ws; u8 *term; /* We depend on unix flags being set. */ //确保unix_config执行且只执行了一次 if ((error = vlib_call_config_function (vm, unix_config))) return error; if (um->flags & UNIX_FLAG_INTERACTIVE) { //支持交互模式 /* Set stdin to be non-blocking. */ /*非阻塞模式,UNIX_CLI_STDIN_FD会交由VLIB_NODE_TYPE_PRE_INPUT类型的 unix-epoll-input node来监视*/ if ((flags = fcntl (UNIX_CLI_STDIN_FD, F_GETFL, 0)) < 0) flags = 0; (void) fcntl (UNIX_CLI_STDIN_FD, F_SETFL, flags | O_NONBLOCK); /*生成或者复用一个VLIB_NODE_TYPE_PROCESS类型node,并调度激活node,等待来 处理该cli session*/ cf_index = unix_cli_file_add (cm, "stdin", UNIX_CLI_STDIN_FD); cf = pool_elt_at_index (cm->cli_file_pool, cf_index); cm->stdin_cli_file_index = cf_index; //下面是调整cli界面参数的,暂时不分析了。 /* If stdin is a tty and we are using chacracter mode, enable * history on the CLI and set the tty line discipline accordingly. */ if (isatty (UNIX_CLI_STDIN_FD) && um->cli_line_mode == 0) { /* Capture terminal resize events */ memset (&sa, 0, sizeof (sa)); sa.sa_handler = unix_cli_resize_interrupt; if (sigaction (SIGWINCH, &sa, 0) < 0) clib_panic ("sigaction"); /* Retrieve the current terminal size */ ioctl (UNIX_CLI_STDIN_FD, TIOCGWINSZ, &ws); cf->width = ws.ws_col; cf->height = ws.ws_row; if (cf->width == 0 || cf->height == 0) /* We have a tty, but no size. Stick to line mode. */ goto notty; /* Setup the history */ cf->history_limit = um->cli_history_limit; cf->has_history = cf->history_limit != 0; /* Setup the pager */ cf->no_pager = um->cli_no_pager; /* We're going to be in char by char mode */ cf->line_mode = 0; /* Save the original tty state so we can restore it later */ tcgetattr (UNIX_CLI_STDIN_FD, &um->tio_stdin); um->tio_isset = 1; /* Tweak the tty settings */ tio = um->tio_stdin; /* echo off, canonical mode off, ext'd input processing off */ tio.c_lflag &= ~(ECHO | ICANON | IEXTEN); tio.c_cc[VMIN] = 1; /* 1 byte at a time */ tio.c_cc[VTIME] = 0; /* no timer */ tcsetattr (UNIX_CLI_STDIN_FD, TCSAFLUSH, &tio); /* See if we can do ANSI/VT100 output */ term = (u8 *) getenv ("TERM"); if (term != NULL) cf->ansi_capable = unix_cli_terminal_type (term, strlen ((char *) term)); } else { notty: /* No tty, so make sure these things are off */ cf->no_pager = 1; cf->history_limit = 0; cf->has_history = 0; cf->line_mode = 1; } /* Send banner and initial prompt */ //一些欢迎信息拷贝到cf->output_vector中,更新epoll状态,等待时机输出。 unix_cli_file_welcome (cm, cf); } //下面是CLI socket支持 /* If we have socket config, LISTEN, otherwise, don't */ clib_socket_t *s = &um->cli_listen_socket; if (s->config && s->config[0] != 0) { /* CLI listen. */ unix_file_t template = { 0 }; s->flags = SOCKET_IS_SERVER; /* listen, don't connect */ //socket初始化,监听模式,代码不难 error = clib_socket_init (s); if (error) return error; template.read_function = unix_cli_listen_read_ready; template.file_descriptor = s->fd; //socket加入到epoll unix_file_add (um, &template); } /* Set CLI prompt. */ if (!cm->cli_prompt) cm->cli_prompt = format (0, "VLIB: "); return 0;}
//该函数启动一个CLI session,关键是要提前理解VLIB_NODE_TYPE_PROCESS类型node运行机制/** Store a new CLI session. * @param name The name of the session. * @param fd The file descriptor for the session I/O. * @return The session ID. */static u32unix_cli_file_add (unix_cli_main_t * cm, char *name, int fd){ unix_main_t *um = &unix_main; unix_cli_file_t *cf; unix_file_t template = { 0 }; vlib_main_t *vm = um->vlib_main; vlib_node_t *n; name = (char *) format (0, "unix-cli-%s", name); //CLI退出时,会把处理该CLI的node放入这个复用链表池,以待继续使用 if (vec_len (cm->unused_cli_process_node_indices) > 0) { uword l = vec_len (cm->unused_cli_process_node_indices); /* Find node and give it new name. */ n = vlib_get_node (vm, cm->unused_cli_process_node_indices[l - 1]); vec_free (n->name); n->name = (u8 *) name; vlib_node_set_state (vm, n->index, VLIB_NODE_STATE_POLLING); _vec_len (cm->unused_cli_process_node_indices) = l - 1; } else { //池子里没有,就新生成一个 static vlib_node_registration_t r = { .function = unix_cli_process, .type = VLIB_NODE_TYPE_PROCESS, .process_log2_n_stack_bytes = 16, }; r.name = name; vlib_register_node (vm, &r); vec_free (name); n = vlib_get_node (vm, r.index); } pool_get (cm->cli_file_pool, cf); memset (cf, 0, sizeof (*cf)); template.read_function = unix_cli_read_ready; template.write_function = unix_cli_write_ready; template.file_descriptor = fd; template.private_data = cf - cm->cli_file_pool; cf->process_node_index = n->index; //该文件fd加入epoll cf->unix_file_index = unix_file_add (um, &template); cf->output_vector = 0; cf->input_vector = 0; //启动该VLIB_NODE_TYPE_PROCESS类型node,它会进入“睡眠”状态,等待外部命令行输入来激活node vlib_start_process (vm, n->runtime_index); vlib_process_t *p = vlib_get_process_from_node (vm, n); p->output_function = unix_vlib_cli_output; p->output_function_arg = cf - cm->cli_file_pool; return cf - cm->cli_file_pool;}
/*当VLIB_NODE_TYPE_PROCESS类型node被CLI输入激活时,会从vlib_process_wait_for_event (vm);
下一行开始执行,理解这里需要VLIB_NODE_TYPE_PROCESS类型node调度的前置知识*/
/** Handle system events. */static uwordunix_cli_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f){ unix_cli_main_t *cm = &unix_cli_main; uword i, *data = 0; while (1) { unix_cli_process_event_type_t event_type; vlib_process_wait_for_event (vm); //激活该node的事件类型 event_type = vlib_process_get_events (vm, &data); switch (event_type) { //有CLI 命令来了,开始解析 case UNIX_CLI_PROCESS_EVENT_READ_READY: for (i = 0; i < vec_len (data); i++) //解析命令行 unix_cli_process_input (cm, data[i]); break; //CLI要退出了 case UNIX_CLI_PROCESS_EVENT_QUIT: /* Kill this process. */ for (i = 0; i < vec_len (data); i++) //如果是标准输入上来的退出命令,那就是退出进程,否则只需要退出该CLI session unix_cli_kill (cm, data[i]); goto done; } if (data) _vec_len (data) = 0; }done: vec_free (data); vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED); /* Add node index so we can re-use this process later. */ //该node完成使命,不需要在主循环上“睡眠”了,丢给复用池 vec_add1 (cm->unused_cli_process_node_indices, rt->node_index); return 0;}
//该函数用在epoll监听到有数据到来时,调用它接受数据。逻辑不难。/** Called when a CLI session file descriptor has data to be read. */static clib_error_t *unix_cli_read_ready (unix_file_t * uf){ unix_main_t *um = &unix_main; unix_cli_main_t *cm = &unix_cli_main; unix_cli_file_t *cf; uword l; int n, n_read, n_try; cf = pool_elt_at_index (cm->cli_file_pool, uf->private_data); n = n_try = 4096; while (n == n_try) { l = vec_len (cf->input_vector); vec_resize (cf->input_vector, l + n_try); n = read (uf->file_descriptor, cf->input_vector + l, n_try); /* Error? */ if (n < 0 && errno != EAGAIN) return clib_error_return_unix (0, "read"); n_read = n < 0 ? 0 : n; _vec_len (cf->input_vector) = l + n_read; } if (!(n < 0)) vlib_process_signal_event (um->vlib_main, cf->process_node_index, (n_read == 0 ? UNIX_CLI_PROCESS_EVENT_QUIT : UNIX_CLI_PROCESS_EVENT_READ_READY), /* event data */ uf->private_data); return /* no error */ 0;}//epoll把需要回馈给用户的CLI输出,写入。/** Called when a CLI session file descriptor can be written to without * blocking. */static clib_error_t *unix_cli_write_ready (unix_file_t * uf){ unix_cli_main_t *cm = &unix_cli_main; unix_cli_file_t *cf; int n; cf = pool_elt_at_index (cm->cli_file_pool, uf->private_data); /* Flush output vector. */ n = write (uf->file_descriptor, cf->output_vector, vec_len (cf->output_vector)); if (n < 0 && errno != EAGAIN) return clib_error_return_unix (0, "write"); else if (n > 0) unix_cli_del_pending_output (uf, cf, n); return /* no error */ 0;}
0 0
- 思科VPP源码分析(CLI支持分析)
- 思科VPP源码分析(多线程支持分析)
- 思科VPP源码分析(Bihash分析)
- 思科VPP源码分析(内存管理)
- 思科VPP源码分析(内存管理)
- 思科VPP源码分析(dpo机制源码分析)
- 思科VPP源码分析(dpdk node分析)
- 思科VPP源码分析(ethernet node分析)
- 思科VPP源码分析(trace机制分析)
- 思科VPP源码分析(路由框架分析一)
- 思科VPP源码分析(路由框架分析二)
- 思科VPP源码分析(feature机制分析)
- 思科VPP源码分析(node调度框架)
- Cordova CLI源码分析
- redis-cli源码分析
- vpp feature node分析总结(snat)
- networking-vpp 分析
- VPP主要结构体分析
- 新项目的熟悉步骤
- Codevs 1222 信与信封问题 二分图匹配
- unity实现N等分圆
- 给python脚本打包成.exe
- 代码与编程题
- 思科VPP源码分析(CLI支持分析)
- iOS Core Data的增删改查详细使用
- java 关键字 static
- 使用Opencv保存视频
- Elasticsearch 理解重点
- nginx + uwsgi 出现Too Many Open Files Error
- 通过nonblock socket file descriptor测试IP和Port是否能建立connection的注意点
- 【JAVA】JAVA 期中练习题
- 以对象形式处理数据