VPP启动

来源:互联网 发布:妙笔生花软件安卓 编辑:程序博客网 时间:2024/05/29 08:29

在上文说到,在VPP启动之前,会提前通过宏定义的方式注册各种需要初始化的业务逻辑函数,本文主要介绍VPP的启动流程

 

VPP的入口函数在src/vpp/vnet/main.c

1.   加载startup.conf,获取配置信息

VPP启动,可以通过命令:如vpp –c /etc/vpp/startup.conf启动

startup.conf包含了VPP默认的配置信息,涉及多种配置参数,每个参数用大括号进行区分:

可以包含的默认配置有:具体可见:https://wiki.fd.io/view/VPP/Command-line_Arguments

VPP启动时主要关心:pluginpath和heapsize,获取plugin路径和堆大小

2.   clib_mem_init:

根据默认配置,分配主堆内存

3.   vpe_main_init:

设置VPP提示,

 

注册srp_ips_process_node, srp_input_node, srp_control_input_node3个node节点

 

此处没细研究,主要理解应该是实现旁路操作系统,实现网络数据直接在网卡和VPP之间传递做准备

4.   vlib_unix_main

核心的启动业务逻辑就在该函数中:

int vlib_unix_main (int argc, char *argv[])

{

 vlib_main_t *vm = &vlib_global_main;        /*one and only time for this! */

 vlib_thread_main_t *tm = &vlib_thread_main;

 unformat_input_t input;

  u8*thread_stacks;

 clib_error_t *e;

  inti;

 

 vm->argv = (u8 **) argv;

 vm->name = argv[0];

 vm->heap_base = clib_mem_get_heap ();

 ASSERT (vm->heap_base);

 

 unformat_init_command_line (&input, (char **) vm->argv);

  //获取plugin信息并填充结构体

if ((e = vlib_plugin_config (vm, &input)))

    {

     clib_error_report (e);

     return 1;

    }

 unformat_free (&input);

 

  //加载启动插件功能

  i =vlib_plugin_early_init (vm);

  if(i)

   return i;

 

 unformat_init_command_line (&input, (char **) vm->argv);

  if(vm->init_functions_called == 0)

   vm->init_functions_called = hash_create (0, /* value bytes */ 0);

  //启动所有宏定义VLIB_EARLY_CONFIG_FUNCTION和VLIB_CONFIG_FUNCTION注册的链表函数

e = vlib_call_all_config_functions (vm, &input, 1 /* early */ );

  if(e != 0)

    {

     clib_error_report (e);

     return 1;

    }

 unformat_free (&input);

 

  /*

   *allocate n x VLIB_THREAD_STACK_SIZE stacks, aligned to a

   *VLIB_THREAD_STACK_SIZE boundary

   *See also: os_get_cpu_number() in vlib/vlib/threads.c

   */

 thread_stacks = clib_mem_alloc_aligned

   ((uword) tm->n_thread_stacks * VLIB_THREAD_STACK_SIZE,

    VLIB_THREAD_STACK_SIZE);

 

 vec_validate (vlib_thread_stacks, tm->n_thread_stacks - 1);

  for(i = 0; i < vec_len (vlib_thread_stacks); i++)

    {

     vlib_thread_stacks[i] = thread_stacks;

 

     /*

      * Disallow writes to the bottom page of the stack, to

      * catch stack overflows.

      */

     if (mprotect (thread_stacks, clib_mem_get_page_size (), PROT_READ) <0)

         clib_unix_warning("thread stack");

 

     thread_stacks += VLIB_THREAD_STACK_SIZE;

    }

 

 //这里启动thread0

  i =clib_calljmp (thread0, (uword) vm,

                       (void *) (vlib_thread_stacks[0] +

                                  VLIB_THREAD_STACK_SIZE));

 return i;

}

5.   vlib/unix/main.c的thread0()函数

调用vlib/中的vlib_main函数

vlib_main (vlib_main_t * volatile vm,unformat_input_t * input)

{

 clib_error_t *volatile error;

 

 vm->queue_signal_callback = dummy_queue_signal_callback;

 

 clib_time_init (&vm->clib_time);

 

  /*Turn on event log. */

  if(!vm->elog_main.event_ring_size)

   vm->elog_main.event_ring_size = 128 << 10;

 elog_init (&vm->elog_main, vm->elog_main.event_ring_size);

 elog_enable_disable (&vm->elog_main, 1);

 

  /*Default name. */

  if(!vm->name)

   vm->name = "VLIB";

 

 vec_validate (vm->buffer_main, 0);

 vlib_buffer_cb_init (vm);

 

  if((error = vlib_thread_init (vm)))

    {

     clib_error_report (error);

     goto done;

    }

 

 //启动宏定义VLIB_REGISTER_NODE注册的所有node节点功能函数,功能比较简单,就是将各个节点加到一个vlib_node_main_t-> nodes

  /*Register static nodes so that init functions may use them. */

 vlib_register_all_static_nodes (vm);

 

  /*Set seed for random number generator.

    Allow user to specify seed to make random sequence deterministic. */

  if(!unformat (input, "seed %wd", &vm->random_seed))

   vm->random_seed = clib_cpu_time_now ();

 clib_random_buffer_init (&vm->random_buffer, vm->random_seed);

 

  /*Initialize node graph. */

//初始化node graph,看代码基本就是填充节点关系字段

  if((error = vlib_node_main_init (vm)))

    {

     /* Arrange for graph hook up error to not be fatal when debugging. */

     if (CLIB_DEBUG > 0)

         clib_error_report(error);

     else

         gotodone;

    }

 

  /*See unix/main.c; most likely already set up */

  if(vm->init_functions_called == 0)

   vm->init_functions_called = hash_create (0, /* value bytes */ 0);

//启动所有宏定义VLIB_INIT_FUNCTION:注册的链表函数

if ((error = vlib_call_all_init_functions(vm)))

   goto done;

 

  /*Create default buffer free list. */

 vlib_buffer_get_or_create_free_list (vm,

                                            VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,

                                            "default");

 

 switch (clib_setjmp (&vm->main_loop_exit,VLIB_MAIN_LOOP_EXIT_NONE))

    {

   case VLIB_MAIN_LOOP_EXIT_NONE:

     vm->main_loop_exit_set = 1;

     break;

 

   case VLIB_MAIN_LOOP_EXIT_CLI:

     goto done;

 

   default:

     error = vm->main_loop_error;

     goto done;

    }

 

  if((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))

   goto done;

 

 

  /*Call all main loop enter functions. */

  {

   clib_error_t *sub_error;

   //启动宏定义VLIB_MAIN_LOOP_ENTER_FUNCTION指定的函数,这里主要启动thread.c中的start_workers

 sub_error =vlib_call_all_main_loop_enter_functions (vm);

   if (sub_error)

     clib_error_report (sub_error);

  }

  //处理节点的核心功能函数

 vlib_main_loop (vm);

 

done:

  /*Call all exit functions. */

  {

   clib_error_t *sub_error;

   sub_error = vlib_call_all_main_loop_exit_functions (vm);

   if (sub_error)

     clib_error_report (sub_error);

  }

 

  if(error)

   clib_error_report (error);

 

 return 0;

}