diff options
author | Neale Ranns <nranns@cisco.com> | 2018-11-21 05:44:35 -0800 |
---|---|---|
committer | Neale Ranns <nranns@cisco.com> | 2018-11-29 12:36:30 +0000 |
commit | b6a47953973f7c94239c394b649100e91bdb2152 (patch) | |
tree | c78645ca5abb40e44b7ccd5d344bfc1059281686 /src/plugins/gbp | |
parent | d40c3e652d487f0f165d5e595864c4ccd464de3b (diff) |
GBP: l3-out subnets
Change-Id: Id4a20066fc5be716c61a497dfcb4d00dc1dbb28d
Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/plugins/gbp')
-rw-r--r-- | src/plugins/gbp/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/gbp/gbp.api | 39 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_api.c | 95 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_bridge_domain.c | 10 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_bridge_domain.h | 1 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_classify.c | 283 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_endpoint.c | 36 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_endpoint.h | 9 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_ext_itf.c | 203 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_ext_itf.h | 81 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_itf.c | 6 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_policy_dpo.c | 213 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_policy_dpo.h | 18 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_recirc.c | 28 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_recirc.h | 9 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_route_domain.c | 10 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_route_domain.h | 1 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_scanner.c | 43 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_scanner.h | 3 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_subnet.c | 97 | ||||
-rw-r--r-- | src/plugins/gbp/gbp_subnet.h | 1 |
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, |