diff options
Diffstat (limited to 'src/vnet/adj/adj_glean.c')
-rw-r--r-- | src/vnet/adj/adj_glean.c | 121 |
1 files changed, 96 insertions, 25 deletions
diff --git a/src/vnet/adj/adj_glean.c b/src/vnet/adj/adj_glean.c index e8ca043662f..ceece0d74ed 100644 --- a/src/vnet/adj/adj_glean.c +++ b/src/vnet/adj/adj_glean.c @@ -45,7 +45,7 @@ adj_glean_db_lookup (fib_protocol_t proto, { uword *p; - if (vec_len(adj_gleans[proto]) <= sw_if_index) + if ((proto >= FIB_PROTOCOL_IP_MAX) || vec_len(adj_gleans[proto]) <= sw_if_index) return (ADJ_INDEX_INVALID); p = hash_get_mem (adj_gleans[proto][sw_if_index], nh_addr); @@ -66,6 +66,7 @@ adj_glean_db_insert (fib_protocol_t proto, vlib_worker_thread_barrier_sync(vm); + ASSERT(proto < FIB_PROTOCOL_IP_MAX); vec_validate(adj_gleans[proto], sw_if_index); if (NULL == adj_gleans[proto][sw_if_index]) @@ -186,6 +187,38 @@ adj_glean_update_rewrite_walk (adj_index_t ai, return (ADJ_WALK_RC_CONTINUE); } +static void +adj_glean_walk_proto (fib_protocol_t proto, + u32 sw_if_index, + adj_walk_cb_t cb, + void *data) +{ + adj_index_t ai, *aip, *ais = NULL; + ip46_address_t *conn; + + ASSERT(proto < FIB_PROTOCOL_IP_MAX); + if (vec_len(adj_gleans[proto]) <= sw_if_index || + NULL == adj_gleans[proto][sw_if_index]) + return; + + /* + * Walk first to collect the indices + * then walk the collection. This is safe + * to modifications of the hash table + */ + hash_foreach_mem(conn, ai, adj_gleans[proto][sw_if_index], + ({ + vec_add1(ais, ai); + })); + + vec_foreach(aip, ais) + { + if (ADJ_WALK_RC_STOP == cb(*aip, data)) + break; + } + vec_free(ais); +} + void adj_glean_walk (u32 sw_if_index, adj_walk_cb_t cb, @@ -195,29 +228,7 @@ adj_glean_walk (u32 sw_if_index, FOR_EACH_FIB_IP_PROTOCOL(proto) { - adj_index_t ai, *aip, *ais = NULL; - ip46_address_t *conn; - - if (vec_len(adj_gleans[proto]) <= sw_if_index || - NULL == adj_gleans[proto][sw_if_index]) - continue; - - /* - * Walk first to collect the indices - * then walk the collection. This is safe - * to modifications of the hash table - */ - hash_foreach_mem(conn, ai, adj_gleans[proto][sw_if_index], - ({ - vec_add1(ais, ai); - })); - - vec_foreach(aip, ais) - { - if (ADJ_WALK_RC_STOP == cb(*aip, data)) - break; - } - vec_free(ais); + adj_glean_walk_proto (proto, sw_if_index, cb, data); } } @@ -235,6 +246,7 @@ adj_glean_get (fib_protocol_t proto, ip46_address_t *conn; adj_index_t ai; + ASSERT(proto < FIB_PROTOCOL_IP_MAX); if (vec_len(adj_gleans[proto]) <= sw_if_index || NULL == adj_gleans[proto][sw_if_index]) return (ADJ_INDEX_INVALID); @@ -256,6 +268,7 @@ adj_glean_get_src (fib_protocol_t proto, const ip_adjacency_t *adj; adj_index_t ai; + ASSERT(proto < FIB_PROTOCOL_IP_MAX); if (vec_len(adj_gleans[proto]) <= sw_if_index || NULL == adj_gleans[proto][sw_if_index]) return (NULL); @@ -424,11 +437,59 @@ VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_glean_interface_delete); */ static void adj_glean_ethernet_change_mac (ethernet_main_t * em, - u32 sw_if_index, uword opaque) + u32 sw_if_index, + uword opaque) { adj_glean_walk (sw_if_index, adj_glean_update_rewrite_walk, NULL); } +static void +adj_glean_table_bind (fib_protocol_t fproto, + u32 sw_if_index, + u32 itf_fib_index) +{ + /* + * for each glean on the interface trigger a walk back to the children + */ + fib_node_back_walk_ctx_t bw_ctx = { + .fnbw_reason = FIB_NODE_BW_REASON_FLAG_INTERFACE_BIND, + .interface_bind = { + .fnbw_to_fib_index = itf_fib_index, + }, + }; + + adj_glean_walk_proto (fproto, sw_if_index, adj_glean_start_backwalk, &bw_ctx); +} + + +/** + * Callback function invoked when an interface's IPv6 Table + * binding changes + */ +static void +adj_glean_ip6_table_bind (ip6_main_t * im, + uword opaque, + u32 sw_if_index, + u32 new_fib_index, + u32 old_fib_index) +{ + adj_glean_table_bind (FIB_PROTOCOL_IP6, sw_if_index, new_fib_index); +} + +/** + * Callback function invoked when an interface's IPv4 Table + * binding changes + */ +static void +adj_glean_ip4_table_bind (ip4_main_t * im, + uword opaque, + u32 sw_if_index, + u32 new_fib_index, + u32 old_fib_index) +{ + adj_glean_table_bind (FIB_PROTOCOL_IP4, sw_if_index, new_fib_index); +} + u8* format_adj_glean (u8* s, va_list *ap) { @@ -519,4 +580,14 @@ adj_glean_module_init (void) .function_opaque = 0, }; vec_add1 (ethernet_main.address_change_callbacks, ctx); + + ip6_table_bind_callback_t cbt6 = { + .function = adj_glean_ip6_table_bind, + }; + vec_add1 (ip6_main.table_bind_callbacks, cbt6); + + ip4_table_bind_callback_t cbt4 = { + .function = adj_glean_ip4_table_bind, + }; + vec_add1 (ip4_main.table_bind_callbacks, cbt4); } |