VPP程式碼閱讀中文註解(一)
阿新 • • 發佈:2018-11-07
一、入口函式位置:
/src/vpp/vnet/main.c中的main函式開始。
二、程式碼註解
int main (int argc, char *argv[]) { int i; vlib_main_t *vm = &vlib_global_main; void vl_msg_api_set_first_available_msg_id (u16); uword main_heap_size = (1ULL << 30); u8 *sizep; u32 size; int main_core = 1; cpu_set_t cpuset; #if __x86_64__ CLIB_UNUSED (const char *msg) = "ERROR: This binary requires CPU with %s extensions.\n"; #define _(a,b) \ if (!clib_cpu_supports_ ## a ()) \ { \ fprintf(stderr, msg, b); \ exit(1); \ } #if __AVX2__ _(avx2, "AVX2") #endif #if __AVX__ _(avx, "AVX") #endif #if __SSE4_2__ _(sse42, "SSE4.2") #endif #if __SSE4_1__ _(sse41, "SSE4.1") #endif #if __SSSE3__ _(ssse3, "SSSE3") #endif #if __SSE3__ _(sse3, "SSE3") #endif #undef _ #endif
這一堆巨集主要檢查各種CPU的擴充套件功能,編譯器的配置情況是否與實際一致。如果不一致,則列印錯誤資訊,並返回。這個時候應該修改原始碼或者編譯指令碼中的編譯巨集。
/* * Load startup config from file. * usage: vpp -c /etc/vpp/startup.conf */ if ((argc == 3) && !strncmp (argv[1], "-c", 2)) { FILE *fp; char inbuf[4096]; int argc_ = 1; char **argv_ = NULL; char *arg = NULL; char *p; fp = fopen (argv[2], "r"); if (fp == NULL) { fprintf (stderr, "open configuration file '%s' failed\n", argv[2]); return 1; } argv_ = calloc (1, sizeof (char *)); if (argv_ == NULL) return 1; arg = strndup (argv[0], 1024); if (arg == NULL) return 1; argv_[0] = arg; while (1) { if (fgets (inbuf, 4096, fp) == 0) break; p = strtok (inbuf, " \t\n"); while (p != NULL) { if (*p == '#') break; argc_++; char **tmp = realloc (argv_, argc_ * sizeof (char *)); if (tmp == NULL) return 1; argv_ = tmp; arg = strndup (p, 1024); if (arg == NULL) return 1; argv_[argc_ - 1] = arg; p = strtok (NULL, " \t\n"); } } fclose (fp); char **tmp = realloc (argv_, (argc_ + 1) * sizeof (char *)); if (tmp == NULL) return 1; argv_ = tmp; argv_[argc_] = NULL; argc = argc_; argv = argv_; }
上述程式碼主要將 /etc/vpp/startup.conf 檔案中的內容讀出來,並重新組成argv引數,供後續使用。即vpp執行時,有2種命令列引數獲取方式:
1. vpp -c /etc/vpp/startup.conf //實際引數在最後這個檔案中
2. vpp arg1 arg2 ... //實際引數即arg1, arg2 , ....
/* * Look for and parse the "heapsize" config parameter. * Manual since none of the clib infra has been bootstrapped yet. * * Format: heapsize <nn>[mM][gG] */ for (i = 1; i < (argc - 1); i++) { if (!strncmp (argv[i], "plugin_path", 11)) { if (i < (argc - 1)) vlib_plugin_path = argv[++i]; } else if (!strncmp (argv[i], "heapsize", 8)) { sizep = (u8 *) argv[i + 1]; size = 0; while (*sizep >= '0' && *sizep <= '9') { size *= 10; size += *sizep++ - '0'; } if (size == 0) { fprintf (stderr, "warning: heapsize parse error '%s', use default %lld\n", argv[i], (long long int) main_heap_size); goto defaulted; } main_heap_size = size; if (*sizep == 'g' || *sizep == 'G') main_heap_size <<= 30; else if (*sizep == 'm' || *sizep == 'M') main_heap_size <<= 20; } else if (!strncmp (argv[i], "main-core", 9)) { if (i < (argc - 1)) { errno = 0; unsigned long x = strtol (argv[++i], 0, 0); if (errno == 0) main_core = x; } } }
上述程式碼遍歷所有的命令列引數,先尋找並解析 plugin_path,heapsize, main-core。 因為接下來很快就要用到。注意M代表metabytes, g代表gigabytes。
defaulted:
/* set process affinity for main thread */
CPU_ZERO (&cpuset);
CPU_SET (main_core, &cpuset);
pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t), &cpuset);
/* Set up the plugin message ID allocator right now... */
vl_msg_api_set_first_available_msg_id (VL_MSG_FIRST_AVAILABLE);
/* Allocate main heap */
if (clib_mem_init_thread_safe (0, main_heap_size))
{
vm->init_functions_called = hash_create (0, /* value bytes */ 0);
vpe_main_init (vm);
return vlib_unix_main (argc, argv);
}
else
{
{
int rv __attribute__ ((unused)) =
write (2, "Main heap allocation failure!\r\n", 31);
}
return 1;
}
}
上述程式碼將本程序繫結到main-core引數對應的CPU上, 根據heapsize引數來預申請本VPP例項用到的動態記憶體空間,
建立init_functions_called雜湊表--主要用於記錄哪些初始化函式已經得到呼叫
vl_msg_api_set_first_available_msg_id,vpe_main_init,vlib_unix_main後續解釋
如果申請動態記憶體失敗,則列印錯誤訊息,並結束程序。