diff options
author | John Lo <loj@cisco.com> | 2017-06-26 01:40:20 -0400 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2017-07-06 13:24:26 +0000 |
commit | 8b81cb43359380e50d3fc216d93ff05894149939 (patch) | |
tree | bcd8b31ead28c30a182b0fcabfc806c35dc2030e /src/vnet | |
parent | f6e3ad0f5e2be10a91b2a52c91e7792ec212dee9 (diff) |
Send GARP/NA on bonded intf slave up/down if in active-backup mode
If a bonded interface is in active-backup mode and configured with
IPv4 and/or IPv6 addresses, on slave interface link up/down, send
a GARP packet if configured with an IPv4 address and an unsolcited
NA if configured with an IPv6 address. These packets can help with
faster route convergence in the next hop router/switch.
Change-Id: I68ccb11a4a40cda414704fa08ee0171c952befa2
Signed-off-by: John Lo <loj@cisco.com>
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/ethernet/arp.c | 83 | ||||
-rw-r--r-- | src/vnet/ethernet/arp_packet.h | 9 | ||||
-rw-r--r-- | src/vnet/ip/ip6.h | 2 | ||||
-rw-r--r-- | src/vnet/ip/ip6_neighbor.c | 53 |
4 files changed, 147 insertions, 0 deletions
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index d5dc9cceb39..df68175055e 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -110,6 +110,9 @@ typedef struct static const u8 vrrp_prefix[] = { 0x00, 0x00, 0x5E, 0x00, 0x01 }; +/* Node index for send_garp_na_process */ +u32 send_garp_na_process_node_index; + static void set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t * a); @@ -2378,6 +2381,86 @@ ethernet_arp_change_mac (u32 sw_if_index) /* *INDENT-ON* */ } +void static +send_ip4_garp (vlib_main_t * vm, vnet_hw_interface_t * hi) +{ + ip4_main_t *i4m = &ip4_main; + u32 sw_if_index = hi->sw_if_index; + ip4_address_t *ip4_addr = ip4_interface_first_address (i4m, sw_if_index, 0); + + if (ip4_addr) + { + clib_warning ("Sending GARP for IP4 address %U on sw_if_idex %d", + format_ip4_address, ip4_addr, sw_if_index); + + /* Form GARP packet for output - Gratuitous ARP is an ARP request packet + where the interface IP/MAC pair is used for both source and request + MAC/IP pairs in the request */ + u32 bi = 0; + ethernet_arp_header_t *h = vlib_packet_template_get_packet + (vm, &i4m->ip4_arp_request_packet_template, &bi); + clib_memcpy (h->ip4_over_ethernet[0].ethernet, hi->hw_address, + sizeof (h->ip4_over_ethernet[0].ethernet)); + clib_memcpy (h->ip4_over_ethernet[1].ethernet, hi->hw_address, + sizeof (h->ip4_over_ethernet[1].ethernet)); + h->ip4_over_ethernet[0].ip4 = ip4_addr[0]; + h->ip4_over_ethernet[1].ip4 = ip4_addr[0]; + + /* Setup MAC header with ARP Etype and broadcast DMAC */ + vlib_buffer_t *b = vlib_get_buffer (vm, bi); + vlib_buffer_advance (b, -sizeof (ethernet_header_t)); + ethernet_header_t *e = vlib_buffer_get_current (b); + e->type = clib_host_to_net_u16 (ETHERNET_TYPE_ARP); + clib_memcpy (e->src_address, hi->hw_address, sizeof (e->src_address)); + memset (e->dst_address, 0xff, sizeof (e->dst_address)); + + /* Send GARP packet out the specified interface */ + vnet_buffer (b)->sw_if_index[VLIB_RX] = + vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index; + vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index); + u32 *to_next = vlib_frame_vector_args (f); + to_next[0] = bi; + f->n_vectors = 1; + vlib_put_frame_to_node (vm, hi->output_node_index, f); + } +} + +static vlib_node_registration_t send_garp_na_proc_node; + +static uword +send_garp_na_process (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + vnet_main_t *vnm = vnet_get_main (); + uword event_type, *event_data = 0; + + send_garp_na_process_node_index = send_garp_na_proc_node.index; + + while (1) + { + vlib_process_wait_for_event (vm); + event_type = vlib_process_get_events (vm, &event_data); + if ((event_type == SEND_GARP_NA) && (vec_len (event_data) >= 1)) + { + u32 hw_if_index = event_data[0]; + vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index); + send_ip4_garp (vm, hi); + send_ip6_na (vm, hi); + } + vec_reset_length (event_data); + } + return 0; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (send_garp_na_proc_node, static) = { + .function = send_garp_na_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "send-garp-na-process", +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/ethernet/arp_packet.h b/src/vnet/ethernet/arp_packet.h index 17e64f43049..d740b844e12 100644 --- a/src/vnet/ethernet/arp_packet.h +++ b/src/vnet/ethernet/arp_packet.h @@ -167,6 +167,15 @@ typedef struct ethernet_arp_ip4_entry_t *ip4_neighbor_entries (u32 sw_if_index); u8 *format_ethernet_arp_ip4_entry (u8 * s, va_list * va); +/* Node index for send_garp_na_process */ +extern u32 send_garp_na_process_node_index; + +/* Even type for send_garp_na_process */ +enum +{ + SEND_GARP_NA = 1, +} dpdk_send_garp_na_process_event_t; + #endif /* included_ethernet_arp_packet_h */ /* diff --git a/src/vnet/ip/ip6.h b/src/vnet/ip/ip6.h index d623c95f52f..cf52994e720 100644 --- a/src/vnet/ip/ip6.h +++ b/src/vnet/ip/ip6.h @@ -375,6 +375,8 @@ int vnet_ip6_nd_term (vlib_main_t * vm, ethernet_header_t * eth, ip6_header_t * ip, u32 sw_if_index, u16 bd_index); +void send_ip6_na (vlib_main_t * vm, vnet_hw_interface_t * hi); + u8 *format_ip6_forward_next_trace (u8 * s, va_list * args); u32 ip6_tcp_udp_icmp_validate_checksum (vlib_main_t * vm, vlib_buffer_t * p0); diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index ba7ea143318..b8f6f9b10e7 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -4192,6 +4192,59 @@ ethernet_ndp_change_mac (u32 sw_if_index) /* *INDENT-ON* */ } +void +send_ip6_na (vlib_main_t * vm, vnet_hw_interface_t * hi) +{ + ip6_main_t *i6m = &ip6_main; + u32 sw_if_index = hi->sw_if_index; + ip6_address_t *ip6_addr = ip6_interface_first_address (i6m, sw_if_index); + if (ip6_addr) + { + clib_warning + ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d", + format_ip6_address, ip6_addr, sw_if_index); + + /* Form unsolicited neighbor advertisement packet from NS pkt template */ + int bogus_length; + u32 bi = 0; + icmp6_neighbor_solicitation_header_t *h = + vlib_packet_template_get_packet (vm, + &i6m->discover_neighbor_packet_template, + &bi); + ip6_set_reserved_multicast_address (&h->ip.dst_address, + IP6_MULTICAST_SCOPE_link_local, + IP6_MULTICAST_GROUP_ID_all_hosts); + h->ip.src_address = ip6_addr[0]; + h->neighbor.icmp.type = ICMP6_neighbor_advertisement; + h->neighbor.target_address = ip6_addr[0]; + h->neighbor.advertisement_flags = clib_host_to_net_u32 + (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE); + clib_memcpy (h->link_layer_option.ethernet_address, + hi->hw_address, vec_len (hi->hw_address)); + h->neighbor.icmp.checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length); + ASSERT (bogus_length == 0); + + /* Setup MAC header with IP6 Etype and mcast DMAC */ + vlib_buffer_t *b = vlib_get_buffer (vm, bi); + vlib_buffer_advance (b, -sizeof (ethernet_header_t)); + ethernet_header_t *e = vlib_buffer_get_current (b); + e->type = clib_host_to_net_u16 (ETHERNET_TYPE_IP6); + clib_memcpy (e->src_address, hi->hw_address, sizeof (e->src_address)); + ip6_multicast_ethernet_address (e->dst_address, + IP6_MULTICAST_GROUP_ID_all_hosts); + + /* Send unsolicited ND advertisement packet out the specified interface */ + vnet_buffer (b)->sw_if_index[VLIB_RX] = + vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index; + vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index); + u32 *to_next = vlib_frame_vector_args (f); + to_next[0] = bi; + f->n_vectors = 1; + vlib_put_frame_to_node (vm, hi->output_node_index, f); + } +} + /* * fd.io coding-style-patch-verification: ON * |