From 22b3b846822df2701bb6cb508fa4e023526e5717 Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Tue, 17 Apr 2018 19:35:42 +0200 Subject: gbp: Add support for ACL Change-Id: I7513c41307e62068ab5d9739cac393675c6066f8 Signed-off-by: Mohsin Kazmi --- src/plugins/gbp/gbp.h | 10 +++++ src/plugins/gbp/gbp_api.c | 23 ++++------- src/plugins/gbp/gbp_contract.c | 65 ++++++++++++++++++++++++----- src/plugins/gbp/gbp_contract.h | 23 ++++++++++- src/plugins/gbp/gbp_policy.c | 59 ++++++++++++++++++++------- src/plugins/gbp/gbp_policy_dpo.c | 56 +++++++++++++++++-------- test/test_gbp.py | 88 +++++++++++++++++++++++++++++++++++----- 7 files changed, 256 insertions(+), 68 deletions(-) diff --git a/src/plugins/gbp/gbp.h b/src/plugins/gbp/gbp.h index 8672fd3b092..06612cd948f 100644 --- a/src/plugins/gbp/gbp.h +++ b/src/plugins/gbp/gbp.h @@ -31,6 +31,8 @@ #ifndef __GBP_H__ #define __GBP_H__ +#include + #include #include #include @@ -38,6 +40,14 @@ #include #include +typedef struct +{ + u32 gbp_acl_user_id; + acl_plugin_methods_t acl_plugin; +} gbp_main_t; + +extern gbp_main_t gbp_main; + #endif /* diff --git a/src/plugins/gbp/gbp_api.c b/src/plugins/gbp/gbp_api.c index 88b2cd1cea9..1f24eedc3d0 100644 --- a/src/plugins/gbp/gbp_api.c +++ b/src/plugins/gbp/gbp_api.c @@ -46,7 +46,7 @@ /* Get the API version number */ #define vl_api_version(n,v) static u32 api_version=(v); -#include +#include #undef vl_api_version #include @@ -63,17 +63,11 @@ _(GBP_CONTRACT_ADD_DEL, gbp_contract_add_del) \ _(GBP_CONTRACT_DUMP, gbp_contract_dump) -/** - * L2 Emulation Main - */ -typedef struct gbp_main_t_ -{ - u16 msg_id_base; -} gbp_main_t; +gbp_main_t gbp_main; -static gbp_main_t gbp_main; +static u16 msg_id_base; -#define GBP_MSG_BASE gbp_main.msg_id_base +#define GBP_MSG_BASE msg_id_base static void vl_api_gbp_endpoint_add_del_t_handler (vl_api_gbp_endpoint_add_del_t * mp) @@ -418,7 +412,7 @@ gbp_contract_send_details (gbp_contract_t * gbpc, void *args) mp->contract.src_epg = ntohl (gbpc->gc_key.gck_src); mp->contract.dst_epg = ntohl (gbpc->gc_key.gck_dst); - mp->contract.acl_index = ntohl (gbpc->gc_acl_index); + mp->contract.acl_index = ntohl (gbpc->gc_value.gc_acl_index); vl_api_send_msg (ctx->reg, (u8 *) mp); @@ -484,10 +478,11 @@ gbp_init (vlib_main_t * vm) gbp_main_t *gbpm = &gbp_main; u8 *name = format (0, "gbp_%08x%c", api_version, 0); - /* Ask for a correctly-sized block of API message decode slots */ - gbpm->msg_id_base = vl_msg_api_get_msg_ids ((char *) name, - VL_MSG_FIRST_AVAILABLE); + gbpm->gbp_acl_user_id = ~0; + /* Ask for a correctly-sized block of API message decode slots */ + msg_id_base = vl_msg_api_get_msg_ids ((char *) name, + VL_MSG_FIRST_AVAILABLE); gbp_api_hookup (vm); /* Add our API messages to the global name_crc hash table */ diff --git a/src/plugins/gbp/gbp_contract.c b/src/plugins/gbp/gbp_contract.c index 71d8bcf4671..a536f89e5fe 100644 --- a/src/plugins/gbp/gbp_contract.c +++ b/src/plugins/gbp/gbp_contract.c @@ -25,22 +25,64 @@ gbp_contract_db_t gbp_contract_db; void gbp_contract_update (epg_id_t src_epg, epg_id_t dst_epg, u32 acl_index) { + gbp_main_t *gm = &gbp_main; + u32 *acl_vec = 0; + gbp_contract_value_t value = { + .gc_lc_index = ~0, + .gc_acl_index = ~0, + }; + uword *p; + gbp_contract_key_t key = { .gck_src = src_epg, .gck_dst = dst_epg, }; - hash_set (gbp_contract_db.gc_hash, key.as_u64, acl_index); + if (~0 == gm->gbp_acl_user_id) + { + acl_plugin_exports_init (&gm->acl_plugin); + gm->gbp_acl_user_id = + gm->acl_plugin.register_user_module ("GBP ACL", "src-epg", "dst-epg"); + } + + p = hash_get (gbp_contract_db.gc_hash, key.as_u64); + if (p != NULL) + { + value.as_u64 = p[0]; + } + else + { + value.gc_lc_index = + gm->acl_plugin.get_lookup_context_index (gm->gbp_acl_user_id, src_epg, + dst_epg); + value.gc_acl_index = acl_index; + hash_set (gbp_contract_db.gc_hash, key.as_u64, value.as_u64); + } + + if (value.gc_lc_index == ~0) + return; + vec_add1 (acl_vec, acl_index); + gm->acl_plugin.set_acl_vec_for_context (value.gc_lc_index, acl_vec); + vec_free (acl_vec); } void gbp_contract_delete (epg_id_t src_epg, epg_id_t dst_epg) { + gbp_main_t *gm = &gbp_main; + uword *p; + gbp_contract_value_t value; gbp_contract_key_t key = { .gck_src = src_epg, .gck_dst = dst_epg, }; + p = hash_get (gbp_contract_db.gc_hash, key.as_u64); + if (p != NULL) + { + value.as_u64 = p[0]; + gm->acl_plugin.put_lookup_context_index (value.gc_lc_index); + } hash_unset (gbp_contract_db.gc_hash, key.as_u64); } @@ -48,14 +90,14 @@ void gbp_contract_walk (gbp_contract_cb_t cb, void *ctx) { gbp_contract_key_t key; - u32 acl_index; + gbp_contract_value_t value; /* *INDENT-OFF* */ - hash_foreach(key.as_u64, acl_index, gbp_contract_db.gc_hash, + hash_foreach(key.as_u64, value.as_u64, gbp_contract_db.gc_hash, ({ gbp_contract_t gbpc = { .gc_key = key, - .gc_acl_index = acl_index, + .gc_value = value, }; if (!cb(&gbpc, ctx)) @@ -112,11 +154,14 @@ gbp_contract_cli (vlib_main_t * vm, * @cliexstart{set gbp contract [del] src-epg dst-epg acl-index } * @cliexend ?*/ +/* *INDENT-OFF* */ VLIB_CLI_COMMAND (gbp_contract_cli_node, static) = { -.path = "gbp contract",.short_help = - "gbp contract [del] src-epg dst-epg acl-index ",.function - = gbp_contract_cli,}; + .path = "gbp contract", + .short_help = + "gbp contract [del] src-epg dst-epg acl-index ", + .function = gbp_contract_cli, +}; /* *INDENT-ON* */ static clib_error_t * @@ -124,15 +169,15 @@ gbp_contract_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { gbp_contract_key_t key; - epg_id_t epg_id; + gbp_contract_value_t value; vlib_cli_output (vm, "Contracts:"); /* *INDENT-OFF* */ - hash_foreach (key.as_u64, epg_id, gbp_contract_db.gc_hash, + hash_foreach (key.as_u64, value.as_u64, gbp_contract_db.gc_hash, { vlib_cli_output (vm, " {%d,%d} -> %d", key.gck_src, - key.gck_dst, epg_id); + key.gck_dst, value.gc_acl_index); }); /* *INDENT-ON* */ diff --git a/src/plugins/gbp/gbp_contract.h b/src/plugins/gbp/gbp_contract.h index 1964098adc3..75f2edca116 100644 --- a/src/plugins/gbp/gbp_contract.h +++ b/src/plugins/gbp/gbp_contract.h @@ -37,6 +37,25 @@ typedef struct gbp_contract_key_t_ }; } gbp_contract_key_t; +/** + * The value for an Contract + */ +typedef struct gbp_contract_value_t_ +{ + union + { + struct + { + /** + * lookup context and acl index + */ + u32 gc_lc_index; + u32 gc_acl_index; + }; + u64 as_u64; + }; +} gbp_contract_value_t; + /** * A Group Based Policy Contract. * Determines the ACL that applies to traffic pass between two endpoint groups @@ -51,7 +70,7 @@ typedef struct gbp_contract_t_ /** * The ACL to apply for packets from the source to the destination EPG */ - u32 gc_acl_index;; + gbp_contract_value_t gc_value; } gbp_contract_t; /** @@ -78,7 +97,7 @@ extern void gbp_contract_walk (gbp_contract_cb_t bgpe, void *ctx); */ extern gbp_contract_db_t gbp_contract_db; -always_inline u32 +always_inline u64 gbp_acl_lookup (gbp_contract_key_t * key) { uword *p; diff --git a/src/plugins/gbp/gbp_policy.c b/src/plugins/gbp/gbp_policy.c index 8f3fc76a019..38254644631 100644 --- a/src/plugins/gbp/gbp_policy.c +++ b/src/plugins/gbp/gbp_policy.c @@ -68,6 +68,7 @@ static uword gbp_policy (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { + gbp_main_t *gm = &gbp_main; gbp_policy_main_t *gpm = &gbp_policy_main; u32 n_left_from, *from, *to_next; u32 next_index; @@ -86,9 +87,11 @@ gbp_policy (vlib_main_t * vm, { gbp_policy_next_t next0; gbp_contract_key_t key0; + gbp_contract_value_t value0 = { + .as_u64 = ~0, + }; u32 bi0, sw_if_index0; vlib_buffer_t *b0; - u32 acl_index0; next0 = GBP_POLICY_NEXT_DENY; bi0 = from[0]; @@ -106,7 +109,6 @@ gbp_policy (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; key0.gck_dst = gbp_port_to_epg (sw_if_index0); key0.gck_src = vnet_buffer2 (b0)->gbp.src_epg; - acl_index0 = ~0; if (~0 != key0.gck_src) { @@ -120,20 +122,48 @@ gbp_policy (vlib_main_t * vm, } else { - acl_index0 = gbp_acl_lookup (&key0); + value0.as_u64 = gbp_acl_lookup (&key0); - if (~0 != acl_index0) + if (~0 != value0.gc_lc_index) { + fa_5tuple_opaque_t pkt_5tuple0; + u8 action0 = 0; + u32 acl_pos_p0, acl_match_p0; + u32 rule_match_p0, trace_bitmap0; + u8 *h0, l2_len0; + u16 ether_type0; + u8 is_ip60 = 0; + + l2_len0 = vnet_buffer (b0)->l2.l2_len; + h0 = vlib_buffer_get_current (b0); + + ether_type0 = + clib_net_to_host_u16 (*(u16 *) (h0 + l2_len0 - 2)); + + is_ip60 = (ether_type0 == ETHERNET_TYPE_IP6) ? 1 : 0; /* - * TODO tests against the ACL - */ - /* - * ACL tables are not available outside of ACL plugin - * until then bypass the ACL to next node + * tests against the ACL */ - next0 = - vnet_l2_feature_next (b0, gpm->l2_output_feat_next, - L2OUTPUT_FEAT_GBP_POLICY); + acl_plugin_fill_5tuple_inline (gm-> + acl_plugin.p_acl_main, + value0.gc_lc_index, b0, + is_ip60, + /* is_input */ 0, + /* is_l2_path */ 1, + &pkt_5tuple0); + acl_plugin_match_5tuple_inline (gm-> + acl_plugin.p_acl_main, + value0.gc_lc_index, + &pkt_5tuple0, is_ip60, + &action0, &acl_pos_p0, + &acl_match_p0, + &rule_match_p0, + &trace_bitmap0); + + if (action0 > 0) + next0 = + vnet_l2_feature_next (b0, gpm->l2_output_feat_next, + L2OUTPUT_FEAT_GBP_POLICY); } } } @@ -153,7 +183,7 @@ gbp_policy (vlib_main_t * vm, vlib_add_trace (vm, node, b0, sizeof (*t)); t->src_epg = key0.gck_src; t->dst_epg = key0.gck_dst; - t->acl_index = acl_index0; + t->acl_index = value0.gc_acl_index; } /* verify speculative enqueue, maybe switch current next frame */ @@ -209,6 +239,7 @@ static clib_error_t * gbp_policy_init (vlib_main_t * vm) { gbp_policy_main_t *gpm = &gbp_policy_main; + clib_error_t *error = 0; /* Initialize the feature next-node indexes */ feat_bitmap_init_next_nodes (vm, @@ -217,7 +248,7 @@ gbp_policy_init (vlib_main_t * vm) l2output_get_feat_names (), gpm->l2_output_feat_next); - return 0; + return error; } VLIB_INIT_FUNCTION (gbp_policy_init); diff --git a/src/plugins/gbp/gbp_policy_dpo.c b/src/plugins/gbp/gbp_policy_dpo.c index 0f62fb3445d..e2af1e6daab 100644 --- a/src/plugins/gbp/gbp_policy_dpo.c +++ b/src/plugins/gbp/gbp_policy_dpo.c @@ -13,15 +13,15 @@ * limitations under the License. */ -#include -#include -#include - #include #include #include #include +#include +#include +#include + /** * DPO pool */ @@ -206,8 +206,9 @@ typedef enum always_inline uword gbp_policy_dpo_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * from_frame, fib_protocol_t fproto) + vlib_frame_t * from_frame, u8 is_ip6) { + gbp_main_t *gm = &gbp_main; u32 n_left_from, next_index, *from, *to_next; from = vlib_frame_vector_args (from_frame); @@ -224,8 +225,11 @@ gbp_policy_dpo_inline (vlib_main_t * vm, while (n_left_from > 0 && n_left_to_next > 0) { const gbp_policy_dpo_t *gpd0; - u32 bi0, next0, acl_index0; + u32 bi0, next0; gbp_contract_key_t key0; + gbp_contract_value_t value0 = { + .as_u64 = ~0, + }; vlib_buffer_t *b0; bi0 = from[0]; @@ -235,7 +239,6 @@ gbp_policy_dpo_inline (vlib_main_t * vm, n_left_from -= 1; n_left_to_next -= 1; next0 = GBP_POLICY_DROP; - acl_index0 = ~0; b0 = vlib_get_buffer (vm, bi0); gpd0 = @@ -256,18 +259,35 @@ gbp_policy_dpo_inline (vlib_main_t * vm, } else { - acl_index0 = gbp_acl_lookup (&key0); + value0.as_u64 = gbp_acl_lookup (&key0); - if (~0 != acl_index0) + if (~0 != value0.gc_lc_index) { + fa_5tuple_opaque_t pkt_5tuple0; + u8 action0 = 0; + u32 acl_pos_p0, acl_match_p0; + u32 rule_match_p0, trace_bitmap0; /* - * TODO tests against the ACL - */ - /* - * ACL tables are not available outside of ACL plugin - * until then bypass the ACL to next node + * tests against the ACL */ - next0 = gpd0->gpd_dpo.dpoi_next_node; + acl_plugin_fill_5tuple_inline (gm-> + acl_plugin.p_acl_main, + value0.gc_lc_index, b0, + is_ip6, + /* is_input */ 1, + /* is_l2_path */ 0, + &pkt_5tuple0); + acl_plugin_match_5tuple_inline (gm-> + acl_plugin.p_acl_main, + value0.gc_lc_index, + &pkt_5tuple0, is_ip6, + &action0, &acl_pos_p0, + &acl_match_p0, + &rule_match_p0, + &trace_bitmap0); + + if (action0 > 0) + next0 = gpd0->gpd_dpo.dpoi_next_node; } } } @@ -287,7 +307,7 @@ gbp_policy_dpo_inline (vlib_main_t * vm, tr = vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->src_epg = key0.gck_src; tr->dst_epg = key0.gck_dst; - tr->acl_index = acl_index0; + tr->acl_index = value0.gc_acl_index; } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, @@ -315,14 +335,14 @@ static uword ip4_gbp_policy_dpo (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return (gbp_policy_dpo_inline (vm, node, from_frame, FIB_PROTOCOL_IP4)); + return (gbp_policy_dpo_inline (vm, node, from_frame, 0)); } static uword ip6_gbp_policy_dpo (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame) { - return (gbp_policy_dpo_inline (vm, node, from_frame, FIB_PROTOCOL_IP6)); + return (gbp_policy_dpo_inline (vm, node, from_frame, 1)); } /* *INDENT-OFF* */ diff --git a/test/test_gbp.py b/test/test_gbp.py index 7ee4d76550c..b6faa12c6a6 100644 --- a/test/test_gbp.py +++ b/test/test_gbp.py @@ -21,7 +21,7 @@ from util import mactobinary class VppGbpEndpoint(VppObject): """ - GDB Endpoint + GBP Endpoint """ @property @@ -94,7 +94,7 @@ class VppGbpEndpoint(VppObject): class VppGbpRecirc(VppObject): """ - GDB Recirculation Interface + GBP Recirculation Interface """ def __init__(self, test, epg, recirc, is_ext=False): @@ -134,7 +134,7 @@ class VppGbpRecirc(VppObject): class VppGbpSubnet(VppObject): """ - GDB Subnet + GBP Subnet """ def __init__(self, test, table_id, address, address_len, @@ -199,7 +199,7 @@ class VppGbpSubnet(VppObject): class VppGbpEndpointGroup(VppObject): """ - GDB Endpoint Group + GBP Endpoint Group """ def __init__(self, test, epg, rd, bd, uplink, @@ -250,7 +250,7 @@ class VppGbpEndpointGroup(VppObject): class VppGbpContract(VppObject): """ - GDB Contract + GBP Contract """ def __init__(self, test, src_epg, dst_epg, acl_index): @@ -291,6 +291,61 @@ class VppGbpContract(VppObject): return False +class VppGbpAcl(VppObject): + """ + GBP Acl + """ + + def __init__(self, test): + self._test = test + self.acl_index = 4294967295 + + def create_rule(self, is_ipv6=0, permit_deny=0, proto=-1, + s_prefix=0, s_ip='\x00\x00\x00\x00', sport_from=0, + sport_to=65535, d_prefix=0, d_ip='\x00\x00\x00\x00', + dport_from=0, dport_to=65535): + if proto == -1 or proto == 0: + sport_to = 0 + dport_to = sport_to + elif proto == 1 or proto == 58: + sport_to = 255 + dport_to = sport_to + rule = ({'is_permit': permit_deny, 'is_ipv6': is_ipv6, 'proto': proto, + 'srcport_or_icmptype_first': sport_from, + 'srcport_or_icmptype_last': sport_to, + 'src_ip_prefix_len': s_prefix, + 'src_ip_addr': s_ip, + 'dstport_or_icmpcode_first': dport_from, + 'dstport_or_icmpcode_last': dport_to, + 'dst_ip_prefix_len': d_prefix, + 'dst_ip_addr': d_ip}) + return rule + + def add_vpp_config(self, rules): + + reply = self._test.vapi.acl_add_replace(self.acl_index, + r=rules, + tag='GBPTest') + self.acl_index = reply.acl_index + return self.acl_index + + def remove_vpp_config(self): + self._test.vapi.acl_del(self.acl_index) + + def __str__(self): + return self.object_id() + + def object_id(self): + return "gbp-acl;[%d]" % (self.acl_index) + + def query_vpp_config(self): + cs = self._test.vapi.acl_dump() + for c in cs: + if c.acl_index == self.acl_index: + return True + return False + + class TestGBP(VppTestCase): """ GBP Test Case """ @@ -875,7 +930,11 @@ class TestGBP(VppTestCase): # # A uni-directional contract from EPG 220 -> 221 # - c1 = VppGbpContract(self, 220, 221, 0) + acl = VppGbpAcl(self) + rule = acl.create_rule(permit_deny=1, proto=17) + rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) + acl_index = acl.add_vpp_config([rule, rule2]) + c1 = VppGbpContract(self, 220, 221, acl_index) c1.add_vpp_config() self.send_and_expect_bridged(self.pg0, @@ -887,7 +946,7 @@ class TestGBP(VppTestCase): # # contract for the return direction # - c2 = VppGbpContract(self, 221, 220, 0) + c2 = VppGbpContract(self, 221, 220, acl_index) c2.add_vpp_config() self.send_and_expect_bridged(self.pg0, @@ -907,7 +966,7 @@ class TestGBP(VppTestCase): # # A uni-directional contract from EPG 220 -> 222 'L3 routed' # - c3 = VppGbpContract(self, 220, 222, 0) + c3 = VppGbpContract(self, 220, 222, acl_index) c3.add_vpp_config() self.logger.info(self.vapi.cli("sh gbp contract")) @@ -923,6 +982,7 @@ class TestGBP(VppTestCase): c2.remove_vpp_config() c1.remove_vpp_config() c3.remove_vpp_config() + acl.remove_vpp_config() self.send_and_assert_no_replies(self.pg2, pkt_inter_epg_221_to_220 * 65) @@ -988,7 +1048,15 @@ class TestGBP(VppTestCase): self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_global * 65) - c4 = VppGbpContract(self, 220, 333, 0) + acl2 = VppGbpAcl(self) + rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234, + sport_to=1234, dport_from=1234, dport_to=1234) + rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17, + sport_from=1234, sport_to=1234, + dport_from=1234, dport_to=1234) + + acl_index2 = acl2.add_vpp_config([rule, rule2]) + c4 = VppGbpContract(self, 220, 333, acl_index2) c4.add_vpp_config() self.send_and_expect_natted(self.pg0, @@ -1020,7 +1088,7 @@ class TestGBP(VppTestCase): self.send_and_assert_no_replies(self.pg7, pkt_inter_epg_220_from_global * 65) - c5 = VppGbpContract(self, 333, 220, 0) + c5 = VppGbpContract(self, 333, 220, acl_index2) c5.add_vpp_config() self.send_and_expect_unnatted(self.pg7, -- cgit 1.2.3-korg