vpp初始化接功能节点如acl、icmp、abf等都是通过VLIB_INIT_FUNCTION宏定义进行初始化的,初始化过程主要包括运行环境、内存、以及对应功能的一些初始化,如acl初始化的地方:
static clib_error_t *
acl_init (vlib_main_t * vm)
{
acl_main_t *am = &acl_main;
clib_error_t *error = 0;
clib_memset (am, 0, sizeof (*am));
am->vlib_main = vm;
am->vnet_main = vnet_get_main ();
am->log_default = vlib_log_register_class ("acl_plugin", 0);
u8 *name = format (0, "acl_%08x%c", api_version, 0);
/* Ask for a correctly-sized block of API message decode slots */
am->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
VL_MSG_FIRST_AVAILABLE);
error = acl_plugin_api_hookup (vm);
/* Add our API messages to the global name_crc hash table */
setup_message_id_table (am, &api_main);
vec_free (name);
if (error)
return error;
error = acl_plugin_exports_init (&acl_plugin);
if (error)
return error;
am->acl_mheap_size = 0; /* auto size when initializing */
am->hash_lookup_mheap_size = ACL_PLUGIN_HASH_LOOKUP_HEAP_SIZE;
am->hash_lookup_hash_buckets = ACL_PLUGIN_HASH_LOOKUP_HASH_BUCKETS;
am->hash_lookup_hash_memory = ACL_PLUGIN_HASH_LOOKUP_HASH_MEMORY;
am->session_timeout_sec[ACL_TIMEOUT_TCP_TRANSIENT] =
TCP_SESSION_TRANSIENT_TIMEOUT_SEC;
am->session_timeout_sec[ACL_TIMEOUT_TCP_IDLE] =
TCP_SESSION_IDLE_TIMEOUT_SEC;
am->session_timeout_sec[ACL_TIMEOUT_UDP_IDLE] =
UDP_SESSION_IDLE_TIMEOUT_SEC;
am->fa_conn_table_hash_num_buckets =
ACL_FA_CONN_TABLE_DEFAULT_HASH_NUM_BUCKETS;
am->fa_conn_table_hash_memory_size =
ACL_FA_CONN_TABLE_DEFAULT_HASH_MEMORY_SIZE;
am->fa_conn_table_max_entries = ACL_FA_CONN_TABLE_DEFAULT_MAX_ENTRIES;
am->reclassify_sessions = 0;
vlib_thread_main_t *tm = vlib_get_thread_main ();
am->fa_min_deleted_sessions_per_interval =
ACL_FA_DEFAULT_MIN_DELETED_SESSIONS_PER_INTERVAL;
am->fa_max_deleted_sessions_per_interval =
ACL_FA_DEFAULT_MAX_DELETED_SESSIONS_PER_INTERVAL;
am->fa_cleaner_wait_time_increment =
ACL_FA_DEFAULT_CLEANER_WAIT_TIME_INCREMENT;
vec_validate (am->per_worker_data, tm->n_vlib_mains - 1);
{
u16 wk;
for (wk = 0; wk < vec_len (am->per_worker_data); wk++)
{
acl_fa_per_worker_data_t *pw = &am->per_worker_data[wk];
if (tm->n_vlib_mains > 1)
{
clib_spinlock_init (&pw->pending_session_change_request_lock);
}
vec_validate (pw->expired,
ACL_N_TIMEOUTS *
am->fa_max_deleted_sessions_per_interval);
_vec_len (pw->expired) = 0;
vec_validate_init_empty (pw->fa_conn_list_head, ACL_N_TIMEOUTS - 1,
FA_SESSION_BOGUS_INDEX);
vec_validate_init_empty (pw->fa_conn_list_tail, ACL_N_TIMEOUTS - 1,
FA_SESSION_BOGUS_INDEX);
vec_validate_init_empty (pw->fa_conn_list_head_expiry_time,
ACL_N_TIMEOUTS - 1, ~0ULL);
}
}
am->fa_cleaner_cnt_delete_by_sw_index = 0;
am->fa_cleaner_cnt_delete_by_sw_index_ok = 0;
am->fa_cleaner_cnt_unknown_event = 0;
am->fa_cleaner_cnt_timer_restarted = 0;
am->fa_cleaner_cnt_wait_with_timeout = 0;
#define _(N, v, s) am->fa_ipv6_known_eh_bitmap = clib_bitmap_set(am->fa_ipv6_known_eh_bitmap, v, 1);
foreach_acl_eh
#undef _
am->l4_match_nonfirst_fragment = 1;
/* use the new fancy hash-based matching */
am->use_hash_acl_matching = 1;
/* use tuplemerge by default */
am->use_tuple_merge = 1;
/* Set the default threshold */
am->tuple_merge_split_threshold = TM_SPLIT_THRESHOLD;
am->interface_acl_user_id =
acl_plugin.register_user_module ("interface ACL", "sw_if_index",
"is_input");
am->acl_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
CLIB_CACHE_LINE_BYTES);
am->acl_counter_lock[0] = 0; /* should be no need */
return error;
}
VLIB_INIT_FUNCTION (acl_init);
VLIB_INIT_FUNCTION 宏定义展开如下所示,主要由VLIB_DECLARE_INIT_FUNCTION宏定义完成注册动作:
#ifndef CLIB_MARCH_VARIANT
#define VLIB_DECLARE_INIT_FUNCTION(x, tag) \
vlib_init_function_t * _VLIB_INIT_FUNCTION_SYMBOL (x, tag) = x; \
static void __vlib_add_##tag##_function_##x (void) \
__attribute__((__constructor__)) ; \
static _vlib_init_function_list_elt_t _vlib_init_function_##tag_##x; \
static void __vlib_add_##tag##_function_##x (void) \
{ \
vlib_main_t * vm = vlib_get_main(); \
_vlib_init_function_##tag_##x.next_init_function \
= vm->tag##_function_registrations; \
vm->tag##_function_registrations = &_vlib_init_function_##tag_##x; \
_vlib_init_function_##tag_##x.f = &x; \
_vlib_init_function_##tag_##x.name = #x; \
} \
static void __vlib_rm_##tag##_function_##x (void) \
__attribute__((__destructor__)) ; \
static void __vlib_rm_##tag##_function_##x (void) \
{ \
vlib_main_t * vm = vlib_get_main(); \
_vlib_init_function_list_elt_t *this, *prev; \
this = vm->tag##_function_registrations; \
if (this == 0) \
return; \
if (this->f == &x) \
{ \
vm->tag##_function_registrations = this->next_init_function; \
return; \
} \
prev = this; \
this = this->next_init_function; \
while (this) \
{ \
if (this->f == &x) \
{ \
prev->next_init_function = \
this->next_init_function; \
return; \
} \
prev = this; \
this = this->next_init_function; \
} \
} \
static _vlib_init_function_list_elt_t _vlib_init_function_##tag_##x
#else
/* create unused pointer to silence compiler warnings and get whole
function optimized out */
#define VLIB_DECLARE_INIT_FUNCTION(x, tag) \
static __clib_unused void * __clib_unused_##tag##_##x = x
#endif
#define VLIB_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,init)
VLIB_INIT_FUNCTION宏定义中的x表示注册的函数,传递给VLIB_DECLARE_INIT_FUNCTION宏定义并添加第二个参数init,VLIB_DECLARE_INIT_FUNCTION宏定义主要由两个自动构造的函数组成,一个是注册函数、一个是卸载函数。
首先构造初始化函数,_VLIB_INIT_FUNCTION_SYMBOL宏定义构造函数头:申明类型为:vlib_init_function_t *的变量_vlib_init_function_acl_init=acl_init,然后构造 __vlib_add_init_function_acl_init 函数并修改函数属性为 _attribute_((_constructor_)),然后再申明类型为_vlib_init_function_list_elt_t的静态变量_vlib_init_function_init_acl_init,最后实现__vlib_add_init_function_acl_init函数方法:
static void __vlib_add_##tag##_function_##x (void) \
{ \
vlib_main_t * vm = vlib_get_main(); \
_vlib_init_function_##tag_##x.next_init_function \
= vm->tag##_function_registrations; \
vm->tag##_function_registrations = &_vlib_init_function_##tag_##x; \
_vlib_init_function_##tag_##x.f = &x; \
_vlib_init_function_##tag_##x.name = #x; \
}
首先使用vlib_get_main或者全局变量vlib_mains,然后把_vlib_init_function_init_acl_init结构体的next_init_function指针指向vlib_mains结构体的init_function_registrations变量,同时把vlib_mains结构体的init_function_registrations变量更改为_vlib_init_function_init_acl_init结构体,这个过程相当于添加当前注册函数到init_function_registrations链表头。最后初始化_vlib_init_function_init_acl_init结构体的函数指针f指向节点的注册函数acl_init和name变量为初始化函数名acl_init。
当vpp启动时根据以下路径对init_function_registrations链表中的注册函数进行调用完成初始化工作
main--->
vlib_unix_main (argc, argv);--->
clib_calljmp (thread0, (uword) vm,(void *) (vlib_thread_stacks[0] +VLIB_THREAD_STACK_SIZE));--->
vlib_main (vm, &input);--->
vlib_call_all_init_functions (vm)--->
vlib_call_init_exit_functions(vm, &vm->init_function_registrations, 1 /* call_once */ );--->
call_init_exit_functions_internal (vm, headp, call_once,1 /* do_sort */ );
static inline clib_error_t *
call_init_exit_functions_internal (vlib_main_t * vm,
_vlib_init_function_list_elt_t ** headp,
int call_once, int do_sort)
{
clib_error_t *error = 0;
_vlib_init_function_list_elt_t *i;
if (do_sort && (error = vlib_sort_init_exit_functions (headp)))
return (error);
i = *headp;
while (i)
{
if (call_once && !hash_get (vm->init_functions_called, i->f))
{
if (call_once)
hash_set1 (vm->init_functions_called, i->f);
error = i->f (vm);
if (error)
return error;
}
i = i->next_init_function;
}
return error;
}
节点注销的注册和初始化注册类似