• VPP-main() 源码学习


    VPP初始化

    VLIB_INIT_FUNCTION用来定义构造函数,注册函数到vlib_main_t->init_function_registrations,这个链表在main()函数之前创建。

    vlib_main()-> vlib_call_all_init_functions()注册的函数在这里被调用初始化,最后执行函数vlib_main_loop()。

    像这样由宏定义和构造函数创建的全局链表的方式还有如下几个:

    ·        VLIB_API_INIT_FUNCTION

    ·        VLIB_CLI_COMMAND

    ·        VLIB_CONFIG_FUNCTION

    ·        VLIB_EARLY_CONFIG_FUNCTION

    ·        VLIB_MAIN_LOOP_ENTER_FUNCTION

    ·        VLIB_MAIN_LOOP_EXIT_FUNCTION

    ·        VLIB_REGISTER_NODE

    vpp/vnet/main.c的main()函数

    程序的入口,设置vlib_plugin_main.handoff_structure_get_cb函数指针,指向vpp/vnet/main.c中的函数vnet_get_handoff_structure。

    vlib/unix/plugin.c中的vnet_get_handoff_structure()函数调用上面的的函数指针handoff_structure_get_cb。

    vnet_get_handoff_structure() 定义了一个静态变量,这个静态变量包含了主要数据指针,比如vlib_main,vnet_main和ethernet_main(看代码没有vlib_main)。每个插件注册的时候,都会通过vlib_plugin_register()将以上数据传递给插件。

    最后调用vlib_unix_main()。

    vlib/unix/main.c的vlib_unix_main()函数

    vlib_plugin_early_init()函数会通过dlopen加载插件目录下的所有插件,这个目录可以通过命令行指定。默认的插件路径是 /usr/lib/vpp_plugins。

    dlopen每个插件后,VPP会获取函数vlib_plugin_register的符号地址,所以每个插件都要求实现该函数,之前说过这个函数会传递非常重要的数据。

    vlib_call_all_config_functions()函数解析所有的命令行选项,并且针对前期需求配置。

    为以下线程创建线程栈,主要有三种类型的线程需要实现:

    普通线程:比如统计采集。

    EAL线程:处理包的工作。

    Processes:这些都是定期执行、相互协作的多线程。比如DHCP租期续订的线程等。VPP主线程的超时到期之后会执行这些。

    最后,该函数跳转到thread0()函数。

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

    调用vlib/main.c的vlib_main()函数

    vlib/main.c的vlib_main()函数

    VLIB_REGISTER_NODE定义图节点,注册到vlib_main_t->node_registrations,vlib_register_all_static_nodes()遍历这个链表,创建图结点(不是连接,是创建)。

    VLIB_INIT_FUNCTION声明的函数,由vlib_call_all_init_functions()调用初始化。

    如果结点被创建,vlib/node.c的vlib_node_main_init()会对图结点进行初始化。

    VLIB_MAIN_LOOP_ENTER_FUNCTION注册一个链表,vlib_call_all_main_loop_enter_functions()函数遍历该链表。

    调用vlib_main_loop()

    vlib/main.c的vlib_main_loop()函数

    创建前面提到的相互协作的多线程,在while(1)循环中处理不同类型的图结点。

    ·         VLIB_NODE_TYPE_PRE_INPUT:类似DBG_CLI的结点

    ·        VLIB_NODE_TYPE_INPUT:这些是主要结点,主要从网卡或者硬件加速器获取数据包

    ·        进程等待信号,这个很重要,因为所有的客户端都要通过共享内存和VPP通信。客户端向共享内存发送一些API消息,并且向VPP发送信号(SIGUSR1)。

    输入结点组织数据包,并且将他们发送到合适的中间结点。由dispatch_pending_node()进一步处理这些数据包。

     1 int
     2 main (int argc, char *argv[])
     3 {
     4   int i;
     5   vlib_main_t *vm = &vlib_global_main;
     6   void vl_msg_api_set_first_available_msg_id (u16);
     7   uword main_heap_size = (1ULL << 30);
     8   u8 *sizep;
     9   u32 size;
    10   int main_core = 1;
    11   cpu_set_t cpuset;
    12 
    13 ..........
    14 
    15   /*
    16    * Look for and parse the "heapsize" config parameter.
    17    * Manual since none of the clib infra has been bootstrapped yet.
    18    *
    19    * Format: heapsize <nn>[mM][gG]
    20    */
    21 
    22   for (i = 1; i < (argc - 1); i++)
    23     {
    24       if (!strncmp (argv[i], "plugin_path", 11))
    25     {
    26       if (i < (argc - 1))
    27         vlib_plugin_path = argv[++i];
    28     }
    29       if (!strncmp (argv[i], "test_plugin_path", 16))
    30     {
    31       if (i < (argc - 1))
    32         vat_plugin_path = argv[++i];
    33     }
    34       else if (!strncmp (argv[i], "heapsize", 8))
    35     {
    36       sizep = (u8 *) argv[i + 1];
    37       size = 0;
    38       while (*sizep >= '0' && *sizep <= '9')
    39         {
    40           size *= 10;
    41           size += *sizep++ - '0';
    42         }
    43       if (size == 0)
    44         {
    45           fprintf
    46         (stderr,
    47          "warning: heapsize parse error '%s', use default %lld
    ",
    48          argv[i], (long long int) main_heap_size);
    49           goto defaulted;
    50         }
    51 
    52       main_heap_size = size;
    53 
    54       if (*sizep == 'g' || *sizep == 'G')
    55         main_heap_size <<= 30;
    56       else if (*sizep == 'm' || *sizep == 'M')
    57         main_heap_size <<= 20;
    58     }
    59       else if (!strncmp (argv[i], "main-core", 9))
    60     {
    61       if (i < (argc - 1))
    62         {
    63           errno = 0;
    64           unsigned long x = strtol (argv[++i], 0, 0);
    65           if (errno == 0)
    66         main_core = x;
    67         }
    68     }
    69     }
    70 
    71 defaulted:
    72 
    73   /* set process affinity for main thread */
    74   CPU_ZERO (&cpuset);
    75   CPU_SET (main_core, &cpuset);
    76   pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
    77 
    78   /* Set up the plugin message ID allocator right now... */
    79   vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
    80 
    81   /* Allocate main heap */
    82   if (clib_mem_init_thread_safe (0, main_heap_size))
    83     {
    84       vm->init_functions_called = hash_create (0, /* value bytes */ 0);
    85       vpe_main_init (vm);
    86       return vlib_unix_main (argc, argv);
    87     }
    88   else
    89     {
    90       {
    91     int rv __attribute__ ((unused)) =
    92       write (2, "Main heap allocation failure!
    ", 31);
    93       }
    94       return 1;
    95     }
    96 }

    vlib_unix_main函数

     1 int
     2 vlib_unix_main (int argc, char *argv[])
     3 {
     4   vlib_main_t *vm = &vlib_global_main;    /* one and only time for this! */
     5   unformat_input_t input;
     6   clib_error_t *e;
     7   int i;
     8 
     9   vm->argv = (u8 **) argv;
    10   vm->name = argv[0];
    11   vm->heap_base = clib_mem_get_heap ();
    12   vm->heap_aligned_base = (void *)
    13     (((uword) vm->heap_base) & ~(VLIB_FRAME_ALIGN - 1));
    14   ASSERT (vm->heap_base);
    15 
    16   unformat_init_command_line (&input, (char **) vm->argv);
    17   if ((e = vlib_plugin_config (vm, &input)))
    18     {
    19       clib_error_report (e);
    20       return 1;
    21     }
    22   unformat_free (&input);
    23 
    24   i = vlib_plugin_early_init (vm);
    25   if (i)
    26     return i;
    27 
    28   unformat_init_command_line (&input, (char **) vm->argv);
    29   if (vm->init_functions_called == 0)
    30     vm->init_functions_called = hash_create (0, /* value bytes */ 0);
    31   e = vlib_call_all_config_functions (vm, &input, 1 /* early */ );
    32   if (e != 0)
    33     {
    34       clib_error_report (e);
    35       return 1;
    36     }
    37   unformat_free (&input);
    38 
    39   /* always load symbols, for signal handler and mheap memory get/put backtrace */
    40   clib_elf_main_init (vm->name);
    41 
    42   vec_validate (vlib_thread_stacks, 0);
    43   vlib_thread_stack_init (0);
    44 
    45   __os_thread_index = 0;
    46   vm->thread_index = 0;
    47 
    48   i = clib_calljmp (thread0, (uword) vm,
    49             (void *) (vlib_thread_stacks[0] +
    50                   VLIB_THREAD_STACK_SIZE));
    51   return i;
    52 }

    thread0 -> vlib_main()  下面介绍vlib_main函数

    vlib_main

      1 int
      2 vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
      3 {
      4   clib_error_t *volatile error;
      5   vlib_node_main_t *nm = &vm->node_main;
      6 
      7   vm->queue_signal_callback = dummy_queue_signal_callback;
      8 
      9   clib_time_init (&vm->clib_time);
     10 
     11   /* Turn on event log. */
     12   if (!vm->elog_main.event_ring_size)
     13     vm->elog_main.event_ring_size = 128 << 10;
     14   elog_init (&vm->elog_main, vm->elog_main.event_ring_size);
     15   elog_enable_disable (&vm->elog_main, 1);
     16   vl_api_set_elog_main (&vm->elog_main);
     17   (void) vl_api_set_elog_trace_api_messages (1);
     18 
     19   /* Default name. */
     20   if (!vm->name)
     21     vm->name = "VLIB";
     22 
     23   if ((error = vlib_physmem_init (vm)))
     24     {
     25       clib_error_report (error);
     26       goto done;
     27     }
     28 
     29   if ((error = vlib_map_stat_segment_init (vm)))
     30     {
     31       clib_error_report (error);
     32       goto done;
     33     }
     34 
     35   if ((error = vlib_buffer_main_init (vm)))
     36     {
     37       clib_error_report (error);
     38       goto done;
     39     }
     40 
     41   if ((error = vlib_thread_init (vm)))
     42     {
     43       clib_error_report (error);
     44       goto done;
     45     }
     46 
     47   /* Register static nodes so that init functions may use them. */
     48   vlib_register_all_static_nodes (vm);
     49 
     50   /* Set seed for random number generator.
     51      Allow user to specify seed to make random sequence deterministic. */
     52   if (!unformat (input, "seed %wd", &vm->random_seed))
     53     vm->random_seed = clib_cpu_time_now ();
     54   clib_random_buffer_init (&vm->random_buffer, vm->random_seed);
     55 
     56   /* Initialize node graph. */
     57   if ((error = vlib_node_main_init (vm)))
     58     {
     59       /* Arrange for graph hook up error to not be fatal when debugging. */
     60       if (CLIB_DEBUG > 0)
     61     clib_error_report (error);
     62       else
     63     goto done;
     64     }
     65 
     66   /* Direct call / weak reference, for vlib standalone use-cases */
     67   if ((error = vpe_api_init (vm)))
     68     {
     69       clib_error_report (error);
     70       goto done;
     71     }
     72 
     73   if ((error = vlibmemory_init (vm)))
     74     {
     75       clib_error_report (error);
     76       goto done;
     77     }
     78 
     79   if ((error = map_api_segment_init (vm)))
     80     {
     81       clib_error_report (error);
     82       goto done;
     83     }
     84 
     85   /* See unix/main.c; most likely already set up */
     86   if (vm->init_functions_called == 0)
     87     vm->init_functions_called = hash_create (0, /* value bytes */ 0);
     88   if ((error = vlib_call_all_init_functions (vm)))
     89     goto done;
     90 
     91   nm->timing_wheel = clib_mem_alloc_aligned (sizeof (TWT (tw_timer_wheel)),
     92                          CLIB_CACHE_LINE_BYTES);
     93 
     94   vec_validate (nm->data_from_advancing_timing_wheel, 10);
     95   _vec_len (nm->data_from_advancing_timing_wheel) = 0;
     96 
     97   /* Create the process timing wheel */
     98   TW (tw_timer_wheel_init) ((TWT (tw_timer_wheel) *) nm->timing_wheel,
     99                 0 /* no callback */ ,
    100                 10e-6 /* timer period 10us */ ,
    101                 ~0 /* max expirations per call */ );
    102 
    103   vec_validate (vm->pending_rpc_requests, 0);
    104   _vec_len (vm->pending_rpc_requests) = 0;
    105   vec_validate (vm->processing_rpc_requests, 0);
    106   _vec_len (vm->processing_rpc_requests) = 0;
    107 
    108   if ((error = vlib_call_all_config_functions (vm, input, 0 /* is_early */ )))
    109     goto done;
    110 
    111   /* Sort per-thread init functions before we start threads */
    112   vlib_sort_init_exit_functions (&vm->worker_init_function_registrations);
    113 
    114   /* Call all main loop enter functions. */
    115   {
    116     clib_error_t *sub_error;
    117     sub_error = vlib_call_all_main_loop_enter_functions (vm);
    118     if (sub_error)
    119       clib_error_report (sub_error);
    120   }
    121 
    122   switch (clib_setjmp (&vm->main_loop_exit, VLIB_MAIN_LOOP_EXIT_NONE))
    123     {
    124     case VLIB_MAIN_LOOP_EXIT_NONE:
    125       vm->main_loop_exit_set = 1;
    126       break;
    127 
    128     case VLIB_MAIN_LOOP_EXIT_CLI:
    129       goto done;
    130 
    131     default:
    132       error = vm->main_loop_error;
    133       goto done;
    134     }
    135 
    136   vlib_main_loop (vm);
    137 
    138 done:
    139   /* Call all exit functions. */
    140   {
    141     clib_error_t *sub_error;
    142     sub_error = vlib_call_all_main_loop_exit_functions (vm);
    143     if (sub_error)
    144       clib_error_report (sub_error);
    145   }
    146 
    147   if (error)
    148     clib_error_report (error);
    149 
    150   return 0;
    151 }

     

  • 相关阅读:
    Centos7安装redis
    Cookie和Session的区别
    JavaWeb中的域对象
    ServletContext使用介绍
    Java Web核心组件之Servlet的使用介绍
    关于反射的杂谈
    leetcode117search-in-rotated-sorted-array
    23longest-consecutive-sequence
    leetcode24:word-ladder-ii
    leetcode25word-ladder
  • 原文地址:https://www.cnblogs.com/mysky007/p/12735682.html
Copyright © 2020-2023  润新知