X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fgbp%2Fgbp_subnet.c;h=2ef3fcfd534d0b6fcc9a947b9ff355f8123e9a5f;hb=59f71132e;hp=5e56c8200b95cb5d63201ee2057c32f1dd4d0893;hpb=4ba67723d716660c56326ce498b99a060a9471b1;p=vpp.git diff --git a/src/plugins/gbp/gbp_subnet.c b/src/plugins/gbp/gbp_subnet.c index 5e56c8200b9..2ef3fcfd534 100644 --- a/src/plugins/gbp/gbp_subnet.c +++ b/src/plugins/gbp/gbp_subnet.c @@ -65,6 +65,8 @@ uword *gbp_subnet_db; */ gbp_subnet_t *gbp_subnet_pool; +static fib_source_t gbp_fib_source; + static index_t gbp_subnet_db_find (u32 fib_index, const fib_prefix_t * pfx) { @@ -122,7 +124,7 @@ gbp_subnet_transport_add (gbp_subnet_t * gs) gs->gs_fei = fib_table_entry_update_one_path (gs->gs_key->gsk_fib_index, &gs->gs_key->gsk_pfx, - FIB_SOURCE_PLUGIN_HI, + gbp_fib_source, FIB_ENTRY_FLAG_NONE, fib_proto_to_dpo (fproto), &ADJ_BCAST_ADDR, @@ -145,7 +147,7 @@ gbp_subnet_internal_add (gbp_subnet_t * gs) gs->gs_fei = fib_table_entry_special_dpo_update (gs->gs_key->gsk_fib_index, &gs->gs_key->gsk_pfx, - FIB_SOURCE_PLUGIN_HI, + gbp_fib_source, FIB_ENTRY_FLAG_EXCLUSIVE, &gfd); @@ -163,12 +165,13 @@ gbp_subnet_external_add (gbp_subnet_t * gs, u32 sw_if_index, sclass_t sclass) gs->gs_stitched_external.gs_sw_if_index = sw_if_index; gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto), + gbp_route_domain_get_scope (gs->gs_rd), gs->gs_stitched_external.gs_sclass, gs->gs_stitched_external.gs_sw_if_index, &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, + gbp_fib_source, (FIB_ENTRY_FLAG_EXCLUSIVE | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT), &gpd); @@ -179,32 +182,55 @@ gbp_subnet_external_add (gbp_subnet_t * gs, u32 sw_if_index, sclass_t sclass) } static int -gbp_subnet_l3_out_add (gbp_subnet_t * gs, u32 sw_if_index, sclass_t sclass) +gbp_subnet_l3_out_add (gbp_subnet_t * gs, sclass_t sclass, int is_anon) { + fib_entry_flag_t flags; dpo_id_t gpd = DPO_INVALID; gs->gs_l3_out.gs_sclass = sclass; gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (gs->gs_key->gsk_pfx.fp_proto), + gbp_route_domain_get_scope (gs->gs_rd), gs->gs_l3_out.gs_sclass, ~0, &gpd); + flags = FIB_ENTRY_FLAG_INTERPOSE; + if (is_anon) + flags |= FIB_ENTRY_FLAG_COVERED_INHERIT; + 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); + flags, &gpd); dpo_reset (&gpd); return (0); } +static void +gbp_subnet_del_i (index_t gsi) +{ + gbp_subnet_t *gs; + + gs = pool_elt_at_index (gbp_subnet_pool, gsi); + + fib_table_entry_delete_index (gs->gs_fei, + (GBP_SUBNET_L3_OUT == gs->gs_type + || GBP_SUBNET_ANON_L3_OUT == + gs->gs_type) ? FIB_SOURCE_SPECIAL : + gbp_fib_source); + + gbp_subnet_db_del (gs); + gbp_route_domain_unlock (gs->gs_rd); + + pool_put (gbp_subnet_pool, gs); +} + int gbp_subnet_del (u32 rd_id, const fib_prefix_t * pfx) { gbp_route_domain_t *grd; index_t gsi, grdi; - gbp_subnet_t *gs; u32 fib_index; grdi = gbp_route_domain_find (rd_id); @@ -220,17 +246,7 @@ gbp_subnet_del (u32 rd_id, const fib_prefix_t * pfx) if (INDEX_INVALID == gsi) return (VNET_API_ERROR_NO_SUCH_ENTRY); - gs = pool_elt_at_index (gbp_subnet_pool, gsi); - - 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); - - pool_put (gbp_subnet_pool, gs); + gbp_subnet_del_i (gsi); return (0); } @@ -246,6 +262,18 @@ gbp_subnet_add (u32 rd_id, u32 fib_index; int rv; + switch (type) + { + case GBP_SUBNET_TRANSPORT: + case GBP_SUBNET_STITCHED_INTERNAL: + case GBP_SUBNET_STITCHED_EXTERNAL: + case GBP_SUBNET_L3_OUT: + case GBP_SUBNET_ANON_L3_OUT: + break; + default: + return (VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE); + } + grdi = gbp_route_domain_find_and_lock (rd_id); if (~0 == grdi) @@ -256,8 +284,11 @@ gbp_subnet_add (u32 rd_id, gsi = gbp_subnet_db_find (fib_index, pfx); + /* + * this is an update if the subnet already exists, so remove the old + */ if (INDEX_INVALID != gsi) - return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS); + gbp_subnet_del_i (gsi); rv = -2; @@ -279,13 +310,108 @@ gbp_subnet_add (u32 rd_id, rv = gbp_subnet_transport_add (gs); break; case GBP_SUBNET_L3_OUT: - rv = gbp_subnet_l3_out_add (gs, sw_if_index, sclass); + rv = gbp_subnet_l3_out_add (gs, sclass, 0 /* is_anon */ ); + break; + case GBP_SUBNET_ANON_L3_OUT: + rv = gbp_subnet_l3_out_add (gs, sclass, 1 /* is_anon */ ); break; } return (rv); } +static clib_error_t * +gbp_subnet_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; + vnet_main_t *vnm = vnet_get_main (); + fib_prefix_t pfx = {.fp_addr = ip46_address_initializer }; + int length; + u32 rd_id = ~0; + u32 sw_if_index = ~0; + gbp_subnet_type_t type = ~0; + u32 sclass = ~0; + int is_add = 1; + 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")) + is_add = 0; + else if (unformat (line_input, "rd %d", &rd_id)) + ; + else + if (unformat + (line_input, "prefix %U/%d", unformat_ip4_address, + &pfx.fp_addr.ip4, &length)) + pfx.fp_proto = FIB_PROTOCOL_IP4; + else + if (unformat + (line_input, "prefix %U/%d", unformat_ip6_address, + &pfx.fp_addr.ip6, &length)) + pfx.fp_proto = FIB_PROTOCOL_IP6; + else if (unformat (line_input, "type transport")) + type = GBP_SUBNET_TRANSPORT; + else if (unformat (line_input, "type stitched-internal")) + type = GBP_SUBNET_STITCHED_INTERNAL; + else if (unformat (line_input, "type stitched-external")) + type = GBP_SUBNET_STITCHED_EXTERNAL; + else if (unformat (line_input, "type anon-l3-out")) + type = GBP_SUBNET_ANON_L3_OUT; + else if (unformat (line_input, "type l3-out")) + type = GBP_SUBNET_L3_OUT; + else + if (unformat_user + (line_input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + ; + else if (unformat (line_input, "sclass %u", &sclass)) + ; + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + } + unformat_free (line_input); + + pfx.fp_len = length; + + if (is_add) + rv = gbp_subnet_add (rd_id, &pfx, type, sw_if_index, sclass); + else + rv = gbp_subnet_del (rd_id, &pfx); + + switch (rv) + { + case 0: + return 0; + case VNET_API_ERROR_NO_SUCH_FIB: + return clib_error_return (0, "no such FIB"); + } + + return clib_error_return (0, "unknown error %d", rv); +} + +/*? + * Add Group Based Policy Subnets + * + * @cliexpar + * @cliexstart{gbp subnet [del] rd prefix type [] [sclass ]} + * @cliexend + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (gbp_subnet_add_del, static) = { + .path = "gbp subnet", + .short_help = "gbp subnet [del] rd prefix type [] [sclass ]\n", + .function = gbp_subnet_add_del_cli, +}; +/* *INDENT-ON* */ + + + void gbp_subnet_walk (gbp_subnet_cb_t cb, void *ctx) { @@ -313,6 +439,7 @@ gbp_subnet_walk (gbp_subnet_cb_t cb, void *ctx) sclass = gs->gs_stitched_external.gs_sclass; break; case GBP_SUBNET_L3_OUT: + case GBP_SUBNET_ANON_L3_OUT: sclass = gs->gs_l3_out.gs_sclass; break; } @@ -345,6 +472,8 @@ format_gbp_subnet_type (u8 * s, va_list * args) return (format (s, "transport")); case GBP_SUBNET_L3_OUT: return (format (s, "l3-out")); + case GBP_SUBNET_ANON_L3_OUT: + return (format (s, "anon-l3-out")); } return (format (s, "unknown")); @@ -378,6 +507,7 @@ format_gbp_subnet (u8 * s, va_list * args) vnet_get_main (), gs->gs_stitched_external.gs_sw_if_index); break; case GBP_SUBNET_L3_OUT: + case GBP_SUBNET_ANON_L3_OUT: s = format (s, " {sclass:%d}", gs->gs_l3_out.gs_sclass); break; } @@ -450,6 +580,9 @@ gbp_subnet_init (vlib_main_t * vm) { gbp_subnet_db = hash_create_mem (0, sizeof (gbp_subnet_key_t), sizeof (u32)); + gbp_fib_source = fib_source_allocate ("gbp-subnet", + FIB_SOURCE_PRIORITY_HI, + FIB_SOURCE_BH_SIMPLE); return (NULL); }