l2: Add support for arp unicast forwarding 14/18714/4
authorMohsin Kazmi <sykazmi@cisco.com>
Fri, 5 Apr 2019 15:40:20 +0000 (17:40 +0200)
committerJohn Lo <loj@cisco.com>
Wed, 24 Apr 2019 14:26:48 +0000 (14:26 +0000)
Change-Id: I79fc55f36a9b83957f84619bdf8cef08acc8ec24
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
src/vnet/l2/l2.api
src/vnet/l2/l2_api.c
src/vnet/l2/l2_bd.c
src/vnet/l2/l2_bd.h
src/vnet/l2/l2_input.c
src/vnet/l2/l2_input.h
test/vpp_l2.py

index dc74376..1c2873f 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-option version = "2.1.2";
+option version = "2.2.2";
 
 import "vnet/ip/ip_types.api";
 import "vnet/ethernet/ethernet_types.api";
@@ -247,6 +247,7 @@ autoreply define bridge_domain_set_mac_age
     @param forward - enable/disable forwarding on all interfaces in the bd
     @param learn - enable/disable learning on all interfaces in the bd
     @param arp_term - enable/disable arp termination in the bd
+    @param arp_ufwd - enable/disable arp unicast forwarding in the bd
     @param mac_age - mac aging time in min, 0 for disabled
     @param is_add - add or delete flag
 */
@@ -260,6 +261,7 @@ autoreply define bridge_domain_add_del
   u8 forward;
   u8 learn;
   u8 arp_term;
+  u8 arp_ufwd;
   u8 mac_age;
   u8 bd_tag[64];
   u8 is_add;
@@ -296,6 +298,7 @@ typeonly manual_print manual_endian define bridge_domain_sw_if
     @param forward - forwarding state on all interfaces in the bd
     @param learn - learning state on all interfaces in the bd
     @param arp_term - arp termination state on all interfaces in the bd
+    @param arp_ufwd - arp unicast forwarding state on all interfaces in the bd
     @param mac_age - mac aging time in min, 0 for disabled
     @param bd_tag - optional textual tag for the bridge domain
     @param n_sw_ifs - number of sw_if_index's in the domain
@@ -309,6 +312,7 @@ manual_print manual_endian define bridge_domain_details
   u8 forward;
   u8 learn;
   u8 arp_term;
+  u8 arp_ufwd;
   u8 mac_age;
   u8 bd_tag[64];
   u32 bvi_sw_if_index;
@@ -326,6 +330,7 @@ enum bd_flags
   BRIDGE_API_FLAG_FLOOD = 0x4,
   BRIDGE_API_FLAG_UU_FLOOD = 0x8,
   BRIDGE_API_FLAG_ARP_TERM = 0x10,
+  BRIDGE_API_FLAG_ARP_UFWD = 0x20,
 };
 
 /** \brief Set bridge flags request
index f60cd41..b55c5d3 100644 (file)
@@ -438,6 +438,7 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp)
     .forward = mp->forward,
     .learn = mp->learn,
     .arp_term = mp->arp_term,
+    .arp_ufwd = mp->arp_ufwd,
     .mac_age = mp->mac_age,
     .bd_id = ntohl (mp->bd_id),
     .bd_tag = mp->bd_tag
@@ -470,6 +471,7 @@ send_bridge_domain_details (l2input_main_t * l2im,
   mp->forward = bd_feature_forward (bd_config);
   mp->learn = bd_feature_learn (bd_config);
   mp->arp_term = bd_feature_arp_term (bd_config);
+  mp->arp_ufwd = bd_feature_arp_ufwd (bd_config);
   mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index);
   mp->uu_fwd_sw_if_index = ntohl (bd_config->uu_fwd_sw_if_index);
   mp->mac_age = bd_config->mac_age;
@@ -552,6 +554,8 @@ bd_flags_decode (vl_api_bd_flags_t v)
     f |= L2_UU_FLOOD;
   if (v & BRIDGE_API_FLAG_ARP_TERM)
     f |= L2_ARP_TERM;
+  if (v & BRIDGE_API_FLAG_ARP_UFWD)
+    f |= L2_ARP_UFWD;
 
   return (f);
 }
index 4dd359e..207ef4d 100644 (file)
@@ -52,7 +52,8 @@ bd_validate (l2_bridge_domain_t * bd_config)
 {
   if (bd_is_valid (bd_config))
     return;
-  bd_config->feature_bitmap = ~(L2INPUT_FEAT_ARP_TERM | L2INPUT_FEAT_UU_FWD);
+  bd_config->feature_bitmap =
+    ~(L2INPUT_FEAT_ARP_TERM | L2INPUT_FEAT_UU_FWD | L2INPUT_FEAT_ARP_UFWD);
   bd_config->bvi_sw_if_index = ~0;
   bd_config->uu_fwd_sw_if_index = ~0;
   bd_config->members = 0;
@@ -275,6 +276,10 @@ bd_set_flags (vlib_main_t * vm, u32 bd_index, bd_flags_t flags, u32 enable)
     {
       feature_bitmap |= L2INPUT_FEAT_ARP_TERM;
     }
+  if (flags & L2_ARP_UFWD)
+    {
+      feature_bitmap |= L2INPUT_FEAT_ARP_UFWD;
+    }
 
   if (enable)
     {
@@ -596,6 +601,71 @@ VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = {
 };
 /* *INDENT-ON* */
 
