From 7490a752814187ed03c0deca4d836b0dca09fb4b Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Tue, 15 Nov 2016 09:19:11 +0100 Subject: [PATCH] feature: API/CLI to enable/disable feature per interface Change-Id: I91d5f5648189143903eb973fdc60de9880fd47c2 Signed-off-by: Pavel Kotucek --- vnet/vnet/api_errno.h | 3 +- vnet/vnet/feature/feature.c | 104 ++++++++++++++++++++++++++++++++++++++++++ vnet/vnet/feature/feature.h | 10 ++++ vpp-api-test/vat/api_format.c | 76 ++++++++++++++++++++++++++++-- vpp/vpp-api/api.c | 43 ++++++++++++++++- vpp/vpp-api/custom_dump.c | 18 +++++++- vpp/vpp-api/vpe.api | 24 ++++++++++ 7 files changed, 272 insertions(+), 6 deletions(-) diff --git a/vnet/vnet/api_errno.h b/vnet/vnet/api_errno.h index baf3c615974..50d6f731035 100644 --- a/vnet/vnet/api_errno.h +++ b/vnet/vnet/api_errno.h @@ -89,7 +89,8 @@ _(EXCEEDED_NUMBER_OF_RANGES_CAPACITY, -95, "Operation would exceed configured ca _(EXCEEDED_NUMBER_OF_PORTS_CAPACITY, -96, "Operation would exceed capacity of number of ports") \ _(INVALID_ADDRESS_FAMILY, -97, "Invalid address family") \ _(INVALID_SUB_SW_IF_INDEX, -98, "Invalid sub-interface sw_if_index") \ -_(TABLE_TOO_BIG, -99, "Table too big") +_(TABLE_TOO_BIG, -99, "Table too big") \ +_(CANNOT_ENABLE_DISABLE_FEATURE, -100, "Cannot enable/disable feature") typedef enum { diff --git a/vnet/vnet/feature/feature.c b/vnet/vnet/feature/feature.c index c8cde360814..e1d172e5707 100644 --- a/vnet/vnet/feature/feature.c +++ b/vnet/vnet/feature/feature.c @@ -152,6 +152,27 @@ vnet_get_feature_arc_index (const char *s) return reg->feature_arc_index; } +vnet_feature_registration_t * +vnet_get_feature_reg (const char *arc_name, const char *node_name) +{ + u8 arc_index; + + arc_index = vnet_get_feature_arc_index (arc_name); + if (arc_index == (u8) ~ 0) + return 0; + + vnet_feature_main_t *fm = &feature_main; + vnet_feature_registration_t *reg; + uword *p; + + p = hash_get_mem (fm->next_feature_by_name[arc_index], node_name); + if (p == 0) + return 0; + + reg = uword_to_pointer (p[0], vnet_feature_registration_t *); + return reg; +} + u32 vnet_get_feature_index (u8 arc, const char *s) { @@ -342,6 +363,89 @@ vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index) } } +static clib_error_t * +set_interface_features_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + + u8 *arc_name = 0; + u8 *feature_name = 0; + u32 sw_if_index = ~0; + u8 enable = 1; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + goto done; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (line_input, "%U %v", unformat_vnet_sw_interface, vnm, &sw_if_index, + &feature_name)) + ; + else if (unformat (line_input, "arc %v", &arc_name)) + ; + else if (unformat (line_input, "disable")) + enable = 0; + else + { + error = unformat_parse_error (line_input); + goto done; + } + } + + if (sw_if_index == ~0) + { + error = clib_error_return (0, "Interface not specified..."); + goto done; + } + + vec_add1 (arc_name, 0); + vec_add1 (feature_name, 0); + + vnet_feature_registration_t *reg; + reg = + vnet_get_feature_reg ((const char *) arc_name, + (const char *) feature_name); + if (reg == 0) + { + error = clib_error_return (0, "Unknown feature..."); + goto done; + } + if (reg->enable_disable_cb) + error = reg->enable_disable_cb (sw_if_index, enable); + if (!error) + vnet_feature_enable_disable ((const char *) arc_name, + (const char *) feature_name, sw_if_index, + enable, 0, 0); + +done: + vec_free (feature_name); + vec_free (arc_name); + return error; +} + +/*? + * Set feature for given interface + * + * @cliexpar + * Example: + * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast} + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_feature_command, static) = { + .path = "set interface feature", + .short_help = "set interface feature arc ", + .function = set_interface_features_command_fn, +}; +/* *INDENT-ON* */ + /* * fd.io coding-style-patch-verification: ON * diff --git a/vnet/vnet/feature/feature.h b/vnet/vnet/feature/feature.h index 667c5e36b62..96d573b69f6 100644 --- a/vnet/vnet/feature/feature.h +++ b/vnet/vnet/feature/feature.h @@ -34,6 +34,10 @@ typedef struct _vnet_feature_arc_registration u8 *arc_index_ptr; } vnet_feature_arc_registration_t; +/* Enable feature callback. */ +typedef clib_error_t *(vnet_feature_enable_disable_function_t) + (u32 sw_if_index, int enable_disable); + /** feature registration object */ typedef struct _vnet_feature_registration { @@ -50,6 +54,9 @@ typedef struct _vnet_feature_registration char **runs_before; /** Constraints of the form "this feature runs after Y" */ char **runs_after; + + /** Function to enable/disable feature **/ + vnet_feature_enable_disable_function_t *enable_disable_cb; } vnet_feature_registration_t; typedef struct vnet_feature_config_main_t_ @@ -121,6 +128,9 @@ vnet_config_update_feature_count (vnet_feature_main_t * fm, u8 arc, u32 vnet_get_feature_index (u8 arc, const char *s); u8 vnet_get_feature_arc_index (const char *s); +vnet_feature_registration_t *vnet_get_feature_reg (const char *arc_name, + const char *node_name); + int vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index, diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index aa875256679..3d7ce4686c8 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -3575,7 +3575,8 @@ _(ip_source_and_port_range_check_add_del_reply) \ _(ip_source_and_port_range_check_interface_add_del_reply)\ _(delete_subif_reply) \ _(l2_interface_pbb_tag_rewrite_reply) \ -_(punt_reply) +_(punt_reply) \ +_(feature_enable_disable_reply) #define _(n) \ static void vl_api_##n##_t_handler \ @@ -3817,7 +3818,8 @@ _(DELETE_SUBIF_REPLY, delete_subif_reply) \ _(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \ _(PUNT_REPLY, punt_reply) \ _(IP_FIB_DETAILS, ip_fib_details) \ -_(IP6_FIB_DETAILS, ip6_fib_details) +_(IP6_FIB_DETAILS, ip6_fib_details) \ +_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) /* M: construct, but don't yet send a message */ @@ -16279,6 +16281,72 @@ api_flow_classify_dump (vat_main_t * vam) return 0; } +static int +api_feature_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_feature_enable_disable_t *mp; + f64 timeout; + u8 *arc_name = 0; + u8 *feature_name = 0; + u32 sw_if_index = ~0; + u8 enable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "arc_name %s", &arc_name)) + ; + else if (unformat (i, "feature_name %s", &feature_name)) + ; + else if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (arc_name == 0) + { + errmsg ("missing arc name\n"); + return -99; + } + if (vec_len (arc_name) > 63) + { + errmsg ("arc name too long\n"); + } + + if (feature_name == 0) + { + errmsg ("missing feature name\n"); + return -99; + } + if (vec_len (feature_name) > 63) + { + errmsg ("feature name too long\n"); + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index\n"); + return -99; + } + + /* Construct the API message */ + M (FEATURE_ENABLE_DISABLE, feature_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + clib_memcpy (mp->arc_name, arc_name, vec_len (arc_name)); + clib_memcpy (mp->feature_name, feature_name, vec_len (feature_name)); + vec_free (arc_name); + vec_free (feature_name); + + S; + W; +} + static int q_or_quit (vat_main_t * vam) { @@ -16889,7 +16957,9 @@ _(flow_classify_set_interface, \ " | sw_if_index [ip4-table ] [ip6-table ] [del]") \ _(flow_classify_dump, "type [ip4|ip6]") \ _(ip_fib_dump, "") \ -_(ip6_fib_dump, "") +_(ip6_fib_dump, "") \ +_(feature_enable_disable, "arc_name " \ + "feature_name | sw_if_index [disable]") /* List of command functions, CLI names map directly to functions */ #define foreach_cli_function \ diff --git a/vpp/vpp-api/api.c b/vpp/vpp-api/api.c index e234df8f41a..b2b639a718c 100644 --- a/vpp/vpp-api/api.c +++ b/vpp/vpp-api/api.c @@ -89,6 +89,7 @@ #include #include #include +#include #undef BIHASH_TYPE #undef __included_bihash_template_h__ @@ -466,7 +467,8 @@ _(IPSEC_SPD_DUMP, ipsec_spd_dump) \ _(IP_FIB_DUMP, ip_fib_dump) \ _(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DUMP, ip6_fib_dump) \ -_(IP6_FIB_DETAILS, ip6_fib_details) +_(IP6_FIB_DETAILS, ip6_fib_details) \ +_(FEATURE_ENABLE_DISABLE, feature_enable_disable) #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) @@ -9174,6 +9176,45 @@ vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp) #endif } +static void +vl_api_feature_enable_disable_t_handler (vl_api_feature_enable_disable_t * mp) +{ + vl_api_feature_enable_disable_reply_t *rmp; + int rv = 0; + + u8 *arc_name = format (0, "%s%c", mp->arc_name, 0); + u8 *feature_name = format (0, "%s%c", mp->feature_name, 0); + u32 sw_if_index = ntohl (mp->sw_if_index); + + vnet_feature_registration_t *reg; + reg = + vnet_get_feature_reg ((const char *) arc_name, + (const char *) feature_name); + if (reg == 0) + rv = VNET_API_ERROR_INVALID_VALUE; + else + { + clib_error_t *error = 0; + + if (reg->enable_disable_cb) + error = reg->enable_disable_cb (sw_if_index, mp->enable); + if (!error) + vnet_feature_enable_disable ((const char *) arc_name, + (const char *) feature_name, + sw_if_index, mp->enable, 0, 0); + else + { + clib_error_report (error); + rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE; + } + } + + vec_free (feature_name); + vec_free (arc_name); + + REPLY_MACRO (VL_API_FEATURE_ENABLE_DISABLE_REPLY); +} + #define BOUNCE_HANDLER(nn) \ static void vl_api_##nn##_t_handler ( \ vl_api_##nn##_t *mp) \ diff --git a/vpp/vpp-api/custom_dump.c b/vpp/vpp-api/custom_dump.c index 1dc96650aec..6c181eecacb 100644 --- a/vpp/vpp-api/custom_dump.c +++ b/vpp/vpp-api/custom_dump.c @@ -2892,6 +2892,21 @@ static void *vl_api_ioam_disable_t_print FINISH; } +static void *vl_api_feature_enable_disable_t_print + (vl_api_feature_enable_disable_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: feature_enable_disable "); + s = format (s, "arc_name %s ", mp->arc_name); + s = format (s, "feature_name %s ", mp->feature_name); + s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); + if (!mp->enable) + s = format (s, "disable"); + + FINISH; +} + #define foreach_custom_print_no_arg_function \ _(lisp_eid_table_vni_dump) \ _(lisp_map_resolver_dump) \ @@ -3062,7 +3077,8 @@ _(GET_FIRST_MSG_ID, get_first_msg_id) \ _(IOAM_ENABLE, ioam_enable) \ _(IOAM_DISABLE, ioam_disable) \ _(IP_FIB_DUMP, ip_fib_dump) \ -_(IP6_FIB_DUMP, ip6_fib_dump) +_(IP6_FIB_DUMP, ip6_fib_dump) \ +_(FEATURE_ENABLE_DISABLE, feature_enable_disable) void vl_msg_api_custom_dump_configure (api_main_t * am) { diff --git a/vpp/vpp-api/vpe.api b/vpp/vpp-api/vpe.api index 8a7fac67604..934c4d830d4 100644 --- a/vpp/vpp-api/vpe.api +++ b/vpp/vpp-api/vpe.api @@ -5495,3 +5495,27 @@ define ipsec_spd_details { u64 packets; }; +/** \brief Feature path enable/disable request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - the interface + @param enable - 1 = on, 0 = off +*/ +define feature_enable_disable { + u32 client_index; + u32 context; + u32 sw_if_index; + u8 enable; + u8 arc_name[64]; + u8 feature_name[64]; +}; + +/** \brief Reply to the eature path enable/disable request + @param context - sender context which was passed in the request + @param retval - return code for the request +*/ +define feature_enable_disable_reply +{ + u32 context; + i32 retval; +}; -- 2.16.6