From 5e6f7348cf456cffc85dae8bc6857589061122ba Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Fri, 5 Apr 2019 17:40:20 +0200 Subject: l2: Add support for arp unicast forwarding Change-Id: I79fc55f36a9b83957f84619bdf8cef08acc8ec24 Signed-off-by: Mohsin Kazmi --- src/vnet/l2/l2.api | 7 +++- src/vnet/l2/l2_api.c | 4 +++ src/vnet/l2/l2_bd.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++---- src/vnet/l2/l2_bd.h | 2 ++ src/vnet/l2/l2_input.c | 5 ++- src/vnet/l2/l2_input.h | 8 +++++ test/vpp_l2.py | 8 +++-- 7 files changed, 118 insertions(+), 10 deletions(-) diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index dc743763f70..1c2873fdf3c 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -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 diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index f60cd41bb39..b55c5d3744a 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -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); } diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 4dd359ed0b7..207ef4d6601 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -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 [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 [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 " " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]" - " [mac-age ] [bd-tag ] [del]", + " [arp-ufwd <0|1>] [mac-age ] [bd-tag ] [del]", .function = bd_add_del_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 65d3dadab28..360880839ec 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -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, diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 704223a3d75..4efb5562806 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -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 */ diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index 93da1277e67..ce9a7d5f0cd 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -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 */ diff --git a/test/vpp_l2.py b/test/vpp_l2.py index 79c72e69051..90de91695f2 100644 --- a/test/vpp_l2.py +++ b/test/vpp_l2.py @@ -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): -- cgit 1.2.3-korg