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));
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'",
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;
freg = freg->next;
}
+ cm->end_feature_index =
+ vnet_get_feature_index (arc_index, areg->end_node);
+
/* next */
areg = areg->next;
arc_index++;
}
- fm->device_input_feature_arc_index =
- vnet_get_feature_arc_index ("device-input");
return 0;
}
VLIB_INIT_FUNCTION (vnet_feature_init);
-void
-vnet_config_update_feature_count (vnet_feature_main_t * fm, u8 arc,
- u32 sw_if_index, int is_add)
-{
- uword bit_value;
-
- vec_validate (fm->feature_count_by_sw_if_index[arc], sw_if_index);
-
- fm->feature_count_by_sw_if_index[arc][sw_if_index] += is_add ? 1 : -1;
-
- ASSERT (fm->feature_count_by_sw_if_index[arc][sw_if_index] >= 0);
-
- bit_value = fm->feature_count_by_sw_if_index[arc][sw_if_index] > 0;
-
- fm->sw_if_index_has_features[arc] =
- clib_bitmap_set (fm->sw_if_index_has_features[arc], sw_if_index,
- bit_value);
-}
-
u8
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)
{
vnet_feature_registration_t *reg;
uword *p;
+ if (s == 0)
+ return ~0;
+
p = hash_get_mem (fm->next_feature_by_name[arc], s);
if (p == 0)
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);
+ i16 feature_count;
+ int is_first_or_last;
+ 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);
+ feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
+
+ if (!enable_disable && feature_count < 1)
+ return 0;
+
ci = (enable_disable
? vnet_config_add_feature
: vnet_config_del_feature)
n_feature_config_bytes);
cm->config_index_by_sw_if_index[sw_if_index] = ci;
- vnet_config_update_feature_count (fm, arc_index, sw_if_index,
- enable_disable);
+ /* update feature count */
+ enable_disable = (enable_disable > 0);
+ feature_count += enable_disable ? 1 : -1;
+ is_first_or_last = (feature_count == enable_disable);
+ ASSERT (feature_count >= 0);
+
+ if (is_first_or_last && cm->end_feature_index != ~0)
+ {
+ /*register end node */
+ ci = (enable_disable
+ ? vnet_config_add_feature
+ : vnet_config_del_feature)
+ (vlib_get_main (), &cm->config_main, ci, cm->end_feature_index, 0, 0);
+ cm->config_index_by_sw_if_index[sw_if_index] = ci;
+ }
+
+ fm->sw_if_index_has_features[arc_index] =
+ clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
+ (feature_count > 0));
+
+ fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
+ 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);
}
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 */
}
}
+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
*