本文共 2562 字,大约阅读时间需要 8 分钟。
每个process结点是由jump机制构成的一个协程,协程主要用于等待、处理事件。
使用longjmp/setjmp的轻量级多任务协程,由应用进程自行进行调度,不受操作系统调度机制的影响,上下文切换只损耗调用longjmp/setjmp的时间。协程中运行的函数类似于线程函数,区别在于协程函数Can be suspended, wait for events, be resumed… (based on setjump/longjump).在vlib_main_or_worker_loop开始包处理循环之前,main线程会对所有的process结点都调度一次,执行相应的node函数,类似于初始化操作。
在dispatch_process函数中讲调用vlib_process_startup函数,处理所有process结点的初始化工作。vlib_process_startup先记录每个process结点正常返回时的jmp信息(return_longjmp),之后跳到vlib_process_bootstrap函数中执行process结点函数。以下为某个典型的process结点函数:
该函数为while (1)的形式,说明该node函数将一直执行直到应用进程退出为止。而在开始的时候这里先调用了vlib_process_wait_for_event函数,检查是否由事件需要处理。该函数先去检查non_empty_event_type_bitmap是否置位,如有说明有需要处理的事件则立刻返回进行处理,否则说明该process node任然需要等待事件,暂不需要分配CPU时间,可以进入suspend状态。
所以,这里先记录下当前的位置(记为resume_longjmp),然后再跳回return_longjmp所记录的位置,完成一次结点调度过程。这样,初始化时调用的dispatch_process可以先初始化所有的process node,而各process node暂时处于suspend状态,等待某个条件的到来进入resume状态并执行业务逻辑,执行完后退出释放CPU资源。internal结点主要用于处理数据包业务逻辑,结点通过函数流程上与input结点大致相同。
static uword sample_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vlib_frame_t *frame -> 由node函数入口传入 U32 *from -> 当前frame中vector的起始数据from = vlib_frame_vector_args(frame);
调用vlib_frame_vector_args函数返回本node vlib_frame_t中数据包的起始位置,对包进行处理使用from[0],from[1]…
vlib_main_t *vm = vlib_get_main ();u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;vlib_node_runtime_t *node;u32 n_left_to_next;u32 *to_next;vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
调用vlib_get_next_frame函数,找到下一node对应的vlib_frame_t中合适的存放数据包的起始位置并保存到to_next
如果要发送数据包,则可以修改to_next[0],to_next[1]……中的数据包索引值vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0);next_index -> 默认的下一结点的indexnext0 -> 实际的下一个结点的index
当next0 != next_index时,说明该包被正确处理,该宏将do nothing
否则,说明本来该包应去next_index但是经过包处理需要去往其他结点使得next0 != next_index,该宏会将该包索引pi0发往到next0实际的下一个结点vlib_put_next_frame(vm, node, next_index, n_left_to_next);
所有流程都正确处理完毕后,下一结点的frame上已经有本结点处理过后的数据索引执行该函数,将相关信息登记到vlib_pending_frame_t中,准备开始调度处理转载地址:http://wbqya.baihongyu.com/