feature: API/CLI to enable/disable feature per interface
[vpp.git] / vnet / vnet / feature / feature.c
index bfdea3d..e1d172e 100644 (file)
@@ -34,6 +34,8 @@ vnet_feature_init (vlib_main_t * vm)
       char *s;
       int i = 0;
       areg->feature_arc_index = arc_index;
+      if (areg->arc_index_ptr)
+       *areg->arc_index_ptr = arc_index;
       hash_set_mem (fm->arc_index_by_name, areg->arc_name,
                    pointer_to_uword (areg));
 
@@ -59,6 +61,7 @@ vnet_feature_init (vlib_main_t * vm)
   freg = fm->next_feature;
   while (freg)
     {
+      vnet_feature_registration_t *next;
       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
       if (p == 0)
        return clib_error_return (0, "Unknown feature arc '%s'",
@@ -67,12 +70,15 @@ vnet_feature_init (vlib_main_t * vm)
       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
       arc_index = areg->feature_arc_index;
 
-      vec_add1 (fm->next_feature_by_arc[arc_index], *freg);
+      next = freg->next;
+      freg->next = fm->next_feature_by_arc[arc_index];
+      fm->next_feature_by_arc[arc_index] = freg;
 
       /* next */
-      freg = freg->next;
+      freg = next;
     }
 
+  areg = fm->next_arc;
   while (areg)
     {
       clib_error_t *error;
@@ -107,8 +113,6 @@ vnet_feature_init (vlib_main_t * vm)
       arc_index++;
     }
 
-  fm->device_input_feature_arc_index =
-    vnet_get_feature_arc_index ("device-input");
   return 0;
 }
 
@@ -148,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)
 {
@@ -160,31 +185,34 @@ vnet_get_feature_index (u8 arc, const char *s)
     return ~0;
 
   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
-  return reg->feature_index_u32;
+  return reg->feature_index;
 }
 
-void
-vnet_feature_enable_disable (const char *arc_name, const char *node_name,
-                            u32 sw_if_index, int enable_disable,
-                            void *feature_config, u32 n_feature_config_bytes)
+int
+vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
+                                       u32 sw_if_index, int enable_disable,
+                                       void *feature_config,
+                                       u32 n_feature_config_bytes)
 {
   vnet_feature_main_t *fm = &feature_main;
   vnet_feature_config_main_t *cm;
-  u32 feature_index, ci;
-  u8 arc_index;
-
-  arc_index = vnet_get_feature_arc_index (arc_name);
+  u32 ci;
 
   if (arc_index == (u8) ~ 0)
-    return;
+    return VNET_API_ERROR_INVALID_VALUE;
+
+  if (feature_index == ~0)
+    return VNET_API_ERROR_INVALID_VALUE_2;
 
   cm = &fm->feature_config_mains[arc_index];
   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
-  feature_index = vnet_get_feature_index (arc_index, node_name);
-  if (feature_index == ~0)
-    return;
   ci = cm->config_index_by_sw_if_index[sw_if_index];
 
+  vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
+  if (!enable_disable
+      && fm->feature_count_by_sw_if_index[arc_index][sw_if_index] < 1)
+    return 0;
+
   ci = (enable_disable
        ? vnet_config_add_feature
        : vnet_config_del_feature)
@@ -195,6 +223,28 @@ vnet_feature_enable_disable (const char *arc_name, const char *node_name,
   vnet_config_update_feature_count (fm, arc_index, sw_if_index,
                                    enable_disable);
 
+  return 0;
+}
+
+int
+vnet_feature_enable_disable (const char *arc_name, const char *node_name,
+                            u32 sw_if_index, int enable_disable,
+                            void *feature_config, u32 n_feature_config_bytes)
+{
+  u32 feature_index;
+  u8 arc_index;
+
+  arc_index = vnet_get_feature_arc_index (arc_name);
+
+  if (arc_index == (u8) ~ 0)
+    return VNET_API_ERROR_INVALID_VALUE;
+
+  feature_index = vnet_get_feature_index (arc_index, node_name);
+
+  return vnet_feature_enable_disable_with_index (arc_index, feature_index,
+                                                sw_if_index, enable_disable,
+                                                feature_config,
+                                                n_feature_config_bytes);
 }
 
 
@@ -216,10 +266,12 @@ show_features_command_fn (vlib_main_t * vm,
   while (areg)
     {
       vlib_cli_output (vm, "%s:", areg->arc_name);
-      vec_foreach (freg, fm->next_feature_by_arc[areg->feature_arc_index])
-      {
-       vlib_cli_output (vm, "  %s\n", freg->node_name);
-      }
+      freg = fm->next_feature_by_arc[areg->feature_arc_index];
+      while (freg)
+       {
+         vlib_cli_output (vm, "  %s\n", freg->node_name);
+         freg = freg->next;
+       }
 
 
       /* next */
@@ -311,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
  *