feature: API/CLI to enable/disable feature per interface 24/3824/4
authorPavel Kotucek <pkotucek@cisco.com>
Tue, 15 Nov 2016 08:19:11 +0000 (09:19 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 17 Nov 2016 21:03:25 +0000 (21:03 +0000)
Change-Id: I91d5f5648189143903eb973fdc60de9880fd47c2
Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
vnet/vnet/api_errno.h
vnet/vnet/feature/feature.c
vnet/vnet/feature/feature.h
vpp-api-test/vat/api_format.c
vpp/vpp-api/api.c
vpp/vpp-api/custom_dump.c
vpp/vpp-api/vpe.api

index baf3c61..50d6f73 100644 (file)
@@ -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
 {
index c8cde36..e1d172e 100644 (file)
@@ -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 <intfc> <feature_name> arc <arc_name>",
+  .function = set_interface_features_command_fn,
+};
+/* *INDENT-ON* */
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index 667c5e3..96d573b 100644 (file)
@@ -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,
index aa87525..3d7ce46 100644 (file)
@@ -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,                                          \
   "<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>] [del]") \
 _(flow_classify_dump, "type [ip4|ip6]")                                 \
 _(ip_fib_dump, "")                                                      \
-_(ip6_fib_dump, "")
+_(ip6_fib_dump, "")                                                     \
+_(feature_enable_disable, "arc_name <arc_name> "                        \
+  "feature_name <feature_name> <intfc> | sw_if_index <nn> [disable]")
 
 /* List of command functions, CLI names map directly to functions */
 #define foreach_cli_function                                    \
index e234df8..b2b639a 100644 (file)
@@ -89,6 +89,7 @@
 #include <vnet/ipsec-gre/ipsec_gre.h>
 #include <vnet/flow/flow_report_classify.h>
 #include <vnet/ip/punt.h>
+#include <vnet/feature/feature.h>
 
 #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)                                                \
index 1dc9665..6c181ee 100644 (file)
@@ -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)
 {
index 8a7fac6..934c4d8 100644 (file)
@@ -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;
+};