From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/feature/feature.c | 463 ++++++++++++++++++++++++++++++++++++++++ src/vnet/feature/feature.h | 382 +++++++++++++++++++++++++++++++++ src/vnet/feature/registration.c | 301 ++++++++++++++++++++++++++ 3 files changed, 1146 insertions(+) create mode 100644 src/vnet/feature/feature.c create mode 100644 src/vnet/feature/feature.h create mode 100644 src/vnet/feature/registration.c (limited to 'src/vnet/feature') diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c new file mode 100644 index 00000000..032fe784 --- /dev/null +++ b/src/vnet/feature/feature.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2016 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 + +vnet_feature_main_t feature_main; + +static clib_error_t * +vnet_feature_init (vlib_main_t * vm) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_registration_t *freg; + vnet_feature_arc_registration_t *areg; + u32 arc_index = 0; + + fm->arc_index_by_name = hash_create_string (0, sizeof (uword)); + areg = fm->next_arc; + + /* process feature arc registrations */ + while (areg) + { + 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)); + + /* process start nodes */ + while ((s = areg->start_nodes[i])) + { + i++; + } + areg->n_start_nodes = i; + + /* next */ + areg = areg->next; + arc_index++; + } + + vec_validate (fm->next_feature_by_arc, arc_index - 1); + vec_validate (fm->feature_nodes, arc_index - 1); + vec_validate (fm->feature_config_mains, arc_index - 1); + vec_validate (fm->next_feature_by_name, arc_index - 1); + vec_validate (fm->sw_if_index_has_features, arc_index - 1); + vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1); + + 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'", + freg->arc_name); + + areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *); + arc_index = areg->feature_arc_index; + + next = freg->next; + freg->next = fm->next_feature_by_arc[arc_index]; + fm->next_feature_by_arc[arc_index] = freg; + + /* next */ + freg = next; + } + + areg = fm->next_arc; + while (areg) + { + clib_error_t *error; + vnet_feature_config_main_t *cm; + vnet_config_main_t *vcm; + + arc_index = areg->feature_arc_index; + cm = &fm->feature_config_mains[arc_index]; + vcm = &cm->config_main; + if ((error = vnet_feature_arc_init (vm, vcm, + areg->start_nodes, + areg->n_start_nodes, + fm->next_feature_by_arc[arc_index], + &fm->feature_nodes[arc_index]))) + { + return error; + } + + fm->next_feature_by_name[arc_index] = + hash_create_string (0, sizeof (uword)); + freg = fm->next_feature_by_arc[arc_index]; + + while (freg) + { + hash_set_mem (fm->next_feature_by_name[arc_index], + freg->node_name, pointer_to_uword (freg)); + freg = freg->next; + } + + cm->end_feature_index = + vnet_get_feature_index (arc_index, areg->end_node); + + /* next */ + areg = areg->next; + arc_index++; + } + + return 0; +} + +VLIB_INIT_FUNCTION (vnet_feature_init); + +u8 +vnet_get_feature_arc_index (const char *s) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_arc_registration_t *reg; + uword *p; + + p = hash_get_mem (fm->arc_index_by_name, s); + if (p == 0) + return ~0; + + reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *); + 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_main_t *fm = &feature_main; + 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; +} + +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; + i16 feature_count; + int is_first_or_last; + u32 ci; + + if (arc_index == (u8) ~ 0) + 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); + 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) + (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config, + n_feature_config_bytes); + cm->config_index_by_sw_if_index[sw_if_index] = ci; + + /* 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); +} + + +/** Display the set of available driver features. + Useful for verifying that expected features are present +*/ + +static clib_error_t * +show_features_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_arc_registration_t *areg; + vnet_feature_registration_t *freg; + + vlib_cli_output (vm, "Available feature paths"); + + areg = fm->next_arc; + while (areg) + { + vlib_cli_output (vm, "%s:", areg->arc_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 */ + areg = areg->next; + } + + return 0; +} + +/*? + * Display the set of available driver features + * + * @cliexpar + * Example: + * @cliexcmd{show ip features} + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_features_command, static) = { + .path = "show features", + .short_help = "show features", + .function = show_features_command_fn, +}; +/* *INDENT-ON* */ + +/** Display the set of driver features configured on a specific interface + * Called by "show interface" handler + */ + +void +vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index) +{ + vnet_feature_main_t *fm = &feature_main; + u32 node_index, current_config_index; + u16 feature_arc; + vnet_feature_config_main_t *cm = fm->feature_config_mains; + vnet_feature_arc_registration_t *areg; + vnet_config_main_t *vcm; + vnet_config_t *cfg; + u32 cfg_index; + vnet_config_feature_t *feat; + vlib_node_t *n; + int i; + + vlib_cli_output (vm, "Driver feature paths configured on %U...", + format_vnet_sw_if_index_name, + vnet_get_main (), sw_if_index); + + areg = fm->next_arc; + while (areg) + { + feature_arc = areg->feature_arc_index; + vcm = &(cm[feature_arc].config_main); + + vlib_cli_output (vm, "\n%s:", areg->arc_name); + areg = areg->next; + + if (NULL == cm[feature_arc].config_index_by_sw_if_index || + vec_len (cm[feature_arc].config_index_by_sw_if_index) <= + sw_if_index) + { + vlib_cli_output (vm, " none configured"); + continue; + } + + current_config_index = + vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index); + + if (current_config_index == ~0) + { + vlib_cli_output (vm, " none configured"); + continue; + } + + ASSERT (current_config_index + < vec_len (vcm->config_pool_index_by_user_index)); + + cfg_index = vcm->config_pool_index_by_user_index[current_config_index]; + cfg = pool_elt_at_index (vcm->config_pool, cfg_index); + + for (i = 0; i < vec_len (cfg->features); i++) + { + feat = cfg->features + i; + node_index = feat->node_index; + n = vlib_get_node (vm, node_index); + vlib_cli_output (vm, " %v", n->name); + } + } +} + +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 + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/feature/feature.h b/src/vnet/feature/feature.h new file mode 100644 index 00000000..b27aaf17 --- /dev/null +++ b/src/vnet/feature/feature.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2016 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. + */ + +#ifndef included_features_h +#define included_features_h + +#include +#include + +/** feature registration object */ +typedef struct _vnet_feature_arc_registration +{ + /** next registration in list of all registrations*/ + struct _vnet_feature_arc_registration *next; + /** Feature Arc name */ + char *arc_name; + /** Start nodes */ + char **start_nodes; + int n_start_nodes; + /** End node */ + char *end_node; + /* Feature arc index, assigned by init function */ + u8 feature_arc_index; + 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 +{ + /** next registration in list of all registrations*/ + struct _vnet_feature_registration *next; + /** Feature arc name */ + char *arc_name; + /** Graph node name */ + char *node_name; + /** Pointer to this feature index, filled in by vnet_feature_arc_init */ + u32 *feature_index_ptr; + u32 feature_index; + /** Constraints of the form "this feature runs before X" */ + 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_ +{ + vnet_config_main_t config_main; + u32 *config_index_by_sw_if_index; + u32 end_feature_index; +} vnet_feature_config_main_t; + +typedef struct +{ + /** feature arc configuration list */ + vnet_feature_arc_registration_t *next_arc; + uword **arc_index_by_name; + + /** feature path configuration lists */ + vnet_feature_registration_t *next_feature; + vnet_feature_registration_t **next_feature_by_arc; + uword **next_feature_by_name; + + /** feature config main objects */ + vnet_feature_config_main_t *feature_config_mains; + + /** Save partial order results for show command */ + char ***feature_nodes; + + /** bitmap of interfaces which have driver rx features configured */ + uword **sw_if_index_has_features; + + /** feature reference counts by interface */ + i16 **feature_count_by_sw_if_index; + + /** Feature arc index for device-input */ + u8 device_input_feature_arc_index; + + /** convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} vnet_feature_main_t; + +extern vnet_feature_main_t feature_main; + +#define VNET_FEATURE_ARC_INIT(x,...) \ + __VA_ARGS__ vnet_feature_arc_registration_t vnet_feat_arc_##x;\ +static void __vnet_add_feature_arc_registration_##x (void) \ + __attribute__((__constructor__)) ; \ +static void __vnet_add_feature_arc_registration_##x (void) \ +{ \ + vnet_feature_main_t * fm = &feature_main; \ + vnet_feat_arc_##x.next = fm->next_arc; \ + fm->next_arc = & vnet_feat_arc_##x; \ +} \ +__VA_ARGS__ vnet_feature_arc_registration_t vnet_feat_arc_##x + +#define VNET_FEATURE_INIT(x,...) \ + __VA_ARGS__ vnet_feature_registration_t vnet_feat_##x; \ +static void __vnet_add_feature_registration_##x (void) \ + __attribute__((__constructor__)) ; \ +static void __vnet_add_feature_registration_##x (void) \ +{ \ + vnet_feature_main_t * fm = &feature_main; \ + vnet_feat_##x.next = fm->next_feature; \ + fm->next_feature = & vnet_feat_##x; \ +} \ +__VA_ARGS__ vnet_feature_registration_t vnet_feat_##x + +void +vnet_config_update_feature_count (vnet_feature_main_t * fm, u8 arc, + u32 sw_if_index, int is_add); + +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, + u32 sw_if_index, int enable_disable, + void *feature_config, + u32 n_feature_config_bytes); + +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); + +static inline vnet_feature_config_main_t * +vnet_get_feature_arc_config_main (u8 arc_index) +{ + vnet_feature_main_t *fm = &feature_main; + + if (arc_index == (u8) ~ 0) + return 0; + + return &fm->feature_config_mains[arc_index]; +} + +static_always_inline vnet_feature_config_main_t * +vnet_feature_get_config_main (u16 arc) +{ + vnet_feature_main_t *fm = &feature_main; + return &fm->feature_config_mains[arc]; +} + +static_always_inline int +vnet_have_features (u8 arc, u32 sw_if_index) +{ + vnet_feature_main_t *fm = &feature_main; + return clib_bitmap_get (fm->sw_if_index_has_features[arc], sw_if_index); +} + +static_always_inline u32 +vnet_get_feature_config_index (u8 arc, u32 sw_if_index) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc]; + return vec_elt (cm->config_index_by_sw_if_index, sw_if_index); +} + +static_always_inline void * +vnet_feature_arc_start_with_data (u8 arc, u32 sw_if_index, u32 * next, + vlib_buffer_t * b, u32 n_data_bytes) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + cm = &fm->feature_config_mains[arc]; + + if (PREDICT_FALSE (vnet_have_features (arc, sw_if_index))) + { + b->feature_arc_index = arc; + b->current_config_index = + vec_elt (cm->config_index_by_sw_if_index, sw_if_index); + return vnet_get_config_data (&cm->config_main, &b->current_config_index, + next, n_data_bytes); + } + return 0; +} + +static_always_inline void +vnet_feature_arc_start (u8 arc, u32 sw_if_index, u32 * next0, + vlib_buffer_t * b0) +{ + vnet_feature_arc_start_with_data (arc, sw_if_index, next0, b0, 0); +} + +static_always_inline void * +vnet_feature_next_with_data (u32 sw_if_index, u32 * next0, + vlib_buffer_t * b0, u32 n_data_bytes) +{ + vnet_feature_main_t *fm = &feature_main; + u8 arc = b0->feature_arc_index; + vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc]; + + return vnet_get_config_data (&cm->config_main, + &b0->current_config_index, next0, + n_data_bytes); +} + +static_always_inline void +vnet_feature_next (u32 sw_if_index, u32 * next0, vlib_buffer_t * b0) +{ + vnet_feature_next_with_data (sw_if_index, next0, b0, 0); +} + +static_always_inline void +vnet_feature_start_device_input_x1 (u32 sw_if_index, u32 * next0, + vlib_buffer_t * b0, u16 buffer_advanced0) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + u8 feature_arc_index = fm->device_input_feature_arc_index; + cm = &fm->feature_config_mains[feature_arc_index]; + + if (PREDICT_FALSE + (clib_bitmap_get + (fm->sw_if_index_has_features[feature_arc_index], sw_if_index))) + { + /* + * Save next0 so that the last feature in the chain + * can skip ethernet-input if indicated... + */ + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; + vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; + vlib_buffer_advance (b0, -buffer_advanced0); + + b0->feature_arc_index = feature_arc_index; + b0->current_config_index = + vec_elt (cm->config_index_by_sw_if_index, sw_if_index); + vnet_get_config_data (&cm->config_main, &b0->current_config_index, + next0, /* # bytes of config data */ 0); + } +} + +static_always_inline void +vnet_feature_start_device_input_x2 (u32 sw_if_index, + u32 * next0, + u32 * next1, + vlib_buffer_t * b0, + vlib_buffer_t * b1, + u16 buffer_advanced0, + u16 buffer_advanced1) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + u8 feature_arc_index = fm->device_input_feature_arc_index; + cm = &fm->feature_config_mains[feature_arc_index]; + + if (PREDICT_FALSE + (clib_bitmap_get + (fm->sw_if_index_has_features[feature_arc_index], sw_if_index))) + { + /* + * Save next0 so that the last feature in the chain + * can skip ethernet-input if indicated... + */ + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; + vnet_buffer (b1)->device_input_feat.saved_next_index = *next1; + vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; + vnet_buffer (b1)->device_input_feat.buffer_advance = buffer_advanced1; + vlib_buffer_advance (b0, -buffer_advanced0); + vlib_buffer_advance (b1, -buffer_advanced1); + + b0->feature_arc_index = feature_arc_index; + b1->feature_arc_index = feature_arc_index; + b0->current_config_index = + vec_elt (cm->config_index_by_sw_if_index, sw_if_index); + b1->current_config_index = b0->current_config_index; + vnet_get_config_data (&cm->config_main, &b0->current_config_index, + next0, /* # bytes of config data */ 0); + vnet_get_config_data (&cm->config_main, &b1->current_config_index, + next1, /* # bytes of config data */ 0); + } +} + +static_always_inline void +vnet_feature_start_device_input_x4 (u32 sw_if_index, + u32 * next0, + u32 * next1, + u32 * next2, + u32 * next3, + vlib_buffer_t * b0, + vlib_buffer_t * b1, + vlib_buffer_t * b2, + vlib_buffer_t * b3, + u16 buffer_advanced0, + u16 buffer_advanced1, + u16 buffer_advanced2, + u16 buffer_advanced3) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + u8 feature_arc_index = fm->device_input_feature_arc_index; + cm = &fm->feature_config_mains[feature_arc_index]; + + if (PREDICT_FALSE + (clib_bitmap_get + (fm->sw_if_index_has_features[feature_arc_index], sw_if_index))) + { + /* + * Save next0 so that the last feature in the chain + * can skip ethernet-input if indicated... + */ + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; + vnet_buffer (b1)->device_input_feat.saved_next_index = *next1; + vnet_buffer (b2)->device_input_feat.saved_next_index = *next2; + vnet_buffer (b3)->device_input_feat.saved_next_index = *next3; + + vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; + vnet_buffer (b1)->device_input_feat.buffer_advance = buffer_advanced1; + vnet_buffer (b2)->device_input_feat.buffer_advance = buffer_advanced2; + vnet_buffer (b3)->device_input_feat.buffer_advance = buffer_advanced3; + + vlib_buffer_advance (b0, -buffer_advanced0); + vlib_buffer_advance (b1, -buffer_advanced1); + vlib_buffer_advance (b2, -buffer_advanced2); + vlib_buffer_advance (b3, -buffer_advanced3); + + b0->feature_arc_index = feature_arc_index; + b1->feature_arc_index = feature_arc_index; + b2->feature_arc_index = feature_arc_index; + b3->feature_arc_index = feature_arc_index; + + b0->current_config_index = + vec_elt (cm->config_index_by_sw_if_index, sw_if_index); + b1->current_config_index = b0->current_config_index; + b2->current_config_index = b0->current_config_index; + b3->current_config_index = b0->current_config_index; + + vnet_get_config_data (&cm->config_main, &b0->current_config_index, + next0, /* # bytes of config data */ 0); + vnet_get_config_data (&cm->config_main, &b1->current_config_index, + next1, /* # bytes of config data */ 0); + vnet_get_config_data (&cm->config_main, &b2->current_config_index, + next2, /* # bytes of config data */ 0); + vnet_get_config_data (&cm->config_main, &b3->current_config_index, + next3, /* # bytes of config data */ 0); + } +} + +#define VNET_FEATURES(...) (char*[]) { __VA_ARGS__, 0} + +clib_error_t *vnet_feature_arc_init (vlib_main_t * vm, + vnet_config_main_t * vcm, + char **feature_start_nodes, + int num_feature_start_nodes, + vnet_feature_registration_t * + first_reg, char ***feature_nodes); + +void vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index); + +#endif /* included_feature_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/feature/registration.c b/src/vnet/feature/registration.c new file mode 100644 index 00000000..1deeeef9 --- /dev/null +++ b/src/vnet/feature/registration.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2016 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 +#include +#include + +/** + * @file + * @brief Feature Subgraph Ordering. + + Dynamically compute feature subgraph ordering by performing a + topological sort across a set of "feature A before feature B" and + "feature C after feature B" constraints. + + Use the topological sort result to set up vnet_config_main_t's for + use at runtime. + + Feature subgraph arcs are simple enough. They start at specific + fixed nodes, and end at specific fixed nodes. In between, a + per-interface current feature configuration dictates which + additional nodes each packet visits. Each so-called feature node + can [of course] drop any specific packet. + + See ip4_forward.c, ip6_forward.c in this directory to see the + current rx-unicast, rx-multicast, and tx feature subgraph arc + definitions. + + Let's say that we wish to add a new feature to the ip4 unicast + feature subgraph arc, which needs to run before @c ip4-lookup. In + either base code or a plugin, +
+    \#include 
+    
+ + and add the new feature as shown: + +
+    VNET_FEATURE_INIT (ip4_lookup, static) =
+    {
+      .arch_name = "ip4-unicast",
+      .node_name = "my-ip4-unicast-feature",
+      .runs_before = VLIB_FEATURES ("ip4-lookup")
+    };
+    
+ + Here's the standard coding pattern to enable / disable + @c my-ip4-unicast-feature on an interface: + +
+
+    sw_if_index = 
+    vnet_feature_enable_disable ("ip4-unicast", "my-ip4-unicast-feature",
+                                 sw_if_index, 1 );
+    
+ + Here's how to obtain the correct next node index in packet + processing code, aka in the implementation of @c my-ip4-unicast-feature: + +
+    vnet_feature_next (sw_if_index0, &next0, b0);
+
+    
+ + Nodes are free to drop or otherwise redirect packets. Packets + which "pass" should be enqueued via the next0 arc computed by + vnet_feature_next. +*/ + + +static int +comma_split (u8 * s, u8 ** a, u8 ** b) +{ + *a = s; + + while (*s && *s != ',') + s++; + + if (*s == ',') + *s = 0; + else + return 1; + + *b = (u8 *) (s + 1); + return 0; +} + +/** + * @brief Initialize a feature graph arc + * @param vm vlib main structure pointer + * @param vcm vnet config main structure pointer + * @param feature_start_nodes names of start-nodes which use this + * feature graph arc + * @param num_feature_start_nodes number of start-nodes + * @param first_reg first element in + * [an __attribute__((constructor)) function built, or + * otherwise created] singly-linked list of feature registrations + * @param [out] in_feature_nodes returned vector of + * topologically-sorted feature node names, for use in + * show commands + * @returns 0 on success, otherwise an error message. Errors + * are fatal since they invariably involve mistyped node-names, or + * genuinely missing node-names + */ +clib_error_t * +vnet_feature_arc_init (vlib_main_t * vm, + vnet_config_main_t * vcm, + char **feature_start_nodes, + int num_feature_start_nodes, + vnet_feature_registration_t * first_reg, + char ***in_feature_nodes) +{ + uword *index_by_name; + uword *reg_by_index; + u8 **node_names = 0; + u8 *node_name; + char **these_constraints; + char *this_constraint_c; + u8 **constraints = 0; + u8 *constraint_tuple; + u8 *this_constraint; + u8 **orig, **closure; + uword *p; + int i, j, k; + u8 *a_name, *b_name; + int a_index, b_index; + int n_features; + u32 *result = 0; + vnet_feature_registration_t *this_reg = 0; + char **feature_nodes = 0; + hash_pair_t *hp; + u8 **keys_to_delete = 0; + + index_by_name = hash_create_string (0, sizeof (uword)); + reg_by_index = hash_create (0, sizeof (uword)); + + this_reg = first_reg; + + /* pass 1, collect feature node names, construct a before b pairs */ + while (this_reg) + { + node_name = format (0, "%s%c", this_reg->node_name, 0); + hash_set (reg_by_index, vec_len (node_names), (uword) this_reg); + + hash_set_mem (index_by_name, node_name, vec_len (node_names)); + + vec_add1 (node_names, node_name); + + these_constraints = this_reg->runs_before; + while (these_constraints && these_constraints[0]) + { + this_constraint_c = these_constraints[0]; + + constraint_tuple = format (0, "%s,%s%c", node_name, + this_constraint_c, 0); + vec_add1 (constraints, constraint_tuple); + these_constraints++; + } + + these_constraints = this_reg->runs_after; + while (these_constraints && these_constraints[0]) + { + this_constraint_c = these_constraints[0]; + + constraint_tuple = format (0, "%s,%s%c", + this_constraint_c, node_name, 0); + vec_add1 (constraints, constraint_tuple); + these_constraints++; + } + + this_reg = this_reg->next; + } + + n_features = vec_len (node_names); + orig = clib_ptclosure_alloc (n_features); + + for (i = 0; i < vec_len (constraints); i++) + { + this_constraint = constraints[i]; + + if (comma_split (this_constraint, &a_name, &b_name)) + return clib_error_return (0, "comma_split failed!"); + + p = hash_get_mem (index_by_name, a_name); + /* + * Note: the next two errors mean that something is + * b0rked. As in: if you code "A depends on B," and you forget + * to define a FEATURE_INIT macro for B, you lose. + * Nonexistent graph nodes are tolerated. + */ + if (p == 0) + return clib_error_return (0, "feature node '%s' not found", a_name); + a_index = p[0]; + + p = hash_get_mem (index_by_name, b_name); + if (p == 0) + return clib_error_return (0, "feature node '%s' not found", b_name); + b_index = p[0]; + + /* add a before b to the original set of constraints */ + orig[a_index][b_index] = 1; + vec_free (this_constraint); + } + + /* Compute the positive transitive closure of the original constraints */ + closure = clib_ptclosure (orig); + + /* Compute a partial order across feature nodes, if one exists. */ +again: + for (i = 0; i < n_features; i++) + { + for (j = 0; j < n_features; j++) + { + if (closure[i][j]) + goto item_constrained; + } + /* Item i can be output */ + vec_add1 (result, i); + { + for (k = 0; k < n_features; k++) + closure[k][i] = 0; + /* + * Add a "Magic" a before a constraint. + * This means we'll never output it again + */ + closure[i][i] = 1; + goto again; + } + item_constrained: + ; + } + + /* see if we got a partial order... */ + if (vec_len (result) != n_features) + return clib_error_return (0, "%d feature_init_cast no partial order!"); + + /* + * We win. + * Bind the index variables, and output the feature node name vector + * using the partial order we just computed. Result is in stack + * order, because the entry with the fewest constraints (e.g. none) + * is output first, etc. + */ + + for (i = n_features - 1; i >= 0; i--) + { + p = hash_get (reg_by_index, result[i]); + ASSERT (p != 0); + this_reg = (vnet_feature_registration_t *) p[0]; + if (this_reg->feature_index_ptr) + *this_reg->feature_index_ptr = n_features - (i + 1); + this_reg->feature_index = n_features - (i + 1); + vec_add1 (feature_nodes, this_reg->node_name); + } + + /* Set up the config infrastructure */ + vnet_config_init (vm, vcm, + feature_start_nodes, + num_feature_start_nodes, + feature_nodes, vec_len (feature_nodes)); + + /* Save a copy for show command */ + *in_feature_nodes = feature_nodes; + + /* Finally, clean up all the shit we allocated */ + /* *INDENT-OFF* */ + hash_foreach_pair (hp, index_by_name, + ({ + vec_add1 (keys_to_delete, (u8 *)hp->key); + })); + /* *INDENT-ON* */ + hash_free (index_by_name); + for (i = 0; i < vec_len (keys_to_delete); i++) + vec_free (keys_to_delete[i]); + vec_free (keys_to_delete); + hash_free (reg_by_index); + vec_free (result); + clib_ptclosure_free (orig); + clib_ptclosure_free (closure); + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 614c13161815c2de21c4679cb217da1ebc4fdb76 Mon Sep 17 00:00:00 2001 From: Billy McFall Date: Wed, 1 Mar 2017 17:01:06 -0500 Subject: VPP-648: CLI Memory leak with invalid parameter After VPP-635 was merged, did one more pass. While the code was waiting to be merged, a few changes were merged to master with the same issue. This is a few additional changes addressing the same issue. See VPP-635. Change-Id: I7abeac5c260c1e2e9d9d318fd1aae24cd6932efc Signed-off-by: Billy McFall --- src/vnet/feature/feature.c | 1 + src/vnet/lisp-cp/one_cli.c | 114 +++++++++++++++++++++++++++++++----------- src/vnet/lisp-gpe/interface.c | 2 +- 3 files changed, 88 insertions(+), 29 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index 032fe784..80ef08d0 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -434,6 +434,7 @@ set_interface_features_command_fn (vlib_main_t * vm, done: vec_free (feature_name); vec_free (arc_name); + unformat_free (line_input); return error; } diff --git a/src/vnet/lisp-cp/one_cli.c b/src/vnet/lisp-cp/one_cli.c index 07010707..05821306 100644 --- a/src/vnet/lisp-cp/one_cli.c +++ b/src/vnet/lisp-cp/one_cli.c @@ -38,9 +38,11 @@ lisp_show_adjacencies_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); + unformat_free (line_input); return 0; } } + unformat_free (line_input); if (~0 == vni) { @@ -94,9 +96,11 @@ lisp_add_del_map_server_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); + unformat_free (line_input); return 0; } } + unformat_free (line_input); if (!ip_set) { @@ -191,7 +195,7 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input, if (key && (0 == key_id)) { vlib_cli_output (vm, "invalid key_id!"); - return 0; + goto done; } gid_address_copy (&a->eid, &eid); @@ -213,6 +217,7 @@ done: vec_free (locator_set_name); gid_address_free (&a->eid); vec_free (a->key); + unformat_free (line_input); return error; } @@ -233,6 +238,7 @@ lisp_eid_table_map_command_fn (vlib_main_t * vm, u8 is_add = 1, is_l2 = 0; u32 vni = 0, dp_id = 0; unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -250,11 +256,16 @@ lisp_eid_table_map_command_fn (vlib_main_t * vm, is_l2 = 1; else { - return unformat_parse_error (line_input); + error = unformat_parse_error (line_input); + goto done; } } vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -482,7 +493,7 @@ lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input, != ip_prefix_version (leid_ippref))) { clib_warning ("remote and local EIDs are of different types!"); - return error; + goto done; } memset (a, 0, sizeof (a[0])); @@ -536,11 +547,14 @@ lisp_map_request_mode_command_fn (vlib_main_t * vm, if (_MR_MODE_MAX == mr_mode) { clib_warning ("No map request mode entered!"); - return 0; + goto done; } vnet_lisp_set_map_request_mode (mr_mode); + done: + unformat_free (i); + return 0; } @@ -633,7 +647,10 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, else if (unformat (line_input, "disable")) is_add = 0; else - return clib_error_return (0, "parse error"); + { + error = clib_error_return (0, "parse error"); + goto done; + } } if (!locator_name_set) @@ -651,6 +668,7 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, done: if (locator_set_name) vec_free (locator_set_name); + unformat_free (line_input); return error; } @@ -774,6 +792,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, gid_address_t eid; u8 print_all = 1; u8 filter = 0; + clib_error_t *error = NULL; memset (&eid, 0, sizeof (eid)); @@ -790,8 +809,11 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, else if (unformat (line_input, "remote")) filter = 2; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s", @@ -818,7 +840,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, { mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid); if ((u32) ~ 0 == mi) - return 0; + goto done; mapit = pool_elt_at_index (lcm->mapping_pool, mi); locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, @@ -827,14 +849,17 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, if (filter && !((1 == filter && ls->local) || (2 == filter && !ls->local))) { - return 0; + goto done; } vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main, lcm, mapit, ls); } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -853,6 +878,7 @@ lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -869,16 +895,24 @@ lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, is_set = 1; else { - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; } } if (!is_set) - return clib_error_return (0, "state not set"); + { + error = clib_error_return (0, "state not set"); + goto done; + } vnet_lisp_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -897,6 +931,7 @@ lisp_map_register_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -915,18 +950,22 @@ lisp_map_register_enable_disable_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (!is_set) { vlib_cli_output (vm, "state not set!"); - return 0; + goto done; } vnet_lisp_map_register_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -945,6 +984,7 @@ lisp_rloc_probe_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -963,18 +1003,22 @@ lisp_rloc_probe_enable_disable_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (!is_set) { vlib_cli_output (vm, "state not set!"); - return 0; + goto done; } vnet_lisp_rloc_probe_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1022,6 +1066,7 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); uword *vni_table = 0; u8 is_l2 = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1040,14 +1085,17 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, is_l2 = 0; } else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } if (!vni_table) { vlib_cli_output (vm, "Error: expected l2|l3 param!\n"); - return 0; + goto done; } vlib_cli_output (vm, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF"); @@ -1059,7 +1107,10 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, })); /* *INDENT-ON* */ - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1131,6 +1182,7 @@ done: vec_free (locators); if (locator_set_name) vec_free (locator_set_name); + unformat_free (line_input); return error; } @@ -1205,6 +1257,7 @@ lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, done: vec_free (locators); vec_free (locator_set_name); + unformat_free (line_input); return error; } @@ -1322,6 +1375,7 @@ lisp_add_del_map_resolver_command_fn (vlib_main_t * vm, } done: + unformat_free (line_input); return error; } @@ -1372,9 +1426,9 @@ lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm, is_add ? "add" : "delete"); } - vec_free (locator_set_name); - done: + vec_free (locator_set_name); + unformat_free (line_input); return error; } @@ -1438,7 +1492,10 @@ lisp_use_petr_set_locator_set_command_fn (vlib_main_t * vm, else if (unformat (line_input, "disable")) is_add = 0; else - return clib_error_return (0, "parse error"); + { + error = clib_error_return (0, "parse error"); + goto done; + } } if (!ip_set) @@ -1454,6 +1511,7 @@ lisp_use_petr_set_locator_set_command_fn (vlib_main_t * vm, } done: + unformat_free (line_input); return error; } diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 292c7e6a..cbd4d4cd 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -849,7 +849,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, { lisp_gpe_del_nsh_iface (&lisp_gpe_main); } - return (NULL); + goto done; } if (vrf_is_set && bd_index_is_set) -- cgit 1.2.3-korg From 35af9e50cdbfc73dab963557f4ffbd56b21e2abc Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 6 Mar 2017 12:02:50 +0100 Subject: features: take device-input buffer advance value directly Change-Id: Ifac7d9134d03d79164ce6f06ae9413279bbaadb3 Signed-off-by: Damjan Marion --- src/plugins/dpdk/device/node.c | 6 ++-- src/vnet/devices/af_packet/node.c | 3 +- src/vnet/devices/netmap/node.c | 2 +- src/vnet/devices/virtio/vhost-user.c | 2 +- src/vnet/feature/feature.h | 62 ++++++++++++++++++++---------------- src/vnet/unix/tapcli.c | 3 +- src/vnet/unix/tuntap.c | 2 +- 7 files changed, 42 insertions(+), 38 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/plugins/dpdk/device/node.c b/src/plugins/dpdk/device/node.c index 04c41655..ccbfd2f2 100644 --- a/src/plugins/dpdk/device/node.c +++ b/src/plugins/dpdk/device/node.c @@ -439,9 +439,7 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, /* Do we have any driver RX features configured on the interface? */ vnet_feature_start_device_input_x4 (xd->vlib_sw_if_index, &next0, &next1, &next2, &next3, - b0, b1, b2, b3, - l3_offset0, l3_offset1, - l3_offset2, l3_offset3); + b0, b1, b2, b3); vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next, n_left_to_next, @@ -502,7 +500,7 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, /* Do we have any driver RX features configured on the interface? */ vnet_feature_start_device_input_x1 (xd->vlib_sw_if_index, &next0, - b0, l3_offset0); + b0); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c index 69fc11c9..ab7fd800 100644 --- a/src/vnet/devices/af_packet/node.c +++ b/src/vnet/devices/af_packet/node.c @@ -216,8 +216,7 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, } /* redirect if feature path enabled */ - vnet_feature_start_device_input_x1 (apif->sw_if_index, &next0, b0, - 0); + vnet_feature_start_device_input_x1 (apif->sw_if_index, &next0, b0); /* enque and take next packet */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, diff --git a/src/vnet/devices/netmap/node.c b/src/vnet/devices/netmap/node.c index 835209a3..68ea7832 100644 --- a/src/vnet/devices/netmap/node.c +++ b/src/vnet/devices/netmap/node.c @@ -218,7 +218,7 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, /* redirect if feature path enabled */ vnet_feature_start_device_input_x1 (nif->sw_if_index, &next0, - first_b0, 0); + first_b0); /* enque and take next packet */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, diff --git a/src/vnet/devices/virtio/vhost-user.c b/src/vnet/devices/virtio/vhost-user.c index f490f0c1..c16e9822 100644 --- a/src/vnet/devices/virtio/vhost-user.c +++ b/src/vnet/devices/virtio/vhost-user.c @@ -1747,7 +1747,7 @@ vhost_user_if_input (vlib_main_t * vm, /* redirect if feature path enabled */ vnet_feature_start_device_input_x1 (vui->sw_if_index, &next0, - b_head, 0); + b_head); u32 bi = to_next[-1]; //Cannot use to_next[-1] in the macro vlib_validate_buffer_enqueue_x1 (vm, node, next_index, diff --git a/src/vnet/feature/feature.h b/src/vnet/feature/feature.h index b27aaf17..77b1499d 100644 --- a/src/vnet/feature/feature.h +++ b/src/vnet/feature/feature.h @@ -18,6 +18,7 @@ #include #include +#include /** feature registration object */ typedef struct _vnet_feature_arc_registration @@ -227,7 +228,7 @@ vnet_feature_next (u32 sw_if_index, u32 * next0, vlib_buffer_t * b0) static_always_inline void vnet_feature_start_device_input_x1 (u32 sw_if_index, u32 * next0, - vlib_buffer_t * b0, u16 buffer_advanced0) + vlib_buffer_t * b0) { vnet_feature_main_t *fm = &feature_main; vnet_feature_config_main_t *cm; @@ -242,9 +243,12 @@ vnet_feature_start_device_input_x1 (u32 sw_if_index, u32 * next0, * Save next0 so that the last feature in the chain * can skip ethernet-input if indicated... */ + u16 adv; + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; - vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; - vlib_buffer_advance (b0, -buffer_advanced0); + adv = device_input_next_node_advance[*next0]; + vnet_buffer (b0)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b0, -adv); b0->feature_arc_index = feature_arc_index; b0->current_config_index = @@ -258,10 +262,7 @@ static_always_inline void vnet_feature_start_device_input_x2 (u32 sw_if_index, u32 * next0, u32 * next1, - vlib_buffer_t * b0, - vlib_buffer_t * b1, - u16 buffer_advanced0, - u16 buffer_advanced1) + vlib_buffer_t * b0, vlib_buffer_t * b1) { vnet_feature_main_t *fm = &feature_main; vnet_feature_config_main_t *cm; @@ -276,12 +277,17 @@ vnet_feature_start_device_input_x2 (u32 sw_if_index, * Save next0 so that the last feature in the chain * can skip ethernet-input if indicated... */ + u16 adv; + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; + adv = device_input_next_node_advance[*next0]; + vnet_buffer (b0)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b0, -adv); + vnet_buffer (b1)->device_input_feat.saved_next_index = *next1; - vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; - vnet_buffer (b1)->device_input_feat.buffer_advance = buffer_advanced1; - vlib_buffer_advance (b0, -buffer_advanced0); - vlib_buffer_advance (b1, -buffer_advanced1); + adv = device_input_next_node_advance[*next1]; + vnet_buffer (b1)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b1, -adv); b0->feature_arc_index = feature_arc_index; b1->feature_arc_index = feature_arc_index; @@ -303,12 +309,7 @@ vnet_feature_start_device_input_x4 (u32 sw_if_index, u32 * next3, vlib_buffer_t * b0, vlib_buffer_t * b1, - vlib_buffer_t * b2, - vlib_buffer_t * b3, - u16 buffer_advanced0, - u16 buffer_advanced1, - u16 buffer_advanced2, - u16 buffer_advanced3) + vlib_buffer_t * b2, vlib_buffer_t * b3) { vnet_feature_main_t *fm = &feature_main; vnet_feature_config_main_t *cm; @@ -323,20 +324,27 @@ vnet_feature_start_device_input_x4 (u32 sw_if_index, * Save next0 so that the last feature in the chain * can skip ethernet-input if indicated... */ + u16 adv; + vnet_buffer (b0)->device_input_feat.saved_next_index = *next0; + adv = device_input_next_node_advance[*next0]; + vnet_buffer (b0)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b0, -adv); + vnet_buffer (b1)->device_input_feat.saved_next_index = *next1; - vnet_buffer (b2)->device_input_feat.saved_next_index = *next2; - vnet_buffer (b3)->device_input_feat.saved_next_index = *next3; + adv = device_input_next_node_advance[*next1]; + vnet_buffer (b1)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b1, -adv); - vnet_buffer (b0)->device_input_feat.buffer_advance = buffer_advanced0; - vnet_buffer (b1)->device_input_feat.buffer_advance = buffer_advanced1; - vnet_buffer (b2)->device_input_feat.buffer_advance = buffer_advanced2; - vnet_buffer (b3)->device_input_feat.buffer_advance = buffer_advanced3; + vnet_buffer (b2)->device_input_feat.saved_next_index = *next2; + adv = device_input_next_node_advance[*next2]; + vnet_buffer (b2)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b2, -adv); - vlib_buffer_advance (b0, -buffer_advanced0); - vlib_buffer_advance (b1, -buffer_advanced1); - vlib_buffer_advance (b2, -buffer_advanced2); - vlib_buffer_advance (b3, -buffer_advanced3); + vnet_buffer (b3)->device_input_feat.saved_next_index = *next3; + adv = device_input_next_node_advance[*next3]; + vnet_buffer (b3)->device_input_feat.buffer_advance = adv; + vlib_buffer_advance (b3, -adv); b0->feature_arc_index = feature_arc_index; b1->feature_arc_index = feature_arc_index; diff --git a/src/vnet/unix/tapcli.c b/src/vnet/unix/tapcli.c index 25c930c6..496f3885 100644 --- a/src/vnet/unix/tapcli.c +++ b/src/vnet/unix/tapcli.c @@ -355,8 +355,7 @@ static uword tapcli_rx_iface(vlib_main_t * vm, to_next++; n_left_to_next--; - vnet_feature_start_device_input_x1 (ti->sw_if_index, &next_index, - b_first, 0); + vnet_feature_start_device_input_x1 (ti->sw_if_index, &next_index, b_first); vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next, n_left_to_next, diff --git a/src/vnet/unix/tuntap.c b/src/vnet/unix/tuntap.c index 4a5dd676..2cfcc92f 100644 --- a/src/vnet/unix/tuntap.c +++ b/src/vnet/unix/tuntap.c @@ -351,7 +351,7 @@ tuntap_rx (vlib_main_t * vm, next_index = VNET_DEVICE_INPUT_NEXT_DROP; } - vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b, 0); + vnet_feature_start_device_input_x1 (tm->sw_if_index, &next_index, b); vlib_set_next_frame_buffer (vm, node, next_index, bi); -- cgit 1.2.3-korg From b069a6910aa2b95316ccdb5d9e5b95143b9dc7c0 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 15 Mar 2017 12:34:25 -0400 Subject: Cache a 'has-features' flag on the adjacency for faster access. Reclaim the node_index memeber from the rewrite for space - this is only used for formtting before: ip4-rewrite * * * * 2.66e1 256.00 after: ip4-rewrite * * * * 2.40e1 256.00 Change-Id: Ic397150727cad38811564777419ad6bd26b8a3a6 Signed-off-by: Neale Ranns --- src/vnet/adj/adj.c | 82 +++++++++++++++++++++++++++++++----- src/vnet/adj/adj.h | 6 +++ src/vnet/adj/adj_mcast.c | 4 +- src/vnet/adj/adj_midchain.c | 4 +- src/vnet/adj/adj_nbr.c | 4 +- src/vnet/feature/feature.c | 2 + src/vnet/ip/ip4_forward.c | 21 ++++++---- src/vnet/ip/ip6_forward.c | 21 ++++++---- src/vnet/ip/lookup.c | 8 ++-- src/vnet/mpls/mpls_output.c | 42 ++++++++++++------- src/vnet/rewrite.c | 100 +------------------------------------------- src/vnet/rewrite.h | 30 +++++++++---- 12 files changed, 162 insertions(+), 162 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c index 4ed4999f..f3d483ac 100644 --- a/src/vnet/adj/adj.c +++ b/src/vnet/adj/adj.c @@ -135,16 +135,6 @@ format_ip_adjacency (u8 * s, va_list * args) vlib_get_combined_counter(&adjacency_counters, adj_index, &counts); s = format (s, "\n counts:[%Ld:%Ld]", counts.packets, counts.bytes); s = format (s, "\n locks:%d", adj->ia_node.fn_locks); - s = format (s, " node:[%d]:%U", - adj->rewrite_header.node_index, - format_vlib_node_name, vlib_get_main(), - adj->rewrite_header.node_index); - s = format (s, " next:[%d]:%U", - adj->rewrite_header.next_index, - format_vlib_next_node_name, - vlib_get_main(), - adj->rewrite_header.node_index, - adj->rewrite_header.next_index); s = format(s, "\n children:\n "); s = fib_node_children_format(adj->ia_node.fn_children, s); } @@ -271,6 +261,78 @@ adj_child_remove (adj_index_t adj_index, sibling_index); } +/* + * Context for the walk to update the cached feture flags. + */ +typedef struct adj_feature_update_t_ +{ + u8 arc; + u8 enable; +} adj_feature_update_ctx_t; + +static adj_walk_rc_t +adj_feature_update_walk_cb (adj_index_t ai, + void *arg) +{ + adj_feature_update_ctx_t *ctx = arg; + ip_adjacency_t *adj; + + adj = adj_get(ai); + + /* + * this ugly mess matches the feature arc that is changing with affected + * adjacencies + */ + if (((ctx->arc == ip6_main.lookup_main.output_feature_arc_index) && + (VNET_LINK_IP6 == adj->ia_link)) || + ((ctx->arc == ip4_main.lookup_main.output_feature_arc_index) && + (VNET_LINK_IP4 == adj->ia_link)) || + ((ctx->arc == mpls_main.output_feature_arc_index) && + (VNET_LINK_MPLS == adj->ia_link))) + { + if (ctx->enable) + adj->rewrite_header.flags |= VNET_REWRITE_HAS_FEATURES; + else + adj->rewrite_header.flags &= ~VNET_REWRITE_HAS_FEATURES; + } + return (ADJ_WALK_RC_CONTINUE); +} + +void +adj_feature_update (u32 sw_if_index, + u8 arc_index, + u8 is_enable) +{ + /* + * Walk all the adjacencies on the interface to update the cached + * 'has-features' flag + */ + adj_feature_update_ctx_t ctx = { + .arc = arc_index, + .enable = is_enable, + }; + adj_walk (sw_if_index, adj_feature_update_walk_cb, &ctx); +} + +/** + * @brief Walk the Adjacencies on a given interface + */ +void +adj_walk (u32 sw_if_index, + adj_walk_cb_t cb, + void *ctx) +{ + /* + * walk all the neighbor adjacencies + */ + fib_protocol_t proto; + + FOR_EACH_FIB_IP_PROTOCOL(proto) + { + adj_nbr_walk(sw_if_index, proto, cb, ctx); + } +} + /** * @brief Return the link type of the adjacency */ diff --git a/src/vnet/adj/adj.h b/src/vnet/adj/adj.h index fcc5890c..271fdbc6 100644 --- a/src/vnet/adj/adj.h +++ b/src/vnet/adj/adj.h @@ -96,6 +96,12 @@ extern u32 adj_get_sw_if_index (adj_index_t ai); */ extern const u8* adj_get_rewrite (adj_index_t ai); +/** + * @brief Notify the adjacency subsystem that the features settings for + * an interface have changed + */ +extern void adj_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable); + /** * @brief * The global adjacnecy pool. Exposed for fast/inline data-plane access diff --git a/src/vnet/adj/adj_mcast.c b/src/vnet/adj/adj_mcast.c index 1345aedb..a3ba4d6a 100644 --- a/src/vnet/adj/adj_mcast.c +++ b/src/vnet/adj/adj_mcast.c @@ -256,15 +256,13 @@ format_adj_mcast (u8* s, va_list *ap) { index_t index = va_arg(*ap, index_t); CLIB_UNUSED(u32 indent) = va_arg(*ap, u32); - vnet_main_t * vnm = vnet_get_main(); ip_adjacency_t * adj = adj_get(index); s = format(s, "%U-mcast: ", format_fib_protocol, adj->ia_nh_proto); s = format (s, "%U", format_vnet_rewrite, - vnm->vlib_main, &adj->rewrite_header, - sizeof (adj->rewrite_data), 0); + &adj->rewrite_header, sizeof (adj->rewrite_data), 0); return (s); } diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index 7d315651..55b5e44b 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -501,7 +501,6 @@ format_adj_midchain (u8* s, va_list *ap) { index_t index = va_arg(*ap, index_t); u32 indent = va_arg(*ap, u32); - vnet_main_t * vnm = vnet_get_main(); ip_adjacency_t * adj = adj_get(index); s = format (s, "%U", format_vnet_link, adj->ia_link); @@ -509,8 +508,7 @@ format_adj_midchain (u8* s, va_list *ap) format_ip46_address, &adj->sub_type.nbr.next_hop); s = format (s, " %U", format_vnet_rewrite, - vnm->vlib_main, &adj->rewrite_header, - sizeof (adj->rewrite_data), indent); + &adj->rewrite_header, sizeof (adj->rewrite_data), indent); s = format (s, "\n%Ustacked-on:\n%U%U", format_white_space, indent, format_white_space, indent+2, diff --git a/src/vnet/adj/adj_nbr.c b/src/vnet/adj/adj_nbr.c index 9e8073d3..9ef3651d 100644 --- a/src/vnet/adj/adj_nbr.c +++ b/src/vnet/adj/adj_nbr.c @@ -433,7 +433,6 @@ adj_nbr_update_rewrite_internal (ip_adjacency_t *adj, vnet_rewrite_clear_data_internal(&adj->rewrite_header, sizeof(adj->rewrite_data)); } - adj->rewrite_header.node_index = this_node; adj->rewrite_header.next_index = vlib_node_add_next(vlib_get_main(), this_node, next_node); @@ -971,7 +970,6 @@ format_adj_nbr (u8* s, va_list *ap) { index_t index = va_arg(*ap, index_t); CLIB_UNUSED(u32 indent) = va_arg(*ap, u32); - vnet_main_t * vnm = vnet_get_main(); ip_adjacency_t * adj = adj_get(index); s = format (s, "%U", format_vnet_link, adj->ia_link); @@ -980,7 +978,7 @@ format_adj_nbr (u8* s, va_list *ap) adj_proto_to_46(adj->ia_nh_proto)); s = format (s, "%U", format_vnet_rewrite, - vnm->vlib_main, &adj->rewrite_header, sizeof (adj->rewrite_data), 0); + &adj->rewrite_header, sizeof (adj->rewrite_data), 0); return (s); } diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index 80ef08d0..5a4be029 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -14,6 +14,7 @@ */ #include +#include vnet_feature_main_t feature_main; @@ -229,6 +230,7 @@ vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index, 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)); + adj_feature_update (sw_if_index, arc_index, (feature_count > 0)); fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count; return 0; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 5472428f..34bc6c5d 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -1232,7 +1232,6 @@ format_ip4_rewrite_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ip4_forward_next_trace_t *t = va_arg (*args, ip4_forward_next_trace_t *); - vnet_main_t *vnm = vnet_get_main (); uword indent = format_get_indent (s); s = format (s, "tx_sw_if_index %d dpo-idx %d : %U flow hash: 0x%08x", @@ -1241,7 +1240,7 @@ format_ip4_rewrite_trace (u8 * s, va_list * args) s = format (s, "\n%U%U", format_white_space, indent, format_ip_adjacency_packet_data, - vnm, t->dpo_index, t->packet_data, sizeof (t->packet_data)); + t->dpo_index, t->packet_data, sizeof (t->packet_data)); return s; } @@ -2507,8 +2506,10 @@ ip4_rewrite_inline (vlib_main_t * vm, tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index; vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + if (PREDICT_FALSE + (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index0, &next0, p0); } if (PREDICT_TRUE (error1 == IP4_ERROR_NONE)) { @@ -2519,8 +2520,10 @@ ip4_rewrite_inline (vlib_main_t * vm, tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index; vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index1, &next1, p1); + if (PREDICT_FALSE + (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index1, &next1, p1); } /* Guess we are only writing on simple Ethernet header. */ @@ -2671,8 +2674,10 @@ ip4_rewrite_inline (vlib_main_t * vm, adj0->sub_type.midchain.fixup_func (vm, adj0, p0); } - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + if (PREDICT_FALSE + (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index0, &next0, p0); } diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index b80c757a..0b8691bf 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -961,7 +961,6 @@ format_ip6_rewrite_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *); - vnet_main_t *vnm = vnet_get_main (); uword indent = format_get_indent (s); s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x", @@ -970,7 +969,7 @@ format_ip6_rewrite_trace (u8 * s, va_list * args) s = format (s, "\n%U%U", format_white_space, indent, format_ip_adjacency_packet_data, - vnm, t->adj_index, t->packet_data, sizeof (t->packet_data)); + t->adj_index, t->packet_data, sizeof (t->packet_data)); return s; } @@ -2054,8 +2053,10 @@ ip6_rewrite_inline (vlib_main_t * vm, vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; next0 = adj0[0].rewrite_header.next_index; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + if (PREDICT_FALSE + (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index0, &next0, p0); } if (PREDICT_TRUE (error1 == IP6_ERROR_NONE)) { @@ -2066,8 +2067,10 @@ ip6_rewrite_inline (vlib_main_t * vm, vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1; next1 = adj1[0].rewrite_header.next_index; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index1, &next1, p1); + if (PREDICT_FALSE + (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index1, &next1, p1); } /* Guess we are only writing on simple Ethernet header. */ @@ -2182,8 +2185,10 @@ ip6_rewrite_inline (vlib_main_t * vm, vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0; next0 = adj0[0].rewrite_header.next_index; - vnet_feature_arc_start (lm->output_feature_arc_index, - tx_sw_if_index0, &next0, p0); + if (PREDICT_FALSE + (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (lm->output_feature_arc_index, + tx_sw_if_index0, &next0, p0); } if (is_midchain) diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index 9ae269cc..dabfa012 100644 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -291,7 +291,6 @@ format_ip_lookup_next (u8 * s, va_list * args) u8 * format_ip_adjacency_packet_data (u8 * s, va_list * args) { - vnet_main_t *vnm = va_arg (*args, vnet_main_t *); u32 adj_index = va_arg (*args, u32); u8 *packet_data = va_arg (*args, u8 *); u32 n_packet_data_bytes = va_arg (*args, u32); @@ -300,10 +299,9 @@ format_ip_adjacency_packet_data (u8 * s, va_list * args) switch (adj->lookup_next_index) { case IP_LOOKUP_NEXT_REWRITE: - s = format (s, "%U", - format_vnet_rewrite_header, - vnm->vlib_main, &adj->rewrite_header, packet_data, - n_packet_data_bytes); + case IP_LOOKUP_NEXT_MCAST: + s = + format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes); break; default: diff --git a/src/vnet/mpls/mpls_output.c b/src/vnet/mpls/mpls_output.c index c06cf917..cf354006 100644 --- a/src/vnet/mpls/mpls_output.c +++ b/src/vnet/mpls/mpls_output.c @@ -35,7 +35,6 @@ format_mpls_output_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *); - vnet_main_t * vnm = vnet_get_main(); uword indent = format_get_indent (s); s = format (s, "adj-idx %d : %U flow hash: 0x%08x", @@ -45,8 +44,7 @@ format_mpls_output_trace (u8 * s, va_list * args) s = format (s, "\n%U%U", format_white_space, indent, format_ip_adjacency_packet_data, - vnm, t->adj_index, - t->packet_data, sizeof (t->packet_data)); + t->adj_index, t->packet_data, sizeof (t->packet_data)); return s; } @@ -59,12 +57,14 @@ mpls_output_inline (vlib_main_t * vm, u32 n_left_from, next_index, * from, * to_next, cpu_index; vlib_node_runtime_t * error_node; u32 n_left_to_next; + mpls_main_t *mm; cpu_index = os_get_cpu_number(); error_node = vlib_node_get_runtime (vm, mpls_output_node.index); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; next_index = node->cached_next_index; + mm = &mpls_main; while (n_left_from > 0) { @@ -154,10 +154,10 @@ mpls_output_inline (vlib_main_t * vm, next0 = adj0[0].rewrite_header.next_index; error0 = IP4_ERROR_NONE; - if (is_midchain) - { - adj0->sub_type.midchain.fixup_func(vm, adj0, p0); - } + if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (mm->output_feature_arc_index, + adj0[0].rewrite_header.sw_if_index, + &next0, p0); } else { @@ -175,16 +175,21 @@ mpls_output_inline (vlib_main_t * vm, next1 = adj1[0].rewrite_header.next_index; error1 = IP4_ERROR_NONE; - if (is_midchain) - { - adj1->sub_type.midchain.fixup_func(vm, adj1, p1); - } + if (PREDICT_FALSE(adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (mm->output_feature_arc_index, + adj1[0].rewrite_header.sw_if_index, + &next1, p1); } else { error1 = IP4_ERROR_MTU_EXCEEDED; next1 = MPLS_OUTPUT_NEXT_DROP; } + if (is_midchain) + { + adj0->sub_type.midchain.fixup_func(vm, adj0, p0); + adj1->sub_type.midchain.fixup_func(vm, adj1, p1); + } p0->error = error_node->errors[error0]; p1->error = error_node->errors[error1]; @@ -254,17 +259,22 @@ mpls_output_inline (vlib_main_t * vm, next0 = adj0[0].rewrite_header.next_index; error0 = IP4_ERROR_NONE; - if (is_midchain) - { - adj0->sub_type.midchain.fixup_func(vm, adj0, p0); - } + if (PREDICT_FALSE(adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)) + vnet_feature_arc_start (mm->output_feature_arc_index, + adj0[0].rewrite_header.sw_if_index, + &next0, p0); } else { error0 = IP4_ERROR_MTU_EXCEEDED; next0 = MPLS_OUTPUT_NEXT_DROP; } - p0->error = error_node->errors[error0]; + if (is_midchain) + { + adj0->sub_type.midchain.fixup_func(vm, adj0, p0); + } + + p0->error = error_node->errors[error0]; from += 1; n_left_from -= 1; diff --git a/src/vnet/rewrite.c b/src/vnet/rewrite.c index 8925ad61..c4a171c1 100644 --- a/src/vnet/rewrite.c +++ b/src/vnet/rewrite.c @@ -67,14 +67,10 @@ vnet_rewrite_copy_slow_path (vnet_rewrite_data_t * p0, u8 * format_vnet_rewrite (u8 * s, va_list * args) { - vlib_main_t *vm = va_arg (*args, vlib_main_t *); vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *); u32 max_data_bytes = va_arg (*args, u32); CLIB_UNUSED (uword indent) = va_arg (*args, u32); vnet_main_t *vnm = vnet_get_main (); - vlib_node_t *next; - - next = vlib_get_next_node (vm, rw->node_index, rw->next_index); if (rw->sw_if_index != ~0) { @@ -85,108 +81,17 @@ format_vnet_rewrite (u8 * s, va_list * args) else s = format (s, "DELETED"); } - else - s = format (s, "%v: ", next->name); /* Format rewrite string. */ if (rw->data_bytes > 0) s = format (s, "%U", - next->format_buffer ? next->format_buffer : format_hex_bytes, + format_hex_bytes, rw->data + max_data_bytes - rw->data_bytes, rw->data_bytes); return s; } -u8 * -format_vnet_rewrite_header (u8 * s, va_list * args) -{ - vlib_main_t *vm = va_arg (*args, vlib_main_t *); - vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *); - u8 *packet_data = va_arg (*args, u8 *); - u32 packet_data_bytes = va_arg (*args, u32); - vlib_node_t *next; - - next = vlib_get_next_node (vm, rw->node_index, rw->next_index); - - /* Format rewrite string. */ - s = format (s, "%U", - next->format_buffer ? next->format_buffer : format_hex_bytes, - packet_data, packet_data_bytes); - - return s; -} - -uword -unformat_vnet_rewrite (unformat_input_t * input, va_list * args) -{ - vlib_main_t *vm = va_arg (*args, vlib_main_t *); - vnet_rewrite_header_t *rw = va_arg (*args, vnet_rewrite_header_t *); - u32 max_data_bytes = va_arg (*args, u32); - vnet_main_t *vnm = vnet_get_main (); - vlib_node_t *next; - u32 next_index, sw_if_index, max_packet_bytes, error; - u8 *rw_data; - - rw_data = 0; - sw_if_index = ~0; - max_packet_bytes = ~0; - error = 1; - - /* Parse sw interface. */ - if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) - { - vnet_hw_interface_t *hi; - - hi = vnet_get_sup_hw_interface (vnm, sw_if_index); - - next_index = hi->output_node_index; - max_packet_bytes = hi->max_l3_packet_bytes[VLIB_RX]; - } - - else if (unformat (input, "%U", unformat_vlib_node, vm, &next_index)) - ; - - else - goto done; - - next = vlib_get_node (vm, next_index); - - if (next->unformat_buffer - && unformat_user (input, next->unformat_buffer, &rw_data)) - ; - - else if (unformat_user (input, unformat_hex_string, &rw_data) - || unformat (input, "0x%U", unformat_hex_string, &rw_data)) - ; - - else - goto done; - - /* Re-write does not fit. */ - if (vec_len (rw_data) >= max_data_bytes) - goto done; - - { - u32 tmp; - - if (unformat (input, "mtu %d", &tmp) - && tmp < (1 << BITS (rw->max_l3_packet_bytes))) - max_packet_bytes = tmp; - } - - error = 0; - rw->sw_if_index = sw_if_index; - rw->max_l3_packet_bytes = max_packet_bytes; - rw->next_index = vlib_node_add_next (vm, rw->node_index, next_index); - vnet_rewrite_set_data_internal (rw, max_data_bytes, rw_data, - vec_len (rw_data)); - -done: - vec_free (rw_data); - return error == 0; -} - u32 vnet_tx_node_index_for_sw_interface (vnet_main_t * vnm, u32 sw_if_index) { @@ -200,7 +105,6 @@ vnet_rewrite_init (vnet_main_t * vnm, u32 this_node, u32 next_node, vnet_rewrite_header_t * rw) { rw->sw_if_index = sw_if_index; - rw->node_index = this_node; rw->next_index = vlib_node_add_next (vnm->vlib_main, this_node, next_node); rw->max_l3_packet_bytes = vnet_sw_interface_get_mtu (vnm, sw_if_index, VLIB_TX); @@ -249,7 +153,6 @@ vnet_rewrite_for_tunnel (vnet_main_t * vnm, * ipX-forward, this will be interpreted as a FIB number. */ rw->sw_if_index = tx_sw_if_index; - rw->node_index = rewrite_node_index; rw->next_index = vlib_node_add_next (vnm->vlib_main, rewrite_node_index, post_rewrite_node_index); rw->max_l3_packet_bytes = (u16) ~ 0; /* we can't know at this point */ @@ -284,7 +187,6 @@ unserialize_vnet_rewrite (serialize_main_t * m, va_list * va) u8 *p; /* It is up to user to fill these in. */ - rw->node_index = ~0; rw->next_index = ~0; unserialize_integer (m, &rw->sw_if_index, sizeof (rw->sw_if_index)); diff --git a/src/vnet/rewrite.h b/src/vnet/rewrite.h index ce2bce3a..8435a726 100644 --- a/src/vnet/rewrite.h +++ b/src/vnet/rewrite.h @@ -46,14 +46,22 @@ /* Consider using vector types for speed? */ typedef uword vnet_rewrite_data_t; +/** + * Flags associated with the rewrite/adjacency + */ +typedef enum vnet_rewrite_flags_t_ +{ + /** + * This adjacency/interface has output features configured + */ + VNET_REWRITE_HAS_FEATURES = (1 << 0), +} __attribute__ ((packed)) vnet_rewrite_flags_t; + /* *INDENT-OFF* */ typedef CLIB_PACKED (struct { /* Interface to mark re-written packets with. */ u32 sw_if_index; - /* Packet processing node where rewrite happens. */ - u32 node_index; - /* Next node to feed after packet rewrite is done. */ u16 next_index; @@ -64,6 +72,11 @@ typedef CLIB_PACKED (struct { Used for MTU check after packet rewrite. */ u16 max_l3_packet_bytes; + u16 unused1; + u8 unused2; + + vnet_rewrite_flags_t flags; + /* When dynamically writing a multicast destination L2 addresss * this is the offset within the address to start writing n * bytes of the IP mcast address */ @@ -79,6 +92,13 @@ typedef CLIB_PACKED (struct { }) vnet_rewrite_header_t; /* *INDENT-ON* */ +/** + * At 16 bytes of rewrite herader we have enought space left for a IPv6 + * (40 bytes) + LISP-GPE (8 bytes) in the cache line + */ +STATIC_ASSERT (sizeof (vnet_rewrite_header_t) <= 16, + "Rewrite header too big"); + /* Helper macro for declaring rewrite string w/ given max-size. @@ -317,11 +337,7 @@ u8 *vnet_build_rewrite_for_sw_interface (struct vnet_main_t *vnm, void vnet_update_adjacency_for_sw_interface (struct vnet_main_t *vnm, u32 sw_if_index, u32 ai); -/* Parser for unformat header & rewrite string. */ -unformat_function_t unformat_vnet_rewrite; - format_function_t format_vnet_rewrite; -format_function_t format_vnet_rewrite_header; serialize_function_t serialize_vnet_rewrite, unserialize_vnet_rewrite; -- cgit 1.2.3-korg From 180279b912827c30494ec1b90ee4325a15cb337c Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 16 Mar 2017 15:49:09 -0400 Subject: Fix IP feature ordering. Drop comes before lookup when enabled. is_first_or_last is not required when setting a feature, the anchor is added in find_config_with_features(). Don't make the PG interfaces automatically L3 enabled, this way we can have tests that check the L3 protocol disbaled behaviour. Change-Id: Icef22a920b27ff9cec6ab2da6b05f05c532cb60f Signed-off-by: Neale Ranns --- src/vnet/devices/devices.c | 1 - src/vnet/feature/feature.c | 15 ------- src/vnet/feature/feature.h | 3 -- src/vnet/interface_output.c | 1 - src/vnet/ip/ip4_forward.c | 29 ++++++------- src/vnet/pg/stream.c | 4 -- test/test_ip4.py | 99 ++++++++++++++++++++++++++++++++++++++++++- test/test_ip6.py | 100 +++++++++++++++++++++++++++++++++++++++++++- test/test_ip_mcast.py | 20 +-------- test/test_mpls.py | 83 ++++++++++++++++++++++++++++++++++++ test/vpp_interface.py | 5 +++ test/vpp_ip_route.py | 17 ++++++++ 12 files changed, 316 insertions(+), 61 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index c81043c6..38f3002b 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -55,7 +55,6 @@ VNET_FEATURE_ARC_INIT (device_input, static) = { .arc_name = "device-input", .start_nodes = VNET_FEATURES ("device-input"), - .end_node = "ethernet-input", .arc_index_ptr = &feature_main.device_input_feature_arc_index, }; diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index 5a4be029..f0e9004c 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -109,9 +109,6 @@ vnet_feature_init (vlib_main_t * vm) freg = freg->next; } - cm->end_feature_index = - vnet_get_feature_index (arc_index, areg->end_node); - /* next */ areg = areg->next; arc_index++; @@ -185,7 +182,6 @@ vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index, vnet_feature_main_t *fm = &feature_main; vnet_feature_config_main_t *cm; i16 feature_count; - int is_first_or_last; u32 ci; if (arc_index == (u8) ~ 0) @@ -214,19 +210,8 @@ vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index, /* 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)); diff --git a/src/vnet/feature/feature.h b/src/vnet/feature/feature.h index 77b1499d..7ec43ea8 100644 --- a/src/vnet/feature/feature.h +++ b/src/vnet/feature/feature.h @@ -30,8 +30,6 @@ typedef struct _vnet_feature_arc_registration /** Start nodes */ char **start_nodes; int n_start_nodes; - /** End node */ - char *end_node; /* Feature arc index, assigned by init function */ u8 feature_arc_index; u8 *arc_index_ptr; @@ -66,7 +64,6 @@ typedef struct vnet_feature_config_main_t_ { vnet_config_main_t config_main; u32 *config_index_by_sw_if_index; - u32 end_feature_index; } vnet_feature_config_main_t; typedef struct diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c index abac50b6..03f2cdca 100644 --- a/src/vnet/interface_output.c +++ b/src/vnet/interface_output.c @@ -1258,7 +1258,6 @@ VNET_FEATURE_ARC_INIT (interface_output, static) = { .arc_name = "interface-output", .start_nodes = VNET_FEATURES (0), - .end_node = "interface-tx", .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index, }; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 34bc6c5d..0dad61d4 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -847,9 +847,8 @@ ip4_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable) !is_enable, 0, 0); - vnet_feature_enable_disable ("ip4-multicast", - "ip4-mfib-forward-lookup", - sw_if_index, is_enable, 0, 0); + vnet_feature_enable_disable ("ip4-multicast", "ip4-drop", + sw_if_index, !is_enable, 0, 0); } static clib_error_t * @@ -954,7 +953,6 @@ VNET_FEATURE_ARC_INIT (ip4_unicast, static) = { .arc_name = "ip4-unicast", .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"), - .end_node = "ip4-lookup", .arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index, }; @@ -1021,27 +1019,25 @@ VNET_FEATURE_INIT (ip4_vxlan_bypass, static) = .runs_before = VNET_FEATURES ("ip4-lookup"), }; -VNET_FEATURE_INIT (ip4_lookup, static) = +VNET_FEATURE_INIT (ip4_drop, static) = { .arc_name = "ip4-unicast", - .node_name = "ip4-lookup", - .runs_before = VNET_FEATURES ("ip4-drop"), + .node_name = "ip4-drop", + .runs_before = VNET_FEATURES ("ip4-lookup"), }; -VNET_FEATURE_INIT (ip4_drop, static) = +VNET_FEATURE_INIT (ip4_lookup, static) = { .arc_name = "ip4-unicast", - .node_name = "ip4-drop", + .node_name = "ip4-lookup", .runs_before = 0, /* not before any other features */ }; - /* Built-in ip4 multicast rx feature path definition */ VNET_FEATURE_ARC_INIT (ip4_multicast, static) = { .arc_name = "ip4-multicast", .start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"), - .end_node = "ip4-lookup-multicast", .arc_index_ptr = &ip4_main.lookup_main.mcast_feature_arc_index, }; @@ -1052,17 +1048,17 @@ VNET_FEATURE_INIT (ip4_vpath_mc, static) = .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"), }; -VNET_FEATURE_INIT (ip4_lookup_mc, static) = +VNET_FEATURE_INIT (ip4_mc_drop, static) = { .arc_name = "ip4-multicast", - .node_name = "ip4-mfib-forward-lookup", - .runs_before = VNET_FEATURES ("ip4-drop"), + .node_name = "ip4-drop", + .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"), }; -VNET_FEATURE_INIT (ip4_mc_drop, static) = +VNET_FEATURE_INIT (ip4_lookup_mc, static) = { .arc_name = "ip4-multicast", - .node_name = "ip4-drop", + .node_name = "ip4-mfib-forward-lookup", .runs_before = 0, /* last feature */ }; @@ -1071,7 +1067,6 @@ VNET_FEATURE_ARC_INIT (ip4_output, static) = { .arc_name = "ip4-output", .start_nodes = VNET_FEATURES ("ip4-rewrite", "ip4-midchain"), - .end_node = "interface-output", .arc_index_ptr = &ip4_main.lookup_main.output_feature_arc_index, }; diff --git a/src/vnet/pg/stream.c b/src/vnet/pg/stream.c index 560c4b07..05d820a3 100644 --- a/src/vnet/pg/stream.c +++ b/src/vnet/pg/stream.c @@ -223,10 +223,6 @@ pg_interface_add_or_get (pg_main_t * pg, uword if_id) CLIB_CACHE_LINE_BYTES); *pi->lockp = 0; } - - ip4_sw_interface_enable_disable (pi->hw_if_index, 1); - ip6_sw_interface_enable_disable (pi->hw_if_index, 1); - mpls_sw_interface_enable_disable (&mpls_main, pi->hw_if_index, 1); } return i; diff --git a/test/test_ip4.py b/test/test_ip4.py index 7f6e92fa..79af5492 100644 --- a/test/test_ip4.py +++ b/test/test_ip4.py @@ -5,7 +5,8 @@ import unittest from framework import VppTestCase, VppTestRunner from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint -from vpp_ip_route import VppIpRoute, VppRoutePath +from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \ + VppMRoutePath, MRouteItfFlags, MRouteEntryFlags from scapy.packet import Raw from scapy.layers.l2 import Ether, Dot1Q @@ -546,5 +547,101 @@ class TestIPNull(VppTestCase): self.assertEqual(icmp.dst, "10.0.0.2") +class TestIPDisabled(VppTestCase): + """ IPv4 disabled """ + + def setUp(self): + super(TestIPDisabled, self).setUp() + + # create 2 pg interfaces + self.create_pg_interfaces(range(2)) + + # PG0 is IP enalbed + self.pg0.admin_up() + self.pg0.config_ip4() + self.pg0.resolve_arp() + + # PG 1 is not IP enabled + self.pg1.admin_up() + + def tearDown(self): + super(TestIPDisabled, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip4() + i.admin_down() + + def send_and_assert_no_replies(self, intf, pkts, remark): + intf.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + for i in self.pg_interfaces: + i.get_capture(0) + i.assert_nothing_captured(remark=remark) + + def test_ip_disabled(self): + """ IP Disabled """ + + # + # An (S,G). + # one accepting interface, pg0, 2 forwarding interfaces + # + route_232_1_1_1 = VppIpMRoute( + self, + "0.0.0.0", + "232.1.1.1", 32, + MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, + [VppMRoutePath(self.pg1.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), + VppMRoutePath(self.pg0.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)]) + route_232_1_1_1.add_vpp_config() + + pu = (Ether(src=self.pg1.remote_mac, + dst=self.pg1.local_mac) / + IP(src="10.10.10.10", dst=self.pg0.remote_ip4) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + pm = (Ether(src=self.pg1.remote_mac, + dst=self.pg1.local_mac) / + IP(src="10.10.10.10", dst="232.1.1.1") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, pu, "IP disabled") + self.send_and_assert_no_replies(self.pg1, pm, "IP disabled") + + # + # IP enable PG1 + # + self.pg1.config_ip4() + + # + # Now we get packets through + # + self.pg1.add_stream(pu) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg0.get_capture(1) + + self.pg1.add_stream(pm) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg0.get_capture(1) + + # + # Disable PG1 + # + self.pg1.unconfig_ip4() + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, pu, "IP disabled") + self.send_and_assert_no_replies(self.pg1, pm, "IP disabled") + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/test_ip6.py b/test/test_ip6.py index e57e034d..a8e8d4de 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -6,7 +6,8 @@ from socket import AF_INET6 from framework import VppTestCase, VppTestRunner from vpp_sub_interface import VppSubInterface, VppDot1QSubint from vpp_pg_interface import is_ipv6_misc -from vpp_ip_route import VppIpRoute, VppRoutePath, find_route +from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \ + VppMRoutePath, MRouteItfFlags, MRouteEntryFlags from vpp_neighbor import find_nbr, VppNeighbor from scapy.packet import Raw @@ -981,5 +982,102 @@ class TestIPNull(VppTestCase): self.assertEqual(icmp.code, 1) +class TestIPDisabled(VppTestCase): + """ IPv6 disabled """ + + def setUp(self): + super(TestIPDisabled, self).setUp() + + # create 2 pg interfaces + self.create_pg_interfaces(range(2)) + + # PG0 is IP enalbed + self.pg0.admin_up() + self.pg0.config_ip6() + self.pg0.resolve_ndp() + + # PG 1 is not IP enabled + self.pg1.admin_up() + + def tearDown(self): + super(TestIPDisabled, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip4() + i.admin_down() + + def send_and_assert_no_replies(self, intf, pkts, remark): + intf.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + for i in self.pg_interfaces: + i.get_capture(0) + i.assert_nothing_captured(remark=remark) + + def test_ip_disabled(self): + """ IP Disabled """ + + # + # An (S,G). + # one accepting interface, pg0, 2 forwarding interfaces + # + route_ff_01 = VppIpMRoute( + self, + "::", + "ffef::1", 128, + MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE, + [VppMRoutePath(self.pg1.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), + VppMRoutePath(self.pg0.sw_if_index, + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)], + is_ip6=1) + route_ff_01.add_vpp_config() + + pu = (Ether(src=self.pg1.remote_mac, + dst=self.pg1.local_mac) / + IPv6(src="2001::1", dst=self.pg0.remote_ip6) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + pm = (Ether(src=self.pg1.remote_mac, + dst=self.pg1.local_mac) / + IPv6(src="2001::1", dst="ffef::1") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled") + self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled") + + # + # IP enable PG1 + # + self.pg1.config_ip6() + + # + # Now we get packets through + # + self.pg1.add_stream(pu) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg0.get_capture(1) + + self.pg1.add_stream(pm) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + rx = self.pg0.get_capture(1) + + # + # Disable PG1 + # + self.pg1.unconfig_ip6() + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled") + self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled") + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/test_ip_mcast.py b/test/test_ip_mcast.py index 864cb803..094942b3 100644 --- a/test/test_ip_mcast.py +++ b/test/test_ip_mcast.py @@ -4,7 +4,8 @@ import unittest from framework import VppTestCase, VppTestRunner from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint -from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal +from vpp_ip_route import VppIpMRoute, VppMRoutePath, VppMFibSignal, \ + MRouteItfFlags, MRouteEntryFlags from scapy.packet import Raw from scapy.layers.l2 import Ether @@ -12,23 +13,6 @@ from scapy.layers.inet import IP, UDP, getmacbyip, ICMP from scapy.layers.inet6 import IPv6, getmacbyip6 from util import ppp - -class MRouteItfFlags: - MFIB_ITF_FLAG_NONE = 0 - MFIB_ITF_FLAG_NEGATE_SIGNAL = 1 - MFIB_ITF_FLAG_ACCEPT = 2 - MFIB_ITF_FLAG_FORWARD = 4 - MFIB_ITF_FLAG_SIGNAL_PRESENT = 8 - MFIB_ITF_FLAG_INTERNAL_COPY = 16 - - -class MRouteEntryFlags: - MFIB_ENTRY_FLAG_NONE = 0 - MFIB_ENTRY_FLAG_SIGNAL = 1 - MFIB_ENTRY_FLAG_DROP = 2 - MFIB_ENTRY_FLAG_CONNECTED = 4 - MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8 - # # The number of packets sent is set to 90 so that when we replicate more than 3 # times, which we do for some entries, we will generate more than 256 packets diff --git a/test/test_mpls.py b/test/test_mpls.py index 9082637b..fc832644 100644 --- a/test/test_mpls.py +++ b/test/test_mpls.py @@ -738,5 +738,88 @@ class TestMPLS(VppTestCase): route_35_eos.remove_vpp_config() route_34_eos.remove_vpp_config() + +class TestMPLSDisabled(VppTestCase): + """ MPLS disabled """ + + def setUp(self): + super(TestMPLSDisabled, self).setUp() + + # create 2 pg interfaces + self.create_pg_interfaces(range(2)) + + # PG0 is MPLS enalbed + self.pg0.admin_up() + self.pg0.config_ip4() + self.pg0.resolve_arp() + self.pg0.enable_mpls() + + # PG 1 is not MPLS enabled + self.pg1.admin_up() + + def tearDown(self): + super(TestMPLSDisabled, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip4() + i.admin_down() + + def send_and_assert_no_replies(self, intf, pkts, remark): + intf.add_stream(pkts) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + for i in self.pg_interfaces: + i.get_capture(0) + i.assert_nothing_captured(remark=remark) + + def test_mpls_disabled(self): + """ MPLS Disabled """ + + tx = (Ether(src=self.pg1.remote_mac, + dst=self.pg1.local_mac) / + MPLS(label=32, ttl=64) / + IPv6(src="2001::1", dst=self.pg0.remote_ip6) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + # + # A simple MPLS xconnect - eos label in label out + # + route_32_eos = VppMplsRoute(self, 32, 1, + [VppRoutePath(self.pg0.remote_ip4, + self.pg0.sw_if_index, + labels=[33])]) + route_32_eos.add_vpp_config() + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, tx, "MPLS disabled") + + # + # MPLS enable PG1 + # + self.pg1.enable_mpls() + + # + # Now we get packets through + # + self.pg1.add_stream(tx) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + + # + # Disable PG1 + # + self.pg1.disable_mpls() + + # + # PG1 does not forward IP traffic + # + self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled") + self.send_and_assert_no_replies(self.pg1, tx, "IPv6 disabled") + + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_interface.py b/test/vpp_interface.py index aeaf27a8..5dba0978 100644 --- a/test/vpp_interface.py +++ b/test/vpp_interface.py @@ -321,6 +321,11 @@ class VppInterface(object): self.test.vapi.sw_interface_enable_disable_mpls( self.sw_if_index) + def disable_mpls(self): + """Enable MPLS on the VPP interface.""" + self.test.vapi.sw_interface_enable_disable_mpls( + self.sw_if_index, 0) + def is_ip4_entry_in_fib_dump(self, dump): for i in dump: if i.address == self.local_ip4n and \ diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index e1c2b4b4..faf5f801 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -12,6 +12,23 @@ MPLS_IETF_MAX_LABEL = 0xfffff MPLS_LABEL_INVALID = MPLS_IETF_MAX_LABEL + 1 +class MRouteItfFlags: + MFIB_ITF_FLAG_NONE = 0 + MFIB_ITF_FLAG_NEGATE_SIGNAL = 1 + MFIB_ITF_FLAG_ACCEPT = 2 + MFIB_ITF_FLAG_FORWARD = 4 + MFIB_ITF_FLAG_SIGNAL_PRESENT = 8 + MFIB_ITF_FLAG_INTERNAL_COPY = 16 + + +class MRouteEntryFlags: + MFIB_ENTRY_FLAG_NONE = 0 + MFIB_ENTRY_FLAG_SIGNAL = 1 + MFIB_ENTRY_FLAG_DROP = 2 + MFIB_ENTRY_FLAG_CONNECTED = 4 + MFIB_ENTRY_FLAG_INHERIT_ACCEPT = 8 + + def find_route(test, ip_addr, len, table_id=0, inet=AF_INET): if inet == AF_INET: s = 4 -- cgit 1.2.3-korg From 3d2a914762af9f9b608480c5ecf5b50e7ab36d5c Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Wed, 16 Aug 2017 21:23:44 -0700 Subject: feature: exit on misconfigured features (VPP-915) Change-Id: Ifa11f356d727b69cb121a2bf4cfb9d87883f545d Signed-off-by: Florin Coras --- src/vnet/feature/feature.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index f0e9004c..ad4047e6 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -65,8 +65,11 @@ vnet_feature_init (vlib_main_t * vm) 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'", - freg->arc_name); + { + /* Don't start vpp with broken features arcs */ + clib_warning ("Unknown feature arc '%s'", freg->arc_name); + os_exit (1); + } areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *); arc_index = areg->feature_arc_index; @@ -95,7 +98,8 @@ vnet_feature_init (vlib_main_t * vm) fm->next_feature_by_arc[arc_index], &fm->feature_nodes[arc_index]))) { - return error; + clib_error_report (error); + os_exit (1); } fm->next_feature_by_name[arc_index] = -- cgit 1.2.3-korg From 1bfd37295f5cd332b7326923f1fbd5e0415829cd Mon Sep 17 00:00:00 2001 From: Pierre Pfister Date: Mon, 18 Sep 2017 11:40:32 +0200 Subject: Add ip6-local feature arc ip4-local feature arc existed but not ip6-local one. This patch also adds node name to the 'show ip local' command and fixes a minor include issue in vnet/ip/ip4.h file. Change-Id: I9bb8a7159917d58f89afcce974680de20d946a70 Signed-off-by: Pierre Pfister --- src/vnet/feature/feature.c | 3 +- src/vnet/ip/ip4.h | 1 + src/vnet/ip/ip4_forward.c | 8 +++- src/vnet/ip/ip6_forward.c | 97 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 101 insertions(+), 8 deletions(-) (limited to 'src/vnet/feature') diff --git a/src/vnet/feature/feature.c b/src/vnet/feature/feature.c index ad4047e6..6756d0d4 100644 --- a/src/vnet/feature/feature.c +++ b/src/vnet/feature/feature.c @@ -441,7 +441,8 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_interface_feature_command, static) = { .path = "set interface feature", - .short_help = "set interface feature arc ", + .short_help = "set interface feature arc " + "[disable]", .function = set_interface_features_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/ip/ip4.h b/src/vnet/ip/ip4.h index decb840b..af0e6b9a 100644 --- a/src/vnet/ip/ip4.h +++ b/src/vnet/ip/ip4.h @@ -44,6 +44,7 @@ #include #include #include +#include typedef struct ip4_mfib_t { diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index c526003c..0a34497d 100755 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -1922,7 +1922,13 @@ show_ip_local_command_fn (vlib_main_t * vm, for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++) { if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT) - vlib_cli_output (vm, "%d", i); + { + u32 node_index = vlib_get_node (vm, + ip4_local_node.index)-> + next_nodes[lm->local_next_by_ip_protocol[i]]; + vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm, + node_index); + } } return 0; } diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 1002f6b6..bb4893ad 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1337,8 +1337,17 @@ ip6_next_proto_is_tcp_udp (vlib_buffer_t * p0, ip6_header_t * ip0, return proto0; } +/* *INDENT-OFF* */ +VNET_FEATURE_ARC_INIT (ip6_local) = +{ + .arc_name = "ip6-local", + .start_nodes = VNET_FEATURES ("ip6-local"), +}; +/* *INDENT-ON* */ + static uword -ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +ip6_local_inline (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame, int head_of_feature_arc) { ip6_main_t *im = &ip6_main; ip_lookup_main_t *lm = &im->lookup_main; @@ -1346,6 +1355,7 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) u32 *from, *to_next, n_left_from, n_left_to_next; vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, ip6_input_node.index); + u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -1377,21 +1387,23 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) to_next += 2; n_left_to_next -= 2; + error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL; + p0 = vlib_get_buffer (vm, pi0); p1 = vlib_get_buffer (vm, pi1); ip0 = vlib_buffer_get_current (p0); ip1 = vlib_buffer_get_current (p1); + if (head_of_feature_arc == 0) + goto skip_checks; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; vnet_buffer (p1)->l3_hdr_offset = p1->current_data; type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol]; type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol]; - next0 = lm->local_next_by_ip_protocol[ip0->protocol]; - next1 = lm->local_next_by_ip_protocol[ip1->protocol]; - flags0 = p0->flags; flags1 = p1->flags; @@ -1485,6 +1497,11 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ? IP6_ERROR_SRC_LOOKUP_MISS : error1); } + skip_checks: + + next0 = lm->local_next_by_ip_protocol[ip0->protocol]; + next1 = lm->local_next_by_ip_protocol[ip1->protocol]; + next0 = error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0; next1 = @@ -1493,6 +1510,18 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) p0->error = error_node->errors[error0]; p1->error = error_node->errors[error1]; + if (head_of_feature_arc) + { + if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL)) + vnet_feature_arc_start (arc_index, + vnet_buffer (p0)->sw_if_index + [VLIB_RX], &next0, p0); + if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL)) + vnet_feature_arc_start (arc_index, + vnet_buffer (p1)->sw_if_index + [VLIB_RX], &next1, p1); + } + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, pi0, pi1, next0, next1); @@ -1515,12 +1544,17 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) to_next += 1; n_left_to_next -= 1; + error0 = IP6_ERROR_UNKNOWN_PROTOCOL; + p0 = vlib_get_buffer (vm, pi0); ip0 = vlib_buffer_get_current (p0); + + if (head_of_feature_arc == 0) + goto skip_check; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol]; - next0 = lm->local_next_by_ip_protocol[ip0->protocol]; flags0 = p0->flags; is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0); good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0; @@ -1573,10 +1607,21 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ? IP6_ERROR_SRC_LOOKUP_MISS : error0); } + skip_check: + + next0 = lm->local_next_by_ip_protocol[ip0->protocol]; next0 = error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0; p0->error = error_node->errors[error0]; + if (head_of_feature_arc) + { + if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL)) + vnet_feature_arc_start (arc_index, + vnet_buffer (p0)->sw_if_index + [VLIB_RX], &next0, p0); + } + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); @@ -1588,6 +1633,12 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) return frame->n_vectors; } +static uword +ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ ); +} + /* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_local_node, static) = { @@ -1608,6 +1659,33 @@ VLIB_REGISTER_NODE (ip6_local_node, static) = VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local); + +static uword +ip6_local_end_of_arc (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ ); +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = { + .function = ip6_local_end_of_arc, + .name = "ip6-local-end-of-arc", + .vector_size = sizeof (u32), + + .format_trace = format_ip6_forward_next_trace, + .sibling_of = "ip6-local", +}; + +VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc) + +VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = { + .arc_name = "ip6-local", + .node_name = "ip6-local-end-of-arc", + .runs_before = 0, /* not before any other features */ +}; +/* *INDENT-ON* */ + void ip6_register_protocol (u32 protocol, u32 node_index) { @@ -3271,7 +3349,14 @@ show_ip6_local_command_fn (vlib_main_t * vm, for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++) { if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT) - vlib_cli_output (vm, "%d", i); + { + + u32 node_index = vlib_get_node (vm, + ip6_local_node.index)-> + next_nodes[lm->local_next_by_ip_protocol[i]]; + vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm, + node_index); + } } return 0; } -- cgit 1.2.3-korg