diff options
author | Eyal Bari <ebari@cisco.com> | 2017-09-20 11:29:17 +0300 |
---|---|---|
committer | John Lo <loj@cisco.com> | 2017-09-22 01:55:33 +0000 |
commit | c125eccc10db9c0b9c5d161d3ad20b4fc8c69b26 (patch) | |
tree | af209e8188ebc6d8ae8719a6307117acd5e41063 /src | |
parent | 03add7f5b5e5351790187ea6d7e83803d5be2440 (diff) |
IP-MAC,ND:wildcard events,fix sending multiple events
wildcard ND events publisher was sending the last event mutiple times
Change-Id: I6c30f2de03fa825e79df9005a3cfaaf68ff7ea2f
Signed-off-by: Eyal Bari <ebari@cisco.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/vlibapi/api_helper_macros.h | 1 | ||||
-rw-r--r-- | src/vnet/ethernet/arp.c | 12 | ||||
-rw-r--r-- | src/vnet/ethernet/ethernet.h | 2 | ||||
-rw-r--r-- | src/vnet/ip/ip6_neighbor.c | 73 | ||||
-rw-r--r-- | src/vnet/ip/ip6_neighbor.h | 8 | ||||
-rw-r--r-- | src/vpp/api/api.c | 221 |
6 files changed, 216 insertions, 101 deletions
diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h index 13734896298..052cc6e78b5 100644 --- a/src/vlibapi/api_helper_macros.h +++ b/src/vlibapi/api_helper_macros.h @@ -216,6 +216,7 @@ _(to_netconf_client) \ _(from_netconf_client) \ _(oam_events) \ _(bfd_events) \ +_(wc_ip6_nd_events) \ _(wc_ip4_arp_events) typedef struct diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index 2f3aa6c73ac..e974d2551e5 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -94,6 +94,7 @@ typedef struct ethernet_proxy_arp_t *proxy_arps; uword wc_ip4_arp_publisher_node; + uword wc_ip4_arp_publisher_et; } ethernet_arp_main_t; static ethernet_arp_main_t ethernet_arp_main; @@ -1536,21 +1537,24 @@ vnet_arp_wc_publish_internal (vnet_main_t * vnm, { vlib_main_t *vm = vlib_get_main (); ethernet_arp_main_t *am = ðernet_arp_main; - if (am->wc_ip4_arp_publisher_node == (uword) ~ 0) + uword ni = am->wc_ip4_arp_publisher_node; + uword et = am->wc_ip4_arp_publisher_et; + + if (ni == (uword) ~ 0) return; wc_arp_report_t *r = - vlib_process_signal_event_data (vm, am->wc_ip4_arp_publisher_node, 1, 1, - sizeof *r); + vlib_process_signal_event_data (vm, ni, et, 1, sizeof *r); r->ip4 = args->a.ip4.as_u32; r->sw_if_index = args->sw_if_index; memcpy (r->mac, args->a.ethernet, sizeof r->mac); } void -wc_arp_set_publisher_node (uword node_index) +wc_arp_set_publisher_node (uword node_index, uword event_type) { ethernet_arp_main_t *am = ðernet_arp_main; am->wc_ip4_arp_publisher_node = node_index; + am->wc_ip4_arp_publisher_et = event_type; } /* diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index 1a9e9790869..a6846b13ffc 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -543,7 +543,7 @@ int vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm, uword type_opaque, uword data, int is_add); -void wc_arp_set_publisher_node (uword inode_index); +void wc_arp_set_publisher_node (uword inode_index, uword event_type); void ethernet_arp_change_mac (u32 sw_if_index); void ethernet_ndp_change_mac (u32 sw_if_index); diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 345ebd34518..1908a679e2e 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -195,6 +195,9 @@ typedef struct u32 limit_neighbor_cache_size; u32 neighbor_delete_rotor; + /* Wildcard nd report publisher */ + uword wc_ip6_nd_publisher_node; + uword wc_ip6_nd_publisher_et; } ip6_neighbor_main_t; /* ipv6 neighbor discovery - timer/event types */ @@ -216,6 +219,50 @@ typedef union static ip6_neighbor_main_t ip6_neighbor_main; static ip6_address_t ip6a_zero; /* ip6 address 0 */ +static void wc_nd_signal_report (wc_nd_report_t * r); + +/** + * @brief publish wildcard arp event + * @param sw_if_index The interface on which the ARP entires are acted + */ +static int +vnet_nd_wc_publish (u32 sw_if_index, u8 * mac, ip6_address_t * ip6) +{ + wc_nd_report_t r = { + .sw_if_index = sw_if_index, + .ip6 = *ip6, + }; + memcpy (r.mac, mac, sizeof r.mac); + + void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); + vl_api_rpc_call_main_thread (wc_nd_signal_report, (u8 *) & r, sizeof r); + return 0; +} + +static void +wc_nd_signal_report (wc_nd_report_t * r) +{ + vlib_main_t *vm = vlib_get_main (); + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + uword ni = nm->wc_ip6_nd_publisher_node; + uword et = nm->wc_ip6_nd_publisher_et; + + if (ni == (uword) ~ 0) + return; + wc_nd_report_t *q = + vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q); + + *q = *r; +} + +void +wc_nd_set_publisher_node (uword node_index, uword event_type) +{ + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + nm->wc_ip6_nd_publisher_node = node_index; + nm->wc_ip6_nd_publisher_et = event_type; +} + static u8 * format_ip6_neighbor_ip6_entry (u8 * s, va_list * va) { @@ -3931,6 +3978,8 @@ ip6_neighbor_init (vlib_main_t * vm) /* default, configurable */ nm->limit_neighbor_cache_size = 50000; + nm->wc_ip6_nd_publisher_node = (uword) ~ 0; + #if 0 /* $$$$ Hack fix for today */ vec_validate_init_empty @@ -4047,7 +4096,6 @@ vnet_ip6_nd_term (vlib_main_t * vm, { ip6_neighbor_main_t *nm = &ip6_neighbor_main; icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; - pending_resolution_t *mc; ndh = ip6_next_header (ip); if (ndh->icmp.type != ICMP6_neighbor_solicitation && @@ -4063,26 +4111,11 @@ vnet_ip6_nd_term (vlib_main_t * vm, } /* Check if anyone want ND events for L2 BDs */ - uword *p = mhash_get (&nm->mac_changes_by_address, &ip6a_zero); - if (p && !ip6_address_is_link_local_unicast (&ip->src_address)) + if (PREDICT_FALSE + (nm->wc_ip6_nd_publisher_node != (uword) ~ 0 + && !ip6_address_is_link_local_unicast (&ip->src_address))) { - u32 next_index = p[0]; - while (next_index != (u32) ~ 0) - { - int (*fp) (u32, u8 *, u32, ip6_address_t *); - int rv = 1; - mc = pool_elt_at_index (nm->mac_changes, next_index); - fp = mc->data_callback; - /* Call the callback, return 1 to suppress dup events */ - if (fp) - rv = (*fp) (mc->data, - eth->src_address, sw_if_index, &ip->src_address); - /* Signal the resolver process */ - if (rv == 0) - vlib_process_signal_event (vm, mc->node_index, - mc->type_opaque, mc->data); - next_index = mc->next_index; - } + vnet_nd_wc_publish (sw_if_index, eth->src_address, &ip->src_address); } /* Check if MAC entry exsist for solicited target IP */ diff --git a/src/vnet/ip/ip6_neighbor.h b/src/vnet/ip/ip6_neighbor.h index 0e302ed4a49..ed80381b35c 100644 --- a/src/vnet/ip/ip6_neighbor.h +++ b/src/vnet/ip/ip6_neighbor.h @@ -89,6 +89,14 @@ extern int ip6_neighbor_proxy_add_del (u32 sw_if_index, u32 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add); +typedef struct +{ + u32 sw_if_index; + ip6_address_t ip6; + u8 mac[6]; +} wc_nd_report_t; + +void wc_nd_set_publisher_node (uword node_index, uword event_type); #endif /* included_ip6_neighbor_h */ diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index e229a5e347f..d020314bfb1 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -1345,8 +1345,6 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac, vpe_api_main_t *am = &vpe_api_main; vlib_main_t *vm = am->vlib_main; vl_api_ip4_arp_event_t *event; - static f64 arp_event_last_time; - f64 now = vlib_time_now (vm); if (pool_is_free_index (am->arp_events, pool_index)) return 1; @@ -1360,7 +1358,6 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac, clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac)); event->sw_if_index = htonl (sw_if_index); - arp_event_last_time = now; return 0; } @@ -1371,35 +1368,19 @@ nd_change_data_callback (u32 pool_index, u8 * new_mac, vpe_api_main_t *am = &vpe_api_main; vlib_main_t *vm = am->vlib_main; vl_api_ip6_nd_event_t *event; - static f64 nd_event_last_time; - f64 now = vlib_time_now (vm); if (pool_is_free_index (am->nd_events, pool_index)) return 1; event = pool_elt_at_index (am->nd_events, pool_index); - - /* *INDENT-OFF* */ - if (memcmp (event->new_mac, new_mac, sizeof (event->new_mac))) + if (eth_mac_equal (event->new_mac, new_mac) && + sw_if_index == ntohl (event->sw_if_index)) { - clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac)); - } - else - { /* same mac */ - if (sw_if_index == ntohl(event->sw_if_index) && - (!event->mac_ip || - /* for BD case, also check IP address with 10 sec timeout */ - (ip6_address_is_equal (address, - (ip6_address_t *) event->address) && - (now - nd_event_last_time) < 10.0))) - return 1; + return 1; } - /* *INDENT-ON* */ - nd_event_last_time = now; + clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac)); event->sw_if_index = htonl (sw_if_index); - if (event->mac_ip) - clib_memcpy (event->address, address, sizeof (event->address)); return 0; } @@ -1427,61 +1408,107 @@ nd_change_delete_callback (u32 pool_index, u8 * notused) return 0; } -static vlib_node_registration_t wc_ip4_arp_process_node; +static vlib_node_registration_t wc_arp_process_node; + +enum +{ WC_ARP_REPORT, WC_ND_REPORT }; static uword -wc_ip4_arp_process (vlib_main_t * vm, - vlib_node_runtime_t * rt, vlib_frame_t * f) +wc_arp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { /* These cross the longjmp boundry (vlib_process_wait_for_event) * and need to be volatile - to prevent them from being optimized into * a register - which could change during suspension */ - volatile wc_arp_report_t prev = { 0 }; - volatile f64 last = vlib_time_now (vm); + volatile wc_arp_report_t arp_prev = { 0 }; + volatile wc_nd_report_t nd_prev = { 0 }; + volatile f64 last_arp = vlib_time_now (vm); + volatile f64 last_nd = vlib_time_now (vm); while (1) { vlib_process_wait_for_event (vm); uword event_type; - wc_arp_report_t *event_data = - vlib_process_get_event_data (vm, &event_type); + void *event_data = vlib_process_get_event_data (vm, &event_type); f64 now = vlib_time_now (vm); int i; - for (i = 0; i < vec_len (event_data); i++) + if (event_type == WC_ARP_REPORT) + { + wc_arp_report_t *arp_events = event_data; + for (i = 0; i < vec_len (arp_events); i++) + { + /* discard dup event */ + if (arp_prev.ip4 == arp_events[i].ip4 && + eth_mac_equal ((u8 *) arp_prev.mac, arp_events[i].mac) && + arp_prev.sw_if_index == arp_events[i].sw_if_index && + (now - last_arp) < 10.0) + { + continue; + } + arp_prev = arp_events[i]; + last_arp = now; + vpe_client_registration_t *reg; + /* *INDENT-OFF* */ + pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations, + ({ + unix_shared_memory_queue_t *q; + q = vl_api_client_index_to_input_queue (reg->client_index); + if (q && q->cursize < q->maxsize) + { + vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event); + memset (event, 0, sizeof *event); + event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT); + event->client_index = reg->client_index; + event->pid = reg->client_pid; + event->mac_ip = 1; + event->address = arp_events[i].ip4; + event->sw_if_index = htonl(arp_events[i].sw_if_index); + memcpy(event->new_mac, arp_events[i].mac, sizeof event->new_mac); + vl_msg_api_send_shmem (q, (u8 *) &event); + } + })); + /* *INDENT-ON* */ + } + } + else if (event_type == WC_ND_REPORT) { - /* discard dup event */ - if (prev.ip4 == event_data[i].ip4 && - eth_mac_equal ((u8 *) prev.mac, event_data[i].mac) && - prev.sw_if_index == event_data[i].sw_if_index && - (now - last) < 10.0) + wc_nd_report_t *nd_events = event_data; + for (i = 0; i < vec_len (nd_events); i++) { - continue; + /* discard dup event */ + if (ip6_address_is_equal + ((ip6_address_t *) & nd_prev.ip6, &nd_events[i].ip6) + && eth_mac_equal ((u8 *) nd_prev.mac, nd_events[i].mac) + && nd_prev.sw_if_index == nd_events[i].sw_if_index + && (now - last_nd) < 10.0) + { + continue; + } + nd_prev = nd_events[i]; + last_nd = now; + vpe_client_registration_t *reg; + /* *INDENT-OFF* */ + pool_foreach(reg, vpe_api_main.wc_ip6_nd_events_registrations, + ({ + unix_shared_memory_queue_t *q; + q = vl_api_client_index_to_input_queue (reg->client_index); + if (q && q->cursize < q->maxsize) + { + vl_api_ip6_nd_event_t * event = vl_msg_api_alloc (sizeof *event); + memset (event, 0, sizeof *event); + event->_vl_msg_id = htons (VL_API_IP6_ND_EVENT); + event->client_index = reg->client_index; + event->pid = reg->client_pid; + event->mac_ip = 1; + memcpy(event->address, nd_events[i].ip6.as_u8, sizeof event->address); + event->sw_if_index = htonl(nd_events[i].sw_if_index); + memcpy(event->new_mac, nd_events[i].mac, sizeof event->new_mac); + vl_msg_api_send_shmem (q, (u8 *) &event); + } + })); + /* *INDENT-ON* */ } - prev = event_data[i]; - last = now; - vpe_client_registration_t *reg; - /* *INDENT-OFF* */ - pool_foreach(reg, vpe_api_main.wc_ip4_arp_events_registrations, - ({ - unix_shared_memory_queue_t *q; - q = vl_api_client_index_to_input_queue (reg->client_index); - if (q && q->cursize < q->maxsize) - { - vl_api_ip4_arp_event_t * event = vl_msg_api_alloc (sizeof *event); - memset (event, 0, sizeof *event); - event->_vl_msg_id = htons (VL_API_IP4_ARP_EVENT); - event->client_index = reg->client_index; - event->pid = reg->client_pid; - event->mac_ip = 1; - event->address = event_data[i].ip4; - event->sw_if_index = htonl(event_data[i].sw_if_index); - memcpy(event->new_mac, event_data[i].mac, sizeof event->new_mac); - vl_msg_api_send_shmem (q, (u8 *) &event); - } - })); - /* *INDENT-ON* */ } vlib_process_put_event_data (vm, event_data); } @@ -1490,8 +1517,8 @@ wc_ip4_arp_process (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_REGISTER_NODE (wc_ip4_arp_process_node,static) = { - .function = wc_ip4_arp_process, +VLIB_REGISTER_NODE (wc_arp_process_node,static) = { + .function = wc_arp_process, .type = VLIB_NODE_TYPE_PROCESS, .name = "wildcard-ip4-arp-publisher-process", }; @@ -1526,7 +1553,7 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp) hash_unset (am->wc_ip4_arp_events_registration_hash, mp->client_index); if (pool_elts (am->wc_ip4_arp_events_registrations) == 0) - wc_arp_set_publisher_node (~0); + wc_arp_set_publisher_node (~0, WC_ARP_REPORT); goto reply; } } @@ -1541,7 +1568,7 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp) rp->client_pid = mp->pid; hash_set (am->wc_ip4_arp_events_registration_hash, rp->client_index, rp - am->wc_ip4_arp_events_registrations); - wc_arp_set_publisher_node (wc_ip4_arp_process_node.index); + wc_arp_set_publisher_node (wc_arp_process_node.index, WC_ARP_REPORT); goto reply; } @@ -1588,7 +1615,47 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp) vpe_api_main_t *am = &vpe_api_main; vnet_main_t *vnm = vnet_get_main (); vl_api_want_ip6_nd_events_reply_t *rmp; - int rv; + int rv = 0; + + if (ip6_address_is_zero ((ip6_address_t *) mp->address)) + { + uword *p = + hash_get (am->wc_ip6_nd_events_registration_hash, mp->client_index); + vpe_client_registration_t *rp; + if (p) + { + if (mp->enable_disable) + { + clib_warning ("pid %d: already enabled...", mp->pid); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + else + { + rp = + pool_elt_at_index (am->wc_ip6_nd_events_registrations, p[0]); + pool_put (am->wc_ip6_nd_events_registrations, rp); + hash_unset (am->wc_ip6_nd_events_registration_hash, + mp->client_index); + if (pool_elts (am->wc_ip6_nd_events_registrations) == 0) + wc_nd_set_publisher_node (~0, 2); + goto reply; + } + } + if (mp->enable_disable == 0) + { + clib_warning ("pid %d: already disabled...", mp->pid); + rv = VNET_API_ERROR_INVALID_REGISTRATION; + goto reply; + } + pool_get (am->wc_ip6_nd_events_registrations, rp); + rp->client_index = mp->client_index; + rp->client_pid = mp->pid; + hash_set (am->wc_ip6_nd_events_registration_hash, rp->client_index, + rp - am->wc_ip6_nd_events_registrations); + wc_nd_set_publisher_node (wc_arp_process_node.index, WC_ND_REPORT); + goto reply; + } if (mp->enable_disable) { @@ -1604,17 +1671,14 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp) if (rv) { pool_put (am->nd_events, event); - goto out; + goto reply; } memset (event, 0, sizeof (*event)); event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT); event->client_index = mp->client_index; - clib_memcpy (event->address, mp->address, 16); + clib_memcpy (event->address, mp->address, sizeof event->address); event->pid = mp->pid; - if (ip6_address_is_zero ((ip6_address_t *) mp->address)) - event->mac_ip = 1; - } else { @@ -1624,7 +1688,7 @@ vl_api_want_ip6_nd_events_t_handler (vl_api_want_ip6_nd_events_t * mp) vpe_resolver_process_node.index, IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ ); } -out: +reply: REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY); } @@ -2325,10 +2389,7 @@ format_nd_event (u8 * s, va_list * args) vl_api_ip6_nd_event_t *event = va_arg (*args, vl_api_ip6_nd_event_t *); s = format (s, "pid %d: ", ntohl (event->pid)); - if (event->mac_ip) - s = format (s, "bd mac/ip6 binding events"); - else - s = format (s, "resolution for %U", format_ip6_address, event->address); + s = format (s, "resolution for %U", format_ip6_address, event->address); return s; } @@ -2340,7 +2401,9 @@ show_ip_arp_nd_events_fn (vlib_main_t * vm, vl_api_ip4_arp_event_t *arp_event; vl_api_ip6_nd_event_t *nd_event; - if ((pool_elts (am->arp_events) == 0) && (pool_elts (am->nd_events) == 0)) + if (pool_elts (am->arp_events) == 0 && pool_elts (am->nd_events) == 0 && + pool_elts (am->wc_ip4_arp_events_registrations) == 0 && + pool_elts (am->wc_ip6_nd_events_registrations) == 0) { vlib_cli_output (vm, "No active arp or nd event registrations"); return 0; @@ -2363,6 +2426,12 @@ show_ip_arp_nd_events_fn (vlib_main_t * vm, ({ vlib_cli_output (vm, "%U", format_nd_event, nd_event); })); + + pool_foreach(reg, am->wc_ip6_nd_events_registrations, + ({ + vlib_cli_output (vm, "pid %d: bd mac/ip6 binding events", + ntohl (reg->client_pid)); + })); /* *INDENT-ON* */ return 0; |