一、入口函数位置:
/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 [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后续解释
如果申请动态内存失败,则打印错误消息,并结束进程。