From 2231150b52b58c4114f8520cde8b26df2761e064 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Fri, 28 Oct 2016 20:30:15 +0200 Subject: feature: add new feature handling code and device-input features Signed-off-by: Damjan Marion Change-Id: I010ecde93863dbdad84b993cd3680a5446db59b5 --- vlib/vlib/node.c | 1 + vlib/vlib/node.h | 3 + vnet/Makefile.am | 14 +- vnet/vnet/buffer.h | 7 + vnet/vnet/devices/af_packet/node.c | 8 +- vnet/vnet/devices/dpdk/node.c | 4 + vnet/vnet/devices/feature.c | 53 ++++ vnet/vnet/devices/netmap/node.c | 8 +- vnet/vnet/devices/virtio/vhost-user.c | 6 + vnet/vnet/ethernet/ethernet.h | 2 +- vnet/vnet/ethernet/interface.c | 27 -- vnet/vnet/feature/feature.c | 337 +++++++++++++++++++++ vnet/vnet/feature/feature.h | 208 +++++++++++++ vnet/vnet/feature/registration.c | 308 ++++++++++++++++++++ vnet/vnet/handoff.c | 7 +- vnet/vnet/interface_cli.c | 17 +- vnet/vnet/ip/feature_registration.c | 534 ---------------------------------- vnet/vnet/ip/feature_registration.h | 63 ---- vnet/vnet/ip/ip4.h | 2 +- vnet/vnet/ip/ip6.h | 2 +- vnet/vnet/ip/lookup.h | 2 +- vnet/vnet/l2/l2_patch.c | 11 +- vnet/vnet/mpls/mpls_features.c | 58 ---- vnet/vnet/mpls/node.c | 1 + vnet/vnet/unix/tuntap.c | 3 + 25 files changed, 984 insertions(+), 702 deletions(-) create mode 100644 vnet/vnet/devices/feature.c create mode 100644 vnet/vnet/feature/feature.c create mode 100644 vnet/vnet/feature/feature.h create mode 100644 vnet/vnet/feature/registration.c delete mode 100644 vnet/vnet/ip/feature_registration.c delete mode 100644 vnet/vnet/ip/feature_registration.h diff --git a/vlib/vlib/node.c b/vlib/vlib/node.c index 23f7ea0239e..118fabe749d 100644 --- a/vlib/vlib/node.c +++ b/vlib/vlib/node.c @@ -424,6 +424,7 @@ register_node (vlib_main_t * vm, vlib_node_registration_t * r) rt->n_next_nodes = r->n_next_nodes; rt->next_frame_index = vec_len (nm->next_frames); + rt->feature_arc_index = ~0; vec_resize (nm->next_frames, rt->n_next_nodes); for (i = 0; i < rt->n_next_nodes; i++) diff --git a/vlib/vlib/node.h b/vlib/vlib/node.h index b624e9d636d..251ee606d20 100644 --- a/vlib/vlib/node.h +++ b/vlib/vlib/node.h @@ -465,6 +465,9 @@ typedef struct vlib_node_runtime_t /* CPU this node runs on */ u16 cpu_index; + /* Index of feature arc in which the node participates */ + u16 feature_arc_index; + /* Function dependent node-runtime. */ u8 runtime_data[0]; } diff --git a/vnet/Makefile.am b/vnet/Makefile.am index f35ec1372db..96306dd3ccd 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 \ @@ -718,6 +716,18 @@ nobase_include_HEADERS += \ vnet/devices/netmap/netmap.h +######################################## +# 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 7aaa6eed9ba..6385f19142c 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 3a3807d8b10..f086b8da1df 100644 --- a/vnet/vnet/devices/af_packet/node.c +++ b/vnet/vnet/devices/af_packet/node.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -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 fa651d81787..01a6094e589 100644 --- a/vnet/vnet/devices/dpdk/node.c +++ b/vnet/vnet/devices/dpdk/node.c @@ -23,6 +23,7 @@ #include #include #include +#include #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 00000000000..8de78178b26 --- /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 + +/* *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 559db669aae..d13fa1bc7b5 100644 --- a/vnet/vnet/devices/netmap/node.c +++ b/vnet/vnet/devices/netmap/node.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -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 5916ced2570..bdac7c24861 100644 --- a/vnet/vnet/devices/virtio/vhost-user.c +++ b/vnet/vnet/devices/virtio/vhost-user.c @@ -36,6 +36,7 @@ #include #include +#include #include @@ -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 11bbd923a93..c31025b7840 100644 --- a/vnet/vnet/ethernet/ethernet.h +++ b/vnet/vnet/ethernet/ethernet.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include always_inline u64 ethernet_mac_address_u64 (u8 * a) diff --git a/vnet/vnet/ethernet/interface.c b/vnet/vnet/ethernet/interface.c index 45d215d324f..a0dea6f52a2 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 ",.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 00000000000..4cfe1faa20f --- /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_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 00000000000..1706dec5456 --- /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 + +/** 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/feature/registration.c b/vnet/vnet/feature/registration.c new file mode 100644 index 00000000000..64a82673b15 --- /dev/null +++ b/vnet/vnet/feature/registration.c @@ -0,0 +1,308 @@ +/* + * 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", 0)
+    };
+    
+ + 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_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:
+
+    config_data0 = vnet_get_config_data (&cm->config_main,
+                                         &b0->current_config_index,
+                                         &next0,
+                                         0 / * sizeof config data * /);
+    
+ + Nodes are free to drop or otherwise redirect packets. Packets + which "pass" should be enqueued via the next0 arc computed by + vnet_get_config_data. +*/ + +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 the xxx_FEATURE_INIT macros are + * 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) + *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); + } + + /* 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: + */ diff --git a/vnet/vnet/handoff.c b/vnet/vnet/handoff.c index 32c665d0c99..5593aa74942 100644 --- a/vnet/vnet/handoff.c +++ b/vnet/vnet/handoff.c @@ -18,6 +18,7 @@ #include #include #include +#include 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 05e650e252c..cd7a620b836 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] [ ...]", + .short_help = "show interfaces [address|addr|features|feat] [ ...]", .function = show_sw_interfaces, }; /* *INDENT-ON* */ diff --git a/vnet/vnet/ip/feature_registration.c b/vnet/vnet/ip/feature_registration.c deleted file mode 100644 index fd94bf1932c..00000000000 --- a/vnet/vnet/ip/feature_registration.c +++ /dev/null @@ -1,534 +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. - */ - -#include -#include -#include - -/** - * @file - * @brief IP Feature Subgraph Ordering. - - Dynamically compute IP 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_IP4_UNICAST_FEATURE_INIT (ip4_lookup, static) =
-    {
-      .node_name = "my-ip4-unicast-feature",
-      .runs_before = ORDER_CONSTRAINTS {"ip4-lookup", 0}
-      .feature_index = &my_feature_index,
-    };
-    
- - Here's the standard coding pattern to enable / disable - @c my-ip4-unicast-feature on an interface: - -
-    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 = 
-    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;
-    
- - For tx features, add this line after setting -
-    tx_cm->config_index_by_sw_if_index = ci.
-    
- - This maintains a - per-interface "at least one TX feature enabled" bitmap: - -
-    vnet_config_update_tx_feature_count (lm, tx_cm, sw_if_index, is_add);
-    
- - Here's how to obtain the correct next node index in packet - processing code, aka in the implementation of @c my-ip4-unicast-feature: - -
-    ip_lookup_main_t * lm = sm->ip4_lookup_main;
-    vnet_feature_config_main_t * cm = &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
-
-    Call @c vnet_get_config_data to set next0, and to advance
-    @c b0->current_config_index:
-
-    config_data0 = vnet_get_config_data (&cm->config_main,
-                                         &b0->current_config_index,
-                                         &next0,
-                                         0 / * sizeof config data * /);
-    
- - Nodes are free to drop or otherwise redirect packets. Packets - which "pass" should be enqueued via the next0 arc computed by - vnet_get_config_data. -*/ - -static const char *vnet_cast_names[] = VNET_CAST_NAMES; - -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 the xxx_FEATURE_INIT macros are - * 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]; - *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; -} - -#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 ", - .function = show_ip_interface_features_command_fn, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/vnet/vnet/ip/feature_registration.h b/vnet/vnet/ip/feature_registration.h deleted file mode 100644 index fcdd96b61bc..00000000000 --- 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 f00b6ca7968..f0806c08449 100644 --- a/vnet/vnet/ip/ip4.h +++ b/vnet/vnet/ip/ip4.h @@ -43,7 +43,7 @@ #include #include #include -#include +#include 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 78546120a23..f6008d71ea1 100644 --- a/vnet/vnet/ip/ip6.h +++ b/vnet/vnet/ip/ip6.h @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/vnet/vnet/ip/lookup.h b/vnet/vnet/ip/lookup.h index a1fbe6eb289..c1d8d204ef9 100644 --- a/vnet/vnet/ip/lookup.h +++ b/vnet/vnet/ip/lookup.h @@ -54,7 +54,7 @@ #include #include #include -#include +#include /** @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 ad05fa0d034..5e4691f45c7 100644 --- a/vnet/vnet/l2/l2_patch.c +++ b/vnet/vnet/l2/l2_patch.c @@ -16,6 +16,7 @@ #include #include #include +#include #include 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 10a58cfb09c..2f98867cf90 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 ", - .function = show_mpls_interface_features_command_fn, -}; - diff --git a/vnet/vnet/mpls/node.c b/vnet/vnet/mpls/node.c index 7a4a302315a..c98b98e733b 100644 --- a/vnet/vnet/mpls/node.c +++ b/vnet/vnet/mpls/node.c @@ -18,6 +18,7 @@ #include #include #include +#include typedef struct { u32 next_index; diff --git a/vnet/vnet/unix/tuntap.c b/vnet/vnet/unix/tuntap.c index 89fd1dcfe81..e4d05446e36 100644 --- a/vnet/vnet/unix/tuntap.c +++ b/vnet/vnet/unix/tuntap.c @@ -47,6 +47,7 @@ #include #include +#include #if DPDK == 1 #include @@ -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) -- cgit 1.2.3-korg