+/**
+    Set bridge-domain arp-unicast forward enable/disable.
+    The CLI format is:
+    set bridge-domain arp-ufwd <bd_index> [disable]
+*/
+static clib_error_t *
+bd_arp_ufwd (vlib_main_t * vm,
+            unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  bd_main_t *bdm = &bd_main;
+  clib_error_t *error = 0;
+  u32 bd_index, bd_id;
+  u32 enable;
+  uword *p;
+
+  if (!unformat (input, "%d", &bd_id))
+    {
+      error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
+                                format_unformat_error, input);
+      goto done;
+    }
+
+  if (bd_id == 0)
+    return clib_error_return (0,
+                             "No operations on the default bridge domain are supported");
+
+  p = hash_get (bdm->bd_index_by_bd_id, bd_id);
+
+  if (p == 0)
+    return clib_error_return (0, "No such bridge domain %d", bd_id);
+
+  bd_index = p[0];
+
+  enable = 1;
+  if (unformat (input, "disable"))
+    {
+      enable = 0;
+    }
+
+  /* set the bridge domain flag */
+  bd_set_flags (vm, bd_index, L2_ARP_UFWD, enable);
+
+done:
+  return error;
+}
+
+/*?
+ * Layer 2 arp-unicast forwarding can be enabled and disabled on each
+ * bridge-domain. It is disabled by default.
+ *
+ * @cliexpar
+ * Example of how to enable arp-unicast forwarding (where 200 is the
+ * bridge-domain-id):
+ * @cliexcmd{set bridge-domain arp-ufwd 200}
+ * Example of how to disable arp-unicast forwarding (where 200 is the bridge-domain-id):
+ * @cliexcmd{set bridge-domain arp-ufwd 200 disable}
+?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (bd_arp_ufwd_cli, static) = {
+  .path = "set bridge-domain arp-ufwd",
+  .short_help = "set bridge-domain arp-ufwd <bridge-domain-id> [disable]",
+  .function = bd_arp_ufwd,
+};
+/* *INDENT-ON* */
+
 /**
     Set bridge-domain arp term enable/disable.
     The CLI format is:
@@ -1046,10 +1116,11 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
            {
              printed = 1;
              vlib_cli_output (vm,
-                              "%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s %=11s",
+                              "%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s %=9s %=11s",
                               "BD-ID", "Index", "BSN", "Age(min)",
                               "Learning", "U-Forwrd", "UU-Flood",
-                              "Flooding", "ARP-Term", "BVI-Intf");
+                              "Flooding", "ARP-Term", "arp-ufwd",
+                              "BVI-Intf");
            }
 
          if (bd_config->mac_age)
@@ -1057,7 +1128,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
          else
            as = format (as, "off");
          vlib_cli_output (vm,
-                          "%=8d %=7d %=4d %=9v %=9s %=9s %=11U %=9s %=9s %=11U",
+                          "%=8d %=7d %=4d %=9v %=9s %=9s %=11U %=9s %=9s %=9s %=11U",
                           bd_config->bd_id, bd_index, bd_config->seq_num, as,
                           bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
                           "on" : "off",
@@ -1068,6 +1139,8 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
                           "on" : "off",
                           bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
                           "on" : "off",
+                          bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD ?
+                          "on" : "off",
                           format_vnet_sw_if_index_name_with_NA,
                           vnm, bd_config->bvi_sw_if_index);
          vec_reset_length (as);
@@ -1226,6 +1299,11 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a)
       else
        disable_flags |= L2_ARP_TERM;
 
+      if (a->arp_ufwd)
+       enable_flags |= L2_ARP_UFWD;
+      else
+       disable_flags |= L2_ARP_UFWD;
+
       if (enable_flags)
        bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ );
 
@@ -1267,7 +1345,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
   clib_error_t *error = 0;
   u8 is_add = 1;
   u32 bd_id = ~0;
-  u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0;
+  u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term =
+    0, arp_ufwd = 0;
   u32 mac_age = 0;
   u8 *bd_tag = NULL;
   l2_bridge_domain_add_del_args_t _a, *a = &_a;
@@ -1291,6 +1370,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
        ;
       else if (unformat (line_input, "arp-term %d", &arp_term))
        ;
+      else if (unformat (line_input, "arp-ufwd %d", &arp_ufwd))
+       ;
       else if (unformat (line_input, "mac-age %d", &mac_age))
        ;
       else if (unformat (line_input, "bd-tag %s", &bd_tag))
@@ -1335,6 +1416,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input,
   a->forward = (u8) forward;
   a->learn = (u8) learn;
   a->arp_term = (u8) arp_term;
+  a->arp_ufwd = (u8) arp_ufwd;
   a->mac_age = (u8) mac_age;
   a->bd_tag = bd_tag;
 
@@ -1404,7 +1486,7 @@ VLIB_CLI_COMMAND (bd_create_cli, static) = {
   .path = "create bridge-domain",
   .short_help = "create bridge-domain <bridge-domain-id>"
                 " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]"
-                " [mac-age <nn>] [bd-tag <tag>] [del]",
+                " [arp-ufwd <0|1>] [mac-age <nn>] [bd-tag <tag>] [del]",
   .function = bd_add_del_command_fn,
 };
 /* *INDENT-ON* */
