aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBenoît Ganne <bganne@cisco.com>2019-06-26 13:36:51 +0200
committerNeale Ranns <nranns@cisco.com>2019-07-02 14:19:07 +0000
commitcfc7a107e6cb8be6e7c53a08e23a146c431c8e90 (patch)
tree2179e92193ce7453b6eb67ba94a3c881f998f4fc /src
parent2ec825937b7ac856f67d086ce6814dd21c5e9bd7 (diff)
gbp: add anonymous l3-out external interfaces
So far, GBP l3-out packets classification & policy relied on programmed EP. All traffic to/from l3-out must go through a known EP. This patch introduces a new feature where l3-out next-hops are only known by their subnets (l3-out prefixes). As there are no longer known EPs to program, an interface must be configured as external anonymous l3-out. Packets classification & policy on this interface will rely on the external subnets programmed in the BD VRF. Note that contrary to all other interfaces in a GBP BD, external anonymous l3-out interfaces have BD L2 learning turned on and rely on ARP/ND. Type: feature Change-Id: Ieedb29dff4e967d08c4301e82d06bff450a63e5f Signed-off-by: Benoît Ganne <bganne@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/gbp/gbp.api8
-rw-r--r--src/plugins/gbp/gbp.h11
-rw-r--r--src/plugins/gbp/gbp_api.c31
-rw-r--r--src/plugins/gbp/gbp_api_print.h23
-rw-r--r--src/plugins/gbp/gbp_classify.c8
-rw-r--r--src/plugins/gbp/gbp_classify.h45
-rw-r--r--src/plugins/gbp/gbp_classify_node.c216
-rw-r--r--src/plugins/gbp/gbp_ext_itf.c114
-rw-r--r--src/plugins/gbp/gbp_ext_itf.h3
-rw-r--r--src/plugins/gbp/gbp_policy.c14
-rw-r--r--src/plugins/gbp/gbp_policy_dpo.h29
-rw-r--r--src/plugins/gbp/gbp_policy_node.c135
-rw-r--r--src/vnet/l2/l2_input.h1
-rw-r--r--src/vnet/l2/l2_output.h1
14 files changed, 483 insertions, 156 deletions
diff --git a/src/plugins/gbp/gbp.api b/src/plugins/gbp/gbp.api
index f6775e7dcd7..d1e483d5e5d 100644
--- a/src/plugins/gbp/gbp.api
+++ b/src/plugins/gbp/gbp.api
@@ -419,6 +419,14 @@ define gbp_ext_itf_details
vl_api_gbp_ext_itf_t ext_itf;
};
+manual_print autoreply define gbp_ext_itf_anon_add_del
+{
+ u32 client_index;
+ u32 context;
+ u8 is_add;
+ vl_api_gbp_ext_itf_t ext_itf;
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/plugins/gbp/gbp.h b/src/plugins/gbp/gbp.h
index 35e02d26ca7..e194a9df82c 100644
--- a/src/plugins/gbp/gbp.h
+++ b/src/plugins/gbp/gbp.h
@@ -48,6 +48,15 @@ typedef struct
extern gbp_main_t gbp_main;
+typedef enum gbp_policy_type_t_
+{
+ GBP_POLICY_PORT,
+ GBP_POLICY_MAC,
+ GBP_POLICY_LPM,
+ GBP_N_POLICY
+#define GBP_N_POLICY GBP_N_POLICY
+} gbp_policy_type_t;
+
/**
* Grouping of global data for the GBP source EPG classification feature
*/
@@ -56,7 +65,7 @@ typedef struct gbp_policy_main_t_
/**
* Next nodes for L2 output features
*/
- u32 l2_output_feat_next[2][32];
+ u32 l2_output_feat_next[GBP_N_POLICY][32];
} gbp_policy_main_t;
extern gbp_policy_main_t gbp_policy_main;
diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c
index 8155a8ff0f1..010e3087eb3 100644
--- a/src/plugins/gbp/gbp_api.c
+++ b/src/plugins/gbp/gbp_api.c
@@ -82,7 +82,8 @@
_(GBP_CONTRACT_DUMP, gbp_contract_dump) \
_(GBP_VXLAN_TUNNEL_ADD, gbp_vxlan_tunnel_add) \
_(GBP_VXLAN_TUNNEL_DEL, gbp_vxlan_tunnel_del) \
- _(GBP_VXLAN_TUNNEL_DUMP, gbp_vxlan_tunnel_dump)
+ _(GBP_VXLAN_TUNNEL_DUMP, gbp_vxlan_tunnel_dump) \
+ _(GBP_EXT_ITF_ANON_ADD_DEL, gbp_ext_itf_anon_add_del)
gbp_main_t gbp_main;
@@ -1146,6 +1147,34 @@ vl_api_gbp_vxlan_tunnel_dump_t_handler (vl_api_gbp_vxlan_tunnel_dump_t * mp)
gbp_vxlan_walk (gbp_vxlan_tunnel_send_details, &ctx);
}
+static void
+vl_api_gbp_ext_itf_anon_add_del_t_handler (vl_api_gbp_ext_itf_anon_add_del_t *
+ mp)
+{
+ vl_api_gbp_ext_itf_anon_add_del_reply_t *rmp;
+ u32 sw_if_index = ~0;
+ vl_api_gbp_ext_itf_t *ext_itf;
+ int rv = 0;
+
+ ext_itf = &mp->ext_itf;
+ if (ext_itf)
+ sw_if_index = ntohl (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_anon_add (sw_if_index,
+ ntohl (ext_itf->bd_id),
+ ntohl (ext_itf->rd_id));
+ else
+ rv = gbp_ext_itf_anon_delete (sw_if_index);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_GBP_EXT_ITF_ANON_ADD_DEL_REPLY + GBP_MSG_BASE);
+}
+
/*
* gbp_api_hookup
* Add vpe's API message handlers to the table.
diff --git a/src/plugins/gbp/gbp_api_print.h b/src/plugins/gbp/gbp_api_print.h
index 67cd30c7da7..b3afc94dc4b 100644
--- a/src/plugins/gbp/gbp_api_print.h
+++ b/src/plugins/gbp/gbp_api_print.h
@@ -340,6 +340,29 @@ vl_api_gbp_ext_itf_add_del_t_print (vl_api_gbp_ext_itf_add_del_t * a,
return handle;
}
+static inline void *
+vl_api_gbp_ext_itf_anon_add_del_t_print (vl_api_gbp_ext_itf_anon_add_del_t *
+ a, void *handle)
+{
+ u8 *s = 0;
+
+ s = format (s, "SCRIPT: gbp_ext_itf_anon_add_del ");
+ if (a->is_add)
+ s = format (s, "add ");
+ else
+ s = format (s, "del ");
+
+ s = format (s, "sw_if_index %d ", ntohl (a->ext_itf.sw_if_index));
+ s = format (s, "bd_id %d ", ntohl (a->ext_itf.bd_id));
+ s = format (s, "rd_id %d ", ntohl (a->ext_itf.rd_id));
+
+ s = format (s, "\n");
+
+ PRINT_S;
+
+ return handle;
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_classify.c b/src/plugins/gbp/gbp_classify.c
index 5735f359af0..255db252871 100644
--- a/src/plugins/gbp/gbp_classify.c
+++ b/src/plugins/gbp/gbp_classify.c
@@ -49,6 +49,14 @@ gbp_src_classify_init (vlib_main_t * vm)
l2input_get_feat_names (),
em->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM]);
+ node = vlib_get_node_by_name (vm, (u8 *) "l2-gbp-lpm-anon-classify");
+ feat_bitmap_init_next_nodes (vm,
+ node->index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names (),
+ em->l2_input_feat_next
+ [GBP_SRC_CLASSIFY_LPM_ANON]);
+
return 0;
}
diff --git a/src/plugins/gbp/gbp_classify.h b/src/plugins/gbp/gbp_classify.h
index c0c1fd53dc5..ca7db94a2c0 100644
--- a/src/plugins/gbp/gbp_classify.h
+++ b/src/plugins/gbp/gbp_classify.h
@@ -19,16 +19,18 @@
#define __GBP_CLASSIFY_H__
#include <plugins/gbp/gbp.h>
+#include <vnet/ethernet/arp_packet.h>
typedef enum gbp_src_classify_type_t_
{
GBP_SRC_CLASSIFY_NULL,
GBP_SRC_CLASSIFY_PORT,
GBP_SRC_CLASSIFY_LPM,
+ GBP_SRC_CLASSIFY_LPM_ANON,
+ GBP_SRC_N_CLASSIFY
+#define GBP_SRC_N_CLASSIFY GBP_SRC_N_CLASSIFY
} gbp_src_classify_type_t;
-#define GBP_SRC_N_CLASSIFY (GBP_SRC_CLASSIFY_LPM + 1)
-
/**
* Grouping of global data for the GBP source EPG classification feature
*/
@@ -42,6 +44,45 @@ typedef struct gbp_src_classify_main_t_
extern gbp_src_classify_main_t gbp_src_classify_main;
+enum gbp_classify_get_ip_way
+{
+ GBP_CLASSIFY_GET_IP_SRC = 0,
+ GBP_CLASSIFY_GET_IP_DST = 1
+};
+
+static_always_inline dpo_proto_t
+gbp_classify_get_ip_address (const ethernet_header_t * eh0,
+ const ip4_address_t ** ip4,
+ const ip6_address_t ** ip6,
+ const enum gbp_classify_get_ip_way way)
+{
+ u16 etype = clib_net_to_host_u16 (eh0->type);
+ const void *l3h0 = eh0 + 1;
+
+ if (ETHERNET_TYPE_VLAN == etype)
+ {
+ const ethernet_vlan_header_t *vh0 =
+ (ethernet_vlan_header_t *) (eh0 + 1);
+ etype = clib_net_to_host_u16 (vh0->type);
+ l3h0 = vh0 + 1;
+ }
+
+ switch (etype)
+ {
+ case ETHERNET_TYPE_IP4:
+ *ip4 = &(&((const ip4_header_t *) l3h0)->src_address)[way];
+ return DPO_PROTO_IP4;
+ case ETHERNET_TYPE_IP6:
+ *ip6 = &(&((const ip6_header_t *) l3h0)->src_address)[way];
+ return DPO_PROTO_IP6;
+ case ETHERNET_TYPE_ARP:
+ *ip4 = &((ethernet_arp_header_t *) l3h0)->ip4_over_ethernet[way].ip4;
+ return DPO_PROTO_IP4;
+ }
+
+ return DPO_PROTO_NONE;
+}
+
#endif
/*
diff --git a/src/plugins/gbp/gbp_classify_node.c b/src/plugins/gbp/gbp_classify_node.c
index 9ad2b06148d..a2058a21284 100644
--- a/src/plugins/gbp/gbp_classify_node.c
+++ b/src/plugins/gbp/gbp_classify_node.c
@@ -279,36 +279,6 @@ typedef enum gbp_lpm_classify_next_t_
GPB_LPM_CLASSIFY_DROP,
} gbp_lpm_classify_next_t;
-always_inline void
-gbp_classify_get_src_ip_address (const ethernet_header_t * eh0,
- const ip4_address_t ** ip4,
- const ip6_address_t ** ip6)
-{
- u16 etype = clib_net_to_host_u16 (eh0->type);
- const void *l3h0 = eh0 + 1;
-
- if (ETHERNET_TYPE_VLAN == etype)
- {
- const ethernet_vlan_header_t *vh0 =
- (ethernet_vlan_header_t *) (eh0 + 1);
- etype = clib_net_to_host_u16 (vh0->type);
- l3h0 = vh0 + 1;
- }
-
- switch (etype)
- {
- case ETHERNET_TYPE_IP4:
- *ip4 = &((const ip4_header_t *) l3h0)->src_address;
- break;
- case ETHERNET_TYPE_IP6:
- *ip6 = &((const ip6_header_t *) l3h0)->src_address;
- break;
- case ETHERNET_TYPE_ARP:
- *ip4 = &((ethernet_arp_header_t *) l3h0)->ip4_over_ethernet[0].ip4;
- break;
- }
-}
-
/**
* per-packet trace data
*/
@@ -333,6 +303,13 @@ format_gbp_lpm_classify_trace (u8 * s, va_list * args)
return s;
}
+enum gbp_lpm_type
+{
+ GBP_LPM_RECIRC,
+ GBP_LPM_EPG,
+ GBP_LPM_ANON
+};
+
/*
* Determine the SRC EPG from a LPM
*/
@@ -340,7 +317,8 @@ 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)
+ const dpo_proto_t dproto,
+ const enum gbp_lpm_type type)
{
gbp_src_classify_main_t *gscm = &gbp_src_classify_main;
u32 n_left_from, *from, *to_next;
@@ -366,8 +344,6 @@ gbp_lpm_classify_inline (vlib_main_t * vm,
const ip4_address_t *ip4_0;
const ip6_address_t *ip6_0;
const gbp_recirc_t *gr0;
- const dpo_id_t *dpo0;
- load_balance_t *lb0;
vlib_buffer_t *b0;
sclass_t sclass0;
@@ -397,10 +373,11 @@ gbp_lpm_classify_inline (vlib_main_t * vm,
else if (DPO_PROTO_ETHERNET == dproto)
{
eh0 = vlib_buffer_get_current (b0);
- gbp_classify_get_src_ip_address (eh0, &ip4_0, &ip6_0);
+ gbp_classify_get_ip_address (eh0, &ip4_0, &ip6_0,
+ GBP_CLASSIFY_GET_IP_SRC);
}
- if (is_recirc)
+ if (GBP_LPM_RECIRC == type)
{
gr0 = gbp_recirc_get (sw_if_index0);
fib_index0 = gr0->gr_fib_index[dproto];
@@ -417,96 +394,105 @@ gbp_lpm_classify_inline (vlib_main_t * vm,
goto trace;
}
- ge0 = gbp_endpoint_find_mac (eh0->src_address,
- vnet_buffer (b0)->l2.bd_index);
-
- if (NULL == ge0)
+ if (GBP_LPM_ANON == type)
{
- /* packet must have come from an EP's mac */
- sclass0 = SCLASS_INVALID;
- goto trace;
- }
-
- fib_index0 = ge0->ge_fwd.gef_fib_index;
-
- if (~0 == fib_index0)
- {
- sclass0 = SCLASS_INVALID;
- goto trace;
- }
-
- if (ip4_0)
- {
- ge_lpm0 = gbp_endpoint_find_ip4 (ip4_0, fib_index0);
- }
- else if (ip6_0)
- {
- ge_lpm0 = gbp_endpoint_find_ip6 (ip6_0, fib_index0);
+ /*
+ * anonymous LPM classification: only honour LPM as no EP
+ * were programmed
+ */
+ gbp_ext_itf_t *gei = gbp_ext_itf_get (sw_if_index0);
+ if (ip4_0)
+ fib_index0 = gei->gx_fib_index[DPO_PROTO_IP4];
+ else if (ip6_0)
+ fib_index0 = gei->gx_fib_index[DPO_PROTO_IP6];
+ else
+ {
+ /* not IP so no LPM classify possible */
+ sclass0 = SCLASS_INVALID;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+ goto trace;
+ }
+ next0 = vnet_l2_feature_next
+ (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM_ANON],
+ L2INPUT_FEAT_GBP_LPM_ANON_CLASSIFY);
}
else
{
- ge_lpm0 = NULL;
- }
+ /*
+ * not an anonymous LPM classification: check it comes from
+ * an EP, and use EP RD info
+ */
+ ge0 = gbp_endpoint_find_mac (eh0->src_address,
+ vnet_buffer (b0)->l2.bd_index);
- next0 = vnet_l2_feature_next
- (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
- L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+ if (NULL == ge0)
+ {
+ /* packet must have come from an EP's mac */
+ sclass0 = SCLASS_INVALID;
+ goto trace;
+ }
- /*
- * if we found the EP by IP lookup, it must be from the EP
- * not a network behind it
- */
- if (NULL != ge_lpm0)
- {
- if (PREDICT_FALSE (ge0 != ge_lpm0))
+ fib_index0 = ge0->ge_fwd.gef_fib_index;
+
+ if (~0 == fib_index0)
{
- /* an EP spoofing another EP */
sclass0 = SCLASS_INVALID;
- next0 = GPB_LPM_CLASSIFY_DROP;
+ goto trace;
+ }
+
+ if (ip4_0)
+ {
+ ge_lpm0 = gbp_endpoint_find_ip4 (ip4_0, fib_index0);
+ }
+ else if (ip6_0)
+ {
+ ge_lpm0 = gbp_endpoint_find_ip6 (ip6_0, fib_index0);
}
else
{
- sclass0 = ge0->ge_fwd.gef_sclass;
+ ge_lpm0 = NULL;
+ }
+
+ next0 = vnet_l2_feature_next
+ (b0, gscm->l2_input_feat_next[GBP_SRC_CLASSIFY_LPM],
+ L2INPUT_FEAT_GBP_LPM_CLASSIFY);
+
+ /*
+ * if we found the EP by IP lookup, it must be from the EP
+ * not a network behind it
+ */
+ if (NULL != ge_lpm0)
+ {
+ if (PREDICT_FALSE (ge0 != ge_lpm0))
+ {
+ /* an EP spoofing another EP */
+ sclass0 = SCLASS_INVALID;
+ next0 = GPB_LPM_CLASSIFY_DROP;
+ }
+ else
+ {
+ sclass0 = ge0->ge_fwd.gef_sclass;
+ }
+ goto trace;
}
- goto trace;
}
}
- if (ip4_0)
- {
- lbi0 = ip4_fib_forwarding_lookup (fib_index0, ip4_0);
- }
- else if (ip6_0)
+ gpd0 = gbp_classify_get_gpd (ip4_0, ip6_0, fib_index0);
+ if (0 == gpd0)
{
- lbi0 =
- ip6_fib_table_fwding_lookup (&ip6_main, fib_index0, ip6_0);
- }
- else
- {
- /* not IP so no LPM classify possible */
+ /* could not classify => drop */
sclass0 = SCLASS_INVALID;
next0 = GPB_LPM_CLASSIFY_DROP;
goto trace;
}
- lb0 = load_balance_get (lbi0);
- dpo0 = load_balance_get_bucket_i (lb0, 0);
+
+ sclass0 = gpd0->gpd_sclass;
/* all packets from an external network should not be learned by the
* reciever. so set the Do-not-learn bit here */
vnet_buffer2 (b0)->gbp.flags = VXLAN_GBP_GPFLAGS_D;
- if (gbp_policy_dpo_type == dpo0->dpoi_type)
- {
- gpd0 = gbp_policy_dpo_get (dpo0->dpoi_index);
- sclass0 = gpd0->gpd_sclass;
- }
- else
- {
- /* could not classify => drop */
- sclass0 = SCLASS_INVALID;
- goto trace;
- }
-
trace:
vnet_buffer2 (b0)->gbp.sclass = sclass0;
@@ -537,21 +523,32 @@ VLIB_NODE_FN (gbp_ip4_lpm_classify_node) (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));
+ return (gbp_lpm_classify_inline
+ (vm, node, frame, DPO_PROTO_IP4, GBP_LPM_RECIRC));
}
VLIB_NODE_FN (gbp_ip6_lpm_classify_node) (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));
+ return (gbp_lpm_classify_inline
+ (vm, node, frame, DPO_PROTO_IP6, GBP_LPM_RECIRC));
}
VLIB_NODE_FN (gbp_l2_lpm_classify_node) (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));
+ return (gbp_lpm_classify_inline
+ (vm, node, frame, DPO_PROTO_ETHERNET, GBP_LPM_EPG));
+}
+
+VLIB_NODE_FN (gbp_l2_lpm_anon_classify_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (gbp_lpm_classify_inline
+ (vm, node, frame, DPO_PROTO_ETHERNET, GBP_LPM_ANON));
}
/* *INDENT-OFF* */
@@ -594,6 +591,19 @@ VLIB_REGISTER_NODE (gbp_l2_lpm_classify_node) = {
},
};
+VLIB_REGISTER_NODE (gbp_l2_lpm_anon_classify_node) = {
+ .name = "l2-gbp-lpm-anon-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_lpm_classify_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = 0,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [GPB_LPM_CLASSIFY_DROP] = "error-drop"
+ },
+};
+
VNET_FEATURE_INIT (gbp_ip4_lpm_classify_feat_node, static) =
{
.arc_name = "ip4-unicast",
diff --git a/src/plugins/gbp/gbp_ext_itf.c b/src/plugins/gbp/gbp_ext_itf.c
index be2d614e1fa..89bcb3da49e 100644
--- a/src/plugins/gbp/gbp_ext_itf.c
+++ b/src/plugins/gbp/gbp_ext_itf.c
@@ -130,6 +130,120 @@ gbp_ext_itf_delete (u32 sw_if_index)
return (VNET_API_ERROR_NO_SUCH_ENTRY);
}
+int
+gbp_ext_itf_anon_add (u32 sw_if_index, u32 bd_id, u32 rd_id)
+{
+ int rv = gbp_ext_itf_add (sw_if_index, bd_id, rd_id);
+ if (rv)
+ return rv;
+ /* add interface to the BD */
+ index_t itf = gbp_itf_add_and_lock (sw_if_index, bd_id);
+ /* setup GBP L2 features on this interface */
+ gbp_itf_set_l2_input_feature (itf, 0,
+ L2INPUT_FEAT_GBP_LPM_ANON_CLASSIFY |
+ L2INPUT_FEAT_LEARN);
+ gbp_itf_set_l2_output_feature (itf, 0, L2OUTPUT_FEAT_GBP_POLICY_LPM);
+ return 0;
+}
+
+int
+gbp_ext_itf_anon_delete (u32 sw_if_index)
+{
+ int rv = gbp_ext_itf_delete (sw_if_index);
+ if (rv)
+ return rv;
+ gbp_itf_unlock (sw_if_index);
+ return 0;
+}
+
+static clib_error_t *
+gbp_ext_itf_add_del_cli (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 sw_if_index = ~0, bd_id = ~0, rd_id = ~0;
+ int add = 1, anon = 0;
+ int rv;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "del"))
+ add = 0;
+ else
+ if (unformat
+ (line_input, "%U", unformat_vnet_sw_interface, vnet_get_main (),
+ &sw_if_index))
+ ;
+ else if (unformat (line_input, "bd %d", &bd_id))
+ ;
+ else if (unformat (line_input, "rd %d", &rd_id))
+ ;
+ else if (unformat (line_input, "anon-l3-out"))
+ anon = 1;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ }
+ unformat_free (line_input);
+
+ if (~0 == sw_if_index)
+ return clib_error_return (0, "interface must be specified");
+
+ if (add)
+ {
+ if (~0 == bd_id)
+ return clib_error_return (0, "BD-ID must be specified");
+ if (~0 == rd_id)
+ return clib_error_return (0, "RD-ID must be specified");
+ if (anon)
+ rv = gbp_ext_itf_anon_add (sw_if_index, bd_id, rd_id);
+ else
+ rv = gbp_ext_itf_add (sw_if_index, bd_id, rd_id);
+ }
+ else
+ {
+ if (anon)
+ rv = gbp_ext_itf_anon_delete (sw_if_index);
+ else
+ rv = gbp_ext_itf_delete (sw_if_index);
+ }
+
+ switch (rv)
+ {
+ case 0:
+ return 0;
+ case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
+ return clib_error_return (0, "interface already exists");
+ case VNET_API_ERROR_NO_SUCH_ENTRY: /* fallthrough */
+ case VNET_API_ERROR_INVALID_SW_IF_INDEX:
+ return clib_error_return (0, "unknown interface");
+ default:
+ return clib_error_return (0, "error %d", rv);
+ }
+
+ /* never reached */
+ return 0;
+}
+
+/*?
+ * Add Group Based Interface as anonymous L3out interface
+ *
+ * @cliexpar
+ * @cliexstart{gbp interface [del] anon-l3out <interface> bd <ID>}
+ * @cliexend
+ ?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gbp_itf_anon_l3out_add_del_node, static) = {
+ .path = "gbp ext-itf",
+ .short_help = "gbp ext-itf [del] <interface> bd <ID> rd <ID> [anon-l3-out]\n",
+ .function = gbp_ext_itf_add_del_cli,
+};
+/* *INDENT-ON* */
+
void
gbp_ext_itf_walk (gbp_ext_itf_cb_t cb, void *ctx)
{
diff --git a/src/plugins/gbp/gbp_ext_itf.h b/src/plugins/gbp/gbp_ext_itf.h
index dafcd08a2e4..d1b0f983447 100644
--- a/src/plugins/gbp/gbp_ext_itf.h
+++ b/src/plugins/gbp/gbp_ext_itf.h
@@ -52,6 +52,9 @@ typedef struct gpb_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 int gbp_ext_itf_anon_add (u32 sw_if_index, u32 bd_id, u32 rd_id);
+extern int gbp_ext_itf_anon_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);
diff --git a/src/plugins/gbp/gbp_policy.c b/src/plugins/gbp/gbp_policy.c
index fbdf3946d1d..0f26701bd19 100644
--- a/src/plugins/gbp/gbp_policy.c
+++ b/src/plugins/gbp/gbp_policy.c
@@ -24,21 +24,27 @@ gbp_policy_init (vlib_main_t * vm)
gbp_policy_main_t *gpm = &gbp_policy_main;
clib_error_t *error = 0;
- vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "gbp-policy-port");
-
/* Initialize the feature next-node indexes */
+ vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "gbp-policy-port");
feat_bitmap_init_next_nodes (vm,
node->index,
L2OUTPUT_N_FEAT,
l2output_get_feat_names (),
- gpm->l2_output_feat_next[1]);
+ gpm->l2_output_feat_next[GBP_POLICY_PORT]);
node = vlib_get_node_by_name (vm, (u8 *) "gbp-policy-mac");
feat_bitmap_init_next_nodes (vm,
node->index,
L2OUTPUT_N_FEAT,
l2output_get_feat_names (),
- gpm->l2_output_feat_next[0]);
+ gpm->l2_output_feat_next[GBP_POLICY_MAC]);
+
+ node = vlib_get_node_by_name (vm, (u8 *) "gbp-policy-lpm");
+ feat_bitmap_init_next_nodes (vm,
+ node->index,
+ L2OUTPUT_N_FEAT,
+ l2output_get_feat_names (),
+ gpm->l2_output_feat_next[GBP_POLICY_LPM]);
return error;
}
diff --git a/src/plugins/gbp/gbp_policy_dpo.h b/src/plugins/gbp/gbp_policy_dpo.h
index 6b4f8c57fd0..1dc11ab2e32 100644
--- a/src/plugins/gbp/gbp_policy_dpo.h
+++ b/src/plugins/gbp/gbp_policy_dpo.h
@@ -17,6 +17,9 @@
#define __GBP_POLICY_DPO_H__
#include <vnet/dpo/dpo.h>
+#include <vnet/dpo/load_balance.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
/**
* @brief
@@ -81,6 +84,32 @@ gbp_policy_dpo_get (index_t index)
return (pool_elt_at_index (gbp_policy_dpo_pool, index));
}
+static_always_inline const gbp_policy_dpo_t *
+gbp_classify_get_gpd (const ip4_address_t * ip4, const ip6_address_t * ip6,
+ const u32 fib_index)
+{
+ const gbp_policy_dpo_t *gpd;
+ const dpo_id_t *dpo;
+ const load_balance_t *lb;
+ u32 lbi;
+
+ if (ip4)
+ lbi = ip4_fib_forwarding_lookup (fib_index, ip4);
+ else if (ip6)
+ lbi = ip6_fib_table_fwding_lookup (&ip6_main, fib_index, ip6);
+ else
+ return 0;
+
+ lb = load_balance_get (lbi);
+ dpo = load_balance_get_bucket_i (lb, 0);
+
+ if (dpo->dpoi_type != gbp_policy_dpo_type)
+ return 0;
+
+ gpd = gbp_policy_dpo_get (dpo->dpoi_index);
+ return gpd;
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/plugins/gbp/gbp_policy_node.c b/src/plugins/gbp/gbp_policy_node.c
index 26f7e9b8c59..10f5956033e 100644
--- a/src/plugins/gbp/gbp_policy_node.c
+++ b/src/plugins/gbp/gbp_policy_node.c
@@ -14,8 +14,10 @@
*/
#include <plugins/gbp/gbp.h>
+#include <plugins/gbp/gbp_classify.h>
#include <plugins/gbp/gbp_policy_dpo.h>
#include <plugins/gbp/gbp_bridge_domain.h>
+#include <plugins/gbp/gbp_ext_itf.h>
#include <vnet/vxlan-gbp/vxlan_gbp_packet.h>
#include <vnet/vxlan-gbp/vxlan_gbp.h>
@@ -109,10 +111,34 @@ gbp_policy_is_ethertype_allowed (const gbp_contract_t * gc0, u16 ethertype)
return (0);
}
+static_always_inline gbp_policy_next_t
+gbp_policy_l2_feature_next (gbp_policy_main_t * gpm, vlib_buffer_t * b,
+ const gbp_policy_type_t type)
+{
+ u32 feat_bit;
+
+ switch (type)
+ {
+ case GBP_POLICY_PORT:
+ feat_bit = L2OUTPUT_FEAT_GBP_POLICY_PORT;
+ break;
+ case GBP_POLICY_MAC:
+ feat_bit = L2OUTPUT_FEAT_GBP_POLICY_MAC;
+ break;
+ case GBP_POLICY_LPM:
+ feat_bit = L2OUTPUT_FEAT_GBP_POLICY_LPM;
+ break;
+ default:
+ return GBP_POLICY_NEXT_DROP;
+ }
+
+ return vnet_l2_feature_next (b, gpm->l2_output_feat_next[type], feat_bit);
+}
+
static uword
gbp_policy_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
- vlib_frame_t * frame, u8 is_port_based)
+ vlib_frame_t * frame, const gbp_policy_type_t type)
{
gbp_main_t *gm = &gbp_main;
gbp_policy_main_t *gpm = &gbp_policy_main;
@@ -174,12 +200,7 @@ gbp_policy_inline (vlib_main_t * vm,
*/
if (vnet_buffer2 (b0)->gbp.flags & VXLAN_GBP_GPFLAGS_A)
{
- next0 = vnet_l2_feature_next (b0,
- gpm->l2_output_feat_next
- [is_port_based],
- (is_port_based ?
- L2OUTPUT_FEAT_GBP_POLICY_PORT :
- L2OUTPUT_FEAT_GBP_POLICY_MAC));
+ next0 = gbp_policy_l2_feature_next (gpm, b0, type);
n_allow_a_bit++;
key0.as_u64 = ~0;
goto trace;
@@ -188,20 +209,40 @@ gbp_policy_inline (vlib_main_t * vm,
/*
* determine the src and dst EPG
*/
- if (is_port_based)
- ge0 = gbp_endpoint_find_itf (sw_if_index0);
- else
- ge0 = gbp_endpoint_find_mac (h0->dst_address,
- vnet_buffer (b0)->l2.bd_index);
- if (NULL != ge0)
+ key0.gck_dst = SCLASS_INVALID;
+
+ if (GBP_POLICY_LPM == type)
{
- key0.gck_dst = ge0->ge_fwd.gef_sclass;
- key0.gck_scope =
- gbp_bridge_domain_get_scope (vnet_buffer (b0)->l2.bd_index);
+ const ip4_address_t *ip4 = 0;
+ const ip6_address_t *ip6 = 0;
+ const dpo_proto_t proto =
+ gbp_classify_get_ip_address (h0, &ip4, &ip6,
+ GBP_CLASSIFY_GET_IP_DST);
+ if (PREDICT_TRUE (DPO_PROTO_NONE != proto))
+ {
+ const gbp_ext_itf_t *ext_itf =
+ gbp_ext_itf_get (sw_if_index0);
+ const gbp_policy_dpo_t *gpd =
+ gbp_classify_get_gpd (ip4, ip6,
+ ext_itf->gx_fib_index[proto]);
+ if (gpd)
+ key0.gck_dst = gpd->gpd_sclass;
+ }
}
else
{
+ if (GBP_POLICY_PORT == type)
+ ge0 = gbp_endpoint_find_itf (sw_if_index0);
+ else
+ ge0 = gbp_endpoint_find_mac (h0->dst_address,
+ vnet_buffer (b0)->l2.bd_index);
+ if (NULL != ge0)
+ key0.gck_dst = ge0->ge_fwd.gef_sclass;
+ }
+
+ if (SCLASS_INVALID == key0.gck_dst)
+ {
/* If you cannot determine the destination EP then drop */
b0->error = node->errors[GBP_POLICY_ERROR_DROP_NO_DCLASS];
goto trace;
@@ -215,13 +256,7 @@ gbp_policy_inline (vlib_main_t * vm,
/*
* intra-epg allowed
*/
- next0 =
- vnet_l2_feature_next (b0,
- gpm->l2_output_feat_next
- [is_port_based],
- (is_port_based ?
- L2OUTPUT_FEAT_GBP_POLICY_PORT :
- L2OUTPUT_FEAT_GBP_POLICY_MAC));
+ next0 = gbp_policy_l2_feature_next (gpm, b0, type);
vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
n_allow_intra++;
}
@@ -230,18 +265,15 @@ gbp_policy_inline (vlib_main_t * vm,
/*
* sclass or dclass 1 allowed
*/
- next0 =
- vnet_l2_feature_next (b0,
- gpm->l2_output_feat_next
- [is_port_based],
- (is_port_based ?
- L2OUTPUT_FEAT_GBP_POLICY_PORT :
- L2OUTPUT_FEAT_GBP_POLICY_MAC));
+ next0 = gbp_policy_l2_feature_next (gpm, b0, type);
vnet_buffer2 (b0)->gbp.flags |= VXLAN_GBP_GPFLAGS_A;
n_allow_sclass_1++;
}
else
{
+ key0.gck_scope =
+ gbp_bridge_domain_get_scope (vnet_buffer (b0)->
+ l2.bd_index);
gci0 = gbp_contract_find (&key0);
if (INDEX_INVALID != gci0)
@@ -321,13 +353,9 @@ gbp_policy_inline (vlib_main_t * vm,
switch (gu->gu_action)
{
case GBP_RULE_PERMIT:
- next0 = vnet_l2_feature_next
- (b0,
- gpm->l2_output_feat_next
- [is_port_based],
- (is_port_based ?
- L2OUTPUT_FEAT_GBP_POLICY_PORT :
- L2OUTPUT_FEAT_GBP_POLICY_MAC));
+ next0 =
+ gbp_policy_l2_feature_next (gpm, b0,
+ type);
break;
case GBP_RULE_DENY:
next0 = GBP_POLICY_NEXT_DROP;
@@ -368,12 +396,7 @@ gbp_policy_inline (vlib_main_t * vm,
* the src EPG is not set when the packet arrives on an EPG
* uplink interface and we do not need to apply policy
*/
- next0 =
- vnet_l2_feature_next (b0,
- gpm->l2_output_feat_next[is_port_based],
- (is_port_based ?
- L2OUTPUT_FEAT_GBP_POLICY_PORT :
- L2OUTPUT_FEAT_GBP_POLICY_MAC));
+ next0 = gbp_policy_l2_feature_next (gpm, b0, type);
}
trace:
@@ -413,14 +436,21 @@ VLIB_NODE_FN (gbp_policy_port_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return (gbp_policy_inline (vm, node, frame, 1));
+ return (gbp_policy_inline (vm, node, frame, GBP_POLICY_PORT));
}
VLIB_NODE_FN (gbp_policy_mac_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- return (gbp_policy_inline (vm, node, frame, 0));
+ return (gbp_policy_inline (vm, node, frame, GBP_POLICY_MAC));
+}
+
+VLIB_NODE_FN (gbp_policy_lpm_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (gbp_policy_inline (vm, node, frame, GBP_POLICY_LPM));
}
/* packet trace format function */
@@ -470,6 +500,21 @@ VLIB_REGISTER_NODE (gbp_policy_mac_node) = {
},
};
+VLIB_REGISTER_NODE (gbp_policy_lpm_node) = {
+ .name = "gbp-policy-lpm",
+ .vector_size = sizeof (u32),
+ .format_trace = format_gbp_policy_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(gbp_policy_error_strings),
+ .error_strings = gbp_policy_error_strings,
+
+ .n_next_nodes = GBP_POLICY_N_NEXT,
+ .next_nodes = {
+ [GBP_POLICY_NEXT_DROP] = "error-drop",
+ },
+};
+
/* *INDENT-ON* */
/*
diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h
index ce9a7d5f0cd..677186bbdf3 100644
--- a/src/vnet/l2/l2_input.h
+++ b/src/vnet/l2/l2_input.h
@@ -112,6 +112,7 @@ l2input_bd_config (u32 bd_index)
_(LEARN, "l2-learn") \
_(L2_EMULATION, "l2-emulation") \
_(GBP_LEARN, "gbp-learn-l2") \
+ _(GBP_LPM_ANON_CLASSIFY, "l2-gbp-lpm-anon-classify") \
_(GBP_NULL_CLASSIFY, "gbp-null-classify") \
_(GBP_SRC_CLASSIFY, "gbp-src-classify") \
_(GBP_LPM_CLASSIFY, "l2-gbp-lpm-classify") \
diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h
index 74d2829839f..1cc1e738841 100644
--- a/src/vnet/l2/l2_output.h
+++ b/src/vnet/l2/l2_output.h
@@ -81,6 +81,7 @@ extern vlib_node_registration_t l2output_node;
#define foreach_l2output_feat \
_(OUTPUT, "interface-output") \
_(SPAN, "span-l2-output") \
+ _(GBP_POLICY_LPM, "gbp-policy-lpm") \
_(GBP_POLICY_PORT, "gbp-policy-port") \
_(GBP_POLICY_MAC, "gbp-policy-mac") \
_(CFM, "feature-bitmap-drop") \