diff options
Diffstat (limited to 'extras/deprecated/plugins/gbp/gbp_itf.c')
-rw-r--r-- | extras/deprecated/plugins/gbp/gbp_itf.c | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/extras/deprecated/plugins/gbp/gbp_itf.c b/extras/deprecated/plugins/gbp/gbp_itf.c new file mode 100644 index 00000000000..738a7ac2e39 --- /dev/null +++ b/extras/deprecated/plugins/gbp/gbp_itf.c @@ -0,0 +1,574 @@ +/* + * 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_itf.h> +#include <plugins/gbp/gbp_bridge_domain.h> +#include <plugins/gbp/gbp_route_domain.h> + +#include <vnet/ip/ip.h> + +#define foreach_gbp_itf_mode \ + _(L2, "l2") \ + _(L3, "L3") + +typedef enum gbp_ift_mode_t_ +{ +#define _(s,v) GBP_ITF_MODE_##s, + foreach_gbp_itf_mode +#undef _ +} gbp_itf_mode_t; + +/** + * Attributes and configurations attached to interfaces by GBP + */ +typedef struct gbp_itf_t_ +{ + /** + * Number of references to this interface + */ + u32 gi_locks; + + /** + * The interface this wrapper is managing + */ + u32 gi_sw_if_index; + + /** + * The mode of the interface + */ + gbp_itf_mode_t gi_mode; + + /** + * Users of this interface - this is encoded in the user's handle + */ + u32 *gi_users; + + /** + * L2/L3 Features configured by each user + */ + u32 *gi_input_fbs; + u32 gi_input_fb; + u32 *gi_output_fbs; + u32 gi_output_fb; + + /** + * function to call when the interface is deleted. + */ + gbp_itf_free_fn_t gi_free_fn; + + union + { + /** + * GBP BD or RD index + */ + u32 gi_gbi; + index_t gi_gri; + }; +} gbp_itf_t; + +static gbp_itf_t *gbp_itf_pool; +static uword *gbp_itf_db; + +static const char *gbp_itf_feat_bit_pos_to_arc[] = { +#define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = a, + foreach_gdb_l3_feature +#undef _ +}; + +static const char *gbp_itf_feat_bit_pos_to_feat[] = { +#define _(s,v,a) [GBP_ITF_L3_FEAT_POS_##s] = v, + foreach_gdb_l3_feature +#undef _ +}; + +u8 * +format_gbp_itf_l3_feat (u8 * s, va_list * args) +{ + gbp_itf_l3_feat_t flags = va_arg (*args, gbp_itf_l3_feat_t); + +#define _(a, b, c) \ + if (flags & GBP_ITF_L3_FEAT_##a) \ + s = format (s, "%s ", b); + foreach_gdb_l3_feature +#undef _ + return (s); +} + +void +gbp_itf_hdl_reset (gbp_itf_hdl_t * gh) +{ + *gh = GBP_ITF_HDL_INVALID; +} + +bool +gbp_itf_hdl_is_valid (gbp_itf_hdl_t gh) +{ + return (gh.gh_which != GBP_ITF_HDL_INVALID.gh_which); +} + +static gbp_itf_t * +gbp_itf_get (index_t gii) +{ + if (pool_is_free_index (gbp_itf_pool, gii)) + return (NULL); + + return (pool_elt_at_index (gbp_itf_pool, gii)); +} + +static gbp_itf_t * +gbp_itf_find (u32 sw_if_index) +{ + uword *p; + + p = hash_get (gbp_itf_db, sw_if_index); + + if (NULL != p) + return (gbp_itf_get (p[0])); + + return (NULL); +} + +static gbp_itf_t * +gbp_itf_find_hdl (gbp_itf_hdl_t gh) +{ + return (gbp_itf_find (gh.gh_which)); +} + +u32 +gbp_itf_get_sw_if_index (gbp_itf_hdl_t hdl) +{ + return (hdl.gh_which); +} + +static gbp_itf_hdl_t +gbp_itf_mk_hdl (gbp_itf_t * gi) +{ + gbp_itf_hdl_t gh; + u32 *useri; + + pool_get (gi->gi_users, useri); + *useri = 0; + + gh.gh_who = useri - gi->gi_users; + gh.gh_which = gi->gi_sw_if_index; + + return (gh); +} + +static gbp_itf_hdl_t +gbp_itf_l2_add_and_lock_i (u32 sw_if_index, index_t gbi, gbp_itf_free_fn_t ff) +{ + gbp_itf_t *gi; + + gi = gbp_itf_find (sw_if_index); + + if (NULL == gi) + { + pool_get_zero (gbp_itf_pool, gi); + + gi->gi_sw_if_index = sw_if_index; + gi->gi_gbi = gbi; + gi->gi_mode = GBP_ITF_MODE_L2; + gi->gi_free_fn = ff; + + gbp_bridge_domain_itf_add (gi->gi_gbi, gi->gi_sw_if_index, + L2_BD_PORT_TYPE_NORMAL); + + hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool); + } + + gi->gi_locks++; + + return (gbp_itf_mk_hdl (gi)); +} + +gbp_itf_hdl_t +gbp_itf_l2_add_and_lock (u32 sw_if_index, index_t gbi) +{ + return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, NULL)); +} + +gbp_itf_hdl_t +gbp_itf_l2_add_and_lock_w_free (u32 sw_if_index, + index_t gbi, gbp_itf_free_fn_t ff) +{ + return (gbp_itf_l2_add_and_lock_i (sw_if_index, gbi, ff)); +} + +gbp_itf_hdl_t +gbp_itf_l3_add_and_lock_i (u32 sw_if_index, index_t gri, gbp_itf_free_fn_t ff) +{ + gbp_itf_t *gi; + + gi = gbp_itf_find (sw_if_index); + + if (NULL == gi) + { + const gbp_route_domain_t *grd; + fib_protocol_t fproto; + + pool_get_zero (gbp_itf_pool, gi); + + gi->gi_sw_if_index = sw_if_index; + gi->gi_mode = GBP_ITF_MODE_L3; + gi->gi_gri = gri; + gi->gi_free_fn = ff; + + grd = gbp_route_domain_get (gi->gi_gri); + + ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 1); + ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 1); + + FOR_EACH_FIB_IP_PROTOCOL (fproto) + ip_table_bind (fproto, gi->gi_sw_if_index, grd->grd_table_id[fproto]); + + hash_set (gbp_itf_db, gi->gi_sw_if_index, gi - gbp_itf_pool); + } + + gi->gi_locks++; + + return (gbp_itf_mk_hdl (gi)); +} + +gbp_itf_hdl_t +gbp_itf_l3_add_and_lock (u32 sw_if_index, index_t gri) +{ + return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, NULL)); +} + +gbp_itf_hdl_t +gbp_itf_l3_add_and_lock_w_free (u32 sw_if_index, + index_t gri, gbp_itf_free_fn_t ff) +{ + return (gbp_itf_l3_add_and_lock_i (sw_if_index, gri, ff)); +} + +void +gbp_itf_lock (gbp_itf_hdl_t gh) +{ + gbp_itf_t *gi; + + if (!gbp_itf_hdl_is_valid (gh)) + return; + + gi = gbp_itf_find_hdl (gh); + + gi->gi_locks++; +} + +gbp_itf_hdl_t +gbp_itf_clone_and_lock (gbp_itf_hdl_t gh) +{ + gbp_itf_t *gi; + + if (!gbp_itf_hdl_is_valid (gh)) + return (GBP_ITF_HDL_INVALID); + + gi = gbp_itf_find_hdl (gh); + + gi->gi_locks++; + + return (gbp_itf_mk_hdl (gi)); +} + +void +gbp_itf_unlock (gbp_itf_hdl_t * gh) +{ + gbp_itf_t *gi; + + if (!gbp_itf_hdl_is_valid (*gh)) + return; + + gi = gbp_itf_find_hdl (*gh); + ASSERT (gi->gi_locks > 0); + gi->gi_locks--; + + if (0 == gi->gi_locks) + { + if (GBP_ITF_MODE_L2 == gi->gi_mode) + { + gbp_itf_l2_set_input_feature (*gh, L2INPUT_FEAT_NONE); + gbp_itf_l2_set_output_feature (*gh, L2OUTPUT_FEAT_NONE); + gbp_bridge_domain_itf_del (gi->gi_gbi, + gi->gi_sw_if_index, + L2_BD_PORT_TYPE_NORMAL); + } + else + { + fib_protocol_t fproto; + + gbp_itf_l3_set_input_feature (*gh, GBP_ITF_L3_FEAT_NONE); + FOR_EACH_FIB_IP_PROTOCOL (fproto) + ip_table_bind (fproto, gi->gi_sw_if_index, 0); + + ip4_sw_interface_enable_disable (gi->gi_sw_if_index, 0); + ip6_sw_interface_enable_disable (gi->gi_sw_if_index, 0); + } + + hash_unset (gbp_itf_db, gi->gi_sw_if_index); + + if (gi->gi_free_fn) + gi->gi_free_fn (gi->gi_sw_if_index); + + pool_free (gi->gi_users); + vec_free (gi->gi_input_fbs); + vec_free (gi->gi_output_fbs); + + memset (gi, 0, sizeof (*gi)); + } + + gbp_itf_hdl_reset (gh); +} + +void +gbp_itf_l3_set_input_feature (gbp_itf_hdl_t gh, gbp_itf_l3_feat_t feats) +{ + u32 diff_fb, new_fb, *fb, feat; + gbp_itf_t *gi; + + gi = gbp_itf_find_hdl (gh); + + if (NULL == gi || GBP_ITF_MODE_L3 != gi->gi_mode) + return; + + vec_validate (gi->gi_input_fbs, gh.gh_who); + gi->gi_input_fbs[gh.gh_who] = feats; + + new_fb = 0; + vec_foreach (fb, gi->gi_input_fbs) + { + new_fb |= *fb; + } + + /* add new features */ + diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat], + gbp_itf_feat_bit_pos_to_feat[feat], + gi->gi_sw_if_index, 1, 0, 0); + })); + /* *INDENT-ON* */ + + /* remove unneeded features */ + diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + vnet_feature_enable_disable (gbp_itf_feat_bit_pos_to_arc[feat], + gbp_itf_feat_bit_pos_to_feat[feat], + gi->gi_sw_if_index, 0, 0, 0); + })); + /* *INDENT-ON* */ + + gi->gi_input_fb = new_fb; +} + +void +gbp_itf_l2_set_input_feature (gbp_itf_hdl_t gh, l2input_feat_masks_t feats) +{ + u32 diff_fb, new_fb, *fb, feat; + gbp_itf_t *gi; + + gi = gbp_itf_find_hdl (gh); + + if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode) + { + ASSERT (0); + return; + } + + vec_validate (gi->gi_input_fbs, gh.gh_who); + gi->gi_input_fbs[gh.gh_who] = feats; + + new_fb = 0; + vec_foreach (fb, gi->gi_input_fbs) + { + new_fb |= *fb; + } + + /* add new features */ + diff_fb = (gi->gi_input_fb ^ new_fb) & new_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1); + })); + /* *INDENT-ON* */ + + /* remove unneeded features */ + diff_fb = (gi->gi_input_fb ^ new_fb) & gi->gi_input_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + l2input_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0); + })); + /* *INDENT-ON* */ + + gi->gi_input_fb = new_fb; +} + +void +gbp_itf_l2_set_output_feature (gbp_itf_hdl_t gh, l2output_feat_masks_t feats) +{ + u32 diff_fb, new_fb, *fb, feat; + gbp_itf_t *gi; + + gi = gbp_itf_find_hdl (gh); + + if (NULL == gi || GBP_ITF_MODE_L2 != gi->gi_mode) + { + ASSERT (0); + return; + } + + vec_validate (gi->gi_output_fbs, gh.gh_who); + gi->gi_output_fbs[gh.gh_who] = feats; + + new_fb = 0; + vec_foreach (fb, gi->gi_output_fbs) + { + new_fb |= *fb; + } + + /* add new features */ + diff_fb = (gi->gi_output_fb ^ new_fb) & new_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 1); + })); + /* *INDENT-ON* */ + + /* remove unneeded features */ + diff_fb = (gi->gi_output_fb ^ new_fb) & gi->gi_output_fb; + + /* *INDENT-OFF* */ + foreach_set_bit (feat, diff_fb, + ({ + l2output_intf_bitmap_enable (gi->gi_sw_if_index, (1 << feat), 0); + })); + /* *INDENT-ON* */ + + gi->gi_output_fb = new_fb; +} + +static u8 * +format_gbp_itf_mode (u8 * s, va_list * args) +{ + gbp_itf_mode_t mode = va_arg (*args, gbp_itf_mode_t); + + switch (mode) + { +#define _(a,v) \ + case GBP_ITF_MODE_##a: \ + return format(s, "%s", v); + foreach_gbp_itf_mode +#undef _ + } + return (s); +} + +static u8 * +format_gbp_itf (u8 * s, va_list * args) +{ + index_t gii = va_arg (*args, index_t); + gbp_itf_t *gi; + + if (INDEX_INVALID == gii) + return (format (s, "unset")); + + gi = gbp_itf_get (gii); + + s = format (s, "%U locks:%d mode:%U ", + format_vnet_sw_if_index_name, vnet_get_main (), + gi->gi_sw_if_index, gi->gi_locks, + format_gbp_itf_mode, gi->gi_mode); + + if (GBP_ITF_MODE_L2 == gi->gi_mode) + s = format (s, "gbp-bd:%d input-feats:[%U] output-feats:[%U]", + gi->gi_gbi, + format_l2_input_features, gi->gi_input_fb, 0, + format_l2_output_features, gi->gi_output_fb, 0); + else + s = format (s, "gbp-rd:%d input-feats:[%U] output-feats:[%U]", + gi->gi_gbi, + format_gbp_itf_l3_feat, gi->gi_input_fb, + format_gbp_itf_l3_feat, gi->gi_output_fb); + + return (s); +} + +u8 * +format_gbp_itf_hdl (u8 * s, va_list * args) +{ + gbp_itf_hdl_t gh = va_arg (*args, gbp_itf_hdl_t); + gbp_itf_t *gi; + + gi = gbp_itf_find_hdl (gh); + + if (NULL == gi) + return format (s, "INVALID"); + + return (format (s, "%U", format_gbp_itf, gi - gbp_itf_pool)); +} + +static clib_error_t * +gbp_itf_show (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u32 gii; + + vlib_cli_output (vm, "Interfaces:"); + + /* *INDENT-OFF* */ + pool_foreach_index (gii, gbp_itf_pool) + { + vlib_cli_output (vm, " [%d] %U", gii, format_gbp_itf, gii); + } + /* *INDENT-ON* */ + + return (NULL); +} + +/*? + * Show Group Based Interfaces + * + * @cliexpar + * @cliexstart{show gbp contract} + * @cliexend + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (gbp_contract_show_node, static) = { + .path = "show gbp interface", + .short_help = "show gbp interface\n", + .function = gbp_itf_show, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |