ip: check all fib src for a connected dst entry 21/20321/9
authorBenoît Ganne <bganne@cisco.com>
Tue, 25 Jun 2019 08:32:28 +0000 (10:32 +0200)
committerBenoît Ganne <bganne@cisco.com>
Tue, 2 Jul 2019 09:05:36 +0000 (11:05 +0200)
When looking for a connected fib entry matching the ARP destination,
there can be other DPO interposed prior to the connected one.

Type: fix

Change-Id: I9b4ab387fb08acf9879d5fda3791e6572a099492
Signed-off-by: Benoît Ganne <bganne@cisco.com>
src/vnet/ethernet/arp.c

index 201bec4..b62dc4e 100644 (file)
@@ -1143,6 +1143,38 @@ arp_mk_reply (vnet_main_t * vnm,
   return (next0);
 }
 
+enum arp_dst_fib_type
+{
+  ARP_DST_FIB_NONE,
+  ARP_DST_FIB_ADJ,
+  ARP_DST_FIB_CONN
+};
+
+/*
+ * we're looking for FIB sources that indicate the destination
+ * is attached. There may be interposed DPO prior to the one
+ * we are looking for
+ */
+static enum arp_dst_fib_type
+arp_dst_fib_check (const fib_node_index_t fei, fib_entry_flag_t * flags)
+{
+  const fib_entry_t *entry = fib_entry_get (fei);
+  const fib_entry_src_t *entry_src;
+  fib_source_t src;
+  /* *INDENT-OFF* */
+  FOR_EACH_SRC_ADDED(entry, entry_src, src,
+  ({
+    *flags = fib_entry_get_flags_for_source (fei, src);
+    if (fib_entry_is_sourced (fei, FIB_SOURCE_ADJ))
+        return ARP_DST_FIB_ADJ;
+      else if (FIB_ENTRY_FLAG_CONNECTED & *flags)
+        return ARP_DST_FIB_CONN;
+  }))
+  /* *INDENT-ON* */
+
+  return ARP_DST_FIB_NONE;
+}
+
 static uword
 arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
@@ -1173,7 +1205,7 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
          ethernet_header_t *eth_rx;
          const ip4_address_t *if_addr0;
          u32 pi0, error0, next0, sw_if_index0, conn_sw_if_index0, fib_index0;
-         u8 dst_is_local0, is_unnum0, is_vrrp_reply0;
+         u8 dst_is_local0, is_vrrp_reply0;
          fib_node_index_t dst_fei, src_fei;
          const fib_prefix_t *pfx0;
          fib_entry_flag_t src_flags, dst_flags;
@@ -1202,15 +1234,6 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              goto drop;
 
            }
-         dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
-                                         &arp0->ip4_over_ethernet[1].ip4,
-                                         32);
-         dst_flags = fib_entry_get_flags (dst_fei);
-
-         conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
-
-         /* Honor unnumbered interface, if any */
-         is_unnum0 = sw_if_index0 != conn_sw_if_index0;
 
          {
            /*
@@ -1313,8 +1336,12 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
              }
          }
 
-         if (fib_entry_is_sourced (dst_fei, FIB_SOURCE_ADJ))
+         dst_fei = ip4_fib_table_lookup (ip4_fib_get (fib_index0),
+                                         &arp0->ip4_over_ethernet[1].ip4,
+                                         32);
+         switch (arp_dst_fib_check (dst_fei, &dst_flags))
            {
+           case ARP_DST_FIB_ADJ:
              /*
               * We matched an adj-fib on ths source subnet (a /32 previously
               * added as a result of ARP). If this request is a gratuitous
@@ -1328,23 +1355,15 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
                error0 = arp_learn (vnm, am, sw_if_index0,
                                    &arp0->ip4_over_ethernet[0]);
              goto drop;
-           }
-         else if (!(FIB_ENTRY_FLAG_CONNECTED & dst_flags))
-           {
+           case ARP_DST_FIB_CONN:
+             /* destination is connected, continue to process */
+             break;
+           case ARP_DST_FIB_NONE:
+             /* destination is not connected, stop here */
              error0 = ETHERNET_ARP_ERROR_l3_dst_address_not_local;
              goto next_feature;
            }
 
-         if (sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
-           {
-             /*
-              * The interface the ARP was received on is not the interface
-              * on which the covering prefix is configured. Maybe this is a
-              * case for unnumbered.
-              */
-             is_unnum0 = 1;
-           }
-
          dst_is_local0 = (FIB_ENTRY_FLAG_LOCAL & dst_flags);
          pfx0 = fib_entry_get_prefix (dst_fei);
          if_addr0 = &pfx0->fp_addr.ip4;
@@ -1390,8 +1409,17 @@ arp_reply (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
            {
              goto next_feature;
            }
-         if (is_unnum0)
+
+         /* Honor unnumbered interface, if any */
+         conn_sw_if_index0 = fib_entry_get_resolving_interface (dst_fei);
+         if (sw_if_index0 != conn_sw_if_index0 ||
+             sw_if_index0 != fib_entry_get_resolving_interface (src_fei))
            {
+             /*
+              * The interface the ARP is sent to or was received on is not the
+              * interface on which the covering prefix is configured.
+              * Maybe this is a case for unnumbered.
+              */
              if (!arp_unnumbered (p0, sw_if_index0, conn_sw_if_index0))
                {
                  error0 = ETHERNET_ARP_ERROR_unnumbered_mismatch;