Change l2-fwd node to allow possible feature before UU-FLOOD
[vpp.git] / src / vnet / l2 / l2_input.c
index f60dd18..5d16b1d 100644 (file)
@@ -23,6 +23,8 @@
 #include <vnet/ip/ip_packet.h>
 #include <vnet/ip/ip4_packet.h>
 #include <vnet/ip/ip6_packet.h>
+#include <vnet/fib/fib_node.h>
+#include <vnet/ethernet/arp_packet.h>
 #include <vlib/cli.h>
 #include <vnet/l2/l2_input.h>
 #include <vnet/l2/l2_output.h>
@@ -154,29 +156,12 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
    *   set tx sw-if-handle
    */
 
-  u16 ethertype;
-  u8 protocol;
-  l2_input_config_t *config;
-  l2_bridge_domain_t *bd_config;
-  u16 bd_index0;
-  u32 feature_bitmap;
-  u32 feat_mask;
-  ethernet_header_t *h0;
-  u8 *l3h0;
-  u32 sw_if_index0;
-
-#define get_u16(addr) ( *((u16 *)(addr)) )
-
-  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
-
-  h0 = vlib_buffer_get_current (b0);
-  l3h0 = (u8 *) h0 + vnet_buffer (b0)->l2.l2_len;
-
-  ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
-  feat_mask = ~0;
+  u32 feat_mask = ~0;
+  u32 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+  ethernet_header_t *h0 = vlib_buffer_get_current (b0);
 
   /* Get config for the input interface */
-  config = vec_elt_at_index (msm->configs, sw_if_index0);
+  l2_input_config_t *config = vec_elt_at_index (msm->configs, sw_if_index0);
 
   /* Save split horizon group */
   vnet_buffer (b0)->l2.shg = config->shg;
@@ -184,7 +169,11 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
   /* determine layer2 kind for stat and mask */
   if (PREDICT_FALSE (ethernet_address_cast (h0->dst_address)))
     {
-      protocol = ((ip6_header_t *) l3h0)->protocol;
+      u8 *l3h0 = (u8 *) h0 + vnet_buffer (b0)->l2.l2_len;
+
+#define get_u16(addr) ( *((u16 *)(addr)) )
+      u16 ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
+      u8 protocol = ((ip6_header_t *) l3h0)->protocol;
 
       /* Disable bridge forwarding (flooding will execute instead if not xconnect) */
       feat_mask &= ~(L2INPUT_FEAT_FWD | L2INPUT_FEAT_UU_FLOOD);
@@ -193,12 +182,37 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
       if (ethertype != ETHERNET_TYPE_ARP &&
          (ethertype != ETHERNET_TYPE_IP6 || protocol != IP_PROTOCOL_ICMP6))
        feat_mask &= ~(L2INPUT_FEAT_ARP_TERM);
+
+      /*
+       * For packet from BVI - set SHG of ARP request or ICMPv6 neighbor
+       * solicitation packet from BVI to 0 so it can also flood to VXLAN
+       * tunnels or other ports with the same SHG as that of the BVI.
+       */
+      else if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] ==
+                             L2INPUT_BVI))
+       {
+         if (ethertype == ETHERNET_TYPE_ARP)
+           {
+             ethernet_arp_header_t *arp0 = (ethernet_arp_header_t *) l3h0;
+             if (arp0->opcode ==
+                 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request))
+               vnet_buffer (b0)->l2.shg = 0;
+           }
+         else                  /* must be ICMPv6 */
+           {
+             ip6_header_t *iph0 = (ip6_header_t *) l3h0;
+             icmp6_neighbor_solicitation_or_advertisement_header_t *ndh0;
+             ndh0 = ip6_next_header (iph0);
+             if (ndh0->icmp.type == ICMP6_neighbor_solicitation)
+               vnet_buffer (b0)->l2.shg = 0;
+           }
+       }
     }
   else
     {
       /*
-       * Check for from-BVI processing - set SHG of unicast packets from BVI
-       * to 0 so it is not dropped for VXLAN tunnels or other ports with the
+       * For packet from BVI - set SHG of unicast packet from BVI to 0 so it
+       * is not dropped on output to VXLAN tunnels or other ports with the
        * same SHG as that of the BVI.
        */
       if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] ==
@@ -210,12 +224,13 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
   if (config->bridge)
     {
       /* Do bridge-domain processing */
-      bd_index0 = config->bd_index;
+      u16 bd_index0 = config->bd_index;
       /* save BD ID for next feature graph nodes */
       vnet_buffer (b0)->l2.bd_index = bd_index0;
 
       /* Get config for the bridge domain interface */
-      bd_config = vec_elt_at_index (msm->bd_configs, bd_index0);
+      l2_bridge_domain_t *bd_config =
+       vec_elt_at_index (msm->bd_configs, bd_index0);
 
       /* Save bridge domain and interface seq_num */
       /* *INDENT-OFF* */
@@ -245,7 +260,7 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
     feat_mask = L2INPUT_FEAT_DROP;
 
   /* mask out features from bitmap using packet type and bd config */
-  feature_bitmap = config->feature_bitmap & feat_mask;
+  u32 feature_bitmap = config->feature_bitmap & feat_mask;
 
   /* save for next feature graph nodes */
   vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap;
@@ -372,9 +387,6 @@ l2input_node_inline (vlib_main_t * vm,
                }
            }
 
-         vlib_node_increment_counter (vm, l2input_node.index,
-                                      L2INPUT_ERROR_L2INPUT, 4);
-
          classify_and_dispatch (msm, b0, &next0);
          classify_and_dispatch (msm, b1, &next1);
          classify_and_dispatch (msm, b2, &next2);
@@ -415,9 +427,6 @@ l2input_node_inline (vlib_main_t * vm,
              clib_memcpy (t->dst, h0->dst_address, 6);
            }
 
-         vlib_node_increment_counter (vm, l2input_node.index,
-                                      L2INPUT_ERROR_L2INPUT, 1);
-
          classify_and_dispatch (msm, b0, &next0);
 
          /* verify speculative enqueue, maybe switch current next frame */
@@ -429,6 +438,9 @@ l2input_node_inline (vlib_main_t * vm,
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
 
+  vlib_node_increment_counter (vm, l2input_node.index,
+                              L2INPUT_ERROR_L2INPUT, frame->n_vectors);
+
   return frame->n_vectors;
 }
 
@@ -1121,14 +1133,13 @@ _(l2fib_init)                                   \
 _(l2_input_classify_init)                             \
 _(l2bd_init)                                    \
 _(l2fwd_init)                                   \
-_(l2_inacl_init)                                \
+_(l2_in_out_acl_init)                           \
 _(l2input_init)                                 \
 _(l2_vtr_init)                                  \
 _(l2_invtr_init)                                \
 _(l2_efp_filter_init)                           \
 _(l2learn_init)                                 \
 _(l2flood_init)                                 \
-_(l2_outacl_init)                               \
 _(l2output_init)                               \
 _(l2_patch_init)                               \
 _(l2_xcrw_init)