diff options
Diffstat (limited to 'vnet')
-rw-r--r-- | vnet/Makefile.am | 14 | ||||
-rw-r--r-- | vnet/vnet/buffer.h | 7 | ||||
-rw-r--r-- | vnet/vnet/devices/af_packet/node.c | 8 | ||||
-rw-r--r-- | vnet/vnet/devices/dpdk/node.c | 4 | ||||
-rw-r--r-- | vnet/vnet/devices/feature.c | 53 | ||||
-rw-r--r-- | vnet/vnet/devices/netmap/node.c | 8 | ||||
-rw-r--r-- | vnet/vnet/devices/virtio/vhost-user.c | 6 | ||||
-rw-r--r-- | vnet/vnet/ethernet/ethernet.h | 2 | ||||
-rw-r--r-- | vnet/vnet/ethernet/interface.c | 27 | ||||
-rw-r--r-- | vnet/vnet/feature/feature.c | 337 | ||||
-rw-r--r-- | vnet/vnet/feature/feature.h | 208 | ||||
-rw-r--r-- | vnet/vnet/feature/registration.c (renamed from vnet/vnet/ip/feature_registration.c) | 254 | ||||
-rw-r--r-- | vnet/vnet/handoff.c | 7 | ||||
-rw-r--r-- | vnet/vnet/interface_cli.c | 17 | ||||
-rw-r--r-- | vnet/vnet/ip/feature_registration.h | 63 | ||||
-rw-r--r-- | vnet/vnet/ip/ip4.h | 2 | ||||
-rw-r--r-- | vnet/vnet/ip/ip6.h | 2 | ||||
-rw-r--r-- | vnet/vnet/ip/lookup.h | 2 | ||||
-rw-r--r-- | vnet/vnet/l2/l2_patch.c | 11 | ||||
-rw-r--r-- | vnet/vnet/mpls/mpls_features.c | 58 | ||||
-rw-r--r-- | vnet/vnet/mpls/node.c | 1 | ||||
-rw-r--r-- | vnet/vnet/unix/tuntap.c | 3 |
22 files changed, 686 insertions, 408 deletions
diff --git a/vnet/Makefile.am b/vnet/Makefile.am index f35ec137..96306dd3 100644 --- a/vnet/Makefile.am +++ b/vnet/Makefile.am @@ -266,7 +266,6 @@ nobase_include_HEADERS += \ # Layer 3 protocol: IP v4/v6 ######################################## libvnet_la_SOURCES += \ - vnet/ip/feature_registration.c \ vnet/ip/format.c \ vnet/ip/icmp4.c \ vnet/ip/icmp6.c \ @@ -298,7 +297,6 @@ libvnet_la_SOURCES += \ vnet/ip/udp_pg.c nobase_include_HEADERS += \ - vnet/ip/feature_registration.h \ vnet/ip/format.h \ vnet/ip/icmp46_packet.h \ vnet/ip/icmp4.h \ @@ -719,6 +717,18 @@ nobase_include_HEADERS += \ ######################################## +# Driver feature graph arc support +######################################## + +libvnet_la_SOURCES += \ + vnet/devices/feature.c \ + vnet/feature/feature.c \ + vnet/feature/registration.c + +nobase_include_HEADERS += \ + vnet/feature/feature.h + +######################################## # Unix kernel related ######################################## diff --git a/vnet/vnet/buffer.h b/vnet/vnet/buffer.h index 7aaa6eed..6385f191 100644 --- a/vnet/vnet/buffer.h +++ b/vnet/vnet/buffer.h @@ -319,6 +319,13 @@ typedef struct u16 overlay_afi; } lisp; + /* Driver rx feature */ + struct + { + u32 saved_next_index; /**< saved by drivers for short-cut */ + u16 buffer_advance; + } device_input_feat; + u32 unused[6]; }; } vnet_buffer_opaque_t; diff --git a/vnet/vnet/devices/af_packet/node.c b/vnet/vnet/devices/af_packet/node.c index 3a3807d8..f086b8da 100644 --- a/vnet/vnet/devices/af_packet/node.c +++ b/vnet/vnet/devices/af_packet/node.c @@ -23,6 +23,7 @@ #include <vlib/unix/unix.h> #include <vnet/ip/ip.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/feature/feature.h> #include <vnet/devices/af_packet/af_packet.h> @@ -164,7 +165,7 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, tph = (struct tpacket2_hdr *) (block_start + rx_frame * frame_size); while ((tph->tp_status & TP_STATUS_USER) && (n_free_bufs > min_bufs)) { - vlib_buffer_t *b0, *first_b0 = 0; + vlib_buffer_t *b0 = 0, *first_b0 = 0; u32 next0 = next_index; u32 n_left_to_next; @@ -236,6 +237,11 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, tr->hw_if_index = apif->hw_if_index; clib_memcpy (&tr->tph, tph, sizeof (struct tpacket2_hdr)); } + + /* redirect if feature path enabled */ + vnet_feature_device_input_redirect_x1 (node, apif->sw_if_index, + &next0, b0, 0); + /* enque and take next packet */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, first_bi0, next0); diff --git a/vnet/vnet/devices/dpdk/node.c b/vnet/vnet/devices/dpdk/node.c index fa651d81..01a6094e 100644 --- a/vnet/vnet/devices/dpdk/node.c +++ b/vnet/vnet/devices/dpdk/node.c @@ -23,6 +23,7 @@ #include <vnet/classify/vnet_classify.h> #include <vnet/mpls/packet.h> #include <vnet/handoff.h> +#include <vnet/feature/feature.h> #include "dpdk_priv.h" @@ -530,6 +531,9 @@ dpdk_device_input (dpdk_main_t * dm, */ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); + /* Do we have any driver RX features configured on the interface? */ + vnet_feature_device_input_redirect_x1 (node, xd->vlib_sw_if_index, &next0, b0, l3_offset0); + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); diff --git a/vnet/vnet/devices/feature.c b/vnet/vnet/devices/feature.c new file mode 100644 index 00000000..8de78178 --- /dev/null +++ b/vnet/vnet/devices/feature.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 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/feature.h> + +/* *INDENT-OFF* */ +VNET_FEATURE_ARC_INIT (device_input, static) = { + .arc_name = "device-input", +#if DPDK > 0 + .start_nodes = VNET_FEATURES ("dpdk-input", "vhost-user-input", "af-packet-input", "netmap-input"), +#else + .start_nodes = VNET_FEATURES ("vhost-user-input", "af-packet-input", "netmap-input"), +#endif +}; + +VNET_FEATURE_INIT (l2_patch, static) = { + .arc_name = "device-input", + .node_name = "l2-patch", + .runs_before = VNET_FEATURES ("ethernet-input"), +}; + +VNET_FEATURE_INIT (worker_handoff, static) = { + .arc_name = "device-input", + .node_name = "worker-handoff", + .runs_before = VNET_FEATURES ("ethernet-input"), +}; + +VNET_FEATURE_INIT (ethernet_input, static) = { + .arc_name = "device-input", + .node_name = "ethernet-input", + .runs_before = 0, /* not before any other features */ +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/vnet/vnet/devices/netmap/node.c b/vnet/vnet/devices/netmap/node.c index 559db669..d13fa1bc 100644 --- a/vnet/vnet/devices/netmap/node.c +++ b/vnet/vnet/devices/netmap/node.c @@ -22,6 +22,7 @@ #include <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/feature/feature.h> #include <vnet/devices/netmap/net_netmap.h> #include <vnet/devices/netmap/netmap.h> @@ -158,7 +159,7 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, while (r && n_left_to_next) { - vlib_buffer_t *b0, *first_b0 = 0; + vlib_buffer_t *b0 = 0, *first_b0 = 0; u32 offset = 0; u32 bi0 = 0, first_bi0 = 0, prev_bi0; u32 next_slot_index = (cur_slot_index + 1) % ring->num_slots; @@ -235,6 +236,11 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, memcpy (&tr->slot, slot, sizeof (struct netmap_slot)); } } + + /* redirect if feature path enabled */ + vnet_feature_device_input_redirect_x1 (node, nif->sw_if_index, + &next0, b0, 0); + /* enque and take next packet */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, first_bi0, diff --git a/vnet/vnet/devices/virtio/vhost-user.c b/vnet/vnet/devices/virtio/vhost-user.c index 5916ced2..bdac7c24 100644 --- a/vnet/vnet/devices/virtio/vhost-user.c +++ b/vnet/vnet/devices/virtio/vhost-user.c @@ -36,6 +36,7 @@ #include <vnet/ip/ip.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/feature/feature.h> #include <vnet/devices/virtio/vhost-user.h> @@ -1290,6 +1291,11 @@ vhost_user_if_input (vlib_main_t * vm, to_next[0] = bi_head; to_next++; n_left_to_next--; + + /* redirect if feature path enabled */ + vnet_feature_device_input_redirect_x1 (node, vui->sw_if_index, + &next0, b_head, 0); + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi_head, next0); diff --git a/vnet/vnet/ethernet/ethernet.h b/vnet/vnet/ethernet/ethernet.h index 11bbd923..c31025b7 100644 --- a/vnet/vnet/ethernet/ethernet.h +++ b/vnet/vnet/ethernet/ethernet.h @@ -43,7 +43,7 @@ #include <vnet/vnet.h> #include <vnet/ethernet/packet.h> #include <vnet/pg/pg.h> -#include <vnet/ip/feature_registration.h> +#include <vnet/feature/feature.h> always_inline u64 ethernet_mac_address_u64 (u8 * a) diff --git a/vnet/vnet/ethernet/interface.c b/vnet/vnet/ethernet/interface.c index 45d215d3..a0dea6f5 100644 --- a/vnet/vnet/ethernet/interface.c +++ b/vnet/vnet/ethernet/interface.c @@ -701,33 +701,6 @@ VLIB_CLI_COMMAND (delete_sub_interface_command, static) = { }; /* *INDENT-ON* */ -static clib_error_t * -show_ethernet_interface_features_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - ethernet_main_t *em = ðernet_main; - u32 sw_if_index; - - if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) - return clib_error_return (0, "Interface not specified..."); - - vlib_cli_output (vm, "Ethernet feature paths configured on %U...", - format_vnet_sw_if_index_name, vnm, sw_if_index); - - ip_interface_features_show (vm, "Ethernet", - em->feature_config_mains, sw_if_index); - - return 0; -} - -VLIB_CLI_COMMAND (show_ethernet_interface_features_command, static) = -{ -.path = "show ethernet interface features",.short_help = - "show ethernet interface features <intfc>",.function = - show_ethernet_interface_features_command_fn,}; - /* * fd.io coding-style-patch-verification: ON * diff --git a/vnet/vnet/feature/feature.c b/vnet/vnet/feature/feature.c new file mode 100644 index 00000000..4cfe1faa --- /dev/null +++ b/vnet/vnet/feature/feature.c @@ -0,0 +1,337 @@ +/* + * 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/feature.h> + +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; + hash_set_mem (fm->arc_index_by_name, areg->arc_name, + pointer_to_uword (areg)); + + /* process start nodes */ + while ((s = areg->start_nodes[i])) + { + vlib_node_t *n; + vlib_node_runtime_t *rt; + n = vlib_get_node_by_name (vm, (u8 *) s); + + if (n == 0) + return clib_error_return (0, + "Unknown start node '%s' on feature arc '%s'", + s, areg->arc_name); + + rt = vlib_node_get_runtime (vm, n->index); + rt->feature_arc_index = arc_index; + 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) + { + vlib_node_t *n; + vlib_node_runtime_t *rt; + 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; + + /* set feature arc index in node runtime */ + n = vlib_get_node_by_name (vm, (u8 *) freg->node_name); + if (n == 0) + return clib_error_return (0, "Unknown node '%s', freg->node_name"); + rt = vlib_node_get_runtime (vm, n->index); + rt->feature_arc_index = arc_index; + + vec_add1 (fm->next_feature_by_arc[arc_index], *freg); + + /* next */ + freg = freg->next; + } + + 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; + } + + /* next */ + areg = areg->next; + arc_index++; + } + + return 0; +} + +VLIB_INIT_FUNCTION (vnet_feature_init); + +void +vnet_config_update_feature_count (vnet_feature_main_t * fm, u16 arc, + u32 sw_if_index, int is_add) +{ + uword bit_value; + + vec_validate (fm->feature_count_by_sw_if_index[arc], sw_if_index); + + fm->feature_count_by_sw_if_index[arc][sw_if_index] += is_add ? 1 : -1; + + ASSERT (fm->feature_count_by_sw_if_index[arc][sw_if_index] >= 0); + + bit_value = fm->feature_count_by_sw_if_index[arc][sw_if_index] > 0; + + fm->sw_if_index_has_features[arc] = + clib_bitmap_set (fm->sw_if_index_has_features[arc], sw_if_index, + bit_value); +} + +u16 +vnet_feature_arc_index_from_node_name (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; +} + +u32 +vnet_feature_index_from_node_name (u16 arc, const char *s) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_registration_t *reg; + uword *p; + + p = hash_get_mem (fm->next_feature_by_name[arc], s); + if (p == 0) + return ~0; + + reg = uword_to_pointer (p[0], vnet_feature_registration_t *); + return reg->feature_index_u32; +} + +void +vnet_feature_enable_disable (const char *arc_name, const char *node_name, + u32 sw_if_index, int enable_disable, + void *feature_config, u32 n_feature_config_bytes) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm; + u32 feature_index, ci; + u16 arc_index; + + arc_index = vnet_feature_arc_index_from_node_name (arc_name); + + if (arc_index == ~0) + return; + + cm = &fm->feature_config_mains[arc_index]; + vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0); + feature_index = vnet_feature_index_from_node_name (arc_index, node_name); + if (feature_index == ~0) + return; + ci = cm->config_index_by_sw_if_index[sw_if_index]; + + 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; + + vnet_config_update_feature_count (fm, arc_index, sw_if_index, + enable_disable); + +} + + +/** 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); + vec_foreach (freg, fm->next_feature_by_arc[areg->feature_arc_index]) + { + vlib_cli_output (vm, " %s\n", freg->node_name); + } + + + /* 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); + } + } +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/vnet/vnet/feature/feature.h b/vnet/vnet/feature/feature.h new file mode 100644 index 00000000..1706dec5 --- /dev/null +++ b/vnet/vnet/feature/feature.h @@ -0,0 +1,208 @@ +/* + * 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 <vnet/vnet.h> + +/** 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; + /* Feature arc index, assigned by init function */ + u16 feature_arc_index; +} vnet_feature_arc_registration_t; + +/** 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; + u32 feature_index_u32; + /** Constraints of the form "this feature runs before X" */ + char **runs_before; + /** Constraints of the form "this feature runs after Y" */ + char **runs_after; +} vnet_feature_registration_t; + +typedef struct vnet_feature_config_main_t_ +{ + vnet_config_main_t config_main; + u32 *config_index_by_sw_if_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; + + /** 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, u16 arc, + u32 sw_if_index, int is_add); + +u32 vnet_feature_index_from_node_name (u16 type, const char *s); + +void +vnet_feature_enable_disable (const char *arc_name, const char *node_name, + u32 sw_if_index, int enable_disable, + void *feature_config, + u32 n_feature_config_bytes); + + +static_always_inline int +vnet_have_features (u32 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_feature_get_config_index (u16 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_redirect (u16 arc, u32 sw_if_index, u32 * next0, + vlib_buffer_t * b0) +{ + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t *cm = &fm->feature_config_mains[arc]; + + if (PREDICT_FALSE (vnet_have_features (arc, sw_if_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_device_input_redirect_x1 (vlib_node_runtime_t * node, + 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; + + ASSERT (node->feature_arc_index != ~(u16) 0); + cm = &fm->feature_config_mains[node->feature_arc_index]; + + if (PREDICT_FALSE + (clib_bitmap_get + (fm->sw_if_index_has_features[node->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->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); + } +} + +#define ORDER_CONSTRAINTS (char*[]) +#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/vnet/vnet/ip/feature_registration.c b/vnet/vnet/feature/registration.c index fd94bf19..64a82673 100644 --- a/vnet/vnet/ip/feature_registration.c +++ b/vnet/vnet/feature/registration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Cisco and/or its affiliates. + * 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: @@ -19,9 +19,9 @@ /** * @file - * @brief IP Feature Subgraph Ordering. + * @brief Feature Subgraph Ordering. - Dynamically compute IP feature subgraph ordering by performing a + 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. @@ -42,17 +42,17 @@ feature subgraph arc, which needs to run before @c ip4-lookup. In either base code or a plugin, <CODE><PRE> - \#include <vnet/ip/feature_registration.h> + \#include <vnet/feature/feature.h> </PRE></CODE> and add the new feature as shown: <CODE><PRE> - VNET_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) = + VNET_FEATURE_INIT (ip4_lookup, static) = { + .arch_name = "ip4-unicast", .node_name = "my-ip4-unicast-feature", - .runs_before = ORDER_CONSTRAINTS {"ip4-lookup", 0} - .feature_index = &my_feature_index, + .runs_before = VLIB_FEATURES ("ip4-lookup", 0) }; </PRE></CODE> @@ -60,42 +60,18 @@ @c my-ip4-unicast-feature on an interface: <CODE><PRE> - ip4_main_t *im = \&ip4_main; - ip_lookup_main_t *lm = &im->lookup_main; - vnet_feature_config_main_t *rx_cm = - &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT]; sw_if_index = <interface-handle> - ci = rx_cm->config_index_by_sw_if_index[sw_if_index]; - ci = (is_add - ? vnet_config_add_feature - : vnet_config_del_feature) - (vm, &rx_cm->config_main, - ci, - my_feature_index, - 0 / * &config struct if feature uses private config data * /, - 0 / * sizeof config struct if feature uses private config data * /); - rx_cm->config_index_by_sw_if_index[sw_if_index] = ci; - </PRE></CODE> - - For tx features, add this line after setting - <CODE><PRE> - tx_cm->config_index_by_sw_if_index = ci. - </PRE></CODE> - - This maintains a - per-interface "at least one TX feature enabled" bitmap: - - <CODE><PRE> - vnet_config_update_tx_feature_count (lm, tx_cm, sw_if_index, is_add); + vnet_feature_enable_disable ("ip4-unicast", "my-ip4-unicast-feature", + sw_if_index, 1 ); </PRE></CODE> Here's how to obtain the correct next node index in packet processing code, aka in the implementation of @c my-ip4-unicast-feature: <CODE><PRE> - ip_lookup_main_t * lm = sm->ip4_lookup_main; - vnet_feature_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT]; + vnet_feature_main_t *fm = &feature_main; + vnet_feature_config_main_t * cm = &fm->feature_config_mains[VNET_FEAT_IP4_UNICAST]; Call @c vnet_get_config_data to set next0, and to advance @c b0->current_config_index: @@ -111,8 +87,6 @@ vnet_get_config_data. */ -static const char *vnet_cast_names[] = VNET_CAST_NAMES; - static int comma_split (u8 * s, u8 ** a, u8 ** b) { @@ -292,7 +266,9 @@ again: p = hash_get (reg_by_index, result[i]); ASSERT (p != 0); this_reg = (vnet_feature_registration_t *) p[0]; - *this_reg->feature_index = n_features - (i + 1); + if (this_reg->feature_index) + *this_reg->feature_index = n_features - (i + 1); + this_reg->feature_index_u32 = n_features - (i + 1); vec_add1 (feature_nodes, this_reg->node_name); } @@ -323,208 +299,6 @@ again: return 0; } -#define foreach_af_cast \ -_(4, VNET_IP_RX_UNICAST_FEAT, "ip4 unicast") \ -_(4, VNET_IP_RX_MULTICAST_FEAT, "ip4 multicast") \ -_(4, VNET_IP_TX_FEAT, "ip4 output") \ -_(6, VNET_IP_RX_UNICAST_FEAT, "ip6 unicast") \ -_(6, VNET_IP_RX_MULTICAST_FEAT, "ip6 multicast") \ -_(6, VNET_IP_TX_FEAT, "ip6 output") - -/** Display the set of available ip features. - Useful for verifying that expected features are present -*/ - -static clib_error_t * -show_ip_features_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - ip4_main_t *im4 = &ip4_main; - ip6_main_t *im6 = &ip6_main; - int i; - char **features; - - vlib_cli_output (vm, "Available IP feature nodes"); - -#define _(a,c,s) \ - do { \ - features = im##a->feature_nodes[c]; \ - vlib_cli_output (vm, "%s:", s); \ - for (i = 0; i < vec_len(features); i++) \ - vlib_cli_output (vm, " %s\n", features[i]); \ - } while(0); - foreach_af_cast; -#undef _ - - return 0; -} - -/*? - * This command is used to display the set of available IP features. - * This can be useful for verifying that expected features are present. - * - * @cliexpar - * Example of how to display the set of available IP features: - * @cliexstart{show ip features} - * Available IP feature nodes - * ip4 unicast: - * ip4-inacl - * ip4-source-check-via-rx - * ip4-source-check-via-any - * ip4-source-and-port-range-check-rx - * ip4-policer-classify - * ipsec-input-ip4 - * vpath-input-ip4 - * snat-in2out - * snat-out2in - * ip4-lookup - * ip4 multicast: - * vpath-input-ip4 - * ip4-lookup-multicast - * ip4 output: - * ip4-source-and-port-range-check-tx - * interface-output - * ip6 unicast: - * ip6-inacl - * ip6-policer-classify - * ipsec-input-ip6 - * l2tp-decap - * vpath-input-ip6 - * sir-to-ila - * ip6-lookup - * ip6 multicast: - * vpath-input-ip6 - * ip6-lookup - * ip6 output: - * interface-output - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_ip_features_command, static) = { - .path = "show ip features", - .short_help = "show ip features", - .function = show_ip_features_command_fn, -}; -/* *INDENT-ON* */ - -/** Display the set of IP features configured on a specific interface - */ - -void -ip_interface_features_show (vlib_main_t * vm, - const char *pname, - vnet_feature_config_main_t * cm, u32 sw_if_index) -{ - u32 node_index, current_config_index; - vnet_cast_t cast; - 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, "%s feature paths configured on %U...", - pname, format_vnet_sw_if_index_name, - vnet_get_main (), sw_if_index); - - for (cast = VNET_IP_RX_UNICAST_FEAT; cast < VNET_N_IP_FEAT; cast++) - { - vcm = &(cm[cast].config_main); - - vlib_cli_output (vm, "\n%s %s:", pname, vnet_cast_names[cast]); - - if (NULL == cm[cast].config_index_by_sw_if_index || - vec_len (cm[cast].config_index_by_sw_if_index) < sw_if_index) - { - vlib_cli_output (vm, "none configured"); - continue; - } - - current_config_index = vec_elt (cm[cast].config_index_by_sw_if_index, - sw_if_index); - - 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 * -show_ip_interface_features_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - ip4_main_t *im4 = &ip4_main; - ip_lookup_main_t *lm4 = &im4->lookup_main; - ip6_main_t *im6 = &ip6_main; - ip_lookup_main_t *lm6 = &im6->lookup_main; - - ip_lookup_main_t *lm; - u32 sw_if_index, af; - - if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) - return clib_error_return (0, "Interface not specified..."); - - vlib_cli_output (vm, "IP feature paths configured on %U...", - format_vnet_sw_if_index_name, vnm, sw_if_index); - - for (af = 0; af < 2; af++) - { - if (af == 0) - lm = lm4; - else - lm = lm6; - - ip_interface_features_show (vm, (af == 0) ? "ip4" : "ip6", - lm->feature_config_mains, sw_if_index); - } - - return 0; -} - -/*? - * This command is used to display the set of IP features configured - * on a specific interface - * - * @cliexpar - * Example of how to display the set of available IP features on an interface: - * @cliexstart{show ip interface features GigabitEthernet2/0/0} - * IP feature paths configured on GigabitEthernet2/0/0... - * ipv4 unicast: - * ip4-lookup - * ipv4 multicast: - * ip4-lookup-multicast - * ipv4 multicast: - * interface-output - * ipv6 unicast: - * ip6-lookup - * ipv6 multicast: - * ip6-lookup - * ipv6 multicast: - * interface-output - * @cliexend -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = { - .path = "show ip interface features", - .short_help = "show ip interface features <interface>", - .function = show_ip_interface_features_command_fn, -}; -/* *INDENT-ON* */ - /* * fd.io coding-style-patch-verification: ON * diff --git a/vnet/vnet/handoff.c b/vnet/vnet/handoff.c index 32c665d0..5593aa74 100644 --- a/vnet/vnet/handoff.c +++ b/vnet/vnet/handoff.c @@ -18,6 +18,7 @@ #include <vppinfra/xxhash.h> #include <vlib/threads.h> #include <vnet/handoff.h> +#include <vnet/feature/feature.h> typedef struct { @@ -234,8 +235,7 @@ interface_handoff_enable_disable (vlib_main_t * vm, u32 sw_if_index, vnet_sw_interface_t *sw; vnet_main_t *vnm = vnet_get_main (); per_inteface_handoff_data_t *d; - int i, rv; - u32 node_index = enable_disable ? worker_handoff_node.index : ~0; + int i, rv = 0; if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index)) return VNET_API_ERROR_INVALID_SW_IF_INDEX; @@ -264,7 +264,8 @@ interface_handoff_enable_disable (vlib_main_t * vm, u32 sw_if_index, /* *INDENT-ON* */ } - rv = vnet_hw_interface_rx_redirect_to_node (vnm, sw_if_index, node_index); + vnet_feature_enable_disable ("device-input", "worker-handoff", + sw_if_index, enable_disable, 0, 0); return rv; } diff --git a/vnet/vnet/interface_cli.c b/vnet/vnet/interface_cli.c index 05e650e2..cd7a620b 100644 --- a/vnet/vnet/interface_cli.c +++ b/vnet/vnet/interface_cli.c @@ -225,12 +225,12 @@ show_sw_interfaces (vlib_main_t * vm, vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; vnet_sw_interface_t *si, *sorted_sis = 0; + u32 sw_if_index = ~(u32) 0; u8 show_addresses = 0; + u8 show_features = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - u32 sw_if_index; - /* See if user wants to show specific interface */ if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) @@ -240,6 +240,8 @@ show_sw_interfaces (vlib_main_t * vm, } else if (unformat (input, "address") || unformat (input, "addr")) show_addresses = 1; + else if (unformat (input, "features") || unformat (input, "feat")) + show_features = 1; else { error = clib_error_return (0, "unknown input `%U'", @@ -248,6 +250,15 @@ show_sw_interfaces (vlib_main_t * vm, } } + if (show_features) + { + if (sw_if_index == ~(u32) 0) + return clib_error_return (0, "Interface not specified..."); + + vnet_interface_features_show (vm, sw_if_index); + return 0; + } + if (!show_addresses) vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0); @@ -390,7 +401,7 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = { .path = "show interfaces", - .short_help = "show interfaces [address|addr] [<if-name1> <if-name2> ...]", + .short_help = "show interfaces [address|addr|features|feat] [<if-name1> <if-name2> ...]", .function = show_sw_interfaces, }; /* *INDENT-ON* */ diff --git a/vnet/vnet/ip/feature_registration.h b/vnet/vnet/ip/feature_registration.h deleted file mode 100644 index fcdd96b6..00000000 --- a/vnet/vnet/ip/feature_registration.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015 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_feature_registration_h -#define included_feature_registration_h - -/** feature registration object */ -typedef struct _vnet_feature_registration -{ - /** next registration in list of all registrations*/ - struct _vnet_feature_registration *next; - /** Graph node name */ - char *node_name; - /** Pointer to this feature index, filled in by vnet_feature_arc_init */ - 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; -} vnet_feature_registration_t; - -typedef struct vnet_feature_config_main_t_ -{ - vnet_config_main_t config_main; - u32 *config_index_by_sw_if_index; -} vnet_feature_config_main_t; - -/** Syntactic sugar, the c-compiler won't initialize registrations without it */ -#define ORDER_CONSTRAINTS (char*[]) - -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 ip_interface_features_show (vlib_main_t * vm, - const char *pname, - vnet_feature_config_main_t * cm, - u32 sw_if_index); - -#endif /* included_feature_registration_h */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/vnet/vnet/ip/ip4.h b/vnet/vnet/ip/ip4.h index f00b6ca7..f0806c08 100644 --- a/vnet/vnet/ip/ip4.h +++ b/vnet/vnet/ip/ip4.h @@ -43,7 +43,7 @@ #include <vnet/ip/ip4_mtrie.h> #include <vnet/ip/ip4_packet.h> #include <vnet/ip/lookup.h> -#include <vnet/ip/feature_registration.h> +#include <vnet/feature/feature.h> typedef struct ip4_fib_t { /* Hash table for each prefix length mapping. */ diff --git a/vnet/vnet/ip/ip6.h b/vnet/vnet/ip/ip6.h index 78546120..f6008d71 100644 --- a/vnet/vnet/ip/ip6.h +++ b/vnet/vnet/ip/ip6.h @@ -46,7 +46,7 @@ #include <vnet/ip/ip6_packet.h> #include <vnet/ip/ip6_hop_by_hop_packet.h> #include <vnet/ip/lookup.h> -#include <vnet/ip/feature_registration.h> +#include <vnet/feature/feature.h> #include <stdbool.h> #include <vppinfra/bihash_24_8.h> #include <vppinfra/bihash_template.h> diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h index a1fbe6eb..c1d8d204 100644 --- a/vnet/vnet/ip/lookup.h +++ b/vnet/vnet/ip/lookup.h @@ -54,7 +54,7 @@ #include <vnet/ip/ip6_packet.h> #include <vnet/fib/fib_node.h> #include <vnet/dpo/dpo.h> -#include <vnet/ip/feature_registration.h> +#include <vnet/feature/feature.h> /** @brief Common (IP4/IP6) next index stored in adjacency. */ typedef enum { diff --git a/vnet/vnet/l2/l2_patch.c b/vnet/vnet/l2/l2_patch.c index ad05fa0d..5e4691f4 100644 --- a/vnet/vnet/l2/l2_patch.c +++ b/vnet/vnet/l2/l2_patch.c @@ -16,6 +16,7 @@ #include <vnet/vnet.h> #include <vnet/pg/pg.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/feature/feature.h> #include <vppinfra/error.h> typedef struct @@ -283,18 +284,16 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_patch_node, l2_patch_node_fn) ethernet_set_flags (l2pm->vnet_main, rxhi->hw_if_index, ETHERNET_INTERFACE_FLAG_ACCEPT_ALL); - vnet_hw_interface_rx_redirect_to_node (l2pm->vnet_main, - rxhi->hw_if_index, - l2_patch_node.index); + vnet_feature_enable_disable ("device-input", "l2-patch", + rxhi->hw_if_index, 1, 0, 0); } else { ethernet_set_flags (l2pm->vnet_main, rxhi->hw_if_index, 0 /* disable promiscuous mode */ ); - vnet_hw_interface_rx_redirect_to_node (l2pm->vnet_main, - rxhi->hw_if_index, - ~0 /* disable */ ); + vnet_feature_enable_disable ("device-input", "l2-patch", + rxhi->hw_if_index, 0, 0, 0); if (vec_len (l2pm->tx_next_by_rx_sw_if_index) > rx_sw_if_index) { l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = ~0; diff --git a/vnet/vnet/mpls/mpls_features.c b/vnet/vnet/mpls/mpls_features.c index 10a58cfb..2f98867c 100644 --- a/vnet/vnet/mpls/mpls_features.c +++ b/vnet/vnet/mpls/mpls_features.c @@ -213,61 +213,3 @@ VNET_SW_INTERFACE_ADD_DEL_FUNCTION (mpls_sw_interface_add_del); _(VNET_IP_RX_UNICAST_FEAT, "mpls input") \ _(VNET_IP_TX_FEAT, "mpls output") \ -static clib_error_t * -show_mpls_features_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - mpls_main_t * mm = &mpls_main; - int i; - char ** features; - - vlib_cli_output (vm, "Available MPLS feature nodes"); - -#define _(c,s) \ - do { \ - features = mm->feature_nodes[c]; \ - vlib_cli_output (vm, "%s:", s); \ - for (i = 0; i < vec_len(features); i++) \ - vlib_cli_output (vm, " %s\n", features[i]); \ - } while(0); - foreach_af_cast; -#undef _ - - return 0; -} - -VLIB_CLI_COMMAND (show_ip_features_command, static) = { - .path = "show mpls features", - .short_help = "show mpls features", - .function = show_mpls_features_command_fn, -}; - -static clib_error_t * -show_mpls_interface_features_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t * vnm = vnet_get_main(); - u32 sw_if_index; - - if (! unformat (input, "%U", unformat_vnet_sw_interface, - vnm, &sw_if_index)) - return clib_error_return (0, "Interface not specified..."); - - vlib_cli_output (vm, "MPLS feature paths configured on %U...", - format_vnet_sw_if_index_name, vnm, sw_if_index); - - ip_interface_features_show (vm, "MPLS", - mpls_main.feature_config_mains, - sw_if_index); - - return 0; -} - -VLIB_CLI_COMMAND (show_mpls_interface_features_command, static) = { - .path = "show mpls interface features", - .short_help = "show mpls interface features <intfc>", - .function = show_mpls_interface_features_command_fn, -}; - diff --git a/vnet/vnet/mpls/node.c b/vnet/vnet/mpls/node.c index 7a4a3023..c98b98e7 100644 --- a/vnet/vnet/mpls/node.c +++ b/vnet/vnet/mpls/node.c @@ -18,6 +18,7 @@ #include <vlib/vlib.h> #include <vnet/pg/pg.h> #include <vnet/mpls/mpls.h> +#include <vnet/feature/feature.h> typedef struct { u32 next_index; diff --git a/vnet/vnet/unix/tuntap.c b/vnet/vnet/unix/tuntap.c index 89fd1dcf..e4d05446 100644 --- a/vnet/vnet/unix/tuntap.c +++ b/vnet/vnet/unix/tuntap.c @@ -47,6 +47,7 @@ #include <vnet/ip/ip.h> #include <vnet/ethernet/ethernet.h> +#include <vnet/feature/feature.h> #if DPDK == 1 #include <vnet/devices/dpdk/dpdk.h> @@ -395,6 +396,8 @@ tuntap_rx (vlib_main_t * vm, next_index = TUNTAP_RX_NEXT_DROP; } + vnet_feature_device_input_redirect_x1 (node, tm->hw_if_index, &next_index, b, 0); + vlib_set_next_frame_buffer (vm, node, next_index, bi); if (n_trace > 0) |