index 65d3dad..3608808 100644 (file)
@@ -123,6 +123,7 @@ typedef struct
   u8 forward;
   u8 learn;
   u8 arp_term;
+  u8 arp_ufwd;
   u8 mac_age;
   u8 *bd_tag;
   u8 is_add;
@@ -152,6 +153,7 @@ typedef enum bd_flags_t_
   L2_FLOOD = (1 << 2),
   L2_UU_FLOOD = (1 << 3),
   L2_ARP_TERM = (1 << 4),
+  L2_ARP_UFWD = (1 << 5),
 } bd_flags_t;
 
 u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, bd_flags_t flags,
index 704223a..4efb556 100644 (file)
@@ -196,11 +196,13 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
                     L2INPUT_FEAT_UU_FLOOD |
                     L2INPUT_FEAT_UU_FWD | L2INPUT_FEAT_GBP_FWD);
 
+      if (ethertype != ETHERNET_TYPE_ARP)
+       feat_mask &= ~(L2INPUT_FEAT_ARP_UFWD);
+
       /* Disable ARP-term for non-ARP and non-ICMP6 packet */
       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
@@ -705,6 +707,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /*           */
                                     L2INPUT_FEAT_UU_FWD |
                                     L2INPUT_FEAT_FLOOD |
                                     L2INPUT_FEAT_LEARN |
+                                    L2INPUT_FEAT_ARP_UFWD |
                                     L2INPUT_FEAT_ARP_TERM);
 
          /* Make sure last-chance drop is configured */
index 93da127..ce9a7d5 100644 (file)
@@ -102,6 +102,7 @@ l2input_bd_config (u32 bd_index)
  _(DROP,          "feature-bitmap-drop")        \
  _(XCONNECT,      "l2-output")                  \
  _(FLOOD,         "l2-flood")                   \
+ _(ARP_UFWD,      "l2-uu-fwd")                  \
  _(ARP_TERM,      "arp-term-l2bd")              \
  _(UU_FLOOD,      "l2-flood")                   \
  _(GBP_FWD,       "gbp-fwd")                    \
@@ -190,6 +191,13 @@ bd_feature_arp_term (l2_bridge_domain_t * bd_config)
          L2INPUT_FEAT_ARP_TERM);
 }
 
+static_always_inline u8
+bd_feature_arp_ufwd (l2_bridge_domain_t * bd_config)
+{
+  return ((bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD) ==
+         L2INPUT_FEAT_ARP_UFWD);
+}
+
 /** Masks for eliminating features that do not apply to a packet */
 
 /** Get a pointer to the config for the given interface */
index 79c72e6..90de916 100644 (file)
@@ -23,6 +23,7 @@ class BRIDGE_FLAGS:
     FLOOD = 4
     UU_FLOOD = 8
     ARP_TERM = 16
+    ARP_UFWD = 32
 
 
 def find_bridge_domain(test, bd_id):
@@ -70,7 +71,7 @@ class VppBridgeDomain(VppObject):
 
     def __init__(self, test, bd_id,
                  flood=1, uu_flood=1, forward=1,
-                 learn=1, arp_term=1):
+                 learn=1, arp_term=1, arp_ufwd=0):
         self._test = test
         self.bd_id = bd_id
         self.flood = flood
@@ -78,6 +79,7 @@ class VppBridgeDomain(VppObject):
         self.forward = forward
         self.learn = learn
         self.arp_term = arp_term
+        self.arp_ufwd = arp_ufwd
 
     def add_vpp_config(self):
         self._test.vapi.bridge_domain_add_del(bd_id=self.bd_id,
@@ -85,7 +87,9 @@ class VppBridgeDomain(VppObject):
                                               uu_flood=self.uu_flood,
                                               forward=self.forward,
                                               learn=self.learn,
-                                              arp_term=self.arp_term, is_add=1)
+                                              arp_term=self.arp_term,
+                                              arp_ufwd=self.arp_ufwd,
+                                              is_add=1)
         self._test.registry.register(self, self._test.logger)
 
     def remove_vpp_config(self):