ARP/NDP does not send solicitation when no source address is available 02/1702/4
authorPierre Pfister <ppfister@cisco.com>
Wed, 22 Jun 2016 11:58:30 +0000 (12:58 +0100)
committerChris Luke <chris_luke@cable.comcast.com>
Wed, 22 Jun 2016 17:09:33 +0000 (17:09 +0000)
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 <ppfister@cisco.com>
vnet/vnet/ethernet/arp_packet.h
vnet/vnet/ip/ip4.h
vnet/vnet/ip/ip4_forward.c
vnet/vnet/ip/ip6.h
vnet/vnet/ip/ip6_forward.c
vnet/vnet/ip/lookup.h

index c221494..b3447c5 100644 (file)
@@ -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 {
index c01006e..f005522 100644 (file)
@@ -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. */
index 3075e0c..08a1785 100644 (file)
@@ -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) = {
index 312e398..70e3267 100644 (file)
@@ -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
index 86ee8d5..b558787 100644 (file)
@@ -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) = {
index 35c19a7..c22c500 100644 (file)
@@ -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)        \