fib: Don't use an address from an attached prefix when sending ARP requests.

Change-Id: I4c3144794dd0bd7de6150929e53f6d305c496b17

Type: fix
Signed-off-by: Neale Ranns <neale@graphiant.com>
Change-Id: I7b0c2c2dec5e867970599b8f2f2da17f2ff0b17c
diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c
index 3a46d22..85b1787 100644
--- a/src/vnet/fib/fib_table.c
+++ b/src/vnet/fib/fib_table.c
@@ -534,7 +534,11 @@
     else if (fib_route_path_is_attached(path))
     {
         path->frp_flags |= FIB_ROUTE_PATH_GLEAN;
-        fib_prefix_normalize(prefix, &path->frp_connected);
+        /*
+         * attached prefixes are not suitable as the source of ARP requests
+         * so don't save the prefix in the glean adj
+         */
+        clib_memset(&path->frp_connected, 0, sizeof(path->frp_connected));
     }
     if (*eflags & FIB_ENTRY_FLAG_DROP)
     {
diff --git a/src/vnet/ip-neighbor/ip4_neighbor.c b/src/vnet/ip-neighbor/ip4_neighbor.c
index 2d4b295..8be4b82 100644
--- a/src/vnet/ip-neighbor/ip4_neighbor.c
+++ b/src/vnet/ip-neighbor/ip4_neighbor.c
@@ -187,12 +187,16 @@
 	      /* resolve the packet's destination */
 	      ip4_header_t *ip0 = vlib_buffer_get_current (p0);
 	      resolve0 = ip0->dst_address;
-	      src0 = adj0->sub_type.glean.rx_pfx.fp_addr.ip4;
 	    }
 	  else
+	    /* resolve the incomplete adj */
+	    resolve0 = adj0->sub_type.nbr.next_hop.ip4;
+
+	  if (is_glean && adj0->sub_type.glean.rx_pfx.fp_len)
+	    /* the glean is for a connected, local prefix */
+	    src0 = adj0->sub_type.glean.rx_pfx.fp_addr.ip4;
+	  else
 	    {
-	      /* resolve the incomplete adj */
-	      resolve0 = adj0->sub_type.nbr.next_hop.ip4;
 	      /* Src IP address in ARP header. */
 	      if (!fib_sas4_get (sw_if_index0, &resolve0, &src0) &&
 		  !ip4_sas_by_sw_if_index (sw_if_index0, &resolve0, &src0))
diff --git a/test/test_neighbor.py b/test/test_neighbor.py
index b600a97..24737da 100644
--- a/test/test_neighbor.py
+++ b/test/test_neighbor.py
@@ -2069,6 +2069,28 @@
         for rx in rxs:
             self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128")
 
+        # apply an attached prefix to the interface
+        # since there's no local address in this prefix,
+        # any other address is used
+        p3 = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
+            / IP(src=self.pg1.remote_ip4, dst="10.0.2.128")
+            / Raw(b"0x5" * 100)
+        )
+
+        VppIpRoute(
+            self,
+            "10.0.2.0",
+            24,
+            [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
+        ).add_vpp_config()
+
+        rxs = self.send_and_expect(self.pg0, [p3], self.pg1)
+        for rx in rxs:
+            self.verify_arp_req(
+                rx, self.pg1.local_mac, self.pg1.local_ip4, "10.0.2.128"
+            )
+
         # cleanup
         conn3.remove_vpp_config()
         conn2.remove_vpp_config()