Cisco VPP VLIB_INIT_FUNCTION宏定义分析

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;
}

节点注销的注册和初始化注册类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值