aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2018-11-21 05:44:35 -0800
committerNeale Ranns <nranns@cisco.com>2018-11-29 12:36:30 +0000
commitb6a47953973f7c94239c394b649100e91bdb2152 (patch)
treec78645ca5abb40e44b7ccd5d344bfc1059281686 /src/plugins
parentd40c3e652d487f0f165d5e595864c4ccd464de3b (diff)
GBP: l3-out subnets
Change-Id: Id4a20066fc5be716c61a497dfcb4d00dc1dbb28d Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/gbp/CMakeLists.txt1
-rw-r--r--src/plugins/gbp/gbp.api39
-rw-r--r--src/plugins/gbp/gbp_api.c95
-rw-r--r--src/plugins/gbp/gbp_bridge_domain.c10
-rw-r--r--src/plugins/gbp/gbp_bridge_domain.h1
-rw-r--r--src/plugins/gbp/gbp_classify.c283
-rw-r--r--src/plugins/gbp/gbp_endpoint.c36
-rw-r--r--src/plugins/gbp/gbp_endpoint.h9
-rw-r--r--src/plugins/gbp/gbp_ext_itf.c203
-rw-r--r--src/plugins/gbp/gbp_ext_itf.h81
-rw-r--r--src/plugins/gbp/gbp_itf.c6
-rw-r--r--src/plugins/gbp/gbp_policy_dpo.c213
-rw-r--r--src/plugins/gbp/gbp_policy_dpo.h18
-rw-r--r--src/plugins/gbp/gbp_recirc.c28
-rw-r--r--src/plugins/gbp/gbp_recirc.h9
-rw-r--r--src/plugins/gbp/gbp_route_domain.c10
-rw-r--r--src/plugins/gbp/gbp_route_domain.h1
-rw-r--r--src/plugins/gbp/gbp_scanner.c43
-rw-r--r--src/plugins/gbp/gbp_scanner.h3
-rw-r--r--src/plugins/gbp/gbp_subnet.c97
-rw-r--r--src/plugins/gbp/gbp_subnet.h1
21 files changed, 909 insertions, 278 deletions
diff --git a/src/plugins/gbp/CMakeLists.txt b/src/plugins/gbp/CMakeLists.txt
index 377197a7c08..4b511413b82 100644
--- a/src/plugins/gbp/CMakeLists.txt
+++ b/src/plugins/gbp/CMakeLists.txt
@@ -19,6 +19,7 @@ add_vpp_plugin(gbp
gbp_contract.c
gbp_endpoint.c
gbp_endpoint_group.c
+ gbp_ext_itf.c
gbp_fwd.c
gbp_fwd_dpo.c
gbp_itf.c
diff --git a/src/plugins/gbp/gbp.api b/src/plugins/gbp/gbp.api
index 6bdcc5d7e0c..bf7c167a42f 100644
--- a/src/plugins/gbp/gbp.api
+++ b/src/plugins/gbp/gbp.api
@@ -95,12 +95,13 @@ define gbp_route_domain_details
enum gbp_endpoint_flags
{
- NONE = 0,
- BOUNCE = 0x1,
- REMOTE = 0x2,
- LEARNT = 0x4,
+ GBP_API_ENDPOINT_FLAG_NONE = 0,
+ GBP_API_ENDPOINT_FLAG_BOUNCE = 0x1,
+ GBP_API_ENDPOINT_FLAG_REMOTE = 0x2,
+ GBP_API_ENDPOINT_FLAG_LEARNT = 0x4,
/* hey Ole WTF */
- REMOTE_LEARNT = 0x6,
+ GBP_API_ENDPOINT_FLAG_REMOTE_LEARNT = 0x6,
+ GBP_API_ENDPOINT_FLAG_EXTERNAL = 0x8,
};
typedef gbp_endpoint_tun
@@ -220,6 +221,7 @@ enum gbp_subnet_type
GBP_API_SUBNET_TRANSPORT,
GBP_API_SUBNET_STITCHED_INTERNAL,
GBP_API_SUBNET_STITCHED_EXTERNAL,
+ GBP_API_SUBNET_L3_OUT,
};
typeonly define gbp_subnet
@@ -379,6 +381,33 @@ define gbp_vxlan_tunnel_details
vl_api_gbp_vxlan_tunnel_t tunnel;
};
+typeonly define gbp_ext_itf
+{
+ u32 sw_if_index;
+ u32 bd_id;
+ u32 rd_id;
+};
+
+autoreply define gbp_ext_itf_add_del
+{
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ vl_api_gbp_ext_itf_t ext_itf;
+};
+
+define gbp_ext_itf_dump
+{
+ u32 client_index;
+ u32 context;
+};
+
+define gbp_ext_itf_details
+{
+ u32 context;
+ vl_api_gbp_ext_itf_t ext_itf;
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c
index 4402ec15b8c..5f87db8f83c 100644
--- a/src/plugins/gbp/gbp_api.c
+++ b/src/plugins/gbp/gbp_api.c
@@ -30,6 +30,7 @@
#include <gbp/gbp_vxlan.h>
#include <gbp/gbp_bridge_domain.h>
#include <gbp/gbp_route_domain.h>
+#include <gbp/gbp_ext_itf.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
@@ -75,6 +76,8 @@
_(GBP_ROUTE_DOMAIN_DUMP, gbp_route_domain_dump) \
_(GBP_RECIRC_ADD_DEL, gbp_recirc_add_del) \
_(GBP_RECIRC_DUMP, gbp_recirc_dump) \
+ _(GBP_EXT_ITF_ADD_DEL, gbp_ext_itf_add_del) \
+ _(GBP_EXT_ITF_DUMP, gbp_ext_itf_dump) \
_(GBP_CONTRACT_ADD_DEL, gbp_contract_add_del) \
_(GBP_CONTRACT_DUMP, gbp_contract_dump) \
_(GBP_ENDPOINT_LEARN_SET_INACTIVE_THRESHOLD, gbp_endpoint_learn_set_inactive_threshold) \
@@ -95,12 +98,14 @@ gbp_endpoint_flags_decode (vl_api_gbp_endpoint_flags_t v)
v = ntohl (v);
- if (v & BOUNCE)
+ if (v & GBP_API_ENDPOINT_FLAG_BOUNCE)
f |= GBP_ENDPOINT_FLAG_BOUNCE;
- if (v & REMOTE)
+ if (v & GBP_API_ENDPOINT_FLAG_REMOTE)
f |= GBP_ENDPOINT_FLAG_REMOTE;
- if (v & LEARNT)
+ if (v & GBP_API_ENDPOINT_FLAG_LEARNT)
f |= GBP_ENDPOINT_FLAG_LEARNT;
+ if (v & GBP_API_ENDPOINT_FLAG_EXTERNAL)
+ f |= GBP_ENDPOINT_FLAG_EXTERNAL;
return (f);
}
@@ -112,11 +117,13 @@ gbp_endpoint_flags_encode (gbp_endpoint_flags_t f)
if (f & GBP_ENDPOINT_FLAG_BOUNCE)
- v |= BOUNCE;
+ v |= GBP_API_ENDPOINT_FLAG_BOUNCE;
if (f & GBP_ENDPOINT_FLAG_REMOTE)
- v |= REMOTE;
+ v |= GBP_API_ENDPOINT_FLAG_REMOTE;
if (f & GBP_ENDPOINT_FLAG_LEARNT)
- v |= LEARNT;
+ v |= GBP_API_ENDPOINT_FLAG_LEARNT;
+ if (f & GBP_ENDPOINT_FLAG_EXTERNAL)
+ v |= GBP_API_ENDPOINT_FLAG_EXTERNAL;
v = htonl (v);
@@ -386,6 +393,9 @@ gub_subnet_type_from_api (vl_api_gbp_subnet_type_t a, gbp_subnet_type_t * t)
case GBP_API_SUBNET_TRANSPORT:
*t = GBP_SUBNET_TRANSPORT;
return (0);
+ case GBP_API_SUBNET_L3_OUT:
+ *t = GBP_SUBNET_L3_OUT;
+ return (0);
case GBP_API_SUBNET_STITCHED_INTERNAL:
*t = GBP_SUBNET_STITCHED_INTERNAL;
return (0);
@@ -440,6 +450,9 @@ gub_subnet_type_to_api (gbp_subnet_type_t t)
case GBP_SUBNET_STITCHED_EXTERNAL:
a = GBP_API_SUBNET_STITCHED_EXTERNAL;
break;
+ case GBP_SUBNET_L3_OUT:
+ a = GBP_API_SUBNET_L3_OUT;
+ break;
}
a = clib_host_to_net_u32 (a);
@@ -642,7 +655,7 @@ vl_api_gbp_recirc_add_del_t_handler (vl_api_gbp_recirc_add_del_t * mp)
REPLY_MACRO (VL_API_GBP_RECIRC_ADD_DEL_REPLY + GBP_MSG_BASE);
}
-static int
+static walk_rc_t
gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
{
vl_api_gbp_recirc_details_t *mp;
@@ -651,7 +664,7 @@ gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
ctx = args;
mp = vl_msg_api_alloc (sizeof (*mp));
if (!mp)
- return 1;
+ return (WALK_STOP);
clib_memset (mp, 0, sizeof (*mp));
mp->_vl_msg_id = ntohs (VL_API_GBP_RECIRC_DETAILS + GBP_MSG_BASE);
@@ -663,7 +676,7 @@ gbp_recirc_send_details (gbp_recirc_t * gr, void *args)
vl_api_send_msg (ctx->reg, (u8 *) mp);
- return (1);
+ return (WALK_CONTINUE);
}
static void
@@ -683,6 +696,70 @@ vl_api_gbp_recirc_dump_t_handler (vl_api_gbp_recirc_dump_t * mp)
gbp_recirc_walk (gbp_recirc_send_details, &ctx);
}
+static void
+vl_api_gbp_ext_itf_add_del_t_handler (vl_api_gbp_ext_itf_add_del_t * mp)
+{
+ vl_api_gbp_ext_itf_add_del_reply_t *rmp;
+ u32 sw_if_index;
+ int rv = 0;
+
+ sw_if_index = ntohl (mp->ext_itf.sw_if_index);
+ if (!vnet_sw_if_index_is_api_valid (sw_if_index))
+ goto bad_sw_if_index;
+
+ if (mp->is_add)
+ rv = gbp_ext_itf_add (sw_if_index,
+ ntohl (mp->ext_itf.bd_id),
+ ntohl (mp->ext_itf.rd_id));
+ else
+ rv = gbp_ext_itf_delete (sw_if_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_GBP_EXT_ITF_ADD_DEL_REPLY + GBP_MSG_BASE);
+}
+
+static walk_rc_t
+gbp_ext_itf_send_details (gbp_ext_itf_t * gx, void *args)
+{
+ vl_api_gbp_ext_itf_details_t *mp;
+ gbp_walk_ctx_t *ctx;
+
+ ctx = args;
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ if (!mp)
+ return (WALK_STOP);
+
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_GBP_EXT_ITF_DETAILS + GBP_MSG_BASE);
+ mp->context = ctx->context;
+
+ mp->ext_itf.bd_id = ntohl (gbp_bridge_domain_get_bd_id (gx->gx_bd));
+ mp->ext_itf.rd_id = ntohl (gbp_route_domain_get_rd_id (gx->gx_rd));
+ mp->ext_itf.sw_if_index = ntohl (gx->gx_itf);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_gbp_ext_itf_dump_t_handler (vl_api_gbp_ext_itf_dump_t * mp)
+{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ gbp_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+
+ gbp_ext_itf_walk (gbp_ext_itf_send_details, &ctx);
+}
+
static int
gbp_contract_rule_action_deocde (vl_api_gbp_rule_action_t in,
gbp_rule_action_t * out)
diff --git a/src/plugins/gbp/gbp_bridge_domain.c b/src/plugins/gbp/gbp_bridge_domain.c
index 298819f87f1..21ffe9cc314 100644
--- a/src/plugins/gbp/gbp_bridge_domain.c
+++ b/src/plugins/gbp/gbp_bridge_domain.c
@@ -56,6 +56,16 @@ gbp_bridge_domain_lock (index_t i)
gb->gb_locks++;
}
+u32
+gbp_bridge_domain_get_bd_id (index_t gbdi)
+{
+ gbp_bridge_domain_t *gb;
+
+ gb = gbp_bridge_domain_get (gbdi);
+
+ return (gb->gb_bd_id);
+}
+
static index_t
gbp_bridge_domain_find (u32 bd_id)
{
diff --git a/src/plugins/gbp/gbp_bridge_domain.h b/src/plugins/gbp/gbp_bridge_domain.h
index cc03320871a..65f133c84da 100644
--- a/src/plugins/gbp/gbp_bridge_domain.h
+++ b/src/plugins/gbp/gbp_bridge_domain.h
@@ -78,6 +78,7 @@ extern void gbp_bridge_domain_unlock (index_t gbi);
extern index_t gbp_bridge_domain_find_and_lock (u32 bd_id);
extern int gbp_bridge_domain_delete (u32 bd_id);
extern index_t gbp_bridge_domain_index (const gbp_bridge_domain_t *);
+extern u32 gbp_bridge_domain_get_bd_id (index_t gbdi);
typedef int (*gbp_bridge_domain_cb_t) (gbp_bridge_domain_t * gb, void *ctx);
extern void gbp_bridge_domain_walk (gbp_bridge_domain_cb_t bgpe, void *ctx);
diff --git a/src/plugins/gbp/gbp_classify.c b/src/plugins/gbp/gbp_classify.c
index 4846911ed65..94044ae7214 100644
--- a/src/plugins/gbp/gbp_classify.c
+++ b/src/plugins/gbp/gbp_classify.c
@@ -16,6 +16,11 @@
*/
#include <plugins/gbp/gbp.h>
+#include <plugins/gbp/gbp_policy_dpo.h>
+#include <plugins/gbp/gbp_ext_itf.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/dpo/load_balance.h>
#include <vnet/l2/l2_input.h>
#include <vnet/l2/feat_bitmap.h>
#include <vnet/fib/fib_table.h>
@@ -25,9 +30,10 @@ typedef enum gbp_src_classify_type_t_
{
GBP_SRC_CLASSIFY_NULL,
GBP_SRC_CLASSIFY_PORT,
+ GBP_SRC_CLASSIFY_LPM,
} gbp_src_classify_type_t;
-#define GBP_SRC_N_CLASSIFY (GBP_SRC_CLASSIFY_PORT + 1)
+#define GBP_SRC_N_CLASSIFY (GBP_SRC_CLASSIFY_LPM + 1)
/**
* Grouping of global data for the GBP source EPG classification feature
@@ -297,6 +303,276 @@ VNET_FEATURE_INIT (gbp_ip6_src_classify_feat_node, static) =
.runs_before = VNET_FEATURES ("nat66-out2in"),
};
+/* *INDENT-ON* */
+
+typedef enum gbp_lpm_classify_next_t_
+{
+ GPB_LPM_CLASSIFY_DROP,
+} gbp_lpm_classify_next_t;
+
+always_inline dpo_proto_t
+ethertype_to_dpo_proto (const ethernet_header_t * eh0)
+{
+ u16 etype = clib_net_to_host_u16 (eh0->type);
+
+ switch (etype)
+ {
+ case ETHERNET_TYPE_IP4:
+ return (DPO_PROTO_IP4);
+ case ETHERNET_TYPE_IP6:
+ return (DPO_PROTO_IP6);
+ case ETHERNET_TYPE_VLAN:
+ {
+ ethernet_vlan_header_t *vh0;
+
+ vh0 = (ethernet_vlan_header_t *) (eh0 + 1);
+
+ switch (clib_net_to_host_u16 (vh0->type))
+ {
+ case ETHERNET_TYPE_IP4:
+ return (DPO_PROTO_IP4);
+ case ETHERNET_TYPE_IP6:
+ return (DPO_PROTO_IP6);
+ }
+ }
+ }
+
+ return (DPO_PROTO_NONE);
+}
+
+/*
+ * Determine the SRC EPG from a LPM
+ */
+always_inline uword
+gbp_lpm_classify_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame,
+ dpo_proto_t dproto, u8 is_recirc)
+{
+ gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
+ u32 n_left_from, *from, *to_next;
+ u32 next_index;
+
+ next_index = 0;
+ n_left_from = frame->n_vectors;
+ from = vlib_frame_vector_args (frame);
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, sw_if_index0, fib_index0, lbi0;
+ gbp_lpm_classify_next_t next0;
+ const gbp_policy_dpo_t *gpd0;
+ const gbp_ext_itf_t *gx0;
+ const gbp_recirc_t *gr0;
+ const dpo_id_t *dpo0;
+ load_balance_t *lb0;
+ ip4_header_t *ip4_0;
+ ip6_header_t *ip6_0;
+ vlib_buffer_t *b0;
+ epg_id_t src_epg0;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+
+ b0 = vlib_get_buffer (vm, bi0);
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_NONE;
+
+ if (DPO_PROTO_IP4 == dproto)
+ ip4_0 = vlib_buffer_get_current (b0);
+ else if (DPO_PROTO_IP4 == dproto)
+ ip6_0 = vlib_buffer_get_current (b0);
+ else if (DPO_PROTO_ETHERNET == dproto)
+ {
+ const ethernet_header_t *eh0;
+
+ eh0 = vlib_buffer_get_current (b0);
+
+ dproto = ethertype_to_dpo_proto (eh0);
+
+ switch (dproto)
+ {
+ case DPO_PROTO_IP4:
+ ip4_0 = (vlib_buffer_get_current (b0) +
+ vnet_buffer (b0)->l2.l2_len);
+ break;
+ case DPO_PROTO_IP6:
+ ip6_0 = (vlib_buffer_get_current (b0) +
+ vnet_buffer (b0)->l2.l2_len);
+ break;
+ default:
+ /* not IP so no LPM classify possible */
+ src_epg0 = EPG_INVALID;
+ goto trace;
+ }
+ }
+
+ if (is_recirc)
+ {
+ gr0 = gbp_recirc_get (sw_if_index0);
+ fib_index0 = gr0->gr_fib_index[dproto];
+
+ vnet_feature_next (&next0, b0);
+ }
+ else
+ {
+ gx0 = gbp_ext_itf_get (sw_if_index0);
+ fib_index0 = gx0->gx_fib_index[dproto];
+
+ next0 = vnet_l2_feature_next
+ (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+ }
+
+ if (DPO_PROTO_IP4 == dproto)
+ {
+ lbi0 = ip4_fib_forwarding_lookup (fib_index0,
+ &ip4_0->src_address);
+ }
+ else if (DPO_PROTO_IP4 == dproto)
+ {
+ lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
+ &ip6_0->src_address);
+ }
+ else
+ {
+ /* not IP so no LPM classify possible */
+ src_epg0 = EPG_INVALID;
+ goto trace;
+ }
+ lb0 = load_balance_get (lbi0);
+ dpo0 = load_balance_get_bucket_i (lb0, 0);
+
+ if (gbp_policy_dpo_type == dpo0->dpoi_type)
+ {
+ gpd0 = gbp_policy_dpo_get (dpo0->dpoi_index);
+ src_epg0 = gpd0->gpd_epg;
+ }
+ else
+ {
+ /* could not classify => drop */
+ src_epg0 = EPG_INVALID;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+ }
+
+ trace:
+ vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
+
+ if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ gbp_classify_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->src_epg = src_epg0;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+static uword
+gbp_ip4_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP4, 1));
+}
+
+static uword
+gbp_ip6_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_IP6, 1));
+}
+
+static uword
+gbp_l2_lpm_classify (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline (vm, node, frame, DPO_PROTO_ETHERNET, 0));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
+ .function = gbp_ip4_lpm_classify,
+ .name = "ip4-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip4_lpm_classify_node, gbp_ip4_lpm_classify);
+
+VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
+ .function = gbp_ip6_lpm_classify,
+ .name = "ip6-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip6_lpm_classify_node, gbp_ip6_lpm_classify);
+
+VLIB_REGISTER_NODE (gbp_l2_lpm_classify_node) = {
+ .function = gbp_l2_lpm_classify,
+ .name = "l2-gbp-lpm-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "error-drop"
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (gbp_l2_lpm_classify_node, gbp_l2_lpm_classify);
+
+VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
+{
+ .arc_name = "ip4-unicast",
+ .node_name = "ip4-gbp-lpm-classify",
+ .runs_before = VNET_FEATURES ("nat44-out2in"),
+};
+VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
+{
+ .arc_name = "ip6-unicast",
+ .node_name = "ip6-gbp-lpm-classify",
+ .runs_before = VNET_FEATURES ("nat66-out2in"),
+};
+
+/* *INDENT-ON* */
+
static clib_error_t *
gbp_src_classify_init (vlib_main_t * vm)
{
@@ -313,6 +589,11 @@ gbp_src_classify_init (vlib_main_t * vm)
L2INPUT_N_FEAT,
l2input_get_feat_names (),
em->l2_input_feat_next[GBP_SRC_CLASSIFY_PORT]);
+ feat_bitmap_init_next_nodes (vm,
+ gbp_l2_lpm_classify_node.index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names (),
+ em->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM]);
return 0;
}
diff --git a/src/plugins/gbp/gbp_endpoint.c b/src/plugins/gbp/gbp_endpoint.c
index e9ced3f9e03..0746b70d57f 100644
--- a/src/plugins/gbp/gbp_endpoint.c
+++ b/src/plugins/gbp/gbp_endpoint.c
@@ -92,7 +92,19 @@ format_gbp_endpoint_flags (u8 * s, va_list * args)
int
gbp_endpoint_is_remote (const gbp_endpoint_t * ge)
{
- return (ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE);
+ return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_local (const gbp_endpoint_t * ge)
+{
+ return (!(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_REMOTE));
+}
+
+int
+gbp_endpoint_is_external (const gbp_endpoint_t * ge)
+{
+ return (! !(ge->ge_fwd.gef_flags & GBP_ENDPOINT_FLAG_EXTERNAL));
}
static void
@@ -625,8 +637,12 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
{
gbp_itf_set_l2_input_feature (gef->gef_itf, gei, L2INPUT_FEAT_GBP_FWD);
- if (gbp_endpoint_is_remote (ge))
+ if (gbp_endpoint_is_remote (ge) || gbp_endpoint_is_external (ge))
{
+ /*
+ * bridged packets to external endpoints should be classifed
+ * based on the EP's/BD's EPG
+ */
gbp_itf_set_l2_output_feature (gef->gef_itf, gei,
L2OUTPUT_FEAT_GBP_POLICY_MAC);
}
@@ -711,6 +727,12 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
ip_sw_if_index, rewrite);
vec_add1 (gef->gef_adjs, ai);
+ /*
+ * if the endpoint is external then routed packet to it must be
+ * classifed to the BD's EPG. but this will happen anyway with
+ * the GBP_MAC classification.
+ */
+
if (NULL != gg)
{
if (gbp_endpoint_is_remote (ge))
@@ -728,6 +750,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
FIB_SOURCE_PLUGIN_HI,
FIB_ENTRY_FLAG_INTERPOSE,
&policy_dpo);
+ dpo_reset (&policy_dpo);
}
/*
@@ -735,7 +758,7 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
* that if this EP has moved from some other place in the
* 'fabric', upstream devices are informed
*/
- if (!gbp_endpoint_is_remote (ge) && ~0 != gg->gg_uplink_sw_if_index)
+ if (gbp_endpoint_is_local (ge) && ~0 != gg->gg_uplink_sw_if_index)
{
gbp_endpoint_add_itf (gef->gef_itf, gei);
if (FIB_PROTOCOL_IP4 == pfx->fp_proto)
@@ -750,13 +773,14 @@ gbb_endpoint_fwd_recalc (gbp_endpoint_t * ge)
}
}
- if (!gbp_endpoint_is_remote (ge))
+ if (gbp_endpoint_is_local (ge) && !gbp_endpoint_is_external (ge))
{
/*
* non-remote endpoints (i.e. those not arriving on iVXLAN
* tunnels) need to be classifed based on the the input interface.
* We enable the GBP-FWD feature only if the group has an uplink
* interface (on which the GBP-FWD feature would send UU traffic).
+ * External endpoints get classified based on an LPM match
*/
l2input_feat_masks_t feats = L2INPUT_FEAT_GBP_SRC_CLASSIFY;
@@ -1444,6 +1468,10 @@ void
gbp_learn_set_inactive_threshold (u32 threshold)
{
GBP_ENDPOINT_INACTIVE_TIME = threshold;
+
+ vlib_process_signal_event (vlib_get_main (),
+ gbp_scanner_node.index,
+ GBP_ENDPOINT_SCAN_SET_TIME, 0);
}
f64
diff --git a/src/plugins/gbp/gbp_endpoint.h b/src/plugins/gbp/gbp_endpoint.h
index d56e91daa99..4b4c2e0b627 100644
--- a/src/plugins/gbp/gbp_endpoint.h
+++ b/src/plugins/gbp/gbp_endpoint.h
@@ -32,8 +32,9 @@ typedef enum gbp_endpoint_attr_t_
{
GBP_ENDPOINT_ATTR_FIRST = 0,
GBP_ENDPOINT_ATTR_BOUNCE = GBP_ENDPOINT_ATTR_FIRST,
- GBP_ENDPOINT_ATTR_REMOTE = 1,
- GBP_ENDPOINT_ATTR_LEARNT = 2,
+ GBP_ENDPOINT_ATTR_REMOTE,
+ GBP_ENDPOINT_ATTR_LEARNT,
+ GBP_ENDPOINT_ATTR_EXTERNAL,
GBP_ENDPOINT_ATTR_LAST,
} gbp_endpoint_attr_t;
@@ -43,12 +44,14 @@ typedef enum gbp_endpoint_flags_t_
GBP_ENDPOINT_FLAG_BOUNCE = (1 << GBP_ENDPOINT_ATTR_BOUNCE),
GBP_ENDPOINT_FLAG_REMOTE = (1 << GBP_ENDPOINT_ATTR_REMOTE),
GBP_ENDPOINT_FLAG_LEARNT = (1 << GBP_ENDPOINT_ATTR_LEARNT),
+ GBP_ENDPOINT_FLAG_EXTERNAL = (1 << GBP_ENDPOINT_ATTR_EXTERNAL),
} gbp_endpoint_flags_t;
#define GBP_ENDPOINT_ATTR_NAMES { \
[GBP_ENDPOINT_ATTR_BOUNCE] = "bounce", \
[GBP_ENDPOINT_ATTR_REMOTE] = "remote", \
[GBP_ENDPOINT_ATTR_LEARNT] = "learnt", \
+ [GBP_ENDPOINT_ATTR_EXTERNAL] = "external", \
}
extern u8 *format_gbp_endpoint_flags (u8 * s, va_list * args);
@@ -235,6 +238,8 @@ extern void gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx);
extern void gbp_endpoint_scan (vlib_main_t * vm);
extern f64 gbp_endpoint_scan_threshold (void);
extern int gbp_endpoint_is_remote (const gbp_endpoint_t * ge);
+extern int gbp_endpoint_is_local (const gbp_endpoint_t * ge);
+extern int gbp_endpoint_is_external (const gbp_endpoint_t * ge);
extern int gbp_endpoint_is_learnt (const gbp_endpoint_t * ge);
diff --git a/src/plugins/gbp/gbp_ext_itf.c b/src/plugins/gbp/gbp_ext_itf.c
new file mode 100644
index 00000000000..57ff625d64a
--- /dev/null
+++ b/src/plugins/gbp/gbp_ext_itf.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <plugins/gbp/gbp_ext_itf.h>
+#include <plugins/gbp/gbp_bridge_domain.h>
+#include <plugins/gbp/gbp_route_domain.h>
+#include <plugins/gbp/gbp_itf.h>
+
+/**
+ * Pool of GBP ext_itfs
+ */
+gbp_ext_itf_t *gbp_ext_itf_pool;
+
+/**
+ * external interface configs keyed by sw_if_index
+ */
+index_t *gbp_ext_itf_db;
+
+#define GBP_EXT_ITF_ID 0x00000080
+
+/**
+ * logger
+ */
+vlib_log_class_t gx_logger;
+
+#define GBP_EXT_ITF_DBG(...) \
+ vlib_log_debug (gx_logger, __VA_ARGS__);
+
+u8 *
+format_gbp_ext_itf (u8 * s, va_list * args)
+{
+ gbp_ext_itf_t *gx = va_arg (*args, gbp_ext_itf_t *);
+
+ return (format (s, "%U in %U",
+ format_gbp_itf, gx->gx_itf,
+ format_gbp_bridge_domain, gx->gx_bd));
+}
+
+int
+gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id)
+{
+ gbp_ext_itf_t *gx;
+ index_t gxi;
+
+ vec_validate_init_empty (gbp_ext_itf_db, sw_if_index, INDEX_INVALID);
+
+ gxi = gbp_ext_itf_db[sw_if_index];
+
+ if (INDEX_INVALID == gxi)
+ {
+ gbp_bridge_domain_t *gb;
+ gbp_route_domain_t *gr;
+ fib_protocol_t fproto;
+ index_t gbi, gri;
+
+ gbi = gbp_bridge_domain_find_and_lock (bd_id);
+
+ if (INDEX_INVALID == gbi)
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+
+ gri = gbp_route_domain_find_and_lock (rd_id);
+
+ if (INDEX_INVALID == gri)
+ {
+ gbp_bridge_domain_unlock (gbi);
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+ }
+
+ pool_get_zero (gbp_ext_itf_pool, gx);
+ gxi = gx - gbp_ext_itf_pool;
+
+ gb = gbp_bridge_domain_get (gbi);
+ gr = gbp_route_domain_get (gri);
+
+ gx->gx_bd = gbi;
+ gx->gx_rd = gri;
+
+ FOR_EACH_FIB_IP_PROTOCOL (fproto)
+ {
+ gx->gx_fib_index[fproto] =
+ gr->grd_fib_index[fib_proto_to_dpo (fproto)];
+ }
+
+ gx->gx_itf = gbp_itf_add_and_lock (sw_if_index, gb->gb_bd_index);
+ gbp_itf_set_l2_input_feature (gx->gx_itf, (gxi | GBP_EXT_ITF_ID),
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+
+ gbp_ext_itf_db[sw_if_index] = gxi;
+
+ GBP_EXT_ITF_DBG ("add: %U", format_gbp_ext_itf, gx);
+
+ return (0);
+ }
+
+ return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
+}
+
+int
+gbp_ext_itf_delete (u32 sw_if_index)
+{
+ gbp_ext_itf_t *gx;
+ index_t gxi;
+
+ gxi = gbp_ext_itf_db[sw_if_index];
+
+ if (INDEX_INVALID != gxi)
+ {
+ gx = pool_elt_at_index (gbp_ext_itf_pool, gxi);
+
+ GBP_EXT_ITF_DBG ("del: %U", format_gbp_ext_itf, gx);
+
+ gbp_itf_set_l2_input_feature (gx->gx_itf,
+ (gxi | GBP_EXT_ITF_ID),
+ L2INPUT_FEAT_NONE);
+ gbp_itf_unlock (gx->gx_itf);
+
+ gbp_route_domain_unlock (gx->gx_rd);
+ gbp_bridge_domain_unlock (gx->gx_bd);
+
+ gbp_ext_itf_db[sw_if_index] = INDEX_INVALID;
+ pool_put (gbp_ext_itf_pool, gx);
+
+ return (0);
+ }
+ return (VNET_API_ERROR_NO_SUCH_ENTRY);
+}
+
+void
+gbp_ext_itf_walk (gbp_ext_itf_cb_t cb, void *ctx)
+{
+ gbp_ext_itf_t *ge;
+
+ /* *INDENT-OFF* */
+ pool_foreach(ge, gbp_ext_itf_pool,
+ {
+ if (!cb(ge, ctx))
+ break;
+ });
+ /* *INDENT-ON* */
+}
+
+static walk_rc_t
+gbp_ext_itf_show_one (gbp_ext_itf_t * gx, void *ctx)
+{
+ vlib_cli_output (ctx, " %U", format_gbp_ext_itf, gx);
+
+ return (WALK_CONTINUE);
+}
+
+static clib_error_t *
+gbp_ext_itf_show (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vlib_cli_output (vm, "External-Interfaces:");
+ gbp_ext_itf_walk (gbp_ext_itf_show_one, vm);
+
+ return (NULL);
+}
+
+/*?
+ * Show Group Based Policy external interface and derived information
+ *
+ * @cliexpar
+ * @cliexstart{show gbp ext-itf}
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gbp_ext_itf_show_node, static) = {
+ .path = "show gbp ext-itf",
+ .short_help = "show gbp ext-itf\n",
+ .function = gbp_ext_itf_show,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+gbp_ext_itf_init (vlib_main_t * vm)
+{
+ gx_logger = vlib_log_register_class ("gbp", "ext-itf");
+
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (gbp_ext_itf_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/gbp/gbp_ext_itf.h b/src/plugins/gbp/gbp_ext_itf.h
new file mode 100644
index 00000000000..dafcd08a2e4
--- /dev/null
+++ b/src/plugins/gbp/gbp_ext_itf.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GBP_EXT_ITF_H__
+#define __GBP_EXT_ITF_H__
+
+#include <gbp/gbp.h>
+
+/**
+ * An external interface maps directly to an oflex L3ExternalInterface.
+ * The special characteristics of an external interface is the way the source
+ * EPG is determined for input packets which, like a recirc interface, is via
+ * a LPM.
+ */
+typedef struct gpb_ext_itf_t_
+{
+ /**
+ * The interface
+ */
+ u32 gx_itf;
+
+ /**
+ * The BD this external interface is a member of
+ */
+ index_t gx_bd;
+
+ /**
+ * The RD this external interface is a member of
+ */
+ index_t gx_rd;
+
+ /**
+ * cached FIB indices from the RD
+ */
+ u32 gx_fib_index[DPO_PROTO_NUM];
+
+} gbp_ext_itf_t;
+
+
+extern int gbp_ext_itf_add (u32 sw_if_index, u32 bd_id, u32 rd_id);
+extern int gbp_ext_itf_delete (u32 sw_if_index);
+
+extern u8 *format_gbp_ext_itf (u8 * s, va_list * args);
+
+typedef walk_rc_t (*gbp_ext_itf_cb_t) (gbp_ext_itf_t * gbpe, void *ctx);
+extern void gbp_ext_itf_walk (gbp_ext_itf_cb_t bgpe, void *ctx);
+
+
+/**
+ * Exposed types for the data-plane
+ */
+extern gbp_ext_itf_t *gbp_ext_itf_pool;
+extern index_t *gbp_ext_itf_db;
+
+always_inline gbp_ext_itf_t *
+gbp_ext_itf_get (u32 sw_if_index)
+{
+ return (pool_elt_at_index (gbp_ext_itf_pool, gbp_ext_itf_db[sw_if_index]));
+}
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/gbp/gbp_itf.c b/src/plugins/gbp/gbp_itf.c
index e1afdfb94dc..7cfe9da0ab0 100644
--- a/src/plugins/gbp/gbp_itf.c
+++ b/src/plugins/gbp/gbp_itf.c
@@ -196,9 +196,9 @@ format_gbp_itf (u8 * s, va_list * args)
s = format (s, "%U locks:%d input-feats:%U output-feats:%U",
format_vnet_sw_if_index_name, vnet_get_main (),
- gi->gi_sw_if_index, gi->gi_locks, format_l2_input_features, 0,
- gi->gi_l2_input_fb, format_l2_output_features, 0,
- gi->gi_l2_output_fb);
+ gi->gi_sw_if_index, gi->gi_locks,
+ format_l2_input_features, gi->gi_l2_input_fb, 0,
+ format_l2_output_features, gi->gi_l2_output_fb, 0);
return (s);
}
diff --git a/src/plugins/gbp/gbp_policy_dpo.c b/src/plugins/gbp/gbp_policy_dpo.c
index 7c53d1bcedb..523e23c4363 100644
--- a/src/plugins/gbp/gbp_policy_dpo.c
+++ b/src/plugins/gbp/gbp_policy_dpo.c
@@ -14,9 +14,6 @@
*/
#include <vnet/dpo/dvr_dpo.h>
-#include <vnet/fib/ip4_fib.h>
-#include <vnet/fib/ip6_fib.h>
-#include <vnet/dpo/load_balance.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
@@ -27,31 +24,19 @@
/**
* DPO pool
*/
-static gbp_policy_dpo_t *gbp_policy_dpo_pool;
+gbp_policy_dpo_t *gbp_policy_dpo_pool;
/**
* DPO type registered for these GBP FWD
*/
-static dpo_type_t gbp_policy_dpo_type;
-
-static inline gbp_policy_dpo_t *
-gbp_policy_dpo_get_i (index_t index)
-{
- return (pool_elt_at_index (gbp_policy_dpo_pool, index));
-}
-
-gbp_policy_dpo_t *
-gbp_policy_dpo_get (index_t index)
-{
- return (gbp_policy_dpo_get_i (index));
-}
+dpo_type_t gbp_policy_dpo_type;
static gbp_policy_dpo_t *
gbp_policy_dpo_alloc (void)
{
gbp_policy_dpo_t *gpd;
- pool_get_zero (gbp_policy_dpo_pool, gpd);
+ pool_get_aligned_zero (gbp_policy_dpo_pool, gpd, CLIB_CACHE_LINE_BYTES);
return (gpd);
}
@@ -61,7 +46,7 @@ gbp_policy_dpo_get_from_dpo (const dpo_id_t * dpo)
{
ASSERT (gbp_policy_dpo_type == dpo->dpoi_type);
- return (gbp_policy_dpo_get_i (dpo->dpoi_index));
+ return (gbp_policy_dpo_get (dpo->dpoi_index));
}
static inline index_t
@@ -138,7 +123,7 @@ format_gbp_policy_dpo (u8 * s, va_list * ap)
{
index_t index = va_arg (*ap, index_t);
u32 indent = va_arg (*ap, u32);
- gbp_policy_dpo_t *gpd = gbp_policy_dpo_get_i (index);
+ gbp_policy_dpo_t *gpd = gbp_policy_dpo_get (index);
vnet_main_t *vnm = vnet_get_main ();
s = format (s, "gbp-policy-dpo: %U, epg:%d out:%U",
@@ -293,8 +278,7 @@ gbp_policy_dpo_inline (vlib_main_t * vm,
b0 = vlib_get_buffer (vm, bi0);
gc0 = NULL;
- gpd0 =
- gbp_policy_dpo_get_i (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
+ gpd0 = gbp_policy_dpo_get (vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
vnet_buffer (b0)->ip.adj_index[VLIB_TX] = gpd0->gpd_dpo.dpoi_index;
if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
@@ -453,191 +437,6 @@ VLIB_NODE_FUNCTION_MULTIARCH (ip4_gbp_policy_dpo_node, ip4_gbp_policy_dpo)
VLIB_NODE_FUNCTION_MULTIARCH (ip6_gbp_policy_dpo_node, ip6_gbp_policy_dpo)
/* *INDENT-ON* */
- /**
- * per-packet trace data
- */
-typedef struct gbp_classify_trace_t_
-{
- /* per-pkt trace data */
- epg_id_t src_epg;
-} gbp_classify_trace_t;
-
-typedef enum gbp_lpm_classify_next_t_
-{
- GPB_LPM_CLASSIFY_DROP,
-} gbp_lpm_classify_next_t;
-
-/*
- * Determine the SRC EPG from a LPM
- */
-always_inline uword
-gbp_lpm_classify_inline (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame, fib_protocol_t fproto)
-{
- u32 n_left_from, *from, *to_next;
- u32 next_index;
-
- next_index = 0;
- n_left_from = frame->n_vectors;
- from = vlib_frame_vector_args (frame);
-
- while (n_left_from > 0)
- {
- u32 n_left_to_next;
-
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- while (n_left_from > 0 && n_left_to_next > 0)
- {
- u32 bi0, sw_if_index0, fib_index0, lbi0;
- gbp_lpm_classify_next_t next0;
- const gbp_policy_dpo_t *gpd0;
- const gbp_recirc_t *gr0;
- const dpo_id_t *dpo0;
- load_balance_t *lb0;
- ip4_header_t *ip4_0;
- ip6_header_t *ip6_0;
- vlib_buffer_t *b0;
- epg_id_t src_epg0;
-
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
- next0 = GPB_LPM_CLASSIFY_DROP;
-
- b0 = vlib_get_buffer (vm, bi0);
-
- sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
- gr0 = gbp_recirc_get (sw_if_index0);
- fib_index0 = gr0->gr_fib_index[fproto];
-
- if (FIB_PROTOCOL_IP4 == fproto)
- {
- ip4_0 = vlib_buffer_get_current (b0);
- lbi0 = ip4_fib_forwarding_lookup (fib_index0,
- &ip4_0->src_address);
- }
- else
- {
- ip6_0 = vlib_buffer_get_current (b0);
- lbi0 = ip6_fib_table_fwding_lookup (&ip6_main, fib_index0,
- &ip6_0->src_address);
- }
-
- lb0 = load_balance_get (lbi0);
- dpo0 = load_balance_get_bucket_i (lb0, 0);
-
- if (gbp_policy_dpo_type == dpo0->dpoi_type)
- {
- gpd0 = gbp_policy_dpo_get_i (dpo0->dpoi_index);
- src_epg0 = gpd0->gpd_epg;
- vnet_feature_next (&next0, b0);
- }
- else
- {
- /* could not classify => drop */
- src_epg0 = 0;
- }
-
- vnet_buffer2 (b0)->gbp.src_epg = src_epg0;
-
- if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED)))
- {
- gbp_classify_trace_t *t =
- vlib_add_trace (vm, node, b0, sizeof (*t));
- t->src_epg = src_epg0;
- }
-
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
- }
-
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
-
- return frame->n_vectors;
-}
-
-static uword
-gbp_ip4_lpm_classify (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP4));
-}
-
-static uword
-gbp_ip6_lpm_classify (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- return (gbp_lpm_classify_inline (vm, node, frame, FIB_PROTOCOL_IP6));
-}
-
- /* packet trace format function */
-static u8 *
-format_gbp_classify_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- gbp_classify_trace_t *t = va_arg (*args, gbp_classify_trace_t *);
-
- s = format (s, "src-epg:%d", t->src_epg);
-
- return s;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (gbp_ip4_lpm_classify_node) = {
- .function = gbp_ip4_lpm_classify,
- .name = "ip4-gbp-lpm-classify",
- .vector_size = sizeof (u32),
- .format_trace = format_gbp_classify_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = 0,
- .n_next_nodes = 1,
- .next_nodes = {
- [GPB_LPM_CLASSIFY_DROP] = "ip4-drop"
- },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip4_lpm_classify_node, gbp_ip4_lpm_classify);
-
-VLIB_REGISTER_NODE (gbp_ip6_lpm_classify_node) = {
- .function = gbp_ip6_lpm_classify,
- .name = "ip6-gbp-lpm-classify",
- .vector_size = sizeof (u32),
- .format_trace = format_gbp_classify_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
-
- .n_errors = 0,
- .n_next_nodes = 1,
- .next_nodes = {
- [GPB_LPM_CLASSIFY_DROP] = "ip6-drop"
- },
-};
-
-VLIB_NODE_FUNCTION_MULTIARCH (gbp_ip6_lpm_classify_node, gbp_ip6_lpm_classify);
-
-VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
-{
- .arc_name = "ip4-unicast",
- .node_name = "ip4-gbp-lpm-classify",
- .runs_before = VNET_FEATURES ("nat44-out2in"),
-};
-VNET_FEATURE_INIT (gbp_ip6_lpm_classify_feat_node, static) =
-{
- .arc_name = "ip6-unicast",
- .node_name = "ip6-gbp-lpm-classify",
- .runs_before = VNET_FEATURES ("nat66-out2in"),
-};
-
-/* *INDENT-ON* */
-
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_policy_dpo.h b/src/plugins/gbp/gbp_policy_dpo.h
index 8ee086d1cb0..097205b8255 100644
--- a/src/plugins/gbp/gbp_policy_dpo.h
+++ b/src/plugins/gbp/gbp_policy_dpo.h
@@ -25,6 +25,8 @@
*/
typedef struct gbp_policy_dpo_t_
{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+
/**
* The protocol of packets using this DPO
*/
@@ -46,7 +48,7 @@ typedef struct gbp_policy_dpo_t_
u16 gpd_locks;
/**
- * Stacked DPO on DVR of output interface
+ * Stacked DPO on DVR/ADJ of output interface
*/
dpo_id_t gpd_dpo;
} gbp_policy_dpo_t;
@@ -55,14 +57,24 @@ extern void gbp_policy_dpo_add_or_lock (dpo_proto_t dproto,
epg_id_t epg,
u32 sw_if_index, dpo_id_t * dpo);
-extern gbp_policy_dpo_t *gbp_policy_dpo_get (index_t index);
-
extern dpo_type_t gbp_policy_dpo_get_type (void);
extern vlib_node_registration_t ip4_gbp_policy_dpo_node;
extern vlib_node_registration_t ip6_gbp_policy_dpo_node;
extern vlib_node_registration_t gbp_policy_port_node;
+/**
+ * Types exposed for the Data-plane
+ */
+extern dpo_type_t gbp_policy_dpo_type;
+extern gbp_policy_dpo_t *gbp_policy_dpo_pool;
+
+always_inline gbp_policy_dpo_t *
+gbp_policy_dpo_get (index_t index)
+{
+ return (pool_elt_at_index (gbp_policy_dpo_pool, index));
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_recirc.c b/src/plugins/gbp/gbp_recirc.c
index 59588eafacd..d907be01b3c 100644
--- a/src/plugins/gbp/gbp_recirc.c
+++ b/src/plugins/gbp/gbp_recirc.c
@@ -21,6 +21,8 @@
#include <vnet/dpo/dvr_dpo.h>
#include <vnet/fib/fib_table.h>
+#include <vlib/unix/plugin.h>
+
/**
* Pool of GBP recircs
*/
@@ -36,6 +38,12 @@ index_t *gbp_recirc_db;
*/
vlib_log_class_t gr_logger;
+/**
+ * L2 Emulation enable/disable symbols
+ */
+static void (*l2e_enable) (u32 sw_if_index);
+static void (*l2e_disable) (u32 sw_if_index);
+
#define GBP_RECIRC_DBG(...) \
vlib_log_debug (gr_logger, __VA_ARGS__);
@@ -72,8 +80,7 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
return (VNET_API_ERROR_NO_SUCH_ENTRY);
gbp_endpoint_group_lock (ggi);
- pool_get (gbp_recirc_pool, gr);
- clib_memset (gr, 0, sizeof (*gr));
+ pool_get_zero (gbp_recirc_pool, gr);
gri = gr - gbp_recirc_pool;
gr->gr_epg = epg_id;
@@ -94,7 +101,7 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
gg = gbp_endpoint_group_get (gr->gr_epgi);
FOR_EACH_FIB_IP_PROTOCOL (fproto)
{
- gr->gr_fib_index[fproto] =
+ gr->gr_fib_index[fib_proto_to_dpo (fproto)] =
gbp_endpoint_group_get_fib_index (gg, fproto);
}
@@ -104,6 +111,11 @@ gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext)
gr->gr_itf = gbp_itf_add_and_lock (gr->gr_sw_if_index, gg->gg_bd_index);
/*
+ * set the interface into L2 emulation mode
+ */
+ l2e_enable (gr->gr_sw_if_index);
+
+ /*
* Packets on the recirculation interface are subject to src-EPG
* classification. Recirc interfaces are L2-emulation mode.
* for internal EPGs this is via an LPM on all external subnets.
@@ -195,6 +207,7 @@ gbp_recirc_delete (u32 sw_if_index)
ip4_sw_interface_enable_disable (gr->gr_sw_if_index, 0);
ip6_sw_interface_enable_disable (gr->gr_sw_if_index, 0);
+ l2e_disable (gr->gr_sw_if_index);
gbp_itf_unlock (gr->gr_itf);
@@ -218,12 +231,12 @@ gbp_recirc_walk (gbp_recirc_cb_t cb, void *ctx)
/* *INDENT-ON* */
}
-static int
+static walk_rc_t
gbp_recirc_show_one (gbp_recirc_t * gr, void *ctx)
{
vlib_cli_output (ctx, " %U", format_gbp_recirc, gr);
- return (1);
+ return (WALK_CONTINUE);
}
static clib_error_t *
@@ -256,6 +269,11 @@ gbp_recirc_init (vlib_main_t * vm)
{
gr_logger = vlib_log_register_class ("gbp", "recirc");
+ l2e_enable =
+ vlib_get_plugin_symbol ("l2e_plugin.so", "l2_emulation_enable");
+ l2e_disable =
+ vlib_get_plugin_symbol ("l2e_plugin.so", "l2_emulation_disable");
+
return (NULL);
}
diff --git a/src/plugins/gbp/gbp_recirc.h b/src/plugins/gbp/gbp_recirc.h
index 1d1a88a396b..c577a5f3ea9 100644
--- a/src/plugins/gbp/gbp_recirc.h
+++ b/src/plugins/gbp/gbp_recirc.h
@@ -20,7 +20,10 @@
#include <vnet/fib/fib_types.h>
/**
- * An Endpoint Group representation
+ * A GBP recirculation interface representation
+ * Thes interfaces join Bridge domains that are internal to those that are
+ * NAT external, so the packets can be NAT translated and then undergo the
+ * whole policy process again.
*/
typedef struct gpb_recirc_t_
{
@@ -37,7 +40,7 @@ typedef struct gpb_recirc_t_
/**
* FIB indices the EPG is mapped to
*/
- u32 gr_fib_index[FIB_PROTOCOL_IP_MAX];
+ u32 gr_fib_index[DPO_PROTO_NUM];
/**
* Is the interface for packets post-NAT translation (i.e. ext)
@@ -59,7 +62,7 @@ typedef struct gpb_recirc_t_
extern int gbp_recirc_add (u32 sw_if_index, epg_id_t epg_id, u8 is_ext);
extern void gbp_recirc_delete (u32 sw_if_index);
-typedef int (*gbp_recirc_cb_t) (gbp_recirc_t * gbpe, void *ctx);
+typedef walk_rc_t (*gbp_recirc_cb_t) (gbp_recirc_t * gbpe, void *ctx);
extern void gbp_recirc_walk (gbp_recirc_cb_t bgpe, void *ctx);
/**
diff --git a/src/plugins/gbp/gbp_route_domain.c b/src/plugins/gbp/gbp_route_domain.c
index df3959edca6..67b6915b463 100644
--- a/src/plugins/gbp/gbp_route_domain.c
+++ b/src/plugins/gbp/gbp_route_domain.c
@@ -231,6 +231,16 @@ gbp_route_domain_unlock (index_t index)
}
}
+u32
+gbp_route_domain_get_rd_id (index_t grdi)
+{
+ gbp_route_domain_t *grd;
+
+ grd = gbp_route_domain_get (grdi);
+
+ return (grd->grd_id);
+}
+
int
gbp_route_domain_delete (u32 rd_id)
{
diff --git a/src/plugins/gbp/gbp_route_domain.h b/src/plugins/gbp/gbp_route_domain.h
index ba5d5e49aca..b83d598ad38 100644
--- a/src/plugins/gbp/gbp_route_domain.h
+++ b/src/plugins/gbp/gbp_route_domain.h
@@ -66,6 +66,7 @@ extern index_t gbp_route_domain_index (const gbp_route_domain_t *);
extern int gbp_route_domain_delete (u32 rd_id);
extern gbp_route_domain_t *gbp_route_domain_get (index_t i);
+extern u32 gbp_route_domain_get_rd_id (index_t i);
typedef int (*gbp_route_domain_cb_t) (gbp_route_domain_t * gb, void *ctx);
extern void gbp_route_domain_walk (gbp_route_domain_cb_t bgpe, void *ctx);
diff --git a/src/plugins/gbp/gbp_scanner.c b/src/plugins/gbp/gbp_scanner.c
index a2d0c9a98cb..90507a60568 100644
--- a/src/plugins/gbp/gbp_scanner.c
+++ b/src/plugins/gbp/gbp_scanner.c
@@ -19,8 +19,16 @@
#include <plugins/gbp/gbp_endpoint.h>
#include <plugins/gbp/gbp_vxlan.h>
+/**
+ * Scanner logger
+ */
vlib_log_class_t gs_logger;
+/**
+ * Scanner state
+ */
+static bool gs_enabled;
+
#define GBP_SCANNER_DBG(...) \
vlib_log_debug (gs_logger, __VA_ARGS__);
@@ -28,13 +36,13 @@ static uword
gbp_scanner (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
{
uword event_type, *event_data = 0;
- bool enabled = 0, do_scan = 0;
+ bool do_scan = 0;
while (1)
{
do_scan = 0;
- if (enabled)
+ if (gs_enabled)
{
/* scan every 'inactive threshold' seconds */
vlib_process_wait_for_event_or_clock (vm,
@@ -55,11 +63,14 @@ gbp_scanner (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
break;
case GBP_ENDPOINT_SCAN_START:
- enabled = 1;
+ gs_enabled = 1;
break;
case GBP_ENDPOINT_SCAN_STOP:
- enabled = 0;
+ gs_enabled = 0;
+ break;
+
+ case GBP_ENDPOINT_SCAN_SET_TIME:
break;
default:
@@ -84,6 +95,30 @@ VLIB_REGISTER_NODE (gbp_scanner_node) = {
};
/* *INDENT-ON* */
+static clib_error_t *
+gbp_scanner_cli (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vlib_cli_output (vm, "GBP-scanner: enabled:%d interval:%f",
+ gs_enabled, gbp_endpoint_scan_threshold ());
+
+ return (NULL);
+}
+
+/*?
+ * Show GBP scanner
+ *
+ * @cliexpar
+ * @cliexstart{show gbp scanner}
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gbp_scanner_cli_node, static) = {
+ .path = "show gbp scanner",
+ .short_help = "show gbp scanner",
+ .function = gbp_scanner_cli,
+};
+/* *INDENT-ON* */
static clib_error_t *
gbp_scanner_init (vlib_main_t * vm)
diff --git a/src/plugins/gbp/gbp_scanner.h b/src/plugins/gbp/gbp_scanner.h
index 070da3892ca..1133167d927 100644
--- a/src/plugins/gbp/gbp_scanner.h
+++ b/src/plugins/gbp/gbp_scanner.h
@@ -22,8 +22,7 @@ typedef enum gbp_scan_event_t_
{
GBP_ENDPOINT_SCAN_START,
GBP_ENDPOINT_SCAN_STOP,
- GBP_VXLAN_SCAN_START,
- GBP_VXLAN_SCAN_STOP,
+ GBP_ENDPOINT_SCAN_SET_TIME,
} gbp_scan_event_t;
extern vlib_node_registration_t gbp_scanner_node;
diff --git a/src/plugins/gbp/gbp_subnet.c b/src/plugins/gbp/gbp_subnet.c
index d9d42997aa7..b0b6db8040e 100644
--- a/src/plugins/gbp/gbp_subnet.c
+++ b/src/plugins/gbp/gbp_subnet.c
@@ -46,7 +46,13 @@ typedef struct gbp_subnet_t_
epg_id_t gs_epg;
u32 gs_sw_if_index;
} gs_stitched_external;
+ struct
+ {
+ epg_id_t gs_epg;
+ } gs_l3_out;
};
+
+ fib_node_index_t gs_fei;
} gbp_subnet_t;
/**
@@ -102,7 +108,7 @@ gbp_subnet_db_del (gbp_subnet_t * gs)
static int
-gbp_subnet_transport_add (const gbp_subnet_t * gs)
+gbp_subnet_transport_add (gbp_subnet_t * gs)
{
dpo_id_t gfd = DPO_INVALID;
gbp_route_domain_t *grd;
@@ -111,14 +117,15 @@ gbp_subnet_transport_add (const gbp_subnet_t * gs)
fproto = gs->gs_key->gsk_pfx.fp_proto;
grd = gbp_route_domain_get (gs->gs_rd);
- fib_table_entry_update_one_path (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- FIB_ENTRY_FLAG_NONE,
- fib_proto_to_dpo (fproto),
- &ADJ_BCAST_ADDR,
- grd->grd_uu_sw_if_index[fproto],
- ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
+ gs->gs_fei = fib_table_entry_update_one_path (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ FIB_ENTRY_FLAG_NONE,
+ fib_proto_to_dpo (fproto),
+ &ADJ_BCAST_ADDR,
+ grd->grd_uu_sw_if_index
+ [fproto], ~0, 1, NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
dpo_reset (&gfd);
@@ -126,17 +133,18 @@ gbp_subnet_transport_add (const gbp_subnet_t * gs)
}
static int
-gbp_subnet_internal_add (const gbp_subnet_t * gs)
+gbp_subnet_internal_add (gbp_subnet_t * gs)
{
dpo_id_t gfd = DPO_INVALID;
gbp_fwd_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto),
&gfd);
- fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- FIB_ENTRY_FLAG_EXCLUSIVE, &gfd);
+ gs->gs_fei = fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ FIB_ENTRY_FLAG_EXCLUSIVE,
+ &gfd);
dpo_reset (&gfd);
@@ -155,12 +163,33 @@ gbp_subnet_external_add (gbp_subnet_t * gs, u32 sw_if_index, epg_id_t epg)
gs->gs_stitched_external.gs_epg,
gs->gs_stitched_external.gs_sw_if_index, &gpd);
- fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx,
- FIB_SOURCE_PLUGIN_HI,
- (FIB_ENTRY_FLAG_EXCLUSIVE |
- FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
- &gpd);
+ gs->gs_fei = fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_PLUGIN_HI,
+ (FIB_ENTRY_FLAG_EXCLUSIVE |
+ FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT),
+ &gpd);
+
+ dpo_reset (&gpd);
+
+ return (0);
+}
+
+static int
+gbp_subnet_l3_out_add (gbp_subnet_t * gs, u32 sw_if_index, epg_id_t epg)
+{
+ dpo_id_t gpd = DPO_INVALID;
+
+ gs->gs_l3_out.gs_epg = epg;
+
+ gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto),
+ gs->gs_l3_out.gs_epg, ~0, &gpd);
+
+ gs->gs_fei = fib_table_entry_special_dpo_add (gs->gs_key->gsk_fib_index,
+ &gs->gs_key->gsk_pfx,
+ FIB_SOURCE_SPECIAL,
+ FIB_ENTRY_FLAG_INTERPOSE,
+ &gpd);
dpo_reset (&gpd);
@@ -190,7 +219,10 @@ gbp_subnet_del (u32 rd_id, const fib_prefix_t * pfx)
gs = pool_elt_at_index (gbp_subnet_pool, gsi);
- fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
+ if (GBP_SUBNET_L3_OUT == gs->gs_type)
+ fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_SPECIAL);
+ else
+ fib_table_entry_delete (fib_index, pfx, FIB_SOURCE_PLUGIN_HI);
gbp_subnet_db_del (gs);
gbp_route_domain_unlock (gs->gs_rd);
@@ -243,6 +275,9 @@ gbp_subnet_add (u32 rd_id,
case GBP_SUBNET_TRANSPORT:
rv = gbp_subnet_transport_add (gs);
break;
+ case GBP_SUBNET_L3_OUT:
+ rv = gbp_subnet_l3_out_add (gs, sw_if_index, epg);
+ break;
}
return (rv);
@@ -274,10 +309,13 @@ gbp_subnet_walk (gbp_subnet_cb_t cb, void *ctx)
sw_if_index = gs->gs_stitched_external.gs_sw_if_index;
epg = gs->gs_stitched_external.gs_epg;
break;
+ case GBP_SUBNET_L3_OUT:
+ epg = gs->gs_l3_out.gs_epg;
+ break;
}
if (WALK_STOP == cb (grd->grd_id, &gs->gs_key->gsk_pfx,
- gs->gs_type, epg, sw_if_index, ctx))
+ gs->gs_type, sw_if_index, epg, ctx))
break;
}));
/* *INDENT-ON* */
@@ -302,6 +340,8 @@ format_gbp_subnet_type (u8 * s, va_list * args)
return (format (s, "stitched-external"));
case GBP_SUBNET_TRANSPORT:
return (format (s, "transport"));
+ case GBP_SUBNET_L3_OUT:
+ return (format (s, "l3-out"));
}
return (format (s, "unknown"));
@@ -334,20 +374,17 @@ format_gbp_subnet (u8 * s, va_list * args)
format_vnet_sw_if_index_name,
vnet_get_main (), gs->gs_stitched_external.gs_sw_if_index);
break;
+ case GBP_SUBNET_L3_OUT:
+ s = format (s, " {epg:%d}", gs->gs_l3_out.gs_epg);
+ break;
}
switch (flags)
{
case GBP_SUBNET_SHOW_DETAILS:
{
- fib_node_index_t fei;
-
- fei = fib_table_lookup_exact_match (gs->gs_key->gsk_fib_index,
- &gs->gs_key->gsk_pfx);
-
- s =
- format (s, "\n %U", format_fib_entry, fei,
- FIB_ENTRY_FORMAT_DETAIL);
+ s = format (s, "\n %U", format_fib_entry, gs->gs_fei,
+ FIB_ENTRY_FORMAT_DETAIL);
}
case GBP_SUBNET_SHOW_BRIEF:
break;
diff --git a/src/plugins/gbp/gbp_subnet.h b/src/plugins/gbp/gbp_subnet.h
index b6906dee674..5fbd4b23df0 100644
--- a/src/plugins/gbp/gbp_subnet.h
+++ b/src/plugins/gbp/gbp_subnet.h
@@ -23,6 +23,7 @@ typedef enum gbp_subnet_type_t_
GBP_SUBNET_TRANSPORT,
GBP_SUBNET_STITCHED_INTERNAL,
GBP_SUBNET_STITCHED_EXTERNAL,
+ GBP_SUBNET_L3_OUT,
} gbp_subnet_type_t;
extern int gbp_subnet_add (u32 rd_id,