diff options
author | John Lo <loj@cisco.com> | 2016-08-27 01:11:57 -0400 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2016-08-31 21:05:06 +0000 |
commit | 1edfba9a6394128ee5fad2b413e9e0a05972ef48 (patch) | |
tree | e1fbed7fe39b487bba72ead48020b3f25d1cbef6 /vpp | |
parent | 7214cf11e9b9edbc015994cb7f9f5828e02d3791 (diff) |
VPP-358: Add IPv6 ND Event Notification and Termination
Add IPv6 equivalent of IPv4 ARP event notification which covers address
resolution for L3 and MAC/IP binding in L2 BD and ARP termination in BD.
For IPv6, ICMP6 neighbor solicitation and advertisement packets are
utilized instead of ARP request and response packets for IPv4.
Change-Id: I0088fa173e4480de297c8053ea2fcd0821322815
Signed-off-by: John Lo <loj@cisco.com>
Diffstat (limited to 'vpp')
-rw-r--r-- | vpp/vpp-api/api.c | 236 | ||||
-rw-r--r-- | vpp/vpp-api/custom_dump.c | 15 | ||||
-rw-r--r-- | vpp/vpp-api/vpe.api | 48 |
3 files changed, 272 insertions, 27 deletions
diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index 8d54ba75..00988184 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -51,6 +51,7 @@ #include <vnet/l2/l2_bd.h> #include <vnet/l2tp/l2tp.h> #include <vnet/ip/ip.h> +#include <vnet/ip/ip6.h> #include <vnet/unix/tuntap.h> #include <vnet/unix/tapcli.h> #include <vnet/mpls-gre/mpls.h> @@ -301,6 +302,7 @@ _(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ +_(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \ _(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del) \ _(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd) \ @@ -425,12 +427,15 @@ typedef struct /* notifications happen really early in the game */ u8 link_state_process_up; - /* ip4 pending route adds */ + /* ip4 and ip6 pending route adds */ pending_route_t *pending_routes; /* ip4 arp event registration pool */ vl_api_ip4_arp_event_t *arp_events; + /* ip6 nd event registration pool */ + vl_api_ip6_nd_event_t *nd_events; + /* convenience */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; @@ -447,6 +452,7 @@ static void send_sw_interface_flags_deleted (vpe_api_main_t * am, u32 sw_if_index); static int arp_change_delete_callback (u32 pool_index, u8 * notused); +static int nd_change_delete_callback (u32 pool_index, u8 * notused); /* Clean up all registrations belonging to the indicated client */ @@ -629,17 +635,25 @@ reply: \ REPLY_MACRO (VL_API_WANT_##UCA##_REPLY); \ } +/* *INDENT-OFF* */ pub_sub_handler (interface_events, INTERFACE_EVENTS) pub_sub_handler (oam_events, OAM_EVENTS) +/* *INDENT-ON* */ + #define RESOLUTION_EVENT 1 #define RESOLUTION_PENDING_EVENT 2 #define IP4_ARP_EVENT 3 - static int ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp); - static int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp); - static int mpls_ethernet_add_del_tunnel_2_t_handler - (vl_api_mpls_ethernet_add_del_tunnel_2_t * mp); +#define IP6_ND_EVENT 4 + +static int ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp); + +static int ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp); + +static int mpls_ethernet_add_del_tunnel_2_t_handler + (vl_api_mpls_ethernet_add_del_tunnel_2_t * mp); - void handle_ip4_arp_event (u32 pool_index) +void +handle_ip4_arp_event (u32 pool_index) { vpe_api_main_t *vam = &vpe_api_main; vnet_main_t *vnm = vam->vnet_main; @@ -687,6 +701,55 @@ pub_sub_handler (oam_events, OAM_EVENTS) } } +void +handle_ip6_nd_event (u32 pool_index) +{ + vpe_api_main_t *vam = &vpe_api_main; + vnet_main_t *vnm = vam->vnet_main; + vlib_main_t *vm = vam->vlib_main; + vl_api_ip6_nd_event_t *event; + vl_api_ip6_nd_event_t *mp; + unix_shared_memory_queue_t *q; + + /* Client can cancel, die, etc. */ + if (pool_is_free_index (vam->nd_events, pool_index)) + return; + + event = pool_elt_at_index (vam->nd_events, pool_index); + + q = vl_api_client_index_to_input_queue (event->client_index); + if (!q) + { + (void) vnet_add_del_ip6_nd_change_event + (vnm, nd_change_delete_callback, + event->pid, &event->address, + vpe_resolver_process_node.index, IP6_ND_EVENT, + ~0 /* pool index, notused */ , 0 /* is_add */ ); + return; + } + + if (q->cursize < q->maxsize) + { + mp = vl_msg_api_alloc (sizeof (*mp)); + clib_memcpy (mp, event, sizeof (*mp)); + vl_msg_api_send_shmem (q, (u8 *) & mp); + } + else + { + static f64 last_time; + /* + * Throttle syslog msgs. + * It's pretty tempting to just revoke the registration... + */ + if (vlib_time_now (vm) > last_time + 10.0) + { + clib_warning ("ip6 nd event for %U to pid %d: queue stuffed!", + format_ip6_address, &event->address, event->pid); + last_time = vlib_time_now (vm); + } + } +} + static uword resolver_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) @@ -774,6 +837,11 @@ resolver_process (vlib_main_t * vm, handle_ip4_arp_event (event_data[i]); break; + case IP6_ND_EVENT: + for (i = 0; i < vec_len (event_data); i++) + handle_ip6_nd_event (event_data[i]); + break; + case ~0: /* timeout, retry pending resolutions */ /* *INDENT-OFF* */ pool_foreach (pr, vam->pending_routes, @@ -6130,30 +6198,69 @@ arp_change_data_callback (u32 pool_index, u8 * new_mac, return 1; event = pool_elt_at_index (am->arp_events, pool_index); + /* *INDENT-OFF* */ if (memcmp (&event->new_mac, new_mac, sizeof (event->new_mac))) { clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac)); } else { /* same mac */ - if ((sw_if_index == event->sw_if_index) && ((address == 0) || - /* for BD case, also check IP address with 10 sec timeout */ - ((address == event->address) - && - ((now - - arp_event_last_time) < - 10.0)))) + if (sw_if_index == event->sw_if_index && + (!event->mac_ip || + /* for BD case, also check IP address with 10 sec timeout */ + (address == event->address && + (now - arp_event_last_time) < 10.0))) return 1; } + /* *INDENT-ON* */ arp_event_last_time = now; event->sw_if_index = sw_if_index; - if (address) + if (event->mac_ip) event->address = address; return 0; } static int +nd_change_data_callback (u32 pool_index, u8 * new_mac, + u32 sw_if_index, ip6_address_t * address) +{ + 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))) + { + clib_memcpy (event->new_mac, new_mac, sizeof (event->new_mac)); + } + else + { /* same mac */ + if (sw_if_index == 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; + } + /* *INDENT-ON* */ + + nd_event_last_time = now; + event->sw_if_index = sw_if_index; + if (event->mac_ip) + clib_memcpy (event->address, address, sizeof (event->address)); + return 0; +} + +static int arp_change_delete_callback (u32 pool_index, u8 * notused) { vpe_api_main_t *am = &vpe_api_main; @@ -6165,6 +6272,18 @@ arp_change_delete_callback (u32 pool_index, u8 * notused) return 0; } +static int +nd_change_delete_callback (u32 pool_index, u8 * notused) +{ + vpe_api_main_t *am = &vpe_api_main; + + if (pool_is_free_index (am->nd_events, pool_index)) + return 1; + + pool_put_index (am->nd_events, pool_index); + return 0; +} + static void vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp) { @@ -6184,6 +6303,8 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp) event->context = mp->context; event->address = mp->address; event->pid = mp->pid; + if (mp->address == 0) + event->mac_ip = 1; rv = vnet_add_del_ip4_arp_change_event (vnm, arp_change_data_callback, @@ -6202,6 +6323,45 @@ vl_api_want_ip4_arp_events_t_handler (vl_api_want_ip4_arp_events_t * mp) REPLY_MACRO (VL_API_WANT_IP4_ARP_EVENTS_REPLY); } +static void +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; + vl_api_ip6_nd_event_t *event; + int rv; + + if (mp->enable_disable) + { + pool_get (am->nd_events, event); + memset (event, 0, sizeof (*event)); + + event->_vl_msg_id = ntohs (VL_API_IP6_ND_EVENT); + event->client_index = mp->client_index; + event->context = mp->context; + clib_memcpy (event->address, mp->address, 16); + event->pid = mp->pid; + if (ip6_address_is_zero ((ip6_address_t *) mp->address)) + event->mac_ip = 1; + + rv = vnet_add_del_ip6_nd_change_event + (vnm, nd_change_data_callback, + mp->pid, mp->address /* addr, in net byte order */ , + vpe_resolver_process_node.index, + IP6_ND_EVENT, event - am->nd_events, 1 /* is_add */ ); + } + else + { + rv = vnet_add_del_ip6_nd_change_event + (vnm, nd_change_delete_callback, + mp->pid, mp->address /* addr, in net byte order */ , + vpe_resolver_process_node.index, + IP6_ND_EVENT, ~0 /* pool index */ , 0 /* is_add */ ); + } + REPLY_MACRO (VL_API_WANT_IP6_ND_EVENTS_REPLY); +} + static void vl_api_input_acl_set_interface_t_handler (vl_api_input_acl_set_interface_t * mp) { @@ -8434,28 +8594,50 @@ format_arp_event (u8 * s, va_list * args) { vl_api_ip4_arp_event_t *event = va_arg (*args, vl_api_ip4_arp_event_t *); - s = format (s, "pid %d: %U", event->pid, - format_ip4_address, &event->address); + s = format (s, "pid %d: ", event->pid); + if (event->mac_ip) + s = format (s, "bd mac/ip4 binding events"); + else + s = format (s, "resolution for %U", format_ip4_address, &event->address); + return s; +} + +static u8 * +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: ", 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); return s; } static clib_error_t * -show_ip4_arp_events_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) +show_ip_arp_nd_events_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) { vpe_api_main_t *am = &vpe_api_main; - vl_api_ip4_arp_event_t *event; + vl_api_ip4_arp_event_t *arp_event; + vl_api_ip6_nd_event_t *nd_event; - if (pool_elts (am->arp_events) == 0) + if ((pool_elts (am->arp_events) == 0) && (pool_elts (am->nd_events) == 0)) { - vlib_cli_output (vm, "No active arp event registrations"); + vlib_cli_output (vm, "No active arp or nd event registrations"); return 0; } /* *INDENT-OFF* */ - pool_foreach (event, am->arp_events, + pool_foreach (arp_event, am->arp_events, + ({ + vlib_cli_output (vm, "%U", format_arp_event, arp_event); + })); + + pool_foreach (nd_event, am->nd_events, ({ - vlib_cli_output (vm, "%U", format_arp_event, event); + vlib_cli_output (vm, "%U", format_nd_event, nd_event); })); /* *INDENT-ON* */ @@ -8463,10 +8645,10 @@ show_ip4_arp_events_fn (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_ip4_arp_events, static) = { - .path = "show arp event registrations", - .function = show_ip4_arp_events_fn, - .short_help = "Show arp event registrations", +VLIB_CLI_COMMAND (show_ip_arp_nd_events, static) = { + .path = "show arp-nd-event registrations", + .function = show_ip_arp_nd_events_fn, + .short_help = "Show ip4 arp and ip6 nd event registrations", }; /* *INDENT-ON* */ diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c index 87331eb1..913ad1c6 100644 --- a/vpp/vpp-api/custom_dump.c +++ b/vpp/vpp-api/custom_dump.c @@ -1708,6 +1708,20 @@ static void *vl_api_want_ip4_arp_events_t_print FINISH; } +static void *vl_api_want_ip6_nd_events_t_print + (vl_api_want_ip6_nd_events_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: want_ip6_nd_events "); + s = format (s, "pid %d address %U ", mp->pid, + format_ip6_address, mp->address); + if (mp->enable_disable == 0) + s = format (s, "del "); + + FINISH; +} + static void *vl_api_input_acl_set_interface_t_print (vl_api_input_acl_set_interface_t * mp, void *handle) { @@ -2688,6 +2702,7 @@ _(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ +_(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index 386ff163..0bfa2fa2 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -3071,6 +3071,7 @@ define want_ip4_arp_events_reply @param pid - client pid registered to receive notification @param sw_if_index - interface which received ARP packet @param new_mac - the new mac address + @param mac_ip - 0: resolution event, 1: mac/ip binding in bd */ define ip4_arp_event { @@ -3080,8 +3081,55 @@ define ip4_arp_event u32 pid; u32 sw_if_index; u8 new_mac[6]; + u8 mac_ip; }; +/** \brief Register for ip6 nd resolution events + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param enable_disable - 1 => register for events, 0 => cancel registration + @param pid - sender's pid + @param address - the exact ip6 address of interest +*/ +define want_ip6_nd_events +{ + u32 client_index; + u32 context; + u8 enable_disable; + u32 pid; + u8 address[16]; +}; + +/** \brief Reply for ip6 nd resolution events registration + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define want_ip6_nd_events_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Tell client about an ip6 nd resolution or mac/ip event + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param pid - client pid registered to receive notification + @param sw_if_index - interface which received ARP packet + @param address - the exact ip6 address of interest + @param new_mac - the new mac address + @param mac_ip - 0: resolution event, 1: mac/ip binding in bd +*/ +define ip6_nd_event +{ + u32 client_index; + u32 context; + u32 pid; + u32 sw_if_index; + u8 address[16]; + u8 new_mac[6]; + u8 mac_ip; +}; + /** \brief L2 bridge domain add or delete request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request |