From: Pierre Pfister Date: Wed, 22 Jun 2016 11:58:30 +0000 (+0100) Subject: ARP/NDP does not send solicitation when no source address is available X-Git-Tag: v16.09-rc1~254 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=d076f19b5e119265d995a031707c8d78608c439f;p=vpp.git ARP/NDP does not send solicitation when no source address is available Currently, when the interface has no address assigned to it, VPP crashes as ip_interface_address_for_packet assumes there always is at least one address. This patch checks if an address is available at all. The only part of VPP using it is ARP or NDP. When a neighbor discovery message has to be sent while there is no address assigned on the interace, no solicitation is sent and an error counter is incremented. Change-Id: Ia9fdaf8e84050a1ceeb47f5370819d3df95714f0 Signed-off-by: Pierre Pfister --- diff --git a/vnet/vnet/ethernet/arp_packet.h b/vnet/vnet/ethernet/arp_packet.h index c2214949d89..b3447c5e1c1 100644 --- a/vnet/vnet/ethernet/arp_packet.h +++ b/vnet/vnet/ethernet/arp_packet.h @@ -109,7 +109,8 @@ typedef enum { IP4_ARP_ERROR_REQUEST_SENT, IP4_ARP_ERROR_NON_ARP_ADJ, IP4_ARP_ERROR_REPLICATE_DROP, - IP4_ARP_ERROR_REPLICATE_FAIL + IP4_ARP_ERROR_REPLICATE_FAIL, + IP4_ARP_ERROR_NO_SOURCE_ADDRESS, } ip4_arp_error_t; typedef CLIB_PACKED (struct { diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h index c01006ea590..f005522bb7a 100644 --- a/vnet/vnet/ip/ip4.h +++ b/vnet/vnet/ip/ip4.h @@ -237,13 +237,16 @@ ip4_unaligned_destination_matches_route (ip4_main_t * im, uword dest_length) { return 0 == ((clib_mem_unaligned (&key->data_u32, u32) ^ dest->data_u32) & im->fib_masks[dest_length]); } -always_inline void +always_inline int ip4_src_address_for_packet (ip4_main_t * im, vlib_buffer_t * p, ip4_address_t * src, u32 sw_if_index) { ip_lookup_main_t * lm = &im->lookup_main; ip_interface_address_t * ia = ip_interface_address_for_packet (lm, p, sw_if_index); + if (ia == NULL) + return -1; ip4_address_t * a = ip_interface_address_get_address (lm, ia); *src = a[0]; + return 0; } /* Find interface address which matches destination. */ diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c index 3075e0c3f73..08a1785aaa5 100644 --- a/vnet/vnet/ip/ip4_forward.c +++ b/vnet/vnet/ip/ip4_forward.c @@ -2373,7 +2373,12 @@ ip4_arp (vlib_main_t * vm, clib_memcpy (h0->ip4_over_ethernet[0].ethernet, hw_if0->hw_address, sizeof (h0->ip4_over_ethernet[0].ethernet)); - ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0); + if (ip4_src_address_for_packet (im, p0, &h0->ip4_over_ethernet[0].ip4, sw_if_index0)) { + //No source address available + p0->error = node->errors[IP4_ARP_ERROR_NO_SOURCE_ADDRESS]; + vlib_buffer_free(vm, &bi0, 1); + continue; + } /* Copy in destination address we are requesting. */ h0->ip4_over_ethernet[1].ip4.data_u32 = ip0->dst_address.data_u32; @@ -2400,6 +2405,7 @@ static char * ip4_arp_error_strings[] = { [IP4_ARP_ERROR_NON_ARP_ADJ] = "ARPs to non-ARP adjacencies", [IP4_ARP_ERROR_REPLICATE_DROP] = "ARP replication completed", [IP4_ARP_ERROR_REPLICATE_FAIL] = "ARP replication failed", + [IP4_ARP_ERROR_NO_SOURCE_ADDRESS] = "no source address for ARP request", }; VLIB_REGISTER_NODE (ip4_arp_node) = { diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h index 312e39845b4..70e32672530 100644 --- a/vnet/vnet/ip/ip6.h +++ b/vnet/vnet/ip/ip6.h @@ -289,13 +289,16 @@ ip6_unaligned_destination_matches_route (ip6_main_t * im, return 1; } -always_inline void +always_inline int ip6_src_address_for_packet (ip6_main_t * im, vlib_buffer_t * p, ip6_address_t * src, u32 sw_if_index) { ip_lookup_main_t * lm = &im->lookup_main; ip_interface_address_t * ia = ip_interface_address_for_packet (lm, p, sw_if_index); + if (ia == NULL) + return -1; ip6_address_t * a = ip_interface_address_get_address (lm, ia); *src = a[0]; + return 0; } always_inline u32 diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c index 86ee8d5ba2b..b558787c45c 100644 --- a/vnet/vnet/ip/ip6_forward.c +++ b/vnet/vnet/ip/ip6_forward.c @@ -1993,6 +1993,7 @@ typedef enum { typedef enum { IP6_DISCOVER_NEIGHBOR_ERROR_DROP, IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT, + IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS, } ip6_discover_neighbor_error_t; static uword @@ -2123,8 +2124,13 @@ ip6_discover_neighbor (vlib_main_t * vm, * Choose source address based on destination lookup * adjacency. */ - ip6_src_address_for_packet (im, p0, &h0->ip.src_address, - sw_if_index0); + if (ip6_src_address_for_packet (im, p0, &h0->ip.src_address, + sw_if_index0)) { + //There is no address on the interface + p0->error = node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]; + vlib_buffer_free(vm, &bi0, 1); + continue; + } /* * Destination address is a solicited node multicast address. @@ -2175,6 +2181,8 @@ static char * ip6_discover_neighbor_error_strings[] = { [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops", [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent", + [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS] + = "no source address for ND solicitation", }; VLIB_REGISTER_NODE (ip6_discover_neighbor_node) = { diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h index 35c19a77327..c22c5003fd3 100644 --- a/vnet/vnet/ip/lookup.h +++ b/vnet/vnet/ip/lookup.h @@ -531,7 +531,7 @@ ip_interface_address_for_packet (ip_lookup_main_t * lm, vlib_buffer_t * b, u32 s vec_elt (lm->if_address_pool_index_by_sw_if_index, sw_if_index) : if_address_index); - return pool_elt_at_index (lm->if_address_pool, if_address_index); + return (if_address_index != ~0)?pool_elt_at_index (lm->if_address_pool, if_address_index):NULL; } #define foreach_ip_interface_address(lm,a,sw_if_index,loop,body) \