From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- src/vnet/l2/dir.dox | 24 + src/vnet/l2/feat_bitmap.c | 185 +++++++ src/vnet/l2/feat_bitmap.h | 96 ++++ src/vnet/l2/l2.api | 38 ++ src/vnet/l2/l2_api.c | 140 +++++ src/vnet/l2/l2_bd.c | 1079 ++++++++++++++++++++++++++++++++++++ src/vnet/l2/l2_bd.h | 150 +++++ src/vnet/l2/l2_bvi.c | 40 ++ src/vnet/l2/l2_bvi.h | 117 ++++ src/vnet/l2/l2_classify.h | 116 ++++ src/vnet/l2/l2_efp_filter.c | 614 +++++++++++++++++++++ src/vnet/l2/l2_efp_filter.h | 33 ++ src/vnet/l2/l2_fib.c | 857 +++++++++++++++++++++++++++++ src/vnet/l2/l2_fib.h | 341 ++++++++++++ src/vnet/l2/l2_flood.c | 568 +++++++++++++++++++ src/vnet/l2/l2_flood.h | 35 ++ src/vnet/l2/l2_fwd.c | 544 +++++++++++++++++++ src/vnet/l2/l2_fwd.h | 36 ++ src/vnet/l2/l2_input.c | 1116 ++++++++++++++++++++++++++++++++++++++ src/vnet/l2/l2_input.h | 266 +++++++++ src/vnet/l2/l2_input_acl.c | 434 +++++++++++++++ src/vnet/l2/l2_input_classify.c | 655 ++++++++++++++++++++++ src/vnet/l2/l2_input_vtr.c | 401 ++++++++++++++ src/vnet/l2/l2_input_vtr.h | 54 ++ src/vnet/l2/l2_learn.c | 597 ++++++++++++++++++++ src/vnet/l2/l2_learn.h | 64 +++ src/vnet/l2/l2_output.c | 708 ++++++++++++++++++++++++ src/vnet/l2/l2_output.h | 285 ++++++++++ src/vnet/l2/l2_output_acl.c | 358 ++++++++++++ src/vnet/l2/l2_output_classify.c | 657 ++++++++++++++++++++++ src/vnet/l2/l2_patch.c | 452 +++++++++++++++ src/vnet/l2/l2_rw.c | 719 ++++++++++++++++++++++++ src/vnet/l2/l2_rw.h | 95 ++++ src/vnet/l2/l2_vtr.c | 770 ++++++++++++++++++++++++++ src/vnet/l2/l2_vtr.h | 270 +++++++++ src/vnet/l2/l2_xcrw.c | 591 ++++++++++++++++++++ src/vnet/l2/l2_xcrw.h | 91 ++++ 37 files changed, 13596 insertions(+) create mode 100644 src/vnet/l2/dir.dox create mode 100644 src/vnet/l2/feat_bitmap.c create mode 100644 src/vnet/l2/feat_bitmap.h create mode 100644 src/vnet/l2/l2.api create mode 100644 src/vnet/l2/l2_api.c create mode 100644 src/vnet/l2/l2_bd.c create mode 100644 src/vnet/l2/l2_bd.h create mode 100644 src/vnet/l2/l2_bvi.c create mode 100644 src/vnet/l2/l2_bvi.h create mode 100644 src/vnet/l2/l2_classify.h create mode 100644 src/vnet/l2/l2_efp_filter.c create mode 100644 src/vnet/l2/l2_efp_filter.h create mode 100644 src/vnet/l2/l2_fib.c create mode 100644 src/vnet/l2/l2_fib.h create mode 100644 src/vnet/l2/l2_flood.c create mode 100644 src/vnet/l2/l2_flood.h create mode 100644 src/vnet/l2/l2_fwd.c create mode 100644 src/vnet/l2/l2_fwd.h create mode 100644 src/vnet/l2/l2_input.c create mode 100644 src/vnet/l2/l2_input.h create mode 100644 src/vnet/l2/l2_input_acl.c create mode 100644 src/vnet/l2/l2_input_classify.c create mode 100644 src/vnet/l2/l2_input_vtr.c create mode 100644 src/vnet/l2/l2_input_vtr.h create mode 100644 src/vnet/l2/l2_learn.c create mode 100644 src/vnet/l2/l2_learn.h create mode 100644 src/vnet/l2/l2_output.c create mode 100644 src/vnet/l2/l2_output.h create mode 100644 src/vnet/l2/l2_output_acl.c create mode 100644 src/vnet/l2/l2_output_classify.c create mode 100644 src/vnet/l2/l2_patch.c create mode 100644 src/vnet/l2/l2_rw.c create mode 100644 src/vnet/l2/l2_rw.h create mode 100644 src/vnet/l2/l2_vtr.c create mode 100644 src/vnet/l2/l2_vtr.h create mode 100644 src/vnet/l2/l2_xcrw.c create mode 100644 src/vnet/l2/l2_xcrw.h (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/dir.dox b/src/vnet/l2/dir.dox new file mode 100644 index 00000000..8497a2f6 --- /dev/null +++ b/src/vnet/l2/dir.dox @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 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. + */ + +/** +@dir +@brief Layer 2 Forwarding Code. + +This directory contains the source code for basic Layer 2 forwarding. + +*/ +/*? %%clicmd:group_label Layer 2 CLI %% ?*/ diff --git a/src/vnet/l2/feat_bitmap.c b/src/vnet/l2/feat_bitmap.c new file mode 100644 index 00000000..6c046467 --- /dev/null +++ b/src/vnet/l2/feat_bitmap.c @@ -0,0 +1,185 @@ +/* + * feat_bitmap.c: bitmap for managing feature invocation + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* + * Drop node for feature bitmaps + * For features that just do a drop, or are not yet implemented. + * Initial feature dispatch nodes don't need to set b0->error + * in case of a possible drop because that will be done here. + *The next node is always error-drop. + */ + +static vlib_node_registration_t feat_bitmap_drop_node; + +#define foreach_feat_bitmap_drop_error \ +_(NO_FWD, "L2 feature forwarding disabled") \ +_(NYI, "L2 feature not implemented") + +typedef enum +{ +#define _(sym,str) FEAT_BITMAP_DROP_ERROR_##sym, + foreach_feat_bitmap_drop_error +#undef _ + FEAT_BITMAP_DROP_N_ERROR, +} feat_bitmap_drop_error_t; + +static char *feat_bitmap_drop_error_strings[] = { +#define _(sym,string) string, + foreach_feat_bitmap_drop_error +#undef _ +}; + +typedef enum +{ + FEAT_BITMAP_DROP_NEXT_DROP, + FEAT_BITMAP_DROP_N_NEXT, +} feat_bitmap_drop_next_t; + +typedef struct +{ + u32 feature_bitmap; +} feat_bitmap_drop_trace_t; + +/* packet trace format function */ +static u8 * +format_feat_bitmap_drop_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + feat_bitmap_drop_trace_t *t = va_arg (*args, feat_bitmap_drop_trace_t *); + + s = + format (s, "feat_bitmap_drop: feature bitmap 0x%08x", t->feature_bitmap); + return s; +} + +static uword +feat_bitmap_drop_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + feat_bitmap_drop_next_t next_index; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + feat_bitmap_drop_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->feature_bitmap = vnet_buffer (b0)->l2.feature_bitmap; + } + + if (vnet_buffer (b0)->l2.feature_bitmap == 1) + { + /* + * If we are executing the last feature, this is the + * No forwarding catch-all + */ + b0->error = node->errors[FEAT_BITMAP_DROP_ERROR_NO_FWD]; + } + else + { + b0->error = node->errors[FEAT_BITMAP_DROP_ERROR_NYI]; + } + next0 = FEAT_BITMAP_DROP_NEXT_DROP; + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + return frame->n_vectors; +} + +clib_error_t * +feat_bitmap_drop_init (vlib_main_t * vm) +{ + return 0; +} + +VLIB_INIT_FUNCTION (feat_bitmap_drop_init); + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (feat_bitmap_drop_node,static) = { + .function = feat_bitmap_drop_node_fn, + .name = "feature-bitmap-drop", + .vector_size = sizeof (u32), + .format_trace = format_feat_bitmap_drop_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(feat_bitmap_drop_error_strings), + .error_strings = feat_bitmap_drop_error_strings, + + .n_next_nodes = FEAT_BITMAP_DROP_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [FEAT_BITMAP_DROP_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/feat_bitmap.h b/src/vnet/l2/feat_bitmap.h new file mode 100644 index 00000000..c6e02ecc --- /dev/null +++ b/src/vnet/l2/feat_bitmap.h @@ -0,0 +1,96 @@ +/* + * feat_bitmap.h: bitmap for managing feature invocation + * + * Copyright (c) 2013 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_vnet_l2_feat_bitmap_h +#define included_vnet_l2_feat_bitmap_h + +#include +#include + +/* + * The feature bitmap is a way of organizing input and output feature graph nodes. + * The set of features to be executed are arranged in a bitmap with one bit per + * feature and each bit positioned in the same order that the features should be + * executed. Features can be dynamically removed from the set by masking off their + * corresponding bits. The bitmap is stored in packet context. Each feature clears + * its bit and then calls feat_bitmap_get_next_node_index() to go to the next + * graph node. + */ + + +/* 32 features in a u32 bitmap */ +#define FEAT_MAX 32 + +/** + Initialize the feature next-node indexes of a graph node. + Should be called by the init function of each feature graph node. +*/ +always_inline void +feat_bitmap_init_next_nodes (vlib_main_t * vm, u32 node_index, /* the current graph node index */ + u32 num_features, /* number of entries in feat_names */ + char **feat_names, /* array of feature graph node names */ + u32 * next_nodes) /* array of 32 next indexes to init */ +{ + u32 idx; + + ASSERT (num_features <= FEAT_MAX); + + for (idx = 0; idx < num_features; idx++) + { + if (vlib_get_node_by_name (vm, (u8 *) feat_names[idx])) + { + next_nodes[idx] = + vlib_node_add_named_next (vm, node_index, feat_names[idx]); + } + else + { // Node may be in plugin which is not installed, use drop node + next_nodes[idx] = + vlib_node_add_named_next (vm, node_index, "feature-bitmap-drop"); + } + } + + /* All unassigned bits go to the drop node */ + for (; idx < FEAT_MAX; idx++) + { + next_nodes[idx] = vlib_node_add_named_next (vm, node_index, + "feature-bitmap-drop"); + } +} + +/** + Return the graph node index for the feature corresponding to the + first set bit in the bitmap. +*/ +always_inline + u32 feat_bitmap_get_next_node_index (u32 * next_nodes, u32 bitmap) +{ + u32 first_bit; + + count_leading_zeros (first_bit, bitmap); + first_bit = uword_bits - 1 - first_bit; + return next_nodes[first_bit]; +} + +#endif /* included_vnet_l2_feat_bitmap_h */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api new file mode 100644 index 00000000..5fce7944 --- /dev/null +++ b/src/vnet/l2/l2.api @@ -0,0 +1,38 @@ +/* Hey Emacs use -*- mode: C -*- */ +/* + * 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. + */ + +/** \brief Reply to l2_xconnect_dump + @param context - sender context which was passed in the request + @param rx_sw_if_index - Receive interface index + @param tx_sw_if_index - Transmit interface index + */ +define l2_xconnect_details +{ + u32 context; + u32 rx_sw_if_index; + u32 tx_sw_if_index; +}; + +/** \brief Dump L2 XConnects + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define l2_xconnect_dump +{ + u32 client_index; + u32 context; +}; + diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c new file mode 100644 index 00000000..ca4f593f --- /dev/null +++ b/src/vnet/l2/l2_api.c @@ -0,0 +1,140 @@ +/* + *------------------------------------------------------------------ + * l2_api.c - layer 2 forwarding api + * + * 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 +#include +#include + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +#include + +#define foreach_vpe_api_msg \ +_(L2_XCONNECT_DUMP, l2_xconnect_dump) + +static void +send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context, + u32 rx_sw_if_index, u32 tx_sw_if_index) +{ + vl_api_l2_xconnect_details_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_L2_XCONNECT_DETAILS); + mp->context = context; + mp->rx_sw_if_index = htonl (rx_sw_if_index); + mp->tx_sw_if_index = htonl (tx_sw_if_index); + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + vnet_main_t *vnm = vnet_get_main (); + vnet_interface_main_t *im = &vnm->interface_main; + l2input_main_t *l2im = &l2input_main; + vnet_sw_interface_t *swif; + l2_input_config_t *config; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + /* *INDENT-OFF* */ + pool_foreach (swif, im->sw_interfaces, + ({ + config = vec_elt_at_index (l2im->configs, swif->sw_if_index); + if (config->xconnect) + send_l2_xconnect_details (q, mp->context, swif->sw_if_index, + config->output_sw_if_index); + })); + /* *INDENT-ON* */ +} + + +/* + * vpe_api_hookup + * Add vpe's API message handlers to the table. + * vlib has alread mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (api_main_t * am) +{ +#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); + foreach_vl_msg_name_crc_l2; +#undef _ +} + +static clib_error_t * +l2_api_hookup (vlib_main_t * vm) +{ + api_main_t *am = &api_main; + +#define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_vpe_api_msg; +#undef _ + + /* + * Set up the (msg_name, crc, message-id) table + */ + setup_message_id_table (am); + + return 0; +} + +VLIB_API_INIT_FUNCTION (l2_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c new file mode 100644 index 00000000..22f83d0b --- /dev/null +++ b/src/vnet/l2/l2_bd.c @@ -0,0 +1,1079 @@ +/* + * l2_bd.c : layer 2 bridge domain + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + * @file + * @brief Ethernet Bridge Domain. + * + * Code in this file manages Layer 2 bridge domains. + * + */ + +bd_main_t bd_main; + +/** + Init bridge domain if not done already. + For feature bitmap, set all bits except ARP termination +*/ +void +bd_validate (l2_bridge_domain_t * bd_config) +{ + if (!bd_is_valid (bd_config)) + { + bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; + bd_config->bvi_sw_if_index = ~0; + bd_config->members = 0; + bd_config->flood_count = 0; + bd_config->tun_master_count = 0; + bd_config->tun_normal_count = 0; + bd_config->mac_by_ip4 = 0; + bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), + sizeof (uword)); + } +} + +u32 +bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + uword *p; + u32 rv; + + if (bd_id == ~0) + { + bd_id = 0; + while (hash_get (bdm->bd_index_by_bd_id, bd_id)) + bd_id++; + } + else + { + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + return (p[0]); + } + + rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); + + /* mark this index busy */ + bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1); + + hash_set (bdm->bd_index_by_bd_id, bd_id, rv); + + vec_validate (l2input_main.bd_configs, rv); + l2input_main.bd_configs[rv].bd_id = bd_id; + + return rv; +} + +int +bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) +{ + uword *p; + u32 bd_index; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + return -1; + + bd_index = p[0]; + + /* mark this index clear */ + bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); + hash_unset (bdm->bd_index_by_bd_id, bd_id); + + l2input_main.bd_configs[bd_index].bd_id = ~0; + l2input_main.bd_configs[bd_index].feature_bitmap = 0; + + return 0; +} + +static void +update_flood_count (l2_bridge_domain_t * bd_config) +{ + bd_config->flood_count = vec_len (bd_config->members) - + (bd_config->tun_master_count ? bd_config->tun_normal_count : 0); +} + +void +bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member) +{ + u32 ix; + vnet_sw_interface_t *sw_if = vnet_get_sw_interface + (vnet_get_main (), member->sw_if_index); + + /* + * Add one element to the vector + * vector is ordered [ bvi, normal/tun_masters..., tun_normals... ] + * When flooding, the bvi interface (if present) must be the last member + * processed due to how BVI processing can change the packet. To enable + * this order, we make the bvi interface the first in the vector and + * flooding walks the vector in reverse. + */ + switch (sw_if->flood_class) + { + case VNET_FLOOD_CLASS_TUNNEL_MASTER: + bd_config->tun_master_count++; + /* Fall through */ + default: + /* Fall through */ + case VNET_FLOOD_CLASS_NORMAL: + ix = (member->flags & L2_FLOOD_MEMBER_BVI) ? 0 : + vec_len (bd_config->members) - bd_config->tun_normal_count; + break; + case VNET_FLOOD_CLASS_TUNNEL_NORMAL: + ix = vec_len (bd_config->members); + bd_config->tun_normal_count++; + break; + } + + vec_insert_elts (bd_config->members, member, 1, ix); + update_flood_count (bd_config); +} + +#define BD_REMOVE_ERROR_OK 0 +#define BD_REMOVE_ERROR_NOT_FOUND 1 + +u32 +bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index) +{ + u32 ix; + + /* Find and delete the member */ + vec_foreach_index (ix, bd_config->members) + { + l2_flood_member_t *m = vec_elt_at_index (bd_config->members, ix); + if (m->sw_if_index == sw_if_index) + { + vnet_sw_interface_t *sw_if = vnet_get_sw_interface + (vnet_get_main (), sw_if_index); + + if (sw_if->flood_class != VNET_FLOOD_CLASS_NORMAL) + { + if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_MASTER) + bd_config->tun_master_count--; + else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL) + bd_config->tun_normal_count--; + } + vec_del1 (bd_config->members, ix); + update_flood_count (bd_config); + + return BD_REMOVE_ERROR_OK; + } + } + + return BD_REMOVE_ERROR_NOT_FOUND; +} + + +clib_error_t * +l2bd_init (vlib_main_t * vm) +{ + bd_main_t *bdm = &bd_main; + u32 bd_index; + bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword)); + /* + * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set + * to packet drop only. Thus, packets received from any L2 interface with + * uninitialized bd_index of 0 can be dropped safely. + */ + bd_index = bd_find_or_add_bd_index (bdm, 0); + ASSERT (bd_index == 0); + l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; + return 0; +} + +VLIB_INIT_FUNCTION (l2bd_init); + + +/** + Set the learn/forward/flood flags for the bridge domain. + Return 0 if ok, non-zero if for an error. +*/ +u32 +bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) +{ + + l2_bridge_domain_t *bd_config; + u32 feature_bitmap = 0; + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + + bd_validate (bd_config); + + if (flags & L2_LEARN) + { + feature_bitmap |= L2INPUT_FEAT_LEARN; + } + if (flags & L2_FWD) + { + feature_bitmap |= L2INPUT_FEAT_FWD; + } + if (flags & L2_FLOOD) + { + feature_bitmap |= L2INPUT_FEAT_FLOOD; + } + if (flags & L2_UU_FLOOD) + { + feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + } + if (flags & L2_ARP_TERM) + { + feature_bitmap |= L2INPUT_FEAT_ARP_TERM; + } + + if (enable) + { + bd_config->feature_bitmap |= feature_bitmap; + } + else + { + bd_config->feature_bitmap &= ~feature_bitmap; + } + + return 0; +} + +/** + Set the mac age for the bridge domain. +*/ +void +bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) +{ + l2_bridge_domain_t *bd_config; + int enable = 0; + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config->mac_age = age; + + /* check if there is at least one bd with mac aging enabled */ + vec_foreach (bd_config, l2input_main.bd_configs) + if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) + enable = 1; + + vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, + enable ? L2_MAC_AGE_PROCESS_EVENT_START : + L2_MAC_AGE_PROCESS_EVENT_STOP, 0); +} + +/** + Set bridge-domain learn enable/disable. + The CLI format is: + set bridge-domain learn [disable] +*/ +static clib_error_t * +bd_learn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_LEARN, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 learning can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable learning (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain learn 200} + * Example of how to disable learning (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain learn 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_learn_cli, static) = { + .path = "set bridge-domain learn", + .short_help = "set bridge-domain learn [disable]", + .function = bd_learn, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain forward enable/disable. + The CLI format is: + set bridge-domain forward [disable] +*/ +static clib_error_t * +bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_FWD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + + +/*? + * Layer 2 unicast forwarding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable forwarding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain forward 200} + * Example of how to disable forwarding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain forward 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_fwd_cli, static) = { + .path = "set bridge-domain forward", + .short_help = "set bridge-domain forward [disable]", + .function = bd_fwd, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain flood enable/disable. + The CLI format is: + set bridge-domain flood [disable] +*/ +static clib_error_t * +bd_flood (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_FLOOD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 flooding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage bridge-domains. It is enabled by default. + * + * @cliexpar + * Example of how to enable flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200} + * Example of how to disable flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_flood_cli, static) = { + .path = "set bridge-domain flood", + .short_help = "set bridge-domain flood [disable]", + .function = bd_flood, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain unkown-unicast flood enable/disable. + The CLI format is: + set bridge-domain uu-flood [disable] +*/ +static clib_error_t * +bd_uu_flood (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +/*? + * Layer 2 unknown-unicast flooding can be enabled and disabled on each + * bridge-domain. It is enabled by default. + * + * @cliexpar + * Example of how to enable unknown-unicast flooding (where 200 is the + * bridge-domain-id): + * @cliexcmd{set bridge-domain uu-flood 200} + * Example of how to disable unknown-unicast flooding (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain uu-flood 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_uu_flood_cli, static) = { + .path = "set bridge-domain uu-flood", + .short_help = "set bridge-domain uu-flood [disable]", + .function = bd_uu_flood, +}; +/* *INDENT-ON* */ + +/** + Set bridge-domain arp term enable/disable. + The CLI format is: + set bridge-domain arp term [disable] +*/ +static clib_error_t * +bd_arp_term (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 enable; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + enable = 1; + if (unformat (input, "disable")) + enable = 0; + + /* set the bridge domain flag */ + if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable)) + { + error = + clib_error_return (0, "bridge-domain id %d out of range", bd_index); + goto done; + } + +done: + return error; +} + +static clib_error_t * +bd_mac_age (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 age; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p == 0) + return clib_error_return (0, "No such bridge domain %d", bd_id); + + bd_index = p[0]; + + if (!unformat (input, "%u", &age)) + { + error = + clib_error_return (0, "expecting ageing time in minutes but got `%U'", + format_unformat_error, input); + goto done; + } + + /* set the bridge domain flag */ + if (age > 255) + { + error = + clib_error_return (0, "mac aging time cannot be bigger than 255"); + goto done; + } + bd_set_mac_age (vm, bd_index, (u8) age); + +done: + return error; +} + +/*? + * Layer 2 mac aging can be enabled and disabled on each + * bridge-domain. Use this command to set or disable mac aging + * on specific bridge-domains. It is disabled by default. + * + * @cliexpar + * Example of how to set mac aging (where 200 is the bridge-domain-id and + * 5 is aging time in minutes): + * @cliexcmd{set bridge-domain mac-age 200 5} + * Example of how to disable mac aging (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain flood 200 0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_mac_age_cli, static) = { + .path = "set bridge-domain mac-age", + .short_help = "set bridge-domain mac-age ", + .function = bd_mac_age, +}; +/* *INDENT-ON* */ + +/*? + * Modify whether or not an existing bridge-domain should terminate and respond + * to ARP Requests. ARP Termination is disabled by default. + * + * @cliexpar + * Example of how to enable ARP termination (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp term 200} + * Example of how to disable ARP termination (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp term 200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_arp_term_cli, static) = { + .path = "set bridge-domain arp term", + .short_help = "set bridge-domain arp term [disable]", + .function = bd_arp_term, +}; +/* *INDENT-ON* */ + + +/** + * Add/delete IP address to MAC address mapping. + * + * The clib hash implementation stores uword entries in the hash table. + * The hash table mac_by_ip4 is keyed via IP4 address and store the + * 6-byte MAC address directly in the hash table entry uword. + * + * @warning This only works for 64-bit processor with 8-byte uword; + * which means this code *WILL NOT WORK* for a 32-bit prcessor with + * 4-byte uword. + */ +u32 +bd_add_del_ip_mac (u32 bd_index, + u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add) +{ + l2input_main_t *l2im = &l2input_main; + l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index); + u64 new_mac = *(u64 *) mac_addr; + u64 *old_mac; + u16 *mac16 = (u16 *) & new_mac; + + ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */ + + mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */ + if (is_ip6) + { + ip6_address_t *ip6_addr_key; + hash_pair_t *hp; + old_mac = (u64 *) hash_get_mem (bd_cfg->mac_by_ip6, ip_addr); + if (is_add) + { + if (old_mac == 0) + { /* new entry - allocate and craete ip6 address key */ + ip6_addr_key = clib_mem_alloc (sizeof (ip6_address_t)); + clib_memcpy (ip6_addr_key, ip_addr, sizeof (ip6_address_t)); + } + else if (*old_mac == new_mac) + { /* same mac entry already exist for ip6 address */ + return 0; + } + else + { /* updat mac for ip6 address */ + hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr); + ip6_addr_key = (ip6_address_t *) hp->key; + } + hash_set_mem (bd_cfg->mac_by_ip6, ip6_addr_key, new_mac); + } + else + { + if (old_mac && (*old_mac == new_mac)) + { + hp = hash_get_pair (bd_cfg->mac_by_ip6, ip_addr); + ip6_addr_key = (ip6_address_t *) hp->key; + hash_unset_mem (bd_cfg->mac_by_ip6, ip_addr); + clib_mem_free (ip6_addr_key); + } + else + return 1; + } + } + else + { + ip4_address_t ip4_addr = *(ip4_address_t *) ip_addr; + old_mac = (u64 *) hash_get (bd_cfg->mac_by_ip4, ip4_addr.as_u32); + if (is_add) + { + if (old_mac && (*old_mac == new_mac)) + return 0; /* mac entry already exist */ + hash_set (bd_cfg->mac_by_ip4, ip4_addr.as_u32, new_mac); + } + else + { + if (old_mac && (*old_mac == new_mac)) + hash_unset (bd_cfg->mac_by_ip4, ip4_addr.as_u32); + else + return 1; + } + } + return 0; +} + +/** + Set bridge-domain arp entry add/delete. + The CLI format is: + set bridge-domain arp entry [del] +*/ +static clib_error_t * +bd_arp_entry (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + u8 is_add = 1; + u8 is_ip6 = 0; + u8 ip_addr[16]; + u8 mac_addr[6]; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + if (unformat (input, "%U", unformat_ip4_address, ip_addr)) + { + is_ip6 = 0; + } + else if (unformat (input, "%U", unformat_ip6_address, ip_addr)) + { + is_ip6 = 1; + } + else + { + error = clib_error_return (0, "expecting IP address but got `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%U", unformat_ethernet_address, mac_addr)) + { + error = clib_error_return (0, "expecting MAC address but got `%U'", + format_unformat_error, input); + goto done; + } + + if (unformat (input, "del")) + { + is_add = 0; + } + + /* set the bridge domain flagAdd IP-MAC entry into bridge domain */ + if (bd_add_del_ip_mac (bd_index, ip_addr, mac_addr, is_ip6, is_add)) + { + error = clib_error_return (0, "MAC %s for IP %U and MAC %U failed", + is_add ? "add" : "del", + is_ip6 ? + format_ip4_address : format_ip6_address, + ip_addr, format_ethernet_address, mac_addr); + } + +done: + return error; +} + +/*? + * Add an ARP entry to an existing bridge-domain. + * + * @cliexpar + * Example of how to add an ARP entry (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a} + * Example of how to delete an ARP entry (where 200 is the bridge-domain-id): + * @cliexcmd{set bridge-domain arp entry 200 192.168.72.45 52:54:00:3b:83:1a del} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_arp_entry_cli, static) = { + .path = "set bridge-domain arp entry", + .short_help = "set bridge-domain arp entry [del]", + .function = bd_arp_entry, +}; +/* *INDENT-ON* */ + +u8 * +format_vtr (u8 * s, va_list * args) +{ + u32 vtr_op = va_arg (*args, u32); + u32 dot1q = va_arg (*args, u32); + u32 tag1 = va_arg (*args, u32); + u32 tag2 = va_arg (*args, u32); + switch (vtr_op) + { + case L2_VTR_DISABLED: + return format (s, "none"); + case L2_VTR_PUSH_1: + return format (s, "push-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_PUSH_2: + return format (s, "push-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", tag1, + tag2); + case L2_VTR_POP_1: + return format (s, "pop-1"); + case L2_VTR_POP_2: + return format (s, "pop-2"); + case L2_VTR_TRANSLATE_1_1: + return format (s, "trans-1-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_TRANSLATE_1_2: + return format (s, "trans-1-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", + tag1, tag2); + case L2_VTR_TRANSLATE_2_1: + return format (s, "trans-2-1 %s %d", dot1q ? "dot1q" : "dot1ad", tag1); + case L2_VTR_TRANSLATE_2_2: + return format (s, "trans-2-2 %s %d %d", dot1q ? "dot1q" : "dot1ad", + tag1, tag2); + default: + return format (s, "none"); + } +} + +/** + Show bridge-domain state. + The CLI format is: + show bridge-domain [] +*/ +static clib_error_t * +bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index = ~0; + l2_bridge_domain_t *bd_config; + u32 start, end; + u32 printed; + u32 detail = 0; + u32 intf = 0; + u32 arp = 0; + u32 bd_id = ~0; + uword *p; + + start = 0; + end = vec_len (l2input_main.bd_configs); + + if (unformat (input, "%d", &bd_id)) + { + if (unformat (input, "detail")) + detail = 1; + else if (unformat (input, "det")) + detail = 1; + if (unformat (input, "int")) + intf = 1; + if (unformat (input, "arp")) + arp = 1; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + if (bd_is_valid (bd_config)) + { + start = bd_index; + end = start + 1; + } + else + { + vlib_cli_output (vm, "bridge-domain %d not in use", bd_id); + goto done; + } + } + + /* Show all bridge-domains that have been initialized */ + printed = 0; + for (bd_index = start; bd_index < end; bd_index++) + { + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + if (bd_is_valid (bd_config)) + { + if (!printed) + { + printed = 1; + vlib_cli_output (vm, + "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s", + "ID", "Index", "Learning", "U-Forwrd", + "UU-Flood", "Flooding", "ARP-Term", + "BVI-Intf"); + } + + vlib_cli_output (vm, + "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U", + bd_config->bd_id, bd_index, + bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on" + : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ? + "on" : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ? + "on" : "off", format_vnet_sw_if_index_name_with_NA, + vnm, bd_config->bvi_sw_if_index); + + if (detail || intf) + { + /* Show all member interfaces */ + int i; + vec_foreach_index (i, bd_config->members) + { + l2_flood_member_t *member = + vec_elt_at_index (bd_config->members, i); + u32 vtr_opr, dot1q, tag1, tag2; + if (i == 0) + { + vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=9s%=30s", + "Interface", "Index", "SHG", "BVI", + "TxFlood", "VLAN-Tag-Rewrite"); + } + l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q, + &tag1, &tag2); + vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=9s%=30U", + format_vnet_sw_if_index_name, vnm, + member->sw_if_index, member->sw_if_index, + member->shg, + member->flags & L2_FLOOD_MEMBER_BVI ? "*" : + "-", i < bd_config->flood_count ? "*" : "-", + format_vtr, vtr_opr, dot1q, tag1, tag2); + } + } + + if ((detail || arp) && + (bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM)) + { + u32 ip4_addr; + ip6_address_t *ip6_addr; + u64 mac_addr; + vlib_cli_output (vm, + "\n IP4/IP6 to MAC table for ARP Termination"); + + /* *INDENT-OFF* */ + hash_foreach (ip4_addr, mac_addr, bd_config->mac_by_ip4, + ({ + vlib_cli_output (vm, "%=40U => %=20U", + format_ip4_address, &ip4_addr, + format_ethernet_address, &mac_addr); + })); + + hash_foreach_mem (ip6_addr, mac_addr, bd_config->mac_by_ip6, + ({ + vlib_cli_output (vm, "%=40U => %=20U", + format_ip6_address, ip6_addr, + format_ethernet_address, &mac_addr); + })); + /* *INDENT-ON* */ + } + } + } + + if (!printed) + { + vlib_cli_output (vm, "no bridge-domains in use"); + } + +done: + return error; +} + +/*? + * Show a summary of all the bridge-domain instances or detailed view of a + * single bridge-domain. Bridge-domains are created by adding an interface + * to a bridge using the 'set interface l2 bridge' command. + * + * @cliexpar + * @parblock + * Example of displaying all bridge-domains: + * @cliexstart{show bridge-domain} + * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 0 0 off off off off off local0 + * 200 1 on on on on off N/A + * @cliexend + * + * Example of displaying details of a single bridge-domains: + * @cliexstart{show bridge-domain 200 detail} + * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 200 1 on on on on off N/A + * + * Interface Index SHG BVI VLAN-Tag-Rewrite + * GigabitEthernet0/8/0.200 3 0 - none + * GigabitEthernet0/9/0.200 4 0 - none + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_show_cli, static) = { + .path = "show bridge-domain", + .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]", + .function = bd_show, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h new file mode 100644 index 00000000..4bb9bc9b --- /dev/null +++ b/src/vnet/l2/l2_bd.h @@ -0,0 +1,150 @@ +/* + * l2_bd.h : layer 2 bridge domain + * + * Copyright (c) 2013 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_l2bd_h +#define included_l2bd_h + +#include +#include + +typedef struct +{ + /* hash bd_id -> bd_index */ + uword *bd_index_by_bd_id; + + /* Busy bd_index bitmap */ + uword *bd_index_bitmap; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} bd_main_t; + +bd_main_t bd_main; + +/* Bridge domain member */ + +#define L2_FLOOD_MEMBER_NORMAL 0 +#define L2_FLOOD_MEMBER_BVI 1 + +typedef struct +{ + u32 sw_if_index; /* the output L2 interface */ + u8 flags; /* 0=normal, 1=bvi */ + u8 shg; /* split horizon group number */ + u16 spare; +} l2_flood_member_t; + + +/* Per-bridge domain configuration */ + +typedef struct +{ + u32 feature_bitmap; + /* + * Contains bit enables for flooding, learning, and forwarding. + * All other feature bits should always be set. + * + * identity of the bridge-domain's BVI interface + * set to ~0 if there is no BVI + */ + u32 bvi_sw_if_index; + + /* bridge domain id, not to be confused with bd_index */ + u32 bd_id; + + /* Vector of member ports */ + l2_flood_member_t *members; + + /* First flood_count member ports are flooded */ + u32 flood_count; + + /* Tunnel Master (Multicast vxlan) are always flooded */ + u32 tun_master_count; + + /* Tunnels (Unicast vxlan) are flooded if there are no masters */ + u32 tun_normal_count; + + /* hash ip4/ip6 -> mac for arp/nd termination */ + uword *mac_by_ip4; + uword *mac_by_ip6; + + /* mac aging */ + u8 mac_age; + +} l2_bridge_domain_t; + +/* Return 1 if bridge domain has been initialized */ +always_inline u32 +bd_is_valid (l2_bridge_domain_t * bd_config) +{ + return (bd_config->feature_bitmap != 0); +} + +/* Init bridge domain if not done already */ +void bd_validate (l2_bridge_domain_t * bd_config); + + +void +bd_add_member (l2_bridge_domain_t * bd_config, l2_flood_member_t * member); + +u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); + + +#define L2_LEARN (1<<0) +#define L2_FWD (1<<1) +#define L2_FLOOD (1<<2) +#define L2_UU_FLOOD (1<<3) +#define L2_ARP_TERM (1<<4) + +u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); +void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); + +/** + * \brief Get or create a bridge domain. + * + * Get or create a bridge domain with the given bridge domain ID. + * + * \param bdm bd_main pointer. + * \param bd_id The bridge domain ID or ~0 if an arbitrary unused bridge domain should be used. + * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. + */ +u32 bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id); + +/** + * \brief Delete a bridge domain. + * + * Delete an existing bridge domain with the given bridge domain ID. + * + * \param bdm bd_main pointer. + * \param bd_id The bridge domain ID. + * \return 0 on success and -1 if the bridge domain does not exist. + */ +int bd_delete_bd_index (bd_main_t * bdm, u32 bd_id); + +u32 bd_add_del_ip_mac (u32 bd_index, + u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_bvi.c b/src/vnet/l2/l2_bvi.c new file mode 100644 index 00000000..f239743a --- /dev/null +++ b/src/vnet/l2/l2_bvi.c @@ -0,0 +1,40 @@ +/* + * l2_bvi.c : layer 2 Bridged Virtual Interface + * + * Copyright (c) 2013 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 +#include +#include + + +/* Call the L2 nodes that need the ethertype mapping */ +void +l2bvi_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index) +{ + l2fwd_register_input_type (vm, type, node_index); + l2flood_register_input_type (vm, type, node_index); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_bvi.h b/src/vnet/l2/l2_bvi.h new file mode 100644 index 00000000..dd1130a6 --- /dev/null +++ b/src/vnet/l2/l2_bvi.h @@ -0,0 +1,117 @@ +/* + * l2_bvi.h : layer 2 Bridged Virtual Interface + * + * Copyright (c) 2013 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_l2bvi_h +#define included_l2bvi_h + +#include +#include +#include + +#include + +#define TO_BVI_ERR_OK 0 +#define TO_BVI_ERR_BAD_MAC 1 +#define TO_BVI_ERR_ETHERTYPE 2 + +/** + * Send a packet from L2 processing to L3 via the BVI interface. + * Set next0 to the proper L3 input node. + * Return an error if the packet isn't what we expect. + */ + +static_always_inline u32 +l2_to_bvi (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, + vlib_buffer_t * b0, + u32 bvi_sw_if_index, next_by_ethertype_t * l3_next, u32 * next0) +{ + u8 l2_len; + u16 ethertype; + u8 *l3h; + ethernet_header_t *e0; + vnet_hw_interface_t *hi; + + e0 = vlib_buffer_get_current (b0); + hi = vnet_get_sup_hw_interface (vnet_main, bvi_sw_if_index); + + /* Perform L3 my-mac filter */ + if ((!ethernet_address_cast (e0->dst_address)) && + (!eth_mac_equal ((u8 *) e0, hi->hw_address))) + { + return TO_BVI_ERR_BAD_MAC; + } + + /* Save L2 header position which may be changed due to packet replication */ + vnet_buffer (b0)->ethernet.start_of_ethernet_header = b0->current_data; + + /* Strip L2 header */ + l2_len = vnet_buffer (b0)->l2.l2_len; + vlib_buffer_advance (b0, l2_len); + + l3h = vlib_buffer_get_current (b0); + ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2)); + + /* Set the input interface to be the BVI interface */ + vnet_buffer (b0)->sw_if_index[VLIB_RX] = bvi_sw_if_index; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + + /* Go to appropriate L3 input node */ + if (ethertype == ETHERNET_TYPE_IP4) + { + *next0 = l3_next->input_next_ip4; + } + else if (ethertype == ETHERNET_TYPE_IP6) + { + *next0 = l3_next->input_next_ip6; + } + else + { + /* uncommon ethertype, check table */ + u32 i0; + + i0 = sparse_vec_index (l3_next->input_next_by_type, ethertype); + *next0 = vec_elt (l3_next->input_next_by_type, i0); + + if (i0 == SPARSE_VEC_INVALID_INDEX) + { + return TO_BVI_ERR_ETHERTYPE; + } + } + + /* increment BVI RX interface stat */ + vlib_increment_combined_counter + (vnet_main->interface_main.combined_sw_if_counters + + VNET_INTERFACE_COUNTER_RX, + vlib_main->cpu_index, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + 1, vlib_buffer_length_in_chain (vlib_main, b0)); + return TO_BVI_ERR_OK; +} + +void +l2bvi_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index); +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_classify.h b/src/vnet/l2/l2_classify.h new file mode 100644 index 00000000..184187ff --- /dev/null +++ b/src/vnet/l2/l2_classify.h @@ -0,0 +1,116 @@ +/* + * 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_vnet_l2_input_classify_h__ +#define __included_vnet_l2_input_classify_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef enum +{ + L2_INPUT_CLASSIFY_NEXT_DROP, + L2_INPUT_CLASSIFY_NEXT_ETHERNET_INPUT, + L2_INPUT_CLASSIFY_NEXT_IP4_INPUT, + L2_INPUT_CLASSIFY_NEXT_IP6_INPUT, + L2_INPUT_CLASSIFY_NEXT_LI, + L2_INPUT_CLASSIFY_N_NEXT, +} l2_input_classify_next_t; + +typedef enum +{ + L2_INPUT_CLASSIFY_TABLE_IP4, + L2_INPUT_CLASSIFY_TABLE_IP6, + L2_INPUT_CLASSIFY_TABLE_OTHER, + L2_INPUT_CLASSIFY_N_TABLES, +} l2_input_classify_table_id_t; + +typedef enum +{ + L2_OUTPUT_CLASSIFY_NEXT_DROP, + L2_OUTPUT_CLASSIFY_N_NEXT, +} l2_output_classify_next_t; + +typedef enum +{ + L2_OUTPUT_CLASSIFY_TABLE_IP4, + L2_OUTPUT_CLASSIFY_TABLE_IP6, + L2_OUTPUT_CLASSIFY_TABLE_OTHER, + L2_OUTPUT_CLASSIFY_N_TABLES, +} l2_output_classify_table_id_t; + +typedef struct _l2_classify_main +{ + /* Next nodes for each feature */ + u32 feat_next_node_index[32]; + + /* Per-address-family classifier table vectors */ + u32 *classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_N_TABLES]; + + /* Next nodes for features and output interfaces */ + l2_output_next_nodes_st next_nodes; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; + vnet_classify_main_t *vnet_classify_main; +} l2_input_classify_main_t; + +typedef struct _l2_classify_main l2_output_classify_main_t; + +extern l2_input_classify_main_t l2_input_classify_main; +extern vlib_node_registration_t l2_input_classify_node; + +extern l2_output_classify_main_t l2_output_classify_main; +extern vlib_node_registration_t l2_output_classify_node; + +void vnet_l2_input_classify_enable_disable (u32 sw_if_index, + int enable_disable); + +int vnet_l2_input_classify_set_tables (u32 sw_if_index, u32 ip4_table_index, + u32 ip6_table_index, + u32 other_table_index); + +void vnet_l2_output_classify_enable_disable (u32 sw_if_index, + int enable_disable); + +int vnet_l2_output_classify_set_tables (u32 sw_if_index, u32 ip4_table_index, + u32 ip6_table_index, + u32 other_table_index); + +#endif /* __included_vnet_l2_input_classify_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_efp_filter.c b/src/vnet/l2/l2_efp_filter.c new file mode 100644 index 00000000..2db4dc69 --- /dev/null +++ b/src/vnet/l2/l2_efp_filter.c @@ -0,0 +1,614 @@ +/* + * l2_efp_filter.c : layer 2 egress EFP Filter processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include + +#include +#include + +/** + * @file + * @brief EFP-filter - Ethernet Flow Point Filter. + * + * It is possible to transmit a packet out a subinterface with VLAN tags + * that are not compatible with that subinterface. In other words, if that + * packet arrived on the output port, it would not be classified as coming + * from the output subinterface. This can happen in various ways: through + * misconfiguration, by putting subinterfaces with different VLAN encaps in + * the same bridge-domain, etc. The EFP Filter Check detects such packets + * and drops them. It consists of two checks, one that verifies the packet + * prior to output VLAN tag rewrite and one that verifies the packet after + * VLAN tag rewrite. + * + */ +typedef struct +{ + + /* Next nodes for features and output interfaces */ + l2_output_next_nodes_st next_nodes; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_efp_filter_main_t; + + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u8 raw[12]; /* raw data (vlans) */ + u32 sw_if_index; +} l2_efp_filter_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_efp_filter_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_efp_filter_trace_t *t = va_arg (*args, l2_efp_filter_trace_t *); + + s = format (s, "l2-output-vtr: sw_if_index %d dst %U src %U data " + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src, + t->raw[0], t->raw[1], t->raw[2], t->raw[3], t->raw[4], + t->raw[5], t->raw[6], t->raw[7], t->raw[8], t->raw[9], + t->raw[10], t->raw[11]); + return s; +} + +l2_efp_filter_main_t l2_efp_filter_main; + +static vlib_node_registration_t l2_efp_filter_node; + +#define foreach_l2_efp_filter_error \ +_(L2_EFP_FILTER, "L2 EFP filter packets") \ +_(DROP, "L2 EFP filter post-rewrite drops") + +typedef enum +{ +#define _(sym,str) L2_EFP_FILTER_ERROR_##sym, + foreach_l2_efp_filter_error +#undef _ + L2_EFP_FILTER_N_ERROR, +} l2_efp_filter_error_t; + +static char *l2_efp_filter_error_strings[] = { +#define _(sym,string) string, + foreach_l2_efp_filter_error +#undef _ +}; + +typedef enum +{ + L2_EFP_FILTER_NEXT_DROP, + L2_EFP_FILTER_N_NEXT, +} l2_efp_filter_next_t; + + +/** + * Extract fields from the packet that will be used in interface + * classification. + */ +static_always_inline void +extract_keys (vnet_main_t * vnet_main, + u32 sw_if_index0, + vlib_buffer_t * b0, + u32 * port_sw_if_index0, + u16 * first_ethertype0, + u16 * outer_id0, u16 * inner_id0, u32 * match_flags0) +{ + ethernet_header_t *e0; + ethernet_vlan_header_t *h0; + u32 tag_len; + u32 tag_num; + + *port_sw_if_index0 = + vnet_get_sup_sw_interface (vnet_main, sw_if_index0)->sw_if_index; + + e0 = vlib_buffer_get_current (b0); + h0 = (ethernet_vlan_header_t *) (e0 + 1); + + *first_ethertype0 = clib_net_to_host_u16 (e0->type); + *outer_id0 = clib_net_to_host_u16 (h0[0].priority_cfi_and_id); + *inner_id0 = clib_net_to_host_u16 (h0[1].priority_cfi_and_id); + + tag_len = vnet_buffer (b0)->l2.l2_len - sizeof (ethernet_header_t); + tag_num = tag_len / sizeof (ethernet_vlan_header_t); + *match_flags0 = eth_create_valid_subint_match_flags (tag_num); +} + +/* + * EFP filtering is a basic switch feature which prevents an interface from + * transmitting a packet that doesn't match the interface's ingress match + * criteria. The check has two parts, one performed before egress vlan tag + * rewrite and one after. + * + * The pre-rewrite check insures the packet matches what an ingress packet looks + * like after going through the interface's ingress tag rewrite operation. Only + * pushed tags are compared. So: + * - if the ingress vlan tag rewrite pushes no tags (or is not enabled), + * any packet passes the filter + * - if the ingress vlan tag rewrite pushes one tag, + * the packet must have at least one tag, and the outer tag must match the pushed tag + * - if the ingress vlan tag rewrite pushes two tags, + * the packet must have at least two tags, and the outer two tags must match the pushed tags + * + * The pre-rewrite check is performed in the l2-output node. + * + * The post-rewrite check insures the packet matches what an ingress packet looks + * like before going through the interface's ingress tag rewrite operation. It verifies + * that such a packet arriving on the wire at this port would be classified as arriving + * an input interface equal to the packet's output interface. This can be done by running + * the output packet's vlan tags and output port through the interface classification, + * and checking if the resulting interface matches the output interface. + * + * The post-rewrite check is performed here. + */ + +static uword +l2_efp_filter_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_efp_filter_next_t next_index; + l2_efp_filter_main_t *msm = &l2_efp_filter_main; + vlib_node_t *n = vlib_get_node (vm, l2_efp_filter_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + u32 cached_sw_if_index = ~0; + u32 cached_next_index = ~0; + + /* invalidate cache to begin with */ + cached_sw_if_index = ~0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 6 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + u32 feature_bitmap0, feature_bitmap1; + u16 first_ethertype0, first_ethertype1; + u16 outer_id0, inner_id0, outer_id1, inner_id1; + u32 match_flags0, match_flags1; + u32 port_sw_if_index0, subint_sw_if_index0, port_sw_if_index1, + subint_sw_if_index1; + vnet_hw_interface_t *hi0, *hi1; + main_intf_t *main_intf0, *main_intf1; + vlan_intf_t *vlan_intf0, *vlan_intf1; + qinq_intf_t *qinq_intf0, *qinq_intf1; + u32 is_l20, is_l21; + __attribute__ ((unused)) u32 matched0, matched1; + u8 error0, error1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3, *p4, *p5; + __attribute__ ((unused)) u32 sw_if_index2, sw_if_index3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + + /* Prefetch the buffer header and packet for the N+2 loop iteration */ + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + + CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE); + + /* + * Prefetch the input config for the N+1 loop iteration + * This depends on the buffer header above + */ + sw_if_index2 = vnet_buffer (p2)->sw_if_index[VLIB_TX]; + sw_if_index3 = vnet_buffer (p3)->sw_if_index[VLIB_TX]; + /* + * $$$ TODO + * CLIB_PREFETCH (vec_elt_at_index(l2output_main.configs, sw_if_index2), CLIB_CACHE_LINE_BYTES, LOAD); + * CLIB_PREFETCH (vec_elt_at_index(l2output_main.configs, sw_if_index3), CLIB_CACHE_LINE_BYTES, LOAD); + */ + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* TX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + + /* process 2 packets */ + em->counters[node_counter_base_index + + L2_EFP_FILTER_ERROR_L2_EFP_FILTER] += 2; + + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; + feature_bitmap1 = + vnet_buffer (b1)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; + + /* Determine next node */ + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2_efp_filter_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2_efp_filter_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b1, sw_if_index1, feature_bitmap1, &next1); + + /* perform the efp filter check on two packets */ + + extract_keys (msm->vnet_main, + sw_if_index0, + b0, + &port_sw_if_index0, + &first_ethertype0, + &outer_id0, &inner_id0, &match_flags0); + + extract_keys (msm->vnet_main, + sw_if_index1, + b1, + &port_sw_if_index1, + &first_ethertype1, + &outer_id1, &inner_id1, &match_flags1); + + eth_vlan_table_lookups (ðernet_main, + msm->vnet_main, + port_sw_if_index0, + first_ethertype0, + outer_id0, + inner_id0, + &hi0, + &main_intf0, &vlan_intf0, &qinq_intf0); + + eth_vlan_table_lookups (ðernet_main, + msm->vnet_main, + port_sw_if_index1, + first_ethertype1, + outer_id1, + inner_id1, + &hi1, + &main_intf1, &vlan_intf1, &qinq_intf1); + + matched0 = eth_identify_subint (hi0, + b0, + match_flags0, + main_intf0, + vlan_intf0, + qinq_intf0, + &subint_sw_if_index0, + &error0, &is_l20); + + matched1 = eth_identify_subint (hi1, + b1, + match_flags1, + main_intf1, + vlan_intf1, + qinq_intf1, + &subint_sw_if_index1, + &error1, &is_l21); + + if (PREDICT_FALSE (sw_if_index0 != subint_sw_if_index0)) + { + /* Drop packet */ + next0 = L2_EFP_FILTER_NEXT_DROP; + b0->error = node->errors[L2_EFP_FILTER_ERROR_DROP]; + } + + if (PREDICT_FALSE (sw_if_index1 != subint_sw_if_index1)) + { + /* Drop packet */ + next1 = L2_EFP_FILTER_NEXT_DROP; + b1->error = node->errors[L2_EFP_FILTER_ERROR_DROP]; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + l2_efp_filter_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h1 = vlib_buffer_get_current (b1); + l2_efp_filter_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + clib_memcpy (t->raw, &h1->type, sizeof (t->raw)); + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + u32 feature_bitmap0; + u16 first_ethertype0; + u16 outer_id0, inner_id0; + u32 match_flags0; + u32 port_sw_if_index0, subint_sw_if_index0; + vnet_hw_interface_t *hi0; + main_intf_t *main_intf0; + vlan_intf_t *vlan_intf0; + qinq_intf_t *qinq_intf0; + u32 is_l20; + __attribute__ ((unused)) u32 matched0; + u8 error0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + + /* process 1 packet */ + em->counters[node_counter_base_index + + L2_EFP_FILTER_ERROR_L2_EFP_FILTER] += 1; + + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; + + /* Determine next node */ + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2_efp_filter_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + + /* perform the efp filter check on one packet */ + + extract_keys (msm->vnet_main, + sw_if_index0, + b0, + &port_sw_if_index0, + &first_ethertype0, + &outer_id0, &inner_id0, &match_flags0); + + eth_vlan_table_lookups (ðernet_main, + msm->vnet_main, + port_sw_if_index0, + first_ethertype0, + outer_id0, + inner_id0, + &hi0, + &main_intf0, &vlan_intf0, &qinq_intf0); + + matched0 = eth_identify_subint (hi0, + b0, + match_flags0, + main_intf0, + vlan_intf0, + qinq_intf0, + &subint_sw_if_index0, + &error0, &is_l20); + + if (PREDICT_FALSE (sw_if_index0 != subint_sw_if_index0)) + { + /* Drop packet */ + next0 = L2_EFP_FILTER_NEXT_DROP; + b0->error = node->errors[L2_EFP_FILTER_ERROR_DROP]; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + l2_efp_filter_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_efp_filter_node,static) = { + .function = l2_efp_filter_node_fn, + .name = "l2-efp-filter", + .vector_size = sizeof (u32), + .format_trace = format_l2_efp_filter_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_efp_filter_error_strings), + .error_strings = l2_efp_filter_error_strings, + + .n_next_nodes = L2_EFP_FILTER_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_EFP_FILTER_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_efp_filter_node, l2_efp_filter_node_fn) + clib_error_t *l2_efp_filter_init (vlib_main_t * vm) +{ + l2_efp_filter_main_t *mp = &l2_efp_filter_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_efp_filter_node.index, + L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + mp->next_nodes.feat_next_node_index); + + /* Initialize the output node mapping table */ + l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_efp_filter_init); + + +/** Enable/disable the EFP Filter check on the subinterface. */ +void +l2_efp_filter_configure (vnet_main_t * vnet_main, u32 sw_if_index, u32 enable) +{ + /* set the interface flag */ + l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_EFP_FILTER, enable); +} + + +/** + * Set subinterface egress efp filter enable/disable. + * The CLI format is: + * set interface l2 efp-filter [disable]] + */ +static clib_error_t * +int_l2_efp_filter (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 enable; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* enable/disable the feature */ + l2_efp_filter_configure (vnm, sw_if_index, enable); + +done: + return error; +} + + +/*? + * EFP filtering is a basic switch feature which prevents an interface from + * transmitting a packet that doesn't match the interface's ingress match + * criteria. The check has two parts, one performed before egress vlan tag + * rewrite and one after. This command enables or disables the EFP filtering + * for a given sub-interface. + * + * @cliexpar + * Example of how to enable a Layer 2 efp-filter on a sub-interface: + * @cliexcmd{set interface l2 efp-filter GigabitEthernet0/8/0.200} + * Example of how to disable a Layer 2 efp-filter on a sub-interface: + * @cliexcmd{set interface l2 efp-filter GigabitEthernet0/8/0.200 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_efp_filter_cli, static) = { + .path = "set interface l2 efp-filter", + .short_help = "set interface l2 efp-filter [disable]", + .function = int_l2_efp_filter, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_efp_filter.h b/src/vnet/l2/l2_efp_filter.h new file mode 100644 index 00000000..f40851df --- /dev/null +++ b/src/vnet/l2/l2_efp_filter.h @@ -0,0 +1,33 @@ +/* + * l2_efp_filter.h : layer 2 egress EFP Filter processing + * + * Copyright (c) 2013 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_vnet_l2_efp_filter_h +#define included_vnet_l2_efp_filter_h + +#include +#include + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c new file mode 100644 index 00000000..d34836e3 --- /dev/null +++ b/src/vnet/l2/l2_fib.c @@ -0,0 +1,857 @@ +/* + * l2_fib.c : layer 2 forwarding table (aka mac table) + * + * Copyright (c) 2013 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/** + * @file + * @brief Ethernet MAC Address FIB Table Management. + * + * The MAC Address forwarding table for bridge-domains is called the l2fib. + * Entries are added automatically as part of mac learning, but MAC Addresses + * entries can also be added manually. + * + */ + +typedef struct +{ + + /* hash table */ + BVT (clib_bihash) mac_table; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2fib_main_t; + +l2fib_main_t l2fib_main; + + +/** Format sw_if_index. If the value is ~0, use the text "N/A" */ +u8 * +format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args) +{ + vnet_main_t *vnm = va_arg (*args, vnet_main_t *); + u32 sw_if_index = va_arg (*args, u32); + if (sw_if_index == ~0) + return format (s, "N/A"); + else + return format (s, "%U", + format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface (vnm, sw_if_index)); +} + +void +l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, + l2fib_entry_result_t ** l2fe_res) +{ + l2fib_main_t *msm = &l2fib_main; + BVT (clib_bihash) * h = &msm->mac_table; + clib_bihash_bucket_t *b; + BVT (clib_bihash_value) * v; + l2fib_entry_key_t key; + l2fib_entry_result_t result; + int i, j, k; + + for (i = 0; i < h->nbuckets; i++) + { + b = &h->buckets[i]; + if (b->offset == 0) + continue; + v = BV (clib_bihash_get_value) (h, b->offset); + for (j = 0; j < (1 << b->log2_pages); j++) + { + for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) + { + if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) + continue; + + key.raw = v->kvp[k].key; + result.raw = v->kvp[k].value; + + if ((bd_index == ~0) || (bd_index == key.fields.bd_index)) + { + vec_add1 (*l2fe_key, key); + vec_add1 (*l2fe_res, result); + } + } + v++; + } + } +} + +/** Display the contents of the l2fib. */ +static clib_error_t * +show_l2fib (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + l2fib_main_t *msm = &l2fib_main; + l2_bridge_domain_t *bd_config; + BVT (clib_bihash) * h = &msm->mac_table; + clib_bihash_bucket_t *b; + BVT (clib_bihash_value) * v; + l2fib_entry_key_t key; + l2fib_entry_result_t result; + u32 first_entry = 1; + u64 total_entries = 0; + int i, j, k; + u8 verbose = 0; + u8 raw = 0; + u32 bd_id, bd_index = ~0; + u8 now = (u8) (vlib_time_now (vm) / 60); + u8 *s = 0; + + if (unformat (input, "raw")) + raw = 1; + else if (unformat (input, "verbose")) + verbose = 1; + else if (unformat (input, "bd_index %d", &bd_index)) + verbose = 1; + else if (unformat (input, "bd_id %d", &bd_id)) + { + uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + { + verbose = 1; + bd_index = p[0]; + } + else + { + vlib_cli_output (vm, "no such bridge domain id"); + return 0; + } + } + + for (i = 0; i < h->nbuckets; i++) + { + b = &h->buckets[i]; + if (b->offset == 0) + continue; + v = BV (clib_bihash_get_value) (h, b->offset); + for (j = 0; j < (1 << b->log2_pages); j++) + { + for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) + { + if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) + continue; + + if (verbose && first_entry) + { + first_entry = 0; + vlib_cli_output (vm, + "%=19s%=7s%=30s%=7s%=8s%=8s%=5s%=16s", + "Mac Address", "BD Idx", "Interface", + "Index", "static", "filter", "bvi", + "Mac Age (min)"); + } + + key.raw = v->kvp[k].key; + result.raw = v->kvp[k].value; + + if (verbose + & ((bd_index >> 31) || (bd_index == key.fields.bd_index))) + { + bd_config = vec_elt_at_index (l2input_main.bd_configs, + key.fields.bd_index); + + if (bd_config->mac_age) + { + i16 delta = now - result.fields.timestamp; + delta += delta < 0 ? 256 : 0; + s = format (s, "%d", delta); + } + else + s = format (s, "disabled"); + + vlib_cli_output (vm, + "%=19U%=7d%=30U%=7d%=8d%=8d%=5d%=16v", + format_ethernet_address, key.fields.mac, + key.fields.bd_index, + format_vnet_sw_if_index_name_with_NA, + msm->vnet_main, result.fields.sw_if_index, + result.fields.sw_if_index == ~0 + ? -1 : result.fields.sw_if_index, + result.fields.static_mac, + result.fields.filter, + result.fields.bvi, s); + vec_reset_length (s); + } + total_entries++; + } + v++; + } + } + + if (total_entries == 0) + vlib_cli_output (vm, "no l2fib entries"); + else + vlib_cli_output (vm, "%lld l2fib entries", total_entries); + + if (raw) + vlib_cli_output (vm, "Raw Hash Table:\n%U\n", + BV (format_bihash), h, 1 /* verbose */ ); + + vec_free (s); + return 0; +} + +/*? + * This command dispays the MAC Address entries of the L2 FIB table. + * Output can be filtered to just get the number of MAC Addresses or display + * each MAC Address for all bridge domains or just a single bridge domain. + * + * @cliexpar + * Example of how to display the number of MAC Address entries in the L2 + * FIB table: + * @cliexstart{show l2fib} + * 3 l2fib entries + * @cliexend + * Example of how to display all the MAC Address entries in the L2 + * FIB table: + * @cliexstart{show l2fib verbose} + * Mac Address BD Idx Interface Index static filter bvi refresh timestamp + * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0 + * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0 + * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0 + * 3 l2fib entries + * @cliexend +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_l2fib_cli, static) = { + .path = "show l2fib", + .short_help = "show l2fib [verbose | bd_id | bd_index | raw]", + .function = show_l2fib, +}; +/* *INDENT-ON* */ + + +/* Remove all entries from the l2fib */ +void +l2fib_clear_table (uint keep_static) +{ + l2fib_main_t *mp = &l2fib_main; + + if (keep_static) + { + /* TODO: remove only non-static entries */ + } + else + { + /* Remove all entries */ + BV (clib_bihash_free) (&mp->mac_table); + BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table", + L2FIB_NUM_BUCKETS, L2FIB_MEMORY_SIZE); + } + + l2learn_main.global_learn_count = 0; +} + +/** Clear all entries in L2FIB. + * @TODO: Later we may want a way to remove only the non-static entries + */ +static clib_error_t * +clear_l2fib (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2fib_clear_table (0); + return 0; +} + +/*? + * This command clears all the MAC Address entries from the L2 FIB table. + * + * @cliexpar + * Example of how to clear the L2 FIB Table: + * @cliexcmd{clear l2fib} + * Example to show the L2 FIB Table has been cleared: + * @cliexstart{show l2fib verbose} + * no l2fib entries + * @cliexend +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_l2fib_cli, static) = { + .path = "clear l2fib", + .short_help = "clear l2fib", + .function = clear_l2fib, +}; +/* *INDENT-ON* */ + + +/** + * Add an entry to the l2fib. + * If the entry already exists then overwrite it + */ +void +l2fib_add_entry (u64 mac, + u32 bd_index, + u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac) +{ + l2fib_entry_key_t key; + l2fib_entry_result_t result; + __attribute__ ((unused)) u32 bucket_contents; + l2fib_main_t *mp = &l2fib_main; + BVT (clib_bihash_kv) kv; + + /* set up key */ + key.raw = l2fib_make_key ((u8 *) & mac, bd_index); + + /* set up result */ + result.raw = 0; /* clear all fields */ + result.fields.sw_if_index = sw_if_index; + result.fields.static_mac = static_mac; + result.fields.filter = filter_mac; + result.fields.bvi = bvi_mac; + + kv.key = key.raw; + kv.value = result.raw; + + BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ ); + + /* increment counter if dynamically learned mac */ + if (result.fields.static_mac) + { + l2learn_main.global_learn_count++; + } +} + +/** + * Add an entry to the L2FIB. + * The CLI format is: + * l2fib add [static] [bvi] + * l2fib add filter + * Note that filter and bvi entries are always static + */ +static clib_error_t * +l2fib_add (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u64 mac; + u32 bd_id; + u32 bd_index; + u32 sw_if_index = ~0; + u32 filter_mac = 0; + u32 static_mac = 0; + u32 bvi_mac = 0; + uword *p; + + if (!unformat_user (input, unformat_ethernet_address, &mac)) + { + error = clib_error_return (0, "expected mac address `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expected bridge domain ID `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (!p) + { + error = clib_error_return (0, "bridge domain ID %d invalid", bd_id); + goto done; + } + bd_index = p[0]; + + if (unformat (input, "filter")) + { + filter_mac = 1; + static_mac = 1; + + } + else + { + + if (!unformat_user + (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + if (unformat (input, "static")) + { + static_mac = 1; + } + else if (unformat (input, "bvi")) + { + bvi_mac = 1; + static_mac = 1; + } + } + + l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac, + bvi_mac); + +done: + return error; +} + +/*? + * This command adds a MAC Address entry to the L2 FIB table + * of an existing bridge-domain. The MAC Address can be static + * or dynamic. This command also allows a filter to be added, + * such that packets with given MAC Addresses (source mac or + * destination mac match) are dropped. + * + * @cliexpar + * Example of how to add a dynamic MAC Address entry to the L2 FIB table + * of a bridge-domain (where 200 is the bridge-domain-id): + * @cliexcmd{l2fib add 52:54:00:53:18:33 200 GigabitEthernet0/8/0.200} + * Example of how to add a static MAC Address entry to the L2 FIB table + * of a bridge-domain (where 200 is the bridge-domain-id): + * @cliexcmd{l2fib add 52:54:00:53:18:55 200 GigabitEthernet0/8/0.200 static} + * Example of how to add a filter such that a packet with the given MAC + * Address will be dropped in a given bridge-domain (where 200 is the + * bridge-domain-id): + * @cliexcmd{l2fib add 52:54:00:53:18:77 200 filter} + * Example of show command of the provisioned MAC Addresses and filters: + * @cliexstart{show l2fib verbose} + * Mac Address BD Idx Interface Index static filter bvi refresh timestamp + * 52:54:00:53:18:33 1 GigabitEthernet0/8/0.200 3 0 0 0 0 0 + * 52:54:00:53:18:55 1 GigabitEthernet0/8/0.200 3 1 0 0 0 0 + * 52:54:00:53:18:77 1 N/A -1 1 1 0 0 0 + * 3 l2fib entries + * @cliexend +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_add_cli, static) = { + .path = "l2fib add", + .short_help = "l2fib add filter | [static | bvi]", + .function = l2fib_add, +}; +/* *INDENT-ON* */ + + +static clib_error_t * +l2fib_test_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + clib_error_t *error = 0; + u64 mac, save_mac; + u32 bd_index = 0; + u32 sw_if_index = 8; + u32 filter_mac = 0; + u32 bvi_mac = 0; + u32 is_add = 0; + u32 is_del = 0; + u32 is_check = 0; + u32 count = 1; + int mac_set = 0; + int i; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "mac %U", unformat_ethernet_address, &mac)) + mac_set = 1; + else if (unformat (input, "add")) + is_add = 1; + else if (unformat (input, "del")) + is_del = 1; + else if (unformat (input, "check")) + is_check = 1; + else if (unformat (input, "count %d", &count)) + ; + else + break; + } + + if (mac_set == 0) + return clib_error_return (0, "mac not set"); + + if (is_add == 0 && is_del == 0 && is_check == 0) + return clib_error_return (0, + "noop: pick at least one of (add,del,check)"); + + save_mac = mac; + + if (is_add) + { + for (i = 0; i < count; i++) + { + u64 tmp; + l2fib_add_entry (mac, bd_index, sw_if_index, mac, + filter_mac, bvi_mac); + tmp = clib_net_to_host_u64 (mac); + tmp >>= 16; + tmp++; + tmp <<= 16; + mac = clib_host_to_net_u64 (tmp); + } + } + + if (is_check) + { + BVT (clib_bihash_kv) kv; + l2fib_main_t *mp = &l2fib_main; + + mac = save_mac; + + for (i = 0; i < count; i++) + { + u64 tmp; + kv.key = l2fib_make_key ((u8 *) & mac, bd_index); + if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv)) + { + clib_warning ("key %U AWOL", format_ethernet_address, &mac); + break; + } + tmp = clib_net_to_host_u64 (mac); + tmp >>= 16; + tmp++; + tmp <<= 16; + mac = clib_host_to_net_u64 (tmp); + } + } + + if (is_del) + { + for (i = 0; i < count; i++) + { + u64 tmp; + + l2fib_del_entry (mac, bd_index); + + tmp = clib_net_to_host_u64 (mac); + tmp >>= 16; + tmp++; + tmp <<= 16; + mac = clib_host_to_net_u64 (tmp); + } + } + + return error; +} + +/*? + * The set of 'test l2fib' commands allow the L2 FIB table of the default + * bridge domain (bridge-domain-id of 0) to be modified. + * + * @cliexpar + * @parblock + * Example of how to add a set of 4 sequential MAC Address entries to L2 + * FIB table of the default bridge-domain: + * @cliexcmd{test l2fib add mac 52:54:00:53:00:00 count 4} + * + * Show the set of 4 sequential MAC Address entries that were added: + * @cliexstart{show l2fib verbose} + * Mac Address BD Idx Interface Index static filter bvi refresh timestamp + * 52:54:00:53:00:00 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0 + * 52:54:00:53:00:01 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0 + * 52:54:00:53:00:03 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0 + * 52:54:00:53:00:02 0 GigabitEthernet0/8/0.300 8 0 0 0 0 0 + * 4 l2fib entries + * @cliexend + * + * Example of how to check that the set of 4 sequential MAC Address + * entries were added to L2 FIB table of the default + * bridge-domain. Used a count of 5 to produce an error: + * + * @cliexcmd{test l2fib check mac 52:54:00:53:00:00 count 5} + * The output of the check command is in the log files. Log file + * location may vary based on your OS and Version: + * + * # tail -f /var/log/messages | grep l2fib_test_command_fn + * + * Sep 7 17:15:24 localhost vnet[4952]: l2fib_test_command_fn:446: key 52:54:00:53:00:04 AWOL + * + * Example of how to delete a set of 4 sequential MAC Address entries + * from L2 FIB table of the default bridge-domain: + * @cliexcmd{test l2fib del mac 52:54:00:53:00:00 count 4} + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_test_command, static) = { + .path = "test l2fib", + .short_help = "test l2fib [add|del|check] mac count ", + .function = l2fib_test_command_fn, +}; +/* *INDENT-ON* */ + + +/** + * Delete an entry from the l2fib. + * Return 0 if the entry was deleted, or 1 if it was not found + */ +u32 +l2fib_del_entry (u64 mac, u32 bd_index) +{ + + l2fib_entry_result_t result; + l2fib_main_t *mp = &l2fib_main; + BVT (clib_bihash_kv) kv; + + /* set up key */ + kv.key = l2fib_make_key ((u8 *) & mac, bd_index); + + if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv)) + return 1; + + result.raw = kv.value; + + /* decrement counter if dynamically learned mac */ + if (result.fields.static_mac) + { + if (l2learn_main.global_learn_count > 0) + { + l2learn_main.global_learn_count--; + } + } + + /* Remove entry from hash table */ + BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ ); + return 0; +} + +/** + * Delete an entry from the L2FIB. + * The CLI format is: + * l2fib del + */ +static clib_error_t * +l2fib_del (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u64 mac; + u32 bd_id; + u32 bd_index; + uword *p; + + if (!unformat_user (input, unformat_ethernet_address, &mac)) + { + error = clib_error_return (0, "expected mac address `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expected bridge domain ID `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (!p) + { + error = clib_error_return (0, "bridge domain ID %d invalid", bd_id); + goto done; + } + bd_index = p[0]; + + /* Delete the entry */ + if (l2fib_del_entry (mac, bd_index)) + { + error = clib_error_return (0, "mac entry not found"); + goto done; + } + +done: + return error; +} + +/*? + * This command deletes an existing MAC Address entry from the L2 FIB + * table of an existing bridge-domain. + * + * @cliexpar + * Example of how to delete a MAC Address entry from the L2 FIB table of a bridge-domain (where 200 is the bridge-domain-id): + * @cliexcmd{l2fib del 52:54:00:53:18:33 200} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_del_cli, static) = { + .path = "l2fib del", + .short_help = "l2fib del ", + .function = l2fib_del, +}; +/* *INDENT-ON* */ + + +BVT (clib_bihash) * get_mac_table (void) +{ + l2fib_main_t *mp = &l2fib_main; + return &mp->mac_table; +} + +static uword +l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, + vlib_frame_t * f) +{ + uword event_type, *event_data = 0; + l2fib_main_t *msm = &l2fib_main; + l2_bridge_domain_t *bd_config; + BVT (clib_bihash) * h = &msm->mac_table; + clib_bihash_bucket_t *b; + BVT (clib_bihash_value) * v; + l2fib_entry_key_t key; + l2fib_entry_result_t result; + int i, j, k; + bool enabled = 0; + f64 start_time, last_run_duration = 0, t; + i16 delta; + + while (1) + { + if (enabled) + vlib_process_wait_for_event_or_clock (vm, 60 - last_run_duration); + else + vlib_process_wait_for_event (vm); + + event_type = vlib_process_get_events (vm, &event_data); + vec_reset_length (event_data); + + switch (event_type) + { + case ~0: + break; + case L2_MAC_AGE_PROCESS_EVENT_START: + enabled = 1; + break; + case L2_MAC_AGE_PROCESS_EVENT_STOP: + enabled = 0; + continue; + default: + ASSERT (0); + } + last_run_duration = start_time = vlib_time_now (vm); + for (i = 0; i < h->nbuckets; i++) + { + /* Allow no more than 10us without a pause */ + t = vlib_time_now (vm); + if (t > start_time + 10e-6) + { + vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */ + start_time = vlib_time_now (vm); + } + + if (i < (h->nbuckets - 3)) + { + b = &h->buckets[i + 3]; + CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); + b = &h->buckets[i + 1]; + if (b->offset) + { + v = BV (clib_bihash_get_value) (h, b->offset); + CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); + } + } + + b = &h->buckets[i]; + if (b->offset == 0) + continue; + v = BV (clib_bihash_get_value) (h, b->offset); + for (j = 0; j < (1 << b->log2_pages); j++) + { + for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) + { + if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) + continue; + + key.raw = v->kvp[k].key; + result.raw = v->kvp[k].value; + + if (result.fields.static_mac) + continue; + + bd_config = vec_elt_at_index (l2input_main.bd_configs, + key.fields.bd_index); + + if (bd_config->mac_age == 0) + continue; + + delta = (u8) (start_time / 60) - result.fields.timestamp; + delta += delta < 0 ? 256 : 0; + + if (delta > bd_config->mac_age) + { + void *p = &key.fields.mac; + l2fib_del_entry (*(u64 *) p, key.fields.bd_index); + } + } + v++; + } + } + last_run_duration = vlib_time_now (vm) - last_run_duration; + } + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2fib_mac_age_scanner_process_node) = { + .function = l2fib_mac_age_scanner_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "l2fib-mac-age-scanner-process", +}; +/* *INDENT-ON* */ + +clib_error_t * +l2fib_init (vlib_main_t * vm) +{ + l2fib_main_t *mp = &l2fib_main; + l2fib_entry_key_t test_key; + u8 test_mac[6]; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Create the hash table */ + BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table", + L2FIB_NUM_BUCKETS, L2FIB_MEMORY_SIZE); + + /* verify the key constructor is good, since it is endian-sensitive */ + memset (test_mac, 0, sizeof (test_mac)); + test_mac[0] = 0x11; + test_key.raw = 0; + test_key.raw = l2fib_make_key ((u8 *) & test_mac, 0x1234); + ASSERT (test_key.fields.mac[0] == 0x11); + ASSERT (test_key.fields.bd_index == 0x1234); + + return 0; +} + +VLIB_INIT_FUNCTION (l2fib_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h new file mode 100644 index 00000000..4a2da59b --- /dev/null +++ b/src/vnet/l2/l2_fib.h @@ -0,0 +1,341 @@ +/* + * l2_fib.h : layer 2 forwarding table (aka mac table) + * + * Copyright (c) 2013 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_l2fib_h +#define included_l2fib_h + +#include +#include + +/* + * The size of the hash table + */ +#define L2FIB_NUM_BUCKETS (64 * 1024) +#define L2FIB_MEMORY_SIZE (256<<20) + +/* + * The L2fib key is the mac address and bridge domain ID + */ +typedef struct +{ + union + { + struct + { + u16 bd_index; + u8 mac[6]; + } fields; + struct + { + u32 w0; + u32 w1; + } words; + u64 raw; + }; +} l2fib_entry_key_t; + +STATIC_ASSERT_SIZEOF (l2fib_entry_key_t, 8); + +/* + * The l2fib entry results + */ +typedef struct +{ + union + { + struct + { + u32 sw_if_index; /* output sw_if_index (L3 interface if bvi==1) */ + + u8 static_mac:1; /* static mac, no dataplane learning */ + u8 bvi:1; /* mac is for a bridged virtual interface */ + u8 filter:1; /* drop packets to/from this mac */ + u8 unused1:5; + u8 timestamp; /* timestamp for aging */ + u16 unused2; + } fields; + u64 raw; + }; +} l2fib_entry_result_t; + +STATIC_ASSERT_SIZEOF (l2fib_entry_result_t, 8); + +/** + * Compute the hash for the given key and return + * the corresponding bucket index + */ +always_inline u32 +l2fib_compute_hash_bucket (l2fib_entry_key_t * key) +{ + u32 result; + u32 temp_a; + u32 temp_b; + + result = 0xa5a5a5a5; /* some seed */ + temp_a = key->words.w0; + temp_b = key->words.w1; + hash_mix32 (temp_a, temp_b, result); + + return result % L2FIB_NUM_BUCKETS; +} + +always_inline u64 +l2fib_make_key (u8 * mac_address, u16 bd_index) +{ + u64 temp; + + /* + * The mac address in memory is A:B:C:D:E:F + * The bd id in register is H:L + */ +#if CLIB_ARCH_IS_LITTLE_ENDIAN + /* + * Create the in-register key as F:E:D:C:B:A:H:L + * In memory the key is L:H:A:B:C:D:E:F + */ + temp = *((u64 *) (mac_address)) << 16; + temp = (temp & ~0xffff) | (u64) (bd_index); +#else + /* + * Create the in-register key as H:L:A:B:C:D:E:F + * In memory the key is H:L:A:B:C:D:E:F + */ + temp = *((u64 *) (mac_address)) >> 16; + temp = temp | (((u64) bd_index) << 48); +#endif + + return temp; +} + + + +/** + * Lookup the entry for mac and bd_index in the mac table for 1 packet. + * Cached_key and cached_result are used as a one-entry cache. + * The function reads and updates them as needed. + * + * mac0 and bd_index0 are the keys. The entry is written to result0. + * If the entry was not found, result0 is set to ~0. + * + * key0 and bucket0 return with the computed key and hash bucket, + * convenient if the entry needs to be updated afterward. + * If the cached_result was used, bucket0 is set to ~0. + */ + +static_always_inline void +l2fib_lookup_1 (BVT (clib_bihash) * mac_table, + l2fib_entry_key_t * cached_key, + l2fib_entry_result_t * cached_result, + u8 * mac0, + u16 bd_index0, + l2fib_entry_key_t * key0, + u32 * bucket0, l2fib_entry_result_t * result0) +{ + /* set up key */ + key0->raw = l2fib_make_key (mac0, bd_index0); + *bucket0 = ~0; + + if (key0->raw == cached_key->raw) + { + /* Hit in the one-entry cache */ + result0->raw = cached_result->raw; + } + else + { + /* Do a regular mac table lookup */ + BVT (clib_bihash_kv) kv; + + kv.key = key0->raw; + kv.value = ~0ULL; + BV (clib_bihash_search_inline) (mac_table, &kv); + result0->raw = kv.value; + + /* Update one-entry cache */ + cached_key->raw = key0->raw; + cached_result->raw = result0->raw; + } +} + + +/** + * Lookup the entry for mac and bd_index in the mac table for 2 packets. + * The lookups for the two packets are interleaved. + * + * Cached_key and cached_result are used as a one-entry cache. + * The function reads and updates them as needed. + * + * mac0 and bd_index0 are the keys. The entry is written to result0. + * If the entry was not found, result0 is set to ~0. The same + * holds for mac1/bd_index1/result1. + */ +static_always_inline void +l2fib_lookup_2 (BVT (clib_bihash) * mac_table, + l2fib_entry_key_t * cached_key, + l2fib_entry_result_t * cached_result, + u8 * mac0, + u8 * mac1, + u16 bd_index0, + u16 bd_index1, + l2fib_entry_key_t * key0, + l2fib_entry_key_t * key1, + u32 * bucket0, + u32 * bucket1, + l2fib_entry_result_t * result0, + l2fib_entry_result_t * result1) +{ + /* set up key */ + key0->raw = l2fib_make_key (mac0, bd_index0); + key1->raw = l2fib_make_key (mac1, bd_index1); + + if ((key0->raw == cached_key->raw) && (key1->raw == cached_key->raw)) + { + /* Both hit in the one-entry cache */ + result0->raw = cached_result->raw; + result1->raw = cached_result->raw; + *bucket0 = ~0; + *bucket1 = ~0; + + } + else + { + BVT (clib_bihash_kv) kv0, kv1; + + /* + * Do a regular mac table lookup + * Interleave lookups for packet 0 and packet 1 + */ + kv0.key = key0->raw; + kv1.key = key1->raw; + kv0.value = ~0ULL; + kv1.value = ~0ULL; + + BV (clib_bihash_search_inline) (mac_table, &kv0); + BV (clib_bihash_search_inline) (mac_table, &kv1); + + result0->raw = kv0.value; + result1->raw = kv1.value; + + /* Update one-entry cache */ + cached_key->raw = key1->raw; + cached_result->raw = result1->raw; + } +} + +static_always_inline void +l2fib_lookup_4 (BVT (clib_bihash) * mac_table, + l2fib_entry_key_t * cached_key, + l2fib_entry_result_t * cached_result, + u8 * mac0, + u8 * mac1, + u8 * mac2, + u8 * mac3, + u16 bd_index0, + u16 bd_index1, + u16 bd_index2, + u16 bd_index3, + l2fib_entry_key_t * key0, + l2fib_entry_key_t * key1, + l2fib_entry_key_t * key2, + l2fib_entry_key_t * key3, + u32 * bucket0, + u32 * bucket1, + u32 * bucket2, + u32 * bucket3, + l2fib_entry_result_t * result0, + l2fib_entry_result_t * result1, + l2fib_entry_result_t * result2, + l2fib_entry_result_t * result3) +{ + /* set up key */ + key0->raw = l2fib_make_key (mac0, bd_index0); + key1->raw = l2fib_make_key (mac1, bd_index1); + key2->raw = l2fib_make_key (mac2, bd_index2); + key3->raw = l2fib_make_key (mac3, bd_index3); + + if ((key0->raw == cached_key->raw) && (key1->raw == cached_key->raw) && + (key2->raw == cached_key->raw) && (key3->raw == cached_key->raw)) + { + /* Both hit in the one-entry cache */ + result0->raw = cached_result->raw; + result1->raw = cached_result->raw; + result2->raw = cached_result->raw; + result3->raw = cached_result->raw; + *bucket0 = ~0; + *bucket1 = ~0; + *bucket2 = ~0; + *bucket3 = ~0; + + } + else + { + BVT (clib_bihash_kv) kv0, kv1, kv2, kv3; + + /* + * Do a regular mac table lookup + * Interleave lookups for packet 0 and packet 1 + */ + kv0.key = key0->raw; + kv1.key = key1->raw; + kv2.key = key2->raw; + kv3.key = key3->raw; + kv0.value = ~0ULL; + kv1.value = ~0ULL; + kv2.value = ~0ULL; + kv3.value = ~0ULL; + + BV (clib_bihash_search_inline) (mac_table, &kv0); + BV (clib_bihash_search_inline) (mac_table, &kv1); + BV (clib_bihash_search_inline) (mac_table, &kv2); + BV (clib_bihash_search_inline) (mac_table, &kv3); + + result0->raw = kv0.value; + result1->raw = kv1.value; + result2->raw = kv2.value; + result3->raw = kv3.value; + + /* Update one-entry cache */ + cached_key->raw = key1->raw; + cached_result->raw = result1->raw; + } +} + +BVT (clib_bihash) * get_mac_table (void); + void + l2fib_clear_table (uint keep_static); + void + l2fib_add_entry (u64 mac, + u32 bd_index, + u32 sw_if_index, + u32 static_mac, u32 drop_mac, u32 bvi_mac); +u32 +l2fib_del_entry (u64 mac, u32 bd_index); + + void + l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, + l2fib_entry_result_t ** l2fe_res); + + u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_flood.c b/src/vnet/l2/l2_flood.c new file mode 100644 index 00000000..ed9e5ac2 --- /dev/null +++ b/src/vnet/l2/l2_flood.c @@ -0,0 +1,568 @@ +/* + * l2_flood.c : layer 2 flooding + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/** + * @file + * @brief Ethernet Flooding. + * + * Flooding uses the packet replication infrastructure to send a copy of the + * packet to each member interface. Logically the replication infrastructure + * expects two graph nodes: a prep node that initiates replication and sends the + * packet to the first destination, and a recycle node that is passed the packet + * after it has been transmitted. + * + * To decrease the amount of code, l2 flooding implements both functions in + * the same graph node. This node can tell if is it being called as the "prep" + * or "recycle" using replication_is_recycled(). + */ + + +typedef struct +{ + + /* Next nodes for each feature */ + u32 feat_next_node_index[32]; + + /* next node index for the L3 input node of each ethertype */ + next_by_ethertype_t l3_next; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2flood_main_t; + +typedef struct +{ + u8 src[6]; + u8 dst[6]; + u32 sw_if_index; + u16 bd_index; +} l2flood_trace_t; + + +/* packet trace format function */ +static u8 * +format_l2flood_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2flood_trace_t *t = va_arg (*args, l2flood_trace_t *); + + s = format (s, "l2-flood: sw_if_index %d dst %U src %U bd_index %d", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src, t->bd_index); + return s; +} + +l2flood_main_t l2flood_main; + +static vlib_node_registration_t l2flood_node; + +#define foreach_l2flood_error \ +_(L2FLOOD, "L2 flood packets") \ +_(REPL_FAIL, "L2 replication failures") \ +_(NO_MEMBERS, "L2 replication complete") \ +_(BVI_BAD_MAC, "BVI L3 mac mismatch") \ +_(BVI_ETHERTYPE, "BVI packet with unhandled ethertype") + +typedef enum +{ +#define _(sym,str) L2FLOOD_ERROR_##sym, + foreach_l2flood_error +#undef _ + L2FLOOD_N_ERROR, +} l2flood_error_t; + +static char *l2flood_error_strings[] = { +#define _(sym,string) string, + foreach_l2flood_error +#undef _ +}; + +typedef enum +{ + L2FLOOD_NEXT_L2_OUTPUT, + L2FLOOD_NEXT_DROP, + L2FLOOD_N_NEXT, +} l2flood_next_t; + +/* + * Perform flooding on one packet + * + * Due to the way BVI processing can modify the packet, the BVI interface + * (if present) must be processed last in the replication. The member vector + * is arranged so that the BVI interface is always the first element. + * Flooding walks the vector in reverse. + * + * BVI processing causes the packet to go to L3 processing. This strips the + * L2 header, which is fine because the replication infrastructure restores + * it. However L3 processing can trigger larger changes to the packet. For + * example, an ARP request could be turned into an ARP reply, an ICMP request + * could be turned into an ICMP reply. If BVI processing is not performed + * last, the modified packet would be replicated to the remaining members. + */ + +static_always_inline void +l2flood_process (vlib_main_t * vm, + vlib_node_runtime_t * node, + l2flood_main_t * msm, + u64 * counter_base, + vlib_buffer_t * b0, + u32 * sw_if_index0, + l2fib_entry_key_t * key0, + u32 * bucket0, l2fib_entry_result_t * result0, u32 * next0) +{ + u16 bd_index0; + l2_bridge_domain_t *bd_config; + l2_flood_member_t *members; + i32 current_member; /* signed */ + replication_context_t *ctx; + u8 in_shg = vnet_buffer (b0)->l2.shg; + + if (!replication_is_recycled (b0)) + { + + /* Do flood "prep node" processing */ + + /* Get config for the bridge domain interface */ + bd_index0 = vnet_buffer (b0)->l2.bd_index; + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index0); + members = bd_config->members; + + /* Find first member that passes the reflection and SHG checks */ + current_member = bd_config->flood_count - 1; + while ((current_member >= 0) && + ((members[current_member].sw_if_index == *sw_if_index0) || + (in_shg && members[current_member].shg == in_shg))) + { + current_member--; + } + + if (current_member < 0) + { + /* No members to flood to */ + *next0 = L2FLOOD_NEXT_DROP; + b0->error = node->errors[L2FLOOD_ERROR_NO_MEMBERS]; + return; + } + + if ((current_member > 0) && + ((current_member > 1) || + ((members[0].sw_if_index != *sw_if_index0) && + (!in_shg || members[0].shg != in_shg)))) + { + /* If more than one member then initiate replication */ + ctx = + replication_prep (vm, b0, l2flood_node.index, 1 /* l2_packet */ ); + ctx->feature_replicas = (uword) members; + ctx->feature_counter = current_member; + } + + } + else + { + vnet_buffer_opaque_t *vnet_buff_op; + + /* Do flood "recycle node" processing */ + + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_REPL_FAIL)) + { + (void) replication_recycle (vm, b0, 1 /* is_last */ ); + *next0 = L2FLOOD_NEXT_DROP; + b0->error = node->errors[L2FLOOD_ERROR_REPL_FAIL]; + return; + } + + ctx = replication_get_ctx (b0); + replication_clear_recycled (b0); + + members = (l2_flood_member_t *) (intptr_t) ctx->feature_replicas; + current_member = (i32) ctx->feature_counter - 1; + + /* Need to update input index from saved packet context */ + vnet_buff_op = (vnet_buffer_opaque_t *) ctx->vnet_buffer; + *sw_if_index0 = vnet_buff_op->sw_if_index[VLIB_RX]; + + /* Find next member that passes the reflection and SHG check */ + while ((current_member >= 0) && + ((members[current_member].sw_if_index == *sw_if_index0) || + (in_shg && members[current_member].shg == in_shg))) + { + current_member--; + } + + if (current_member < 0) + { + /* + * No more members to flood to. + * Terminate replication and drop packet. + */ + + replication_recycle (vm, b0, 1 /* is_last */ ); + + *next0 = L2FLOOD_NEXT_DROP; + /* Ideally we woudn't bump a counter here, just silently complete */ + b0->error = node->errors[L2FLOOD_ERROR_NO_MEMBERS]; + return; + } + + /* Restore packet and context and continue replication */ + ctx->feature_counter = current_member; + replication_recycle (vm, b0, ((current_member == 0) || /*is_last */ + ((current_member == 1) && + ((members[0].sw_if_index == + *sw_if_index0) || (in_shg + && members[0].shg == + in_shg))))); + } + + /* Forward packet to the current member */ + if (PREDICT_FALSE (members[current_member].flags & L2_FLOOD_MEMBER_BVI)) + { + /* Do BVI processing */ + u32 rc; + rc = l2_to_bvi (vm, + msm->vnet_main, + b0, + members[current_member].sw_if_index, + &msm->l3_next, next0); + + if (PREDICT_FALSE (rc)) + { + if (rc == TO_BVI_ERR_BAD_MAC) + { + b0->error = node->errors[L2FLOOD_ERROR_BVI_BAD_MAC]; + *next0 = L2FLOOD_NEXT_DROP; + } + else if (rc == TO_BVI_ERR_ETHERTYPE) + { + b0->error = node->errors[L2FLOOD_ERROR_BVI_ETHERTYPE]; + *next0 = L2FLOOD_NEXT_DROP; + } + } + } + else + { + /* Do normal L2 forwarding */ + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + members[current_member].sw_if_index; + *next0 = L2FLOOD_NEXT_L2_OUTPUT; + + } + +} + + +static uword +l2flood_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2flood_next_t next_index; + l2flood_main_t *msm = &l2flood_main; + vlib_node_t *n = vlib_get_node (vm, l2flood_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 6 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + l2fib_entry_key_t key0, key1; + l2fib_entry_result_t result0, result1; + u32 bucket0, bucket1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3, *p4, *p5; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + + /* Prefetch the buffer header for the N+2 loop iteration */ + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + + /* Prefetch the replication context for the N+1 loop iteration */ + /* This depends on the buffer header above */ + replication_prefetch_ctx (p2); + replication_prefetch_ctx (p3); + + /* Prefetch the packet for the N+1 loop iteration */ + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* RX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + /* process 2 pkts */ + em->counters[node_counter_base_index + L2FLOOD_ERROR_L2FLOOD] += 2; + + l2flood_process (vm, node, msm, + &em->counters[node_counter_base_index], b0, + &sw_if_index0, &key0, &bucket0, &result0, &next0); + + l2flood_process (vm, node, msm, + &em->counters[node_counter_base_index], b1, + &sw_if_index1, &key1, &bucket1, &result1, &next1); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + l2flood_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED)) + { + l2flood_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + ethernet_header_t *h1 = vlib_buffer_get_current (b1); + t->sw_if_index = sw_if_index1; + t->bd_index = vnet_buffer (b1)->l2.bd_index; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + l2fib_entry_key_t key0; + l2fib_entry_result_t result0; + u32 bucket0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + /* process 1 pkt */ + em->counters[node_counter_base_index + L2FLOOD_ERROR_L2FLOOD] += 1; + + l2flood_process (vm, node, msm, + &em->counters[node_counter_base_index], b0, + &sw_if_index0, &key0, &bucket0, &result0, &next0); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && + (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2flood_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2flood_node,static) = { + .function = l2flood_node_fn, + .name = "l2-flood", + .vector_size = sizeof (u32), + .format_trace = format_l2flood_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2flood_error_strings), + .error_strings = l2flood_error_strings, + + .n_next_nodes = L2FLOOD_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2FLOOD_NEXT_L2_OUTPUT] = "l2-output", + [L2FLOOD_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2flood_node, l2flood_node_fn) + clib_error_t *l2flood_init (vlib_main_t * vm) +{ + l2flood_main_t *mp = &l2flood_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2flood_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + mp->feat_next_node_index); + + return 0; +} + +VLIB_INIT_FUNCTION (l2flood_init); + + + +/** Add the L3 input node for this ethertype to the next nodes structure. */ +void +l2flood_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index) +{ + l2flood_main_t *mp = &l2flood_main; + u32 next_index; + + next_index = vlib_node_add_next (vm, l2flood_node.index, node_index); + + next_by_ethertype_register (&mp->l3_next, type, next_index); +} + + +/** + * Set subinterface flood enable/disable. + * The CLI format is: + * set interface l2 flood [disable] + */ +static clib_error_t * +int_flood (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 enable; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the interface flag */ + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_FLOOD, enable); + +done: + return error; +} + +/*? + * Layer 2 flooding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage interfaces. It is enabled by default. + * + * @cliexpar + * Example of how to enable flooding: + * @cliexcmd{set interface l2 flood GigabitEthernet0/8/0} + * Example of how to disable flooding: + * @cliexcmd{set interface l2 flood GigabitEthernet0/8/0 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_flood_cli, static) = { + .path = "set interface l2 flood", + .short_help = "set interface l2 flood [disable]", + .function = int_flood, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_flood.h b/src/vnet/l2/l2_flood.h new file mode 100644 index 00000000..acd7c905 --- /dev/null +++ b/src/vnet/l2/l2_flood.h @@ -0,0 +1,35 @@ +/* + * l2_flood.h : layer 2 flooding + * + * Copyright (c) 2013 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_l2flood_h +#define included_l2flood_h + +#include +#include + +void +l2flood_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index); +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c new file mode 100644 index 00000000..710a9d9e --- /dev/null +++ b/src/vnet/l2/l2_fwd.c @@ -0,0 +1,544 @@ +/* + * l2_fwd.c : layer 2 forwarding using l2fib + * + * Copyright (c) 2013 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 +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +/** + * @file + * @brief Ethernet Forwarding. + * + * Code in this file handles forwarding Layer 2 packets. This file calls + * the FIB lookup, packet learning and the packet flooding as necessary. + * Packet is then sent to the next graph node. + */ + +typedef struct +{ + + /* Hash table */ + BVT (clib_bihash) * mac_table; + + /* next node index for the L3 input node of each ethertype */ + next_by_ethertype_t l3_next; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2fwd_main_t; + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u32 sw_if_index; + u16 bd_index; +} l2fwd_trace_t; + +/* packet trace format function */ +static u8 * +format_l2fwd_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2fwd_trace_t *t = va_arg (*args, l2fwd_trace_t *); + + s = format (s, "l2-fwd: sw_if_index %d dst %U src %U bd_index %d", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src, t->bd_index); + return s; +} + +l2fwd_main_t l2fwd_main; + +static vlib_node_registration_t l2fwd_node; + +#define foreach_l2fwd_error \ +_(L2FWD, "L2 forward packets") \ +_(FLOOD, "L2 forward misses") \ +_(HIT, "L2 forward hits") \ +_(BVI_BAD_MAC, "BVI L3 MAC mismatch") \ +_(BVI_ETHERTYPE, "BVI packet with unhandled ethertype") \ +_(FILTER_DROP, "Filter Mac Drop") \ +_(REFLECT_DROP, "Reflection Drop") + +typedef enum +{ +#define _(sym,str) L2FWD_ERROR_##sym, + foreach_l2fwd_error +#undef _ + L2FWD_N_ERROR, +} l2fwd_error_t; + +static char *l2fwd_error_strings[] = { +#define _(sym,string) string, + foreach_l2fwd_error +#undef _ +}; + +typedef enum +{ + L2FWD_NEXT_L2_OUTPUT, + L2FWD_NEXT_FLOOD, + L2FWD_NEXT_DROP, + L2FWD_N_NEXT, +} l2fwd_next_t; + +/** Forward one packet based on the mac table lookup result. */ + +static_always_inline void +l2fwd_process (vlib_main_t * vm, + vlib_node_runtime_t * node, + l2fwd_main_t * msm, + vlib_error_main_t * em, + vlib_buffer_t * b0, + u32 sw_if_index0, l2fib_entry_result_t * result0, u32 * next0) +{ + if (PREDICT_FALSE (result0->raw == ~0)) + { + /* + * lookup miss, so flood + * TODO:replicate packet to each intf in bridge-domain + * For now just drop + */ + if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD) + { + *next0 = L2FWD_NEXT_FLOOD; + } + else + { + /* Flooding is disabled */ + b0->error = node->errors[L2FWD_ERROR_FLOOD]; + *next0 = L2FWD_NEXT_DROP; + } + + } + else + { + + /* lookup hit, forward packet */ +#ifdef COUNTERS + em->counters[node_counter_base_index + L2FWD_ERROR_HIT] += 1; +#endif + + vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index; + *next0 = L2FWD_NEXT_L2_OUTPUT; + + /* perform reflection check */ + if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index)) + { + b0->error = node->errors[L2FWD_ERROR_REFLECT_DROP]; + *next0 = L2FWD_NEXT_DROP; + + /* perform filter check */ + } + else if (PREDICT_FALSE (result0->fields.filter)) + { + b0->error = node->errors[L2FWD_ERROR_FILTER_DROP]; + *next0 = L2FWD_NEXT_DROP; + + /* perform BVI check */ + } + else if (PREDICT_FALSE (result0->fields.bvi)) + { + u32 rc; + rc = l2_to_bvi (vm, + msm->vnet_main, + b0, + vnet_buffer (b0)->sw_if_index[VLIB_TX], + &msm->l3_next, next0); + + if (PREDICT_FALSE (rc)) + { + if (rc == TO_BVI_ERR_BAD_MAC) + { + b0->error = node->errors[L2FWD_ERROR_BVI_BAD_MAC]; + *next0 = L2FWD_NEXT_DROP; + } + else if (rc == TO_BVI_ERR_ETHERTYPE) + { + b0->error = node->errors[L2FWD_ERROR_BVI_ETHERTYPE]; + *next0 = L2FWD_NEXT_DROP; + } + } + } + } +} + + +static uword +l2fwd_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2fwd_next_t next_index; + l2fwd_main_t *msm = &l2fwd_main; + vlib_node_t *n = vlib_get_node (vm, l2fwd_node.index); + CLIB_UNUSED (u32 node_counter_base_index) = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + l2fib_entry_key_t cached_key; + l2fib_entry_result_t cached_result; + + /* Clear the one-entry cache in case mac table was updated */ + cached_key.raw = ~0; + cached_result.raw = ~0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 8 && n_left_to_next >= 4) + { + u32 bi0, bi1, bi2, bi3; + vlib_buffer_t *b0, *b1, *b2, *b3; + u32 next0, next1, next2, next3; + u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3; + ethernet_header_t *h0, *h1, *h2, *h3; + l2fib_entry_key_t key0, key1, key2, key3; + l2fib_entry_result_t result0, result1, result2, result3; + u32 bucket0, bucket1, bucket2, bucket3; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p4, *p5, *p6, *p7; + + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + p6 = vlib_get_buffer (vm, from[6]); + p7 = vlib_get_buffer (vm, from[7]); + + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + vlib_prefetch_buffer_header (p6, LOAD); + vlib_prefetch_buffer_header (p7, LOAD); + + CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + to_next[2] = bi2 = from[2]; + to_next[3] = bi3 = from[3]; + from += 4; + to_next += 4; + n_left_from -= 4; + n_left_to_next -= 4; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b2 = vlib_get_buffer (vm, bi2); + b3 = vlib_get_buffer (vm, bi3); + + /* RX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX]; + sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX]; + + h0 = vlib_buffer_get_current (b0); + h1 = vlib_buffer_get_current (b1); + h2 = vlib_buffer_get_current (b2); + h3 = vlib_buffer_get_current (b3); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2fwd_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2fwd_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->bd_index = vnet_buffer (b1)->l2.bd_index; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + if (b2->flags & VLIB_BUFFER_IS_TRACED) + { + l2fwd_trace_t *t = + vlib_add_trace (vm, node, b2, sizeof (*t)); + t->sw_if_index = sw_if_index2; + t->bd_index = vnet_buffer (b2)->l2.bd_index; + clib_memcpy (t->src, h2->src_address, 6); + clib_memcpy (t->dst, h2->dst_address, 6); + } + if (b3->flags & VLIB_BUFFER_IS_TRACED) + { + l2fwd_trace_t *t = + vlib_add_trace (vm, node, b3, sizeof (*t)); + t->sw_if_index = sw_if_index3; + t->bd_index = vnet_buffer (b3)->l2.bd_index; + clib_memcpy (t->src, h3->src_address, 6); + clib_memcpy (t->dst, h3->dst_address, 6); + } + } + + /* process 2 pkts */ +#ifdef COUNTERS + em->counters[node_counter_base_index + L2FWD_ERROR_L2FWD] += 4; +#endif + /* *INDENT-OFF* */ + l2fib_lookup_4 (msm->mac_table, &cached_key, &cached_result, + h0->dst_address, h1->dst_address, + h2->dst_address, h3->dst_address, + vnet_buffer (b0)->l2.bd_index, + vnet_buffer (b1)->l2.bd_index, + vnet_buffer (b2)->l2.bd_index, + vnet_buffer (b3)->l2.bd_index, + &key0, /* not used */ + &key1, /* not used */ + &key2, /* not used */ + &key3, /* not used */ + &bucket0, /* not used */ + &bucket1, /* not used */ + &bucket2, /* not used */ + &bucket3, /* not used */ + &result0, + &result1, + &result2, + &result3); + /* *INDENT-ON* */ + l2fwd_process (vm, node, msm, em, b0, sw_if_index0, &result0, + &next0); + l2fwd_process (vm, node, msm, em, b1, sw_if_index1, &result1, + &next1); + l2fwd_process (vm, node, msm, em, b2, sw_if_index2, &result2, + &next2); + l2fwd_process (vm, node, msm, em, b3, sw_if_index3, &result3, + &next3); + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x4 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, bi2, bi3, + next0, next1, next2, next3); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + ethernet_header_t *h0; + l2fib_entry_key_t key0; + l2fib_entry_result_t result0; + u32 bucket0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + h0 = vlib_buffer_get_current (b0); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2fwd_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + /* process 1 pkt */ +#ifdef COUNTERS + em->counters[node_counter_base_index + L2FWD_ERROR_L2FWD] += 1; +#endif + l2fib_lookup_1 (msm->mac_table, &cached_key, &cached_result, h0->dst_address, vnet_buffer (b0)->l2.bd_index, &key0, /* not used */ + &bucket0, /* not used */ + &result0); + l2fwd_process (vm, node, msm, em, b0, sw_if_index0, &result0, + &next0); + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2fwd_node,static) = { + .function = l2fwd_node_fn, + .name = "l2-fwd", + .vector_size = sizeof (u32), + .format_trace = format_l2fwd_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2fwd_error_strings), + .error_strings = l2fwd_error_strings, + + .n_next_nodes = L2FWD_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2FWD_NEXT_L2_OUTPUT] = "l2-output", + [L2FWD_NEXT_FLOOD] = "l2-flood", + [L2FWD_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2fwd_node, l2fwd_node_fn) + clib_error_t *l2fwd_init (vlib_main_t * vm) +{ + l2fwd_main_t *mp = &l2fwd_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* init the hash table ptr */ + mp->mac_table = get_mac_table (); + + /* Initialize the next nodes for each ethertype */ + next_by_ethertype_init (&mp->l3_next); + + return 0; +} + +VLIB_INIT_FUNCTION (l2fwd_init); + + +/** Add the L3 input node for this ethertype to the next nodes structure. */ +void +l2fwd_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index) +{ + l2fwd_main_t *mp = &l2fwd_main; + u32 next_index; + + next_index = vlib_node_add_next (vm, l2fwd_node.index, node_index); + + next_by_ethertype_register (&mp->l3_next, type, next_index); +} + + +/** + * Set subinterface forward enable/disable. + * The CLI format is: + * set interface l2 forward [disable] + */ +static clib_error_t * +int_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 enable; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the interface flag */ + if (l2input_intf_config (sw_if_index)->xconnect) + { + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_XCONNECT, enable); + } + else + { + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_FWD, enable); + } + +done: + return error; +} + +/*? + * Layer 2 unicast forwarding can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage interfaces. It is enabled by default. + * + * @cliexpar + * Example of how to enable fowarding: + * @cliexcmd{set interface l2 forward GigabitEthernet0/8/0} + * Example of how to disable fowarding: + * @cliexcmd{set interface l2 forward GigabitEthernet0/8/0 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_fwd_cli, static) = { + .path = "set interface l2 forward", + .short_help = "set interface l2 forward [disable]", + .function = int_fwd, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_fwd.h b/src/vnet/l2/l2_fwd.h new file mode 100644 index 00000000..3968732d --- /dev/null +++ b/src/vnet/l2/l2_fwd.h @@ -0,0 +1,36 @@ +/* + * l2_fwd.c : layer 2 forwarding using l2fib + * + * Copyright (c) 2013 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_l2fwd_h +#define included_l2fwd_h + +#include +#include + + +void +l2fwd_register_input_type (vlib_main_t * vm, + ethernet_type_t type, u32 node_index); +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c new file mode 100644 index 00000000..a104ec9e --- /dev/null +++ b/src/vnet/l2/l2_input.c @@ -0,0 +1,1116 @@ +/* + * l2_input.c : layer 2 input packet processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + * @file + * @brief Interface Input Mode (Layer 2 Cross-Connect or Bridge / Layer 3). + * + * This file contains the CLI Commands that modify the input mode of an + * interface. For interfaces in a Layer 2 cross-connect, all packets + * received on one interface will be transmitted to the other. For + * interfaces in a bridge-domain, packets will be forwarded to other + * interfaces in the same bridge-domain based on destination mac address. + * For interfaces in Layer 3 mode, the packets will be routed. + */ + +/* Feature graph node names */ +static char *l2input_feat_names[] = { +#define _(sym,name) name, + foreach_l2input_feat +#undef _ +}; + +char ** +l2input_get_feat_names (void) +{ + return l2input_feat_names; +} + + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u32 next_index; + u32 sw_if_index; +} l2input_trace_t; + +/* packet trace format function */ +static u8 * +format_l2input_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2input_trace_t *t = va_arg (*args, l2input_trace_t *); + + s = format (s, "l2-input: sw_if_index %d dst %U src %U", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src); + return s; +} + +l2input_main_t l2input_main; + +#define foreach_l2input_error \ +_(L2INPUT, "L2 input packets") \ +_(DROP, "L2 input drops") + +typedef enum +{ +#define _(sym,str) L2INPUT_ERROR_##sym, + foreach_l2input_error +#undef _ + L2INPUT_N_ERROR, +} l2input_error_t; + +static char *l2input_error_strings[] = { +#define _(sym,string) string, + foreach_l2input_error +#undef _ +}; + +typedef enum +{ /* */ + L2INPUT_NEXT_LEARN, + L2INPUT_NEXT_FWD, + L2INPUT_NEXT_DROP, + L2INPUT_N_NEXT, +} l2input_next_t; + + +static_always_inline void +classify_and_dispatch (vlib_main_t * vm, + vlib_node_runtime_t * node, + u32 cpu_index, + l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) +{ + /* + * Load L2 input feature struct + * Load bridge domain struct + * Parse ethernet header to determine unicast/mcast/broadcast + * take L2 input stat + * classify packet as IP/UDP/TCP, control, other + * mask feature bitmap + * go to first node in bitmap + * Later: optimize VTM + * + * For L2XC, + * set tx sw-if-handle + */ + + u16 ethertype; + u8 protocol; + l2_input_config_t *config; + l2_bridge_domain_t *bd_config; + u16 bd_index0; + u32 feature_bitmap; + u32 feat_mask; + ethernet_header_t *h0; + u8 *l3h0; + u32 sw_if_index0; + +#define get_u16(addr) ( *((u16 *)(addr)) ) + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + h0 = vlib_buffer_get_current (b0); + l3h0 = (u8 *) h0 + vnet_buffer (b0)->l2.l2_len; + + ethertype = clib_net_to_host_u16 (get_u16 (l3h0 - 2)); + feat_mask = ~0; + + /* Get config for the input interface */ + config = vec_elt_at_index (msm->configs, sw_if_index0); + + /* Save split horizon group */ + vnet_buffer (b0)->l2.shg = config->shg; + + /* determine layer2 kind for stat and mask */ + if (PREDICT_FALSE (ethernet_address_cast (h0->dst_address))) + { + protocol = ((ip6_header_t *) l3h0)->protocol; + + /* Disable bridge forwarding (flooding will execute instead if not xconnect) */ + feat_mask &= ~(L2INPUT_FEAT_FWD | L2INPUT_FEAT_UU_FLOOD); + + /* Disable ARP-term for non-ARP and non-ICMP6 packet */ + if (ethertype != ETHERNET_TYPE_ARP && + (ethertype != ETHERNET_TYPE_IP6 || protocol != IP_PROTOCOL_ICMP6)) + feat_mask &= ~(L2INPUT_FEAT_ARP_TERM); + } + else + { + /* + * Check for from-BVI processing - set SHG of unicast packets from BVI + * to 0 so it is not dropped for VXLAN tunnels or other ports with the + * same SHG as that of the BVI. + */ + if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] == + L2INPUT_BVI)) + vnet_buffer (b0)->l2.shg = 0; + } + + + if (config->xconnect) + { + /* Set the output interface */ + vnet_buffer (b0)->sw_if_index[VLIB_TX] = config->output_sw_if_index; + } + else + { + /* Do bridge-domain processing */ + bd_index0 = config->bd_index; + /* save BD ID for next feature graph nodes */ + vnet_buffer (b0)->l2.bd_index = bd_index0; + + /* Get config for the bridge domain interface */ + bd_config = vec_elt_at_index (msm->bd_configs, bd_index0); + + /* + * Process bridge domain feature enables. + * To perform learning/flooding/forwarding, the corresponding bit + * must be enabled in both the input interface config and in the + * bridge domain config. In the bd_bitmap, bits for features other + * than learning/flooding/forwarding should always be set. + */ + feat_mask = feat_mask & bd_config->feature_bitmap; + } + + /* mask out features from bitmap using packet type and bd config */ + feature_bitmap = config->feature_bitmap & feat_mask; + + /* save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; + + /* Determine the next node */ + *next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + feature_bitmap); +} + + +static uword +l2input_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2input_next_t next_index; + l2input_main_t *msm = &l2input_main; + u32 cpu_index = os_get_cpu_number (); + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 8 && n_left_to_next >= 4) + { + u32 bi0, bi1, bi2, bi3; + vlib_buffer_t *b0, *b1, *b2, *b3; + u32 next0, next1, next2, next3; + u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p4, *p5, *p6, *p7; + + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + p6 = vlib_get_buffer (vm, from[6]); + p7 = vlib_get_buffer (vm, from[7]); + + /* Prefetch the buffer header and packet for the N+2 loop iteration */ + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + vlib_prefetch_buffer_header (p6, LOAD); + vlib_prefetch_buffer_header (p7, LOAD); + + CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE); + + /* + * Don't bother prefetching the bridge-domain config (which + * depends on the input config above). Only a small number of + * bridge domains are expected. Plus the structure is small + * and several fit in a cache line. + */ + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + to_next[2] = bi2 = from[2]; + to_next[3] = bi3 = from[3]; + from += 4; + to_next += 4; + n_left_from -= 4; + n_left_to_next -= 4; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b2 = vlib_get_buffer (vm, bi2); + b3 = vlib_get_buffer (vm, bi3); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + /* RX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX]; + sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX]; + + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + l2input_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h1 = vlib_buffer_get_current (b1); + l2input_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + if (b2->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h2 = vlib_buffer_get_current (b2); + l2input_trace_t *t = + vlib_add_trace (vm, node, b2, sizeof (*t)); + t->sw_if_index = sw_if_index2; + clib_memcpy (t->src, h2->src_address, 6); + clib_memcpy (t->dst, h2->dst_address, 6); + } + if (b3->flags & VLIB_BUFFER_IS_TRACED) + { + ethernet_header_t *h3 = vlib_buffer_get_current (b3); + l2input_trace_t *t = + vlib_add_trace (vm, node, b3, sizeof (*t)); + t->sw_if_index = sw_if_index3; + clib_memcpy (t->src, h3->src_address, 6); + clib_memcpy (t->dst, h3->dst_address, 6); + } + } + + vlib_node_increment_counter (vm, l2input_node.index, + L2INPUT_ERROR_L2INPUT, 4); + + classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0); + classify_and_dispatch (vm, node, cpu_index, msm, b1, &next1); + classify_and_dispatch (vm, node, cpu_index, msm, b2, &next2); + classify_and_dispatch (vm, node, cpu_index, msm, b3, &next3); + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x4 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, bi2, bi3, + next0, next1, next2, next3); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + l2input_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + vlib_node_increment_counter (vm, l2input_node.index, + L2INPUT_ERROR_L2INPUT, 1); + + classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0); + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2input_node) = { + .function = l2input_node_fn, + .name = "l2-input", + .vector_size = sizeof (u32), + .format_trace = format_l2input_trace, + .format_buffer = format_ethernet_header_with_length, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2input_error_strings), + .error_strings = l2input_error_strings, + + .n_next_nodes = L2INPUT_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2INPUT_NEXT_LEARN] = "l2-learn", + [L2INPUT_NEXT_FWD] = "l2-fwd", + [L2INPUT_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2input_node, l2input_node_fn) + clib_error_t *l2input_init (vlib_main_t * vm) +{ + l2input_main_t *mp = &l2input_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Get packets RX'd from L2 interfaces */ + ethernet_register_l2_input (vm, l2input_node.index); + + /* Create the config vector */ + vec_validate (mp->configs, 100); + /* create 100 sw interface entries and zero them */ + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2input_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + mp->feat_next_node_index); + + return 0; +} + +VLIB_INIT_FUNCTION (l2input_init); + + +/** Get a pointer to the config for the given interface. */ +l2_input_config_t * +l2input_intf_config (u32 sw_if_index) +{ + l2input_main_t *mp = &l2input_main; + + vec_validate (mp->configs, sw_if_index); + return vec_elt_at_index (mp->configs, sw_if_index); +} + +/** Enable (or disable) the feature in the bitmap for the given interface. */ +u32 +l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) +{ + l2input_main_t *mp = &l2input_main; + l2_input_config_t *config; + + vec_validate (mp->configs, sw_if_index); + config = vec_elt_at_index (mp->configs, sw_if_index); + + if (enable) + { + config->feature_bitmap |= feature_bitmap; + } + else + { + config->feature_bitmap &= ~feature_bitmap; + } + + return config->feature_bitmap; +} + +u32 +l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value) +{ + l2_bridge_domain_t *bd_config; + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_validate (bd_config); + bd_config->feature_bitmap = + (bd_config->feature_bitmap & ~feat_mask) | feat_value; + return bd_config->feature_bitmap; +} + +/** + * Set the subinterface to run in l2 or l3 mode. + * For L3 mode, just the sw_if_index is specified. + * For bridged mode, the bd id and bvi flag are also specified. + * For xconnect mode, the peer sw_if_index is also specified. + * Return 0 if ok, or non-0 if there was an error. + */ + +u32 +set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_index, u32 bd_index, /* for bridged interface */ + u32 bvi, /* the bridged interface is the BVI */ + u32 shg, /* the bridged interface's split horizon group */ + u32 xc_sw_if_index) /* peer interface for xconnect */ +{ + l2input_main_t *mp = &l2input_main; + l2output_main_t *l2om = &l2output_main; + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hi; + l2_output_config_t *out_config; + l2_input_config_t *config; + l2_bridge_domain_t *bd_config; + l2_flood_member_t member; + u64 mac; + i32 l2_if_adjust = 0; + u32 slot; + + hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + config = l2input_intf_config (sw_if_index); + + if (config->bridge) + { + /* Interface is already in bridge mode. Undo the existing config. */ + bd_config = vec_elt_at_index (mp->bd_configs, config->bd_index); + + /* remove interface from flood vector */ + bd_remove_member (bd_config, sw_if_index); + + /* undo any BVI-related config */ + if (bd_config->bvi_sw_if_index == sw_if_index) + { + bd_config->bvi_sw_if_index = ~0; + config->bvi = 0; + + /* delete the l2fib entry for the bvi interface */ + mac = *((u64 *) hi->hw_address); + l2fib_del_entry (mac, config->bd_index); + + /* Make loop output node send packet back to ethernet-input node */ + slot = + vlib_node_add_named_next_with_slot (vm, hi->tx_node_index, + "ethernet-input", + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + } + l2_if_adjust--; + } + else if (config->xconnect) + { + l2_if_adjust--; + } + + /* + * Directs the l2 output path to work out the interface + * output next-arc itself. Needed when recycling a sw_if_index. + */ + vec_validate_init_empty (l2om->next_nodes.output_node_index_vec, + sw_if_index, ~0); + l2om->next_nodes.output_node_index_vec[sw_if_index] = ~0; + + /* Initialize the l2-input configuration for the interface */ + if (mode == MODE_L3) + { + /* Set L2 config to BD index 0 so that if any packet accidentally + * came in on L2 path, it will be dropped in BD 0 */ + config->xconnect = 0; + config->bridge = 0; + config->shg = 0; + config->bd_index = 0; + config->feature_bitmap = L2INPUT_FEAT_DROP; + + /* Make sure any L2-output packet to this interface now in L3 mode is + * dropped. This may happen if L2 FIB MAC entry is stale */ + l2om->next_nodes.output_node_index_vec[sw_if_index] = + L2OUTPUT_NEXT_BAD_INTF; + } + else if (mode == MODE_L2_CLASSIFY) + { + config->xconnect = 1; + config->bridge = 0; + config->output_sw_if_index = xc_sw_if_index; + + /* Make sure last-chance drop is configured */ + config->feature_bitmap |= + L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY; + + /* Make sure bridging features are disabled */ + config->feature_bitmap &= + ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD); + shg = 0; /* not used in xconnect */ + + /* Insure all packets go to ethernet-input */ + ethernet_set_rx_redirect (vnet_main, hi, 1); + } + else + { + + if (mode == MODE_L2_BRIDGE) + { + /* + * Remove a check that the interface must be an Ethernet. + * Specifically so we can bridge to L3 tunnel interfaces. + * Here's the check: + * if (hi->hw_class_index != ethernet_hw_interface_class.index) + * + */ + if (!hi) + return MODE_ERROR_ETH; /* non-ethernet */ + + config->xconnect = 0; + config->bridge = 1; + config->bd_index = bd_index; + + /* + * Enable forwarding, flooding, learning and ARP termination by default + * (note that ARP term is disabled on BD feature bitmap by default) + */ + config->feature_bitmap |= L2INPUT_FEAT_FWD | L2INPUT_FEAT_UU_FLOOD | + L2INPUT_FEAT_FLOOD | L2INPUT_FEAT_LEARN | L2INPUT_FEAT_ARP_TERM; + + /* Make sure last-chance drop is configured */ + config->feature_bitmap |= L2INPUT_FEAT_DROP; + + /* Make sure xconnect is disabled */ + config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT; + + /* Set up bridge domain */ + vec_validate (mp->bd_configs, bd_index); + bd_config = vec_elt_at_index (mp->bd_configs, bd_index); + bd_validate (bd_config); + + /* TODO: think: add l2fib entry even for non-bvi interface? */ + + /* Do BVI interface initializations */ + if (bvi) + { + /* ensure BD has no bvi interface (or replace that one with this??) */ + if (bd_config->bvi_sw_if_index != ~0) + { + return MODE_ERROR_BVI_DEF; /* bd already has a bvi interface */ + } + bd_config->bvi_sw_if_index = sw_if_index; + config->bvi = 1; + + /* create the l2fib entry for the bvi interface */ + mac = *((u64 *) hi->hw_address); + l2fib_add_entry (mac, bd_index, sw_if_index, 1, 0, 1); /* static + bvi */ + + /* Disable learning by default. no use since l2fib entry is static. */ + config->feature_bitmap &= ~L2INPUT_FEAT_LEARN; + + /* Make loop output node send packet to l2-input node */ + slot = + vlib_node_add_named_next_with_slot (vm, hi->tx_node_index, + "l2-input", + VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); + } + + /* Add interface to bridge-domain flood vector */ + member.sw_if_index = sw_if_index; + member.flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL; + member.shg = shg; + bd_add_member (bd_config, &member); + + } + else + { + config->xconnect = 1; + config->bridge = 0; + config->output_sw_if_index = xc_sw_if_index; + + /* Make sure last-chance drop is configured */ + config->feature_bitmap |= L2INPUT_FEAT_DROP; + + /* Make sure bridging features are disabled */ + config->feature_bitmap &= + ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD); + + config->feature_bitmap |= L2INPUT_FEAT_XCONNECT; + shg = 0; /* not used in xconnect */ + } + + /* set up split-horizon group */ + config->shg = shg; + out_config = l2output_intf_config (sw_if_index); + out_config->shg = shg; + + /* + * Test: remove this when non-IP features can be configured. + * Enable a non-IP feature to test IP feature masking + * config->feature_bitmap |= L2INPUT_FEAT_CTRL_PKT; + */ + + l2_if_adjust++; + } + + /* Adjust count of L2 interfaces */ + hi->l2_if_count += l2_if_adjust; + + if (hi->hw_class_index == ethernet_hw_interface_class.index) + { + if ((hi->l2_if_count == 1) && (l2_if_adjust == 1)) + { + /* Just added first L2 interface on this port */ + + /* Set promiscuous mode on the l2 interface */ + ethernet_set_flags (vnet_main, hi->hw_if_index, + ETHERNET_INTERFACE_FLAG_ACCEPT_ALL); + + /* ensure all packets go to ethernet-input */ + ethernet_set_rx_redirect (vnet_main, hi, 1); + + } + else if ((hi->l2_if_count == 0) && (l2_if_adjust == -1)) + { + /* Just removed only L2 subinterface on this port */ + + /* Disable promiscuous mode on the l2 interface */ + ethernet_set_flags (vnet_main, hi->hw_if_index, 0); + + /* Allow ip packets to go directly to ip4-input etc */ + ethernet_set_rx_redirect (vnet_main, hi, 0); + } + } + + /* Set up the L2/L3 flag in the interface parsing tables */ + ethernet_sw_interface_set_l2_mode (vnm, sw_if_index, (mode != MODE_L3)); + + return 0; +} + +/** + * Set subinterface in bridging mode with a bridge-domain ID. + * The CLI format is: + * set interface l2 bridge [bvi] [split-horizon-group] + */ +static clib_error_t * +int_l2_bridge (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 bd_index, bd_id; + u32 sw_if_index; + u32 bvi; + u32 rc; + u32 shg; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expected bridge domain ID `%U'", + format_unformat_error, input); + goto done; + } + + bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); + + /* optional bvi */ + bvi = unformat (input, "bvi"); + + /* optional split horizon group */ + shg = 0; + (void) unformat (input, "%d", &shg); + + /* set the interface mode */ + if ((rc = + set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, sw_if_index, bd_index, bvi, + shg, 0))) + { + if (rc == MODE_ERROR_ETH) + { + error = clib_error_return (0, "bridged interface must be ethernet", + format_unformat_error, input); + } + else if (rc == MODE_ERROR_BVI_DEF) + { + error = + clib_error_return (0, "bridge-domain already has a bvi interface", + format_unformat_error, input); + } + else + { + error = clib_error_return (0, "invalid configuration for interface", + format_unformat_error, input); + } + goto done; + } + +done: + return error; +} + +/*? + * Use this command put an interface into Layer 2 bridge domain. If a + * bridge-domain with the provided bridge-domain-id does not exist, it + * will be created. Interfaces in a bridge-domain forward packets to + * other interfaces in the same bridge-domain based on destination mac + * address. To remove an interface from a the Layer 2 bridge domain, + * put the interface in a different mode, for example Layer 3 mode. + * + * Optionally, an interface can be added to a Layer 2 bridge-domain as + * a Bridged Virtual Interface (bvi). Only one interface in a Layer 2 + * bridge-domain can be a bvi. + * + * Optionally, a split-horizon group can also be specified. This defaults + * to 0 if not specified. + * + * @cliexpar + * Example of how to configure a Layer 2 bridge-domain with three + * interfaces (where 200 is the bridge-domain-id): + * @cliexcmd{set interface l2 bridge GigabitEthernet0/8/0.200 200} + * This interface is added a BVI interface: + * @cliexcmd{set interface l2 bridge GigabitEthernet0/9/0.200 200 bvi} + * This interface also has a split-horizon group of 1 specified: + * @cliexcmd{set interface l2 bridge GigabitEthernet0/a/0.200 200 1} + * Example of how to remove an interface from a Layer2 bridge-domain: + * @cliexcmd{set interface l3 GigabitEthernet0/a/0.200} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_bridge_cli, static) = { + .path = "set interface l2 bridge", + .short_help = "set interface l2 bridge [bvi] [shg]", + .function = int_l2_bridge, +}; +/* *INDENT-ON* */ + +/** + * Set subinterface in xconnect mode with another interface. + * The CLI format is: + * set interface l2 xconnect + */ +static clib_error_t * +int_l2_xc (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 xc_sw_if_index; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + if (!unformat_user + (input, unformat_vnet_sw_interface, vnm, &xc_sw_if_index)) + { + error = clib_error_return (0, "unknown peer interface `%U'", + format_unformat_error, input); + goto done; + } + + /* set the interface mode */ + if (set_int_l2_mode + (vm, vnm, MODE_L2_XC, sw_if_index, 0, 0, 0, xc_sw_if_index)) + { + error = clib_error_return (0, "invalid configuration for interface", + format_unformat_error, input); + goto done; + } + +done: + return error; +} + +/*? + * Use this command put an interface into Layer 2 cross-connect mode. + * Both interfaces must be in this mode for bi-directioal traffic. All + * packets received on one interface will be transmitted to the other. + * To remove the Layer 2 cross-connect, put the interface in a different + * mode, for example Layer 3 mode. + * + * @cliexpar + * Example of how to configure a Layer2 cross-connect between two interfaces: + * @cliexcmd{set interface l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300} + * @cliexcmd{set interface l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300} + * Example of how to remove a Layer2 cross-connect: + * @cliexcmd{set interface l3 GigabitEthernet0/8/0.300} + * @cliexcmd{set interface l3 GigabitEthernet0/9/0.300} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_xc_cli, static) = { + .path = "set interface l2 xconnect", + .short_help = "set interface l2 xconnect ", + .function = int_l2_xc, +}; +/* *INDENT-ON* */ + +/** + * Set subinterface in L3 mode. + * The CLI format is: + * set interface l3 + */ +static clib_error_t * +int_l3 (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + /* set the interface mode */ + if (set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0)) + { + error = clib_error_return (0, "invalid configuration for interface", + format_unformat_error, input); + goto done; + } + +done: + return error; +} + +/*? + * Modify the packet processing mode of the interface to Layer 3, which + * implies packets will be routed. This is the default mode of an interface. + * Use this command to remove an interface from a Layer 2 cross-connect or a + * Layer 2 bridge. + * + * @cliexpar + * Example of how to set the mode of an interface to Layer 3: + * @cliexcmd{set interface l3 GigabitEthernet0/8/0.200} +?*/ +/* *INDENT-OFF* */ + VLIB_CLI_COMMAND (int_l3_cli, static) = { + .path = "set interface l3", + .short_help = "set interface l3 ", + .function = int_l3, +}; +/* *INDENT-ON* */ + +/** + * Show interface mode. + * The CLI format is: + * show mode [ ...] + */ +static clib_error_t * +show_int_mode (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + char *mode; + u8 *args; + vnet_interface_main_t *im = &vnm->interface_main; + vnet_sw_interface_t *si, *sis = 0; + l2input_main_t *mp = &l2input_main; + l2_input_config_t *config; + + 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)) + { + si = pool_elt_at_index (im->sw_interfaces, sw_if_index); + vec_add1 (sis, si[0]); + } + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + goto done; + } + + } + + if (vec_len (sis) == 0) /* Get all interfaces */ + { + /* Gather interfaces. */ + sis = vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces)); + _vec_len (sis) = 0; + /* *INDENT-OFF* */ + pool_foreach (si, im->sw_interfaces, ({ vec_add1 (sis, si[0]); })); + /* *INDENT-ON* */ + } + + vec_foreach (si, sis) + { + vec_validate (mp->configs, si->sw_if_index); + config = vec_elt_at_index (mp->configs, si->sw_if_index); + if (config->bridge) + { + u32 bd_id; + mode = "l2 bridge"; + bd_id = l2input_main.bd_configs[config->bd_index].bd_id; + + args = format (0, "bd_id %d%s%d", bd_id, + config->bvi ? " bvi shg " : " shg ", config->shg); + } + else if (config->xconnect) + { + mode = "l2 xconnect"; + args = format (0, "%U", + format_vnet_sw_if_index_name, + vnm, config->output_sw_if_index); + } + else + { + mode = "l3"; + args = format (0, " "); + } + vlib_cli_output (vm, "%s %U %v\n", + mode, + format_vnet_sw_if_index_name, + vnm, si->sw_if_index, args); + vec_free (args); + } + +done: + vec_free (sis); + + return error; +} + +/*? + * Show the packet processing mode (Layer2 xcross-onnect, Layer 2 bridge, + * Layer 3 routed) of all interfaces and sub-interfaces, or limit the + * output to just the provided list of interfaces and sub-interfaces. + * The output shows the mode, the interface, and if the interface is + * a member of a bridge, the bridge-domain-id and the split horizen group (shg). + * + * @cliexpar + * Example of displaying the mode of all interfaces: + * @cliexstart{show mode} + * l3 local0 + * l3 GigabitEthernet0/8/0 + * l3 GigabitEthernet0/9/0 + * l3 GigabitEthernet0/a/0 + * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0 + * l2 bridge GigabitEthernet0/9/0.200 bd_id 200 shg 0 + * l2 bridge GigabitEthernet0/a/0.200 bd_id 200 shg 0 + * l2 xconnect GigabitEthernet0/8/0.300 GigabitEthernet0/9/0.300 + * l2 xconnect GigabitEthernet0/9/0.300 GigabitEthernet0/8/0.300 + * @cliexend + * Example of displaying the mode of a seleted list of interfaces: + * @cliexstart{show mode GigabitEthernet0/8/0 GigabitEthernet0/8/0.200} + * l3 GigabitEthernet0/8/0 + * l2 bridge GigabitEthernet0/8/0.200 bd_id 200 shg 0 + * @cliexend +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_l2_mode, static) = { + .path = "show mode", + .short_help = "show mode [ ...]", + .function = show_int_mode, +}; +/* *INDENT-ON* */ + +#define foreach_l2_init_function \ +_(feat_bitmap_drop_init) \ +_(l2fib_init) \ +_(l2_input_classify_init) \ +_(l2bd_init) \ +_(l2fwd_init) \ +_(l2_inacl_init) \ +_(l2input_init) \ +_(l2_vtr_init) \ +_(l2_invtr_init) \ +_(l2_efp_filter_init) \ +_(l2learn_init) \ +_(l2flood_init) \ +_(l2_outacl_init) \ +_(l2output_init) \ +_(l2_patch_init) \ +_(l2_xcrw_init) + +clib_error_t * +l2_init (vlib_main_t * vm) +{ + clib_error_t *error; + +#define _(a) do { \ + if ((error = vlib_call_init_function (vm, a))) return error; } \ +while (0); + foreach_l2_init_function; +#undef _ + return 0; +} + +VLIB_INIT_FUNCTION (l2_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h new file mode 100644 index 00000000..f3fada6a --- /dev/null +++ b/src/vnet/l2/l2_input.h @@ -0,0 +1,266 @@ +/* + * l2_input.h : layer 2 input packet processing + * + * Copyright (c) 2013 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_vnet_l2_input_h +#define included_vnet_l2_input_h + +#include +#include +#include +#include +#include + +/* Per-subinterface L2 feature configuration */ + +typedef struct +{ + + union + { + u16 bd_index; /* bridge domain id */ + u32 output_sw_if_index; /* for xconnect */ + }; + + /* Interface mode. If both are 0, this interface is in L3 mode */ + u8 xconnect; + u8 bridge; + + /* this is the bvi interface for the bridge-domain */ + u8 bvi; + + /* config for which input features are configured on this interface */ + u32 feature_bitmap; + + /* some of these flags are also in the feature bitmap */ + u8 learn_enable; + u8 fwd_enable; + u8 flood_enable; + + /* split horizon group */ + u8 shg; + +} l2_input_config_t; + + +typedef struct +{ + + /* Next nodes for the feature bitmap */ + u32 feat_next_node_index[32]; + + /* config vector indexed by sw_if_index */ + l2_input_config_t *configs; + + /* bridge domain config vector indexed by bd_index */ + l2_bridge_domain_t *bd_configs; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2input_main_t; + +extern l2input_main_t l2input_main; + +extern vlib_node_registration_t l2input_node; + +static_always_inline l2_bridge_domain_t * +l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index) +{ + l2_bridge_domain_t *bd_config; + + bd_config = vec_elt_at_index (l2im->bd_configs, bd_index); + return bd_is_valid (bd_config) ? bd_config : NULL; +} + +/* L2 input indication packet is from BVI, using -2 */ +#define L2INPUT_BVI ((u32) (~0-1)) + +/* L2 input features */ + +/* Mappings from feature ID to graph node name */ +#define foreach_l2input_feat \ + _(DROP, "feature-bitmap-drop") \ + _(XCONNECT, "l2-output") \ + _(FLOOD, "l2-flood") \ + _(ARP_TERM, "arp-term-l2bd") \ + _(UU_FLOOD, "l2-flood") \ + _(FWD, "l2-fwd") \ + _(RW, "l2-rw") \ + _(LEARN, "l2-learn") \ + _(VTR, "l2-input-vtr") \ + _(VPATH, "vpath-input-l2") \ + _(ACL, "l2-input-acl") \ + _(POLICER_CLAS, "l2-policer-classify") \ + _(INPUT_CLASSIFY, "l2-input-classify") + +/* Feature bitmap positions */ +typedef enum +{ +#define _(sym,str) L2INPUT_FEAT_##sym##_BIT, + foreach_l2input_feat +#undef _ + L2INPUT_N_FEAT, +} l2input_feat_t; + +/* Feature bit masks */ +typedef enum +{ +#define _(sym,str) L2INPUT_FEAT_##sym = (1<feature_bitmap & L2INPUT_FEAT_FLOOD) == + L2INPUT_FEAT_FLOOD); +} + +static_always_inline u8 +bd_feature_uu_flood (l2_bridge_domain_t * bd_config) +{ + return ((bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD) == + L2INPUT_FEAT_UU_FLOOD); +} + +static_always_inline u8 +bd_feature_forward (l2_bridge_domain_t * bd_config) +{ + return ((bd_config->feature_bitmap & L2INPUT_FEAT_FWD) == L2INPUT_FEAT_FWD); +} + +static_always_inline u8 +bd_feature_learn (l2_bridge_domain_t * bd_config) +{ + return ((bd_config->feature_bitmap & L2INPUT_FEAT_LEARN) == + L2INPUT_FEAT_LEARN); +} + +static_always_inline u8 +bd_feature_arp_term (l2_bridge_domain_t * bd_config) +{ + return ((bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM) == + L2INPUT_FEAT_ARP_TERM); +} + +/** Masks for eliminating features that do not apply to a packet */ + +/** Get a pointer to the config for the given interface */ +l2_input_config_t *l2input_intf_config (u32 sw_if_index); + +/* Enable (or disable) the feature in the bitmap for the given interface */ +u32 l2input_intf_bitmap_enable (u32 sw_if_index, + u32 feature_bitmap, u32 enable); + +/* Sets modifies flags from a bridge domain */ +u32 l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value); + + +#define MODE_L3 0 +#define MODE_L2_BRIDGE 1 +#define MODE_L2_XC 2 +#define MODE_L2_CLASSIFY 3 + +#define MODE_ERROR_ETH 1 +#define MODE_ERROR_BVI_DEF 2 + +u32 set_int_l2_mode (vlib_main_t * vm, + vnet_main_t * vnet_main, + u32 mode, + u32 sw_if_index, + u32 bd_index, u32 bvi, u32 shg, u32 xc_sw_if_index); + +static inline void +vnet_update_l2_len (vlib_buffer_t * b) +{ + ethernet_header_t *eth; + u16 ethertype; + u8 vlan_count = 0; + + /* point at currrent l2 hdr */ + eth = vlib_buffer_get_current (b); + + /* + * l2-output pays no attention to this + * but the tag push/pop code on an l2 subif needs it. + * + * Determine l2 header len, check for up to 2 vlans + */ + vnet_buffer (b)->l2.l2_len = sizeof (ethernet_header_t); + ethertype = clib_net_to_host_u16 (eth->type); + if (ethernet_frame_is_tagged (ethertype)) + { + ethernet_vlan_header_t *vlan; + vnet_buffer (b)->l2.l2_len += sizeof (*vlan); + vlan_count = 1; + vlan = (void *) (eth + 1); + ethertype = clib_net_to_host_u16 (vlan->type); + if (ethertype == ETHERNET_TYPE_VLAN) + { + vnet_buffer (b)->l2.l2_len += sizeof (*vlan); + vlan_count = 2; + } + } + ethernet_buffer_set_vlan_count (b, vlan_count); +} + +/* + * Compute flow hash of an ethernet packet, use 5-tuple hash if L3 packet + * is ip4 or ip6. Otherwise hash on smac/dmac/etype. + * The vlib buffer current pointer is expected to be at ethernet header + * and vnet l2.l2_len is exppected to be setup already. + */ +static inline u32 +vnet_l2_compute_flow_hash (vlib_buffer_t * b) +{ + ethernet_header_t *eh = vlib_buffer_get_current (b); + u8 *l3h = (u8 *) eh + vnet_buffer (b)->l2.l2_len; + u16 ethertype = clib_net_to_host_u16 (*(u16 *) (l3h - 2)); + + if (ethertype == ETHERNET_TYPE_IP4) + return ip4_compute_flow_hash ((ip4_header_t *) l3h, IP_FLOW_HASH_DEFAULT); + else if (ethertype == ETHERNET_TYPE_IP6) + return ip6_compute_flow_hash ((ip6_header_t *) l3h, IP_FLOW_HASH_DEFAULT); + else + { + u32 a, b, c; + u32 *ap = (u32 *) & eh->dst_address[2]; + u32 *bp = (u32 *) & eh->src_address[2]; + a = *ap; + b = *bp; + c = ethertype; + hash_v3_mix32 (a, b, c); + hash_v3_finalize32 (a, b, c); + return c; + } +} + +#endif + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input_acl.c b/src/vnet/l2/l2_input_acl.c new file mode 100644 index 00000000..104fcd15 --- /dev/null +++ b/src/vnet/l2/l2_input_acl.c @@ -0,0 +1,434 @@ +/* + * l2_input_acl.c : layer 2 input acl processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +typedef struct +{ + + /* Next nodes for each feature */ + u32 feat_next_node_index[32]; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_inacl_main_t; + +typedef struct +{ + u32 sw_if_index; + u32 next_index; + u32 table_index; + u32 offset; +} l2_inacl_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_inacl_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_inacl_trace_t *t = va_arg (*args, l2_inacl_trace_t *); + + s = format (s, "INACL: sw_if_index %d, next_index %d, table %d, offset %d", + t->sw_if_index, t->next_index, t->table_index, t->offset); + return s; +} + +l2_inacl_main_t l2_inacl_main; + +static vlib_node_registration_t l2_inacl_node; + +#define foreach_l2_inacl_error \ +_(NONE, "valid input ACL packets") \ +_(MISS, "input ACL misses") \ +_(HIT, "input ACL hits") \ +_(CHAIN_HIT, "input ACL hits after chain walk") \ +_(TABLE_MISS, "input ACL table-miss drops") \ +_(SESSION_DENY, "input ACL session deny drops") + + +typedef enum +{ +#define _(sym,str) L2_INACL_ERROR_##sym, + foreach_l2_inacl_error +#undef _ + L2_INACL_N_ERROR, +} l2_inacl_error_t; + +static char *l2_inacl_error_strings[] = { +#define _(sym,string) string, + foreach_l2_inacl_error +#undef _ +}; + +static uword +l2_inacl_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + acl_next_index_t next_index; + l2_inacl_main_t *msm = &l2_inacl_main; + input_acl_main_t *am = &input_acl_main; + vnet_classify_main_t *vcm = am->vnet_classify_main; + input_acl_table_id_t tid = INPUT_ACL_TABLE_L2; + f64 now = vlib_time_now (vm); + u32 hits = 0; + u32 misses = 0; + u32 chain_hits = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + /* First pass: compute hashes */ + while (n_left_from > 2) + { + vlib_buffer_t *b0, *b1; + u32 bi0, bi1; + u8 *h0, *h1; + u32 sw_if_index0, sw_if_index1; + u32 table_index0, table_index1; + vnet_classify_table_t *t0, *t1; + + /* prefetch next iteration */ + { + vlib_buffer_t *p1, *p2; + + p1 = vlib_get_buffer (vm, from[1]); + p2 = vlib_get_buffer (vm, from[2]); + + vlib_prefetch_buffer_header (p1, STORE); + CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE); + vlib_prefetch_buffer_header (p2, STORE); + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + + bi1 = from[1]; + b1 = vlib_get_buffer (vm, bi1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + table_index0 = + am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + table_index1 = + am->classify_table_index_by_sw_if_index[tid][sw_if_index1]; + + t0 = pool_elt_at_index (vcm->tables, table_index0); + + t1 = pool_elt_at_index (vcm->tables, table_index1); + + if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA) + h0 = (void *) vlib_buffer_get_current (b0) + t0->current_data_offset; + else + h0 = b0->data; + + vnet_buffer (b0)->l2_classify.hash = + vnet_classify_hash_packet (t0, (u8 *) h0); + + vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash); + + if (t1->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA) + h1 = (void *) vlib_buffer_get_current (b1) + t1->current_data_offset; + else + h1 = b1->data; + + vnet_buffer (b1)->l2_classify.hash = + vnet_classify_hash_packet (t1, (u8 *) h1); + + vnet_classify_prefetch_bucket (t1, vnet_buffer (b1)->l2_classify.hash); + + vnet_buffer (b0)->l2_classify.table_index = table_index0; + + vnet_buffer (b1)->l2_classify.table_index = table_index1; + + from += 2; + n_left_from -= 2; + } + + while (n_left_from > 0) + { + vlib_buffer_t *b0; + u32 bi0; + u8 *h0; + u32 sw_if_index0; + u32 table_index0; + vnet_classify_table_t *t0; + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + table_index0 = + am->classify_table_index_by_sw_if_index[tid][sw_if_index0]; + + t0 = pool_elt_at_index (vcm->tables, table_index0); + + if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA) + h0 = (void *) vlib_buffer_get_current (b0) + t0->current_data_offset; + else + h0 = b0->data; + + vnet_buffer (b0)->l2_classify.hash = + vnet_classify_hash_packet (t0, (u8 *) h0); + + vnet_buffer (b0)->l2_classify.table_index = table_index0; + vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash); + + from++; + n_left_from--; + } + + next_index = node->cached_next_index; + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Not enough load/store slots to dual loop... */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = ACL_NEXT_INDEX_DENY; + u32 table_index0; + vnet_classify_table_t *t0; + vnet_classify_entry_t *e0; + u64 hash0; + u8 *h0; + u8 error0; + + /* Stride 3 seems to work best */ + if (PREDICT_TRUE (n_left_from > 3)) + { + vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]); + vnet_classify_table_t *tp1; + u32 table_index1; + u64 phash1; + + table_index1 = vnet_buffer (p1)->l2_classify.table_index; + + if (PREDICT_TRUE (table_index1 != ~0)) + { + tp1 = pool_elt_at_index (vcm->tables, table_index1); + phash1 = vnet_buffer (p1)->l2_classify.hash; + vnet_classify_prefetch_entry (tp1, phash1); + } + } + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + table_index0 = vnet_buffer (b0)->l2_classify.table_index; + e0 = 0; + t0 = 0; + + /* Feature bitmap update */ + vnet_buffer (b0)->l2.feature_bitmap &= ~L2INPUT_FEAT_ACL; + + vnet_buffer (b0)->l2_classify.opaque_index = ~0; + /* Determine the next node */ + next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + vnet_buffer (b0)-> + l2.feature_bitmap); + + if (PREDICT_TRUE (table_index0 != ~0)) + { + hash0 = vnet_buffer (b0)->l2_classify.hash; + t0 = pool_elt_at_index (vcm->tables, table_index0); + + if (t0->current_data_flag == CLASSIFY_FLAG_USE_CURR_DATA) + h0 = + (void *) vlib_buffer_get_current (b0) + + t0->current_data_offset; + else + h0 = b0->data; + + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + if (e0) + { + vnet_buffer (b0)->l2_classify.opaque_index + = e0->opaque_index; + vlib_buffer_advance (b0, e0->advance); + + next0 = (e0->next_index < ACL_NEXT_INDEX_N_NEXT) ? + e0->next_index : next0; + + hits++; + + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_INACL_ERROR_SESSION_DENY : L2_INACL_ERROR_NONE; + b0->error = node->errors[error0]; + } + else + { + while (1) + { + if (PREDICT_TRUE (t0->next_table_index != ~0)) + t0 = pool_elt_at_index (vcm->tables, + t0->next_table_index); + else + { + next0 = + (t0->miss_next_index < + ACL_NEXT_INDEX_N_NEXT) ? t0->miss_next_index : + next0; + + misses++; + + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_INACL_ERROR_TABLE_MISS : L2_INACL_ERROR_NONE; + b0->error = node->errors[error0]; + break; + } + + if (t0->current_data_flag == + CLASSIFY_FLAG_USE_CURR_DATA) + h0 = + (void *) vlib_buffer_get_current (b0) + + t0->current_data_offset; + else + h0 = b0->data; + + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = vnet_classify_find_entry + (t0, (u8 *) h0, hash0, now); + if (e0) + { + vlib_buffer_advance (b0, e0->advance); + next0 = (e0->next_index < ACL_NEXT_INDEX_N_NEXT) ? + e0->next_index : next0; + hits++; + chain_hits++; + + error0 = (next0 == ACL_NEXT_INDEX_DENY) ? + L2_INACL_ERROR_SESSION_DENY : L2_INACL_ERROR_NONE; + b0->error = node->errors[error0]; + break; + } + } + } + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_inacl_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->next_index = next0; + t->table_index = t0 ? t0 - vcm->tables : ~0; + t->offset = (t0 && e0) ? vnet_classify_get_offset (t0, e0) : ~0; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + L2_INACL_ERROR_MISS, misses); + vlib_node_increment_counter (vm, node->node_index, + L2_INACL_ERROR_HIT, hits); + vlib_node_increment_counter (vm, node->node_index, + L2_INACL_ERROR_CHAIN_HIT, chain_hits); + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_inacl_node,static) = { + .function = l2_inacl_node_fn, + .name = "l2-input-acl", + .vector_size = sizeof (u32), + .format_trace = format_l2_inacl_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_inacl_error_strings), + .error_strings = l2_inacl_error_strings, + + .n_next_nodes = ACL_NEXT_INDEX_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [ACL_NEXT_INDEX_DENY] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_inacl_node, l2_inacl_node_fn) + clib_error_t *l2_inacl_init (vlib_main_t * vm) +{ + l2_inacl_main_t *mp = &l2_inacl_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_inacl_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + mp->feat_next_node_index); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_inacl_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input_classify.c b/src/vnet/l2/l2_input_classify.c new file mode 100644 index 00000000..497df192 --- /dev/null +++ b/src/vnet/l2/l2_input_classify.c @@ -0,0 +1,655 @@ +/* + * 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. + */ +/* + * l2_classify.c + */ + +#include +#include + +/** + * @file + * @brief L2 input classifier. + * + * @sa @ref vnet/vnet/classify/vnet_classify.c + * @sa @ref vnet/vnet/classify/vnet_classify.h + */ + +/** + * @brief l2_input_classifier packet trace record. + */ +typedef struct +{ + /** interface handle for the ith packet */ + u32 sw_if_index; + /** graph arc index selected for this packet */ + u32 next_index; + /** classifier table which provided the final result */ + u32 table_index; + /** offset in classifier heap of the corresponding session */ + u32 session_offset; +} l2_input_classify_trace_t; + +/** + * @brief vlib node runtime. + */ +typedef struct +{ + /** use-case independent main object pointer */ + vnet_classify_main_t *vcm; + /** l2 input classifier main object pointer */ + l2_input_classify_main_t *l2cm; +} l2_input_classify_runtime_t; + +/** Packet trace format function. */ +static u8 * +format_l2_input_classify_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_input_classify_trace_t *t = va_arg (*args, l2_input_classify_trace_t *); + + s = format (s, "l2-classify: sw_if_index %d, table %d, offset %x, next %d", + t->sw_if_index, t->table_index, t->session_offset, + t->next_index); + return s; +} + +/** l2 input classifier main data structure. */ +l2_input_classify_main_t l2_input_classify_main; + +vlib_node_registration_t l2_input_classify_node; + +#define foreach_l2_input_classify_error \ +_(MISS, "Classify misses") \ +_(HIT, "Classify hits") \ +_(CHAIN_HIT, "Classify hits after chain walk") \ +_(DROP, "L2 Classify Drops") + +typedef enum +{ +#define _(sym,str) L2_INPUT_CLASSIFY_ERROR_##sym, + foreach_l2_input_classify_error +#undef _ + L2_INPUT_CLASSIFY_N_ERROR, +} l2_input_classify_error_t; + +static char *l2_input_classify_error_strings[] = { +#define _(sym,string) string, + foreach_l2_input_classify_error +#undef _ +}; + +/** + * @brief l2 input classifier node. + * @node l2-input-classify + * + * This is the l2 input classifier dispatch node + * + * @param vm vlib_main_t corresponding to the current thread. + * @param node vlib_node_runtime_t data for this node. + * @param frame vlib_frame_t whose contents should be dispatched. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * @em Uses: + * - (l2_input_classify_runtime_t *) + * rt->classify_table_index_by_sw_if_index + * - Head of the per-interface, per-protocol classifier table chain + * for a specific interface. + * - @c ~0 => send pkts to the next feature in the L2 feature chain. + * - vnet_buffer(b)->sw_if_index[VLIB_RX] + * - Indicates the @c sw_if_index value of the interface that the + * packet was received on. + * - vnet_buffer(b0)->l2.feature_bitmap + * - Used to steer packets across l2 features enabled on the interface + * - (vnet_classify_entry_t) e0->next_index + * - Used to steer traffic when the classifier hits on a session + * - (vnet_classify_entry_t) e0->advance + * - Signed quantity applied via vlib_buffer_advance + * when the classifier hits on a session + * - (vnet_classify_table_t) t0->miss_next_index + * - Used to steer traffic when the classifier misses + * + * @em Sets: + * - vnet_buffer (b0)->l2_classify.table_index + * - Classifier table index of the first classifier table in + * the classifier table chain + * - vnet_buffer (b0)->l2_classify.hash + * - Bounded-index extensible hash corresponding to the + * masked fields in the current packet + * - vnet_buffer (b0)->l2.feature_bitmap + * - Used to steer packets across l2 features enabled on the interface + * - vnet_buffer (b0)->l2_classify.opaque_index + * - Copied from the classifier session object upon classifier hit + * + * @em Counters: + * - L2_INPUT_CLASSIFY_ERROR_MISS Classifier misses + * - L2_INPUT_CLASSIFY_ERROR_HIT Classifier hits + * - L2_INPUT_CLASSIFY_ERROR_CHAIN_HIT + * Classifier hits in other than the first table + */ + +static uword +l2_input_classify_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_input_classify_next_t next_index; + l2_input_classify_main_t *cm = &l2_input_classify_main; + vnet_classify_main_t *vcm = cm->vnet_classify_main; + l2_input_classify_runtime_t *rt = + (l2_input_classify_runtime_t *) node->runtime_data; + u32 feature_bitmap; + u32 hits = 0; + u32 misses = 0; + u32 chain_hits = 0; + f64 now; + u32 n_next_nodes; + + n_next_nodes = node->n_next_nodes; + + now = vlib_time_now (vm); + + n_left_from = frame->n_vectors; + from = vlib_frame_vector_args (frame); + + /* First pass: compute hash */ + + while (n_left_from > 2) + { + vlib_buffer_t *b0, *b1; + u32 bi0, bi1; + ethernet_header_t *h0, *h1; + u32 sw_if_index0, sw_if_index1; + u16 type0, type1; + int type_index0, type_index1; + vnet_classify_table_t *t0, *t1; + u32 table_index0, table_index1; + u64 hash0, hash1; + + + /* prefetch next iteration */ + { + vlib_buffer_t *p1, *p2; + + p1 = vlib_get_buffer (vm, from[1]); + p2 = vlib_get_buffer (vm, from[2]); + + vlib_prefetch_buffer_header (p1, STORE); + CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE); + vlib_prefetch_buffer_header (p2, STORE); + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + bi1 = from[1]; + b1 = vlib_get_buffer (vm, bi1); + h1 = vlib_buffer_get_current (b1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->l2_classify.table_index = ~0; + + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + vnet_buffer (b1)->l2_classify.table_index = ~0; + + /* Select classifier table based on ethertype */ + type0 = clib_net_to_host_u16 (h0->type); + type1 = clib_net_to_host_u16 (h1->type); + + type_index0 = (type0 == ETHERNET_TYPE_IP4) + ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER; + type_index0 = (type0 == ETHERNET_TYPE_IP6) + ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index0; + + type_index1 = (type1 == ETHERNET_TYPE_IP4) + ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER; + type_index1 = (type1 == ETHERNET_TYPE_IP6) + ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index1; + + vnet_buffer (b0)->l2_classify.table_index = + table_index0 = + rt->l2cm->classify_table_index_by_sw_if_index + [type_index0][sw_if_index0]; + + if (table_index0 != ~0) + { + t0 = pool_elt_at_index (vcm->tables, table_index0); + + vnet_buffer (b0)->l2_classify.hash = hash0 = + vnet_classify_hash_packet (t0, (u8 *) h0); + vnet_classify_prefetch_bucket (t0, hash0); + } + + vnet_buffer (b1)->l2_classify.table_index = + table_index1 = + rt->l2cm->classify_table_index_by_sw_if_index + [type_index1][sw_if_index1]; + + if (table_index1 != ~0) + { + t1 = pool_elt_at_index (vcm->tables, table_index1); + + vnet_buffer (b1)->l2_classify.hash = hash1 = + vnet_classify_hash_packet (t1, (u8 *) h1); + vnet_classify_prefetch_bucket (t1, hash1); + } + + from += 2; + n_left_from -= 2; + } + + while (n_left_from > 0) + { + vlib_buffer_t *b0; + u32 bi0; + ethernet_header_t *h0; + u32 sw_if_index0; + u16 type0; + u32 type_index0; + vnet_classify_table_t *t0; + u32 table_index0; + u64 hash0; + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->l2_classify.table_index = ~0; + + /* Select classifier table based on ethertype */ + type0 = clib_net_to_host_u16 (h0->type); + + type_index0 = (type0 == ETHERNET_TYPE_IP4) + ? L2_INPUT_CLASSIFY_TABLE_IP4 : L2_INPUT_CLASSIFY_TABLE_OTHER; + type_index0 = (type0 == ETHERNET_TYPE_IP6) + ? L2_INPUT_CLASSIFY_TABLE_IP6 : type_index0; + + vnet_buffer (b0)->l2_classify.table_index = + table_index0 = rt->l2cm->classify_table_index_by_sw_if_index + [type_index0][sw_if_index0]; + + if (table_index0 != ~0) + { + t0 = pool_elt_at_index (vcm->tables, table_index0); + + vnet_buffer (b0)->l2_classify.hash = hash0 = + vnet_classify_hash_packet (t0, (u8 *) h0); + vnet_classify_prefetch_bucket (t0, hash0); + } + from++; + n_left_from--; + } + + next_index = node->cached_next_index; + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Not enough load/store slots to dual loop... */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = ~0; /* next l2 input feature, please... */ + ethernet_header_t *h0; + u32 table_index0; + u64 hash0; + vnet_classify_table_t *t0; + vnet_classify_entry_t *e0; + + if (PREDICT_TRUE (n_left_from > 2)) + { + vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]); + u64 phash2; + u32 table_index2; + vnet_classify_table_t *tp2; + + /* + * Prefetch table entry two ahead. Buffer / data + * were prefetched above... + */ + table_index2 = vnet_buffer (p2)->l2_classify.table_index; + + if (PREDICT_TRUE (table_index2 != ~0)) + { + tp2 = pool_elt_at_index (vcm->tables, table_index2); + phash2 = vnet_buffer (p2)->l2_classify.hash; + vnet_classify_prefetch_entry (tp2, phash2); + } + } + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + table_index0 = vnet_buffer (b0)->l2_classify.table_index; + e0 = 0; + vnet_buffer (b0)->l2_classify.opaque_index = ~0; + + /* Remove ourself from the feature bitmap */ + feature_bitmap = vnet_buffer (b0)->l2.feature_bitmap + & ~L2INPUT_FEAT_INPUT_CLASSIFY; + + /* save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; + + if (PREDICT_TRUE (table_index0 != ~0)) + { + hash0 = vnet_buffer (b0)->l2_classify.hash; + t0 = pool_elt_at_index (vcm->tables, table_index0); + + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + if (e0) + { + vnet_buffer (b0)->l2_classify.opaque_index + = e0->opaque_index; + vlib_buffer_advance (b0, e0->advance); + next0 = (e0->next_index < n_next_nodes) ? + e0->next_index : next0; + hits++; + } + else + { + while (1) + { + if (t0->next_table_index != ~0) + t0 = pool_elt_at_index (vcm->tables, + t0->next_table_index); + else + { + next0 = (t0->miss_next_index < n_next_nodes) ? + t0->miss_next_index : next0; + misses++; + break; + } + + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = + vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + if (e0) + { + vnet_buffer (b0)->l2_classify.opaque_index + = e0->opaque_index; + vlib_buffer_advance (b0, e0->advance); + next0 = (e0->next_index < n_next_nodes) ? + e0->next_index : next0; + hits++; + chain_hits++; + break; + } + } + } + } + + if (PREDICT_FALSE (next0 == 0)) + b0->error = node->errors[L2_INPUT_CLASSIFY_ERROR_DROP]; + + if (PREDICT_TRUE (next0 == ~0)) + { + // Determine the next node + next0 = + feat_bitmap_get_next_node_index (cm->feat_next_node_index, + feature_bitmap); + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_input_classify_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->table_index = table_index0; + t->next_index = next0; + t->session_offset = e0 ? vnet_classify_get_offset (t0, e0) : 0; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + L2_INPUT_CLASSIFY_ERROR_MISS, misses); + vlib_node_increment_counter (vm, node->node_index, + L2_INPUT_CLASSIFY_ERROR_HIT, hits); + vlib_node_increment_counter (vm, node->node_index, + L2_INPUT_CLASSIFY_ERROR_CHAIN_HIT, chain_hits); + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_input_classify_node) = { + .function = l2_input_classify_node_fn, + .name = "l2-input-classify", + .vector_size = sizeof (u32), + .format_trace = format_l2_input_classify_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_input_classify_error_strings), + .error_strings = l2_input_classify_error_strings, + + .runtime_data_bytes = sizeof (l2_input_classify_runtime_t), + + .n_next_nodes = L2_INPUT_CLASSIFY_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_INPUT_CLASSIFY_NEXT_DROP] = "error-drop", + [L2_INPUT_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input-not-l2", + [L2_INPUT_CLASSIFY_NEXT_IP4_INPUT] = "ip4-input", + [L2_INPUT_CLASSIFY_NEXT_IP6_INPUT] = "ip6-input", + [L2_INPUT_CLASSIFY_NEXT_LI] = "li-hit", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_input_classify_node, + l2_input_classify_node_fn); + +/** l2 input classsifier feature initialization. */ +clib_error_t * +l2_input_classify_init (vlib_main_t * vm) +{ + l2_input_classify_main_t *cm = &l2_input_classify_main; + l2_input_classify_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, l2_input_classify_node.index); + + cm->vlib_main = vm; + cm->vnet_main = vnet_get_main (); + cm->vnet_classify_main = &vnet_classify_main; + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_input_classify_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + cm->feat_next_node_index); + rt->l2cm = cm; + rt->vcm = cm->vnet_classify_main; + + return 0; +} + +VLIB_INIT_FUNCTION (l2_input_classify_init); + + +/** Enable/disable l2 input classification on a specific interface. */ +void +vnet_l2_input_classify_enable_disable (u32 sw_if_index, int enable_disable) +{ + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_INPUT_CLASSIFY, + (u32) enable_disable); +} + +/** @brief Set l2 per-protocol, per-interface input classification tables. + * + * @param sw_if_index interface handle + * @param ip4_table_index ip4 classification table index, or ~0 + * @param ip6_table_index ip6 classification table index, or ~0 + * @param other_table_index non-ip4, non-ip6 classification table index, + * or ~0 + * @returns 0 on success, VNET_API_ERROR_NO_SUCH_TABLE, TABLE2, TABLE3 + * if the indicated (non-~0) table does not exist. + */ + +int +vnet_l2_input_classify_set_tables (u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, u32 other_table_index) +{ + l2_input_classify_main_t *cm = &l2_input_classify_main; + vnet_classify_main_t *vcm = cm->vnet_classify_main; + + /* Assume that we've validated sw_if_index in the API layer */ + + if (ip4_table_index != ~0 && + pool_is_free_index (vcm->tables, ip4_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE; + + if (ip6_table_index != ~0 && + pool_is_free_index (vcm->tables, ip6_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE2; + + if (other_table_index != ~0 && + pool_is_free_index (vcm->tables, other_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE3; + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4], + sw_if_index); + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6], + sw_if_index); + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER], + sw_if_index); + + cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP4] + [sw_if_index] = ip4_table_index; + + cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_IP6] + [sw_if_index] = ip6_table_index; + + cm->classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_TABLE_OTHER] + [sw_if_index] = other_table_index; + + return 0; +} + +static clib_error_t * +int_l2_input_classify_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 = ~0; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 other_table_index = ~0; + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "intfc %U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + ; + else if (unformat (input, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (input, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (input, "other-table %d", &other_table_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "interface must be specified"); + + + if (ip4_table_index == ~0 && ip6_table_index == ~0 + && other_table_index == ~0) + { + vlib_cli_output (vm, "L2 classification disabled"); + vnet_l2_input_classify_enable_disable (sw_if_index, 0 /* enable */ ); + return 0; + } + + rv = vnet_l2_input_classify_set_tables (sw_if_index, ip4_table_index, + ip6_table_index, other_table_index); + switch (rv) + { + case 0: + vnet_l2_input_classify_enable_disable (sw_if_index, 1 /* enable */ ); + break; + + default: + return clib_error_return (0, "vnet_l2_input_classify_set_tables: %d", + rv); + break; + } + + return 0; +} + +/*? + * Configure l2 input classification. + * + * @cliexpar + * @cliexstart{set interface l2 input classify intfc [ip4-table ] [ip6-table ] [other-table ]} + * @cliexend + * @todo This is incomplete. This needs a detailed description and a + * practical example. + ?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_input_classify_cli, static) = { + .path = "set interface l2 input classify", + .short_help = + "set interface l2 input classify intfc [ip4-table ]\n" + " [ip6-table ] [other-table ]", + .function = int_l2_input_classify_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input_vtr.c b/src/vnet/l2/l2_input_vtr.c new file mode 100644 index 00000000..60a39631 --- /dev/null +++ b/src/vnet/l2/l2_input_vtr.c @@ -0,0 +1,401 @@ +/* + * l2_input_vtr.c : layer 2 input vlan tag rewrite processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u8 raw[12]; /* raw data (vlans) */ + u32 sw_if_index; +} l2_invtr_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_invtr_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_invtr_trace_t *t = va_arg (*args, l2_invtr_trace_t *); + + s = format (s, "l2-input-vtr: sw_if_index %d dst %U src %U data " + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src, + t->raw[0], t->raw[1], t->raw[2], t->raw[3], t->raw[4], + t->raw[5], t->raw[6], t->raw[7], t->raw[8], t->raw[9], + t->raw[10], t->raw[11]); + return s; +} + +l2_invtr_main_t l2_invtr_main; + +static vlib_node_registration_t l2_invtr_node; + +#define foreach_l2_invtr_error \ +_(L2_INVTR, "L2 inverter packets") \ +_(DROP, "L2 input tag rewrite drops") + +typedef enum +{ +#define _(sym,str) L2_INVTR_ERROR_##sym, + foreach_l2_invtr_error +#undef _ + L2_INVTR_N_ERROR, +} l2_invtr_error_t; + +static char *l2_invtr_error_strings[] = { +#define _(sym,string) string, + foreach_l2_invtr_error +#undef _ +}; + +typedef enum +{ + L2_INVTR_NEXT_DROP, + L2_INVTR_N_NEXT, +} l2_invtr_next_t; + + +static uword +l2_invtr_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_invtr_next_t next_index; + l2_invtr_main_t *msm = &l2_invtr_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 6 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + u32 feature_bitmap0, feature_bitmap1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3, *p4, *p5; + u32 sw_if_index2, sw_if_index3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + + /* Prefetch the buffer header and packet for the N+2 loop iteration */ + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + + CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE); + + /* + * Prefetch the input config for the N+1 loop iteration + * This depends on the buffer header above + */ + sw_if_index2 = vnet_buffer (p2)->sw_if_index[VLIB_RX]; + sw_if_index3 = vnet_buffer (p3)->sw_if_index[VLIB_RX]; + CLIB_PREFETCH (vec_elt_at_index + (l2output_main.configs, sw_if_index2), + CLIB_CACHE_LINE_BYTES, LOAD); + CLIB_PREFETCH (vec_elt_at_index + (l2output_main.configs, sw_if_index3), + CLIB_CACHE_LINE_BYTES, LOAD); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* RX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + /* process 2 packets */ + + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; + feature_bitmap1 = + vnet_buffer (b1)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; + + /* save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; + vnet_buffer (b1)->l2.feature_bitmap = feature_bitmap1; + + /* Determine the next node */ + next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + feature_bitmap0); + next1 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + feature_bitmap1); + + l2_output_config_t *config0; + l2_output_config_t *config1; + config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0); + config1 = vec_elt_at_index (l2output_main.configs, sw_if_index1); + + if (PREDICT_FALSE (config0->out_vtr_flag)) + { + if (config0->output_vtr.push_and_pop_bytes) + { + /* perform the tag rewrite on two packets */ + if (l2_vtr_process + (b0, + &(vec_elt_at_index + (l2output_main.configs, sw_if_index0)->input_vtr))) + { + /* Drop packet */ + next0 = L2_INVTR_NEXT_DROP; + b0->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + else if (config0->output_pbb_vtr.push_and_pop_bytes) + { + if (l2_pbb_process (b0, &(config0->input_pbb_vtr))) + { + /* Drop packet */ + next0 = L2_INVTR_NEXT_DROP; + b0->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + } + if (PREDICT_FALSE (config1->out_vtr_flag)) + { + if (config1->output_vtr.push_and_pop_bytes) + { + if (l2_vtr_process + (b1, + &(vec_elt_at_index + (l2output_main.configs, sw_if_index1)->input_vtr))) + { + /* Drop packet */ + next1 = L2_INVTR_NEXT_DROP; + b1->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + else if (config1->output_pbb_vtr.push_and_pop_bytes) + { + if (l2_pbb_process (b1, &(config1->input_pbb_vtr))) + { + /* Drop packet */ + next1 = L2_INVTR_NEXT_DROP; + b1->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2_invtr_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2_invtr_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + ethernet_header_t *h1 = vlib_buffer_get_current (b1); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + clib_memcpy (t->raw, &h1->type, sizeof (t->raw)); + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + u32 feature_bitmap0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + /* process 1 packet */ + + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; + + /* save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; + + /* Determine the next node */ + next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + feature_bitmap0); + + l2_output_config_t *config0; + config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0); + + if (PREDICT_FALSE (config0->out_vtr_flag)) + { + if (config0->output_vtr.push_and_pop_bytes) + { + /* perform the tag rewrite on one packet */ + if (l2_vtr_process + (b0, + &(vec_elt_at_index + (l2output_main.configs, sw_if_index0)->input_vtr))) + { + /* Drop packet */ + next0 = L2_INVTR_NEXT_DROP; + b0->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + else if (config0->output_pbb_vtr.push_and_pop_bytes) + { + if (l2_pbb_process (b0, &(config0->input_pbb_vtr))) + { + /* Drop packet */ + next0 = L2_INVTR_NEXT_DROP; + b0->error = node->errors[L2_INVTR_ERROR_DROP]; + } + } + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_invtr_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + ethernet_header_t *h0 = vlib_buffer_get_current (b0); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_invtr_node,static) = { + .function = l2_invtr_node_fn, + .name = "l2-input-vtr", + .vector_size = sizeof (u32), + .format_trace = format_l2_invtr_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_invtr_error_strings), + .error_strings = l2_invtr_error_strings, + + .n_next_nodes = L2_INVTR_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_INVTR_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_invtr_node, l2_invtr_node_fn) + clib_error_t *l2_invtr_init (vlib_main_t * vm) +{ + l2_invtr_main_t *mp = &l2_invtr_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_invtr_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + mp->feat_next_node_index); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_invtr_init); + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_input_vtr.h b/src/vnet/l2/l2_input_vtr.h new file mode 100644 index 00000000..f248669e --- /dev/null +++ b/src/vnet/l2/l2_input_vtr.h @@ -0,0 +1,54 @@ +/* + * l2_input_vtr.h : layer 2 input vlan tag rewrite processing + * + * Copyright (c) 2013 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_vnet_l2_input_vtr_h +#define included_vnet_l2_input_vtr_h + +#include +#include +#include +#include + + +typedef struct +{ + + /* + * The input vtr data is located in l2_output_config_t because + * the same config data is used for the egress EFP Filter check. + */ + + /* Next nodes for each feature */ + u32 feat_next_node_index[32]; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_invtr_main_t; + +extern l2_invtr_main_t l2_invtr_main; + +#endif /* included_vnet_l2_input_vtr_h */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c new file mode 100644 index 00000000..7f19f936 --- /dev/null +++ b/src/vnet/l2/l2_learn.c @@ -0,0 +1,597 @@ +/* + * l2_learn.c : layer 2 learning using l2fib + * + * Copyright (c) 2013 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 +#include +#include + +#include +#include +#include +#include + +#include +#include + +/** + * @file + * @brief Ethernet Bridge Learning. + * + * Populate the mac table with entries mapping the packet's source mac + bridge + * domain ID to the input sw_if_index. + * + * Note that learning and forwarding are separate graph nodes. This means that + * for a set of packets, all learning is performed first, then all nodes are + * forwarded. The forwarding is done based on the end-state of the mac table, + * instead of the state after each packet. Thus the forwarding results could + * differ in certain cases (mac move tests), but this not expected to cause + * problems in real-world networks. It is much simpler to separate learning + * and forwarding into separate nodes. + */ + + +typedef struct +{ + u8 src[6]; + u8 dst[6]; + u32 sw_if_index; + u16 bd_index; +} l2learn_trace_t; + + +/* packet trace format function */ +static u8 * +format_l2learn_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2learn_trace_t *t = va_arg (*args, l2learn_trace_t *); + + s = format (s, "l2-learn: sw_if_index %d dst %U src %U bd_index %d", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src, t->bd_index); + return s; +} + +static vlib_node_registration_t l2learn_node; + +#define foreach_l2learn_error \ +_(L2LEARN, "L2 learn packets") \ +_(MISS, "L2 learn misses") \ +_(MAC_MOVE, "L2 mac moves") \ +_(MAC_MOVE_VIOLATE, "L2 mac move violations") \ +_(LIMIT, "L2 not learned due to limit") \ +_(HIT, "L2 learn hits") \ +_(FILTER_DROP, "L2 filter mac drops") + +typedef enum +{ +#define _(sym,str) L2LEARN_ERROR_##sym, + foreach_l2learn_error +#undef _ + L2LEARN_N_ERROR, +} l2learn_error_t; + +static char *l2learn_error_strings[] = { +#define _(sym,string) string, + foreach_l2learn_error +#undef _ +}; + +typedef enum +{ + L2LEARN_NEXT_L2FWD, + L2LEARN_NEXT_DROP, + L2LEARN_N_NEXT, +} l2learn_next_t; + + +/** Perform learning on one packet based on the mac table lookup result. */ + +static_always_inline void +l2learn_process (vlib_node_runtime_t * node, + l2learn_main_t * msm, + u64 * counter_base, + vlib_buffer_t * b0, + u32 sw_if_index0, + l2fib_entry_key_t * key0, + l2fib_entry_key_t * cached_key, + u32 * bucket0, + l2fib_entry_result_t * result0, u32 * next0, u8 timestamp) +{ + u32 feature_bitmap; + + /* Set up the default next node (typically L2FWD) */ + + /* Remove ourself from the feature bitmap */ + feature_bitmap = vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_LEARN; + + /* Save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; + + /* Determine the next node */ + *next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, + feature_bitmap); + + /* Check mac table lookup result */ + + if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) + { + /* + * The entry was in the table, and the sw_if_index matched, the normal case + */ + counter_base[L2LEARN_ERROR_HIT] += 1; + if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) + result0->fields.timestamp = timestamp; + + } + else if (result0->raw == ~0) + { + + /* The entry was not in table, so add it */ + + counter_base[L2LEARN_ERROR_MISS] += 1; + + if (msm->global_learn_count == msm->global_learn_limit) + { + /* + * Global limit reached. Do not learn the mac but forward the packet. + * In the future, limits could also be per-interface or bridge-domain. + */ + counter_base[L2LEARN_ERROR_LIMIT] += 1; + goto done; + + } + else + { + BVT (clib_bihash_kv) kv; + /* It is ok to learn */ + + result0->raw = 0; /* clear all fields */ + result0->fields.sw_if_index = sw_if_index0; + result0->fields.timestamp = timestamp; + kv.key = key0->raw; + kv.value = result0->raw; + + BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); + + cached_key->raw = ~0; /* invalidate the cache */ + msm->global_learn_count++; + } + + } + else + { + + /* The entry was in the table, but with the wrong sw_if_index mapping (mac move) */ + counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; + + if (result0->fields.static_mac) + { + /* + * Don't overwrite a static mac + * TODO: Check violation policy. For now drop the packet + */ + b0->error = node->errors[L2LEARN_ERROR_MAC_MOVE_VIOLATE]; + *next0 = L2LEARN_NEXT_DROP; + } + else + { + /* + * Update the entry + * TODO: may want to rate limit mac moves + * TODO: check global/bridge domain/interface learn limits + */ + BVT (clib_bihash_kv) kv; + + result0->raw = 0; /* clear all fields */ + result0->fields.sw_if_index = sw_if_index0; + result0->fields.timestamp = timestamp; + + kv.key = key0->raw; + kv.value = result0->raw; + + cached_key->raw = ~0; /* invalidate the cache */ + + BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); + } + } + + if (result0->fields.filter) + { + /* drop packet because lookup matched a filter mac entry */ + + if (*next0 != L2LEARN_NEXT_DROP) + { + /* if we're not already dropping the packet, do it now */ + b0->error = node->errors[L2LEARN_ERROR_FILTER_DROP]; + *next0 = L2LEARN_NEXT_DROP; + } + } + +done: + return; +} + + +static uword +l2learn_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2learn_next_t next_index; + l2learn_main_t *msm = &l2learn_main; + vlib_node_t *n = vlib_get_node (vm, l2learn_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + l2fib_entry_key_t cached_key; + l2fib_entry_result_t cached_result; + u8 timestamp = (u8) (vlib_time_now (vm) / 60); + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + /* Clear the one-entry cache in case mac table was updated */ + cached_key.raw = ~0; + cached_result.raw = ~0; /* warning be gone */ + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 8 && n_left_to_next >= 4) + { + u32 bi0, bi1, bi2, bi3; + vlib_buffer_t *b0, *b1, *b2, *b3; + u32 next0, next1, next2, next3; + u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3; + ethernet_header_t *h0, *h1, *h2, *h3; + l2fib_entry_key_t key0, key1, key2, key3; + l2fib_entry_result_t result0, result1, result2, result3; + u32 bucket0, bucket1, bucket2, bucket3; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p4, *p5, *p6, *p7;; + + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + p6 = vlib_get_buffer (vm, from[6]); + p7 = vlib_get_buffer (vm, from[7]); + + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + vlib_prefetch_buffer_header (p6, LOAD); + vlib_prefetch_buffer_header (p7, LOAD); + + CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + to_next[2] = bi2 = from[2]; + to_next[3] = bi3 = from[3]; + from += 4; + to_next += 4; + n_left_from -= 4; + n_left_to_next -= 4; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b2 = vlib_get_buffer (vm, bi2); + b3 = vlib_get_buffer (vm, bi3); + + /* RX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX]; + sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX]; + + /* Process 4 x pkts */ + + h0 = vlib_buffer_get_current (b0); + h1 = vlib_buffer_get_current (b1); + h2 = vlib_buffer_get_current (b2); + h3 = vlib_buffer_get_current (b3); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2learn_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2learn_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->bd_index = vnet_buffer (b1)->l2.bd_index; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + if (b2->flags & VLIB_BUFFER_IS_TRACED) + { + l2learn_trace_t *t = + vlib_add_trace (vm, node, b2, sizeof (*t)); + t->sw_if_index = sw_if_index2; + t->bd_index = vnet_buffer (b2)->l2.bd_index; + clib_memcpy (t->src, h2->src_address, 6); + clib_memcpy (t->dst, h2->dst_address, 6); + } + if (b3->flags & VLIB_BUFFER_IS_TRACED) + { + l2learn_trace_t *t = + vlib_add_trace (vm, node, b3, sizeof (*t)); + t->sw_if_index = sw_if_index3; + t->bd_index = vnet_buffer (b3)->l2.bd_index; + clib_memcpy (t->src, h3->src_address, 6); + clib_memcpy (t->dst, h3->dst_address, 6); + } + } + + /* process 4 pkts */ + vlib_node_increment_counter (vm, l2learn_node.index, + L2LEARN_ERROR_L2LEARN, 4); + + l2fib_lookup_4 (msm->mac_table, &cached_key, &cached_result, + h0->src_address, + h1->src_address, + h2->src_address, + h3->src_address, + vnet_buffer (b0)->l2.bd_index, + vnet_buffer (b1)->l2.bd_index, + vnet_buffer (b2)->l2.bd_index, + vnet_buffer (b3)->l2.bd_index, + &key0, &key1, &key2, &key3, + &bucket0, &bucket1, &bucket2, &bucket3, + &result0, &result1, &result2, &result3); + + l2learn_process (node, msm, &em->counters[node_counter_base_index], + b0, sw_if_index0, &key0, &cached_key, + &bucket0, &result0, &next0, timestamp); + + l2learn_process (node, msm, &em->counters[node_counter_base_index], + b1, sw_if_index1, &key1, &cached_key, + &bucket1, &result1, &next1, timestamp); + + l2learn_process (node, msm, &em->counters[node_counter_base_index], + b2, sw_if_index2, &key2, &cached_key, + &bucket2, &result2, &next2, timestamp); + + l2learn_process (node, msm, &em->counters[node_counter_base_index], + b3, sw_if_index3, &key3, &cached_key, + &bucket3, &result3, &next3, timestamp); + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x4 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, bi2, bi3, + next0, next1, next2, next3); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + ethernet_header_t *h0; + l2fib_entry_key_t key0; + l2fib_entry_result_t result0; + u32 bucket0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + h0 = vlib_buffer_get_current (b0); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2learn_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->bd_index = vnet_buffer (b0)->l2.bd_index; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + /* process 1 pkt */ + vlib_node_increment_counter (vm, l2learn_node.index, + L2LEARN_ERROR_L2LEARN, 1); + + + l2fib_lookup_1 (msm->mac_table, &cached_key, &cached_result, + h0->src_address, vnet_buffer (b0)->l2.bd_index, + &key0, &bucket0, &result0); + + l2learn_process (node, msm, &em->counters[node_counter_base_index], + b0, sw_if_index0, &key0, &cached_key, + &bucket0, &result0, &next0, timestamp); + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2learn_node,static) = { + .function = l2learn_node_fn, + .name = "l2-learn", + .vector_size = sizeof (u32), + .format_trace = format_l2learn_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2learn_error_strings), + .error_strings = l2learn_error_strings, + + .n_next_nodes = L2LEARN_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2LEARN_NEXT_DROP] = "error-drop", + [L2LEARN_NEXT_L2FWD] = "l2-fwd", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2learn_node, l2learn_node_fn) + clib_error_t *l2learn_init (vlib_main_t * vm) +{ + l2learn_main_t *mp = &l2learn_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2learn_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + mp->feat_next_node_index); + + /* init the hash table ptr */ + mp->mac_table = get_mac_table (); + + /* + * Set the default number of dynamically learned macs to the number + * of buckets. + */ + mp->global_learn_limit = L2FIB_NUM_BUCKETS * 16; + + return 0; +} + +VLIB_INIT_FUNCTION (l2learn_init); + + +/** + * Set subinterface learn enable/disable. + * The CLI format is: + * set interface l2 learn [disable] + */ +static clib_error_t * +int_learn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 enable; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the interface flag */ + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_LEARN, enable); + +done: + return error; +} + +/*? + * Layer 2 learning can be enabled and disabled on each + * interface and on each bridge-domain. Use this command to + * manage interfaces. It is enabled by default. + * + * @cliexpar + * Example of how to enable learning: + * @cliexcmd{set interface l2 learn GigabitEthernet0/8/0} + * Example of how to disable learning: + * @cliexcmd{set interface l2 learn GigabitEthernet0/8/0 disable} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_learn_cli, static) = { + .path = "set interface l2 learn", + .short_help = "set interface l2 learn [disable]", + .function = int_learn, +}; +/* *INDENT-ON* */ + + +static clib_error_t * +l2learn_config (vlib_main_t * vm, unformat_input_t * input) +{ + l2learn_main_t *mp = &l2learn_main; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "limit %d", &mp->global_learn_limit)) + ; + + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + return 0; +} + +VLIB_CONFIG_FUNCTION (l2learn_config, "l2learn"); + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h new file mode 100644 index 00000000..5bb1130b --- /dev/null +++ b/src/vnet/l2/l2_learn.h @@ -0,0 +1,64 @@ +/* + * l2_learn.c : layer 2 learning using l2fib + * + * Copyright (c) 2014 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_l2learn_h +#define included_l2learn_h + +#include +#include + + +typedef struct +{ + + /* Hash table */ + BVT (clib_bihash) * mac_table; + + /* number of dynamically learned mac entries */ + u32 global_learn_count; + + /* maximum number of dynamically learned mac entries */ + u32 global_learn_limit; + + /* Next nodes for each feature */ + u32 feat_next_node_index[32]; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2learn_main_t; + + +l2learn_main_t l2learn_main; + +extern vlib_node_registration_t l2fib_mac_age_scanner_process_node; + +enum +{ + L2_MAC_AGE_PROCESS_EVENT_START = 1, + L2_MAC_AGE_PROCESS_EVENT_STOP = 2, +} l2_mac_age_process_event_t; + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c new file mode 100644 index 00000000..953fcb02 --- /dev/null +++ b/src/vnet/l2/l2_output.c @@ -0,0 +1,708 @@ +/* + * l2_output.c : layer 2 output packet processing + * + * Copyright (c) 2013 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 +#include +#include + +#include +#include +#include +#include + + +/* Feature graph node names */ +static char *l2output_feat_names[] = { +#define _(sym,name) name, + foreach_l2output_feat +#undef _ +}; + +char ** +l2output_get_feat_names (void) +{ + return l2output_feat_names; +} + +l2output_main_t l2output_main; + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u32 sw_if_index; +} l2output_trace_t; + +/* packet trace format function */ +static u8 * +format_l2output_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2output_trace_t *t = va_arg (*args, l2output_trace_t *); + + s = format (s, "l2-output: sw_if_index %d dst %U src %U", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src); + return s; +} + + +static char *l2output_error_strings[] = { +#define _(sym,string) string, + foreach_l2output_error +#undef _ +}; + +/** + * Check for split horizon violations. + * Return 0 if split horizon check passes, otherwise return non-zero. + * Packets should not be transmitted out an interface with the same + * split-horizon group as the input interface, except if the @c shg is 0 + * in which case the check always passes. + */ +static_always_inline u32 +split_horizon_violation (u8 shg1, u8 shg2) +{ + if (PREDICT_TRUE (shg1 == 0)) + { + return 0; + } + else + { + return shg1 == shg2; + } +} + +static_always_inline void +l2output_vtr (vlib_node_runtime_t * node, l2_output_config_t * config, + u32 feature_bitmap, vlib_buffer_t * b, u32 * next) +{ + if (PREDICT_FALSE (config->out_vtr_flag)) + { + /* Perform pre-vtr EFP filter check if configured */ + if (config->output_vtr.push_and_pop_bytes) + { + /* + * Perform output vlan tag rewrite and the pre-vtr EFP filter check. + * The EFP Filter only needs to be run if there is an output VTR + * configured. The flag for the post-vtr EFP Filter node is used + * to trigger the pre-vtr check as well. + */ + u32 failed1 = (feature_bitmap & L2OUTPUT_FEAT_EFP_FILTER) + && (l2_efp_filter_process (b, &(config->input_vtr))); + u32 failed2 = l2_vtr_process (b, &(config->output_vtr)); + + if (PREDICT_FALSE (failed1 | failed2)) + { + *next = L2OUTPUT_NEXT_DROP; + if (failed2) + { + b->error = node->errors[L2OUTPUT_ERROR_VTR_DROP]; + } + if (failed1) + { + b->error = node->errors[L2OUTPUT_ERROR_EFP_DROP]; + } + } + } + // perform the PBB rewrite + else if (config->output_pbb_vtr.push_and_pop_bytes) + { + u32 failed = l2_pbb_process (b, &(config->output_pbb_vtr)); + if (PREDICT_FALSE (failed)) + { + *next = L2OUTPUT_NEXT_DROP; + b->error = node->errors[L2OUTPUT_ERROR_VTR_DROP]; + } + } + } +} + + +static vlib_node_registration_t l2output_node; + +static uword +l2output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2output_next_t next_index; + l2output_main_t *msm = &l2output_main; + u32 cached_sw_if_index; + u32 cached_next_index; + + /* Invalidate cache */ + cached_sw_if_index = ~0; + cached_next_index = ~0; /* warning be gone */ + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 8 && n_left_to_next >= 4) + { + u32 bi0, bi1, bi2, bi3; + vlib_buffer_t *b0, *b1, *b2, *b3; + u32 next0, next1, next2, next3; + u32 sw_if_index0, sw_if_index1, sw_if_index2, sw_if_index3; + ethernet_header_t *h0, *h1, *h2, *h3; + l2_output_config_t *config0, *config1, *config2, *config3; + u32 feature_bitmap0, feature_bitmap1; + u32 feature_bitmap2, feature_bitmap3; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p4, *p5, *p6, *p7; + + p4 = vlib_get_buffer (vm, from[4]); + p5 = vlib_get_buffer (vm, from[5]); + p6 = vlib_get_buffer (vm, from[6]); + p7 = vlib_get_buffer (vm, from[7]); + + /* Prefetch the buffer header for the N+2 loop iteration */ + vlib_prefetch_buffer_header (p4, LOAD); + vlib_prefetch_buffer_header (p5, LOAD); + vlib_prefetch_buffer_header (p6, LOAD); + vlib_prefetch_buffer_header (p7, LOAD); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + to_next[2] = bi2 = from[2]; + to_next[3] = bi3 = from[3]; + from += 4; + to_next += 4; + n_left_from -= 4; + n_left_to_next -= 4; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b2 = vlib_get_buffer (vm, bi2); + b3 = vlib_get_buffer (vm, bi3); + + /* TX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_TX]; + sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_TX]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + h0 = vlib_buffer_get_current (b0); + h1 = vlib_buffer_get_current (b1); + h2 = vlib_buffer_get_current (b2); + h3 = vlib_buffer_get_current (b3); + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + if (b2->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b2, sizeof (*t)); + t->sw_if_index = sw_if_index2; + clib_memcpy (t->src, h2->src_address, 6); + clib_memcpy (t->dst, h2->dst_address, 6); + } + if (b3->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b3, sizeof (*t)); + t->sw_if_index = sw_if_index3; + clib_memcpy (t->src, h3->src_address, 6); + clib_memcpy (t->dst, h3->dst_address, 6); + } + } + + vlib_node_increment_counter (vm, l2output_node.index, + L2OUTPUT_ERROR_L2OUTPUT, 4); + + /* Get config for the output interface */ + config0 = vec_elt_at_index (msm->configs, sw_if_index0); + config1 = vec_elt_at_index (msm->configs, sw_if_index1); + config2 = vec_elt_at_index (msm->configs, sw_if_index2); + config3 = vec_elt_at_index (msm->configs, sw_if_index3); + + /* + * Get features from the config + * TODO: mask out any non-applicable features + */ + feature_bitmap0 = config0->feature_bitmap; + feature_bitmap1 = config1->feature_bitmap; + feature_bitmap2 = config2->feature_bitmap; + feature_bitmap3 = config3->feature_bitmap; + + /* Determine next node */ + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2output_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2output_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b1, sw_if_index1, feature_bitmap1, &next1); + + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2output_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b2, sw_if_index2, feature_bitmap2, &next2); + + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2output_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b3, sw_if_index3, feature_bitmap3, &next3); + + l2output_vtr (node, config0, feature_bitmap0, b0, &next0); + l2output_vtr (node, config1, feature_bitmap1, b1, &next1); + l2output_vtr (node, config2, feature_bitmap2, b2, &next2); + l2output_vtr (node, config3, feature_bitmap3, b3, &next3); + + /* + * Perform the split horizon check + * The check can only fail for non-zero shg's + */ + if (PREDICT_FALSE (config0->shg + config1->shg + + config2->shg + config3->shg)) + { + /* one of the checks might fail, check both */ + if (split_horizon_violation + (config0->shg, vnet_buffer (b0)->l2.shg)) + { + next0 = L2OUTPUT_NEXT_DROP; + b0->error = node->errors[L2OUTPUT_ERROR_SHG_DROP]; + } + if (split_horizon_violation + (config1->shg, vnet_buffer (b1)->l2.shg)) + { + next1 = L2OUTPUT_NEXT_DROP; + b1->error = node->errors[L2OUTPUT_ERROR_SHG_DROP]; + } + if (split_horizon_violation + (config2->shg, vnet_buffer (b2)->l2.shg)) + { + next2 = L2OUTPUT_NEXT_DROP; + b2->error = node->errors[L2OUTPUT_ERROR_SHG_DROP]; + } + if (split_horizon_violation + (config3->shg, vnet_buffer (b3)->l2.shg)) + { + next3 = L2OUTPUT_NEXT_DROP; + b3->error = node->errors[L2OUTPUT_ERROR_SHG_DROP]; + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x4 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, bi2, bi3, + next0, next1, next2, next3); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + ethernet_header_t *h0; + l2_output_config_t *config0; + u32 feature_bitmap0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + h0 = vlib_buffer_get_current (b0); + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + vlib_node_increment_counter (vm, l2output_node.index, + L2OUTPUT_ERROR_L2OUTPUT, 1); + + /* Get config for the output interface */ + config0 = vec_elt_at_index (msm->configs, sw_if_index0); + + /* + * Get features from the config + * TODO: mask out any non-applicable features + */ + feature_bitmap0 = config0->feature_bitmap; + + /* Determine next node */ + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2output_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + + l2output_vtr (node, config0, feature_bitmap0, b0, &next0); + + /* Perform the split horizon check */ + if (PREDICT_FALSE + (split_horizon_violation + (config0->shg, vnet_buffer (b0)->l2.shg))) + { + next0 = L2OUTPUT_NEXT_DROP; + b0->error = node->errors[L2OUTPUT_ERROR_SHG_DROP]; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2output_node,static) = { + .function = l2output_node_fn, + .name = "l2-output", + .vector_size = sizeof (u32), + .format_trace = format_l2output_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2output_error_strings), + .error_strings = l2output_error_strings, + + .n_next_nodes = L2OUTPUT_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2OUTPUT_NEXT_DROP] = "error-drop", + [L2OUTPUT_NEXT_BAD_INTF] = "l2-output-bad-intf", + }, +}; +/* *INDENT-ON* */ + + +#define foreach_l2output_bad_intf_error \ +_(DROP, "L2 output to interface not in L2 mode or deleted") + +static char *l2output_bad_intf_error_strings[] = { +#define _(sym,string) string, + foreach_l2output_bad_intf_error +#undef _ +}; + +typedef enum +{ +#define _(sym,str) L2OUTPUT_BAD_INTF_ERROR_##sym, + foreach_l2output_bad_intf_error +#undef _ + L2OUTPUT_BAD_INTF_N_ERROR, +} l2output_bad_intf_error_t; + + +/** + * Output node for interfaces/tunnels which was in L2 mode but were changed + * to L3 mode or possibly deleted thereafter. On changing forwarding mode + * of any tunnel/interface from L2 to L3, its entry in l2_output_main table + * next_nodes.output_node_index_vec[sw_if_index] MUST be set to the value of + * L2OUTPUT_NEXT_BAD_INTF. Thus, if there are stale entries in the L2FIB for + * this sw_if_index, l2-output will send packets for this sw_if_index to the + * l2-output-bad-intf node which just setup the proper drop reason before + * sending packets to the error-drop node to drop the packet. Then, stale L2FIB + * entries for delted tunnels won't cause possible packet or memory corrpution. + */ +static vlib_node_registration_t l2output_bad_intf_node; + +static uword +l2output_bad_intf_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2output_next_t next_index = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + b0->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP]; + b1->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP]; + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + b0 = vlib_get_buffer (vm, bi0); + b0->error = node->errors[L2OUTPUT_BAD_INTF_ERROR_DROP]; + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2output_bad_intf_node,static) = { + .function = l2output_bad_intf_node_fn, + .name = "l2-output-bad-intf", + .vector_size = sizeof (u32), + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2output_bad_intf_error_strings), + .error_strings = l2output_bad_intf_error_strings, + + .n_next_nodes = 1, + + /* edit / add dispositions here */ + .next_nodes = { + [0] = "error-drop", + }, +}; +/* *INDENT-ON* */ + + +VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn) + clib_error_t *l2output_init (vlib_main_t * vm) +{ + l2output_main_t *mp = &l2output_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Create the config vector */ + vec_validate (mp->configs, 100); + /* Until we hook up the CLI config, just create 100 sw interface entries and zero them */ + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2output_node.index, + L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + mp->next_nodes.feat_next_node_index); + + /* Initialize the output node mapping table */ + l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); + + return 0; +} + +VLIB_INIT_FUNCTION (l2output_init); + +typedef struct +{ + u32 node_index; + u32 sw_if_index; +} output_node_mapping_rpc_args_t; + +static void output_node_rpc_callback (output_node_mapping_rpc_args_t * a); + +static void +output_node_mapping_send_rpc (u32 node_index, u32 sw_if_index) +{ + output_node_mapping_rpc_args_t args; + void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); + + args.node_index = node_index; + args.sw_if_index = sw_if_index; + + vl_api_rpc_call_main_thread (output_node_rpc_callback, + (u8 *) & args, sizeof (args)); +} + + +/** Create a mapping in the next node mapping table for the given sw_if_index. */ +u32 +l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 node_index, /* index of current node */ + u32 * output_node_index_vec, + u32 sw_if_index) +{ + + u32 next; /* index of next graph node */ + vnet_hw_interface_t *hw0; + u32 *node; + + hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + + uword cpu_number; + + cpu_number = os_get_cpu_number (); + + if (cpu_number) + { + u32 oldflags; + + oldflags = __sync_fetch_and_or (&hw0->flags, + VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED); + + if ((oldflags & VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED)) + return L2OUTPUT_NEXT_DROP; + + output_node_mapping_send_rpc (node_index, sw_if_index); + return L2OUTPUT_NEXT_DROP; + } + + /* dynamically create graph node arc */ + next = vlib_node_add_next (vlib_main, node_index, hw0->output_node_index); + + /* Initialize vector with the mapping */ + + node = vec_elt_at_index (output_node_index_vec, sw_if_index); + *node = next; + + /* reset mapping bit, includes memory barrier */ + __sync_fetch_and_and (&hw0->flags, ~VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED); + + return next; +} + +void +output_node_rpc_callback (output_node_mapping_rpc_args_t * a) +{ + vlib_main_t *vm = vlib_get_main (); + vnet_main_t *vnm = vnet_get_main (); + l2output_main_t *mp = &l2output_main; + + (void) l2output_create_output_node_mapping + (vm, vnm, a->node_index, mp->next_nodes.output_node_index_vec, + a->sw_if_index); +} + +/* Get a pointer to the config for the given interface */ +l2_output_config_t * +l2output_intf_config (u32 sw_if_index) +{ + l2output_main_t *mp = &l2output_main; + + vec_validate (mp->configs, sw_if_index); + return vec_elt_at_index (mp->configs, sw_if_index); +} + +/** Enable (or disable) the feature in the bitmap for the given interface. */ +void +l2output_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) +{ + l2output_main_t *mp = &l2output_main; + l2_output_config_t *config; + + vec_validate (mp->configs, sw_if_index); + config = vec_elt_at_index (mp->configs, sw_if_index); + + if (enable) + { + config->feature_bitmap |= feature_bitmap; + } + else + { + config->feature_bitmap &= ~feature_bitmap; + } +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h new file mode 100644 index 00000000..c683b1ad --- /dev/null +++ b/src/vnet/l2/l2_output.h @@ -0,0 +1,285 @@ +/* + * l2_output.h : layer 2 output packet processing + * + * Copyright (c) 2013 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_vnet_l2_output_h +#define included_vnet_l2_output_h + +#include +#include +#include +#include + + +/* The L2 output feature configuration, a per-interface struct */ +typedef struct +{ + + u32 feature_bitmap; + + /* + * vlan tag rewrite for ingress and egress + * ingress vtr is located here because the same config data is used for + * the egress EFP filter check + */ + vtr_config_t input_vtr; + vtr_config_t output_vtr; + ptr_config_t input_pbb_vtr; + ptr_config_t output_pbb_vtr; + + /* some of these flags may get integrated into the feature bitmap */ + u8 fwd_enable; + u8 flood_enable; + + /* split horizon group */ + u8 shg; + + /* flag for output vtr operation */ + u8 out_vtr_flag; + +} l2_output_config_t; + + +/* + * The set of next nodes for features and interface output. + * Each output feature node should include this. + */ +typedef struct +{ + /* + * vector of output next node index, indexed by sw_if_index. + * used when all output features have been executed and the + * next nodes are the interface output nodes. + */ + u32 *output_node_index_vec; + + /* + * array of next node index for each output feature, indexed + * by l2output_feat_t. Used to determine next feature node. + */ + u32 feat_next_node_index[32]; + +} l2_output_next_nodes_st; + + +typedef struct +{ + /* Next nodes for features and output interfaces */ + l2_output_next_nodes_st next_nodes; + + /* config vector indexed by sw_if_index */ + l2_output_config_t *configs; + + /* Convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2output_main_t; + +l2output_main_t l2output_main; + +/* L2 output features */ + +/* Mappings from feature ID to graph node name */ +#define foreach_l2output_feat \ + _(SPAN, "feature-bitmap-drop") \ + _(CFM, "feature-bitmap-drop") \ + _(QOS, "feature-bitmap-drop") \ + _(ACL, "l2-output-acl") \ + _(L2PT, "feature-bitmap-drop") \ + _(EFP_FILTER, "l2-efp-filter") \ + _(IPIW, "feature-bitmap-drop") \ + _(STP_BLOCKED, "feature-bitmap-drop") \ + _(LINESTATUS_DOWN, "feature-bitmap-drop") \ + _(OUTPUT_CLASSIFY, "l2-output-classify") \ + _(XCRW, "l2-xcrw") + +/* Feature bitmap positions */ +typedef enum +{ +#define _(sym,str) L2OUTPUT_FEAT_##sym##_BIT, + foreach_l2output_feat +#undef _ + L2OUTPUT_N_FEAT, +} l2output_feat_t; + +/* Feature bit masks */ +typedef enum +{ +#define _(sym,str) L2OUTPUT_FEAT_##sym = (1<l2.feature_bitmap = feature_bitmap; + + /* Determine the next node */ + *next0 = + feat_bitmap_get_next_node_index (next_nodes->feat_next_node_index, + feature_bitmap); + } + else + { + /* + * There are no features. Send packet to TX node for sw_if_index0 + * This is a little tricky in that the output interface next node indexes + * are not precomputed at init time. + */ + + if (sw_if_index == *cached_sw_if_index) + { + /* We hit in the one-entry cache. Use it. */ + *next0 = *cached_next_index; + } + else + { + /* Look up the output TX node */ + *next0 = l2output_get_output_node (vlib_main, + vnet_main, + node_index, + sw_if_index, + &next_nodes->output_node_index_vec); + + if (*next0 == L2OUTPUT_NEXT_DROP) + { + vnet_hw_interface_t *hw0; + hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + + if (hw0->flags & VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED) + b0->error = node->errors[L2OUTPUT_ERROR_MAPPING_DROP]; + } + + /* Update the one-entry cache */ + *cached_sw_if_index = sw_if_index; + *cached_next_index = *next0; + } + } +} + +/** Get a pointer to the config for the given interface */ +l2_output_config_t *l2output_intf_config (u32 sw_if_index); + +/** Enable (or disable) the feature in the bitmap for the given interface */ +void l2output_intf_bitmap_enable (u32 sw_if_index, + u32 feature_bitmap, u32 enable); + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_output_acl.c b/src/vnet/l2/l2_output_acl.c new file mode 100644 index 00000000..94a4d66b --- /dev/null +++ b/src/vnet/l2/l2_output_acl.c @@ -0,0 +1,358 @@ +/* + * l2_output_acl.c : layer 2 output acl processing + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +typedef struct +{ + /* Next nodes for features and output interfaces */ + l2_output_next_nodes_st next_nodes; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_outacl_main_t; + + + +typedef struct +{ + /* per-pkt trace data */ + u8 src[6]; + u8 dst[6]; + u32 next_index; + u32 sw_if_index; +} l2_outacl_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_outacl_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_outacl_trace_t *t = va_arg (*args, l2_outacl_trace_t *); + + s = format (s, "l2-output-acl: sw_if_index %d dst %U src %U", + t->sw_if_index, + format_ethernet_address, t->dst, + format_ethernet_address, t->src); + return s; +} + +l2_outacl_main_t l2_outacl_main; + +static vlib_node_registration_t l2_outacl_node; + +#define foreach_l2_outacl_error \ +_(L2_OUTACL, "L2 output ACL packets") \ +_(DROP, "L2 output drops") + +typedef enum +{ +#define _(sym,str) L2_OUTACL_ERROR_##sym, + foreach_l2_outacl_error +#undef _ + L2_OUTACL_N_ERROR, +} l2_outacl_error_t; + +static char *l2_outacl_error_strings[] = { +#define _(sym,string) string, + foreach_l2_outacl_error +#undef _ +}; + +typedef enum +{ + L2_OUTACL_NEXT_DROP, + L2_OUTACL_N_NEXT, +} l2_outacl_next_t; + + + +static uword +l2_outacl_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_outacl_next_t next_index; + l2_outacl_main_t *msm = &l2_outacl_main; + vlib_node_t *n = vlib_get_node (vm, l2_outacl_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + u32 cached_sw_if_index = (u32) ~ 0; + u32 cached_next_index = (u32) ~ 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (0 && n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + ethernet_header_t *h0, *h1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + /* bi is "buffer index", b is pointer to the buffer */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + /* TX interface handles */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2_outacl_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->next_index = next0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2_outacl_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->next_index = next1; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + } + } + + em->counters[node_counter_base_index + L2_OUTACL_ERROR_L2_OUTACL] += + 2; + + /* add core loop code here */ + + /* verify speculative enqueues, maybe switch current next frame */ + /* if next0==next1==next_index then nothing special needs to be done */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + ethernet_header_t *h0; + u32 feature_bitmap0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_outacl_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + } + + em->counters[node_counter_base_index + L2_OUTACL_ERROR_L2_OUTACL] += + 1; + + /* + * L2_OUTACL code + * Dummy for now, just go to next feature node + */ + + + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_ACL; + + /* Determine next node */ + l2_output_dispatch (msm->vlib_main, + msm->vnet_main, + node, + l2_outacl_node.index, + &cached_sw_if_index, + &cached_next_index, + &msm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_outacl_node,static) = { + .function = l2_outacl_node_fn, + .name = "l2-output-acl", + .vector_size = sizeof (u32), + .format_trace = format_l2_outacl_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_outacl_error_strings), + .error_strings = l2_outacl_error_strings, + + .n_next_nodes = L2_OUTACL_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_OUTACL_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn) + clib_error_t *l2_outacl_init (vlib_main_t * vm) +{ + l2_outacl_main_t *mp = &l2_outacl_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_outacl_node.index, + L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + mp->next_nodes.feat_next_node_index); + + /* Initialize the output node mapping table */ + l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_outacl_init); + +#if 0 +/** @todo maybe someone will add output ACL's in the future. + * Set subinterface outacl enable/disable. + * The CLI format is: + * set interface acl output [disable] + */ +static clib_error_t * +int_l2_outacl (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 enable; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + enable = 1; + if (unformat (input, "disable")) + { + enable = 0; + } + + /* set the interface flag */ + l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_ACL, enable); + +done: + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_outacl_cli, static) = { + .path = "set interface acl output", + .short_help = "set interface acl output [disable]", + .function = int_l2_outacl, +}; +/* *INDENT-ON* */ +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c new file mode 100644 index 00000000..27d5eb39 --- /dev/null +++ b/src/vnet/l2/l2_output_classify.c @@ -0,0 +1,657 @@ +/* + * 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 + +/** + * @file + * @brief Layer 2 Output Classifier. + * + * @sa @ref vnet/vnet/classify/vnet_classify.c + * @sa @ref vnet/vnet/classify/vnet_classify.h + */ + +typedef struct +{ + /** interface handle for the ith packet */ + u32 sw_if_index; + /** graph arc index selected for this packet */ + u32 next_index; + /** classifier table which provided the final result */ + u32 table_index; + /** offset in classifier heap of the corresponding session */ + u32 session_offset; +} l2_output_classify_trace_t; + +typedef struct +{ + /** use-case independent main object pointer */ + vnet_classify_main_t *vcm; + /** l2 input classifier main object pointer */ + l2_output_classify_main_t *l2cm; +} l2_output_classify_runtime_t; + +/** Packet trace format function. */ +static u8 * +format_l2_output_classify_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_output_classify_trace_t *t = + va_arg (*args, l2_output_classify_trace_t *); + + s = format (s, "l2-classify: sw_if_index %d, table %d, offset %x, next %d", + t->sw_if_index, t->table_index, t->session_offset, + t->next_index); + return s; +} + +/** l2 output classifier main data structure. */ +l2_output_classify_main_t l2_output_classify_main; + +vlib_node_registration_t l2_output_classify_node; + +#define foreach_l2_output_classify_error \ +_(MISS, "Classify misses") \ +_(HIT, "Classify hits") \ +_(CHAIN_HIT, "Classify hits after chain walk") \ +_(DROP, "L2 Classify Drops") + +typedef enum +{ +#define _(sym,str) L2_OUTPUT_CLASSIFY_ERROR_##sym, + foreach_l2_output_classify_error +#undef _ + L2_OUTPUT_CLASSIFY_N_ERROR, +} l2_output_classify_error_t; + +static char *l2_output_classify_error_strings[] = { +#define _(sym,string) string, + foreach_l2_output_classify_error +#undef _ +}; + +/** + * @brief l2 output classifier node. + * @node l2-output-classify + * + * This is the l2 output classifier dispatch node + * + * @param vm vlib_main_t corresponding to the current thread. + * @param node vlib_node_runtime_t data for this node. + * @param frame vlib_frame_t whose contents should be dispatched. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * @em Uses: + * - (l2_output_classify_runtime_t *) + * rt->classify_table_index_by_sw_if_index + * Head of the per-interface, perprotocol classifier table chain + * for a specific interface. ~0 => send pkts to the next + * feature in the L2 feature chain. + * - vnet_buffer(b)->sw_if_index[VLIB_TX] + * - Indicates the @c sw_if_index value of the interface that the + * packet was received on. + * - vnet_buffer (b0)->l2.feature_bitmap + * - Used to steer packets across l2 features enabled on the interface + * - (vnet_classify_entry_t) e0->next_index + * - Used to steer traffic when the classifier hits on a session + * - (vnet_classify_entry_t) e0->advance + * - Signed quantity applied via vlib_buffer_advance + * when the classifier hits on a session + * - (vnet_classify_table_t) t0->miss_next_index + * - Used to steer traffic when the classifier misses + * + * @em Sets: + * - vnet_buffer (b0)->l2_classify.table_index + * - Classifier table index of the first classifier table in + * the classifier table chain + * - vnet_buffer (b0)->l2_classify.hash + * - Bounded-index extensible hash corresponding to the + * masked fields in the current packet + * - vnet_buffer (b0)->l2.feature_bitmap + * - Used to steer packets across l2 features enabled on the interface + * - vnet_buffer (b0)->l2_classify.opaque_index + * - Copied from the classifier session object upon classifier hit + * + * @em Counters: + * - L2_OUTPUT_CLASSIFY_ERROR_MISS Classifier misses + * - L2_OUTPUT_CLASSIFY_ERROR_HIT Classifier hits + * - L2_OUTPUT_CLASSIFY_ERROR_CHAIN_HIT + * Classifier hits in other than the first table + */ + +static uword +l2_output_classify_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_output_classify_next_t next_index; + l2_output_classify_main_t *cm = &l2_output_classify_main; + vnet_classify_main_t *vcm = cm->vnet_classify_main; + l2_output_classify_runtime_t *rt = + (l2_output_classify_runtime_t *) node->runtime_data; + u32 feature_bitmap0; + u32 hits = 0; + u32 misses = 0; + u32 chain_hits = 0; + f64 now; + u32 n_next_nodes; + u32 cached_sw_if_index = (u32) ~ 0; + u32 cached_next_index = (u32) ~ 0; + u32 sw_if_index0; + + n_next_nodes = node->n_next_nodes; + + now = vlib_time_now (vm); + + n_left_from = frame->n_vectors; + from = vlib_frame_vector_args (frame); + + /* First pass: compute hash */ + + while (n_left_from > 2) + { + vlib_buffer_t *b0, *b1; + u32 bi0, bi1; + ethernet_header_t *h0, *h1; + u32 sw_if_index0, sw_if_index1; + u16 type0, type1; + int type_index0, type_index1; + vnet_classify_table_t *t0, *t1; + u32 table_index0, table_index1; + u64 hash0, hash1; + + + /* prefetch next iteration */ + { + vlib_buffer_t *p1, *p2; + + p1 = vlib_get_buffer (vm, from[1]); + p2 = vlib_get_buffer (vm, from[2]); + + vlib_prefetch_buffer_header (p1, STORE); + CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE); + vlib_prefetch_buffer_header (p2, STORE); + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + bi1 = from[1]; + b1 = vlib_get_buffer (vm, bi1); + h1 = vlib_buffer_get_current (b1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + vnet_buffer (b0)->l2_classify.table_index = ~0; + + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + vnet_buffer (b1)->l2_classify.table_index = ~0; + + /* Select classifier table based on ethertype */ + type0 = clib_net_to_host_u16 (h0->type); + type1 = clib_net_to_host_u16 (h1->type); + + type_index0 = (type0 == ETHERNET_TYPE_IP4) + ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER; + type_index0 = (type0 == ETHERNET_TYPE_IP6) + ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index0; + + type_index1 = (type1 == ETHERNET_TYPE_IP4) + ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER; + type_index1 = (type1 == ETHERNET_TYPE_IP6) + ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index1; + + vnet_buffer (b0)->l2_classify.table_index = + table_index0 = + rt->l2cm->classify_table_index_by_sw_if_index + [type_index0][sw_if_index0]; + + if (table_index0 != ~0) + { + t0 = pool_elt_at_index (vcm->tables, table_index0); + + vnet_buffer (b0)->l2_classify.hash = hash0 = + vnet_classify_hash_packet (t0, (u8 *) h0); + vnet_classify_prefetch_bucket (t0, hash0); + } + + vnet_buffer (b1)->l2_classify.table_index = + table_index1 = + rt->l2cm->classify_table_index_by_sw_if_index + [type_index1][sw_if_index1]; + + if (table_index1 != ~0) + { + t1 = pool_elt_at_index (vcm->tables, table_index1); + + vnet_buffer (b1)->l2_classify.hash = hash1 = + vnet_classify_hash_packet (t1, (u8 *) h1); + vnet_classify_prefetch_bucket (t1, hash1); + } + + from += 2; + n_left_from -= 2; + } + + while (n_left_from > 0) + { + vlib_buffer_t *b0; + u32 bi0; + ethernet_header_t *h0; + u16 type0; + u32 type_index0; + vnet_classify_table_t *t0; + u32 table_index0; + u64 hash0; + + bi0 = from[0]; + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + vnet_buffer (b0)->l2_classify.table_index = ~0; + + /* Select classifier table based on ethertype */ + type0 = clib_net_to_host_u16 (h0->type); + + type_index0 = (type0 == ETHERNET_TYPE_IP4) + ? L2_OUTPUT_CLASSIFY_TABLE_IP4 : L2_OUTPUT_CLASSIFY_TABLE_OTHER; + type_index0 = (type0 == ETHERNET_TYPE_IP6) + ? L2_OUTPUT_CLASSIFY_TABLE_IP6 : type_index0; + + vnet_buffer (b0)->l2_classify.table_index = + table_index0 = rt->l2cm->classify_table_index_by_sw_if_index + [type_index0][sw_if_index0]; + + if (table_index0 != ~0) + { + t0 = pool_elt_at_index (vcm->tables, table_index0); + + vnet_buffer (b0)->l2_classify.hash = hash0 = + vnet_classify_hash_packet (t0, (u8 *) h0); + vnet_classify_prefetch_bucket (t0, hash0); + } + from++; + n_left_from--; + } + + next_index = node->cached_next_index; + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + /* Not enough load/store slots to dual loop... */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = ~0; + ethernet_header_t *h0; + u32 table_index0; + u64 hash0; + vnet_classify_table_t *t0; + vnet_classify_entry_t *e0; + + if (PREDICT_TRUE (n_left_from > 2)) + { + vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]); + u64 phash2; + u32 table_index2; + vnet_classify_table_t *tp2; + + /* + * Prefetch table entry two ahead. Buffer / data + * were prefetched above... + */ + table_index2 = vnet_buffer (p2)->l2_classify.table_index; + + if (PREDICT_TRUE (table_index2 != ~0)) + { + tp2 = pool_elt_at_index (vcm->tables, table_index2); + phash2 = vnet_buffer (p2)->l2_classify.hash; + vnet_classify_prefetch_entry (tp2, phash2); + } + } + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + table_index0 = vnet_buffer (b0)->l2_classify.table_index; + e0 = 0; + vnet_buffer (b0)->l2_classify.opaque_index = ~0; + /* Remove ourself from the feature bitmap */ + feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap + & ~L2OUTPUT_FEAT_OUTPUT_CLASSIFY; + + /* save for next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; + + if (PREDICT_TRUE (table_index0 != ~0)) + { + hash0 = vnet_buffer (b0)->l2_classify.hash; + t0 = pool_elt_at_index (vcm->tables, table_index0); + + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + if (e0) + { + vnet_buffer (b0)->l2_classify.opaque_index + = e0->opaque_index; + vlib_buffer_advance (b0, e0->advance); + next0 = (e0->next_index < n_next_nodes) ? + e0->next_index : next0; + hits++; + } + else + { + while (1) + { + if (t0->next_table_index != ~0) + t0 = pool_elt_at_index (vcm->tables, + t0->next_table_index); + else + { + next0 = (t0->miss_next_index < n_next_nodes) ? + t0->miss_next_index : next0; + misses++; + break; + } + + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = + vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + if (e0) + { + vnet_buffer (b0)->l2_classify.opaque_index + = e0->opaque_index; + vlib_buffer_advance (b0, e0->advance); + next0 = (e0->next_index < n_next_nodes) ? + e0->next_index : next0; + hits++; + chain_hits++; + break; + } + } + } + } + + if (PREDICT_FALSE (next0 == 0)) + b0->error = node->errors[L2_OUTPUT_CLASSIFY_ERROR_DROP]; + + if (PREDICT_FALSE (next0 == ~0)) + { + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + + /* Determine next node */ + l2_output_dispatch (cm->vlib_main, + cm->vnet_main, + node, + l2_output_classify_node.index, + &cached_sw_if_index, + &cached_next_index, + &cm->next_nodes, + b0, sw_if_index0, feature_bitmap0, &next0); + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_output_classify_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->table_index = table_index0; + t->next_index = next0; + t->session_offset = e0 ? vnet_classify_get_offset (t0, e0) : 0; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + vlib_node_increment_counter (vm, node->node_index, + L2_OUTPUT_CLASSIFY_ERROR_MISS, misses); + vlib_node_increment_counter (vm, node->node_index, + L2_OUTPUT_CLASSIFY_ERROR_HIT, hits); + vlib_node_increment_counter (vm, node->node_index, + L2_OUTPUT_CLASSIFY_ERROR_CHAIN_HIT, + chain_hits); + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_output_classify_node) = { + .function = l2_output_classify_node_fn, + .name = "l2-output-classify", + .vector_size = sizeof (u32), + .format_trace = format_l2_output_classify_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_output_classify_error_strings), + .error_strings = l2_output_classify_error_strings, + + .runtime_data_bytes = sizeof (l2_output_classify_runtime_t), + + .n_next_nodes = L2_OUTPUT_CLASSIFY_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_OUTPUT_CLASSIFY_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_output_classify_node, + l2_output_classify_node_fn); + +/** l2 output classsifier feature initialization. */ +clib_error_t * +l2_output_classify_init (vlib_main_t * vm) +{ + l2_output_classify_main_t *cm = &l2_output_classify_main; + l2_output_classify_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, l2_output_classify_node.index); + + cm->vlib_main = vm; + cm->vnet_main = vnet_get_main (); + cm->vnet_classify_main = &vnet_classify_main; + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + l2_output_classify_node.index, + L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + cm->feat_next_node_index); + rt->l2cm = cm; + rt->vcm = cm->vnet_classify_main; + + /* Initialize the output node mapping table */ + l2output_init_output_node_vec (&cm->next_nodes.output_node_index_vec); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_output_classify_init); + +/** Enable/disable l2 input classification on a specific interface. */ +void +vnet_l2_output_classify_enable_disable (u32 sw_if_index, int enable_disable) +{ + + l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_OUTPUT_CLASSIFY, + (u32) enable_disable); +} + +/** @brief Set l2 per-protocol, per-interface output classification tables. + * + * @param sw_if_index interface handle + * @param ip4_table_index ip4 classification table index, or ~0 + * @param ip6_table_index ip6 classification table index, or ~0 + * @param other_table_index non-ip4, non-ip6 classification table index, + * or ~0 + * @returns 0 on success, VNET_API_ERROR_NO_SUCH_TABLE, TABLE2, TABLE3 + * if the indicated (non-~0) table does not exist. + */ + +int +vnet_l2_output_classify_set_tables (u32 sw_if_index, + u32 ip4_table_index, + u32 ip6_table_index, + u32 other_table_index) +{ + l2_output_classify_main_t *cm = &l2_output_classify_main; + vnet_classify_main_t *vcm = cm->vnet_classify_main; + + /* Assume that we've validated sw_if_index in the API layer */ + + if (ip4_table_index != ~0 && + pool_is_free_index (vcm->tables, ip4_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE; + + if (ip6_table_index != ~0 && + pool_is_free_index (vcm->tables, ip6_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE2; + + if (other_table_index != ~0 && + pool_is_free_index (vcm->tables, other_table_index)) + return VNET_API_ERROR_NO_SUCH_TABLE3; + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4], + sw_if_index); + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6], + sw_if_index); + + vec_validate + (cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_OTHER], + sw_if_index); + + cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP4] + [sw_if_index] = ip4_table_index; + + cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_IP6] + [sw_if_index] = ip6_table_index; + + cm->classify_table_index_by_sw_if_index[L2_OUTPUT_CLASSIFY_TABLE_OTHER] + [sw_if_index] = other_table_index; + + return 0; +} + +static clib_error_t * +int_l2_output_classify_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 = ~0; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 other_table_index = ~0; + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "intfc %U", unformat_vnet_sw_interface, + vnm, &sw_if_index)) + ; + else if (unformat (input, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (input, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (input, "other-table %d", &other_table_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "interface must be specified"); + + + if (ip4_table_index == ~0 && ip6_table_index == ~0 + && other_table_index == ~0) + { + vlib_cli_output (vm, "L2 classification disabled"); + vnet_l2_output_classify_enable_disable (sw_if_index, 0 /* enable */ ); + return 0; + } + + rv = vnet_l2_output_classify_set_tables (sw_if_index, ip4_table_index, + ip6_table_index, + other_table_index); + switch (rv) + { + case 0: + vnet_l2_output_classify_enable_disable (sw_if_index, 1 /* enable */ ); + break; + + default: + return clib_error_return (0, "vnet_l2_output_classify_set_tables: %d", + rv); + break; + } + + return 0; +} + +/*? + * Configure Layer 2 output classification. + * + * @cliexpar + * @cliexstart{set interface l2 output classify intfc [ip4-table ] [ip6-table ] [other-table ]} + * @cliexend + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_output_classify_cli, static) = { + .path = "set interface l2 output classify", + .short_help = + "set interface l2 output classify intfc <> [ip4-table ]\n" + " [ip6-table ] [other-table ]", + .function = int_l2_output_classify_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_patch.c b/src/vnet/l2/l2_patch.c new file mode 100644 index 00000000..5e4691f4 --- /dev/null +++ b/src/vnet/l2/l2_patch.c @@ -0,0 +1,452 @@ +/* + * 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 +#include +#include +#include + +typedef struct +{ + /* vector of dispositions, indexed by rx_sw_if_index */ + u32 *tx_next_by_rx_sw_if_index; + u32 *tx_sw_if_index_by_rx_sw_if_index; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_patch_main_t; + +typedef struct +{ + u32 rx_sw_if_index; + u32 tx_sw_if_index; +} l2_patch_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_patch_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_patch_trace_t *t = va_arg (*args, l2_patch_trace_t *); + + s = format (s, "L2_PATCH: rx %d tx %d", t->rx_sw_if_index, + t->tx_sw_if_index); + return s; +} + +l2_patch_main_t l2_patch_main; + +static vlib_node_registration_t l2_patch_node; + +#define foreach_l2_patch_error \ +_(PATCHED, "L2 patch packets") \ +_(DROPPED, "L2 patch misconfigured drops") + +typedef enum +{ +#define _(sym,str) L2_PATCH_ERROR_##sym, + foreach_l2_patch_error +#undef _ + L2_PATCH_N_ERROR, +} l2_patch_error_t; + +static char *l2_patch_error_strings[] = { +#define _(sym,string) string, + foreach_l2_patch_error +#undef _ +}; + +typedef enum +{ + L2_PATCH_NEXT_DROP, + L2_PATCH_N_NEXT, +} l2_patch_next_t; + +static uword +l2_patch_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_patch_next_t next_index; + l2_patch_main_t *l2pm = &l2_patch_main; + vlib_node_t *n = vlib_get_node (vm, l2_patch_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + /* So stupid / simple, we don't need to prefetch data */ + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0); + ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0); + ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index1] != ~0); + ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1] != ~0); + + next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0]; + next1 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index1]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0]; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2_patch_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = sw_if_index0; + t->tx_sw_if_index = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0]; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2_patch_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->rx_sw_if_index = sw_if_index1; + t->tx_sw_if_index = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index1]; + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + ASSERT (l2pm->tx_next_by_rx_sw_if_index[sw_if_index0] != ~0); + ASSERT (l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0] != ~0); + + next0 = l2pm->tx_next_by_rx_sw_if_index[sw_if_index0]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0]; + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2_patch_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = sw_if_index0; + t->tx_sw_if_index = + l2pm->tx_sw_if_index_by_rx_sw_if_index[sw_if_index0]; + } + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + em->counters[node_counter_base_index + L2_PATCH_ERROR_PATCHED] += + frame->n_vectors; + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_patch_node, static) = { + .function = l2_patch_node_fn, + .name = "l2-patch", + .vector_size = sizeof (u32), + .format_trace = format_l2_patch_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_patch_error_strings), + .error_strings = l2_patch_error_strings, + + .n_next_nodes = L2_PATCH_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_PATCH_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_patch_node, l2_patch_node_fn) + int vnet_l2_patch_add_del (u32 rx_sw_if_index, u32 tx_sw_if_index, + int is_add) +{ + l2_patch_main_t *l2pm = &l2_patch_main; + vnet_hw_interface_t *rxhi, *txhi; + u32 tx_next_index; + + /* + * We assume that the API msg handler has used 2x VALIDATE_SW_IF_INDEX + * macros... + */ + + rxhi = vnet_get_sup_hw_interface (l2pm->vnet_main, rx_sw_if_index); + + /* Make sure caller didn't pass a vlan subif, etc. */ + if (rxhi->sw_if_index != rx_sw_if_index) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + txhi = vnet_get_sup_hw_interface (l2pm->vnet_main, tx_sw_if_index); + if (txhi->sw_if_index != tx_sw_if_index) + return VNET_API_ERROR_INVALID_SW_IF_INDEX_2; + + if (is_add) + { + tx_next_index = vlib_node_add_next (l2pm->vlib_main, + l2_patch_node.index, + txhi->output_node_index); + + vec_validate_init_empty (l2pm->tx_next_by_rx_sw_if_index, + rx_sw_if_index, ~0); + + l2pm->tx_next_by_rx_sw_if_index[rx_sw_if_index] = tx_next_index; + vec_validate_init_empty (l2pm->tx_sw_if_index_by_rx_sw_if_index, + rx_sw_if_index, ~0); + l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index] + = txhi->sw_if_index; + + ethernet_set_flags (l2pm->vnet_main, rxhi->hw_if_index, + ETHERNET_INTERFACE_FLAG_ACCEPT_ALL); + + 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_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; + l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index] = ~0; + } + } + + return 0; +} + +static clib_error_t * +test_patch_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2_patch_main_t *l2pm = &l2_patch_main; + unformat_input_t _line_input, *line_input = &_line_input; + u32 rx_sw_if_index, tx_sw_if_index; + int rv; + int rx_set = 0; + int tx_set = 0; + int is_add = 1; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "rx %U", unformat_vnet_sw_interface, + l2pm->vnet_main, &rx_sw_if_index)) + rx_set = 1; + else if (unformat (line_input, "tx %U", unformat_vnet_sw_interface, + l2pm->vnet_main, &tx_sw_if_index)) + tx_set = 1; + else if (unformat (line_input, "del")) + is_add = 0; + else + break; + } + + if (rx_set == 0) + return clib_error_return (0, "rx interface not set"); + + if (tx_set == 0) + return clib_error_return (0, "tx interface not set"); + + rv = vnet_l2_patch_add_del (rx_sw_if_index, tx_sw_if_index, is_add); + + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return (0, "rx interface not a physical port"); + + case VNET_API_ERROR_INVALID_SW_IF_INDEX_2: + return clib_error_return (0, "tx interface not a physical port"); + + default: + return clib_error_return + (0, "WARNING: vnet_l2_patch_add_del returned %d", rv); + } + + return 0; +} + +/*? + * Create or delete a Layer 2 patch. + * + * @cliexpar + * @cliexstart{test l2patch rx tx [del]} + * @cliexend + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_patch_command, static) = { + .path = "test l2patch", + .short_help = "test l2patch rx tx [del]", + .function = test_patch_command_fn, +}; +/* *INDENT-ON* */ + +/** Display the contents of the l2patch table. */ +static clib_error_t * +show_l2patch (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2_patch_main_t *l2pm = &l2_patch_main; + u32 rx_sw_if_index; + u32 no_entries = 1; + + ASSERT (vec_len (l2pm->tx_next_by_rx_sw_if_index) == + vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index)); + + for (rx_sw_if_index = 0; + rx_sw_if_index < vec_len (l2pm->tx_sw_if_index_by_rx_sw_if_index); + rx_sw_if_index++) + { + u32 tx_sw_if_index = + l2pm->tx_sw_if_index_by_rx_sw_if_index[rx_sw_if_index]; + if (tx_sw_if_index != ~0) + { + no_entries = 0; + vlib_cli_output (vm, "%26U -> %U", + format_vnet_sw_if_index_name, + l2pm->vnet_main, rx_sw_if_index, + format_vnet_sw_if_index_name, + l2pm->vnet_main, tx_sw_if_index); + } + } + + if (no_entries) + vlib_cli_output (vm, "no l2patch entries"); + + return 0; +} + +/*? + * Show Layer 2 patch entries. + * + * @cliexpar + * @cliexstart{show l2patch} + * @cliexend + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_l2patch_cli, static) = { + .path = "show l2patch", + .short_help = "Show l2 interface cross-connect entries", + .function = show_l2patch, +}; +/* *INDENT-ON* */ + +clib_error_t * +l2_patch_init (vlib_main_t * vm) +{ + l2_patch_main_t *mp = &l2_patch_main; + + mp->vlib_main = vm; + mp->vnet_main = vnet_get_main (); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_patch_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_rw.c b/src/vnet/l2/l2_rw.c new file mode 100644 index 00000000..c54509d0 --- /dev/null +++ b/src/vnet/l2/l2_rw.c @@ -0,0 +1,719 @@ +/* + * 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 Layer 2 Rewrite. + * + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + */ + + +l2_rw_main_t l2_rw_main; + +vlib_node_registration_t l2_rw_node; + +typedef struct +{ + u32 sw_if_index; + u32 classify_table_index; + u32 rewrite_entry_index; +} l2_rw_trace_t; + +static u8 * +format_l2_rw_entry (u8 * s, va_list * args) +{ + l2_rw_entry_t *e = va_arg (*args, l2_rw_entry_t *); + l2_rw_main_t *rw = &l2_rw_main; + s = format (s, "%d - mask:%U value:%U\n", + e - rw->entries, + format_hex_bytes, e->mask, + e->rewrite_n_vectors * sizeof (u32x4), format_hex_bytes, + e->value, e->rewrite_n_vectors * sizeof (u32x4)); + s = + format (s, " hits:%d skip_bytes:%d", e->hit_count, + e->skip_n_vectors * sizeof (u32x4)); + return s; +} + +static u8 * +format_l2_rw_config (u8 * s, va_list * args) +{ + l2_rw_config_t *c = va_arg (*args, l2_rw_config_t *); + return format (s, "table-index:%d miss-index:%d", + c->table_index, c->miss_index); +} + +/* packet trace format function */ +static u8 * +format_l2_rw_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_rw_trace_t *t = va_arg (*args, l2_rw_trace_t *); + return format (s, "l2-rw: sw_if_index %d, table %d, entry %d", + t->sw_if_index, t->classify_table_index, + t->rewrite_entry_index); +} + +always_inline l2_rw_config_t * +l2_rw_get_config (u32 sw_if_index) +{ + l2_rw_main_t *rw = &l2_rw_main; + if (PREDICT_FALSE (!clib_bitmap_get (rw->configs_bitmap, sw_if_index))) + { + vec_validate (rw->configs, sw_if_index); + rw->configs[sw_if_index].table_index = ~0; + rw->configs[sw_if_index].miss_index = ~0; + rw->configs_bitmap = + clib_bitmap_set (rw->configs_bitmap, sw_if_index, 1); + } + return &rw->configs[sw_if_index]; +} + +static_always_inline void +l2_rw_rewrite (l2_rw_entry_t * rwe, u8 * h) +{ + if (U32X4_ALIGNED (h)) + { + u32x4 *d = ((u32x4 *) h) + rwe->skip_n_vectors; + switch (rwe->rewrite_n_vectors) + { + case 5: + d[4] = (d[4] & ~rwe->mask[4]) | rwe->value[4]; + /* FALLTHROUGH */ + case 4: + d[3] = (d[3] & ~rwe->mask[3]) | rwe->value[3]; + /* FALLTHROUGH */ + case 3: + d[2] = (d[2] & ~rwe->mask[2]) | rwe->value[2]; + /* FALLTHROUGH */ + case 2: + d[1] = (d[1] & ~rwe->mask[1]) | rwe->value[1]; + /* FALLTHROUGH */ + case 1: + d[0] = (d[0] & ~rwe->mask[0]) | rwe->value[0]; + break; + default: + abort (); + } + } + else + { + u64 *d = ((u64 *) h) + rwe->skip_n_vectors * 2; + switch (rwe->rewrite_n_vectors) + { + case 5: + d[8] = + (d[8] & ~(((u64 *) rwe->mask)[8])) | (((u64 *) rwe->value)[8]); + d[9] = + (d[9] & ~(((u64 *) rwe->mask)[9])) | (((u64 *) rwe->value)[9]); + /* FALLTHROUGH */ + case 4: + d[6] = + (d[6] & ~(((u64 *) rwe->mask)[6])) | (((u64 *) rwe->value)[6]); + d[7] = + (d[7] & ~(((u64 *) rwe->mask)[7])) | (((u64 *) rwe->value)[7]); + /* FALLTHROUGH */ + case 3: + d[4] = + (d[4] & ~(((u64 *) rwe->mask)[4])) | (((u64 *) rwe->value)[4]); + d[5] = + (d[5] & ~(((u64 *) rwe->mask)[5])) | (((u64 *) rwe->value)[5]); + /* FALLTHROUGH */ + case 2: + d[2] = + (d[2] & ~(((u64 *) rwe->mask)[2])) | (((u64 *) rwe->value)[2]); + d[3] = + (d[3] & ~(((u64 *) rwe->mask)[3])) | (((u64 *) rwe->value)[3]); + /* FALLTHROUGH */ + case 1: + d[0] = + (d[0] & ~(((u64 *) rwe->mask)[0])) | (((u64 *) rwe->value)[0]); + d[1] = + (d[1] & ~(((u64 *) rwe->mask)[1])) | (((u64 *) rwe->value)[1]); + break; + default: + abort (); + } + } +} + +static uword +l2_rw_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + l2_rw_main_t *rw = &l2_rw_main; + u32 n_left_from, *from, *to_next, next_index; + vnet_classify_main_t *vcm = &vnet_classify_main; + f64 now = vlib_time_now (vlib_get_main ()); + u32 prefetch_size = 0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; /* number of packets to process */ + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + /* get space to enqueue frame to graph node "next_index" */ + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, next0, sw_if_index0, feature_bitmap0, rwe_index0; + u32 bi1, next1, sw_if_index1, feature_bitmap1, rwe_index1; + vlib_buffer_t *b0, *b1; + ethernet_header_t *h0, *h1; + l2_rw_config_t *config0, *config1; + u64 hash0, hash1; + vnet_classify_table_t *t0, *t1; + vnet_classify_entry_t *e0, *e1; + l2_rw_entry_t *rwe0, *rwe1; + + { + vlib_buffer_t *p2, *p3; + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + CLIB_PREFETCH (vlib_buffer_get_current (p2), prefetch_size, LOAD); + CLIB_PREFETCH (vlib_buffer_get_current (p3), prefetch_size, LOAD); + } + + bi0 = from[0]; + bi1 = from[1]; + to_next[0] = bi0; + to_next[1] = bi1; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + h0 = vlib_buffer_get_current (b0); + h1 = vlib_buffer_get_current (b1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + config0 = l2_rw_get_config (sw_if_index0); /*TODO: check sw_if_index0 value */ + config1 = l2_rw_get_config (sw_if_index1); /*TODO: check sw_if_index0 value */ + t0 = pool_elt_at_index (vcm->tables, config0->table_index); + t1 = pool_elt_at_index (vcm->tables, config1->table_index); + prefetch_size = + (t1->skip_n_vectors + t1->match_n_vectors) * sizeof (u32x4); + + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + hash1 = vnet_classify_hash_packet (t1, (u8 *) h1); + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + e1 = vnet_classify_find_entry (t1, (u8 *) h1, hash1, now); + + while (!e0 && (t0->next_table_index != ~0)) + { + t0 = pool_elt_at_index (vcm->tables, t0->next_table_index); + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + } + + while (!e1 && (t1->next_table_index != ~0)) + { + t1 = pool_elt_at_index (vcm->tables, t1->next_table_index); + hash1 = vnet_classify_hash_packet (t1, (u8 *) h1); + e1 = vnet_classify_find_entry (t1, (u8 *) h1, hash1, now); + } + + rwe_index0 = e0 ? e0->opaque_index : config0->miss_index; + rwe_index1 = e1 ? e1->opaque_index : config1->miss_index; + + if (rwe_index0 != ~0) + { + rwe0 = pool_elt_at_index (rw->entries, rwe_index0); + l2_rw_rewrite (rwe0, (u8 *) h0); + } + if (rwe_index1 != ~0) + { + rwe1 = pool_elt_at_index (rw->entries, rwe_index1); + l2_rw_rewrite (rwe1, (u8 *) h1); + } + + if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_rw_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->classify_table_index = config0->table_index; + t->rewrite_entry_index = rwe_index0; + } + + if (PREDICT_FALSE ((b1->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_rw_trace_t *t = vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + t->classify_table_index = config1->table_index; + t->rewrite_entry_index = rwe_index1; + } + + /* Update feature bitmap and get next feature index */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; + feature_bitmap1 = + vnet_buffer (b1)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; + vnet_buffer (b1)->l2.feature_bitmap = feature_bitmap1; + next0 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, + feature_bitmap0); + next1 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, + feature_bitmap1); + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0, next0, sw_if_index0, feature_bitmap0, rwe_index0; + vlib_buffer_t *b0; + ethernet_header_t *h0; + l2_rw_config_t *config0; + u64 hash0; + vnet_classify_table_t *t0; + vnet_classify_entry_t *e0; + l2_rw_entry_t *rwe0; + + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + h0 = vlib_buffer_get_current (b0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + config0 = l2_rw_get_config (sw_if_index0); /*TODO: check sw_if_index0 value */ + t0 = pool_elt_at_index (vcm->tables, config0->table_index); + + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + + while (!e0 && (t0->next_table_index != ~0)) + { + t0 = pool_elt_at_index (vcm->tables, t0->next_table_index); + hash0 = vnet_classify_hash_packet (t0, (u8 *) h0); + e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now); + } + + rwe_index0 = e0 ? e0->opaque_index : config0->miss_index; + + if (rwe_index0 != ~0) + { + rwe0 = pool_elt_at_index (rw->entries, rwe_index0); + l2_rw_rewrite (rwe0, (u8 *) h0); + } + + if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_rw_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + t->classify_table_index = config0->table_index; + t->rewrite_entry_index = rwe_index0; + } + + /* Update feature bitmap and get next feature index */ + feature_bitmap0 = + vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; + next0 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, + feature_bitmap0); + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +int +l2_rw_mod_entry (u32 * index, + u8 * mask, u8 * value, u32 len, u32 skip, u8 is_del) +{ + l2_rw_main_t *rw = &l2_rw_main; + l2_rw_entry_t *e = 0; + if (*index != ~0) + { + if (pool_is_free_index (rw->entries, *index)) + { + return -1; + } + e = pool_elt_at_index (rw->entries, *index); + } + else + { + pool_get (rw->entries, e); + *index = e - rw->entries; + } + + if (!e) + return -1; + + if (is_del) + { + pool_put (rw->entries, e); + return 0; + } + + e->skip_n_vectors = skip / sizeof (u32x4); + skip -= e->skip_n_vectors * sizeof (u32x4); + e->rewrite_n_vectors = (skip + len - 1) / sizeof (u32x4) + 1; + vec_alloc_aligned (e->mask, e->rewrite_n_vectors, sizeof (u32x4)); + memset (e->mask, 0, e->rewrite_n_vectors * sizeof (u32x4)); + vec_alloc_aligned (e->value, e->rewrite_n_vectors, sizeof (u32x4)); + memset (e->value, 0, e->rewrite_n_vectors * sizeof (u32x4)); + + clib_memcpy (((u8 *) e->value) + skip, value, len); + clib_memcpy (((u8 *) e->mask) + skip, mask, len); + + int i; + for (i = 0; i < e->rewrite_n_vectors; i++) + { + e->value[i] &= e->mask[i]; + } + + return 0; +} + +static clib_error_t * +l2_rw_entry_cli_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u32 index = ~0; + u8 *mask = 0; + u8 *value = 0; + u32 skip = 0; + u8 del = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "index %d", &index)) + ; + else if (unformat (input, "mask %U", unformat_hex_string, &mask)) + ; + else if (unformat (input, "value %U", unformat_hex_string, &value)) + ; + else if (unformat (input, "skip %d", &skip)) + ; + else if (unformat (input, "del")) + del = 1; + else + break; + } + + if (!mask || !value) + return clib_error_return (0, "Unspecified mask or value"); + + if (vec_len (mask) != vec_len (value)) + return clib_error_return (0, "Mask and value lengths must be identical"); + + int ret; + if ((ret = + l2_rw_mod_entry (&index, mask, value, vec_len (mask), skip, del))) + return clib_error_return (0, "Could not add entry"); + + return 0; +} + +/*? + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_rw_entry_cli, static) = { + .path = "l2 rewrite entry", + .short_help = + "l2 rewrite entry [index ] [mask ] [value ] [skip ] [del]", + .function = l2_rw_entry_cli_fn, +}; +/* *INDENT-ON* */ + +int +l2_rw_interface_set_table (u32 sw_if_index, u32 table_index, u32 miss_index) +{ + l2_rw_config_t *c = l2_rw_get_config (sw_if_index); + l2_rw_main_t *rw = &l2_rw_main; + + c->table_index = table_index; + c->miss_index = miss_index; + u32 feature_bitmap = (table_index == ~0) ? 0 : L2INPUT_FEAT_RW; + + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_RW, feature_bitmap); + + if (c->table_index == ~0) + clib_bitmap_set (rw->configs_bitmap, sw_if_index, 0); + + return 0; +} + +static clib_error_t * +l2_rw_interface_cli_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 table_index = ~0; + u32 sw_if_index = ~0; + u32 miss_index = ~0; + + if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index); + } + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "table %d", &table_index)) + ; + else if (unformat (input, "miss-index %d", &miss_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, + "You must specify an interface 'iface '", + format_unformat_error, input); + int ret; + if ((ret = + l2_rw_interface_set_table (sw_if_index, table_index, miss_index))) + return clib_error_return (0, "l2_rw_interface_set_table returned %d", + ret); + + return 0; +} + +/*? + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_rw_interface_cli, static) = { + .path = "set interface l2 rewrite", + .short_help = + "set interface l2 rewrite [table ] [miss-index ]", + .function = l2_rw_interface_cli_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +l2_rw_show_interfaces_cli_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + l2_rw_main_t *rw = &l2_rw_main; + if (clib_bitmap_count_set_bits (rw->configs_bitmap) == 0) + vlib_cli_output (vm, "No interface is currently using l2 rewrite\n"); + + uword i; + /* *INDENT-OFF* */ + clib_bitmap_foreach(i, rw->configs_bitmap, { + vlib_cli_output (vm, "sw_if_index:%d %U\n", i, format_l2_rw_config, &rw->configs[i]); + }); + /* *INDENT-ON* */ + return 0; +} + +/*? + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_rw_show_interfaces_cli, static) = { + .path = "show l2 rewrite interfaces", + .short_help = + "show l2 rewrite interfaces", + .function = l2_rw_show_interfaces_cli_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +l2_rw_show_entries_cli_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2_rw_main_t *rw = &l2_rw_main; + l2_rw_entry_t *e; + if (pool_elts (rw->entries) == 0) + vlib_cli_output (vm, "No entries\n"); + + /* *INDENT-OFF* */ + pool_foreach(e, rw->entries, { + vlib_cli_output (vm, "%U\n", format_l2_rw_entry, e); + }); + /* *INDENT-ON* */ + return 0; +} + +/*? + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_rw_show_entries_cli, static) = { + .path = "show l2 rewrite entries", + .short_help = + "show l2 rewrite entries", + .function = l2_rw_show_entries_cli_fn, +}; +/* *INDENT-ON* */ + +int +l2_rw_enable_disable (u32 bridge_domain, u8 disable) +{ + u32 mask = L2INPUT_FEAT_RW; + l2input_set_bridge_features (bridge_domain, mask, disable ? 0 : mask); + return 0; +} + +static clib_error_t * +l2_rw_set_cli_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + u32 bridge_domain; + u8 disable = 0; + + if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT || + !unformat (input, "%d", &bridge_domain)) + { + return clib_error_return (0, "You must specify a bridge domain"); + } + + if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT && + unformat (input, "disable")) + { + disable = 1; + } + + if (l2_rw_enable_disable (bridge_domain, disable)) + return clib_error_return (0, "Could not enable or disable rewrite"); + + return 0; +} + +/*? + * Layer 2-Rewrite node uses classify tables to match packets. Then, using + * the provisioned mask and value, modfies the packet header. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2_rw_set_cli, static) = { + .path = "set bridge-domain rewrite", + .short_help = + "set bridge-domain rewrite [disable]", + .function = l2_rw_set_cli_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +l2_rw_init (vlib_main_t * vm) +{ + l2_rw_main_t *rw = &l2_rw_main; + rw->configs = 0; + rw->entries = 0; + clib_bitmap_alloc (rw->configs_bitmap, 1); + feat_bitmap_init_next_nodes (vm, + l2_rw_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + rw->feat_next_node_index); + return 0; +} + +VLIB_INIT_FUNCTION (l2_rw_init); + +enum +{ + L2_RW_NEXT_DROP, + L2_RW_N_NEXT, +}; + +#define foreach_l2_rw_error \ +_(UNKNOWN, "Unknown error") + +typedef enum +{ +#define _(sym,str) L2_RW_ERROR_##sym, + foreach_l2_rw_error +#undef _ + L2_RW_N_ERROR, +} l2_rw_error_t; + +static char *l2_rw_error_strings[] = { +#define _(sym,string) string, + foreach_l2_rw_error +#undef _ +}; + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_rw_node) = { + .function = l2_rw_node_fn, + .name = "l2-rw", + .vector_size = sizeof (u32), + .format_trace = format_l2_rw_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + .n_errors = ARRAY_LEN(l2_rw_error_strings), + .error_strings = l2_rw_error_strings, + .runtime_data_bytes = 0, + .n_next_nodes = L2_RW_N_NEXT, + .next_nodes = { [L2_RW_NEXT_DROP] = "error-drop"}, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_rw_node, l2_rw_node_fn) +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_rw.h b/src/vnet/l2/l2_rw.h new file mode 100644 index 00000000..49aa25fb --- /dev/null +++ b/src/vnet/l2/l2_rw.h @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/* + * l2_rw is based on vnet classifier and provides a way + * to modify packets matching a given table. + * + * Tables must be created using vnet's classify features. + * Entries contained within these tables must have their + * opaque index set to the rewrite entry created with l2_rw_mod_entry. + */ + +#ifndef L2_RW_H_ +#define L2_RW_H_ + +#include + +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct _l2_rw_entry { + u16 skip_n_vectors; + u16 rewrite_n_vectors; + u64 hit_count; + u32x4 *mask; + u32x4 *value; +}) l2_rw_entry_t; +/* *INDENT-ON* */ + +/* l2_rw configuration for one interface */ +/* *INDENT-OFF* */ +typedef CLIB_PACKED(struct _l2_rw_config { + u32 table_index; /* Which classify table to use */ + u32 miss_index; /* Rewrite entry to use if table does not match */ +}) l2_rw_config_t; +/* *INDENT-ON* */ + +typedef struct +{ + /* Next feature node indexes */ + u32 feat_next_node_index[32]; + + /* A pool of entries */ + l2_rw_entry_t *entries; + + /* Config vector indexed by sw_if_index */ + l2_rw_config_t *configs; + uword *configs_bitmap; +} l2_rw_main_t; + +extern l2_rw_main_t l2_rw_main; + +/* + * Specifies which classify table and miss_index should be used + * with the given interface. + * Use special values ~0 in order to un-set table_index + * or miss_index. + * l2_rw feature is automatically enabled for the interface + * when table_index or miss_index is not ~0. + * returns 0 on success and something else on error. + */ +int l2_rw_interface_set_table (u32 sw_if_index, + u32 table_index, u32 miss_index); + +/* + * Creates, modifies or delete a rewrite entry. + * If *index != ~0, modifies an existing entry (or simply + * deletes it if is_del is set). + * If *index == ~0, creates a new entry and the created + * entry index is stored in *index (Does nothing if is_del + * is set). + * returns 0 on success and something else on error. + */ +int l2_rw_mod_entry (u32 * index, + u8 * mask, u8 * value, u32 len, u32 skip, u8 is_del); + +#endif /* L2_FW_H_ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_vtr.c b/src/vnet/l2/l2_vtr.c new file mode 100644 index 00000000..95a4f157 --- /dev/null +++ b/src/vnet/l2/l2_vtr.c @@ -0,0 +1,770 @@ +/* + * l2_vtr.c : layer 2 vlan tag rewrite configuration + * + * Copyright (c) 2013 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * @file + * @brief Ethernet VLAN Tag Rewrite. + * + * VLAN tag rewrite provides the ability to change the VLAN tags on a packet. + * Existing tags can be popped, new tags can be pushed, and existing tags can + * be swapped with new tags. The rewrite feature is attached to a subinterface + * as input and output operations. The input operation is explicitly configured. + * The output operation is the symmetric opposite and is automatically derived + * from the input operation. + */ + +/** Just a placeholder; ensures file is not eliminated by linker. */ +clib_error_t * +l2_vtr_init (vlib_main_t * vm) +{ + return 0; +} + +VLIB_INIT_FUNCTION (l2_vtr_init); + +u32 +l2pbb_configure (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, + u8 * b_dmac, u8 * b_smac, + u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag) +{ + u32 error = 0; + u32 enable = 0; + + l2_output_config_t *config = 0; + vnet_hw_interface_t *hi; + hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + + if (!hi) + { + error = VNET_API_ERROR_INVALID_INTERFACE; + goto done; + } + + // Config for this interface should be already initialized + ptr_config_t *in_config; + ptr_config_t *out_config; + config = vec_elt_at_index (l2output_main.configs, sw_if_index); + in_config = &(config->input_pbb_vtr); + out_config = &(config->output_pbb_vtr); + + in_config->pop_bytes = 0; + in_config->push_bytes = 0; + out_config->pop_bytes = 0; + out_config->push_bytes = 0; + enable = (vtr_op != L2_VTR_DISABLED); + + if (!enable) + goto done; + + if (vtr_op == L2_VTR_POP_2) + { + in_config->pop_bytes = sizeof (ethernet_pbb_header_packed_t); + } + else if (vtr_op == L2_VTR_PUSH_2) + { + clib_memcpy (in_config->macs_tags.b_dst_address, b_dmac, + sizeof (in_config->macs_tags.b_dst_address)); + clib_memcpy (in_config->macs_tags.b_src_address, b_smac, + sizeof (in_config->macs_tags.b_src_address)); + in_config->macs_tags.b_type = + clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AD); + in_config->macs_tags.priority_dei_id = + clib_net_to_host_u16 (b_vlanid & 0xFFF); + in_config->macs_tags.i_type = + clib_net_to_host_u16 (ETHERNET_TYPE_DOT1AH); + in_config->macs_tags.priority_dei_uca_res_sid = + clib_net_to_host_u32 (i_sid & 0xFFFFF); + in_config->push_bytes = sizeof (ethernet_pbb_header_packed_t); + } + else if (vtr_op == L2_VTR_TRANSLATE_2_2) + { + /* TODO after PoC */ + } + + /* + * Construct the output tag-rewrite config + * + * The push/pop values are always reversed + */ + out_config->raw_data = in_config->raw_data; + out_config->pop_bytes = in_config->push_bytes; + out_config->push_bytes = in_config->pop_bytes; + +done: + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable); + if (config) + config->out_vtr_flag = (u8) enable; + + /* output vtr enable is checked explicitly in l2_output */ + return error; +} + +/** + * Configure vtag tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 +l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, u32 push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */ + u32 vtr_tag1, /* first pushed tag */ + u32 vtr_tag2) /* second pushed tag */ +{ + vnet_hw_interface_t *hi; + vnet_sw_interface_t *si; + u32 hw_no_tags; + u32 error = 0; + l2_output_config_t *config; + vtr_config_t *in_config; + vtr_config_t *out_config; + u32 enable; + u32 push_inner_et; + u32 push_outer_et; + u32 cfg_tags; + + hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index)) + { + error = VNET_API_ERROR_INVALID_INTERFACE; /* non-ethernet interface */ + goto done; + } + + /* Init the config for this interface */ + vec_validate (l2output_main.configs, sw_if_index); + config = vec_elt_at_index (l2output_main.configs, sw_if_index); + in_config = &(config->input_vtr); + out_config = &(config->output_vtr); + in_config->raw_tags = 0; + out_config->raw_tags = 0; + + /* Get the configured tags for the interface */ + si = vnet_get_sw_interface (vnet_main, sw_if_index); + hw_no_tags = (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE); + + /* Construct the input tag-rewrite config */ + + push_outer_et = + clib_net_to_host_u16 (push_dot1q ? ETHERNET_TYPE_VLAN : + ETHERNET_TYPE_DOT1AD); + push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN); + vtr_tag1 = clib_net_to_host_u16 (vtr_tag1); + vtr_tag2 = clib_net_to_host_u16 (vtr_tag2); + + /* Determine number of vlan tags with explictly configured values */ + cfg_tags = 0; + if (hw_no_tags || si->sub.eth.flags.no_tags) + { + cfg_tags = 0; + } + else if (si->sub.eth.flags.one_tag) + { + cfg_tags = 1; + if (si->sub.eth.flags.outer_vlan_id_any) + { + cfg_tags = 0; + } + } + else if (si->sub.eth.flags.two_tags) + { + cfg_tags = 2; + if (si->sub.eth.flags.inner_vlan_id_any) + { + cfg_tags = 1; + } + if (si->sub.eth.flags.outer_vlan_id_any) + { + cfg_tags = 0; + } + } + + switch (vtr_op) + { + case L2_VTR_DISABLED: + in_config->push_and_pop_bytes = 0; + break; + + case L2_VTR_POP_1: + if (cfg_tags < 1) + { + /* Need one or two tags */ + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; + goto done; + } + in_config->pop_bytes = 4; + in_config->push_bytes = 0; + break; + + case L2_VTR_POP_2: + if (cfg_tags < 2) + { + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */ + goto done; + } + in_config->pop_bytes = 8; + in_config->push_bytes = 0; + + out_config->push_bytes = in_config->pop_bytes; + out_config->pop_bytes = in_config->push_bytes; + break; + + case L2_VTR_PUSH_1: + in_config->pop_bytes = 0; + in_config->push_bytes = 4; + in_config->tags[1].priority_cfi_and_id = vtr_tag1; + in_config->tags[1].type = push_outer_et; + break; + + case L2_VTR_PUSH_2: + in_config->pop_bytes = 0; + in_config->push_bytes = 8; + in_config->tags[0].priority_cfi_and_id = vtr_tag1; + in_config->tags[0].type = push_outer_et; + in_config->tags[1].priority_cfi_and_id = vtr_tag2; + in_config->tags[1].type = push_inner_et; + break; + + case L2_VTR_TRANSLATE_1_1: + if (cfg_tags < 1) + { + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */ + goto done; + } + in_config->pop_bytes = 4; + in_config->push_bytes = 4; + in_config->tags[1].priority_cfi_and_id = vtr_tag1; + in_config->tags[1].type = push_outer_et; + break; + + case L2_VTR_TRANSLATE_1_2: + if (cfg_tags < 1) + { + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need one or two tags */ + goto done; + } + in_config->pop_bytes = 4; + in_config->push_bytes = 8; + in_config->tags[0].priority_cfi_and_id = vtr_tag1; + in_config->tags[0].type = push_outer_et; + in_config->tags[1].priority_cfi_and_id = vtr_tag2; + in_config->tags[1].type = push_inner_et; + break; + + case L2_VTR_TRANSLATE_2_1: + if (cfg_tags < 2) + { + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */ + goto done; + } + in_config->pop_bytes = 8; + in_config->push_bytes = 4; + in_config->tags[1].priority_cfi_and_id = vtr_tag1; + in_config->tags[1].type = push_outer_et; + break; + + case L2_VTR_TRANSLATE_2_2: + if (cfg_tags < 2) + { + error = VNET_API_ERROR_INVALID_VLAN_TAG_COUNT; /* Need two tags */ + goto done; + } + in_config->pop_bytes = 8; + in_config->push_bytes = 8; + in_config->tags[0].priority_cfi_and_id = vtr_tag1; + in_config->tags[0].type = push_outer_et; + in_config->tags[1].priority_cfi_and_id = vtr_tag2; + in_config->tags[1].type = push_inner_et; + break; + } + + /* + * Construct the output tag-rewrite config + * + * The push/pop values are always reversed + */ + out_config->push_bytes = in_config->pop_bytes; + out_config->pop_bytes = in_config->push_bytes; + + /* Any pushed tags are derived from the subinterface config */ + push_outer_et = + clib_net_to_host_u16 (si->sub.eth.flags.dot1ad ? ETHERNET_TYPE_DOT1AD : + ETHERNET_TYPE_VLAN); + push_inner_et = clib_net_to_host_u16 (ETHERNET_TYPE_VLAN); + vtr_tag1 = clib_net_to_host_u16 (si->sub.eth.outer_vlan_id); + vtr_tag2 = clib_net_to_host_u16 (si->sub.eth.inner_vlan_id); + + if (out_config->push_bytes == 4) + { + out_config->tags[1].priority_cfi_and_id = vtr_tag1; + out_config->tags[1].type = push_outer_et; + } + else if (out_config->push_bytes == 8) + { + out_config->tags[0].priority_cfi_and_id = vtr_tag1; + out_config->tags[0].type = push_outer_et; + out_config->tags[1].priority_cfi_and_id = vtr_tag2; + out_config->tags[1].type = push_inner_et; + } + + /* set the interface enable flags */ + enable = (vtr_op != L2_VTR_DISABLED); + config->out_vtr_flag = (u8) enable; + l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_VTR, enable); + /* output vtr enable is checked explicitly in l2_output */ + +done: + return error; +} + +/** + * Get vtag tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 +l2vtr_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, u32 * vtr_op, u32 * push_dot1q, /* ethertype of first pushed tag is dot1q/dot1ad */ + u32 * vtr_tag1, /* first pushed tag */ + u32 * vtr_tag2) /* second pushed tag */ +{ + vnet_hw_interface_t *hi; + u32 error = 0; + vtr_config_t *in_config; + + if (!vtr_op || !push_dot1q || !vtr_tag1 || !vtr_tag2) + { + clib_warning ("invalid arguments"); + error = VNET_API_ERROR_INVALID_ARGUMENT; + goto done; + } + + *vtr_op = L2_VTR_DISABLED; + *vtr_tag1 = 0; + *vtr_tag2 = 0; + *push_dot1q = 0; + + hi = vnet_get_sup_hw_interface (vnet_main, sw_if_index); + if (!hi || (hi->hw_class_index != ethernet_hw_interface_class.index)) + { + /* non-ethernet interface */ + goto done; + } + + if (sw_if_index >= vec_len (l2output_main.configs)) + { + /* no specific config (return disabled) */ + goto done; + } + + /* Get the config for this interface */ + in_config = + &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_vtr); + + /* DISABLED */ + if (in_config->push_and_pop_bytes == 0) + { + goto done; + } + + /* find out vtr_op */ + switch (in_config->pop_bytes) + { + case 0: + switch (in_config->push_bytes) + { + case 0: + /* DISABLED */ + goto done; + case 4: + *vtr_op = L2_VTR_PUSH_1; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[1].type)); + break; + case 8: + *vtr_op = L2_VTR_PUSH_2; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id); + *vtr_tag2 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[0].type)); + break; + default: + clib_warning ("invalid push_bytes count: %d", + in_config->push_bytes); + error = VNET_API_ERROR_UNEXPECTED_INTF_STATE; + goto done; + } + break; + + case 4: + switch (in_config->push_bytes) + { + case 0: + *vtr_op = L2_VTR_POP_1; + break; + case 4: + *vtr_op = L2_VTR_TRANSLATE_1_1; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[1].type)); + break; + case 8: + *vtr_op = L2_VTR_TRANSLATE_1_2; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id); + *vtr_tag2 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[0].type)); + break; + default: + clib_warning ("invalid push_bytes count: %d", + in_config->push_bytes); + error = VNET_API_ERROR_UNEXPECTED_INTF_STATE; + goto done; + } + break; + + case 8: + switch (in_config->push_bytes) + { + case 0: + *vtr_op = L2_VTR_POP_2; + break; + case 4: + *vtr_op = L2_VTR_TRANSLATE_2_1; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[1].type)); + break; + case 8: + *vtr_op = L2_VTR_TRANSLATE_2_2; + *vtr_tag1 = + clib_host_to_net_u16 (in_config->tags[0].priority_cfi_and_id); + *vtr_tag2 = + clib_host_to_net_u16 (in_config->tags[1].priority_cfi_and_id); + *push_dot1q = + (ETHERNET_TYPE_VLAN == + clib_host_to_net_u16 (in_config->tags[0].type)); + break; + default: + clib_warning ("invalid push_bytes count: %d", + in_config->push_bytes); + error = VNET_API_ERROR_UNEXPECTED_INTF_STATE; + goto done; + } + break; + + default: + clib_warning ("invalid pop_bytes count: %d", in_config->pop_bytes); + error = VNET_API_ERROR_UNEXPECTED_INTF_STATE; + goto done; + } + +done: + return error; +} + +/** + * Set subinterface vtr enable/disable. + * The CLI format is: + * set interface l2 tag-rewrite [disable | pop 1 | pop 2 | push {dot1q|dot1ad} []] + * + * "push" can also be replaced by "translate-{1|2}-{1|2}" + */ +static clib_error_t * +int_l2_vtr (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + u32 vtr_op; + u32 push_dot1q = 0; + u32 tag1 = 0, tag2 = 0; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + vtr_op = L2_VTR_DISABLED; + + if (unformat (input, "disable")) + { + vtr_op = L2_VTR_DISABLED; + } + else if (unformat (input, "pop 1")) + { + vtr_op = L2_VTR_POP_1; + } + else if (unformat (input, "pop 2")) + { + vtr_op = L2_VTR_POP_2; + + } + else if (unformat (input, "push dot1q %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_PUSH_2; + push_dot1q = 1; + } + else if (unformat (input, "push dot1ad %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_PUSH_2; + + } + else if (unformat (input, "push dot1q %d", &tag1)) + { + vtr_op = L2_VTR_PUSH_1; + push_dot1q = 1; + } + else if (unformat (input, "push dot1ad %d", &tag1)) + { + vtr_op = L2_VTR_PUSH_1; + + } + else if (unformat (input, "translate 1-1 dot1q %d", &tag1)) + { + vtr_op = L2_VTR_TRANSLATE_1_1; + push_dot1q = 1; + } + else if (unformat (input, "translate 1-1 dot1ad %d", &tag1)) + { + vtr_op = L2_VTR_TRANSLATE_1_1; + + } + else if (unformat (input, "translate 2-1 dot1q %d", &tag1)) + { + vtr_op = L2_VTR_TRANSLATE_2_1; + push_dot1q = 1; + } + else if (unformat (input, "translate 2-1 dot1ad %d", &tag1)) + { + vtr_op = L2_VTR_TRANSLATE_2_1; + + } + else if (unformat (input, "translate 2-2 dot1q %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_TRANSLATE_2_2; + push_dot1q = 1; + } + else if (unformat (input, "translate 2-2 dot1ad %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_TRANSLATE_2_2; + + } + else if (unformat (input, "translate 1-2 dot1q %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_TRANSLATE_1_2; + push_dot1q = 1; + } + else if (unformat (input, "translate 1-2 dot1ad %d %d", &tag1, &tag2)) + { + vtr_op = L2_VTR_TRANSLATE_1_2; + + } + else + { + error = + clib_error_return (0, + "expecting [disable | pop 1 | pop 2 | push {dot1q|dot1ah} []\n" + " | translate {1|2}-{1|2} {dot1q|dot1ah} []] but got `%U'", + format_unformat_error, input); + goto done; + } + + if (l2vtr_configure (vm, vnm, sw_if_index, vtr_op, push_dot1q, tag1, tag2)) + { + error = + clib_error_return (0, + "vlan tag rewrite is not compatible with interface"); + goto done; + } + +done: + return error; +} + +/*? + * VLAN tag rewrite provides the ability to change the VLAN tags on a packet. + * Existing tags can be popped, new tags can be pushed, and existing tags can + * be swapped with new tags. The rewrite feature is attached to a subinterface + * as input and output operations. The input operation is explicitly configured. + * The output operation is the symmetric opposite and is automatically derived + * from the input operation. + * + * POP: For pop operations, the subinterface encapsulation (the vlan + * tags specified when it was created) must have at least the number of popped + * tags. e.g. the \"pop 2\" operation would be rejected on a single-vlan interface. + * The output tag-rewrite operation for pops is to push the specified number of + * vlan tags onto the packet. The pushed tag values are the ones in the + * subinterface encapsulation. + * + * PUSH: For push operations, the ethertype is also specified. The + * output tag-rewrite operation for pushes is to pop the same number of tags + * off the packet. If the packet doesn't have enough tags it is dropped. + * + * + * @cliexpar + * @parblock + * By default a subinterface has no tag-rewrite. To return a subinterface to + * this state use: + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 disable} + * + * To pop vlan tags off packets received from a subinterface, use: + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 1} + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 pop 2} + * + * To push one or two vlan tags onto packets received from an interface, use: + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1q 100} + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 push dot1ad 100 150} + * + * Tags can also be translated, which is basically a combination of a pop and push. + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-1 dot1ad 100} + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-2 dot1ad 100 150} + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 1-2 dot1q 100} + * @cliexcmd{set interface l2 tag-rewrite GigabitEthernet0/8/0.200 translate 2-1 dot1q 100 150} + * + * To display the VLAN Tag settings, show the associate bridge-domain: + * @cliexstart{show bridge-domain 200 detail} + * ID Index Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 200 1 on on on on off N/A + * + * Interface Index SHG BVI VLAN-Tag-Rewrite + * GigabitEthernet0/8/0.200 5 0 - trans-1-1 dot1ad 100 + * GigabitEthernet0/9/0.200 4 0 - none + * GigabitEthernet0/a/0.200 6 0 - none + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = { + .path = "set interface l2 tag-rewrite", + .short_help = "set interface l2 tag-rewrite [disable | pop {1|2} | push {dot1q|dot1ad} ]", + .function = int_l2_vtr, +}; +/* *INDENT-ON* */ + +/** + * Set subinterface pbb vtr enable/disable. + * The CLI format is: + * set interface l2 pbb-tag-rewrite [disable | pop | push | translate_pbb_stag dmac
smac
s_id [b_vlanid ]] + */ +static clib_error_t * +int_l2_pbb_vtr (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index, tmp; + u32 vtr_op = L2_VTR_DISABLED; + u32 outer_tag = 0; + u8 dmac[6]; + u8 smac[6]; + u8 dmac_set = 0, smac_set = 0; + u16 b_vlanid = 0; + u32 s_id = ~0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat_user + (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + ; + else if (unformat (input, "disable")) + vtr_op = L2_VTR_DISABLED; + else if (vtr_op == L2_VTR_DISABLED && unformat (input, "pop")) + vtr_op = L2_VTR_POP_2; + else if (vtr_op == L2_VTR_DISABLED && unformat (input, "push")) + vtr_op = L2_VTR_PUSH_2; + else if (vtr_op == L2_VTR_DISABLED + && unformat (input, "translate_pbb_stag %d", &outer_tag)) + vtr_op = L2_VTR_TRANSLATE_2_1; + else if (unformat (input, "dmac %U", unformat_ethernet_address, dmac)) + dmac_set = 1; + else if (unformat (input, "smac %U", unformat_ethernet_address, smac)) + smac_set = 1; + else if (unformat (input, "b_vlanid %d", &tmp)) + b_vlanid = tmp; + else if (unformat (input, "s_id %d", &s_id)) + ; + else + { + error = clib_error_return (0, + "expecting [disable | pop | push | translate_pbb_stag \n" + "dmac
smac
s_id [b_vlanid ]]"); + goto done; + } + } + + if ((vtr_op == L2_VTR_PUSH_2 || vtr_op == L2_VTR_TRANSLATE_2_1) + && (!dmac_set || !smac_set || s_id == ~0)) + { + error = clib_error_return (0, + "expecting dmac
smac
s_id [b_vlanid ]"); + goto done; + } + + if (l2pbb_configure + (vm, vnm, sw_if_index, vtr_op, dmac, smac, b_vlanid, s_id, outer_tag)) + { + error = + clib_error_return (0, + "pbb tag rewrite is not compatible with interface"); + goto done; + } + +done: + return error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (int_l2_pbb_vtr_cli, static) = { + .path = "set interface l2 pbb-tag-rewrite", + .short_help = "set interface l2 pbb-tag-rewrite [disable | pop | push | translate_pbb_stag dmac
smac
s_id [b_vlanid ]]", + .function = int_l2_pbb_vtr, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_vtr.h b/src/vnet/l2/l2_vtr.h new file mode 100644 index 00000000..893b2272 --- /dev/null +++ b/src/vnet/l2/l2_vtr.h @@ -0,0 +1,270 @@ +/* + * l2_vtr.h : layer 2 vlan tag rewrite processing + * + * Copyright (c) 2013 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_vnet_l2_vtr_h +#define included_vnet_l2_vtr_h + +#include +#include +#include +#include + +/* VTR config options for API and CLI support */ +typedef enum +{ + L2_VTR_DISABLED, + L2_VTR_PUSH_1, + L2_VTR_PUSH_2, + L2_VTR_POP_1, + L2_VTR_POP_2, + L2_VTR_TRANSLATE_1_1, + L2_VTR_TRANSLATE_1_2, + L2_VTR_TRANSLATE_2_1, + L2_VTR_TRANSLATE_2_2 +} l2_vtr_op_t; + +/** + * Per-interface vlan tag rewrite configuration + * There will be one instance of this struct for each sw_if_index + * for both input vtr and output vtr + */ +typedef struct +{ + union + { + /* + * Up to two vlan tags to push. + * if there is only one vlan tag to push, it is in tags[1]. + */ + ethernet_vlan_header_tv_t tags[2]; + u64 raw_tags; + }; + + union + { + struct + { + u8 push_bytes; /* number of bytes to push for up to 2 vlans (0,4,8) */ + u8 pop_bytes; /* number of bytes to pop for up to 2 vlans (0,4,8) */ + }; + u16 push_and_pop_bytes; /* if 0 then the feature is disabled */ + }; +} vtr_config_t; + + +/** + * Perform the configured tag rewrite on the packet. + * Return 0 if ok, 1 if packet should be dropped (e.g. tried to pop + * too many tags) + */ +always_inline u32 +l2_vtr_process (vlib_buffer_t * b0, vtr_config_t * config) +{ + u64 temp_8; + u32 temp_4; + u8 *eth; + + eth = vlib_buffer_get_current (b0); + + /* copy the 12B dmac and smac to a temporary location */ + temp_8 = *((u64 *) eth); + temp_4 = *((u32 *) (eth + 8)); + + /* adjust for popped tags */ + eth += config->pop_bytes; + + /* if not enough tags to pop then drop packet */ + if (PREDICT_FALSE ((vnet_buffer (b0)->l2.l2_len - 12) < config->pop_bytes)) + { + return 1; + } + + /* copy the 2 new tags to the start of the packet */ + *((u64 *) (eth + 12 - 8)) = config->raw_tags; + + /* TODO: set cos bits */ + + /* adjust for pushed tags: */ + eth -= config->push_bytes; + + /* copy the 12 dmac and smac back to the packet */ + *((u64 *) eth) = temp_8; + *((u32 *) (eth + 8)) = temp_4; + + /* Update l2_len */ + vnet_buffer (b0)->l2.l2_len += + (word) config->push_bytes - (word) config->pop_bytes; + + /* Update vlan tag count */ + ethernet_buffer_adjust_vlan_count_by_bytes (b0, + (word) config->push_bytes - + (word) config->pop_bytes); + + /* Update packet len */ + vlib_buffer_advance (b0, + (word) config->pop_bytes - (word) config->push_bytes); + + return 0; +} + + +/* + * Perform the egress pre-vlan tag rewrite EFP Filter check. + * The post-vlan tag rewrite check is a separate graph node. + * + * This check insures that a packet being output to an interface + * (before output vtr is performed) has vlan tags that match those + * on a packet received from that interface (after vtr has been performed). + * This means verifying that any tags pushed by input vtr are present + * on the packet. + * + * Return 0 if ok, 1 if packet should be dropped. + * This function should be passed the input vtr config for the interface. + */ +always_inline u8 +l2_efp_filter_process (vlib_buffer_t * b0, vtr_config_t * in_config) +{ + u8 *eth; + u64 packet_tags; + u64 tag_mask; + + eth = vlib_buffer_get_current (b0); + + /* + * If there are 2 tags pushed, they must match config->tags[0] and + * config->tags[1]. + * If there is one tag pushed, it must match config->tag[1]. + * If there are 0 tags pushed, the check passes. + */ + + /* mask for two vlan id and ethertypes, no cos bits */ + tag_mask = clib_net_to_host_u64 (0xFFFF0FFFFFFF0FFF); + /* mask for one vlan id and ethertype, no cos bits */ + tag_mask = + (in_config->push_bytes == + 4) ? clib_net_to_host_u64 (0xFFFF0FFF) : tag_mask; + /* mask for always match */ + tag_mask = (in_config->push_bytes == 0) ? 0 : tag_mask; + + /* + * Read 8B from the packet, getting the proper set of vlan tags + * For 0 push bytes, the address doesn't matter since the mask + * clears the data to 0. + */ + packet_tags = *((u64 *) (eth + 4 + in_config->push_bytes)); + + /* Check if the packet tags match the configured tags */ + return (packet_tags & tag_mask) != in_config->raw_tags; +} + +typedef struct +{ + union + { + ethernet_pbb_header_t macs_tags; + struct + { + u64 data1; + u64 data2; + u16 data3; + u32 data4; + } raw_data; + }; + union + { + struct + { + u8 push_bytes; /* number of bytes to push pbb tags */ + u8 pop_bytes; /* number of bytes to pop pbb tags */ + }; + u16 push_and_pop_bytes; /* if 0 then the feature is disabled */ + }; +} ptr_config_t; + +always_inline u32 +l2_pbb_process (vlib_buffer_t * b0, ptr_config_t * config) +{ + u8 *eth = vlib_buffer_get_current (b0); + + if (config->pop_bytes > 0) + { + ethernet_pbb_header_packed_t *ph = (ethernet_pbb_header_packed_t *) eth; + + // drop packet without PBB header or with wrong I-tag or B-tag + if (clib_net_to_host_u16 (ph->priority_dei_id) != + clib_net_to_host_u16 (config->macs_tags.priority_dei_id) + || clib_net_to_host_u32 (ph->priority_dei_uca_res_sid) != + clib_net_to_host_u32 (config->macs_tags.priority_dei_uca_res_sid)) + return 1; + + eth += config->pop_bytes; + } + + if (config->push_bytes > 0) + { + eth -= config->push_bytes; + // copy the B-DA (6B), B-SA (6B), B-TAG (4B), I-TAG (6B) + *((u64 *) eth) = config->raw_data.data1; + *((u64 *) (eth + 8)) = config->raw_data.data2; + *((u16 *) (eth + 16)) = config->raw_data.data3; + *((u32 *) (eth + 18)) = config->raw_data.data4; + } + + /* Update l2_len */ + vnet_buffer (b0)->l2.l2_len += + (word) config->push_bytes - (word) config->pop_bytes; + /* Update packet len */ + vlib_buffer_advance (b0, + (word) config->pop_bytes - (word) config->push_bytes); + + return 0; +} + +u32 l2pbb_configure (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, u32 sw_if_index, u32 vtr_op, + u8 * b_dmac, u8 * b_smac, + u16 b_vlanid, u32 i_sid, u16 vlan_outer_tag); + +/** + * Configure vtag tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 l2vtr_configure (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, + u32 sw_if_index, + u32 vtr_op, u32 push_dot1q, u32 vtr_tag1, u32 vtr_tag2); + +/** + * Get vtag tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 l2vtr_get (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, + u32 sw_if_index, + u32 * vtr_op, + u32 * push_dot1q, u32 * vtr_tag1, u32 * vtr_tag2); + +#endif /* included_vnet_l2_vtr_h */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_xcrw.c b/src/vnet/l2/l2_xcrw.c new file mode 100644 index 00000000..70610a85 --- /dev/null +++ b/src/vnet/l2/l2_xcrw.c @@ -0,0 +1,591 @@ +/* + * 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 + +/** + * @file + * General L2 / L3 cross-connect, used to set up + * "L2 interface <--> your-favorite-tunnel-encap" tunnels. + * + * We set up a typical L2 cross-connect or (future) bridge + * to hook L2 interface(s) up to the L3 stack in arbitrary ways. + * + * Each l2_xcrw adjacency specifies 3 things: + * + * 1. The next graph node (presumably in the L3 stack) to + * process the (L2 -> L3) packet + * + * 2. A new value for vnet_buffer(b)->sw_if_index[VLIB_TX] + * (i.e. a lookup FIB index), + * + * 3. A rewrite string to apply. + * + * Example: to cross-connect an L2 interface or (future) bridge + * to an mpls-o-gre tunnel, set up the L2 rewrite string as shown in + * mpls_gre_rewrite, and use "mpls-post-rewrite" to fix the + * GRE IP header checksum and length fields. + */ + +typedef struct +{ + u32 next_index; + u32 tx_fib_index; +} l2_xcrw_trace_t; + +/* packet trace format function */ +static u8 * +format_l2_xcrw_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + l2_xcrw_trace_t *t = va_arg (*args, l2_xcrw_trace_t *); + + s = format (s, "L2_XCRW: next index %d tx_fib_index %d", + t->next_index, t->tx_fib_index); + return s; +} + +l2_xcrw_main_t l2_xcrw_main; + +static vlib_node_registration_t l2_xcrw_node; + +static char *l2_xcrw_error_strings[] = { +#define _(sym,string) string, + foreach_l2_xcrw_error +#undef _ +}; + +static uword +l2_xcrw_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + l2_xcrw_next_t next_index; + l2_xcrw_main_t *xcm = &l2_xcrw_main; + vlib_node_t *n = vlib_get_node (vm, l2_xcrw_node.index); + u32 node_counter_base_index = n->error_heap_index; + vlib_error_main_t *em = &vm->error_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + u32 next0, next1; + u32 sw_if_index0, sw_if_index1; + l2_xcrw_adjacency_t *adj0, *adj1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + + adj0 = vec_elt_at_index (xcm->adj_by_sw_if_index, sw_if_index0); + adj1 = vec_elt_at_index (xcm->adj_by_sw_if_index, sw_if_index1); + + next0 = adj0->rewrite_header.next_index; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + adj0->rewrite_header.sw_if_index; + + next1 = adj1->rewrite_header.next_index; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = + adj1->rewrite_header.sw_if_index; + + em->counters[node_counter_base_index + next1]++; + + if (PREDICT_TRUE (next0 > 0)) + { + u8 *h0 = vlib_buffer_get_current (b0); + vnet_rewrite_one_header (adj0[0], h0, + adj0->rewrite_header.data_bytes); + vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes); + em->counters[node_counter_base_index + L2_XCRW_ERROR_FWD]++; + } + + if (PREDICT_TRUE (next1 > 0)) + { + u8 *h1 = vlib_buffer_get_current (b1); + vnet_rewrite_one_header (adj1[0], h1, + adj1->rewrite_header.data_bytes); + vlib_buffer_advance (b1, -adj1->rewrite_header.data_bytes); + em->counters[node_counter_base_index + L2_XCRW_ERROR_FWD]++; + } + + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_xcrw_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->tx_fib_index = adj0->rewrite_header.sw_if_index; + } + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b1->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_xcrw_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->next_index = next1; + t->tx_fib_index = adj1->rewrite_header.sw_if_index; + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0; + u32 sw_if_index0; + l2_xcrw_adjacency_t *adj0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + + adj0 = vec_elt_at_index (xcm->adj_by_sw_if_index, sw_if_index0); + + next0 = adj0->rewrite_header.next_index; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + adj0->rewrite_header.sw_if_index; + + if (PREDICT_TRUE (next0 > 0)) + { + u8 *h0 = vlib_buffer_get_current (b0); + vnet_rewrite_one_header (adj0[0], h0, + adj0->rewrite_header.data_bytes); + vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes); + em->counters[node_counter_base_index + L2_XCRW_ERROR_FWD]++; + } + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + l2_xcrw_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); + t->next_index = next0; + t->tx_fib_index = adj0->rewrite_header.sw_if_index; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (l2_xcrw_node, static) = { + .function = l2_xcrw_node_fn, + .name = "l2-xcrw", + .vector_size = sizeof (u32), + .format_trace = format_l2_xcrw_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(l2_xcrw_error_strings), + .error_strings = l2_xcrw_error_strings, + + .n_next_nodes = L2_XCRW_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [L2_XCRW_NEXT_DROP] = "error-drop", + }, +}; +/* *INDENT-ON* */ + +VLIB_NODE_FUNCTION_MULTIARCH (l2_xcrw_node, l2_xcrw_node_fn) + clib_error_t *l2_xcrw_init (vlib_main_t * vm) +{ + l2_xcrw_main_t *mp = &l2_xcrw_main; + + mp->vlib_main = vm; + mp->vnet_main = &vnet_main; + mp->tunnel_index_by_l2_sw_if_index = hash_create (0, sizeof (uword)); + + return 0; +} + +VLIB_INIT_FUNCTION (l2_xcrw_init); + +static uword +dummy_interface_tx (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + clib_warning ("you shouldn't be here, leaking buffers..."); + return frame->n_vectors; +} + +static u8 * +format_xcrw_name (u8 * s, va_list * args) +{ + u32 dev_instance = va_arg (*args, u32); + return format (s, "xcrw%d", dev_instance); +} + +/* *INDENT-OFF* */ +VNET_DEVICE_CLASS (xcrw_device_class,static) = { + .name = "Xcrw", + .format_device_name = format_xcrw_name, + .tx_function = dummy_interface_tx, +}; +/* *INDENT-ON* */ + +/* Create a sham tunnel interface and return its sw_if_index */ +static u32 +create_xcrw_interface (vlib_main_t * vm) +{ + vnet_main_t *vnm = vnet_get_main (); + static u32 instance; + u8 address[6]; + u32 hw_if_index; + vnet_hw_interface_t *hi; + u32 sw_if_index; + + /* mac address doesn't really matter */ + memset (address, 0, sizeof (address)); + address[2] = 0x12; + + /* can returns error iff phy != 0 */ + (void) ethernet_register_interface + (vnm, xcrw_device_class.index, instance++, address, &hw_if_index, + /* flag change */ 0); + + hi = vnet_get_hw_interface (vnm, hw_if_index); + sw_if_index = hi->sw_if_index; + vnet_sw_interface_set_flags (vnm, sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + + /* Output to the sham tunnel invokes the encap node */ + hi->output_node_index = l2_xcrw_node.index; + + return sw_if_index; +} + +int +vnet_configure_l2_xcrw (vlib_main_t * vm, vnet_main_t * vnm, + u32 l2_sw_if_index, u32 tx_fib_index, + u8 * rewrite, u32 next_node_index, int is_add) +{ + l2_xcrw_main_t *xcm = &l2_xcrw_main; + l2_xcrw_adjacency_t *a; + l2_xcrw_tunnel_t *t; + uword *p; + + if (is_add) + { + + pool_get (xcm->tunnels, t); + + /* No interface allocated? Do it. Otherwise, set admin up */ + if (t->tunnel_sw_if_index == 0) + t->tunnel_sw_if_index = create_xcrw_interface (vm); + else + vnet_sw_interface_set_flags (vnm, t->tunnel_sw_if_index, + VNET_SW_INTERFACE_FLAG_ADMIN_UP); + + t->l2_sw_if_index = l2_sw_if_index; + + vec_validate (xcm->adj_by_sw_if_index, t->l2_sw_if_index); + + a = vec_elt_at_index (xcm->adj_by_sw_if_index, t->l2_sw_if_index); + memset (a, 0, sizeof (*a)); + + a->rewrite_header.sw_if_index = tx_fib_index; + + /* + * Add or find a dynamic disposition for the successor node, + * e.g. so we can ship pkts to mpls_post_rewrite... + */ + a->rewrite_header.next_index = + vlib_node_add_next (vm, l2_xcrw_node.index, next_node_index); + + if (vec_len (rewrite)) + vnet_rewrite_set_data (a[0], rewrite, vec_len (rewrite)); + + set_int_l2_mode (vm, vnm, MODE_L2_XC, t->l2_sw_if_index, 0, 0, 0, + t->tunnel_sw_if_index); + hash_set (xcm->tunnel_index_by_l2_sw_if_index, + t->l2_sw_if_index, t - xcm->tunnels); + return 0; + } + else + { + p = hash_get (xcm->tunnel_index_by_l2_sw_if_index, l2_sw_if_index); + if (p == 0) + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + + t = pool_elt_at_index (xcm->tunnels, p[0]); + + a = vec_elt_at_index (xcm->adj_by_sw_if_index, t->l2_sw_if_index); + /* Reset adj to drop traffic */ + memset (a, 0, sizeof (*a)); + + set_int_l2_mode (vm, vnm, MODE_L3, t->l2_sw_if_index, 0, 0, 0, 0); + + vnet_sw_interface_set_flags (vnm, t->tunnel_sw_if_index, 0 /* down */ ); + + hash_unset (xcm->tunnel_index_by_l2_sw_if_index, l2_sw_if_index); + pool_put (xcm->tunnels, t); + } + return 0; +} + + +static clib_error_t * +set_l2_xcrw_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + int is_add = 1; + int is_ipv6 = 0; /* for fib id -> fib index mapping */ + u32 tx_fib_id = ~0; + u32 tx_fib_index = ~0; + u32 next_node_index = ~0; + u32 l2_sw_if_index; + u8 *rw = 0; + vnet_main_t *vnm = vnet_get_main (); + int rv; + + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + if (!unformat (line_input, "%U", + unformat_vnet_sw_interface, vnm, &l2_sw_if_index)) + return clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "next %U", + unformat_vlib_node, vm, &next_node_index)) + ; + else if (unformat (line_input, "tx-fib-id %d", &tx_fib_id)) + ; + else if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "ipv6")) + is_ipv6 = 1; + else if (unformat (line_input, "rw %U", unformat_hex_string, &rw)); + else + break; + } + + if (next_node_index == ~0) + return clib_error_return (0, "next node not specified"); + + if (tx_fib_id != ~0) + { + uword *p; + + if (is_ipv6) + p = hash_get (ip6_main.fib_index_by_table_id, tx_fib_id); + else + p = hash_get (ip4_main.fib_index_by_table_id, tx_fib_id); + + if (p == 0) + return clib_error_return (0, "nonexistent tx_fib_id %d", tx_fib_id); + + tx_fib_index = p[0]; + } + + rv = vnet_configure_l2_xcrw (vm, vnm, l2_sw_if_index, tx_fib_index, + rw, next_node_index, is_add); + + switch (rv) + { + + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return (0, "%U not cross-connected", + format_vnet_sw_if_index_name, + vnm, l2_sw_if_index); + default: + return clib_error_return (0, "vnet_configure_l2_xcrw returned %d", rv); + } + + vec_free (rw); + + return 0; +} + +/*? + * Add or delete a Layer 2 to Layer 3 rewrite cross-connect. This is + * used to hook Layer 2 interface(s) up to the Layer 3 stack in + * arbitrary ways. For example, cross-connect an L2 interface or + * (future) bridge to an mpls-o-gre tunnel. Set up the L2 rewrite + * string as shown in mpls_gre_rewrite, and use \"mpls-post-rewrite\" + * to fix the GRE IP header checksum and length fields. + * + * @cliexpar + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_l2_xcrw_command, static) = { + .path = "set interface l2 xcrw", + .short_help = + "set interface l2 xcrw next \n" + " [del] [tx-fib-id ] [ipv6] rw ", + .function = set_l2_xcrw_command_fn, +}; +/* *INDENT-ON* */ + +static u8 * +format_l2xcrw (u8 * s, va_list * args) +{ + vnet_main_t *vnm = va_arg (*args, vnet_main_t *); + l2_xcrw_tunnel_t *t = va_arg (*args, l2_xcrw_tunnel_t *); + l2_xcrw_main_t *xcm = &l2_xcrw_main; + vlib_main_t *vm = vlib_get_main (); + l2_xcrw_adjacency_t *a; + u8 *rewrite_string; + + if (t == 0) + { + s = format (s, "%-25s%s", "L2 interface", "Tunnel Details"); + return s; + } + + s = format (s, "%-25U %U ", + format_vnet_sw_if_index_name, vnm, t->l2_sw_if_index, + format_vnet_sw_if_index_name, vnm, t->tunnel_sw_if_index); + + a = vec_elt_at_index (xcm->adj_by_sw_if_index, t->l2_sw_if_index); + + s = format (s, "next %U ", + format_vlib_next_node_name, vm, l2_xcrw_node.index, + a->rewrite_header.next_index); + + if (a->rewrite_header.sw_if_index != ~0) + s = format (s, "tx fib index %d ", a->rewrite_header.sw_if_index); + + if (a->rewrite_header.data_bytes) + { + rewrite_string = (u8 *) (a + 1); + rewrite_string -= a->rewrite_header.data_bytes; + s = format (s, "rewrite data: %U ", + format_hex_bytes, rewrite_string, + a->rewrite_header.data_bytes); + } + + s = format (s, "\n"); + + return s; +} + + +static clib_error_t * +show_l2xcrw_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + l2_xcrw_main_t *xcm = &l2_xcrw_main; + l2_xcrw_tunnel_t *t; + + if (pool_elts (xcm->tunnels) == 0) + { + vlib_cli_output (vm, "No L2 / L3 rewrite cross-connects configured"); + return 0; + } + + vlib_cli_output (vm, "%U", format_l2xcrw, 0, 0); + + /* *INDENT-OFF* */ + pool_foreach (t, xcm->tunnels, + ({ + vlib_cli_output (vm, "%U", format_l2xcrw, vnm, t); + })); + /* *INDENT-ON* */ + + return 0; +} + +/*? + * Display a Layer 2 to Layer 3 rewrite cross-connect. This is used to + * hook Layer 2 interface(s) up to the Layer 3 stack in arbitrary ways. + * + * @todo This is incomplete. This needs a detailed description and a + * practical example. +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_l2xcrw_command, static) = { + .path = "show l2xcrw", + .short_help = "show l2xcrw", + .function = show_l2xcrw_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_xcrw.h b/src/vnet/l2/l2_xcrw.h new file mode 100644 index 00000000..ca80aae9 --- /dev/null +++ b/src/vnet/l2/l2_xcrw.h @@ -0,0 +1,91 @@ +/* + * 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_l2_xcrw_h__ +#define __included_l2_xcrw_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + /* + * Let: rewrite_header.sw_if_index = tx_fib_index or ~0. + * rewrite_header.next_index = L2_XCRW_NEXT_XXX + */ + vnet_declare_rewrite (VLIB_BUFFER_PRE_DATA_SIZE); +} l2_xcrw_adjacency_t; + +typedef struct +{ + /* L2 interface */ + u32 l2_sw_if_index; + + /* Tunnel interface */ + u32 tunnel_sw_if_index; /* This field remains set in freed pool elts */ + +} l2_xcrw_tunnel_t; + +typedef struct +{ + u32 cached_next_index; + + /* Vector of cross-connect rewrites */ + l2_xcrw_adjacency_t *adj_by_sw_if_index; + + /* Pool of xcrw tunnels */ + l2_xcrw_tunnel_t *tunnels; + + /* Tunnel index by tunnel sw_if_index */ + uword *tunnel_index_by_l2_sw_if_index; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2_xcrw_main_t; + +typedef enum +{ + L2_XCRW_NEXT_DROP, + L2_XCRW_N_NEXT, +} l2_xcrw_next_t; + +#define foreach_l2_xcrw_error \ +_(DROP, "Packets dropped") \ +_(FWD, "Packets forwarded") + +typedef enum +{ +#define _(sym,str) L2_XCRW_ERROR_##sym, + foreach_l2_xcrw_error +#undef _ + L2_XCRW_N_ERROR, +} l2_xcrw_error_t; + +#endif /* __included_l2_xcrw_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg From 0f971d8c22adf89d3f8592ac0d207727f2b1a23a Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Tue, 3 Jan 2017 10:48:54 +0100 Subject: API refactoring : l2, mpls, sr Change-Id: Ic5f273dae607a1d3902489e65734c76f027dc30f Signed-off-by: Pavel Kotucek --- src/vnet.am | 15 +- src/vnet/l2/l2.api | 229 +++++++++++ src/vnet/l2/l2_api.c | 373 +++++++++++++++++- src/vnet/mpls/mpls.api | 246 ++++++++++++ src/vnet/mpls/mpls_api.c | 497 ++++++++++++++++++++++++ src/vnet/sr/sr.api | 119 ++++++ src/vnet/sr/sr_api.c | 279 ++++++++++++++ src/vnet/vnet_all_api_h.h | 2 + src/vpp/api/api.c | 947 +--------------------------------------------- src/vpp/api/vpe.api | 574 +--------------------------- 10 files changed, 1770 insertions(+), 1511 deletions(-) create mode 100644 src/vnet/mpls/mpls.api create mode 100644 src/vnet/mpls/mpls_api.c create mode 100644 src/vnet/sr/sr.api create mode 100644 src/vnet/sr/sr_api.c (limited to 'src/vnet/l2') diff --git a/src/vnet.am b/src/vnet.am index bc0820a3..bca56227 100644 --- a/src/vnet.am +++ b/src/vnet.am @@ -498,15 +498,18 @@ libvnet_la_SOURCES += \ vnet/mpls/node.c \ vnet/mpls/interface.c \ vnet/mpls/mpls_tunnel.c \ - vnet/mpls/pg.c + vnet/mpls/pg.c \ + vnet/mpls/mpls_api.c nobase_include_HEADERS += \ vnet/mpls/mpls.h \ vnet/mpls/mpls_types.h \ vnet/mpls/mpls_tunnel.h \ vnet/mpls/packet.h \ - vnet/mpls/error.def + vnet/mpls/error.def \ + vnet/mpls/mpls.api.h +API_FILES += vnet/mpls/mpls.api ######################################## # Tunnel protocol: vxlan-gpe @@ -666,13 +669,17 @@ nobase_include_HEADERS += \ if WITH_IPV6SR libvnet_la_SOURCES += \ vnet/sr/sr.c \ - vnet/sr/sr_replicate.c + vnet/sr/sr_replicate.c \ + vnet/sr/sr_api.c endif nobase_include_HEADERS += \ vnet/sr/sr_packet.h \ vnet/sr/sr_error.def \ - vnet/sr/sr.h + vnet/sr/sr.h \ + vnet/sr/sr.api.h + +API_FILES += vnet/sr/sr.api ######################################## # DHCPv6 proxy diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 5fce7944..5b24f259 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -36,3 +36,232 @@ define l2_xconnect_dump u32 context; }; +/** \brief l2 fib table entry structure + @param bd_id - the l2 fib / bridge domain table id + @param mac - the entry's mac address + @param sw_if_index - index of the interface + @param static_mac - the entry is statically configured. + @param filter_mac - the entry is a mac filter entry. + @param bvi_mac - the mac address is a bridge virtual interface +*/ +define l2_fib_table_entry +{ + u32 context; + u32 bd_id; + u64 mac; + u32 sw_if_index; + u8 static_mac; + u8 filter_mac; + u8 bvi_mac; +}; + +/** \brief Dump l2 fib (aka bridge domain) table + @param client_index - opaque cookie to identify the sender + @param bd_id - the l2 fib / bridge domain table identifier +*/ +define l2_fib_table_dump +{ + u32 client_index; + u32 context; + u32 bd_id; +}; + +/** \brief L2 fib clear table request, clear all mac entries in the l2 fib + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define l2_fib_clear_table +{ + u32 client_index; + u32 context; +}; + +/** \brief L2 fib clear table response + @param context - sender context, to match reply w/ request + @param retval - return code for the request +*/ +define l2_fib_clear_table_reply +{ + u32 context; + i32 retval; +}; + +/** \brief L2 FIB add entry request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mac - the entry's mac address + @param bd_id - the entry's bridge domain id + @param sw_if_index - the interface + @param is_add - If non zero add the entry, else delete it + @param static_mac - + @param filter_mac - +*/ +define l2fib_add_del +{ + u32 client_index; + u32 context; + u64 mac; + u32 bd_id; + u32 sw_if_index; + u8 is_add; + u8 static_mac; + u8 filter_mac; + u8 bvi_mac; +}; + +/** \brief L2 FIB add entry response + @param context - sender context, to match reply w/ request + @param retval - return code for the add l2fib entry request +*/ +define l2fib_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Set L2 flags request !!! TODO - need more info, feature bits in l2_input.h + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface + @param is_set - if non-zero, set the bits, else clear them + @param feature_bitmap - non-zero bits to set or clear +*/ +define l2_flags +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u8 is_set; + u32 feature_bitmap; +}; + +/** \brief Set L2 bits response + @param context - sender context, to match reply w/ request + @param retval - return code for the set l2 bits request +*/ +define l2_flags_reply +{ + u32 context; + i32 retval; + u32 resulting_feature_bitmap; +}; + +/** \brief L2 bridge domain add or delete request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the bridge domain to create + @param flood - enable/disable bcast/mcast flooding in the bd + @param uu_flood - enable/disable uknown unicast flood in the bd + @param forward - enable/disable forwarding on all interfaces in the bd + @param learn - enable/disable learning on all interfaces in the bd + @param arp_term - enable/disable arp termination in the bd + @param mac_age - mac aging time in min, 0 for disabled + @param is_add - add or delete flag +*/ +define bridge_domain_add_del +{ + u32 client_index; + u32 context; + u32 bd_id; + u8 flood; + u8 uu_flood; + u8 forward; + u8 learn; + u8 arp_term; + u8 mac_age; + u8 is_add; +}; + +/** \brief L2 bridge domain add or delete response + @param context - sender context, to match reply w/ request + @param retval - return code for the set bridge flags request +*/ +define bridge_domain_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief L2 bridge domain request operational state details + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the bridge domain id desired or ~0 to request all bds +*/ +define bridge_domain_dump +{ + u32 client_index; + u32 context; + u32 bd_id; +}; + +/** \brief L2 bridge domain operational state response + @param bd_id - the bridge domain id + @param flood - bcast/mcast flooding state on all interfaces in the bd + @param uu_flood - uknown unicast flooding state on all interfaces in the bd + @param forward - forwarding state on all interfaces in the bd + @param learn - learning state on all interfaces in the bd + @param arp_term - arp termination state on all interfaces in the bd + @param mac_age - mac aging time in min, 0 for disabled + @param n_sw_ifs - number of sw_if_index's in the domain +*/ +define bridge_domain_details +{ + u32 context; + u32 bd_id; + u8 flood; + u8 uu_flood; + u8 forward; + u8 learn; + u8 arp_term; + u8 mac_age; + u32 bvi_sw_if_index; + u32 n_sw_ifs; +}; + +/** \brief L2 bridge domain sw interface operational state response + @param bd_id - the bridge domain id + @param sw_if_index - sw_if_index in the domain + @param shg - split horizon group for the interface +*/ +define bridge_domain_sw_if_details +{ + u32 context; + u32 bd_id; + u32 sw_if_index; + u8 shg; +}; + +/** \brief Set bridge flags (such as L2_LEARN, L2_FWD, L2_FLOOD, + L2_UU_FLOOD, or L2_ARP_TERM) request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the bridge domain to set the flags for + @param is_set - if non-zero, set the flags, else clear them + @param feature_bitmap - bits that are non-zero to set or clear +*/ +define bridge_flags +{ + u32 client_index; + u32 context; + u32 bd_id; + u8 is_set; + u32 feature_bitmap; +}; + +/** \brief Set bridge flags response + @param context - sender context, to match reply w/ request + @param retval - return code for the set bridge flags request + @param resulting_feature_bitmap - the feature bitmap value after the request is implemented +*/ +define bridge_flags_reply +{ + u32 context; + i32 retval; + u32 resulting_feature_bitmap; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index ca4f593f..ef33509c 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -42,8 +43,18 @@ #include -#define foreach_vpe_api_msg \ -_(L2_XCONNECT_DUMP, l2_xconnect_dump) +#define foreach_vpe_api_msg \ +_(L2_XCONNECT_DUMP, l2_xconnect_dump) \ +_(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ +_(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ +_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ +_(L2FIB_ADD_DEL, l2fib_add_del) \ +_(L2_FLAGS, l2_flags) \ +_(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ +_(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ +_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ +_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ +_(BRIDGE_FLAGS, bridge_flags) static void send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context, @@ -86,9 +97,365 @@ vl_api_l2_xconnect_dump_t_handler (vl_api_l2_xconnect_dump_t * mp) /* *INDENT-ON* */ } +static void +vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp) +{ + int rv = 0; + vl_api_l2_fib_clear_table_reply_t *rmp; + + /* DAW-FIXME: This API should only clear non-static l2fib entries, but + * that is not currently implemented. When that TODO is fixed + * this call should be changed to pass 1 instead of 0. + */ + l2fib_clear_table (0); + + REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY); +} + +static void +send_l2fib_table_entry (vpe_api_main_t * am, + unix_shared_memory_queue_t * q, + l2fib_entry_key_t * l2fe_key, + l2fib_entry_result_t * l2fe_res, u32 context) +{ + vl_api_l2_fib_table_entry_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_ENTRY); + + mp->bd_id = + ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id); + + mp->mac = l2fib_make_key (l2fe_key->fields.mac, 0); + mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index); + mp->static_mac = l2fe_res->fields.static_mac; + mp->filter_mac = l2fe_res->fields.filter; + mp->bvi_mac = l2fe_res->fields.bvi; + mp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_l2_fib_table_entry_t_handler (vl_api_l2_fib_table_entry_t * mp) +{ + clib_warning ("BUG"); +} + +static void +vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp) +{ + vpe_api_main_t *am = &vpe_api_main; + bd_main_t *bdm = &bd_main; + l2fib_entry_key_t *l2fe_key = NULL; + l2fib_entry_result_t *l2fe_res = NULL; + u32 ni, bd_id = ntohl (mp->bd_id); + u32 bd_index; + unix_shared_memory_queue_t *q; + uword *p; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + /* see l2fib_table_dump: ~0 means "any" */ + if (bd_id == ~0) + bd_index = ~0; + else + { + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + return; + + bd_index = p[0]; + } + + l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res); + + vec_foreach_index (ni, l2fe_key) + { + send_l2fib_table_entry (am, q, vec_elt_at_index (l2fe_key, ni), + vec_elt_at_index (l2fe_res, ni), mp->context); + } + vec_free (l2fe_key); + vec_free (l2fe_res); +} + +static void +vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) +{ + bd_main_t *bdm = &bd_main; + l2input_main_t *l2im = &l2input_main; + vl_api_l2fib_add_del_reply_t *rmp; + int rv = 0; + u64 mac = 0; + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 bd_id = ntohl (mp->bd_id); + u32 bd_index; + u32 static_mac; + u32 filter_mac; + u32 bvi_mac; + uword *p; + + mac = mp->mac; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (!p) + { + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto bad_sw_if_index; + } + bd_index = p[0]; + + if (mp->is_add) + { + filter_mac = mp->filter_mac ? 1 : 0; + if (filter_mac == 0) + { + VALIDATE_SW_IF_INDEX (mp); + if (vec_len (l2im->configs) <= sw_if_index) + { + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + goto bad_sw_if_index; + } + else + { + l2_input_config_t *config; + config = vec_elt_at_index (l2im->configs, sw_if_index); + if (config->bridge == 0) + { + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; + goto bad_sw_if_index; + } + } + } + static_mac = mp->static_mac ? 1 : 0; + bvi_mac = mp->bvi_mac ? 1 : 0; + l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac, + bvi_mac); + } + else + { + l2fib_del_entry (mac, bd_index); + } + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY); +} + +static void +vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) +{ + vl_api_l2_flags_reply_t *rmp; + int rv = 0; + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 flags = ntohl (mp->feature_bitmap); + u32 rbm = 0; + + VALIDATE_SW_IF_INDEX (mp); + +#define _(a,b) \ + if (flags & L2INPUT_FEAT_ ## a) \ + rbm = l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ ## a, mp->is_set); + foreach_l2input_feat; +#undef _ + + BAD_SW_IF_INDEX_LABEL; + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_L2_FLAGS_REPLY, + ({ + rmp->resulting_feature_bitmap = ntohl(rbm); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + bd_main_t *bdm = &bd_main; + vl_api_bridge_domain_add_del_reply_t *rmp; + int rv = 0; + u32 enable_flags = 0, disable_flags = 0; + u32 bd_id = ntohl (mp->bd_id); + u32 bd_index; + + if (mp->is_add) + { + bd_index = bd_find_or_add_bd_index (bdm, bd_id); + + if (mp->flood) + enable_flags |= L2_FLOOD; + else + disable_flags |= L2_FLOOD; + + if (mp->uu_flood) + enable_flags |= L2_UU_FLOOD; + else + disable_flags |= L2_UU_FLOOD; + + if (mp->forward) + enable_flags |= L2_FWD; + else + disable_flags |= L2_FWD; + + if (mp->arp_term) + enable_flags |= L2_ARP_TERM; + else + disable_flags |= L2_ARP_TERM; + + if (mp->learn) + enable_flags |= L2_LEARN; + else + disable_flags |= L2_LEARN; + + if (enable_flags) + bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); + + if (disable_flags) + bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); + + bd_set_mac_age (vm, bd_index, mp->mac_age); + } + else + rv = bd_delete_bd_index (bdm, bd_id); + + REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); +} + +static void +vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void + vl_api_bridge_domain_sw_if_details_t_handler + (vl_api_bridge_domain_sw_if_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void +send_bridge_domain_details (unix_shared_memory_queue_t * q, + l2_bridge_domain_t * bd_config, + u32 n_sw_ifs, u32 context) +{ + vl_api_bridge_domain_details_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_DETAILS); + mp->bd_id = ntohl (bd_config->bd_id); + mp->flood = bd_feature_flood (bd_config); + mp->uu_flood = bd_feature_uu_flood (bd_config); + mp->forward = bd_feature_forward (bd_config); + mp->learn = bd_feature_learn (bd_config); + mp->arp_term = bd_feature_arp_term (bd_config); + mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index); + mp->mac_age = bd_config->mac_age; + mp->n_sw_ifs = ntohl (n_sw_ifs); + mp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +send_bd_sw_if_details (l2input_main_t * l2im, + unix_shared_memory_queue_t * q, + l2_flood_member_t * member, u32 bd_id, u32 context) +{ + vl_api_bridge_domain_sw_if_details_t *mp; + l2_input_config_t *input_cfg; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_SW_IF_DETAILS); + mp->bd_id = ntohl (bd_id); + mp->sw_if_index = ntohl (member->sw_if_index); + input_cfg = vec_elt_at_index (l2im->configs, member->sw_if_index); + mp->shg = input_cfg->shg; + mp->context = context; + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) +{ + bd_main_t *bdm = &bd_main; + l2input_main_t *l2im = &l2input_main; + unix_shared_memory_queue_t *q; + l2_bridge_domain_t *bd_config; + u32 bd_id, bd_index; + u32 end; + + q = vl_api_client_index_to_input_queue (mp->client_index); + + if (q == 0) + return; + + bd_id = ntohl (mp->bd_id); + + bd_index = (bd_id == ~0) ? 0 : bd_find_or_add_bd_index (bdm, bd_id); + end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; + for (; bd_index < end; bd_index++) + { + bd_config = l2input_bd_config_from_index (l2im, bd_index); + /* skip dummy bd_id 0 */ + if (bd_config && (bd_config->bd_id > 0)) + { + u32 n_sw_ifs; + l2_flood_member_t *m; + + n_sw_ifs = vec_len (bd_config->members); + send_bridge_domain_details (q, bd_config, n_sw_ifs, mp->context); + + vec_foreach (m, bd_config->members) + { + send_bd_sw_if_details (l2im, q, m, bd_config->bd_id, mp->context); + } + } + } +} + +static void +vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + bd_main_t *bdm = &bd_main; + vl_api_bridge_flags_reply_t *rmp; + int rv = 0; + u32 bd_id = ntohl (mp->bd_id); + u32 bd_index; + u32 flags = ntohl (mp->feature_bitmap); + uword *p; + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + { + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; + } + + bd_index = p[0]; + + bd_set_flags (vm, bd_index, flags, mp->is_set); + +out: + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY, + ({ + rmp->resulting_feature_bitmap = ntohl(flags); + })); + /* *INDENT-ON* */ +} /* - * vpe_api_hookup + * l2_api_hookup * Add vpe's API message handlers to the table. * vlib has alread mapped shared memory and * added the client registration handlers. diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api new file mode 100644 index 00000000..2e3bfaf5 --- /dev/null +++ b/src/vnet/mpls/mpls.api @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2015-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. + */ + +/** \brief Bind/Unbind an MPLS local label to an IP prefix. i.e. create + a per-prefix label entry. + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mb_mpls_table_id - The MPLS table-id the MPLS entry will be added in + @param mb_label - The MPLS label value to bind + @param mb_ip_table_id - The IP table-id of the IP prefix to bind to. + @param mb_create_table_if_needed - Create either/both tables if required. + @param mb_is_bind - Bind or unbind + @param mb_is_ip4 - The prefix to bind to is IPv4 + @param mb_address_length - Length of IP prefix + @param mb_address[16] - IP prefix/ +*/ +define mpls_ip_bind_unbind +{ + u32 client_index; + u32 context; + u32 mb_mpls_table_id; + u32 mb_label; + u32 mb_ip_table_id; + u8 mb_create_table_if_needed; + u8 mb_is_bind; + u8 mb_is_ip4; + u8 mb_address_length; + u8 mb_address[16]; +}; + +/** \brief Reply for MPLS IP bind/unbind request + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define mpls_ip_bind_unbind_reply +{ + u32 context; + i32 retval; +}; + +/** \brief MPLS tunnel Add / del route + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mt_is_add - Is this a route add or delete + @param mt_sw_if_index - The SW interface index of the tunnel to delete + @param mt_next_hop_proto_is_ip4 - The next-hop is IPV4 + @param mt_next_hop_weight - The weight, for UCMP + @param mt_next_hop[16] - the nextop address + @param mt_next_hop_sw_if_index - the next-hop SW interface + @param mt_next_hop_table_id - the next-hop table-id (if appropriate) + @param mt_next_hop_n_out_labels - the number of next-hop output labels + @param mt_next_hop_out_label_stack - the next-hop output label stack, outer most first +*/ +define mpls_tunnel_add_del +{ + u32 client_index; + u32 context; + u32 mt_sw_if_index; + u8 mt_is_add; + u8 mt_l2_only; + u8 mt_next_hop_proto_is_ip4; + u8 mt_next_hop_weight; + u8 mt_next_hop[16]; + u8 mt_next_hop_n_out_labels; + u32 mt_next_hop_sw_if_index; + u32 mt_next_hop_table_id; + u32 mt_next_hop_out_label_stack[mt_next_hop_n_out_labels]; +}; + +/** \brief Reply for MPLS tunnel add / del request + @param context - returned sender context, to match reply w/ request + @param retval - return code + @param sw_if_index - SW interface index of the tunnel created +*/ +define mpls_tunnel_add_del_reply +{ + u32 context; + i32 retval; + u32 sw_if_index; +}; + +/** \brief Dump mpls eth tunnel table + @param client_index - opaque cookie to identify the sender + @param tunnel_index - eth tunnel identifier or -1 in case of all tunnels +*/ +define mpls_tunnel_dump +{ + u32 client_index; + u32 context; + i32 tunnel_index; +}; + +/** \brief mpls eth tunnel operational state response + @param tunnel_index - eth tunnel identifier + @param intfc_address - interface ipv4 addr + @param mask_width - interface ipv4 addr mask + @param hw_if_index - interface id + @param l2_only - + @param tunnel_dst_mac - + @param tx_sw_if_index - + @param encap_index - reference to mpls label table + @param nlabels - number of resolved labels + @param labels - resolved labels +*/ +define mpls_tunnel_details +{ + u32 context; + u32 tunnel_index; + u8 mt_l2_only; + u8 mt_sw_if_index; + u8 mt_next_hop_proto_is_ip4; + u8 mt_next_hop[16]; + u32 mt_next_hop_sw_if_index; + u32 mt_next_hop_table_id; + u32 mt_next_hop_n_labels; + u32 mt_next_hop_out_labels[mt_next_hop_n_labels]; +}; + +/** \brief MPLS Route Add / del route + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mr_label - The MPLS label value + @param mr_eos - The End of stack bit + @param mr_table_id - The MPLS table-id the route is added in + @param mr_classify_table_index - If this is a classify route, + this is the classify table index + @param mr_create_table_if_needed - If the MPLS or IP tables do not exist, + create them + @param mr_is_add - Is this a route add or delete + @param mr_is_classify - Is this route result a classify + @param mr_is_multipath - Is this route update a multipath - i.e. is this + a path addition to an existing route + @param mr_is_resolve_host - Recurse resolution constraint via a host prefix + @param mr_is_resolve_attached - Recurse resolution constraint via attached prefix + @param mr_next_hop_proto_is_ip4 - The next-hop is IPV4 + @param mr_next_hop_weight - The weight, for UCMP + @param mr_next_hop[16] - the nextop address + @param mr_next_hop_sw_if_index - the next-hop SW interface + @param mr_next_hop_table_id - the next-hop table-id (if appropriate) + @param mr_next_hop_n_out_labels - the number of labels in the label stack + @param mr_next_hop_out_label_stack - the next-hop output label stack, outer most first + @param next_hop_via_label - The next-hop is a resolved via a local label +*/ +define mpls_route_add_del +{ + u32 client_index; + u32 context; + u32 mr_label; + u8 mr_eos; + u32 mr_table_id; + u32 mr_classify_table_index; + u8 mr_create_table_if_needed; + u8 mr_is_add; + u8 mr_is_classify; + u8 mr_is_multipath; + u8 mr_is_resolve_host; + u8 mr_is_resolve_attached; + u8 mr_next_hop_proto_is_ip4; + u8 mr_next_hop_weight; + u8 mr_next_hop[16]; + u8 mr_next_hop_n_out_labels; + u32 mr_next_hop_sw_if_index; + u32 mr_next_hop_table_id; + u32 mr_next_hop_via_label; + u32 mr_next_hop_out_label_stack[mr_next_hop_n_out_labels]; +}; + +/** \brief Reply for MPLS route add / del request + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define mpls_route_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief FIB path + @param sw_if_index - index of the interface + @param weight - The weight, for UCMP + @param is_local - local if non-zero, else remote + @param is_drop - Drop the packet + @param is_unreach - Drop the packet and rate limit send ICMP unreachable + @param is_prohibit - Drop the packet and rate limit send ICMP prohibited + @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 + @param next_hop[16] - the next hop address + + WARNING: this type is replicated, pending cleanup completion + +*/ +typeonly manual_print manual_endian define fib_path2 +{ + u32 sw_if_index; + u32 weight; + u8 is_local; + u8 is_drop; + u8 is_unreach; + u8 is_prohibit; + u8 afi; + u8 next_hop[16]; +}; + +/** \brief Dump MPLS fib table + @param client_index - opaque cookie to identify the sender +*/ +define mpls_fib_dump +{ + u32 client_index; + u32 context; +}; + +/** \brief mpls FIB table response + @param table_id - MPLS fib table id + @param s_bit - End-of-stack bit + @param label - MPLS label value + @param count - the number of fib_path in path + @param path - array of of fib_path structures +*/ +manual_endian manual_print define mpls_fib_details +{ + u32 context; + u32 table_id; + u8 eos_bit; + u32 label; + u32 count; + vl_api_fib_path2_t path[count]; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ + \ No newline at end of file diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c new file mode 100644 index 00000000..ebbeba69 --- /dev/null +++ b/src/vnet/mpls/mpls_api.c @@ -0,0 +1,497 @@ +/* + *------------------------------------------------------------------ + * mpls_api.c - mpls api + * + * 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 +#include +#include +#include +#include +#include + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +#include + +#define foreach_vpe_api_msg \ +_(MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind) \ +_(MPLS_ROUTE_ADD_DEL, mpls_route_add_del) \ +_(MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del) \ +_(MPLS_TUNNEL_DUMP, mpls_tunnel_dump) \ +_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ +_(MPLS_FIB_DUMP, mpls_fib_dump) \ +_(MPLS_FIB_DETAILS, mpls_fib_details) + +extern void stats_dslock_with_hint (int hint, int tag); +extern void stats_dsunlock (void); + +static int +mpls_ip_bind_unbind_handler (vnet_main_t * vnm, + vl_api_mpls_ip_bind_unbind_t * mp) +{ + u32 mpls_fib_index, ip_fib_index; + + mpls_fib_index = + fib_table_find (FIB_PROTOCOL_MPLS, ntohl (mp->mb_mpls_table_id)); + + if (~0 == mpls_fib_index) + { + if (mp->mb_create_table_if_needed) + { + mpls_fib_index = + fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS, + ntohl (mp->mb_mpls_table_id)); + } + else + return VNET_API_ERROR_NO_SUCH_FIB; + } + + ip_fib_index = fib_table_find ((mp->mb_is_ip4 ? + FIB_PROTOCOL_IP4 : + FIB_PROTOCOL_IP6), + ntohl (mp->mb_ip_table_id)); + if (~0 == ip_fib_index) + return VNET_API_ERROR_NO_SUCH_FIB; + + fib_prefix_t pfx = { + .fp_len = mp->mb_address_length, + }; + + if (mp->mb_is_ip4) + { + pfx.fp_proto = FIB_PROTOCOL_IP4; + clib_memcpy (&pfx.fp_addr.ip4, mp->mb_address, + sizeof (pfx.fp_addr.ip4)); + } + else + { + pfx.fp_proto = FIB_PROTOCOL_IP6; + clib_memcpy (&pfx.fp_addr.ip6, mp->mb_address, + sizeof (pfx.fp_addr.ip6)); + } + + if (mp->mb_is_bind) + fib_table_entry_local_label_add (ip_fib_index, &pfx, + ntohl (mp->mb_label)); + else + fib_table_entry_local_label_remove (ip_fib_index, &pfx, + ntohl (mp->mb_label)); + + return (0); +} + +void +vl_api_mpls_ip_bind_unbind_t_handler (vl_api_mpls_ip_bind_unbind_t * mp) +{ + vl_api_mpls_ip_bind_unbind_reply_t *rmp; + vnet_main_t *vnm; + int rv; + + vnm = vnet_get_main (); + vnm->api_errno = 0; + + rv = mpls_ip_bind_unbind_handler (vnm, mp); + rv = (rv == 0) ? vnm->api_errno : rv; + + REPLY_MACRO (VL_API_MPLS_IP_BIND_UNBIND_REPLY); +} + +static int +mpls_route_add_del_t_handler (vnet_main_t * vnm, + vl_api_mpls_route_add_del_t * mp) +{ + u32 fib_index, next_hop_fib_index; + mpls_label_t *label_stack = NULL; + int rv, ii, n_labels;; + + fib_prefix_t pfx = { + .fp_len = 21, + .fp_proto = FIB_PROTOCOL_MPLS, + .fp_eos = mp->mr_eos, + .fp_label = ntohl (mp->mr_label), + }; + if (pfx.fp_eos) + { + if (mp->mr_next_hop_proto_is_ip4) + { + pfx.fp_payload_proto = DPO_PROTO_IP4; + } + else + { + pfx.fp_payload_proto = DPO_PROTO_IP6; + } + } + else + { + pfx.fp_payload_proto = DPO_PROTO_MPLS; + } + + rv = add_del_route_check (FIB_PROTOCOL_MPLS, + mp->mr_table_id, + mp->mr_next_hop_sw_if_index, + dpo_proto_to_fib (pfx.fp_payload_proto), + mp->mr_next_hop_table_id, + mp->mr_create_table_if_needed, + &fib_index, &next_hop_fib_index); + + if (0 != rv) + return (rv); + + ip46_address_t nh; + memset (&nh, 0, sizeof (nh)); + + if (mp->mr_next_hop_proto_is_ip4) + memcpy (&nh.ip4, mp->mr_next_hop, sizeof (nh.ip4)); + else + memcpy (&nh.ip6, mp->mr_next_hop, sizeof (nh.ip6)); + + n_labels = mp->mr_next_hop_n_out_labels; + if (n_labels == 0) + ; + else if (1 == n_labels) + vec_add1 (label_stack, ntohl (mp->mr_next_hop_out_label_stack[0])); + else + { + vec_validate (label_stack, n_labels - 1); + for (ii = 0; ii < n_labels; ii++) + label_stack[ii] = ntohl (mp->mr_next_hop_out_label_stack[ii]); + } + + return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add, 0, // mp->is_drop, + 0, // mp->is_unreach, + 0, // mp->is_prohibit, + 0, // mp->is_local, + mp->mr_is_classify, + mp->mr_classify_table_index, + mp->mr_is_resolve_host, + mp->mr_is_resolve_attached, + fib_index, &pfx, + mp->mr_next_hop_proto_is_ip4, + &nh, ntohl (mp->mr_next_hop_sw_if_index), + next_hop_fib_index, + mp->mr_next_hop_weight, + ntohl (mp->mr_next_hop_via_label), + label_stack)); +} + +void +vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp) +{ + vl_api_mpls_route_add_del_reply_t *rmp; + vnet_main_t *vnm; + int rv; + + vnm = vnet_get_main (); + vnm->api_errno = 0; + + rv = mpls_route_add_del_t_handler (vnm, mp); + + rv = (rv == 0) ? vnm->api_errno : rv; + + REPLY_MACRO (VL_API_MPLS_ROUTE_ADD_DEL_REPLY); +} + +static void +vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) +{ + vl_api_mpls_tunnel_add_del_reply_t *rmp; + int rv = 0; + u32 tunnel_sw_if_index; + int ii; + + stats_dslock_with_hint (1 /* release hint */ , 5 /* tag */ ); + + if (mp->mt_is_add) + { + fib_route_path_t rpath, *rpaths = NULL; + mpls_label_t *label_stack = NULL; + + memset (&rpath, 0, sizeof (rpath)); + + if (mp->mt_next_hop_proto_is_ip4) + { + rpath.frp_proto = FIB_PROTOCOL_IP4; + clib_memcpy (&rpath.frp_addr.ip4, + mp->mt_next_hop, sizeof (rpath.frp_addr.ip4)); + } + else + { + rpath.frp_proto = FIB_PROTOCOL_IP6; + clib_memcpy (&rpath.frp_addr.ip6, + mp->mt_next_hop, sizeof (rpath.frp_addr.ip6)); + } + rpath.frp_sw_if_index = ntohl (mp->mt_next_hop_sw_if_index); + + for (ii = 0; ii < mp->mt_next_hop_n_out_labels; ii++) + vec_add1 (label_stack, ntohl (mp->mt_next_hop_out_label_stack[ii])); + + vec_add1 (rpaths, rpath); + + vnet_mpls_tunnel_add (rpaths, label_stack, + mp->mt_l2_only, &tunnel_sw_if_index); + vec_free (rpaths); + vec_free (label_stack); + } + else + { + tunnel_sw_if_index = ntohl (mp->mt_sw_if_index); + vnet_mpls_tunnel_del (tunnel_sw_if_index); + } + + stats_dsunlock (); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_MPLS_TUNNEL_ADD_DEL_REPLY, + ({ + rmp->sw_if_index = ntohl(tunnel_sw_if_index); + })); + /* *INDENT-ON* */ +} + +static void +vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_tunnel_details_t * mp) +{ + clib_warning ("BUG"); +} + +typedef struct mpls_tunnel_send_walk_ctx_t_ +{ + unix_shared_memory_queue_t *q; + u32 index; + u32 context; +} mpls_tunnel_send_walk_ctx_t; + +static void +send_mpls_tunnel_entry (u32 mti, void *arg) +{ + mpls_tunnel_send_walk_ctx_t *ctx; + vl_api_mpls_tunnel_details_t *mp; + const mpls_tunnel_t *mt; + u32 nlabels; + + ctx = arg; + + if (~0 != ctx->index && mti != ctx->index) + return; + + mt = mpls_tunnel_get (mti); + nlabels = vec_len (mt->mt_label_stack); + + mp = vl_msg_api_alloc (sizeof (*mp) + nlabels * sizeof (u32)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_MPLS_TUNNEL_DETAILS); + mp->context = ctx->context; + + mp->tunnel_index = ntohl (mti); + memcpy (mp->mt_next_hop_out_labels, + mt->mt_label_stack, nlabels * sizeof (u32)); + + // FIXME + + vl_msg_api_send_shmem (ctx->q, (u8 *) & mp); +} + +static void +vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + mpls_tunnel_send_walk_ctx_t ctx = { + .q = q, + .index = ntohl (mp->tunnel_index), + .context = mp->context, + }; + mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx); +} + +static void +vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void +vl_api_mpls_fib_details_t_endian (vl_api_mpls_fib_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void +vl_api_mpls_fib_details_t_print (vl_api_mpls_fib_details_t * mp) +{ + clib_warning ("BUG"); +} + +static void +send_mpls_fib_details (vpe_api_main_t * am, + unix_shared_memory_queue_t * q, + u32 table_id, u32 label, u32 eos, + fib_route_path_encode_t * api_rpaths, u32 context) +{ + vl_api_mpls_fib_details_t *mp; + fib_route_path_encode_t *api_rpath; + vl_api_fib_path2_t *fp; + int path_count; + + path_count = vec_len (api_rpaths); + mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp)); + if (!mp) + return; + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_MPLS_FIB_DETAILS); + mp->context = context; + + mp->table_id = htonl (table_id); + mp->eos_bit = eos; + mp->label = htonl (label); + + mp->count = htonl (path_count); + fp = mp->path; + vec_foreach (api_rpath, api_rpaths) + { + memset (fp, 0, sizeof (*fp)); + fp->weight = htonl (api_rpath->rpath.frp_weight); + fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index); + copy_fib_next_hop (api_rpath, fp); + fp++; + } + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + +static void +vl_api_mpls_fib_dump_t_handler (vl_api_mpls_fib_dump_t * mp) +{ + vpe_api_main_t *am = &vpe_api_main; + unix_shared_memory_queue_t *q; + mpls_main_t *mm = &mpls_main; + fib_table_t *fib_table; + fib_node_index_t lfei, *lfeip, *lfeis = NULL; + mpls_label_t key; + fib_prefix_t pfx; + u32 fib_index; + fib_route_path_encode_t *api_rpaths; + + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0) + return; + + /* *INDENT-OFF* */ + pool_foreach (fib_table, mm->fibs, + ({ + hash_foreach(key, lfei, fib_table->mpls.mf_entries, + ({ + vec_add1(lfeis, lfei); + })); + })); + /* *INDENT-ON* */ + vec_sort_with_function (lfeis, fib_entry_cmp_for_sort); + + vec_foreach (lfeip, lfeis) + { + fib_entry_get_prefix (*lfeip, &pfx); + fib_index = fib_entry_get_fib_index (*lfeip); + fib_table = fib_table_get (fib_index, pfx.fp_proto); + api_rpaths = NULL; + fib_entry_encode (*lfeip, &api_rpaths); + send_mpls_fib_details (am, q, + fib_table->ft_table_id, + pfx.fp_label, pfx.fp_eos, api_rpaths, mp->context); + vec_free (api_rpaths); + } + + vec_free (lfeis); +} + +/* + * mpls_api_hookup + * Add vpe's API message handlers to the table. + * vlib has alread mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (api_main_t * am) +{ +#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); + foreach_vl_msg_name_crc_mpls; +#undef _ +} + +static clib_error_t * +mpls_api_hookup (vlib_main_t * vm) +{ + api_main_t *am = &api_main; + +#define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_vpe_api_msg; +#undef _ + + /* + * Trace space for 8 MPLS encap labels + */ + am->api_trace_cfg[VL_API_MPLS_TUNNEL_ADD_DEL].size += 8 * sizeof (u32); + + /* + * Set up the (msg_name, crc, message-id) table + */ + setup_message_id_table (am); + + return 0; +} + +VLIB_API_INIT_FUNCTION (mpls_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/sr/sr.api b/src/vnet/sr/sr.api new file mode 100644 index 00000000..3d017ce5 --- /dev/null +++ b/src/vnet/sr/sr.api @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015-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. + */ + +/** \brief IPv6 segment routing tunnel add / del request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add the tunnel if non-zero, else delete it + @param name[] - tunnel name (len. 64) + @param src_address[] - + @param dst_address[] - + @param dst_mask_width - + @param inner_vrf_id - + @param outer_vrf_id - + @param flags_net_byte_order - + @param n_segments - + @param n_tags - + @param segs_and_tags[] - + @param policy_name[] - name of policy to associate this tunnel to (len. 64) +*/ +define sr_tunnel_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + u8 name[64]; + u8 src_address[16]; + u8 dst_address[16]; + u8 dst_mask_width; + u32 inner_vrf_id; + u32 outer_vrf_id; + u16 flags_net_byte_order; + u8 n_segments; + u8 n_tags; + u8 policy_name[64]; + u8 segs_and_tags[0]; +}; + +/** \brief IPv6 segment routing tunnel add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define sr_tunnel_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief IPv6 segment routing policy add / del request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add the tunnel if non-zero, else delete it + @param name[] - policy name (len. 64) + @param tunnel_names[] - +*/ +define sr_policy_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + u8 name[64]; + u8 tunnel_names[0]; +}; + +/** \brief IPv6 segment routing policy add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request + + +*/ +define sr_policy_add_del_reply +{ + u32 context; + i32 retval; +}; + +/** \brief IPv6 segment routing multicast map to policy add / del request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add the tunnel if non-zero, else delete it + @param multicast_address[] - IP6 multicast address + @param policy_name[] = policy name (len.64) +*/ +define sr_multicast_map_add_del +{ + u32 client_index; + u32 context; + u8 is_add; + u8 multicast_address[16]; + u8 policy_name[64]; +}; + +/** \brief IPv6 segment routing multicast map to policy add / del response + @param context - sender context, to match reply w/ request + @param retval - return value for request +*/ +define sr_multicast_map_add_del_reply +{ + u32 context; + i32 retval; +}; + +/* + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ + \ No newline at end of file diff --git a/src/vnet/sr/sr_api.c b/src/vnet/sr/sr_api.c new file mode 100644 index 00000000..6c6eb9b6 --- /dev/null +++ b/src/vnet/sr/sr_api.c @@ -0,0 +1,279 @@ +/* + *------------------------------------------------------------------ + * sr_api.c - ipv6 segment routing api + * + * 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 +#include +#include + +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +#include + +#define foreach_vpe_api_msg \ +_(SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del) + +static void vl_api_sr_tunnel_add_del_t_handler + (vl_api_sr_tunnel_add_del_t * mp) +{ +#if IP6SR == 0 + clib_warning ("unimplemented"); +#else + ip6_sr_add_del_tunnel_args_t _a, *a = &_a; + int rv = 0; + vl_api_sr_tunnel_add_del_reply_t *rmp; + ip6_address_t *segments = 0, *seg; + ip6_address_t *tags = 0, *tag; + ip6_address_t *this_address; + int i; + + if (mp->n_segments == 0) + { + rv = -11; + goto out; + } + + memset (a, 0, sizeof (*a)); + a->src_address = (ip6_address_t *) & mp->src_address; + a->dst_address = (ip6_address_t *) & mp->dst_address; + a->dst_mask_width = mp->dst_mask_width; + a->flags_net_byte_order = mp->flags_net_byte_order; + a->is_del = (mp->is_add == 0); + a->rx_table_id = ntohl (mp->outer_vrf_id); + a->tx_table_id = ntohl (mp->inner_vrf_id); + + a->name = format (0, "%s", mp->name); + if (!(vec_len (a->name))) + a->name = 0; + + a->policy_name = format (0, "%s", mp->policy_name); + if (!(vec_len (a->policy_name))) + a->policy_name = 0; + + /* Yank segments and tags out of the API message */ + this_address = (ip6_address_t *) mp->segs_and_tags; + for (i = 0; i < mp->n_segments; i++) + { + vec_add2 (segments, seg, 1); + clib_memcpy (seg->as_u8, this_address->as_u8, sizeof (*this_address)); + this_address++; + } + for (i = 0; i < mp->n_tags; i++) + { + vec_add2 (tags, tag, 1); + clib_memcpy (tag->as_u8, this_address->as_u8, sizeof (*this_address)); + this_address++; + } + + a->segments = segments; + a->tags = tags; + + rv = ip6_sr_add_del_tunnel (a); + +out: + + REPLY_MACRO (VL_API_SR_TUNNEL_ADD_DEL_REPLY); +#endif +} + +static void vl_api_sr_policy_add_del_t_handler + (vl_api_sr_policy_add_del_t * mp) +{ +#if IP6SR == 0 + clib_warning ("unimplemented"); +#else + ip6_sr_add_del_policy_args_t _a, *a = &_a; + int rv = 0; + vl_api_sr_policy_add_del_reply_t *rmp; + int i; + + memset (a, 0, sizeof (*a)); + a->is_del = (mp->is_add == 0); + + a->name = format (0, "%s", mp->name); + if (!(vec_len (a->name))) + { + rv = VNET_API_ERROR_NO_SUCH_NODE2; + goto out; + } + + if (!(mp->tunnel_names[0])) + { + rv = VNET_API_ERROR_NO_SUCH_NODE2; + goto out; + } + + // start deserializing tunnel_names + int num_tunnels = mp->tunnel_names[0]; //number of tunnels + u8 *deser_tun_names = mp->tunnel_names; + deser_tun_names += 1; //moving along + + u8 *tun_name = 0; + int tun_name_len = 0; + + for (i = 0; i < num_tunnels; i++) + { + tun_name_len = *deser_tun_names; + deser_tun_names += 1; + vec_resize (tun_name, tun_name_len); + memcpy (tun_name, deser_tun_names, tun_name_len); + vec_add1 (a->tunnel_names, tun_name); + deser_tun_names += tun_name_len; + tun_name = 0; + } + + rv = ip6_sr_add_del_policy (a); + +out: + + REPLY_MACRO (VL_API_SR_POLICY_ADD_DEL_REPLY); +#endif +} + +static void vl_api_sr_multicast_map_add_del_t_handler + (vl_api_sr_multicast_map_add_del_t * mp) +{ +#if IP6SR == 0 + clib_warning ("unimplemented"); +#else + ip6_sr_add_del_multicastmap_args_t _a, *a = &_a; + int rv = 0; + vl_api_sr_multicast_map_add_del_reply_t *rmp; + + memset (a, 0, sizeof (*a)); + a->is_del = (mp->is_add == 0); + + a->multicast_address = (ip6_address_t *) & mp->multicast_address; + a->policy_name = format (0, "%s", mp->policy_name); + + if (a->multicast_address == 0) + { + rv = -1; + goto out; + } + + if (!(a->policy_name)) + { + rv = -2; + goto out; + } + +#if DPDK > 0 /* Cannot call replicate without DPDK */ + rv = ip6_sr_add_del_multicastmap (a); +#else + clib_warning ("multicast replication without DPDK not implemented"); + rv = VNET_API_ERROR_UNIMPLEMENTED; +#endif /* DPDK */ + +out: + + REPLY_MACRO (VL_API_SR_MULTICAST_MAP_ADD_DEL_REPLY); +#endif +} + +/* + * sr_api_hookup + * Add vpe's API message handlers to the table. + * vlib has alread mapped shared memory and + * added the client registration handlers. + * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() + */ +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (api_main_t * am) +{ +#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); + foreach_vl_msg_name_crc_sr; +#undef _ +} + +static clib_error_t * +sr_api_hookup (vlib_main_t * vm) +{ + api_main_t *am = &api_main; + +#define _(N,n) \ + vl_msg_api_set_handlers(VL_API_##N, #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_vpe_api_msg; +#undef _ + + /* + * Manually register the sr tunnel add del msg, so we trace + * enough bytes to capture a typical segment list + */ + vl_msg_api_set_handlers (VL_API_SR_TUNNEL_ADD_DEL, + "sr_tunnel_add_del", + vl_api_sr_tunnel_add_del_t_handler, + vl_noop_handler, + vl_api_sr_tunnel_add_del_t_endian, + vl_api_sr_tunnel_add_del_t_print, 256, 1); + + + /* + * Manually register the sr policy add del msg, so we trace + * enough bytes to capture a typical tunnel name list + */ + vl_msg_api_set_handlers (VL_API_SR_POLICY_ADD_DEL, + "sr_policy_add_del", + vl_api_sr_policy_add_del_t_handler, + vl_noop_handler, + vl_api_sr_policy_add_del_t_endian, + vl_api_sr_policy_add_del_t_print, 256, 1); + + /* + * Set up the (msg_name, crc, message-id) table + */ + setup_message_id_table (am); + + return 0; +} + +VLIB_API_INIT_FUNCTION (sr_api_hookup); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/vnet_all_api_h.h b/src/vnet/vnet_all_api_h.h index d48e1540..1024f92c 100644 --- a/src/vnet/vnet_all_api_h.h +++ b/src/vnet/vnet_all_api_h.h @@ -50,6 +50,8 @@ #include #include #include +#include +#include /* * fd.io coding-style-patch-verification: ON diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 46e28e9d..3d6905dd 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -52,8 +52,6 @@ #include #include #include -#include -#include #include #include #if IPV6SR > 0 @@ -119,24 +117,14 @@ #define foreach_vpe_api_msg \ _(WANT_OAM_EVENTS, want_oam_events) \ _(OAM_ADD_DEL, oam_add_del) \ -_(MPLS_ROUTE_ADD_DEL, mpls_route_add_del) \ -_(MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind) \ _(IS_ADDRESS_REACHABLE, is_address_reachable) \ _(SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable) \ _(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \ _(SW_INTERFACE_SET_VXLAN_BYPASS, sw_interface_set_vxlan_bypass) \ _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \ _(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \ -_(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ -_(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ -_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ -_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ -_(L2FIB_ADD_DEL, l2fib_add_del) \ -_(L2_FLAGS, l2_flags) \ -_(BRIDGE_FLAGS, bridge_flags) \ _(CREATE_VLAN_SUBIF, create_vlan_subif) \ _(CREATE_SUBIF, create_subif) \ -_(MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del) \ _(PROXY_ARP_ADD_DEL, proxy_arp_add_del) \ _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \ _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \ @@ -159,12 +147,9 @@ _(GET_NODE_INDEX, get_node_index) \ _(ADD_NODE_NEXT, add_node_next) \ _(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ _(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ -_(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ _(SHOW_VERSION, show_version) \ -_(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ -_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ _(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ @@ -178,15 +163,10 @@ _(COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable) \ _(GET_NODE_GRAPH, get_node_graph) \ _(IOAM_ENABLE, ioam_enable) \ _(IOAM_DISABLE, ioam_disable) \ -_(SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del) \ _(POLICER_ADD_DEL, policer_add_del) \ _(POLICER_DUMP, policer_dump) \ _(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \ _(POLICER_CLASSIFY_DUMP, policer_classify_dump) \ -_(MPLS_TUNNEL_DUMP, mpls_tunnel_dump) \ -_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ -_(MPLS_FIB_DUMP, mpls_fib_dump) \ -_(MPLS_FIB_DETAILS, mpls_fib_details) \ _(CLASSIFY_TABLE_IDS,classify_table_ids) \ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \ _(CLASSIFY_TABLE_INFO,classify_table_info) \ @@ -411,173 +391,6 @@ VLIB_REGISTER_NODE (vpe_resolver_process_node,static) = { }; /* *INDENT-ON* */ -static int -mpls_route_add_del_t_handler (vnet_main_t * vnm, - vl_api_mpls_route_add_del_t * mp) -{ - u32 fib_index, next_hop_fib_index; - mpls_label_t *label_stack = NULL; - int rv, ii, n_labels;; - - fib_prefix_t pfx = { - .fp_len = 21, - .fp_proto = FIB_PROTOCOL_MPLS, - .fp_eos = mp->mr_eos, - .fp_label = ntohl (mp->mr_label), - }; - if (pfx.fp_eos) - { - if (mp->mr_next_hop_proto_is_ip4) - { - pfx.fp_payload_proto = DPO_PROTO_IP4; - } - else - { - pfx.fp_payload_proto = DPO_PROTO_IP6; - } - } - else - { - pfx.fp_payload_proto = DPO_PROTO_MPLS; - } - - rv = add_del_route_check (FIB_PROTOCOL_MPLS, - mp->mr_table_id, - mp->mr_next_hop_sw_if_index, - dpo_proto_to_fib (pfx.fp_payload_proto), - mp->mr_next_hop_table_id, - mp->mr_create_table_if_needed, - &fib_index, &next_hop_fib_index); - - if (0 != rv) - return (rv); - - ip46_address_t nh; - memset (&nh, 0, sizeof (nh)); - - if (mp->mr_next_hop_proto_is_ip4) - memcpy (&nh.ip4, mp->mr_next_hop, sizeof (nh.ip4)); - else - memcpy (&nh.ip6, mp->mr_next_hop, sizeof (nh.ip6)); - - n_labels = mp->mr_next_hop_n_out_labels; - if (n_labels == 0) - ; - else if (1 == n_labels) - vec_add1 (label_stack, ntohl (mp->mr_next_hop_out_label_stack[0])); - else - { - vec_validate (label_stack, n_labels - 1); - for (ii = 0; ii < n_labels; ii++) - label_stack[ii] = ntohl (mp->mr_next_hop_out_label_stack[ii]); - } - - return (add_del_route_t_handler (mp->mr_is_multipath, mp->mr_is_add, 0, // mp->is_drop, - 0, // mp->is_unreach, - 0, // mp->is_prohibit, - 0, // mp->is_local, - mp->mr_is_classify, - mp->mr_classify_table_index, - mp->mr_is_resolve_host, - mp->mr_is_resolve_attached, - fib_index, &pfx, - mp->mr_next_hop_proto_is_ip4, - &nh, ntohl (mp->mr_next_hop_sw_if_index), - next_hop_fib_index, - mp->mr_next_hop_weight, - ntohl (mp->mr_next_hop_via_label), - label_stack)); -} - -void -vl_api_mpls_route_add_del_t_handler (vl_api_mpls_route_add_del_t * mp) -{ - vl_api_mpls_route_add_del_reply_t *rmp; - vnet_main_t *vnm; - int rv; - - vnm = vnet_get_main (); - vnm->api_errno = 0; - - rv = mpls_route_add_del_t_handler (vnm, mp); - - rv = (rv == 0) ? vnm->api_errno : rv; - - REPLY_MACRO (VL_API_MPLS_ROUTE_ADD_DEL_REPLY); -} - -static int -mpls_ip_bind_unbind_handler (vnet_main_t * vnm, - vl_api_mpls_ip_bind_unbind_t * mp) -{ - u32 mpls_fib_index, ip_fib_index; - - mpls_fib_index = - fib_table_find (FIB_PROTOCOL_MPLS, ntohl (mp->mb_mpls_table_id)); - - if (~0 == mpls_fib_index) - { - if (mp->mb_create_table_if_needed) - { - mpls_fib_index = - fib_table_find_or_create_and_lock (FIB_PROTOCOL_MPLS, - ntohl (mp->mb_mpls_table_id)); - } - else - return VNET_API_ERROR_NO_SUCH_FIB; - } - - ip_fib_index = fib_table_find ((mp->mb_is_ip4 ? - FIB_PROTOCOL_IP4 : - FIB_PROTOCOL_IP6), - ntohl (mp->mb_ip_table_id)); - if (~0 == ip_fib_index) - return VNET_API_ERROR_NO_SUCH_FIB; - - fib_prefix_t pfx = { - .fp_len = mp->mb_address_length, - }; - - if (mp->mb_is_ip4) - { - pfx.fp_proto = FIB_PROTOCOL_IP4; - clib_memcpy (&pfx.fp_addr.ip4, mp->mb_address, - sizeof (pfx.fp_addr.ip4)); - } - else - { - pfx.fp_proto = FIB_PROTOCOL_IP6; - clib_memcpy (&pfx.fp_addr.ip6, mp->mb_address, - sizeof (pfx.fp_addr.ip6)); - } - - if (mp->mb_is_bind) - fib_table_entry_local_label_add (ip_fib_index, &pfx, - ntohl (mp->mb_label)); - else - fib_table_entry_local_label_remove (ip_fib_index, &pfx, - ntohl (mp->mb_label)); - - return (0); -} - -void -vl_api_mpls_ip_bind_unbind_t_handler (vl_api_mpls_ip_bind_unbind_t * mp) -{ - vl_api_mpls_route_add_del_reply_t *rmp; - vnet_main_t *vnm; - int rv; - - vnm = vnet_get_main (); - vnm->api_errno = 0; - - rv = mpls_ip_bind_unbind_handler (vnm, mp); - - rv = (rv == 0) ? vnm->api_errno : rv; - - REPLY_MACRO (VL_API_MPLS_ROUTE_ADD_DEL_REPLY); -} - static void vl_api_sw_interface_set_vpath_t_handler (vl_api_sw_interface_set_vpath_t * mp) { @@ -690,278 +503,6 @@ static void REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY); } -static void -vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - bd_main_t *bdm = &bd_main; - vl_api_bridge_domain_add_del_reply_t *rmp; - int rv = 0; - u32 enable_flags = 0, disable_flags = 0; - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - - if (mp->is_add) - { - bd_index = bd_find_or_add_bd_index (bdm, bd_id); - - if (mp->flood) - enable_flags |= L2_FLOOD; - else - disable_flags |= L2_FLOOD; - - if (mp->uu_flood) - enable_flags |= L2_UU_FLOOD; - else - disable_flags |= L2_UU_FLOOD; - - if (mp->forward) - enable_flags |= L2_FWD; - else - disable_flags |= L2_FWD; - - if (mp->arp_term) - enable_flags |= L2_ARP_TERM; - else - disable_flags |= L2_ARP_TERM; - - if (mp->learn) - enable_flags |= L2_LEARN; - else - disable_flags |= L2_LEARN; - - if (enable_flags) - bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); - - if (disable_flags) - bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); - - bd_set_mac_age (vm, bd_index, mp->mac_age); - } - else - rv = bd_delete_bd_index (bdm, bd_id); - - REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); -} - -static void -vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void - vl_api_bridge_domain_sw_if_details_t_handler - (vl_api_bridge_domain_sw_if_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -send_bridge_domain_details (unix_shared_memory_queue_t * q, - l2_bridge_domain_t * bd_config, - u32 n_sw_ifs, u32 context) -{ - vl_api_bridge_domain_details_t *mp; - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_DETAILS); - mp->bd_id = ntohl (bd_config->bd_id); - mp->flood = bd_feature_flood (bd_config); - mp->uu_flood = bd_feature_uu_flood (bd_config); - mp->forward = bd_feature_forward (bd_config); - mp->learn = bd_feature_learn (bd_config); - mp->arp_term = bd_feature_arp_term (bd_config); - mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index); - mp->mac_age = bd_config->mac_age; - mp->n_sw_ifs = ntohl (n_sw_ifs); - mp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -send_bd_sw_if_details (l2input_main_t * l2im, - unix_shared_memory_queue_t * q, - l2_flood_member_t * member, u32 bd_id, u32 context) -{ - vl_api_bridge_domain_sw_if_details_t *mp; - l2_input_config_t *input_cfg; - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_SW_IF_DETAILS); - mp->bd_id = ntohl (bd_id); - mp->sw_if_index = ntohl (member->sw_if_index); - input_cfg = vec_elt_at_index (l2im->configs, member->sw_if_index); - mp->shg = input_cfg->shg; - mp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) -{ - bd_main_t *bdm = &bd_main; - l2input_main_t *l2im = &l2input_main; - unix_shared_memory_queue_t *q; - l2_bridge_domain_t *bd_config; - u32 bd_id, bd_index; - u32 end; - - q = vl_api_client_index_to_input_queue (mp->client_index); - - if (q == 0) - return; - - bd_id = ntohl (mp->bd_id); - - bd_index = (bd_id == ~0) ? 0 : bd_find_or_add_bd_index (bdm, bd_id); - end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; - for (; bd_index < end; bd_index++) - { - bd_config = l2input_bd_config_from_index (l2im, bd_index); - /* skip dummy bd_id 0 */ - if (bd_config && (bd_config->bd_id > 0)) - { - u32 n_sw_ifs; - l2_flood_member_t *m; - - n_sw_ifs = vec_len (bd_config->members); - send_bridge_domain_details (q, bd_config, n_sw_ifs, mp->context); - - vec_foreach (m, bd_config->members) - { - send_bd_sw_if_details (l2im, q, m, bd_config->bd_id, mp->context); - } - } - } -} - -static void -vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) -{ - bd_main_t *bdm = &bd_main; - l2input_main_t *l2im = &l2input_main; - vl_api_l2fib_add_del_reply_t *rmp; - int rv = 0; - u64 mac = 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 static_mac; - u32 filter_mac; - u32 bvi_mac; - uword *p; - - mac = mp->mac; - - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto bad_sw_if_index; - } - bd_index = p[0]; - - if (mp->is_add) - { - filter_mac = mp->filter_mac ? 1 : 0; - if (filter_mac == 0) - { - VALIDATE_SW_IF_INDEX (mp); - if (vec_len (l2im->configs) <= sw_if_index) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } - else - { - l2_input_config_t *config; - config = vec_elt_at_index (l2im->configs, sw_if_index); - if (config->bridge == 0) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto bad_sw_if_index; - } - } - } - static_mac = mp->static_mac ? 1 : 0; - bvi_mac = mp->bvi_mac ? 1 : 0; - l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac, - bvi_mac); - } - else - { - l2fib_del_entry (mac, bd_index); - } - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY); -} - -static void -vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) -{ - vl_api_l2_flags_reply_t *rmp; - int rv = 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 flags = ntohl (mp->feature_bitmap); - u32 rbm = 0; - - VALIDATE_SW_IF_INDEX (mp); - -#define _(a,b) \ - if (flags & L2INPUT_FEAT_ ## a) \ - rbm = l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ ## a, mp->is_set); - foreach_l2input_feat; -#undef _ - - BAD_SW_IF_INDEX_LABEL; - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_L2_FLAGS_REPLY, - ({ - rmp->resulting_feature_bitmap = ntohl(rbm); - })); - /* *INDENT-ON* */ -} - -static void -vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) -{ - vlib_main_t *vm = vlib_get_main (); - bd_main_t *bdm = &bd_main; - vl_api_bridge_flags_reply_t *rmp; - int rv = 0; - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 flags = ntohl (mp->feature_bitmap); - uword *p; - - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p == 0) - { - rv = VNET_API_ERROR_NO_SUCH_ENTRY; - goto out; - } - - bd_index = p[0]; - - bd_set_flags (vm, bd_index, flags, mp->is_set); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY, - ({ - rmp->resulting_feature_bitmap = ntohl(flags); - })); - /* *INDENT-ON* */ -} - static void vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp) { @@ -1147,64 +688,6 @@ out: /* *INDENT-ON* */ } -static void -vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) -{ - vl_api_mpls_tunnel_add_del_reply_t *rmp; - int rv = 0; - stats_main_t *sm = &stats_main; - u32 tunnel_sw_if_index; - int ii; - - dslock (sm, 1 /* release hint */ , 5 /* tag */ ); - - if (mp->mt_is_add) - { - fib_route_path_t rpath, *rpaths = NULL; - mpls_label_t *label_stack = NULL; - - memset (&rpath, 0, sizeof (rpath)); - - if (mp->mt_next_hop_proto_is_ip4) - { - rpath.frp_proto = FIB_PROTOCOL_IP4; - clib_memcpy (&rpath.frp_addr.ip4, - mp->mt_next_hop, sizeof (rpath.frp_addr.ip4)); - } - else - { - rpath.frp_proto = FIB_PROTOCOL_IP6; - clib_memcpy (&rpath.frp_addr.ip6, - mp->mt_next_hop, sizeof (rpath.frp_addr.ip6)); - } - rpath.frp_sw_if_index = ntohl (mp->mt_next_hop_sw_if_index); - - for (ii = 0; ii < mp->mt_next_hop_n_out_labels; ii++) - vec_add1 (label_stack, ntohl (mp->mt_next_hop_out_label_stack[ii])); - - vec_add1 (rpaths, rpath); - - vnet_mpls_tunnel_add (rpaths, label_stack, - mp->mt_l2_only, &tunnel_sw_if_index); - vec_free (rpaths); - vec_free (label_stack); - } - else - { - tunnel_sw_if_index = ntohl (mp->mt_sw_if_index); - vnet_mpls_tunnel_del (tunnel_sw_if_index); - } - - dsunlock (sm); - - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_MPLS_TUNNEL_ADD_DEL_REPLY, - ({ - rmp->sw_if_index = ntohl(tunnel_sw_if_index); - })); - /* *INDENT-ON* */ -} - static void vl_api_proxy_arp_add_del_t_handler (vl_api_proxy_arp_add_del_t * mp) { @@ -1929,164 +1412,6 @@ vl_api_set_arp_neighbor_limit_t_handler (vl_api_set_arp_neighbor_limit_t * mp) REPLY_MACRO (VL_API_SET_ARP_NEIGHBOR_LIMIT_REPLY); } -static void vl_api_sr_tunnel_add_del_t_handler - (vl_api_sr_tunnel_add_del_t * mp) -{ -#if IP6SR == 0 - clib_warning ("unimplemented"); -#else - ip6_sr_add_del_tunnel_args_t _a, *a = &_a; - int rv = 0; - vl_api_sr_tunnel_add_del_reply_t *rmp; - ip6_address_t *segments = 0, *seg; - ip6_address_t *tags = 0, *tag; - ip6_address_t *this_address; - int i; - - if (mp->n_segments == 0) - { - rv = -11; - goto out; - } - - memset (a, 0, sizeof (*a)); - a->src_address = (ip6_address_t *) & mp->src_address; - a->dst_address = (ip6_address_t *) & mp->dst_address; - a->dst_mask_width = mp->dst_mask_width; - a->flags_net_byte_order = mp->flags_net_byte_order; - a->is_del = (mp->is_add == 0); - a->rx_table_id = ntohl (mp->outer_vrf_id); - a->tx_table_id = ntohl (mp->inner_vrf_id); - - a->name = format (0, "%s", mp->name); - if (!(vec_len (a->name))) - a->name = 0; - - a->policy_name = format (0, "%s", mp->policy_name); - if (!(vec_len (a->policy_name))) - a->policy_name = 0; - - /* Yank segments and tags out of the API message */ - this_address = (ip6_address_t *) mp->segs_and_tags; - for (i = 0; i < mp->n_segments; i++) - { - vec_add2 (segments, seg, 1); - clib_memcpy (seg->as_u8, this_address->as_u8, sizeof (*this_address)); - this_address++; - } - for (i = 0; i < mp->n_tags; i++) - { - vec_add2 (tags, tag, 1); - clib_memcpy (tag->as_u8, this_address->as_u8, sizeof (*this_address)); - this_address++; - } - - a->segments = segments; - a->tags = tags; - - rv = ip6_sr_add_del_tunnel (a); - -out: - - REPLY_MACRO (VL_API_SR_TUNNEL_ADD_DEL_REPLY); -#endif -} - -static void vl_api_sr_policy_add_del_t_handler - (vl_api_sr_policy_add_del_t * mp) -{ -#if IP6SR == 0 - clib_warning ("unimplemented"); -#else - ip6_sr_add_del_policy_args_t _a, *a = &_a; - int rv = 0; - vl_api_sr_policy_add_del_reply_t *rmp; - int i; - - memset (a, 0, sizeof (*a)); - a->is_del = (mp->is_add == 0); - - a->name = format (0, "%s", mp->name); - if (!(vec_len (a->name))) - { - rv = VNET_API_ERROR_NO_SUCH_NODE2; - goto out; - } - - if (!(mp->tunnel_names[0])) - { - rv = VNET_API_ERROR_NO_SUCH_NODE2; - goto out; - } - - // start deserializing tunnel_names - int num_tunnels = mp->tunnel_names[0]; //number of tunnels - u8 *deser_tun_names = mp->tunnel_names; - deser_tun_names += 1; //moving along - - u8 *tun_name = 0; - int tun_name_len = 0; - - for (i = 0; i < num_tunnels; i++) - { - tun_name_len = *deser_tun_names; - deser_tun_names += 1; - vec_resize (tun_name, tun_name_len); - memcpy (tun_name, deser_tun_names, tun_name_len); - vec_add1 (a->tunnel_names, tun_name); - deser_tun_names += tun_name_len; - tun_name = 0; - } - - rv = ip6_sr_add_del_policy (a); - -out: - - REPLY_MACRO (VL_API_SR_POLICY_ADD_DEL_REPLY); -#endif -} - -static void vl_api_sr_multicast_map_add_del_t_handler - (vl_api_sr_multicast_map_add_del_t * mp) -{ -#if IP6SR == 0 - clib_warning ("unimplemented"); -#else - ip6_sr_add_del_multicastmap_args_t _a, *a = &_a; - int rv = 0; - vl_api_sr_multicast_map_add_del_reply_t *rmp; - - memset (a, 0, sizeof (*a)); - a->is_del = (mp->is_add == 0); - - a->multicast_address = (ip6_address_t *) & mp->multicast_address; - a->policy_name = format (0, "%s", mp->policy_name); - - if (a->multicast_address == 0) - { - rv = -1; - goto out; - } - - if (!(a->policy_name)) - { - rv = -2; - goto out; - } - -#if DPDK > 0 /* Cannot call replicate without DPDK */ - rv = ip6_sr_add_del_multicastmap (a); -#else - clib_warning ("multicast replication without DPDK not implemented"); - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif /* DPDK */ - -out: - - REPLY_MACRO (VL_API_SR_MULTICAST_MAP_ADD_DEL_REPLY); -#endif -} - #define foreach_classify_add_del_table_field \ _(table_index) \ _(nbuckets) \ @@ -2246,21 +1571,6 @@ static void vl_api_classify_set_interface_l2_tables_t_handler REPLY_MACRO (VL_API_CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY); } -static void -vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp) -{ - int rv = 0; - vl_api_l2_fib_clear_table_reply_t *rmp; - - /* DAW-FIXME: This API should only clear non-static l2fib entries, but - * that is not currently implemented. When that TODO is fixed - * this call should be changed to pass 1 instead of 0. - */ - l2fib_clear_table (0); - - REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY); -} - extern void l2_efp_filter_configure (vnet_main_t * vnet_main, u32 sw_if_index, u32 enable); @@ -2321,76 +1631,6 @@ static void REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY); } -static void -vl_api_l2_fib_table_entry_t_handler (vl_api_l2_fib_table_entry_t * mp) -{ - clib_warning ("BUG"); -} - -static void -send_l2fib_table_entry (vpe_api_main_t * am, - unix_shared_memory_queue_t * q, - l2fib_entry_key_t * l2fe_key, - l2fib_entry_result_t * l2fe_res, u32 context) -{ - vl_api_l2_fib_table_entry_t *mp; - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_ENTRY); - - mp->bd_id = - ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id); - - mp->mac = l2fib_make_key (l2fe_key->fields.mac, 0); - mp->sw_if_index = ntohl (l2fe_res->fields.sw_if_index); - mp->static_mac = l2fe_res->fields.static_mac; - mp->filter_mac = l2fe_res->fields.filter; - mp->bvi_mac = l2fe_res->fields.bvi; - mp->context = context; - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp) -{ - vpe_api_main_t *am = &vpe_api_main; - bd_main_t *bdm = &bd_main; - l2fib_entry_key_t *l2fe_key = NULL; - l2fib_entry_result_t *l2fe_res = NULL; - u32 ni, bd_id = ntohl (mp->bd_id); - u32 bd_index; - unix_shared_memory_queue_t *q; - uword *p; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* see l2fib_table_dump: ~0 means "any" */ - if (bd_id == ~0) - bd_index = ~0; - else - { - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p == 0) - return; - - bd_index = p[0]; - } - - l2fib_table_dump (bd_index, &l2fe_key, &l2fe_res); - - vec_foreach_index (ni, l2fe_key) - { - send_l2fib_table_entry (am, q, vec_elt_at_index (l2fe_key, ni), - vec_elt_at_index (l2fe_res, ni), mp->context); - } - vec_free (l2fe_key); - vec_free (l2fe_res); -} - static void vl_api_show_version_t_handler (vl_api_show_version_t * mp) { @@ -3357,167 +2597,6 @@ vl_api_policer_classify_dump_t_handler (vl_api_policer_classify_dump_t * mp) } } -static void -vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -typedef struct mpls_tunnel_send_walk_ctx_t_ -{ - unix_shared_memory_queue_t *q; - u32 index; - u32 context; -} mpls_tunnel_send_walk_ctx_t; - -static void -send_mpls_tunnel_entry (u32 mti, void *arg) -{ - mpls_tunnel_send_walk_ctx_t *ctx; - vl_api_mpls_tunnel_details_t *mp; - const mpls_tunnel_t *mt; - u32 nlabels; - - ctx = arg; - - if (~0 != ctx->index && mti != ctx->index) - return; - - mt = mpls_tunnel_get (mti); - nlabels = vec_len (mt->mt_label_stack); - - mp = vl_msg_api_alloc (sizeof (*mp) + nlabels * sizeof (u32)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_TUNNEL_DETAILS); - mp->context = ctx->context; - - mp->tunnel_index = ntohl (mti); - memcpy (mp->mt_next_hop_out_labels, - mt->mt_label_stack, nlabels * sizeof (u32)); - - // FIXME - - vl_msg_api_send_shmem (ctx->q, (u8 *) & mp); -} - -static void -vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - mpls_tunnel_send_walk_ctx_t ctx = { - .q = q, - .index = ntohl (mp->tunnel_index), - .context = mp->context, - }; - mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx); -} - -static void -vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_endian (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_print (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -send_mpls_fib_details (vpe_api_main_t * am, - unix_shared_memory_queue_t * q, - u32 table_id, u32 label, u32 eos, - fib_route_path_encode_t * api_rpaths, u32 context) -{ - vl_api_mpls_fib_details_t *mp; - fib_route_path_encode_t *api_rpath; - vl_api_fib_path2_t *fp; - int path_count; - - path_count = vec_len (api_rpaths); - mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp)); - if (!mp) - return; - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_MPLS_FIB_DETAILS); - mp->context = context; - - mp->table_id = htonl (table_id); - mp->eos_bit = eos; - mp->label = htonl (label); - - mp->count = htonl (path_count); - fp = mp->path; - vec_foreach (api_rpath, api_rpaths) - { - memset (fp, 0, sizeof (*fp)); - fp->weight = htonl (api_rpath->rpath.frp_weight); - fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index); - copy_fib_next_hop (api_rpath, fp); - fp++; - } - - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -vl_api_mpls_fib_dump_t_handler (vl_api_mpls_fib_dump_t * mp) -{ - vpe_api_main_t *am = &vpe_api_main; - unix_shared_memory_queue_t *q; - mpls_main_t *mm = &mpls_main; - fib_table_t *fib_table; - fib_node_index_t lfei, *lfeip, *lfeis = NULL; - mpls_label_t key; - fib_prefix_t pfx; - u32 fib_index; - fib_route_path_encode_t *api_rpaths; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - return; - - /* *INDENT-OFF* */ - pool_foreach (fib_table, mm->fibs, - ({ - hash_foreach(key, lfei, fib_table->mpls.mf_entries, - ({ - vec_add1(lfeis, lfei); - })); - })); - vec_sort_with_function(lfeis, fib_entry_cmp_for_sort); - - vec_foreach(lfeip, lfeis) - { - fib_entry_get_prefix(*lfeip, &pfx); - fib_index = fib_entry_get_fib_index(*lfeip); - fib_table = fib_table_get(fib_index, pfx.fp_proto); - api_rpaths = NULL; - fib_entry_encode(*lfeip, &api_rpaths); - send_mpls_fib_details (am, q, - fib_table->ft_table_id, - pfx.fp_label, - pfx.fp_eos, - api_rpaths, - mp->context); - vec_free(api_rpaths); - } - - vec_free (lfeis); -} - static void vl_api_classify_table_ids_t_handler (vl_api_classify_table_ids_t * mp) { @@ -4487,32 +3566,8 @@ vpe_api_hookup (vlib_main_t * vm) #undef _ /* - * Manually register the sr tunnel add del msg, so we trace - * enough bytes to capture a typical segment list - */ - vl_msg_api_set_handlers (VL_API_SR_TUNNEL_ADD_DEL, - "sr_tunnel_add_del", - vl_api_sr_tunnel_add_del_t_handler, - vl_noop_handler, - vl_api_sr_tunnel_add_del_t_endian, - vl_api_sr_tunnel_add_del_t_print, 256, 1); - - - /* - * Manually register the sr policy add del msg, so we trace - * enough bytes to capture a typical tunnel name list - */ - vl_msg_api_set_handlers (VL_API_SR_POLICY_ADD_DEL, - "sr_policy_add_del", - vl_api_sr_policy_add_del_t_handler, - vl_noop_handler, - vl_api_sr_policy_add_del_t_endian, - vl_api_sr_policy_add_del_t_print, 256, 1); - - /* - * Trace space for 8 MPLS encap labels, classifier mask+match + * Trace space for classifier mask+match */ - am->api_trace_cfg[VL_API_MPLS_TUNNEL_ADD_DEL].size += 8 * sizeof (u32); am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_TABLE].size += 5 * sizeof (u32x4); am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_SESSION].size += 5 * sizeof (u32x4); diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 3e4bcdf9..e784fa01 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -22,21 +22,24 @@ /* * Note: API placement cleanup in progress * If you're looking for interface APIs, please - * see .../vnet/vnet/{interface.api,interface_api.c} - * IP APIs: see .../vnet/vnet/ip/{ip.api, ip_api.c} - * TAP APIs: see .../vnet/vnet/unix/{tap.api, tap_api.c} - * VXLAN APIs: see .../vnet/vnet/vxlan/{vxlan.api, vxlan_api.c} + * see .../src/vnet/{interface.api,interface_api.c} + * IP APIs: see .../src/vnet/ip/{ip.api, ip_api.c} + * TAP APIs: see .../src/vnet/unix/{tap.api, tap_api.c} + * VXLAN APIs: see .../src/vnet/vxlan/{vxlan.api, vxlan_api.c} * AF-PACKET APIs: ... see /vnet/devices/af_packet/{af_packet.api, af_packet_api.c} - * NETMAP APIs: see ... /vnet/vnet/devices/netmap/{netmap.api, netmap_api.c} + * NETMAP APIs: see ... /src/vnet/devices/netmap/{netmap.api, netmap_api.c} * VHOST-USER APIs: see .../vnet/devices/virtio/{vhost_user.api, vhost_user_api.c} - * VXLAN GPE APIs: see .../vnet/vnet/vxlan-gpe/{vxlan_gpe.api, vxlan_gpe_api.c} - * GRE APIs: see .../vnet/vnet/gre/{gre.api, gre_api.c} - * L2TP APIs: see .../vnet/vnet/l2tp/{l2tp.api, l2tp_api.c} - * BFD APIs: see .../vnet/vnet/bfd/{bfd.api, bfd_api.c} - * IPSEC APIs: see .../vnet/vnet/ipsec/{ipsec.api, ipsec_api.c} - * IPSEC-GRE APIs: see .../vnet/vnet/ipsec-gre/{ipsec_gre.api, ipsec_gre_api.c} - * LISP APIs: see .../vnet/vnet/lisp/{lisp.api, lisp_api.c} - * LISP-GPE APIs: see .../vnet/vnet/lisp-gpe/{lisp_gpe.api, lisp_gpe_api.c} + * VXLAN GPE APIs: see .../src/vnet/vxlan-gpe/{vxlan_gpe.api, vxlan_gpe_api.c} + * GRE APIs: see .../src/vnet/gre/{gre.api, gre_api.c} + * L2 APIs: see .../src/vnet/l2/{l2.api, l2_api.c} + * L2TP APIs: see .../src/vnet/l2tp/{l2tp.api, l2tp_api.c} + * BFD APIs: see .../src/vnet/bfd/{bfd.api, bfd_api.c} + * IPSEC APIs: see .../src/vnet/ipsec/{ipsec.api, ipsec_api.c} + * IPSEC-GRE APIs: see .../src/vnet/ipsec-gre/{ipsec_gre.api, ipsec_gre_api.c} + * LISP APIs: see .../src/vnet/lisp/{lisp.api, lisp_api.c} + * LISP-GPE APIs: see .../src/vnet/lisp-gpe/{lisp_gpe.api, lisp_gpe_api.c} + * MPLS APIs: see .../src/vnet/mpls/{mpls.api, mpls_api.c} + * SR APIs: see .../src/vnet/sr/{sr.api, sr_api.c} * DPDK APIs: ... see /src/vnet/devices/dpdk/{dpdk.api, dpdk_api.c} */ @@ -90,231 +93,6 @@ define sw_interface_set_mpls_enable_reply i32 retval; }; -/** \brief MPLS Route Add / del route - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param mr_label - The MPLS label value - @param mr_eos - The End of stack bit - @param mr_table_id - The MPLS table-id the route is added in - @param mr_classify_table_index - If this is a classify route, - this is the classify table index - @param mr_create_table_if_needed - If the MPLS or IP tables do not exist, - create them - @param mr_is_add - Is this a route add or delete - @param mr_is_classify - Is this route result a classify - @param mr_is_multipath - Is this route update a multipath - i.e. is this - a path addition to an existing route - @param mr_is_resolve_host - Recurse resolution constraint via a host prefix - @param mr_is_resolve_attached - Recurse resolution constraint via attached prefix - @param mr_next_hop_proto_is_ip4 - The next-hop is IPV4 - @param mr_next_hop_weight - The weight, for UCMP - @param mr_next_hop[16] - the nextop address - @param mr_next_hop_sw_if_index - the next-hop SW interface - @param mr_next_hop_table_id - the next-hop table-id (if appropriate) - @param mr_next_hop_n_out_labels - the number of labels in the label stack - @param mr_next_hop_out_label_stack - the next-hop output label stack, outer most first - @param next_hop_via_label - The next-hop is a resolved via a local label -*/ -define mpls_route_add_del -{ - u32 client_index; - u32 context; - u32 mr_label; - u8 mr_eos; - u32 mr_table_id; - u32 mr_classify_table_index; - u8 mr_create_table_if_needed; - u8 mr_is_add; - u8 mr_is_classify; - u8 mr_is_multipath; - u8 mr_is_resolve_host; - u8 mr_is_resolve_attached; - u8 mr_next_hop_proto_is_ip4; - u8 mr_next_hop_weight; - u8 mr_next_hop[16]; - u8 mr_next_hop_n_out_labels; - u32 mr_next_hop_sw_if_index; - u32 mr_next_hop_table_id; - u32 mr_next_hop_via_label; - u32 mr_next_hop_out_label_stack[mr_next_hop_n_out_labels]; -}; - -/** \brief Reply for MPLS route add / del request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_route_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Dump MPLS fib table - @param client_index - opaque cookie to identify the sender -*/ -define mpls_fib_dump -{ - u32 client_index; - u32 context; -}; - -/** \brief FIB path - @param sw_if_index - index of the interface - @param weight - The weight, for UCMP - @param is_local - local if non-zero, else remote - @param is_drop - Drop the packet - @param is_unreach - Drop the packet and rate limit send ICMP unreachable - @param is_prohibit - Drop the packet and rate limit send ICMP prohibited - @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2 - @param next_hop[16] - the next hop address - - WARNING: this type is replicated, pending cleanup completion - -*/ -typeonly manual_print manual_endian define fib_path2 -{ - u32 sw_if_index; - u32 weight; - u8 is_local; - u8 is_drop; - u8 is_unreach; - u8 is_prohibit; - u8 afi; - u8 next_hop[16]; -}; - -/** \brief mpls FIB table response - @param table_id - MPLS fib table id - @param s_bit - End-of-stack bit - @param label - MPLS label value - @param count - the number of fib_path in path - @param path - array of of fib_path structures -*/ -manual_endian manual_print define mpls_fib_details -{ - u32 context; - u32 table_id; - u8 eos_bit; - u32 label; - u32 count; - vl_api_fib_path2_t path[count]; -}; - -/** \brief Bind/Unbind an MPLS local label to an IP prefix. i.e. create - a per-prefix label entry. - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param mb_mpls_table_id - The MPLS table-id the MPLS entry will be added in - @param mb_label - The MPLS label value to bind - @param mb_ip_table_id - The IP table-id of the IP prefix to bind to. - @param mb_create_table_if_needed - Create either/both tables if required. - @param mb_is_bind - Bind or unbind - @param mb_is_ip4 - The prefix to bind to is IPv4 - @param mb_address_length - Length of IP prefix - @param mb_address[16] - IP prefix/ -*/ -define mpls_ip_bind_unbind -{ - u32 client_index; - u32 context; - u32 mb_mpls_table_id; - u32 mb_label; - u32 mb_ip_table_id; - u8 mb_create_table_if_needed; - u8 mb_is_bind; - u8 mb_is_ip4; - u8 mb_address_length; - u8 mb_address[16]; -}; - -/** \brief Reply for MPLS IP bind/unbind request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_ip_bind_unbind_reply -{ - u32 context; - i32 retval; -}; - -/** \brief MPLS tunnel Add / del route - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param mt_is_add - Is this a route add or delete - @param mt_sw_if_index - The SW interface index of the tunnel to delete - @param mt_next_hop_proto_is_ip4 - The next-hop is IPV4 - @param mt_next_hop_weight - The weight, for UCMP - @param mt_next_hop[16] - the nextop address - @param mt_next_hop_sw_if_index - the next-hop SW interface - @param mt_next_hop_table_id - the next-hop table-id (if appropriate) - @param mt_next_hop_n_out_labels - the number of next-hop output labels - @param mt_next_hop_out_label_stack - the next-hop output label stack, outer most first -*/ -define mpls_tunnel_add_del -{ - u32 client_index; - u32 context; - u32 mt_sw_if_index; - u8 mt_is_add; - u8 mt_l2_only; - u8 mt_next_hop_proto_is_ip4; - u8 mt_next_hop_weight; - u8 mt_next_hop[16]; - u8 mt_next_hop_n_out_labels; - u32 mt_next_hop_sw_if_index; - u32 mt_next_hop_table_id; - u32 mt_next_hop_out_label_stack[mt_next_hop_n_out_labels]; -}; - -/** \brief Reply for MPLS tunnel add / del request - @param context - returned sender context, to match reply w/ request - @param retval - return code - @param sw_if_index - SW interface index of the tunnel created -*/ -define mpls_tunnel_add_del_reply -{ - u32 context; - i32 retval; - u32 sw_if_index; -}; - -/** \brief Dump mpls eth tunnel table - @param client_index - opaque cookie to identify the sender - @param tunnel_index - eth tunnel identifier or -1 in case of all tunnels -*/ -define mpls_tunnel_dump -{ - u32 client_index; - u32 context; - i32 tunnel_index; -}; - -/** \brief mpls eth tunnel operational state response - @param tunnel_index - eth tunnel identifier - @param intfc_address - interface ipv4 addr - @param mask_width - interface ipv4 addr mask - @param hw_if_index - interface id - @param l2_only - - @param tunnel_dst_mac - - @param tx_sw_if_index - - @param encap_index - reference to mpls label table - @param nlabels - number of resolved labels - @param labels - resolved labels -*/ -define mpls_tunnel_details -{ - u32 context; - u32 tunnel_index; - u8 mt_l2_only; - u8 mt_sw_if_index; - u8 mt_next_hop_proto_is_ip4; - u8 mt_next_hop[16]; - u32 mt_next_hop_sw_if_index; - u32 mt_next_hop_table_id; - u32 mt_next_hop_n_labels; - u32 mt_next_hop_out_labels[mt_next_hop_n_labels]; -}; - /** \brief Proxy ARP add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -797,102 +575,6 @@ define l2_patch_add_del_reply i32 retval; }; -/** \brief IPv6 segment routing tunnel add / del request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add the tunnel if non-zero, else delete it - @param name[] - tunnel name (len. 64) - @param src_address[] - - @param dst_address[] - - @param dst_mask_width - - @param inner_vrf_id - - @param outer_vrf_id - - @param flags_net_byte_order - - @param n_segments - - @param n_tags - - @param segs_and_tags[] - - @param policy_name[] - name of policy to associate this tunnel to (len. 64) -*/ -define sr_tunnel_add_del -{ - u32 client_index; - u32 context; - u8 is_add; - u8 name[64]; - u8 src_address[16]; - u8 dst_address[16]; - u8 dst_mask_width; - u32 inner_vrf_id; - u32 outer_vrf_id; - u16 flags_net_byte_order; - u8 n_segments; - u8 n_tags; - u8 policy_name[64]; - u8 segs_and_tags[0]; -}; - -/** \brief IPv6 segment routing tunnel add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_tunnel_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief IPv6 segment routing policy add / del request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add the tunnel if non-zero, else delete it - @param name[] - policy name (len. 64) - @param tunnel_names[] - -*/ -define sr_policy_add_del -{ - u32 client_index; - u32 context; - u8 is_add; - u8 name[64]; - u8 tunnel_names[0]; -}; - -/** \brief IPv6 segment routing policy add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_policy_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief IPv6 segment routing multicast map to policy add / del request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add the tunnel if non-zero, else delete it - @param multicast_address[] - IP6 multicast address - @param policy_name[] = policy name (len.64) -*/ -define sr_multicast_map_add_del -{ - u32 client_index; - u32 context; - u8 is_add; - u8 multicast_address[16]; - u8 policy_name[64]; -}; - -/** \brief IPv6 segment routing multicast map to policy add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_multicast_map_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Interface set vpath request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -973,95 +655,6 @@ define sw_interface_set_l2_bridge_reply i32 retval; }; -/** \brief L2 FIB add entry request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param mac - the entry's mac address - @param bd_id - the entry's bridge domain id - @param sw_if_index - the interface - @param is_add - If non zero add the entry, else delete it - @param static_mac - - @param filter_mac - -*/ -define l2fib_add_del -{ - u32 client_index; - u32 context; - u64 mac; - u32 bd_id; - u32 sw_if_index; - u8 is_add; - u8 static_mac; - u8 filter_mac; - u8 bvi_mac; -}; - -/** \brief L2 FIB add entry response - @param context - sender context, to match reply w/ request - @param retval - return code for the add l2fib entry request -*/ -define l2fib_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief Set L2 flags request !!! TODO - need more info, feature bits in l2_input.h - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - interface - @param is_set - if non-zero, set the bits, else clear them - @param feature_bitmap - non-zero bits to set or clear -*/ -define l2_flags -{ - u32 client_index; - u32 context; - u32 sw_if_index; - u8 is_set; - u32 feature_bitmap; -}; - -/** \brief Set L2 bits response - @param context - sender context, to match reply w/ request - @param retval - return code for the set l2 bits request -*/ -define l2_flags_reply -{ - u32 context; - i32 retval; - u32 resulting_feature_bitmap; -}; - -/** \brief Set bridge flags (such as L2_LEARN, L2_FWD, L2_FLOOD, - L2_UU_FLOOD, or L2_ARP_TERM) request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param bd_id - the bridge domain to set the flags for - @param is_set - if non-zero, set the flags, else clear them - @param feature_bitmap - bits that are non-zero to set or clear -*/ -define bridge_flags -{ - u32 client_index; - u32 context; - u32 bd_id; - u8 is_set; - u32 feature_bitmap; -}; - -/** \brief Set bridge flags response - @param context - sender context, to match reply w/ request - @param retval - return code for the set bridge flags request - @param resulting_feature_bitmap - the feature bitmap value after the request is implemented -*/ -define bridge_flags_reply -{ - u32 context; - i32 retval; - u32 resulting_feature_bitmap; -}; - /** \brief Set bridge domain ip to mac entry request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1335,26 +928,6 @@ define dhcp_proxy_config_2_reply i32 retval; }; -/** \brief L2 fib clear table request, clear all mac entries in the l2 fib - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request -*/ -define l2_fib_clear_table -{ - u32 client_index; - u32 context; -}; - -/** \brief L2 fib clear table response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_fib_clear_table_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 interface ethernet flow point filtering enable/disable request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1463,36 +1036,6 @@ define show_version_reply u8 build_directory[256]; }; -/** \brief l2 fib table entry structure - @param bd_id - the l2 fib / bridge domain table id - @param mac - the entry's mac address - @param sw_if_index - index of the interface - @param static_mac - the entry is statically configured. - @param filter_mac - the entry is a mac filter entry. - @param bvi_mac - the mac address is a bridge virtual interface -*/ -define l2_fib_table_entry -{ - u32 context; - u32 bd_id; - u64 mac; - u32 sw_if_index; - u8 static_mac; - u8 filter_mac; - u8 bvi_mac; -}; - -/** \brief Dump l2 fib (aka bridge domain) table - @param client_index - opaque cookie to identify the sender - @param bd_id - the l2 fib / bridge domain table identifier -*/ -define l2_fib_table_dump -{ - u32 client_index; - u32 context; - u32 bd_id; -}; - /* Gross kludge, DGMS */ define interface_name_renumber { @@ -1600,91 +1143,6 @@ define ip6_nd_event u8 mac_ip; }; -/** \brief L2 bridge domain add or delete request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param bd_id - the bridge domain to create - @param flood - enable/disable bcast/mcast flooding in the bd - @param uu_flood - enable/disable uknown unicast flood in the bd - @param forward - enable/disable forwarding on all interfaces in the bd - @param learn - enable/disable learning on all interfaces in the bd - @param arp_term - enable/disable arp termination in the bd - @param mac_age - mac aging time in min, 0 for disabled - @param is_add - add or delete flag -*/ -define bridge_domain_add_del -{ - u32 client_index; - u32 context; - u32 bd_id; - u8 flood; - u8 uu_flood; - u8 forward; - u8 learn; - u8 arp_term; - u8 mac_age; - u8 is_add; -}; - -/** \brief L2 bridge domain add or delete response - @param context - sender context, to match reply w/ request - @param retval - return code for the set bridge flags request -*/ -define bridge_domain_add_del_reply -{ - u32 context; - i32 retval; -}; - -/** \brief L2 bridge domain request operational state details - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param bd_id - the bridge domain id desired or ~0 to request all bds -*/ -define bridge_domain_dump -{ - u32 client_index; - u32 context; - u32 bd_id; -}; - -/** \brief L2 bridge domain operational state response - @param bd_id - the bridge domain id - @param flood - bcast/mcast flooding state on all interfaces in the bd - @param uu_flood - uknown unicast flooding state on all interfaces in the bd - @param forward - forwarding state on all interfaces in the bd - @param learn - learning state on all interfaces in the bd - @param arp_term - arp termination state on all interfaces in the bd - @param mac_age - mac aging time in min, 0 for disabled - @param n_sw_ifs - number of sw_if_index's in the domain -*/ -define bridge_domain_details -{ - u32 context; - u32 bd_id; - u8 flood; - u8 uu_flood; - u8 forward; - u8 learn; - u8 arp_term; - u8 mac_age; - u32 bvi_sw_if_index; - u32 n_sw_ifs; -}; - -/** \brief L2 bridge domain sw interface operational state response - @param bd_id - the bridge domain id - @param sw_if_index - sw_if_index in the domain - @param shg - split horizon group for the interface -*/ -define bridge_domain_sw_if_details -{ - u32 context; - u32 bd_id; - u32 sw_if_index; - u8 shg; -}; - /** \brief DHCP Client config add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request -- cgit 1.2.3-korg From adec5878d3ac8399a3202728b0962a350939e7d9 Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Wed, 25 Jan 2017 08:50:53 +0100 Subject: API refactoring : l2 (add) Change-Id: I693a73ba9a5e3b0cb5d2a6c5d363f671e19c1f24 Signed-off-by: Pavel Kotucek --- src/vnet/l2/l2.api | 65 ++++++++++++++++++++++++++++++++++++++++ src/vnet/l2/l2_api.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/vpp/api/api.c | 82 --------------------------------------------------- src/vpp/api/vpe.api | 65 ---------------------------------------- 4 files changed, 147 insertions(+), 148 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 5b24f259..061990c0 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -260,6 +260,71 @@ define bridge_flags_reply u32 resulting_feature_bitmap; }; +/** \brief L2 interface vlan tag rewrite configure request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface the operation is applied to + @param vtr_op - Choose from l2_vtr_op_t enum values + @param push_dot1q - first pushed flag dot1q id set, else dot1ad + @param tag1 - Needed for any push or translate vtr op + @param tag2 - Needed for any push 2 or translate x-2 vtr ops +*/ +define l2_interface_vlan_tag_rewrite +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u32 vtr_op; + u32 push_dot1q; // ethertype of first pushed tag is dot1q/dot1ad + u32 tag1; // first pushed tag + u32 tag2; // second pushed tag +}; + +/** \brief L2 interface vlan tag rewrite response + @param context - sender context, to match reply w/ request + @param retval - return code for the request +*/ +define l2_interface_vlan_tag_rewrite_reply +{ + u32 context; + i32 retval; +}; + +/** \brief L2 interface pbb tag rewrite configure request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface the operation is applied to + @param vtr_op - Choose from l2_vtr_op_t enum values + @param inner_tag - needed for translate_qinq vtr op only + @param outer_tag - needed for translate_qinq vtr op only + @param b_dmac - B-tag remote mac address, needed for any push or translate_qinq vtr op + @param b_smac - B-tag local mac address, needed for any push or translate qinq vtr op + @param b_vlanid - B-tag vlanid, needed for any push or translate qinq vtr op + @param i_sid - I-tag service id, needed for any push or translate qinq vtr op +*/ +define l2_interface_pbb_tag_rewrite +{ + u32 client_index; + u32 context; + u32 sw_if_index; + u32 vtr_op; + u16 outer_tag; + u8 b_dmac[6]; + u8 b_smac[6]; + u16 b_vlanid; + u32 i_sid; +}; + +/** \brief L2 interface pbb tag rewrite response + @param context - sender context, to match reply w/ request + @param retval - return code for the request +*/ +define l2_interface_pbb_tag_rewrite_reply +{ + u32 context; + i32 retval; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index ef33509c..a3cc49bf 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -54,7 +55,9 @@ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ _(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ -_(BRIDGE_FLAGS, bridge_flags) +_(BRIDGE_FLAGS, bridge_flags) \ +_(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ +_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) static void send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context, @@ -454,6 +457,84 @@ out: /* *INDENT-ON* */ } +static void + vl_api_l2_interface_vlan_tag_rewrite_t_handler + (vl_api_l2_interface_vlan_tag_rewrite_t * mp) +{ + int rv = 0; + vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp; + vnet_main_t *vnm = vnet_get_main (); + vlib_main_t *vm = vlib_get_main (); + u32 vtr_op; + + VALIDATE_SW_IF_INDEX (mp); + + vtr_op = ntohl (mp->vtr_op); + + /* The L2 code is unsuspicious */ + switch (vtr_op) + { + case L2_VTR_DISABLED: + case L2_VTR_PUSH_1: + case L2_VTR_PUSH_2: + case L2_VTR_POP_1: + case L2_VTR_POP_2: + case L2_VTR_TRANSLATE_1_1: + case L2_VTR_TRANSLATE_1_2: + case L2_VTR_TRANSLATE_2_1: + case L2_VTR_TRANSLATE_2_2: + break; + + default: + rv = VNET_API_ERROR_INVALID_VALUE; + goto bad_sw_if_index; + } + + rv = l2vtr_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op, + ntohl (mp->push_dot1q), ntohl (mp->tag1), + ntohl (mp->tag2)); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY); +} + +static void + vl_api_l2_interface_pbb_tag_rewrite_t_handler + (vl_api_l2_interface_pbb_tag_rewrite_t * mp) +{ + vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp; + vnet_main_t *vnm = vnet_get_main (); + vlib_main_t *vm = vlib_get_main (); + u32 vtr_op; + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + vtr_op = ntohl (mp->vtr_op); + + switch (vtr_op) + { + case L2_VTR_DISABLED: + case L2_VTR_PUSH_2: + case L2_VTR_POP_2: + case L2_VTR_TRANSLATE_2_1: + break; + + default: + rv = VNET_API_ERROR_INVALID_VALUE; + goto bad_sw_if_index; + } + + rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op, + mp->b_dmac, mp->b_smac, ntohs (mp->b_vlanid), + ntohl (mp->i_sid), ntohs (mp->outer_tag)); + + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY); +} + /* * l2_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 6317f557..e6227a68 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -134,7 +133,6 @@ _(ADD_NODE_NEXT, add_node_next) \ _(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ _(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \ -_(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ _(SHOW_VERSION, show_version) \ _(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ @@ -160,7 +158,6 @@ _(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, \ _(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, \ ip_source_and_port_range_check_interface_add_del) \ _(DELETE_SUBIF, delete_subif) \ -_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \ _(PUNT, punt) \ _(FEATURE_ENABLE_DISABLE, feature_enable_disable) @@ -1316,48 +1313,6 @@ vl_api_l2_interface_efp_filter_t_handler (vl_api_l2_interface_efp_filter_t * REPLY_MACRO (VL_API_L2_INTERFACE_EFP_FILTER_REPLY); } -static void - vl_api_l2_interface_vlan_tag_rewrite_t_handler - (vl_api_l2_interface_vlan_tag_rewrite_t * mp) -{ - int rv = 0; - vl_api_l2_interface_vlan_tag_rewrite_reply_t *rmp; - vnet_main_t *vnm = vnet_get_main (); - vlib_main_t *vm = vlib_get_main (); - u32 vtr_op; - - VALIDATE_SW_IF_INDEX (mp); - - vtr_op = ntohl (mp->vtr_op); - - /* The L2 code is unsuspicious */ - switch (vtr_op) - { - case L2_VTR_DISABLED: - case L2_VTR_PUSH_1: - case L2_VTR_PUSH_2: - case L2_VTR_POP_1: - case L2_VTR_POP_2: - case L2_VTR_TRANSLATE_1_1: - case L2_VTR_TRANSLATE_1_2: - case L2_VTR_TRANSLATE_2_1: - case L2_VTR_TRANSLATE_2_2: - break; - - default: - rv = VNET_API_ERROR_INVALID_VALUE; - goto bad_sw_if_index; - } - - rv = l2vtr_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op, - ntohl (mp->push_dot1q), ntohl (mp->tag1), - ntohl (mp->tag2)); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_L2_INTERFACE_VLAN_TAG_REWRITE_REPLY); -} - static void vl_api_show_version_t_handler (vl_api_show_version_t * mp) { @@ -2497,43 +2452,6 @@ vl_api_delete_subif_t_handler (vl_api_delete_subif_t * mp) REPLY_MACRO (VL_API_DELETE_SUBIF_REPLY); } -static void - vl_api_l2_interface_pbb_tag_rewrite_t_handler - (vl_api_l2_interface_pbb_tag_rewrite_t * mp) -{ - vl_api_l2_interface_pbb_tag_rewrite_reply_t *rmp; - vnet_main_t *vnm = vnet_get_main (); - vlib_main_t *vm = vlib_get_main (); - u32 vtr_op; - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - vtr_op = ntohl (mp->vtr_op); - - switch (vtr_op) - { - case L2_VTR_DISABLED: - case L2_VTR_PUSH_2: - case L2_VTR_POP_2: - case L2_VTR_TRANSLATE_2_1: - break; - - default: - rv = VNET_API_ERROR_INVALID_VALUE; - goto bad_sw_if_index; - } - - rv = l2pbb_configure (vm, vnm, ntohl (mp->sw_if_index), vtr_op, - mp->b_dmac, mp->b_smac, ntohs (mp->b_vlanid), - ntohl (mp->i_sid), ntohs (mp->outer_tag)); - - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_L2_INTERFACE_PBB_TAG_REWRITE_REPLY); - -} - static void vl_api_punt_t_handler (vl_api_punt_t * mp) { diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 3a35a54a..981ae25e 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -797,36 +797,6 @@ define l2_interface_efp_filter_reply i32 retval; }; -/** \brief L2 interface vlan tag rewrite configure request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - interface the operation is applied to - @param vtr_op - Choose from l2_vtr_op_t enum values - @param push_dot1q - first pushed flag dot1q id set, else dot1ad - @param tag1 - Needed for any push or translate vtr op - @param tag2 - Needed for any push 2 or translate x-2 vtr ops -*/ -define l2_interface_vlan_tag_rewrite -{ - u32 client_index; - u32 context; - u32 sw_if_index; - u32 vtr_op; - u32 push_dot1q; // ethertype of first pushed tag is dot1q/dot1ad - u32 tag1; // first pushed tag - u32 tag2; // second pushed tag -}; - -/** \brief L2 interface vlan tag rewrite response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_interface_vlan_tag_rewrite_reply -{ - u32 context; - i32 retval; -}; - define create_subif { u32 client_index; @@ -1475,41 +1445,6 @@ define delete_subif_reply { i32 retval; }; -/** \brief L2 interface pbb tag rewrite configure request - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param sw_if_index - interface the operation is applied to - @param vtr_op - Choose from l2_vtr_op_t enum values - @param inner_tag - needed for translate_qinq vtr op only - @param outer_tag - needed for translate_qinq vtr op only - @param b_dmac - B-tag remote mac address, needed for any push or translate_qinq vtr op - @param b_smac - B-tag local mac address, needed for any push or translate qinq vtr op - @param b_vlanid - B-tag vlanid, needed for any push or translate qinq vtr op - @param i_sid - I-tag service id, needed for any push or translate qinq vtr op -*/ -define l2_interface_pbb_tag_rewrite -{ - u32 client_index; - u32 context; - u32 sw_if_index; - u32 vtr_op; - u16 outer_tag; - u8 b_dmac[6]; - u8 b_smac[6]; - u16 b_vlanid; - u32 i_sid; -}; - -/** \brief L2 interface pbb tag rewrite response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_interface_pbb_tag_rewrite_reply -{ - u32 context; - i32 retval; -}; - /** \brief Punt traffic to the host @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request -- cgit 1.2.3-korg From 681abe46c9ea30e5c386db74c997714433470c4c Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Wed, 15 Feb 2017 09:01:01 -0500 Subject: l2 input: avoid per-packet trace checks in the fast path Change-Id: Ib0c8572773499d8dd4d81b3a565c24412ccc3510 Signed-off-by: Dave Barach --- src/vnet/l2/l2_fwd.c | 20 ++++++++++++++------ src/vnet/l2/l2_input.c | 21 ++++++++++++++------- src/vnet/l2/l2_learn.c | 19 +++++++++++++------ src/vnet/l2/l2_output.c | 19 +++++++++++++------ 4 files changed, 54 insertions(+), 25 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c index 710a9d9e..f7e2ccb6 100644 --- a/src/vnet/l2/l2_fwd.c +++ b/src/vnet/l2/l2_fwd.c @@ -195,9 +195,9 @@ l2fwd_process (vlib_main_t * vm, } -static uword -l2fwd_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static_always_inline uword +l2fwd_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame, int do_trace) { u32 n_left_from, *from, *to_next; l2fwd_next_t next_index; @@ -281,7 +281,7 @@ l2fwd_node_fn (vlib_main_t * vm, h2 = vlib_buffer_get_current (b2); h3 = vlib_buffer_get_current (b3); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + if (do_trace) { if (b0->flags & VLIB_BUFFER_IS_TRACED) { @@ -388,8 +388,7 @@ l2fwd_node_fn (vlib_main_t * vm, h0 = vlib_buffer_get_current (b0); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { l2fwd_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); t->sw_if_index = sw_if_index0; @@ -420,6 +419,15 @@ l2fwd_node_fn (vlib_main_t * vm, return frame->n_vectors; } +static uword +l2fwd_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + return l2fwd_node_inline (vm, node, frame, 1 /* do_trace */ ); + return l2fwd_node_inline (vm, node, frame, 0 /* do_trace */ ); +} + /* *INDENT-OFF* */ VLIB_REGISTER_NODE (l2fwd_node,static) = { .function = l2fwd_node_fn, diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index a104ec9e..ead9ca85 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -222,10 +222,10 @@ classify_and_dispatch (vlib_main_t * vm, feature_bitmap); } - -static uword -l2input_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static_always_inline uword +l2input_node_inline (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame, + int do_trace) { u32 n_left_from, *from, *to_next; l2input_next_t next_index; @@ -294,7 +294,7 @@ l2input_node_fn (vlib_main_t * vm, b2 = vlib_get_buffer (vm, bi2); b3 = vlib_get_buffer (vm, bi3); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + if (do_trace) { /* RX interface handles */ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; @@ -373,8 +373,7 @@ l2input_node_fn (vlib_main_t * vm, b0 = vlib_get_buffer (vm, bi0); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { ethernet_header_t *h0 = vlib_buffer_get_current (b0); l2input_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); @@ -401,6 +400,14 @@ l2input_node_fn (vlib_main_t * vm, return frame->n_vectors; } +static uword +l2input_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + return l2input_node_inline (vm, node, frame, 1 /* do_trace */ ); + return l2input_node_inline (vm, node, frame, 0 /* do_trace */ ); +} /* *INDENT-OFF* */ VLIB_REGISTER_NODE (l2input_node) = { diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 7f19f936..afe7f478 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -231,9 +231,9 @@ done: } -static uword -l2learn_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static_always_inline uword +l2learn_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame, int do_trace) { u32 n_left_from, *from, *to_next; l2learn_next_t next_index; @@ -320,7 +320,7 @@ l2learn_node_fn (vlib_main_t * vm, h2 = vlib_buffer_get_current (b2); h3 = vlib_buffer_get_current (b3); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + if (do_trace) { if (b0->flags & VLIB_BUFFER_IS_TRACED) { @@ -426,8 +426,7 @@ l2learn_node_fn (vlib_main_t * vm, h0 = vlib_buffer_get_current (b0); - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { l2learn_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); t->sw_if_index = sw_if_index0; @@ -461,6 +460,14 @@ l2learn_node_fn (vlib_main_t * vm, return frame->n_vectors; } +static uword +l2learn_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + return l2learn_node_inline (vm, node, frame, 1 /* do_trace */ ); + return l2learn_node_inline (vm, node, frame, 0 /* do_trace */ ); +} /* *INDENT-OFF* */ VLIB_REGISTER_NODE (l2learn_node,static) = { diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index 953fcb02..acfe3aba 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -140,9 +140,9 @@ l2output_vtr (vlib_node_runtime_t * node, l2_output_config_t * config, static vlib_node_registration_t l2output_node; -static uword -l2output_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) +static_always_inline uword +l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame, int do_trace) { u32 n_left_from, *from, *to_next; l2output_next_t next_index; @@ -214,7 +214,7 @@ l2output_node_fn (vlib_main_t * vm, sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_TX]; sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_TX]; - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + if (do_trace) { h0 = vlib_buffer_get_current (b0); h1 = vlib_buffer_get_current (b1); @@ -378,8 +378,7 @@ l2output_node_fn (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) + if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { l2output_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); @@ -434,6 +433,14 @@ l2output_node_fn (vlib_main_t * vm, return frame->n_vectors; } +static uword +l2output_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + return l2output_node_inline (vm, node, frame, 1 /* do_trace */ ); + return l2output_node_inline (vm, node, frame, 0 /* do_trace */ ); +} /* *INDENT-OFF* */ VLIB_REGISTER_NODE (l2output_node,static) = { -- cgit 1.2.3-korg From 65e845785f21e6b43c026f092e982171eec1f641 Mon Sep 17 00:00:00 2001 From: Pavel Kotucek Date: Mon, 16 Jan 2017 17:01:56 +0100 Subject: VPP-540 : pbb tag rewrite details Extended sw_interface_dump to provide 802.1ah (pbb) tag rewrite info if present. Extended log "l2-output" to provide raw data to display result of prospetive pbb tag rewrite. Tracing is moved after l2output_vtr to show these changes. Change-Id: I8b7cb865dc67ce21afab402cc086dac35f7c0f07 Signed-off-by: Pavel Kotucek --- src/vat/api_format.c | 13 +++++ src/vnet/ethernet/format.c | 38 ++++----------- src/vnet/interface.api | 19 +++++++- src/vnet/interface_api.c | 20 ++++++++ src/vnet/l2/l2_output.c | 115 +++++++++++++++++++++++++-------------------- src/vnet/l2/l2_vtr.c | 66 ++++++++++++++++++++++++++ src/vnet/l2/l2_vtr.h | 11 +++++ 7 files changed, 200 insertions(+), 82 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index e3d8ab48..0f035279 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -914,6 +914,19 @@ static void vl_api_sw_interface_details_t_handler_json ntohl (mp->vtr_push_dot1q)); vat_json_object_add_uint (node, "vtr_tag1", ntohl (mp->vtr_tag1)); vat_json_object_add_uint (node, "vtr_tag2", ntohl (mp->vtr_tag2)); + if (mp->sub_dot1ah) + { + vat_json_object_add_string_copy (node, "pbb_vtr_dmac", + format (0, "%U", + format_ethernet_address, + &mp->b_dmac)); + vat_json_object_add_string_copy (node, "pbb_vtr_smac", + format (0, "%U", + format_ethernet_address, + &mp->b_smac)); + vat_json_object_add_uint (node, "pbb_vtr_b_vlanid", mp->b_vlanid); + vat_json_object_add_uint (node, "pbb_vtr_i_sid", mp->i_sid); + } } static void vl_api_sw_interface_set_flags_t_handler diff --git a/src/vnet/ethernet/format.c b/src/vnet/ethernet/format.c index 4edef5ad..5b589998 100644 --- a/src/vnet/ethernet/format.c +++ b/src/vnet/ethernet/format.c @@ -87,30 +87,6 @@ format_ethernet_vlan_tci (u8 * s, va_list * va) return s; } -u8 * -format_ethernet_pbb (u8 * s, va_list * va) -{ - u32 b_tag = va_arg (*va, u32); - u32 i_tag = va_arg (*va, u32); - u32 vid = (b_tag & 0xfff); - u32 bdei = (b_tag >> 12) & 1; - u32 bpcp = (b_tag >> 13); - u32 sid = (i_tag & 0xffffff); - u8 ires = (i_tag >> 24) & 3; - u8 iuca = (i_tag >> 27) & 1; - u8 idei = (i_tag >> 28) & 1; - u8 ipcp = (i_tag >> 29); - - s = - format (s, "B_tag %04X (vid %d, dei %d, pcp %d), ", b_tag, vid, bdei, - bpcp); - s = - format (s, "I_tag %08X (sid %d, res %d, dei %d, pcp %d)", i_tag, sid, - ires, iuca, idei, ipcp); - - return s; -} - u8 * format_ethernet_header_with_length (u8 * s, va_list * args) { @@ -177,10 +153,16 @@ format_ethernet_header_with_length (u8 * s, va_list * args) } else { - s = format (s, "\n%UPBB header : %U", format_white_space, indent, - format_ethernet_pbb, - clib_net_to_host_u16 (ph->priority_dei_id), - clib_net_to_host_u32 (ph->priority_dei_uca_res_sid)); + s = + format (s, " %s b-tag %04X", + (clib_net_to_host_u16 (ph->b_type) == + ETHERNET_TYPE_DOT1AD) ? "802.1ad" : "", + clib_net_to_host_u16 (ph->priority_dei_id)); + s = + format (s, " %s i-tag %08X", + (clib_net_to_host_u16 (ph->i_type) == + ETHERNET_TYPE_DOT1AH) ? "802.1ah" : "", + clib_net_to_host_u32 (ph->priority_dei_uca_res_sid)); } return s; diff --git a/src/vnet/interface.api b/src/vnet/interface.api index 752e79c5..afa8bb5e 100644 --- a/src/vnet/interface.api +++ b/src/vnet/interface.api @@ -83,9 +83,10 @@ define want_interface_events_reply @param interface_name - name of the interface @param link_duplex - 1 if half duplex, 2 if full duplex @param link_speed - 1 = 10M, 2 = 100M, 4 = 1G, 8 = 10G, 16 = 40G, 32 = 100G - @param link_MTU - max. transmittion unit + @param link_MTU - max. transmittion unit @param sub_if_id - A number 0-N to uniquely identify this subif on super if - @param sub_dot1ad - 0 = dot1q, 1=dot1ad + @param sub_dot1ad - 0 = dot1q, 1 = dot1ad + @param sub_dot1ah - 1 = dot1ah, 0 = otherwise @param sub_number_of_tags - Number of tags (0 - 2) @param sub_outer_vlan_id @param sub_inner_vlan_id @@ -97,6 +98,11 @@ define want_interface_events_reply @param vtr_push_dot1q @param vtr_tag1 @param vtr_tag2 + @param pbb_outer_tag - translate pbb s-tag + @param pbb_b_dmac[6] - B-tag remote mac address + @param pbb_b_smac[6] - B-tag local mac address + @param pbb_b_vlanid - B-tag vlanid + @param pbb_i_sid - I-tag service id */ define sw_interface_details { @@ -132,6 +138,8 @@ define sw_interface_details /* 0 = dot1q, 1=dot1ad */ u8 sub_dot1ad; + /* 1 = dot1h, 1=otherwise */ + u8 sub_dot1ah; /* Number of tags 0-2 */ u8 sub_number_of_tags; @@ -148,6 +156,13 @@ define sw_interface_details u32 vtr_tag1; // first pushed tag u32 vtr_tag2; // second pushed tag u8 tag[64]; + + /* pbb tag rewrite info */ + u16 outer_tag; + u8 b_dmac[6]; + u8 b_smac[6]; + u16 b_vlanid; + u32 i_sid; }; /* works */ diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 42fd14ee..63f7cad4 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -203,6 +203,26 @@ send_sw_interface_details (vpe_api_main_t * am, } } + /* pbb tag rewrite data */ + u32 vtr_op = L2_VTR_DISABLED; + u16 outer_tag = 0; + u8 b_dmac[6]; + u8 b_smac[6]; + u16 b_vlanid = 0; + u32 i_sid = 0; + memset (b_dmac, 0, sizeof (b_dmac)); + memset (b_smac, 0, sizeof (b_smac)); + + if (!l2pbb_get (am->vlib_main, am->vnet_main, swif->sw_if_index, + &vtr_op, &outer_tag, b_dmac, b_smac, &b_vlanid, &i_sid)) + { + mp->sub_dot1ah = 1; + clib_memcpy (mp->b_dmac, b_dmac, sizeof (b_dmac)); + clib_memcpy (mp->b_smac, b_smac, sizeof (b_smac)); + mp->b_vlanid = b_vlanid; + mp->i_sid = i_sid; + } + tag = vnet_get_sw_interface_tag (vnm, swif->sw_if_index); if (tag) strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1); diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index acfe3aba..00f22571 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -48,6 +48,7 @@ typedef struct u8 src[6]; u8 dst[6]; u32 sw_if_index; + u8 raw[12]; /* raw data */ } l2output_trace_t; /* packet trace format function */ @@ -58,10 +59,15 @@ format_l2output_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); l2output_trace_t *t = va_arg (*args, l2output_trace_t *); - s = format (s, "l2-output: sw_if_index %d dst %U src %U", + s = format (s, "l2-output: sw_if_index %d dst %U src %U data " + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", t->sw_if_index, format_ethernet_address, t->dst, - format_ethernet_address, t->src); + format_ethernet_address, t->src, + t->raw[0], t->raw[1], t->raw[2], t->raw[3], t->raw[4], + t->raw[5], t->raw[6], t->raw[7], t->raw[8], t->raw[9], + t->raw[10], t->raw[11]); + return s; } @@ -214,46 +220,6 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_TX]; sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_TX]; - if (do_trace) - { - h0 = vlib_buffer_get_current (b0); - h1 = vlib_buffer_get_current (b1); - h2 = vlib_buffer_get_current (b2); - h3 = vlib_buffer_get_current (b3); - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - l2output_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - clib_memcpy (t->src, h0->src_address, 6); - clib_memcpy (t->dst, h0->dst_address, 6); - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - l2output_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->sw_if_index = sw_if_index1; - clib_memcpy (t->src, h1->src_address, 6); - clib_memcpy (t->dst, h1->dst_address, 6); - } - if (b2->flags & VLIB_BUFFER_IS_TRACED) - { - l2output_trace_t *t = - vlib_add_trace (vm, node, b2, sizeof (*t)); - t->sw_if_index = sw_if_index2; - clib_memcpy (t->src, h2->src_address, 6); - clib_memcpy (t->dst, h2->dst_address, 6); - } - if (b3->flags & VLIB_BUFFER_IS_TRACED) - { - l2output_trace_t *t = - vlib_add_trace (vm, node, b3, sizeof (*t)); - t->sw_if_index = sw_if_index3; - clib_memcpy (t->src, h3->src_address, 6); - clib_memcpy (t->dst, h3->dst_address, 6); - } - } - vlib_node_increment_counter (vm, l2output_node.index, L2OUTPUT_ERROR_L2OUTPUT, 4); @@ -314,6 +280,50 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, l2output_vtr (node, config2, feature_bitmap2, b2, &next2); l2output_vtr (node, config3, feature_bitmap3, b3, &next3); + if (do_trace) + { + h0 = vlib_buffer_get_current (b0); + h1 = vlib_buffer_get_current (b1); + h2 = vlib_buffer_get_current (b2); + h3 = vlib_buffer_get_current (b3); + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->sw_if_index = sw_if_index1; + clib_memcpy (t->src, h1->src_address, 6); + clib_memcpy (t->dst, h1->dst_address, 6); + clib_memcpy (t->raw, &h1->type, sizeof (t->raw)); + } + if (b2->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b2, sizeof (*t)); + t->sw_if_index = sw_if_index2; + clib_memcpy (t->src, h2->src_address, 6); + clib_memcpy (t->dst, h2->dst_address, 6); + clib_memcpy (t->raw, &h2->type, sizeof (t->raw)); + } + if (b3->flags & VLIB_BUFFER_IS_TRACED) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b3, sizeof (*t)); + t->sw_if_index = sw_if_index3; + clib_memcpy (t->src, h3->src_address, 6); + clib_memcpy (t->dst, h3->dst_address, 6); + clib_memcpy (t->raw, &h3->type, sizeof (t->raw)); + } + } + /* * Perform the split horizon check * The check can only fail for non-zero shg's @@ -378,16 +388,6 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) - { - l2output_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->sw_if_index = sw_if_index0; - h0 = vlib_buffer_get_current (b0); - clib_memcpy (t->src, h0->src_address, 6); - clib_memcpy (t->dst, h0->dst_address, 6); - } - vlib_node_increment_counter (vm, l2output_node.index, L2OUTPUT_ERROR_L2OUTPUT, 1); @@ -412,6 +412,17 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, l2output_vtr (node, config0, feature_bitmap0, b0, &next0); + if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) + { + l2output_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->sw_if_index = sw_if_index0; + h0 = vlib_buffer_get_current (b0); + clib_memcpy (t->src, h0->src_address, 6); + clib_memcpy (t->dst, h0->dst_address, 6); + clib_memcpy (t->raw, &h0->type, sizeof (t->raw)); + } + /* Perform the split horizon check */ if (PREDICT_FALSE (split_horizon_violation diff --git a/src/vnet/l2/l2_vtr.c b/src/vnet/l2/l2_vtr.c index 95a4f157..e03a4880 100644 --- a/src/vnet/l2/l2_vtr.c +++ b/src/vnet/l2/l2_vtr.c @@ -681,6 +681,72 @@ VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = { }; /* *INDENT-ON* */ +/** + * Get pbb tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 +l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, + u32 * vtr_op, u16 * outer_tag, u8 * b_dmac, u8 * b_smac, + u16 * b_vlanid, u32 * i_sid) +{ + u32 error = 1; + ptr_config_t *in_config; + + if (!vtr_op || !outer_tag || !b_vlanid || !i_sid) + { + clib_warning ("invalid arguments"); + error = VNET_API_ERROR_INVALID_ARGUMENT; + goto done; + } + + *vtr_op = L2_VTR_DISABLED; + *outer_tag = 0; + *b_dmac = 0; + *b_smac = 0; + *b_vlanid = 0; + *i_sid = 0; + + if (sw_if_index >= vec_len (l2output_main.configs)) + { + /* no specific config (return disabled) */ + goto done; + } + + /* Get the config for this interface */ + in_config = + &(vec_elt_at_index (l2output_main.configs, sw_if_index)->input_pbb_vtr); + + if (in_config->push_and_pop_bytes == 0) + { + /* DISABLED */ + goto done; + } + else + { + if (in_config->pop_bytes && in_config->push_bytes) + *vtr_op = L2_VTR_TRANSLATE_2_1; + else if (in_config->pop_bytes) + *vtr_op = L2_VTR_POP_2; + else if (in_config->push_bytes) + *vtr_op = L2_VTR_PUSH_2; + + clib_memcpy (b_dmac, in_config->macs_tags.b_dst_address, + sizeof (b_dmac)); + clib_memcpy (b_smac, in_config->macs_tags.b_src_address, + sizeof (b_smac)); + + *b_vlanid = + clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF; + *i_sid = + clib_host_to_net_u32 (in_config-> + macs_tags.priority_dei_uca_res_sid) & 0xFFFFF; + error = 0; + } +done: + return error; +} + /** * Set subinterface pbb vtr enable/disable. * The CLI format is: diff --git a/src/vnet/l2/l2_vtr.h b/src/vnet/l2/l2_vtr.h index 893b2272..99aedc97 100644 --- a/src/vnet/l2/l2_vtr.h +++ b/src/vnet/l2/l2_vtr.h @@ -258,6 +258,17 @@ u32 l2vtr_get (vlib_main_t * vlib_main, u32 * vtr_op, u32 * push_dot1q, u32 * vtr_tag1, u32 * vtr_tag2); +/** + * Get pbb tag rewrite on the given interface. + * Return 1 if there is an error, 0 if ok + */ +u32 l2pbb_get (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, + u32 sw_if_index, + u32 * vtr_op, + u16 * outer_tag, + u8 * b_dmac, u8 * b_smac, u16 * b_vlanid, u32 * i_sid); + #endif /* included_vnet_l2_vtr_h */ -- cgit 1.2.3-korg From a9a20e7f69f4a91a4d5267ab5ce14125bdc7d6c6 Mon Sep 17 00:00:00 2001 From: Billy McFall Date: Wed, 15 Feb 2017 11:39:12 -0500 Subject: VPP-635: CLI Memory leak with invalid parameter In the CLI parsing, below is a common pattern: /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "x")) x = 1; : else return clib_error_return (0, "unknown input `%U'", format_unformat_error, line_input); } unformat_free (line_input); The 'else' returns if an unknown string is encountered. There a memory leak because the 'unformat_free(line_input)' is not called. There is a large number of instances of this pattern. Replaced the previous pattern with: /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "x")) x = 1; : else { error = clib_error_return (0, "unknown input `%U'", format_unformat_error, line_input); goto done: } } /* ...Remaining code... */ done: unformat_free (line_input); return error; } In multiple files, 'unformat_free (line_input);' was never called, so there was a memory leak whether an invalid string was entered or not. Also, there were multiple instance where: error = clib_error_return (0, "unknown input `%U'", format_unformat_error, line_input); used 'input' as the last parameter instead of 'line_input'. The result is that output did not contain the substring in error, instead just an empty string. Fixed all of those as well. There are a lot of file, and very mind numbing work, so tried to keep it to a pattern to avoid mistakes. Change-Id: I8902f0c32a47dd7fb3bb3471a89818571702f1d2 Signed-off-by: Billy McFall Signed-off-by: Dave Barach --- build-root/emacs-lisp/tunnel-c-skel.el | 19 ++- src/plugins/ila/ila.c | 25 ++- src/plugins/lb/cli.c | 99 ++++++----- src/plugins/sixrd/sixrd.c | 42 +++-- src/plugins/snat/snat.c | 139 +++++++++++----- src/vlib/threads_cli.c | 79 ++++++--- src/vlib/trace.c | 13 +- src/vlib/unix/cli.c | 22 ++- src/vnet/devices/af_packet/cli.c | 56 +++++-- src/vnet/devices/dpdk/cli.c | 290 +++++++++++++++++++++++---------- src/vnet/devices/dpdk/ipsec/cli.c | 15 +- src/vnet/devices/netmap/cli.c | 54 ++++-- src/vnet/devices/virtio/vhost-user.c | 62 +++++-- src/vnet/gre/interface.c | 35 ++-- src/vnet/ip/ip4_source_check.c | 6 +- src/vnet/ip/ip4_test.c | 15 +- src/vnet/ip/ip6_neighbor.c | 27 ++- src/vnet/ip/lookup.c | 34 ++-- src/vnet/ipsec-gre/interface.c | 34 ++-- src/vnet/ipsec/ipsec_cli.c | 177 +++++++++++++------- src/vnet/l2/l2_patch.c | 26 ++- src/vnet/l2/l2_xcrw.c | 34 +++- src/vnet/l2tp/l2tp.c | 39 +++-- src/vnet/lisp-cp/lisp_cli.c | 139 ++++++++++++---- src/vnet/lisp-gpe/interface.c | 58 +++++-- src/vnet/lisp-gpe/lisp_gpe.c | 13 +- src/vnet/map/map.c | 186 +++++++++++++++------ src/vnet/mpls/mpls.c | 2 + src/vnet/mpls/mpls_tunnel.c | 19 ++- src/vnet/pg/cli.c | 39 +++-- src/vnet/policer/node_funcs.c | 19 ++- src/vnet/policer/policer.c | 13 +- src/vnet/unix/tapcli.c | 57 +++++-- src/vnet/vxlan-gpe/vxlan_gpe.c | 62 +++++-- src/vnet/vxlan/vxlan.c | 81 ++++++--- src/vpp/app/l2t.c | 9 +- src/vpp/app/vpe_cli.c | 24 ++- 37 files changed, 1487 insertions(+), 576 deletions(-) (limited to 'src/vnet/l2') diff --git a/build-root/emacs-lisp/tunnel-c-skel.el b/build-root/emacs-lisp/tunnel-c-skel.el index aa260e53..a1b1757d 100644 --- a/build-root/emacs-lisp/tunnel-c-skel.el +++ b/build-root/emacs-lisp/tunnel-c-skel.el @@ -288,6 +288,7 @@ static clib_error_t * vlib_cli_command_t * cmd) { unformat_input_t _line_input, * line_input = &_line_input; + clib_error_t *error = 0; ip4_address_t src, dst; u8 is_add = 1; u8 src_set = 0; @@ -322,13 +323,19 @@ static clib_error_t * { encap_fib_index = fib_index_from_fib_id (tmp); if (encap_fib_index == ~0) - return clib_error_return (0, \"nonexistent encap fib id %d\", tmp); + { + unformat_free (line_input); + return clib_error_return (0, \"nonexistent encap fib id %d\", tmp); + } } else if (unformat (line_input, \"decap-vrf-id %d\", &tmp)) { decap_fib_index = fib_index_from_fib_id (tmp); if (decap_fib_index == ~0) - return clib_error_return (0, \"nonexistent decap fib id %d\", tmp); + { + unformat_free (line_input); + return clib_error_return (0, \"nonexistent decap fib id %d\", tmp); + } } else if (unformat (line_input, \"decap-next %U\", unformat_decap_next, &decap_next_index)) @@ -346,8 +353,12 @@ static clib_error_t * * in the " ENCAP_STACK " header */ else - return clib_error_return (0, \"parse error: '%U'\", - format_unformat_error, line_input); + { + error = clib_error_return (0, \"parse error: '%U'\", + format_unformat_error, line_input); + unformat_free (line_input); + return error; + } } unformat_free (line_input); diff --git a/src/plugins/ila/ila.c b/src/plugins/ila/ila.c index e0f3907f..52c7ea55 100644 --- a/src/plugins/ila/ila.c +++ b/src/plugins/ila/ila.c @@ -949,6 +949,7 @@ ila_entry_command_fn (vlib_main_t * vm, ila_add_del_entry_args_t args = { 0 }; u8 next_hop_set = 0; int ret; + clib_error_t *error = 0; args.type = ILA_TYPE_IID; args.csum_mode = ILA_CSUM_MODE_NO_ACTION; @@ -986,19 +987,29 @@ ila_entry_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) args.is_del = 1; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (!next_hop_set) - return clib_error_return (0, "Specified a next hop"); + { + error = clib_error_return (0, "Specified a next hop"); + goto done; + } if ((ret = ila_add_del_entry (&args))) - return clib_error_return (0, "ila_add_del_entry returned error %d", ret); + { + error = clib_error_return (0, "ila_add_del_entry returned error %d", ret); + goto done; + } - return NULL; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (ila_entry_command, static) = diff --git a/src/plugins/lb/cli.c b/src/plugins/lb/cli.c index b59c6426..6452a875 100644 --- a/src/plugins/lb/cli.c +++ b/src/plugins/lb/cli.c @@ -28,13 +28,16 @@ lb_vip_command_fn (vlib_main_t * vm, int ret; u32 gre4 = 0; lb_vip_type_t type; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; - if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY, &plen)) - return clib_error_return (0, "invalid vip prefix: '%U'", - format_unformat_error, line_input); + if (!unformat(line_input, "%U", unformat_ip46_prefix, &prefix, &plen, IP46_TYPE_ANY, &plen)) { + error = clib_error_return (0, "invalid vip prefix: '%U'", + format_unformat_error, line_input); + goto done; + } while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { @@ -46,13 +49,13 @@ lb_vip_command_fn (vlib_main_t * vm, gre4 = 1; else if (unformat(line_input, "encap gre6")) gre4 = 0; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + else { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (ip46_prefix_is_ip4(&prefix, plen)) { type = (gre4)?LB_VIP_TYPE_IP4_GRE4:LB_VIP_TYPE_IP4_GRE6; @@ -65,17 +68,25 @@ lb_vip_command_fn (vlib_main_t * vm, u32 index; if (!del) { if ((ret = lb_vip_add(&prefix, plen, type, new_len, &index))) { - return clib_error_return (0, "lb_vip_add error %d", ret); + error = clib_error_return (0, "lb_vip_add error %d", ret); + goto done; } else { vlib_cli_output(vm, "lb_vip_add ok %d", index); } } else { - if ((ret = lb_vip_find_index(&prefix, plen, &index))) - return clib_error_return (0, "lb_vip_find_index error %d", ret); - else if ((ret = lb_vip_del(index))) - return clib_error_return (0, "lb_vip_del error %d", ret); + if ((ret = lb_vip_find_index(&prefix, plen, &index))) { + error = clib_error_return (0, "lb_vip_find_index error %d", ret); + goto done; + } else if ((ret = lb_vip_del(index))) { + error = clib_error_return (0, "lb_vip_del error %d", ret); + goto done; + } } - return NULL; + +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (lb_vip_command, static) = @@ -96,16 +107,21 @@ lb_as_command_fn (vlib_main_t * vm, u32 vip_index; u8 del = 0; int ret; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; - if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) - return clib_error_return (0, "invalid as address: '%U'", - format_unformat_error, line_input); + if (!unformat(line_input, "%U", unformat_ip46_prefix, &vip_prefix, &vip_plen, IP46_TYPE_ANY)) { + error = clib_error_return (0, "invalid as address: '%U'", + format_unformat_error, line_input); + goto done; + } - if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) - return clib_error_return (0, "lb_vip_find_index error %d", ret); + if ((ret = lb_vip_find_index(&vip_prefix, vip_plen, &vip_index))) { + error = clib_error_return (0, "lb_vip_find_index error %d", ret); + goto done; + } while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { @@ -114,15 +130,15 @@ lb_as_command_fn (vlib_main_t * vm, } else if (unformat(line_input, "del")) { del = 1; } else { - vec_free(as_array); - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; } } if (!vec_len(as_array)) { - vec_free(as_array); - return clib_error_return (0, "No AS address provided"); + error = clib_error_return (0, "No AS address provided"); + goto done; } lb_garbage_collection(); @@ -130,18 +146,21 @@ lb_as_command_fn (vlib_main_t * vm, if (del) { if ((ret = lb_vip_del_ass(vip_index, as_array, vec_len(as_array)))) { - vec_free(as_array); - return clib_error_return (0, "lb_vip_del_ass error %d", ret); + error = clib_error_return (0, "lb_vip_del_ass error %d", ret); + goto done; } } else { if ((ret = lb_vip_add_ass(vip_index, as_array, vec_len(as_array)))) { - vec_free(as_array); - return clib_error_return (0, "lb_vip_add_ass error %d", ret); + error = clib_error_return (0, "lb_vip_add_ass error %d", ret); + goto done; } } +done: + unformat_free (line_input); vec_free(as_array); - return 0; + + return error; } VLIB_CLI_COMMAND (lb_as_command, static) = @@ -163,6 +182,7 @@ lb_conf_command_fn (vlib_main_t * vm, u32 per_cpu_sticky_buckets_log2 = 0; u32 flow_timeout = lbm->flow_timeout; int ret; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -181,19 +201,24 @@ lb_conf_command_fn (vlib_main_t * vm, per_cpu_sticky_buckets = 1 << per_cpu_sticky_buckets_log2; } else if (unformat(line_input, "timeout %d", &flow_timeout)) ; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + else { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - lb_garbage_collection(); - if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) - return clib_error_return (0, "lb_conf error %d", ret); + if ((ret = lb_conf(&ip4, &ip6, per_cpu_sticky_buckets, flow_timeout))) { + error = clib_error_return (0, "lb_conf error %d", ret); + goto done; + } - return NULL; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (lb_conf_command, static) = diff --git a/src/plugins/sixrd/sixrd.c b/src/plugins/sixrd/sixrd.c index 71fc181f..67a9a3ad 100644 --- a/src/plugins/sixrd/sixrd.c +++ b/src/plugins/sixrd/sixrd.c @@ -192,6 +192,7 @@ sixrd_add_domain_command_fn (vlib_main_t *vm, u32 num_m_args = 0; /* Optional arguments */ u32 mtu = 0; + clib_error_t *error = 0; /* Get a line of input. */ if (!unformat_user(input, unformat_line_input, line_input)) @@ -205,19 +206,25 @@ sixrd_add_domain_command_fn (vlib_main_t *vm, num_m_args++; else if (unformat(line_input, "mtu %d", &mtu)) num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); + else { + error = clib_error_return(0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free(line_input); - if (num_m_args < 3) - return clib_error_return(0, "mandatory argument(s) missing"); + if (num_m_args < 3) { + error = clib_error_return(0, "mandatory argument(s) missing"); + goto done; + } sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, &ip4_src, &sixrd_domain_index, mtu); - return 0; +done: + unformat_free (line_input); + + return error; } static clib_error_t * @@ -228,6 +235,7 @@ sixrd_del_domain_command_fn (vlib_main_t *vm, unformat_input_t _line_input, *line_input = &_line_input; u32 num_m_args = 0; u32 sixrd_domain_index; + clib_error_t *error = 0; /* Get a line of input. */ if (! unformat_user(input, unformat_line_input, line_input)) @@ -236,18 +244,24 @@ sixrd_del_domain_command_fn (vlib_main_t *vm, while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) { if (unformat(line_input, "index %d", &sixrd_domain_index)) num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); + else { + error = clib_error_return(0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free(line_input); - if (num_m_args != 1) - return clib_error_return(0, "mandatory argument(s) missing"); + if (num_m_args != 1) { + error = clib_error_return(0, "mandatory argument(s) missing"); + goto done; + } sixrd_delete_domain(sixrd_domain_index); - return 0; +done: + unformat_free (line_input); + + return error; } static u8 * diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 73854a7a..8c2bacdb 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -1705,6 +1705,7 @@ add_address_command_fn (vlib_main_t * vm, int i, count; int is_add = 1; int rv = 0; + clib_error_t *error = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1721,19 +1722,27 @@ add_address_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) is_add = 0; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (sm->static_mapping_only) - return clib_error_return (0, "static mapping only mode"); + { + error = clib_error_return (0, "static mapping only mode"); + goto done; + } start_host_order = clib_host_to_net_u32 (start_addr.as_u32); end_host_order = clib_host_to_net_u32 (end_addr.as_u32); if (end_host_order < start_host_order) - return clib_error_return (0, "end address less than start address"); + { + error = clib_error_return (0, "end address less than start address"); + goto done; + } count = (end_host_order - start_host_order) + 1; @@ -1755,11 +1764,11 @@ add_address_command_fn (vlib_main_t * vm, switch (rv) { case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "S-NAT address not exist."); - break; + error = clib_error_return (0, "S-NAT address not exist."); + goto done; case VNET_API_ERROR_UNSPECIFIED: - return clib_error_return (0, "S-NAT address used in static mapping."); - break; + error = clib_error_return (0, "S-NAT address used in static mapping."); + goto done; default: break; } @@ -1767,7 +1776,10 @@ add_address_command_fn (vlib_main_t * vm, increment_v4_address (&this_addr); } - return 0; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (add_address_command, static) = { @@ -1807,10 +1819,12 @@ snat_feature_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) is_del = 1; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (vec_len (inside_sw_if_indices)) { @@ -1830,6 +1844,8 @@ snat_feature_command_fn (vlib_main_t * vm, } } +done: + unformat_free (line_input); vec_free (inside_sw_if_indices); vec_free (outside_sw_if_indices); @@ -1923,13 +1939,18 @@ add_static_mapping_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) is_add = 0; else - return clib_error_return (0, "unknown input: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (!addr_only && !proto_set) - return clib_error_return (0, "missing protocol"); + { + error = clib_error_return (0, "missing protocol"); + goto done; + } rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, vrf_id, addr_only, sw_if_index, proto, is_add); @@ -1937,22 +1958,27 @@ add_static_mapping_command_fn (vlib_main_t * vm, switch (rv) { case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "External port already in use."); - break; + error = clib_error_return (0, "External port already in use."); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: if (is_add) - return clib_error_return (0, "External addres must be allocated."); + error = clib_error_return (0, "External addres must be allocated."); else - return clib_error_return (0, "Mapping not exist."); - break; + error = clib_error_return (0, "Mapping not exist."); + goto done; case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "No such VRF id."); + error = clib_error_return (0, "No such VRF id."); + goto done; case VNET_API_ERROR_VALUE_EXIST: - return clib_error_return (0, "Mapping already exist."); + error = clib_error_return (0, "Mapping already exist."); + goto done; default: break; } +done: + unformat_free (line_input); + return error; } @@ -1985,6 +2011,7 @@ set_workers_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; uword *bitmap = 0; int rv = 0; + clib_error_t *error = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1995,13 +2022,18 @@ set_workers_command_fn (vlib_main_t * vm, if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap)) ; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (bitmap == 0) - return clib_error_return (0, "List of workers must be specified."); + { + error = clib_error_return (0, "List of workers must be specified."); + goto done; + } rv = snat_set_workers(bitmap); @@ -2010,17 +2042,20 @@ set_workers_command_fn (vlib_main_t * vm, switch (rv) { case VNET_API_ERROR_INVALID_WORKER: - return clib_error_return (0, "Invalid worker(s)."); - break; + error = clib_error_return (0, "Invalid worker(s)."); + goto done; case VNET_API_ERROR_FEATURE_DISABLED: - return clib_error_return (0, + error = clib_error_return (0, "Supported only if 2 or more workes available."); - break; + goto done; default: break; } - return 0; +done: + unformat_free (line_input); + + return error; } /*? @@ -2047,6 +2082,7 @@ snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm, u32 src_port = 0; u8 enable = 1; int rv = 0; + clib_error_t *error = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2061,17 +2097,25 @@ snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm, else if (unformat (line_input, "disable")) enable = 0; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port); if (rv) - return clib_error_return (0, "ipfix logging enable failed"); + { + error = clib_error_return (0, "ipfix logging enable failed"); + goto done; + } - return 0; +done: + unformat_free (line_input); + + return error; } /*? @@ -2604,6 +2648,7 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, u32 sw_if_index; int rv; int is_del = 0; + clib_error_t *error = 0; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2617,8 +2662,11 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) is_del = 1; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } rv = snat_add_interface_address (sm, sw_if_index, is_del); @@ -2629,10 +2677,15 @@ snat_add_interface_address_command_fn (vlib_main_t * vm, break; default: - return clib_error_return (0, "snat_add_interface_address returned %d", - rv); + error = clib_error_return (0, "snat_add_interface_address returned %d", + rv); + goto done; } - return 0; + +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { diff --git a/src/vlib/threads_cli.c b/src/vlib/threads_cli.c index 54cc1aed..36f8109e 100644 --- a/src/vlib/threads_cli.c +++ b/src/vlib/threads_cli.c @@ -163,21 +163,31 @@ trace_frame_queue (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "index %u", &index)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (enable > 1) - return clib_error_return (0, "expecting on or off"); + { + error = clib_error_return (0, "expecting on or off"); + goto done; + } if (vec_len (tm->frame_queue_mains) == 0) - return clib_error_return (0, "no worker handoffs exist"); + { + error = clib_error_return (0, "no worker handoffs exist"); + goto done; + } if (index > vec_len (tm->frame_queue_mains) - 1) - return clib_error_return (0, - "expecting valid worker handoff queue index"); + { + error = clib_error_return (0, + "expecting valid worker handoff queue index"); + goto done; + } fqm = vec_elt_at_index (tm->frame_queue_mains, index); @@ -185,7 +195,7 @@ trace_frame_queue (vlib_main_t * vm, unformat_input_t * input, if (num_fq == 0) { vlib_cli_output (vm, "No frame queues exist\n"); - return error; + goto done; } // Allocate storage for trace if necessary @@ -204,6 +214,10 @@ trace_frame_queue (vlib_main_t * vm, unformat_input_t * input, memset (fqh, 0, sizeof (*fqh)); fqm->vlib_frame_queues[fqix]->trace = enable; } + +done: + unformat_free (line_input); + return error; } @@ -432,28 +446,33 @@ test_frame_queue_nelts (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "index %u", &index)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (index > vec_len (tm->frame_queue_mains) - 1) - return clib_error_return (0, - "expecting valid worker handoff queue index"); + { + error = clib_error_return (0, + "expecting valid worker handoff queue index"); + goto done; + } fqm = vec_elt_at_index (tm->frame_queue_mains, index); if ((nelts != 4) && (nelts != 8) && (nelts != 16) && (nelts != 32)) { - return clib_error_return (0, "expecting 4,8,16,32"); + error = clib_error_return (0, "expecting 4,8,16,32"); + goto done; } num_fq = vec_len (fqm->vlib_frame_queues); if (num_fq == 0) { vlib_cli_output (vm, "No frame queues exist\n"); - return error; + goto done; } for (fqix = 0; fqix < num_fq; fqix++) @@ -461,6 +480,9 @@ test_frame_queue_nelts (vlib_main_t * vm, unformat_input_t * input, fqm->vlib_frame_queues[fqix]->nelts = nelts; } +done: + unformat_free (line_input); + return error; } @@ -499,15 +521,19 @@ test_frame_queue_threshold (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "index %u", &index)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (index > vec_len (tm->frame_queue_mains) - 1) - return clib_error_return (0, - "expecting valid worker handoff queue index"); + { + error = clib_error_return (0, + "expecting valid worker handoff queue index"); + goto done; + } fqm = vec_elt_at_index (tm->frame_queue_mains, index); @@ -515,7 +541,7 @@ test_frame_queue_threshold (vlib_main_t * vm, unformat_input_t * input, if (threshold == ~(u32) 0) { vlib_cli_output (vm, "expecting threshold value\n"); - return error; + goto done; } if (threshold == 0) @@ -525,7 +551,7 @@ test_frame_queue_threshold (vlib_main_t * vm, unformat_input_t * input, if (num_fq == 0) { vlib_cli_output (vm, "No frame queues exist\n"); - return error; + goto done; } for (fqix = 0; fqix < num_fq; fqix++) @@ -533,6 +559,9 @@ test_frame_queue_threshold (vlib_main_t * vm, unformat_input_t * input, fqm->vlib_frame_queues[fqix]->vector_threshold = threshold; } +done: + unformat_free (line_input); + return error; } diff --git a/src/vlib/trace.c b/src/vlib/trace.c index dcdb837f..6d487ae1 100644 --- a/src/vlib/trace.c +++ b/src/vlib/trace.c @@ -372,6 +372,7 @@ cli_add_trace_buffer (vlib_main_t * vm, vlib_trace_node_t *tn; u32 node_index, add; u8 verbose = 0; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -384,8 +385,11 @@ cli_add_trace_buffer (vlib_main_t * vm, else if (unformat (line_input, "verbose")) verbose = 1; else - return clib_error_create ("expected NODE COUNT, got `%U'", - format_unformat_error, line_input); + { + error = clib_error_create ("expected NODE COUNT, got `%U'", + format_unformat_error, line_input); + goto done; + } } /* *INDENT-OFF* */ @@ -403,7 +407,10 @@ cli_add_trace_buffer (vlib_main_t * vm, })); /* *INDENT-ON* */ - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vlib/unix/cli.c b/src/vlib/unix/cli.c index 69fca6ec..88e2453c 100644 --- a/src/vlib/unix/cli.c +++ b/src/vlib/unix/cli.c @@ -2835,6 +2835,7 @@ unix_cli_set_terminal_pager (vlib_main_t * vm, unix_cli_main_t *cm = &unix_cli_main; unix_cli_file_t *cf; unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -2852,13 +2853,17 @@ unix_cli_set_terminal_pager (vlib_main_t * vm, "Pager limit set to %u lines; note, this is global.\n", um->cli_pager_buffer_limit); else - return clib_error_return (0, "unknown parameter: `%U`", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown parameter: `%U`", + format_unformat_error, line_input); + goto done; + } } +done: unformat_free (line_input); - return 0; + return error; } /*? @@ -2886,6 +2891,7 @@ unix_cli_set_terminal_history (vlib_main_t * vm, unix_cli_file_t *cf; unformat_input_t _line_input, *line_input = &_line_input; u32 limit; + clib_error_t *error = 0; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -2901,8 +2907,11 @@ unix_cli_set_terminal_history (vlib_main_t * vm, else if (unformat (line_input, "limit %u", &cf->history_limit)) ; else - return clib_error_return (0, "unknown parameter: `%U`", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown parameter: `%U`", + format_unformat_error, line_input); + goto done; + } /* If we reduced history size, or turned it off, purge the history */ limit = cf->has_history ? cf->history_limit : 0; @@ -2914,9 +2923,10 @@ unix_cli_set_terminal_history (vlib_main_t * vm, } } +done: unformat_free (line_input); - return 0; + return error; } /*? diff --git a/src/vnet/devices/af_packet/cli.c b/src/vnet/devices/af_packet/cli.c index 6baa26e1..d4aa7016 100644 --- a/src/vnet/devices/af_packet/cli.c +++ b/src/vnet/devices/af_packet/cli.c @@ -49,6 +49,7 @@ af_packet_create_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 *hw_addr_ptr = 0; u32 sw_if_index; int r; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -63,29 +64,47 @@ af_packet_create_command_fn (vlib_main_t * vm, unformat_input_t * input, (line_input, "hw-addr %U", unformat_ethernet_address, hwaddr)) hw_addr_ptr = hwaddr; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (host_if_name == NULL) - return clib_error_return (0, "missing host interface name"); + { + error = clib_error_return (0, "missing host interface name"); + goto done; + } r = af_packet_create_if (vm, host_if_name, hw_addr_ptr, &sw_if_index); - vec_free (host_if_name); if (r == VNET_API_ERROR_SYSCALL_ERROR_1) - return clib_error_return (0, "%s (errno %d)", strerror (errno), errno); + { + error = clib_error_return (0, "%s (errno %d)", strerror (errno), errno); + goto done; + } if (r == VNET_API_ERROR_INVALID_INTERFACE) - return clib_error_return (0, "Invalid interface name"); + { + error = clib_error_return (0, "Invalid interface name"); + goto done; + } if (r == VNET_API_ERROR_SUBIF_ALREADY_EXISTS) - return clib_error_return (0, "Interface elready exists"); + { + error = clib_error_return (0, "Interface elready exists"); + goto done; + } vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index); - return 0; + +done: + vec_free (host_if_name); + unformat_free (line_input); + + return error; } /*? @@ -124,6 +143,7 @@ af_packet_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, { unformat_input_t _line_input, *line_input = &_line_input; u8 *host_if_name = NULL; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -134,18 +154,26 @@ af_packet_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, if (unformat (line_input, "name %s", &host_if_name)) ; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (host_if_name == NULL) - return clib_error_return (0, "missing host interface name"); + { + error = clib_error_return (0, "missing host interface name"); + goto done; + } af_packet_delete_if (vm, host_if_name); + +done: vec_free (host_if_name); + unformat_free (line_input); - return 0; + return error; } /*? diff --git a/src/vnet/devices/dpdk/cli.c b/src/vnet/devices/dpdk/cli.c index d133cfd9..1fc665ac 100644 --- a/src/vnet/devices/dpdk/cli.c +++ b/src/vnet/devices/dpdk/cli.c @@ -398,7 +398,7 @@ set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input, u32 hw_if_index = (u32) ~ 0; u32 nb_rx_desc = (u32) ~ 0; u32 nb_tx_desc = (u32) ~ 0; - clib_error_t *rv; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -414,25 +414,37 @@ set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "rx %d", &nb_rx_desc)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); if ((xd->flags & DPDK_DEVICE_FLAG_PMD) == 0) - return clib_error_return (0, "number of descriptors can be set only for " - "physical devices"); + { + error = + clib_error_return (0, + "number of descriptors can be set only for " + "physical devices"); + goto done; + } if ((nb_rx_desc == (u32) ~ 0 || nb_rx_desc == xd->nb_rx_desc) && (nb_tx_desc == (u32) ~ 0 || nb_tx_desc == xd->nb_tx_desc)) - return clib_error_return (0, "nothing changed"); + { + error = clib_error_return (0, "nothing changed"); + goto done; + } if (nb_rx_desc != (u32) ~ 0) xd->nb_rx_desc = nb_rx_desc; @@ -440,9 +452,12 @@ set_dpdk_if_desc (vlib_main_t * vm, unformat_input_t * input, if (nb_tx_desc != (u32) ~ 0) xd->nb_tx_desc = nb_tx_desc; - rv = dpdk_port_setup (dm, xd); + error = dpdk_port_setup (dm, xd); + +done: + unformat_free (line_input); - return rv; + return error; } /* *INDENT-OFF* */ @@ -523,6 +538,7 @@ set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input, u32 queue = (u32) 0; u32 cpu = (u32) ~ 0; int i; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -538,18 +554,25 @@ set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "thread %d", &cpu)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } if (cpu < dm->input_cpu_first_index || cpu >= (dm->input_cpu_first_index + dm->input_cpu_count)) - return clib_error_return (0, "please specify valid thread id"); + { + error = clib_error_return (0, "please specify valid thread id"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -563,7 +586,7 @@ set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input, queue == dq->queue_id) { if (cpu == i) /* nothing to do */ - return 0; + goto done; vec_del1(dm->devices_by_cpu[i], dq - dm->devices_by_cpu[i]); vec_add2(dm->devices_by_cpu[cpu], dq, 1); @@ -586,13 +609,18 @@ set_dpdk_if_placement (vlib_main_t * vm, unformat_input_t * input, vlib_node_set_state (vlib_mains[cpu], dpdk_input_node.index, VLIB_NODE_STATE_POLLING); - return 0; + goto done; } } /* *INDENT-ON* */ } - return clib_error_return (0, "not found"); + error = clib_error_return (0, "not found"); + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -653,6 +681,7 @@ set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, u32 hw_if_index = (u32) ~ 0; u32 cpu = (u32) ~ 0; int i; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -666,18 +695,22 @@ set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "thread %d", &cpu)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) return clib_error_return (0, "please specify valid interface name"); if (cpu < dm->hqos_cpu_first_index || cpu >= (dm->hqos_cpu_first_index + dm->hqos_cpu_count)) - return clib_error_return (0, "please specify valid thread id"); + { + error = clib_error_return (0, "please specify valid thread id"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -689,7 +722,7 @@ set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, if (hw_if_index == dm->devices[dq->device].vlib_hw_if_index) { if (cpu == i) /* nothing to do */ - return 0; + goto done; vec_del1 (dm->devices_by_hqos_cpu[i], dq - dm->devices_by_hqos_cpu[i]); @@ -703,12 +736,17 @@ set_dpdk_if_hqos_placement (vlib_main_t * vm, unformat_input_t * input, vec_sort_with_function (dm->devices_by_hqos_cpu[cpu], dpdk_device_queue_sort); - return 0; + goto done; } } } - return clib_error_return (0, "not found"); + error = clib_error_return (0, "not found"); + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -732,6 +770,7 @@ set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input, u32 pipe_id = (u32) ~ 0; u32 profile_id = (u32) ~ 0; int rv; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -749,14 +788,18 @@ set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "profile %d", &profile_id)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -765,9 +808,15 @@ set_dpdk_if_hqos_pipe (vlib_main_t * vm, unformat_input_t * input, rte_sched_pipe_config (xd->hqos_ht->hqos, subport_id, pipe_id, profile_id); if (rv) - return clib_error_return (0, "pipe configuration failed"); + { + error = clib_error_return (0, "pipe configuration failed"); + goto done; + } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -797,6 +846,7 @@ set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input, .tc_period = 10, }; int rv; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -829,23 +879,33 @@ set_dpdk_if_hqos_subport (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "period %d", &p.tc_period)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); rv = rte_sched_subport_config (xd->hqos_ht->hqos, subport_id, &p); if (rv) - return clib_error_return (0, "subport configuration failed"); + { + error = clib_error_return (0, "subport configuration failed"); + goto done; + } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -872,6 +932,7 @@ set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, u32 queue = (u32) ~ 0; u32 entry = (u32) ~ 0; u32 val, i; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -889,20 +950,33 @@ set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "queue %d", &queue)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } if (entry >= 64) - return clib_error_return (0, "invalid entry"); + { + error = clib_error_return (0, "invalid entry"); + goto done; + } if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) - return clib_error_return (0, "invalid traffic class"); + { + error = clib_error_return (0, "invalid traffic class"); + goto done; + } if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) - return clib_error_return (0, "invalid traffic class"); + { + error = clib_error_return (0, "invalid traffic class"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -911,7 +985,10 @@ set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); /* Should never happen, shut up Coverity warning */ if (p == 0) - return clib_error_return (0, "no worker registrations?"); + { + error = clib_error_return (0, "no worker registrations?"); + goto done; + } vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; int worker_thread_first = tr->first_index; @@ -921,7 +998,10 @@ set_dpdk_if_hqos_tctbl (vlib_main_t * vm, unformat_input_t * input, for (i = 0; i < worker_thread_count; i++) xd->hqos_wt[worker_thread_first + i].hqos_tc_table[entry] = val; - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -939,6 +1019,7 @@ set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, unformat_input_t _line_input, *line_input = &_line_input; vlib_thread_main_t *tm = vlib_get_thread_main (); dpdk_main_t *dm = &dpdk_main; + clib_error_t *error = NULL; /* Device specific data */ struct rte_eth_dev_info dev_info; @@ -984,15 +1065,19 @@ set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "mask %llx", &mask)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - /* Get interface */ if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify valid interface name"); + { + error = clib_error_return (0, "please specify valid interface name"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -1019,7 +1104,7 @@ set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, if (devconf->hqos_enabled == 0) { vlib_cli_output (vm, "HQoS disabled for this interface"); - return 0; + goto done; } n_subports_per_port = devconf->hqos.port.n_subports_per_port; @@ -1028,27 +1113,39 @@ set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, /* Validate packet field configuration: id, offset and mask */ if (id >= 3) - return clib_error_return (0, "invalid packet field id"); + { + error = clib_error_return (0, "invalid packet field id"); + goto done; + } switch (id) { case 0: if (dpdk_hqos_validate_mask (mask, n_subports_per_port) != 0) - return clib_error_return (0, "invalid subport ID mask " - "(n_subports_per_port = %u)", - n_subports_per_port); + { + error = clib_error_return (0, "invalid subport ID mask " + "(n_subports_per_port = %u)", + n_subports_per_port); + goto done; + } break; case 1: if (dpdk_hqos_validate_mask (mask, n_pipes_per_subport) != 0) - return clib_error_return (0, "invalid pipe ID mask " - "(n_pipes_per_subport = %u)", - n_pipes_per_subport); + { + error = clib_error_return (0, "invalid pipe ID mask " + "(n_pipes_per_subport = %u)", + n_pipes_per_subport); + goto done; + } break; case 2: default: if (dpdk_hqos_validate_mask (mask, tctbl_size) != 0) - return clib_error_return (0, "invalid TC table index mask " - "(TC table size = %u)", tctbl_size); + { + error = clib_error_return (0, "invalid TC table index mask " + "(TC table size = %u)", tctbl_size); + goto done; + } } /* Propagate packet field configuration to all workers */ @@ -1075,7 +1172,10 @@ set_dpdk_if_hqos_pktfield (vlib_main_t * vm, unformat_input_t * input, __builtin_ctzll (mask); } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1106,6 +1206,7 @@ show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, dpdk_device_config_t *devconf = 0; vlib_thread_registration_t *tr; uword *p = 0; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -1117,14 +1218,18 @@ show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, &hw_if_index)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify interface name!!"); + { + error = clib_error_return (0, "please specify interface name!!"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -1151,7 +1256,7 @@ show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, if (devconf->hqos_enabled == 0) { vlib_cli_output (vm, "HQoS disabled for this interface"); - return 0; + goto done; } /* Detect the set of worker threads */ @@ -1159,7 +1264,10 @@ show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, /* Should never happen, shut up Coverity warning */ if (p == 0) - return clib_error_return (0, "no worker registrations?"); + { + error = clib_error_return (0, "no worker registrations?"); + goto done; + } tr = (vlib_thread_registration_t *) p[0]; @@ -1284,7 +1392,10 @@ show_dpdk_if_hqos (vlib_main_t * vm, unformat_input_t * input, } #endif - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1315,6 +1426,7 @@ show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, u32 qindex; struct rte_sched_queue_stats stats; u16 qlen; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -1339,14 +1451,18 @@ show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "please specify interface name!!"); + { + error = clib_error_return (0, "please specify interface name!!"); + goto done; + } hw = vnet_get_hw_interface (dm->vnet_main, hw_if_index); xd = vec_elt_at_index (dm->devices, hw->dev_instance); @@ -1373,7 +1489,7 @@ show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, if (devconf->hqos_enabled == 0) { vlib_cli_output (vm, "HQoS disabled for this interface"); - return 0; + goto done; } /* @@ -1386,7 +1502,10 @@ show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, if (rte_sched_queue_read_stats (xd->hqos_ht->hqos, qindex, &stats, &qlen) != 0) - return clib_error_return (0, "failed to read stats"); + { + error = clib_error_return (0, "failed to read stats"); + goto done; + } vlib_cli_output (vm, "%=24s%=16s", "Stats Parameter", "Value"); vlib_cli_output (vm, "%=24s%=16d", "Packets", stats.n_pkts); @@ -1399,7 +1518,10 @@ show_dpdk_hqos_queue_stats (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "%=24s%=16d", "Bytes dropped", stats.n_bytes_dropped); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/devices/dpdk/ipsec/cli.c b/src/vnet/devices/dpdk/ipsec/cli.c index 93df4a64..f9d3a5d0 100644 --- a/src/vnet/devices/dpdk/ipsec/cli.c +++ b/src/vnet/devices/dpdk/ipsec/cli.c @@ -111,6 +111,7 @@ lcore_cryptodev_map_fn (vlib_main_t * vm, unformat_input_t * input, { unformat_input_t _line_input, *line_input = &_line_input; u16 detail = 0; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -120,15 +121,19 @@ lcore_cryptodev_map_fn (vlib_main_t * vm, unformat_input_t * input, if (unformat (line_input, "verbose")) detail = 1; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - dpdk_ipsec_show_mapping (vm, detail); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/devices/netmap/cli.c b/src/vnet/devices/netmap/cli.c index 6157f27c..71363294 100644 --- a/src/vnet/devices/netmap/cli.c +++ b/src/vnet/devices/netmap/cli.c @@ -37,6 +37,7 @@ netmap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, u8 is_pipe = 0; u8 is_master = 0; u32 sw_if_index = ~0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -57,30 +58,48 @@ netmap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "slave")) is_master = 0; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (host_if_name == NULL) - return clib_error_return (0, "missing host interface name"); + { + error = clib_error_return (0, "missing host interface name"); + goto done; + } r = netmap_create_if (vm, host_if_name, hw_addr_ptr, is_pipe, is_master, &sw_if_index); if (r == VNET_API_ERROR_SYSCALL_ERROR_1) - return clib_error_return (0, "%s (errno %d)", strerror (errno), errno); + { + error = clib_error_return (0, "%s (errno %d)", strerror (errno), errno); + goto done; + } if (r == VNET_API_ERROR_INVALID_INTERFACE) - return clib_error_return (0, "Invalid interface name"); + { + error = clib_error_return (0, "Invalid interface name"); + goto done; + } if (r == VNET_API_ERROR_SUBIF_ALREADY_EXISTS) - return clib_error_return (0, "Interface already exists"); + { + error = clib_error_return (0, "Interface already exists"); + goto done; + } vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index); - return 0; + +done: + unformat_free (line_input); + + return error; } /*? @@ -144,6 +163,7 @@ netmap_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, { unformat_input_t _line_input, *line_input = &_line_input; u8 *host_if_name = NULL; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -154,17 +174,25 @@ netmap_delete_command_fn (vlib_main_t * vm, unformat_input_t * input, if (unformat (line_input, "name %s", &host_if_name)) ; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (host_if_name == NULL) - return clib_error_return (0, "missing host interface name"); + { + error = clib_error_return (0, "missing host interface name"); + goto done; + } netmap_delete_if (vm, host_if_name); - return 0; +done: + unformat_free (line_input); + + return error; } /*? diff --git a/src/vnet/devices/virtio/vhost-user.c b/src/vnet/devices/virtio/vhost-user.c index 315daa77..c43f6e67 100644 --- a/src/vnet/devices/virtio/vhost-user.c +++ b/src/vnet/devices/virtio/vhost-user.c @@ -2682,6 +2682,7 @@ vhost_user_connect_command_fn (vlib_main_t * vm, u32 custom_dev_instance = ~0; u8 hwaddr[6]; u8 *hw = NULL; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2704,10 +2705,12 @@ vhost_user_connect_command_fn (vlib_main_t * vm, renumber = 1; } else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); vnet_main_t *vnm = vnet_get_main (); @@ -2716,14 +2719,18 @@ vhost_user_connect_command_fn (vlib_main_t * vm, is_server, &sw_if_index, feature_mask, renumber, custom_dev_instance, hw))) { - vec_free (sock_filename); - return clib_error_return (0, "vhost_user_create_if returned %d", rv); + error = clib_error_return (0, "vhost_user_create_if returned %d", rv); + goto done; } - vec_free (sock_filename); vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index); - return 0; + +done: + vec_free (sock_filename); + unformat_free (line_input); + + return error; } clib_error_t * @@ -2734,6 +2741,7 @@ vhost_user_delete_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u32 sw_if_index = ~0; vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -2751,15 +2759,25 @@ vhost_user_delete_command_fn (vlib_main_t * vm, vnet_get_sup_hw_interface (vnm, sw_if_index); if (hwif == NULL || vhost_user_dev_class.index != hwif->dev_class_index) - return clib_error_return (0, "Not a vhost interface"); + { + error = clib_error_return (0, "Not a vhost interface"); + goto done; + } } else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); + vhost_user_delete_if (vnm, vm, sw_if_index); - return 0; + +done: + unformat_free (line_input); + + return error; } int @@ -3286,6 +3304,7 @@ vhost_thread_command_fn (vlib_main_t * vm, u32 sw_if_index; u8 del = 0; int rv; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -3295,9 +3314,9 @@ vhost_thread_command_fn (vlib_main_t * vm, (line_input, "%U %d", unformat_vnet_sw_interface, vnet_get_main (), &sw_if_index, &worker_thread_index)) { - unformat_free (line_input); - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; } if (unformat (line_input, "del")) @@ -3305,9 +3324,16 @@ vhost_thread_command_fn (vlib_main_t * vm, if ((rv = vhost_user_thread_placement (sw_if_index, worker_thread_index, del))) - return clib_error_return (0, "vhost_user_thread_placement returned %d", - rv); - return 0; + { + error = clib_error_return (0, "vhost_user_thread_placement returned %d", + rv); + goto done; + } + +done: + unformat_free (line_input); + + return error; } diff --git a/src/vnet/gre/interface.c b/src/vnet/gre/interface.c index d624587d..d4476ac4 100644 --- a/src/vnet/gre/interface.c +++ b/src/vnet/gre/interface.c @@ -491,6 +491,7 @@ create_gre_tunnel_command_fn (vlib_main_t * vm, u32 num_m_args = 0; u8 is_add = 1; u32 sw_if_index; + clib_error_t *error = NULL; /* Get a line of input. */ if (! unformat_user (input, unformat_line_input, line_input)) @@ -508,16 +509,24 @@ create_gre_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "teb")) teb = 1; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args < 2) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } if (memcmp (&src, &dst, sizeof(src)) == 0) - return clib_error_return (0, "src and dst are identical"); + { + error = clib_error_return (0, "src and dst are identical"); + goto done; + } memset (a, 0, sizeof (*a)); a->outer_fib_id = outer_fib_id; @@ -536,15 +545,21 @@ create_gre_tunnel_command_fn (vlib_main_t * vm, vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index); break; case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "GRE tunnel already exists..."); + error = clib_error_return (0, "GRE tunnel already exists..."); + goto done; case VNET_API_ERROR_NO_SUCH_FIB: - return clib_error_return (0, "outer fib ID %d doesn't exist\n", - outer_fib_id); + error = clib_error_return (0, "outer fib ID %d doesn't exist\n", + outer_fib_id); + goto done; default: - return clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv); + error = clib_error_return (0, "vnet_gre_add_del_tunnel returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (create_gre_tunnel_command, static) = { diff --git a/src/vnet/ip/ip4_source_check.c b/src/vnet/ip/ip4_source_check.c index d461cc88..3af32f2e 100644 --- a/src/vnet/ip/ip4_source_check.c +++ b/src/vnet/ip/ip4_source_check.c @@ -399,6 +399,8 @@ set_ip_source_check (vlib_main_t * vm, vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, is_del == 0, &config, sizeof (config)); done: + unformat_free (line_input); + return error; } @@ -531,7 +533,9 @@ ip_source_check_accept (vlib_main_t * vm, } done: - return (error); + unformat_free (line_input); + + return error; } /*? diff --git a/src/vnet/ip/ip4_test.c b/src/vnet/ip/ip4_test.c index 45d17113..73dabfdc 100644 --- a/src/vnet/ip/ip4_test.c +++ b/src/vnet/ip/ip4_test.c @@ -143,8 +143,11 @@ thrash (vlib_main_t * vm, else if (unformat (line_input, "verbose")) verbose = 1; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } } @@ -178,7 +181,7 @@ thrash (vlib_main_t * vm, if (p == 0) { vlib_cli_output (vm, "Couldn't map fib id %d to fib index\n", table_id); - return 0; + goto done; } table_index = p[0]; @@ -294,7 +297,11 @@ thrash (vlib_main_t * vm, pool_free (tm->route_pool); } - return 0; + +done: + unformat_free (line_input); + + return error; } /*? diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 7229591e..6b53137f 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -2923,7 +2923,10 @@ ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input, else if (unformat (line_input, "ra-lifetime")) { if (!unformat (line_input, "%d", &ra_lifetime)) - return (error = unformat_parse_error (line_input)); + { + error = unformat_parse_error (line_input); + goto done; + } use_lifetime = 1; break; } @@ -2931,13 +2934,19 @@ ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input, { if (!unformat (line_input, "%d %d", &ra_initial_count, &ra_initial_interval)) - return (error = unformat_parse_error (line_input)); + { + error = unformat_parse_error (line_input); + goto done; + } break; } else if (unformat (line_input, "ra-interval")) { if (!unformat (line_input, "%d", &ra_max_interval)) - return (error = unformat_parse_error (line_input)); + { + error = unformat_parse_error (line_input); + goto done; + } if (!unformat (line_input, "%d", &ra_min_interval)) ra_min_interval = 0; @@ -2949,7 +2958,10 @@ ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input, break; } else - return (unformat_parse_error (line_input)); + { + error = unformat_parse_error (line_input); + goto done; + } } if (add_radv_info) @@ -3006,7 +3018,10 @@ ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input, else if (unformat (line_input, "no-onlink")) no_onlink = 1; else - return (unformat_parse_error (line_input)); + { + error = unformat_parse_error (line_input); + goto done; + } } ip6_neighbor_ra_prefix (vm, sw_if_index, @@ -3018,9 +3033,9 @@ ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input, off_link, no_autoconfig, no_onlink, is_no); } +done: unformat_free (line_input); -done: return error; } diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index 0ef0e7a6..807b87b6 100644 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -568,8 +568,6 @@ vnet_ip_route_cmd (vlib_main_t * vm, } } - unformat_free (line_input); - if (vec_len (prefixs) == 0) { error = @@ -704,6 +702,7 @@ done: vec_free (dpos); vec_free (prefixs); vec_free (rpaths); + unformat_free (line_input); return error; } @@ -872,8 +871,6 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, } } - unformat_free (line_input); - if (~0 == table_id) { /* @@ -970,6 +967,8 @@ vnet_ip_mroute_cmd (vlib_main_t * vm, (scount * gcount) / (timet[1] - timet[0])); done: + unformat_free (line_input); + return error; } @@ -1149,24 +1148,37 @@ probe_neighbor_address (vlib_main_t * vm, is_ip4 = 0; } else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (sw_if_index == ~0) - return clib_error_return (0, "Interface required, not set."); + { + error = clib_error_return (0, "Interface required, not set."); + goto done; + } if (address_set == 0) - return clib_error_return (0, "ip address required, not set."); + { + error = clib_error_return (0, "ip address required, not set."); + goto done; + } if (address_set > 1) - return clib_error_return (0, "Multiple ip addresses not supported."); + { + error = clib_error_return (0, "Multiple ip addresses not supported."); + goto done; + } if (is_ip4) error = ip4_probe_neighbor_wait (vm, &a4, sw_if_index, retry_count); else error = ip6_probe_neighbor_wait (vm, &a6, sw_if_index, retry_count); +done: + unformat_free (line_input); + return error; } diff --git a/src/vnet/ipsec-gre/interface.c b/src/vnet/ipsec-gre/interface.c index 3b6e4ac2..0772ce73 100644 --- a/src/vnet/ipsec-gre/interface.c +++ b/src/vnet/ipsec-gre/interface.c @@ -232,6 +232,7 @@ create_ipsec_gre_tunnel_command_fn (vlib_main_t * vm, vnet_ipsec_gre_add_del_tunnel_args_t _a, *a = &_a; int rv; u32 sw_if_index; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -250,16 +251,24 @@ create_ipsec_gre_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "remote-sa %d", &rsa)) num_m_args++; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args < 4) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } if (memcmp (&src, &dst, sizeof (src)) == 0) - return clib_error_return (0, "src and dst are identical"); + { + error = clib_error_return (0, "src and dst are identical"); + goto done; + } memset (a, 0, sizeof (*a)); a->is_add = is_add; @@ -277,14 +286,19 @@ create_ipsec_gre_tunnel_command_fn (vlib_main_t * vm, vnet_get_main (), sw_if_index); break; case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "GRE tunnel already exists..."); + error = clib_error_return (0, "GRE tunnel already exists..."); + goto done; default: - return clib_error_return (0, - "vnet_ipsec_gre_add_del_tunnel returned %d", - rv); + error = clib_error_return (0, + "vnet_ipsec_gre_add_del_tunnel returned %d", + rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index 3c1e26f2..0e034402 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -32,6 +32,7 @@ set_interface_spd_command_fn (vlib_main_t * vm, u32 sw_if_index = (u32) ~ 0; u32 spd_id; int is_add = 1; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -43,14 +44,18 @@ set_interface_spd_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) is_add = 0; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - - unformat_free (line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -72,7 +77,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, ipsec_sa_t sa; int is_add = ~0; u8 *ck = 0, *ik = 0; - clib_error_t *err = 0; + clib_error_t *error = NULL; memset (&sa, 0, sizeof (sa)); @@ -90,8 +95,11 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "esp")) sa.protocol = IPSEC_PROTOCOL_ESP; else if (unformat (line_input, "ah")) - //sa.protocol = IPSEC_PROTOCOL_AH; - return clib_error_return (0, "unsupported security protocol 'AH'"); + { + //sa.protocol = IPSEC_PROTOCOL_AH; + error = clib_error_return (0, "unsupported security protocol 'AH'"); + goto done; + } else if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck)) sa.crypto_key_len = vec_len (ck); @@ -102,8 +110,12 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, { if (sa.crypto_alg < IPSEC_CRYPTO_ALG_AES_CBC_128 || sa.crypto_alg >= IPSEC_CRYPTO_N_ALG) - return clib_error_return (0, "unsupported crypto-alg: '%U'", - format_ipsec_crypto_alg, sa.crypto_alg); + { + error = clib_error_return (0, "unsupported crypto-alg: '%U'", + format_ipsec_crypto_alg, + sa.crypto_alg); + goto done; + } } else if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik)) @@ -113,8 +125,12 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, { if (sa.integ_alg < IPSEC_INTEG_ALG_SHA1_96 || sa.integ_alg >= IPSEC_INTEG_N_ALG) - return clib_error_return (0, "unsupported integ-alg: '%U'", - format_ipsec_integ_alg, sa.integ_alg); + { + error = clib_error_return (0, "unsupported integ-alg: '%U'", + format_ipsec_integ_alg, + sa.integ_alg); + goto done; + } } else if (unformat (line_input, "tunnel-src %U", unformat_ip4_address, &sa.tunnel_src_addr.ip4)) @@ -135,12 +151,13 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, sa.is_tunnel_ip6 = 1; } else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (sa.crypto_key_len > sizeof (sa.crypto_key)) sa.crypto_key_len = sizeof (sa.crypto_key); @@ -156,14 +173,17 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, if (is_add) { ASSERT (im->cb.check_support_cb); - err = im->cb.check_support_cb (&sa); - if (err) - return err; + error = im->cb.check_support_cb (&sa); + if (error) + goto done; } ipsec_add_del_sa (vm, &sa, is_add); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -183,6 +203,7 @@ ipsec_spd_add_del_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u32 spd_id = ~0; int is_add = ~0; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -196,18 +217,25 @@ ipsec_spd_add_del_command_fn (vlib_main_t * vm, else if (unformat (line_input, "%u", &spd_id)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (spd_id == ~0) - return clib_error_return (0, "please specify SPD ID"); + { + error = clib_error_return (0, "please specify SPD ID"); + goto done; + } ipsec_add_del_spd (vm, spd_id, is_add); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -230,6 +258,7 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, int is_add = 0; int is_ip_any = 1; u32 tmp, tmp2; + clib_error_t *error = NULL; memset (&p, 0, sizeof (p)); p.lport.stop = p.rport.stop = ~0; @@ -262,7 +291,10 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, &p.policy)) { if (p.policy == IPSEC_POLICY_ACTION_RESOLVE) - return clib_error_return (0, "unsupported action: 'resolve'"); + { + error = clib_error_return (0, "unsupported action: 'resolve'"); + goto done; + } } else if (unformat (line_input, "sa %u", &p.sa_id)) ; @@ -300,19 +332,24 @@ ipsec_policy_add_del_command_fn (vlib_main_t * vm, p.rport.stop = tmp2; } else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - ipsec_add_del_policy (vm, &p, is_add); if (is_ip_any) { p.is_ipv6 = 1; ipsec_add_del_policy (vm, &p, is_add); } - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -332,6 +369,7 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; ipsec_sa_t sa; u8 *ck = 0, *ik = 0; + clib_error_t *error = NULL; memset (&sa, 0, sizeof (sa)); @@ -349,12 +387,13 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm, if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik)) sa.integ_key_len = vec_len (ik); else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (sa.crypto_key_len > sizeof (sa.crypto_key)) sa.crypto_key_len = sizeof (sa.crypto_key); @@ -369,7 +408,10 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm, ipsec_set_sa_key (vm, &sa); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -649,6 +691,7 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, ipsec_add_del_tunnel_args_t a; int rv; u32 num_m_args = 0; + clib_error_t *error = NULL; memset (&a, 0, sizeof (a)); a.is_add = 1; @@ -673,13 +716,18 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "del")) a.is_add = 0; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args < 4) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } rv = ipsec_add_del_tunnel_if (&a); @@ -689,16 +737,21 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, break; case VNET_API_ERROR_INVALID_VALUE: if (a.is_add) - return clib_error_return (0, - "IPSec tunnel interface already exists..."); + error = clib_error_return (0, + "IPSec tunnel interface already exists..."); else - return clib_error_return (0, "IPSec tunnel interface not exists..."); + error = clib_error_return (0, "IPSec tunnel interface not exists..."); + goto done; default: - return clib_error_return (0, "ipsec_register_interface returned %d", - rv); + error = clib_error_return (0, "ipsec_register_interface returned %d", + rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -720,6 +773,7 @@ set_interface_key_command_fn (vlib_main_t * vm, u32 hw_if_index = (u32) ~ 0; u32 alg; u8 *key = 0; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -748,25 +802,38 @@ set_interface_key_command_fn (vlib_main_t * vm, else if (unformat (line_input, "%U", unformat_hex_string, &key)) ; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (type == IPSEC_IF_SET_KEY_TYPE_NONE) - return clib_error_return (0, "unknown key type"); + { + error = clib_error_return (0, "unknown key type"); + goto done; + } if (alg > 0 && vec_len (key) == 0) - return clib_error_return (0, "key is not specified"); + { + error = clib_error_return (0, "key is not specified"); + goto done; + } if (hw_if_index == (u32) ~ 0) - return clib_error_return (0, "interface not specified"); + { + error = clib_error_return (0, "interface not specified"); + goto done; + } ipsec_set_interface_key (im->vnet_main, hw_if_index, type, alg, key); + +done: vec_free (key); + unformat_free (line_input); - return 0; + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/l2/l2_patch.c b/src/vnet/l2/l2_patch.c index 5e4691f4..ff3d2f3a 100644 --- a/src/vnet/l2/l2_patch.c +++ b/src/vnet/l2/l2_patch.c @@ -315,6 +315,7 @@ test_patch_command_fn (vlib_main_t * vm, int rx_set = 0; int tx_set = 0; int is_add = 1; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -335,10 +336,16 @@ test_patch_command_fn (vlib_main_t * vm, } if (rx_set == 0) - return clib_error_return (0, "rx interface not set"); + { + error = clib_error_return (0, "rx interface not set"); + goto done; + } if (tx_set == 0) - return clib_error_return (0, "tx interface not set"); + { + error = clib_error_return (0, "tx interface not set"); + goto done; + } rv = vnet_l2_patch_add_del (rx_sw_if_index, tx_sw_if_index, is_add); @@ -348,17 +355,24 @@ test_patch_command_fn (vlib_main_t * vm, break; case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return (0, "rx interface not a physical port"); + error = clib_error_return (0, "rx interface not a physical port"); + goto done; case VNET_API_ERROR_INVALID_SW_IF_INDEX_2: - return clib_error_return (0, "tx interface not a physical port"); + error = clib_error_return (0, "tx interface not a physical port"); + goto done; default: - return clib_error_return + error = clib_error_return (0, "WARNING: vnet_l2_patch_add_del returned %d", rv); + goto done; } - return 0; + +done: + unformat_free (line_input); + + return error; } /*? diff --git a/src/vnet/l2/l2_xcrw.c b/src/vnet/l2/l2_xcrw.c index 70610a85..d08a5d8f 100644 --- a/src/vnet/l2/l2_xcrw.c +++ b/src/vnet/l2/l2_xcrw.c @@ -409,6 +409,7 @@ set_l2_xcrw_command_fn (vlib_main_t * vm, u8 *rw = 0; vnet_main_t *vnm = vnet_get_main (); int rv; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) @@ -416,8 +417,11 @@ set_l2_xcrw_command_fn (vlib_main_t * vm, if (!unformat (line_input, "%U", unformat_vnet_sw_interface, vnm, &l2_sw_if_index)) - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { @@ -436,7 +440,10 @@ set_l2_xcrw_command_fn (vlib_main_t * vm, } if (next_node_index == ~0) - return clib_error_return (0, "next node not specified"); + { + error = clib_error_return (0, "next node not specified"); + goto done; + } if (tx_fib_id != ~0) { @@ -448,7 +455,11 @@ set_l2_xcrw_command_fn (vlib_main_t * vm, p = hash_get (ip4_main.fib_index_by_table_id, tx_fib_id); if (p == 0) - return clib_error_return (0, "nonexistent tx_fib_id %d", tx_fib_id); + { + error = + clib_error_return (0, "nonexistent tx_fib_id %d", tx_fib_id); + goto done; + } tx_fib_index = p[0]; } @@ -463,16 +474,21 @@ set_l2_xcrw_command_fn (vlib_main_t * vm, break; case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return (0, "%U not cross-connected", - format_vnet_sw_if_index_name, - vnm, l2_sw_if_index); + error = clib_error_return (0, "%U not cross-connected", + format_vnet_sw_if_index_name, + vnm, l2_sw_if_index); + goto done; + default: - return clib_error_return (0, "vnet_configure_l2_xcrw returned %d", rv); + error = clib_error_return (0, "vnet_configure_l2_xcrw returned %d", rv); + goto done; } +done: vec_free (rw); + unformat_free (line_input); - return 0; + return error; } /*? diff --git a/src/vnet/l2tp/l2tp.c b/src/vnet/l2tp/l2tp.c index a4531dab..2d323397 100644 --- a/src/vnet/l2tp/l2tp.c +++ b/src/vnet/l2tp/l2tp.c @@ -427,6 +427,7 @@ create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, u32 sw_if_index; u32 encap_fib_id = ~0; u32 encap_fib_index = ~0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -455,18 +456,22 @@ create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "l2-sublayer-present")) l2_sublayer_present = 1; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (encap_fib_id != ~0) { uword *p; ip6_main_t *im = &ip6_main; if (!(p = hash_get (im->fib_index_by_table_id, encap_fib_id))) - return clib_error_return (0, "No fib with id %d", encap_fib_id); + { + error = clib_error_return (0, "No fib with id %d", encap_fib_id); + goto done; + } encap_fib_index = p[0]; } else @@ -475,9 +480,15 @@ create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, } if (our_address_set == 0) - return clib_error_return (0, "our address not specified"); + { + error = clib_error_return (0, "our address not specified"); + goto done; + } if (client_address_set == 0) - return clib_error_return (0, "client address not specified"); + { + error = clib_error_return (0, "client address not specified"); + goto done; + } rv = create_l2tpv3_ipv6_tunnel (lm, &client_address, &our_address, local_session_id, remote_session_id, @@ -491,16 +502,22 @@ create_l2tpv3_tunnel_command_fn (vlib_main_t * vm, vnet_get_main (), sw_if_index); break; case VNET_API_ERROR_INVALID_VALUE: - return clib_error_return (0, "session already exists..."); + error = clib_error_return (0, "session already exists..."); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "session does not exist..."); + error = clib_error_return (0, "session does not exist..."); + goto done; default: - return clib_error_return (0, "l2tp_session_add_del returned %d", rv); + error = clib_error_return (0, "l2tp_session_add_del returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/lisp-cp/lisp_cli.c b/src/vnet/lisp-cp/lisp_cli.c index 25d11c61..05df9fb6 100644 --- a/src/vnet/lisp-cp/lisp_cli.c +++ b/src/vnet/lisp-cp/lisp_cli.c @@ -25,6 +25,7 @@ lisp_show_adjacencies_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "%s %40s\n", "leid", "reid"); unformat_input_t _line_input, *line_input = &_line_input; u32 vni = ~0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -38,14 +39,14 @@ lisp_show_adjacencies_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (~0 == vni) { vlib_cli_output (vm, "error: no vni specified!"); - return 0; + goto done; } adjs = vnet_lisp_adjacencies_get_by_vni (vni); @@ -57,7 +58,10 @@ lisp_show_adjacencies_command_fn (vlib_main_t * vm, } vec_free (adjs); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -77,6 +81,7 @@ lisp_add_del_map_server_command_fn (vlib_main_t * vm, u8 is_add = 1, ip_set = 0; ip_address_t ip; unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -94,14 +99,14 @@ lisp_add_del_map_server_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (!ip_set) { vlib_cli_output (vm, "map-server ip address not set!"); - return 0; + goto done; } rv = vnet_lisp_add_del_map_server (&ip, is_add); @@ -109,7 +114,10 @@ lisp_add_del_map_server_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "failed to %s map-server!", is_add ? "add" : "delete"); - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -191,7 +199,7 @@ lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input, if (key && (0 == key_id)) { vlib_cli_output (vm, "invalid key_id!"); - return 0; + goto done;; } gid_address_copy (&a->eid, &eid); @@ -213,6 +221,8 @@ done: vec_free (locator_set_name); gid_address_free (&a->eid); vec_free (a->key); + unformat_free (line_input); + return error; } @@ -233,6 +243,7 @@ lisp_eid_table_map_command_fn (vlib_main_t * vm, u8 is_add = 1, is_l2 = 0; u32 vni = 0, dp_id = 0; unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -250,11 +261,16 @@ lisp_eid_table_map_command_fn (vlib_main_t * vm, is_l2 = 1; else { - return unformat_parse_error (line_input); + error = unformat_parse_error (line_input); + goto done; } } vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -479,7 +495,7 @@ lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input, != ip_prefix_version (leid_ippref))) { clib_warning ("remote and local EIDs are of different types!"); - return error; + goto done; } memset (a, 0, sizeof (a[0])); @@ -512,6 +528,7 @@ lisp_map_request_mode_command_fn (vlib_main_t * vm, { unformat_input_t _i, *i = &_i; map_request_mode_t mr_mode = _MR_MODE_MAX; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, i)) @@ -533,12 +550,15 @@ lisp_map_request_mode_command_fn (vlib_main_t * vm, if (_MR_MODE_MAX == mr_mode) { clib_warning ("No LISP map request mode entered!"); - return 0; + goto done; } vnet_lisp_set_map_request_mode (mr_mode); + done: - return 0; + unformat_free (i); + + return error; } /* *INDENT-OFF* */ @@ -630,7 +650,10 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, else if (unformat (line_input, "disable")) is_add = 0; else - return clib_error_return (0, "parse error"); + { + error = clib_error_return (0, "parse error"); + goto done; + } } if (!locator_name_set) @@ -648,6 +671,8 @@ lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm, done: if (locator_set_name) vec_free (locator_set_name); + unformat_free (line_input); + return error; } @@ -771,6 +796,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, gid_address_t eid; u8 print_all = 1; u8 filter = 0; + clib_error_t *error = NULL; memset (&eid, 0, sizeof (eid)); @@ -787,8 +813,11 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, else if (unformat (line_input, "remote")) filter = 2; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s", @@ -818,7 +847,7 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, { mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid); if ((u32) ~ 0 == mi) - return 0; + goto done; mapit = pool_elt_at_index (lcm->mapping_pool, mi); locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, @@ -827,14 +856,17 @@ lisp_show_eid_table_command_fn (vlib_main_t * vm, if (filter && !((1 == filter && ls->local) || (2 == filter && !ls->local))) { - return 0; + goto done; } vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main, lcm, mapit, ls); } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -853,6 +885,7 @@ lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -869,16 +902,24 @@ lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input, is_set = 1; else { - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; } } if (!is_set) - return clib_error_return (0, "state not set"); + { + error = clib_error_return (0, "state not set"); + goto done; + } vnet_lisp_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -897,6 +938,7 @@ lisp_map_register_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -915,18 +957,22 @@ lisp_map_register_enable_disable_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (!is_set) { vlib_cli_output (vm, "state not set!"); - return 0; + goto done; } vnet_lisp_map_register_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -945,6 +991,7 @@ lisp_rloc_probe_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u8 is_enabled = 0; u8 is_set = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -963,18 +1010,22 @@ lisp_rloc_probe_enable_disable_command_fn (vlib_main_t * vm, { vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, line_input); - return 0; + goto done; } } if (!is_set) { vlib_cli_output (vm, "state not set!"); - return 0; + goto done; } vnet_lisp_rloc_probe_enable_disable (is_enabled); - return 0; + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1022,6 +1073,7 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); uword *vni_table = 0; u8 is_l2 = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -1040,14 +1092,17 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, is_l2 = 0; } else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } if (!vni_table) { vlib_cli_output (vm, "Error: expected l2|l3 param!\n"); - return 0; + goto done; } vlib_cli_output (vm, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF"); @@ -1059,7 +1114,10 @@ lisp_show_eid_table_map_command_fn (vlib_main_t * vm, })); /* *INDENT-ON* */ - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ @@ -1131,6 +1189,8 @@ done: vec_free (locators); if (locator_set_name) vec_free (locator_set_name); + unformat_free (line_input); + return error; } @@ -1205,6 +1265,8 @@ lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, done: vec_free (locators); vec_free (locator_set_name); + unformat_free (line_input); + return error; } @@ -1322,6 +1384,8 @@ lisp_add_del_map_resolver_command_fn (vlib_main_t * vm, } done: + unformat_free (line_input); + return error; } @@ -1372,11 +1436,11 @@ lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm, is_add ? "add" : "delete"); } +done: vec_free (locator_set_name); + unformat_free (line_input); -done: return error; - } /* *INDENT-OFF* */ @@ -1438,7 +1502,10 @@ lisp_use_petr_set_locator_set_command_fn (vlib_main_t * vm, else if (unformat (line_input, "disable")) is_add = 0; else - return clib_error_return (0, "parse error"); + { + error = clib_error_return (0, "parse error"); + goto done; + } } if (!ip_set) @@ -1454,6 +1521,8 @@ lisp_use_petr_set_locator_set_command_fn (vlib_main_t * vm, } done: + unformat_free (line_input); + return error; } diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 2142e095..19ac22e7 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -794,6 +794,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, u32 table_id, vni, bd_id; u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0; u8 nsh_iface = 0; + clib_error_t *error = NULL; if (vnet_lisp_gpe_enable_disable_status () == 0) { @@ -828,8 +829,9 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, } else { - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; } } @@ -839,7 +841,8 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main)) { - return clib_error_return (0, "NSH interface not created"); + error = clib_error_return (0, "NSH interface not created"); + goto done; } } else @@ -850,21 +853,34 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, } if (vrf_is_set && bd_index_is_set) - return clib_error_return (0, - "Cannot set both vrf and brdige domain index!"); + { + error = clib_error_return + (0, "Cannot set both vrf and brdige domain index!"); + goto done; + } if (!vni_is_set) - return clib_error_return (0, "vni must be set!"); + { + error = clib_error_return (0, "vni must be set!"); + goto done; + } if (!vrf_is_set && !bd_index_is_set) - return clib_error_return (0, "vrf or bridge domain index must be set!"); + { + error = + clib_error_return (0, "vrf or bridge domain index must be set!"); + goto done; + } if (bd_index_is_set) { if (is_add) { if (~0 == lisp_gpe_tenant_l2_iface_add_or_lock (vni, bd_id)) - return clib_error_return (0, "L2 interface not created"); + { + error = clib_error_return (0, "L2 interface not created"); + goto done; + } } else lisp_gpe_tenant_l2_iface_unlock (vni); @@ -874,13 +890,35 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input, if (is_add) { if (~0 == lisp_gpe_tenant_l3_iface_add_or_lock (vni, table_id)) - return clib_error_return (0, "L3 interface not created"); + { + error = clib_error_return (0, "L3 interface not created"); + goto done; + } } else lisp_gpe_tenant_l3_iface_unlock (vni); } - return (NULL); + if (nsh_iface) + { + if (is_add) + { + if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main)) + { + error = clib_error_return (0, "NSH interface not created"); + goto done; + } + else + { + lisp_gpe_del_nsh_iface (&lisp_gpe_main); + } + } + } + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index 1f8afdae..f2fbcbd5 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -218,6 +218,7 @@ lisp_gpe_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u8 is_en = 1; vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -231,12 +232,18 @@ lisp_gpe_enable_disable_command_fn (vlib_main_t * vm, is_en = 0; else { - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; } } a->is_en = is_en; - return vnet_lisp_gpe_enable_disable (a); + error = vnet_lisp_gpe_enable_disable (a); + +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/map/map.c b/src/vnet/map/map.c index aeec6a94..a2d28118 100644 --- a/src/vnet/map/map.c +++ b/src/vnet/map/map.c @@ -465,6 +465,8 @@ map_security_check_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; + clib_error_t *error = NULL; + /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -476,11 +478,17 @@ map_security_check_command_fn (vlib_main_t * vm, else if (unformat (line_input, "on")) mm->sec_check = true; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + + return error; } static clib_error_t * @@ -490,6 +498,8 @@ map_security_check_frag_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; + clib_error_t *error = NULL; + /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -501,11 +511,17 @@ map_security_check_frag_command_fn (vlib_main_t * vm, else if (unformat (line_input, "on")) mm->sec_check_frag = true; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + + return error; } static clib_error_t * @@ -523,6 +539,7 @@ map_add_domain_command_fn (vlib_main_t * vm, u32 mtu = 0; u8 flags = 0; ip6_src_len = 128; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -559,20 +576,28 @@ map_add_domain_command_fn (vlib_main_t * vm, else if (unformat (line_input, "map-t")) flags |= MAP_DOMAIN_TRANSLATION; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args < 3) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } map_create_domain (&ip4_prefix, ip4_prefix_len, &ip6_prefix, ip6_prefix_len, &ip6_src, ip6_src_len, ea_bits_len, psid_offset, psid_length, &map_domain_index, mtu, flags); - return 0; +done: + unformat_free (line_input); + + return error; } static clib_error_t * @@ -582,6 +607,7 @@ map_del_domain_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; u32 num_m_args = 0; u32 map_domain_index; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -592,17 +618,25 @@ map_del_domain_command_fn (vlib_main_t * vm, if (unformat (line_input, "index %d", &map_domain_index)) num_m_args++; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args != 1) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } map_delete_domain (map_domain_index); - return 0; +done: + unformat_free (line_input); + + return error; } static clib_error_t * @@ -613,6 +647,7 @@ map_add_rule_command_fn (vlib_main_t * vm, ip6_address_t tep; u32 num_m_args = 0; u32 psid = 0, map_domain_index; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -628,19 +663,29 @@ map_add_rule_command_fn (vlib_main_t * vm, if (unformat (line_input, "ip6-dst %U", unformat_ip6_address, &tep)) num_m_args++; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args != 3) - return clib_error_return (0, "mandatory argument(s) missing"); + { + error = clib_error_return (0, "mandatory argument(s) missing"); + goto done; + } if (map_add_del_psid (map_domain_index, psid, &tep, 1) != 0) { - return clib_error_return (0, "Failing to add Mapping Rule"); + error = clib_error_return (0, "Failing to add Mapping Rule"); + goto done; } - return 0; + +done: + unformat_free (line_input); + + return error; } #if MAP_SKIP_IP6_LOOKUP @@ -653,6 +698,7 @@ map_pre_resolve_command_fn (vlib_main_t * vm, ip4_address_t ip4nh; ip6_address_t ip6nh; map_main_t *mm = &map_main; + clib_error_t *error = NULL; memset (&ip4nh, 0, sizeof (ip4nh)); memset (&ip6nh, 0, sizeof (ip6nh)); @@ -669,14 +715,19 @@ map_pre_resolve_command_fn (vlib_main_t * vm, if (unformat (line_input, "ip6-nh %U", unformat_ip6_address, &ip6nh)) mm->preresolve_ip6 = ip6nh; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); map_pre_resolve (&ip4nh, &ip6nh); - return 0; +done: + unformat_free (line_input); + + return error; } #endif @@ -688,6 +739,7 @@ map_icmp_relay_source_address_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; ip4_address_t icmp_src_address; map_main_t *mm = &map_main; + clib_error_t *error = NULL; mm->icmp4_src_address.as_u32 = 0; @@ -701,12 +753,17 @@ map_icmp_relay_source_address_command_fn (vlib_main_t * vm, (line_input, "%U", unformat_ip4_address, &icmp_src_address)) mm->icmp4_src_address = icmp_src_address; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + return error; } static clib_error_t * @@ -717,6 +774,7 @@ map_icmp_unreachables_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; int num_m_args = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -730,16 +788,21 @@ map_icmp_unreachables_command_fn (vlib_main_t * vm, else if (unformat (line_input, "off")) mm->icmp6_enabled = false; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (num_m_args != 1) - return clib_error_return (0, "mandatory argument(s) missing"); + error = clib_error_return (0, "mandatory argument(s) missing"); - return 0; +done: + unformat_free (line_input); + + return error; } static clib_error_t * @@ -748,6 +811,7 @@ map_fragment_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -760,12 +824,17 @@ map_fragment_command_fn (vlib_main_t * vm, else if (unformat (line_input, "outer")) mm->frag_inner = false; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + return error; } static clib_error_t * @@ -775,6 +844,7 @@ map_fragment_df_command_fn (vlib_main_t * vm, { unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -787,12 +857,17 @@ map_fragment_df_command_fn (vlib_main_t * vm, else if (unformat (line_input, "off")) mm->frag_ignore_df = false; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + return error; } static clib_error_t * @@ -803,6 +878,7 @@ map_traffic_class_command_fn (vlib_main_t * vm, unformat_input_t _line_input, *line_input = &_line_input; map_main_t *mm = &map_main; u32 tc = 0; + clib_error_t *error = NULL; mm->tc_copy = false; @@ -817,12 +893,17 @@ map_traffic_class_command_fn (vlib_main_t * vm, else if (unformat (line_input, "%x", &tc)) mm->tc = tc & 0xff; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + +done: unformat_free (line_input); - return 0; + return error; } static u8 * @@ -922,6 +1003,7 @@ show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input, map_domain_t *d; bool counters = false; u32 map_domain_index = ~0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -934,10 +1016,12 @@ show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "index %d", &map_domain_index)) ; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); if (pool_elts (mm->domains) == 0) vlib_cli_output (vm, "No MAP domains are configured..."); @@ -952,15 +1036,19 @@ show_map_domain_command_fn (vlib_main_t * vm, unformat_input_t * input, { if (pool_is_free_index (mm->domains, map_domain_index)) { - return clib_error_return (0, "MAP domain does not exists %d", - map_domain_index); + error = clib_error_return (0, "MAP domain does not exists %d", + map_domain_index); + goto done; } d = pool_elt_at_index (mm->domains, map_domain_index); vlib_cli_output (vm, "%U", format_map_domain, d, counters); } - return 0; +done: + unformat_free (line_input); + + return error; } static clib_error_t * diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c index 0e610e17..7ae4aa00 100644 --- a/src/vnet/mpls/mpls.c +++ b/src/vnet/mpls/mpls.c @@ -470,6 +470,8 @@ vnet_mpls_local_label (vlib_main_t * vm, } done: + unformat_free (line_input); + return error; } diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c index 8d1e30a3..e488271d 100644 --- a/src/vnet/mpls/mpls_tunnel.c +++ b/src/vnet/mpls/mpls_tunnel.c @@ -535,6 +535,7 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, fib_route_path_t rpath, *rpaths = NULL; mpls_label_t out_label = MPLS_LABEL_INVALID, *labels = NULL; u32 sw_if_index; + clib_error_t *error = NULL; memset(&rpath, 0, sizeof(rpath)); @@ -595,8 +596,11 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "l2-only")) l2_only = 1; else - return clib_error_return (0, "unknown input '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } } if (is_del) @@ -606,17 +610,22 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm, else { if (0 == vec_len(labels)) - return clib_error_return (0, "No Output Labels '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "No Output Labels '%U'", + format_unformat_error, line_input); + goto done; + } vec_add1(rpaths, rpath); vnet_mpls_tunnel_add(rpaths, labels, l2_only, &sw_if_index); } +done: vec_free(labels); vec_free(rpaths); + unformat_free (line_input); - return (NULL); + return error; } /*? diff --git a/src/vnet/pg/cli.c b/src/vnet/pg/cli.c index f5896b43..3c249a7b 100644 --- a/src/vnet/pg/cli.c +++ b/src/vnet/pg/cli.c @@ -547,21 +547,30 @@ pg_capture_cmd_fn (vlib_main_t * vm, else { error = clib_error_create ("unknown input `%U'", - format_unformat_error, input); - return error; + format_unformat_error, line_input); + goto done; } } if (!hi) - return clib_error_return (0, "Please specify interface name"); + { + error = clib_error_return (0, "Please specify interface name"); + goto done; + } if (hi->dev_class_index != pg_dev_class.index) - return clib_error_return (0, "Please specify packet-generator interface"); + { + error = + clib_error_return (0, "Please specify packet-generator interface"); + goto done; + } if (!pcap_file_name && is_disable == 0) - return clib_error_return (0, "Please specify pcap file name"); + { + error = clib_error_return (0, "Please specify pcap file name"); + goto done; + } - unformat_free (line_input); pg_capture_args_t _a, *a = &_a; @@ -572,6 +581,10 @@ pg_capture_cmd_fn (vlib_main_t * vm, a->count = count; error = pg_capture (a); + +done: + unformat_free (line_input); + return error; } @@ -590,6 +603,7 @@ create_pg_if_cmd_fn (vlib_main_t * vm, pg_main_t *pg = &pg_main; unformat_input_t _line_input, *line_input = &_line_input; u32 if_id; + clib_error_t *error = NULL; if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -600,14 +614,19 @@ create_pg_if_cmd_fn (vlib_main_t * vm, ; else - return clib_error_create ("unknown input `%U'", - format_unformat_error, input); + { + error = clib_error_create ("unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + pg_interface_add_or_get (pg, if_id); + +done: unformat_free (line_input); - pg_interface_add_or_get (pg, if_id); - return 0; + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/policer/node_funcs.c b/src/vnet/policer/node_funcs.c index 1f4997ff..457dd09f 100644 --- a/src/vnet/policer/node_funcs.c +++ b/src/vnet/policer/node_funcs.c @@ -447,6 +447,7 @@ test_policer_command_fn (vlib_main_t * vm, int rx_set = 0; int is_add = 1; int is_show = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -468,7 +469,10 @@ test_policer_command_fn (vlib_main_t * vm, } if (rx_set == 0) - return clib_error_return (0, "interface not set"); + { + error = clib_error_return (0, "interface not set"); + goto done; + } if (is_show) { @@ -477,12 +481,13 @@ test_policer_command_fn (vlib_main_t * vm, policer = pool_elt_at_index (pm->policers, pi); vlib_cli_output (vm, "%U", format_policer_instance, policer); - return 0; + goto done; } if (is_add && config_name == 0) { - return clib_error_return (0, "policer config name required"); + error = clib_error_return (0, "policer config name required"); + goto done; } rv = test_policer_add_del (rx_sw_if_index, config_name, is_add); @@ -493,11 +498,15 @@ test_policer_command_fn (vlib_main_t * vm, break; default: - return clib_error_return + error = clib_error_return (0, "WARNING: vnet_vnet_policer_add_del returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/policer/policer.c b/src/vnet/policer/policer.c index 290a6af5..cd754e29 100644 --- a/src/vnet/policer/policer.c +++ b/src/vnet/policer/policer.c @@ -413,6 +413,7 @@ configure_policer_command_fn (vlib_main_t * vm, u8 is_add = 1; u8 *name = 0; u32 pi; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -433,13 +434,19 @@ configure_policer_command_fn (vlib_main_t * vm, foreach_config_param #undef _ else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } + error = policer_add_del (vm, name, &c, &pi, is_add); + +done: unformat_free (line_input); - return policer_add_del (vm, name, &c, &pi, is_add); + return error; } /* *INDENT-OFF* */ diff --git a/src/vnet/unix/tapcli.c b/src/vnet/unix/tapcli.c index 48e81b50..25c930c6 100644 --- a/src/vnet/unix/tapcli.c +++ b/src/vnet/unix/tapcli.c @@ -1308,6 +1308,7 @@ tap_connect_command_fn (vlib_main_t * vm, int ip6_address_set = 0; u32 ip4_mask_width = 0; u32 ip6_mask_width = 0; + clib_error_t *error = NULL; if (tm->is_disabled) return clib_error_return (0, "device disabled..."); @@ -1336,12 +1337,18 @@ tap_connect_command_fn (vlib_main_t * vm, else if (unformat (line_input, "%s", &intfc_name)) ; else - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } } if (intfc_name == 0) - return clib_error_return (0, "interface name must be specified"); + { + error = clib_error_return (0, "interface name must be specified"); + goto done; + } memset (ap, 0, sizeof (*ap)); @@ -1367,48 +1374,64 @@ tap_connect_command_fn (vlib_main_t * vm, switch (rv) { case VNET_API_ERROR_SYSCALL_ERROR_1: - return clib_error_return (0, "Couldn't open /dev/net/tun"); + error = clib_error_return (0, "Couldn't open /dev/net/tun"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_2: - return clib_error_return (0, "Error setting flags on '%s'", intfc_name); - + error = clib_error_return (0, "Error setting flags on '%s'", intfc_name); + goto done; + case VNET_API_ERROR_SYSCALL_ERROR_3: - return clib_error_return (0, "Couldn't open provisioning socket"); + error = clib_error_return (0, "Couldn't open provisioning socket"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_4: - return clib_error_return (0, "Couldn't get if_index"); + error = clib_error_return (0, "Couldn't get if_index"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_5: - return clib_error_return (0, "Couldn't bind provisioning socket"); + error = clib_error_return (0, "Couldn't bind provisioning socket"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_6: - return clib_error_return (0, "Couldn't set device non-blocking flag"); + error = clib_error_return (0, "Couldn't set device non-blocking flag"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_7: - return clib_error_return (0, "Couldn't set device MTU"); + error = clib_error_return (0, "Couldn't set device MTU"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_8: - return clib_error_return (0, "Couldn't get interface flags"); + error = clib_error_return (0, "Couldn't get interface flags"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_9: - return clib_error_return (0, "Couldn't set intfc admin state up"); + error = clib_error_return (0, "Couldn't set intfc admin state up"); + goto done; case VNET_API_ERROR_SYSCALL_ERROR_10: - return clib_error_return (0, "Couldn't set intfc address/mask"); + error = clib_error_return (0, "Couldn't set intfc address/mask"); + goto done; case VNET_API_ERROR_INVALID_REGISTRATION: - return clib_error_return (0, "Invalid registration"); + error = clib_error_return (0, "Invalid registration"); + goto done; case 0: break; default: - return clib_error_return (0, "Unknown error: %d", rv); + error = clib_error_return (0, "Unknown error: %d", rv); + goto done; } vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index); - return 0; + +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (tap_connect_command, static) = { diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.c b/src/vnet/vxlan-gpe/vxlan_gpe.c index b97510c4..2cba596f 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.c +++ b/src/vnet/vxlan-gpe/vxlan_gpe.c @@ -454,6 +454,7 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, u32 tmp; vnet_vxlan_gpe_add_del_tunnel_args_t _a, * a = &_a; u32 sw_if_index; + clib_error_t *error = NULL; /* Get a line of input. */ if (! unformat_user (input, unformat_line_input, line_input)) @@ -494,7 +495,10 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, encap_fib_index = ip4_fib_index_from_table_id (tmp); if (encap_fib_index == ~0) - return clib_error_return (0, "nonexistent encap fib id %d", tmp); + { + error = clib_error_return (0, "nonexistent encap fib id %d", tmp); + goto done; + } } else if (unformat (line_input, "decap-vrf-id %d", &tmp)) { @@ -504,7 +508,10 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, decap_fib_index = ip4_fib_index_from_table_id (tmp); if (decap_fib_index == ~0) - return clib_error_return (0, "nonexistent decap fib id %d", tmp); + { + error = clib_error_return (0, "nonexistent decap fib id %d", tmp); + goto done; + } } else if (unformat (line_input, "vni %d", &vni)) vni_set = 1; @@ -517,27 +524,43 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, else if (unformat(line_input, "next-nsh")) protocol = VXLAN_GPE_PROTOCOL_NSH; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (local_set == 0) - return clib_error_return (0, "tunnel local address not specified"); + { + error = clib_error_return (0, "tunnel local address not specified"); + goto done; + } if (remote_set == 0) - return clib_error_return (0, "tunnel remote address not specified"); + { + error = clib_error_return (0, "tunnel remote address not specified"); + goto done; + } if (ipv4_set && ipv6_set) - return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + { + error = clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + goto done; + } if ((ipv4_set && memcmp(&local.ip4, &remote.ip4, sizeof(local.ip4)) == 0) || (ipv6_set && memcmp(&local.ip6, &remote.ip6, sizeof(local.ip6)) == 0)) - return clib_error_return (0, "src and dst addresses are identical"); + { + error = clib_error_return (0, "src and dst addresses are identical"); + goto done; + } if (vni_set == 0) - return clib_error_return (0, "vni not specified"); + { + error = clib_error_return (0, "vni not specified"); + goto done; + } memset (a, 0, sizeof (*a)); @@ -558,20 +581,27 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, vlib_cli_output(vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main(), sw_if_index); break; case VNET_API_ERROR_INVALID_DECAP_NEXT: - return clib_error_return (0, "invalid decap-next..."); + error = clib_error_return (0, "invalid decap-next..."); + goto done; case VNET_API_ERROR_TUNNEL_EXIST: - return clib_error_return (0, "tunnel already exists..."); + error = clib_error_return (0, "tunnel already exists..."); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "tunnel does not exist..."); + error = clib_error_return (0, "tunnel does not exist..."); + goto done; default: - return clib_error_return + error = clib_error_return (0, "vnet_vxlan_gpe_add_del_tunnel returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = { diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index 849fc25d..eedc16f8 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -657,6 +657,7 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, int rv; vnet_vxlan_add_del_tunnel_args_t _a, * a = &_a; u32 tunnel_sw_if_index; + clib_error_t *error = NULL; /* Cant "universally zero init" (={0}) due to GCC bug 53119 */ memset(&src, 0, sizeof src); @@ -715,7 +716,10 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, { encap_fib_index = fib_table_find (fib_ip_proto (ipv6_set), tmp); if (encap_fib_index == ~0) - return clib_error_return (0, "nonexistent encap-vrf-id %d", tmp); + { + error = clib_error_return (0, "nonexistent encap-vrf-id %d", tmp); + goto done; + } } else if (unformat (line_input, "decap-next %U", unformat_decap_next, &decap_next_index, ipv4_set)) @@ -723,41 +727,72 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, else if (unformat (line_input, "vni %d", &vni)) { if (vni >> 24) - return clib_error_return (0, "vni %d out of range", vni); + { + error = clib_error_return (0, "vni %d out of range", vni); + goto done; + } } else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + goto done; + } } - unformat_free (line_input); - if (src_set == 0) - return clib_error_return (0, "tunnel src address not specified"); + { + error = clib_error_return (0, "tunnel src address not specified"); + goto done; + } if (dst_set == 0) - return clib_error_return (0, "tunnel dst address not specified"); + { + error = clib_error_return (0, "tunnel dst address not specified"); + goto done; + } if (grp_set && !ip46_address_is_multicast(&dst)) - return clib_error_return (0, "tunnel group address not multicast"); + { + error = clib_error_return (0, "tunnel group address not multicast"); + goto done; + } if (grp_set == 0 && ip46_address_is_multicast(&dst)) - return clib_error_return (0, "dst address must be unicast"); + { + error = clib_error_return (0, "dst address must be unicast"); + goto done; + } if (grp_set && mcast_sw_if_index == ~0) - return clib_error_return (0, "tunnel nonexistent multicast device"); + { + error = clib_error_return (0, "tunnel nonexistent multicast device"); + goto done; + } if (ipv4_set && ipv6_set) - return clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + { + error = clib_error_return (0, "both IPv4 and IPv6 addresses specified"); + goto done; + } if (ip46_address_cmp(&src, &dst) == 0) - return clib_error_return (0, "src and dst addresses are identical"); + { + error = clib_error_return (0, "src and dst addresses are identical"); + goto done; + } if (decap_next_index == ~0) - return clib_error_return (0, "next node not found"); + { + error = clib_error_return (0, "next node not found"); + goto done; + } if (vni == 0) - return clib_error_return (0, "vni not specified"); + { + error = clib_error_return (0, "vni not specified"); + goto done; + } memset (a, 0, sizeof (*a)); @@ -779,17 +814,23 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm, break; case VNET_API_ERROR_TUNNEL_EXIST: - return clib_error_return (0, "tunnel already exists..."); + error = clib_error_return (0, "tunnel already exists..."); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: - return clib_error_return (0, "tunnel does not exist..."); + error = clib_error_return (0, "tunnel does not exist..."); + goto done; default: - return clib_error_return + error = clib_error_return (0, "vnet_vxlan_add_del_tunnel returned %d", rv); + goto done; } - return 0; +done: + unformat_free (line_input); + + return error; } /*? @@ -912,6 +953,8 @@ set_ip_vxlan_bypass (u32 is_ip6, vnet_int_vxlan_bypass_mode (sw_if_index, is_ip6, is_enable); done: + unformat_free (line_input); + return error; } diff --git a/src/vpp/app/l2t.c b/src/vpp/app/l2t.c index 45dd2807..e1eda155 100644 --- a/src/vpp/app/l2t.c +++ b/src/vpp/app/l2t.c @@ -254,6 +254,7 @@ l2tp_session_add_command_fn (vlib_main_t * vm, u32 local_session_id = 1, remote_session_id = 1; int our_address_set = 0, client_address_set = 0; int l2_sublayer_present = 0; + clib_error_t *error = NULL; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) @@ -290,8 +291,12 @@ l2tp_session_add_command_fn (vlib_main_t * vm, else if (unformat (line_input, "l2-sublayer-present")) l2_sublayer_present = 1; else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); + { + error = clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + unformat_free (line_input); + return error; + } } unformat_free (line_input); diff --git a/src/vpp/app/vpe_cli.c b/src/vpp/app/vpe_cli.c index a26bf71f..94bdc84c 100644 --- a/src/vpp/app/vpe_cli.c +++ b/src/vpp/app/vpe_cli.c @@ -36,6 +36,7 @@ virtual_ip_cmd_fn_command_fn (vlib_main_t * vm, mac_addr_t *mac_addrs = 0; u32 sw_if_index; u32 i; + clib_error_t *error = NULL; next_hops = NULL; rpaths = NULL; @@ -49,7 +50,11 @@ virtual_ip_cmd_fn_command_fn (vlib_main_t * vm, if (!unformat (line_input, "%U %U", unformat_ip4_address, &prefix.fp_addr.ip4, unformat_vnet_sw_interface, vnm, &sw_if_index)) - goto barf; + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { @@ -67,13 +72,18 @@ virtual_ip_cmd_fn_command_fn (vlib_main_t * vm, } else { - barf: - return clib_error_return (0, "unknown input `%U'", - format_unformat_error, input); + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; } } + if (vec_len (mac_addrs) == 0 || vec_len (mac_addrs) != vec_len (next_hops)) - goto barf; + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } /* Create / delete special interface route /32's */ @@ -100,10 +110,12 @@ virtual_ip_cmd_fn_command_fn (vlib_main_t * vm, &prefix, FIB_SOURCE_CLI, FIB_ENTRY_FLAG_NONE, rpaths); +done: vec_free (mac_addrs); vec_free (next_hops); + unformat_free (line_input); - return 0; + return error; } /* *INDENT-OFF* */ -- cgit 1.2.3-korg From 7100b9cc6f1342a320c372bf746ae85cf815c41b Mon Sep 17 00:00:00 2001 From: John Lo Date: Tue, 28 Feb 2017 13:10:52 -0500 Subject: Clear L2 output config on interface mode change to L3 (VPP-651) With VPP-651, the L2 output config with L2-tag rewrite was not cleared when a sub-interface is deleted. Subsequently, when the same sw_if_index was reused for another interface, the L2 output config with L2-tag rewrite remained on the new interface. On deleting a (sub-)interface which is in L2 mode, it will be changed to L3 mode first to clear any L2 config. The L2 to L3 mode change path did address L2 input config cleanup. It is now fixed to also clear L2 output config. Change-Id: I3352a89d92e1b27340a5adcf75bbaa01a5050c29 Signed-off-by: John Lo --- src/vnet/l2/l2_input.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index ead9ca85..fbd75f22 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -513,10 +513,13 @@ l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value) */ u32 -set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_index, u32 bd_index, /* for bridged interface */ - u32 bvi, /* the bridged interface is the BVI */ - u32 shg, /* the bridged interface's split horizon group */ - u32 xc_sw_if_index) /* peer interface for xconnect */ +set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ + u32 mode, /* One of L2 modes or back to L3 mode */ + u32 sw_if_index, /* sw interface index */ + u32 bd_index, /* for bridged interface */ + u32 bvi, /* the bridged interface is the BVI */ + u32 shg, /* the bridged interface split horizon group */ + u32 xc_sw_if_index) /* peer interface for xconnect */ { l2input_main_t *mp = &l2input_main; l2output_main_t *l2om = &l2output_main; @@ -584,6 +587,10 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_ config->bd_index = 0; config->feature_bitmap = L2INPUT_FEAT_DROP; + /* Clear L2 output config */ + out_config = l2output_intf_config (sw_if_index); + memset (out_config, 0, sizeof (l2_output_config_t)); + /* Make sure any L2-output packet to this interface now in L3 mode is * dropped. This may happen if L2 FIB MAC entry is stale */ l2om->next_nodes.output_node_index_vec[sw_if_index] = -- cgit 1.2.3-korg From 25b36674f7e9072084f8f149067450f5eb6a5841 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Thu, 2 Mar 2017 10:43:19 +0200 Subject: bridge domain: fix members reordered when removing since adding support for multicast vxlan flooding (flood class tunnel master) correct flood functionality depends on the order of the memebers vector solved by using vec_delete instead of vec_del1 which swaps members before deleting the last element Change-Id: I234f218d49172b4142c567db9699a5cb274e4a66 Signed-off-by: Eyal Bari --- src/vnet/l2/l2_bd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 22f83d0b..f741b643 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -185,7 +185,7 @@ bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index) else if (sw_if->flood_class == VNET_FLOOD_CLASS_TUNNEL_NORMAL) bd_config->tun_normal_count--; } - vec_del1 (bd_config->members, ix); + vec_delete (bd_config->members, 1, ix); update_flood_count (bd_config); return BD_REMOVE_ERROR_OK; -- cgit 1.2.3-korg From a1a093d4e46e38503332a97ad216f80053a15f2b Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Thu, 2 Mar 2017 13:13:23 -0500 Subject: Clean up binary api message handler registration issues Removed a fair number of "BUG" message handlers, due to conflicts with actual message handlers in api_format.c. Vpp itself had no business receiving certain messages, up to the point where we started building in relevant code from vpp_api_test. Eliminated all but one duplicate registration complaint. That one needs attention from the vxlan team since the duplicated handlers have diverged. Change-Id: Iafce5429d2f906270643b4ea5f0130e20beb4d1d Signed-off-by: Dave Barach --- src/vat/api_format.c | 43 ++++++- src/vlib/unix/input.c | 31 ++++- src/vlibapi/api.h | 15 +++ src/vlibapi/api_shared.c | 4 + src/vnet/classify/classify_api.c | 8 -- src/vnet/devices/virtio/vhost_user_api.c | 10 +- src/vnet/dhcp/dhcp_api.c | 8 -- src/vnet/interface_api.c | 7 - src/vnet/ip/ip_api.c | 83 ------------ src/vnet/l2/l2_api.c | 22 ---- src/vnet/mpls/mpls_api.c | 28 +--- src/vpp/api/api.c | 211 ------------------------------- src/vpp/api/api_main.c | 1 - src/vpp/stats/stats.c | 7 - 14 files changed, 81 insertions(+), 397 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 1321bade..52436917 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -944,6 +944,7 @@ static void vl_api_sw_interface_details_t_handler_json } } +#if VPP_API_TEST_BUILTIN == 0 static void vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp) { @@ -954,6 +955,7 @@ static void vl_api_sw_interface_set_flags_t_handler mp->admin_up_down ? "admin-up" : "admin-down", mp->link_up_down ? "link-up" : "link-down"); } +#endif static void vl_api_sw_interface_set_flags_t_handler_json (vl_api_sw_interface_set_flags_t * mp) @@ -4009,7 +4011,6 @@ foreach_standard_reply_retval_handler; #define foreach_vpe_api_reply_msg \ _(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ _(SW_INTERFACE_DETAILS, sw_interface_details) \ -_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ _(CONTROL_PING_REPLY, control_ping_reply) \ _(CLI_REPLY, cli_reply) \ @@ -4126,11 +4127,6 @@ _(IKEV2_INITIATE_REKEY_CHILD_SA_REPLY, ikev2_initiate_rekey_child_sa_reply) \ _(DELETE_LOOPBACK_REPLY, delete_loopback_reply) \ _(BD_IP_MAC_ADD_DEL_REPLY, bd_ip_mac_add_del_reply) \ _(DHCP_COMPL_EVENT, dhcp_compl_event) \ -_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ -_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ -_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ -_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \ -_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \ _(MAP_ADD_DOMAIN_REPLY, map_add_domain_reply) \ _(MAP_DEL_DOMAIN_REPLY, map_del_domain_reply) \ _(MAP_ADD_DEL_RULE_REPLY, map_add_del_rule_reply) \ @@ -4232,6 +4228,14 @@ _(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) \ _(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ _(SW_INTERFACE_GET_TABLE_REPLY, sw_interface_get_table_reply) +#define foreach_standalone_reply_msg \ +_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ +_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ +_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ +_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ +_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \ +_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) + typedef struct { u8 *name; @@ -15425,7 +15429,15 @@ api_af_packet_create (vat_main_t * vam) vec_free (host_if_name); S (mp); - W2 (ret, fprintf (vam->ofp, " new sw_if_index = %d ", vam->sw_if_index)); + + /* *INDENT-OFF* */ + W2 (ret, + ({ + if (ret == 0) + fprintf (vam->ofp ? vam->ofp : stderr, + " new sw_if_index = %d\n", vam->sw_if_index); + })); + /* *INDENT-ON* */ return ret; } @@ -18417,6 +18429,9 @@ _(unset, "usage: unset ") } \ } foreach_vpe_api_reply_msg; +#if VPP_API_TEST_BUILTIN == 0 +foreach_standalone_reply_msg; +#endif #undef _ void @@ -18430,6 +18445,9 @@ vat_api_hookup (vat_main_t * vam) vl_api_##n##_t_print, \ sizeof(vl_api_##n##_t), 1); foreach_vpe_api_reply_msg; +#if VPP_API_TEST_BUILTIN == 0 + foreach_standalone_reply_msg; +#endif #undef _ #if (VPP_API_TEST_BUILTIN==0) @@ -18463,6 +18481,17 @@ vat_api_hookup (vat_main_t * vam) #undef _ } +#if VPP_API_TEST_BUILTIN +static clib_error_t * +vat_api_hookup_shim (vlib_main_t * vm) +{ + vat_api_hookup (&vat_main); + return 0; +} + +VLIB_API_INIT_FUNCTION (vat_api_hookup_shim); +#endif + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vlib/unix/input.c b/src/vlib/unix/input.c index 07096ed2..7b4183a4 100644 --- a/src/vlib/unix/input.c +++ b/src/vlib/unix/input.c @@ -66,6 +66,7 @@ linux_epoll_file_update (unix_file_t * f, unix_file_update_type_t update_type) unix_main_t *um = &unix_main; linux_epoll_main_t *em = &linux_epoll_main; struct epoll_event e; + int op; memset (&e, 0, sizeof (e)); @@ -76,13 +77,29 @@ linux_epoll_file_update (unix_file_t * f, unix_file_update_type_t update_type) e.events |= EPOLLET; e.data.u32 = f - um->file_pool; - if (epoll_ctl (em->epoll_fd, - (update_type == UNIX_FILE_UPDATE_ADD - ? EPOLL_CTL_ADD - : (update_type == UNIX_FILE_UPDATE_MODIFY - ? EPOLL_CTL_MOD - : EPOLL_CTL_DEL)), f->file_descriptor, &e) < 0) - clib_warning ("epoll_ctl"); + op = -1; + + switch (update_type) + { + case UNIX_FILE_UPDATE_ADD: + op = EPOLL_CTL_ADD; + break; + + case UNIX_FILE_UPDATE_MODIFY: + op = EPOLL_CTL_MOD; + break; + + case UNIX_FILE_UPDATE_DELETE: + op = EPOLL_CTL_DEL; + break; + + default: + clib_warning ("unknown update_type %d", update_type); + return; + } + + if (epoll_ctl (em->epoll_fd, op, f->file_descriptor, &e) < 0) + clib_unix_warning ("epoll_ctl"); } static uword diff --git a/src/vlibapi/api.h b/src/vlibapi/api.h index fcb101d7..b40ece15 100644 --- a/src/vlibapi/api.h +++ b/src/vlibapi/api.h @@ -271,6 +271,21 @@ vlib_node_t **vlib_node_unserialize (u8 * vector); #define VLIB_API_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,api_init) +/* Call given init function: used for init function dependencies. */ +#define vlib_call_api_init_function(vm, x) \ + ({ \ + extern vlib_init_function_t * _VLIB_INIT_FUNCTION_SYMBOL (x,api_init); \ + vlib_init_function_t * _f = _VLIB_INIT_FUNCTION_SYMBOL (x,api_init); \ + clib_error_t * _error = 0; \ + if (! hash_get (vm->init_functions_called, _f)) \ + { \ + hash_set1 (vm->init_functions_called, _f); \ + _error = _f (vm); \ + } \ + _error; \ + }) + + #endif /* included_api_h */ /* diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c index 1a2740e2..79921afe 100644 --- a/src/vlibapi/api_shared.c +++ b/src/vlibapi/api_shared.c @@ -667,6 +667,10 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c) foreach_msg_api_vector; #undef _ + if (am->msg_names[c->id]) + clib_warning ("BUG: multiple registrations of 'vl_api_%s_t_handler'", + c->name); + am->msg_names[c->id] = c->name; am->msg_handlers[c->id] = c->handler; am->msg_cleanup_handlers[c->id] = c->cleanup; diff --git a/src/vnet/classify/classify_api.c b/src/vnet/classify/classify_api.c index 77a8b434..24c7a2b9 100644 --- a/src/vnet/classify/classify_api.c +++ b/src/vnet/classify/classify_api.c @@ -53,7 +53,6 @@ _(CLASSIFY_TABLE_IDS,classify_table_ids) \ _(CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface) \ _(CLASSIFY_TABLE_INFO,classify_table_info) \ _(CLASSIFY_SESSION_DUMP,classify_session_dump) \ -_(CLASSIFY_SESSION_DETAILS,classify_session_details) \ _(POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface) \ _(POLICER_CLASSIFY_DUMP, policer_classify_dump) \ _(FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface) \ @@ -356,13 +355,6 @@ vl_api_classify_table_info_t_handler (vl_api_classify_table_info_t * mp) vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void -vl_api_classify_session_details_t_handler (vl_api_classify_session_details_t * - mp) -{ - clib_warning ("BUG"); -} - static void send_classify_session_details (unix_shared_memory_queue_t * q, u32 table_id, diff --git a/src/vnet/devices/virtio/vhost_user_api.c b/src/vnet/devices/virtio/vhost_user_api.c index dd517c26..8dbd032b 100644 --- a/src/vnet/devices/virtio/vhost_user_api.c +++ b/src/vnet/devices/virtio/vhost_user_api.c @@ -46,8 +46,7 @@ _(CREATE_VHOST_USER_IF, create_vhost_user_if) \ _(MODIFY_VHOST_USER_IF, modify_vhost_user_if) \ _(DELETE_VHOST_USER_IF, delete_vhost_user_if) \ -_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) \ -_(SW_INTERFACE_VHOST_USER_DETAILS, sw_interface_vhost_user_details) +_(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) /* * WARNING: replicated pending api refactor completion @@ -148,13 +147,6 @@ vl_api_delete_vhost_user_if_t_handler (vl_api_delete_vhost_user_if_t * mp) } } -static void - vl_api_sw_interface_vhost_user_details_t_handler - (vl_api_sw_interface_vhost_user_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_sw_interface_vhost_user_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c index bdf02cae..ce34f6a4 100644 --- a/src/vnet/dhcp/dhcp_api.c +++ b/src/vnet/dhcp/dhcp_api.c @@ -46,7 +46,6 @@ #define foreach_vpe_api_msg \ _(DHCP_PROXY_CONFIG,dhcp_proxy_config) \ _(DHCP_PROXY_DUMP,dhcp_proxy_dump) \ -_(DHCP_PROXY_DETAILS,dhcp_proxy_details) \ _(DHCP_PROXY_SET_VSS,dhcp_proxy_set_vss) \ _(DHCP_CLIENT_CONFIG, dhcp_client_config) @@ -158,13 +157,6 @@ dhcp_send_details (fib_protocol_t proto, vl_msg_api_send_shmem (q, (u8 *) & mp); } - -static void -vl_api_dhcp_proxy_details_t_handler (vl_api_dhcp_proxy_details_t * mp) -{ - clib_warning ("BUG"); -} - void dhcp_compl_event_callback (u32 client_index, u32 pid, u8 * hostname, u8 is_ipv6, u8 * host_address, u8 * router_address, diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 63f7cad4..60cd6d40 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -50,7 +50,6 @@ _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(SW_INTERFACE_SET_MTU, sw_interface_set_mtu) \ _(WANT_INTERFACE_EVENTS, want_interface_events) \ _(SW_INTERFACE_DUMP, sw_interface_dump) \ -_(SW_INTERFACE_DETAILS, sw_interface_details) \ _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \ _(SW_INTERFACE_SET_TABLE, sw_interface_set_table) \ _(SW_INTERFACE_GET_TABLE, sw_interface_get_table) \ @@ -684,12 +683,6 @@ out: REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY); } -static void -vl_api_sw_interface_details_t_handler (vl_api_sw_interface_details_t * mp) -{ - clib_warning ("BUG"); -} - /* * vpe_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c index 49d941c2..ab164a5f 100644 --- a/src/vnet/ip/ip_api.c +++ b/src/vnet/ip/ip_api.c @@ -59,17 +59,12 @@ #define foreach_ip_api_msg \ _(IP_FIB_DUMP, ip_fib_dump) \ -_(IP_FIB_DETAILS, ip_fib_details) \ _(IP6_FIB_DUMP, ip6_fib_dump) \ -_(IP6_FIB_DETAILS, ip6_fib_details) \ _(IP_MFIB_DUMP, ip_mfib_dump) \ -_(IP_MFIB_DETAILS, ip_mfib_details) \ _(IP6_MFIB_DUMP, ip6_mfib_dump) \ -_(IP6_MFIB_DETAILS, ip6_mfib_details) \ _(IP_NEIGHBOR_DUMP, ip_neighbor_dump) \ _(IP_MROUTE_ADD_DEL, ip_mroute_add_del) \ _(MFIB_SIGNAL_DUMP, mfib_signal_dump) \ -_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ _(IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del) \ @@ -105,12 +100,6 @@ send_ip_neighbor_details (u8 is_ipv6, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void -vl_api_ip_neighbor_details_t_handler (vl_api_ip_neighbor_details_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_ip_neighbor_dump_t_handler (vl_api_ip_neighbor_dump_t * mp) { @@ -185,24 +174,6 @@ copy_fib_next_hop (fib_route_path_encode_t * api_rpath, void *fp_arg) sizeof (api_rpath->rpath.frp_addr.ip6)); } -static void -vl_api_ip_fib_details_t_handler (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_fib_details_t_endian (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_fib_details_t_print (vl_api_ip_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -316,24 +287,6 @@ vl_api_ip_fib_dump_t_handler (vl_api_ip_fib_dump_t * mp) vec_free (lfeis); } -static void -vl_api_ip6_fib_details_t_handler (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_fib_details_t_endian (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_fib_details_t_print (vl_api_ip6_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip6_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -469,24 +422,6 @@ vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp) /* *INDENT-ON* */ } -static void -vl_api_ip_mfib_details_t_handler (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_mfib_details_t_endian (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip_mfib_details_t_print (vl_api_ip_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip_mfib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, @@ -591,24 +526,6 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp) vec_free (api_rpaths); } -static void -vl_api_ip6_mfib_details_t_handler (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_mfib_details_t_endian (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_ip6_mfib_details_t_print (vl_api_ip6_mfib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_ip6_mfib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a3cc49bf..a985852c 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -48,13 +48,10 @@ _(L2_XCONNECT_DUMP, l2_xconnect_dump) \ _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ _(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ -_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ -_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ -_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ _(BRIDGE_FLAGS, bridge_flags) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ _(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) @@ -140,12 +137,6 @@ send_l2fib_table_entry (vpe_api_main_t * am, vl_msg_api_send_shmem (q, (u8 *) & mp); } -static void -vl_api_l2_fib_table_entry_t_handler (vl_api_l2_fib_table_entry_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_l2_fib_table_dump_t_handler (vl_api_l2_fib_table_dump_t * mp) { @@ -329,19 +320,6 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); } -static void -vl_api_bridge_domain_details_t_handler (vl_api_bridge_domain_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void - vl_api_bridge_domain_sw_if_details_t_handler - (vl_api_bridge_domain_sw_if_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_bridge_domain_details (unix_shared_memory_queue_t * q, l2_bridge_domain_t * bd_config, diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c index ebbeba69..a36a5046 100644 --- a/src/vnet/mpls/mpls_api.c +++ b/src/vnet/mpls/mpls_api.c @@ -50,9 +50,7 @@ _(MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind) \ _(MPLS_ROUTE_ADD_DEL, mpls_route_add_del) \ _(MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del) \ _(MPLS_TUNNEL_DUMP, mpls_tunnel_dump) \ -_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ -_(MPLS_FIB_DUMP, mpls_fib_dump) \ -_(MPLS_FIB_DETAILS, mpls_fib_details) +_(MPLS_FIB_DUMP, mpls_fib_dump) extern void stats_dslock_with_hint (int hint, int tag); extern void stats_dsunlock (void); @@ -280,12 +278,6 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp) /* *INDENT-ON* */ } -static void -vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_tunnel_details_t * mp) -{ - clib_warning ("BUG"); -} - typedef struct mpls_tunnel_send_walk_ctx_t_ { unix_shared_memory_queue_t *q; @@ -340,24 +332,6 @@ vl_api_mpls_tunnel_dump_t_handler (vl_api_mpls_tunnel_dump_t * mp) mpls_tunnel_walk (send_mpls_tunnel_entry, &ctx); } -static void -vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_endian (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - -static void -vl_api_mpls_fib_details_t_print (vl_api_mpls_fib_details_t * mp) -{ - clib_warning ("BUG"); -} - static void send_mpls_fib_details (vpe_api_main_t * am, unix_shared_memory_queue_t * q, diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 60fd0199..a8f471e8 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -128,12 +128,8 @@ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(GET_NODE_INDEX, get_node_index) \ _(ADD_NODE_NEXT, add_node_next) \ -_(VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ -_(VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ _(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \ _(SHOW_VERSION, show_version) \ -_(VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel) \ -_(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ _(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ @@ -1436,62 +1432,6 @@ out: /* *INDENT-ON* */ } -static void vl_api_vxlan_add_del_tunnel_t_handler - (vl_api_vxlan_add_del_tunnel_t * mp) -{ - vl_api_vxlan_add_del_tunnel_reply_t *rmp; - int rv = 0; - vnet_vxlan_add_del_tunnel_args_t _a, *a = &_a; - u32 encap_fib_index; - uword *p; - ip4_main_t *im = &ip4_main; - vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ~0; - - p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } - encap_fib_index = p[0]; - memset (a, 0, sizeof (*a)); - - a->is_add = mp->is_add; - a->is_ip6 = mp->is_ipv6; - - /* ip addresses sent in network byte order */ - ip46_from_addr_buf (mp->is_ipv6, mp->dst_address, &a->dst); - ip46_from_addr_buf (mp->is_ipv6, mp->src_address, &a->src); - - /* Check src & dst are different */ - if (ip46_address_cmp (&a->dst, &a->src) == 0) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - a->mcast_sw_if_index = ntohl (mp->mcast_sw_if_index); - if (ip46_address_is_multicast (&a->dst) && - pool_is_free_index (vnm->interface_main.sw_interfaces, - a->mcast_sw_if_index)) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto out; - } - a->encap_fib_index = encap_fib_index; - a->decap_next_index = ntohl (mp->decap_next_index); - a->vni = ntohl (mp->vni); - rv = vnet_vxlan_add_del_tunnel (a, &sw_if_index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_VXLAN_ADD_DEL_TUNNEL_REPLY, - ({ - rmp->sw_if_index = ntohl (sw_if_index); - })); - /* *INDENT-ON* */ -} - static void send_vxlan_tunnel_details (vxlan_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context) { @@ -1525,43 +1465,6 @@ static void send_vxlan_tunnel_details vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void vl_api_vxlan_tunnel_dump_t_handler - (vl_api_vxlan_tunnel_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - vxlan_main_t *vxm = &vxlan_main; - vxlan_tunnel_t *t; - u32 sw_if_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - sw_if_index = ntohl (mp->sw_if_index); - - if (~0 == sw_if_index) - { - /* *INDENT-OFF* */ - pool_foreach (t, vxm->tunnels, - ({ - send_vxlan_tunnel_details(t, q, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - if ((sw_if_index >= vec_len (vxm->tunnel_index_by_sw_if_index)) || - (~0 == vxm->tunnel_index_by_sw_if_index[sw_if_index])) - { - return; - } - t = &vxm->tunnels[vxm->tunnel_index_by_sw_if_index[sw_if_index]]; - send_vxlan_tunnel_details (t, q, mp->context); - } -} - static void vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp) { @@ -1585,83 +1488,6 @@ vl_api_l2_patch_add_del_t_handler (vl_api_l2_patch_add_del_t * mp) REPLY_MACRO (VL_API_L2_PATCH_ADD_DEL_REPLY); } -static void - vl_api_vxlan_gpe_add_del_tunnel_t_handler - (vl_api_vxlan_gpe_add_del_tunnel_t * mp) -{ - vl_api_vxlan_gpe_add_del_tunnel_reply_t *rmp; - int rv = 0; - vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a; - u32 encap_fib_index, decap_fib_index; - u8 protocol; - uword *p; - ip4_main_t *im = &ip4_main; - u32 sw_if_index = ~0; - - - p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } - encap_fib_index = p[0]; - - protocol = mp->protocol; - - /* Interpret decap_vrf_id as an opaque if sending to other-than-ip4-input */ - if (protocol == VXLAN_GPE_INPUT_NEXT_IP4_INPUT) - { - p = hash_get (im->fib_index_by_table_id, ntohl (mp->decap_vrf_id)); - if (!p) - { - rv = VNET_API_ERROR_NO_SUCH_INNER_FIB; - goto out; - } - decap_fib_index = p[0]; - } - else - { - decap_fib_index = ntohl (mp->decap_vrf_id); - } - - /* Check src & dst are different */ - if ((mp->is_ipv6 && memcmp (mp->local, mp->remote, 16) == 0) || - (!mp->is_ipv6 && memcmp (mp->local, mp->remote, 4) == 0)) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - memset (a, 0, sizeof (*a)); - - a->is_add = mp->is_add; - a->is_ip6 = mp->is_ipv6; - /* ip addresses sent in network byte order */ - if (a->is_ip6) - { - clib_memcpy (&(a->local.ip6), mp->local, 16); - clib_memcpy (&(a->remote.ip6), mp->remote, 16); - } - else - { - clib_memcpy (&(a->local.ip4), mp->local, 4); - clib_memcpy (&(a->remote.ip4), mp->remote, 4); - } - a->encap_fib_index = encap_fib_index; - a->decap_fib_index = decap_fib_index; - a->protocol = protocol; - a->vni = ntohl (mp->vni); - rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index); - -out: - /* *INDENT-OFF* */ - REPLY_MACRO2(VL_API_VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, - ({ - rmp->sw_if_index = ntohl (sw_if_index); - })); - /* *INDENT-ON* */ -} - static void send_vxlan_gpe_tunnel_details (vxlan_gpe_tunnel_t * t, unix_shared_memory_queue_t * q, u32 context) { @@ -1696,43 +1522,6 @@ static void send_vxlan_gpe_tunnel_details vl_msg_api_send_shmem (q, (u8 *) & rmp); } -static void vl_api_vxlan_gpe_tunnel_dump_t_handler - (vl_api_vxlan_gpe_tunnel_dump_t * mp) -{ - unix_shared_memory_queue_t *q; - vxlan_gpe_main_t *vgm = &vxlan_gpe_main; - vxlan_gpe_tunnel_t *t; - u32 sw_if_index; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (q == 0) - { - return; - } - - sw_if_index = ntohl (mp->sw_if_index); - - if (~0 == sw_if_index) - { - /* *INDENT-OFF* */ - pool_foreach (t, vgm->tunnels, - ({ - send_vxlan_gpe_tunnel_details(t, q, mp->context); - })); - /* *INDENT-ON* */ - } - else - { - if ((sw_if_index >= vec_len (vgm->tunnel_index_by_sw_if_index)) || - (~0 == vgm->tunnel_index_by_sw_if_index[sw_if_index])) - { - return; - } - t = &vgm->tunnels[vgm->tunnel_index_by_sw_if_index[sw_if_index]]; - send_vxlan_gpe_tunnel_details (t, q, mp->context); - } -} - static void vl_api_interface_name_renumber_t_handler (vl_api_interface_name_renumber_t * mp) diff --git a/src/vpp/api/api_main.c b/src/vpp/api/api_main.c index 97b501e0..6ae510b1 100644 --- a/src/vpp/api/api_main.c +++ b/src/vpp/api/api_main.c @@ -48,7 +48,6 @@ api_main_init (vlib_main_t * vm) vam->vlib_main = vm; vam->my_client_index = (u32) ~ 0; init_error_string_table (vam); - vat_api_hookup (vam); rv = vat_plugin_init (vam); if (rv) clib_warning ("vat_plugin_init returned %d", rv); diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c index 5e9b0d69..c46d441a 100644 --- a/src/vpp/stats/stats.c +++ b/src/vpp/stats/stats.c @@ -46,7 +46,6 @@ stats_main_t stats_main; #define foreach_stats_msg \ _(WANT_STATS, want_stats) \ -_(WANT_STATS_REPLY, want_stats_reply) \ _(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ _(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ _(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ @@ -1226,12 +1225,6 @@ vl_api_vnet_ip6_nbr_counters_t_handler (vl_api_vnet_ip6_nbr_counters_t * mp) } } -static void -vl_api_want_stats_reply_t_handler (vl_api_want_stats_reply_t * mp) -{ - clib_warning ("BUG"); -} - static void vl_api_want_stats_t_handler (vl_api_want_stats_t * mp) { -- cgit 1.2.3-korg From cc40565b6eb3136d42fd67b57e4f0e01a5970a72 Mon Sep 17 00:00:00 2001 From: Andrew Yourtchenko Date: Fri, 3 Mar 2017 13:11:30 +0000 Subject: VPP-651: Ensure sw_if_index to node mapping for L2 output path is only done via l2output_main.next_nodes Before this commit, several output features that happen to be the last in the list of features to be executed, send the packets directly to -output. To do this, they use l2_output_dispatch, which builds a list of sw_if_index to next index mappings. When interfaces are deleted and the new interfaces are created, these mappings become stale, and cause the packets being sent to wrong interface output nodes. This patch (thanks John Lo for the brilliant idea!) adds a feature node "output", whose sole purpose is dispatching the packets to the correct interface output nodes. To do that, it uses the l2output_main.next_nodes, which is already taken care of for the case of the sw_if_index reuse, so this makes the dependent features all work correctly. Since this changes the packet path, for the features that were always the last ones it has triggered a side problem of the output feat_next_node_index not being properly initalized. These two users are l2-output-classify node and the output nodes belonging to the acl-plugin. For the first one the less invasive fix is just to initialize that field. For the acl-plugin nodes, rewrite the affected part of the code to use feat_bitmap_get_next_node_index since this is essentially what the conditional in l2_output_dispatch does, and fix the compiler warnings generated. This fix was first made in stable/1701 under commit e7dcee4027854b0ad076101471afdfff67eb9011. Change-Id: I32e876ab1e1d498cf0854c19c6318dcf59a93805 Signed-off-by: Andrew Yourtchenko --- src/plugins/acl/acl.c | 6 +++- src/plugins/acl/acl.h | 5 ++- src/plugins/acl/l2sess.c | 16 ++++++--- src/plugins/acl/l2sess.h | 3 +- src/plugins/acl/l2sess_node.c | 73 ++++++---------------------------------- src/plugins/acl/node_in.c | 2 +- src/plugins/acl/node_out.c | 16 +++------ src/vnet/l2/l2_input.c | 3 +- src/vnet/l2/l2_output.h | 15 ++++++++- src/vnet/l2/l2_output_classify.c | 2 +- 10 files changed, 53 insertions(+), 88 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/plugins/acl/acl.c b/src/plugins/acl/acl.c index 85c9113b..3fe084b4 100644 --- a/src/plugins/acl/acl.c +++ b/src/plugins/acl/acl.c @@ -1883,7 +1883,11 @@ acl_setup_nodes (void) feat_bitmap_init_next_nodes (vm, acl_in_node.index, L2INPUT_N_FEAT, l2input_get_feat_names (), - am->acl_in_node_input_next_node_index); + am->acl_in_node_feat_next_node_index); + + feat_bitmap_init_next_nodes (vm, acl_out_node.index, L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + am->acl_out_node_feat_next_node_index); memset (&am->acl_in_ip4_match_next[0], 0, sizeof (am->acl_in_ip4_match_next)); diff --git a/src/plugins/acl/acl.h b/src/plugins/acl/acl.h index 62046788..0252ff38 100644 --- a/src/plugins/acl/acl.h +++ b/src/plugins/acl/acl.h @@ -122,9 +122,8 @@ typedef struct { u32 l2_output_classify_next_acl; /* next node indices for feature bitmap */ - u32 acl_in_node_input_next_node_index[32]; - /* the respective thing for the output feature */ - l2_output_next_nodes_st acl_out_output_next_nodes; + u32 acl_in_node_feat_next_node_index[32]; + u32 acl_out_node_feat_next_node_index[32]; /* ACL match actions (must be coherent across in/out ACLs to next indices (can differ) */ diff --git a/src/plugins/acl/l2sess.c b/src/plugins/acl/l2sess.c index b0385be1..7a1567fb 100644 --- a/src/plugins/acl/l2sess.c +++ b/src/plugins/acl/l2sess.c @@ -31,10 +31,18 @@ #include void -l2sess_init_next_features_input (vlib_main_t * vm, l2sess_main_t * sm) +l2sess_init_next_features (vlib_main_t * vm, l2sess_main_t * sm) { -#define _(node_name, node_var, is_out, is_ip6, is_track) \ - if (!is_out) feat_bitmap_init_next_nodes(vm, node_var.index, L2INPUT_N_FEAT, l2input_get_feat_names (), sm->node_var ## _input_next_node_index); +#define _(node_name, node_var, is_out, is_ip6, is_track) \ + if (is_out) \ + feat_bitmap_init_next_nodes(vm, node_var.index, L2OUTPUT_N_FEAT, \ + l2output_get_feat_names (), \ + sm->node_var ## _feat_next_node_index); \ + else \ + feat_bitmap_init_next_nodes(vm, node_var.index, L2INPUT_N_FEAT, \ + l2input_get_feat_names (), \ + sm->node_var ## _feat_next_node_index); + foreach_l2sess_node #undef _ } @@ -62,7 +70,7 @@ l2sess_setup_nodes (void) vlib_main_t *vm = vlib_get_main (); l2sess_main_t *sm = &l2sess_main; - l2sess_init_next_features_input (vm, sm); + l2sess_init_next_features (vm, sm); l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-input-classify", 0); l2sess_add_our_next_nodes (vm, sm, (u8 *) "l2-output-classify", 1); diff --git a/src/plugins/acl/l2sess.h b/src/plugins/acl/l2sess.h index 888b5301..961c08c8 100644 --- a/src/plugins/acl/l2sess.h +++ b/src/plugins/acl/l2sess.h @@ -95,8 +95,7 @@ typedef struct { * on whether the node is an input or output one. */ #define _(node_name, node_var, is_out, is_ip6, is_track) \ - u32 node_var ## _input_next_node_index[32]; \ - l2_output_next_nodes_st node_var ## _next_nodes; + u32 node_var ## _feat_next_node_index[32]; foreach_l2sess_node #undef _ l2_output_next_nodes_st output_next_nodes; diff --git a/src/plugins/acl/l2sess_node.c b/src/plugins/acl/l2sess_node.c index 520e5929..689d216d 100644 --- a/src/plugins/acl/l2sess_node.c +++ b/src/plugins/acl/l2sess_node.c @@ -526,13 +526,13 @@ check_idle_sessions (l2sess_main_t * sm, u32 sw_if_index, u64 now) static uword l2sess_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) + vlib_node_runtime_t * node, vlib_frame_t * frame, + int node_is_out, int node_is_ip6, int node_is_track, + u32 *feat_next_node_index) { u32 n_left_from, *from, *to_next; l2sess_next_t next_index; u32 pkts_swapped = 0; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; u32 feature_bitmap0; u32 trace_flags0; @@ -570,45 +570,19 @@ l2sess_node_fn (vlib_main_t * vm, //en0 = vlib_buffer_get_current (b0); /* - * The non-boilerplate is in the block below. - * Note first a magic macro block that sets up the behavior qualifiers: * node_is_out : 1 = is output, 0 = is input * node_is_ip6 : 1 = is ip6, 0 = is ip4 * node_is_track : 1 = is a state tracking node, 0 - is a session addition node * - * Subsequently the code adjusts its behavior depending on these variables. - * It's most probably not great performance wise but much easier to work with. - * + * The below code adjust the behavior according to these parameters. */ { - int node_is_out = -1; - CLIB_UNUSED (int node_is_ip6) = -1; - CLIB_UNUSED (int node_is_track) = -1; - u32 node_index = 0; u32 session_tables[2] = { ~0, ~0 }; u32 session_nexts[2] = { ~0, ~0 }; - l2_output_next_nodes_st *next_nodes = 0; - u32 *input_feat_next_node_index; u8 l4_proto; u64 now = clib_cpu_time_now (); -/* - * Set the variables according to which of the 8 nodes we are. - * Hopefully the compiler is smart enough to eliminate the extraneous. - */ -#define _(node_name, node_var, is_out, is_ip6, is_track) \ -if(node_var.index == node->node_index) \ - { \ - node_is_out = is_out; \ - node_is_ip6 = is_ip6; \ - node_is_track = is_track; \ - node_index = node_var.index; \ - next_nodes = &sm->node_var ## _next_nodes; \ - input_feat_next_node_index = sm->node_var ## _input_next_node_index; \ - } - foreach_l2sess_node -#undef _ - trace_flags0 = 0; + trace_flags0 = 0; if (node_is_out) { sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; @@ -715,38 +689,8 @@ if(node_var.index == node->node_index) \ check_idle_sessions (sm, sw_if_index0, now); } - if (node_is_out) - { - if (feature_bitmap0) - { - trace_flags0 |= 0x10; - } - if (sw_if_index0 == cached_sw_if_index) - { - trace_flags0 |= 0x20; - } - l2_output_dispatch (sm->vlib_main, - sm->vnet_main, - node, - node_index, - &cached_sw_if_index, - &cached_next_index, - next_nodes, - b0, sw_if_index0, feature_bitmap0, - &next0); - trace_flags0 |= 2; - - } - else - { - next0 = - feat_bitmap_get_next_node_index (input_feat_next_node_index, + next0 = feat_bitmap_get_next_node_index (feat_next_node_index, feature_bitmap0); - trace_flags0 |= 4; - - } - - if (next0 >= node->n_next_nodes) { @@ -795,7 +739,10 @@ node_var ## node_fn (vlib_main_t * vm, \ vlib_node_runtime_t * node, \ vlib_frame_t * frame) \ { \ - return l2sess_node_fn(vm, node, frame); \ + l2sess_main_t *sm = &l2sess_main; \ + return l2sess_node_fn(vm, node, frame, \ + is_out, is_ip6, is_track, \ + sm->node_var ## _feat_next_node_index); \ } \ VLIB_REGISTER_NODE (node_var) = { \ .function = node_var ## node_fn, \ diff --git a/src/plugins/acl/node_in.c b/src/plugins/acl/node_in.c index 2a5199a9..95802df5 100644 --- a/src/plugins/acl/node_in.c +++ b/src/plugins/acl/node_in.c @@ -73,7 +73,7 @@ acl_in_node_fn (vlib_main_t * vm, u32 feature_bitmap0; u32 trace_bitmap = 0; u32 *input_feat_next_node_index = - acl_main.acl_in_node_input_next_node_index; + acl_main.acl_in_node_feat_next_node_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; diff --git a/src/plugins/acl/node_out.c b/src/plugins/acl/node_out.c index 50af3679..cbec3b9a 100644 --- a/src/plugins/acl/node_out.c +++ b/src/plugins/acl/node_out.c @@ -68,13 +68,12 @@ acl_out_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { acl_main_t *am = &acl_main; - l2_output_next_nodes_st *next_nodes = &am->acl_out_output_next_nodes; + u32 *output_feat_next_node_index = + am->acl_out_node_feat_next_node_index; u32 n_left_from, *from, *to_next; acl_out_next_t next_index; u32 pkts_acl_checked = 0; u32 feature_bitmap0; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; u32 match_acl_index = ~0; u32 match_rule_index = ~0; u32 trace_bitmap = 0; @@ -119,14 +118,9 @@ acl_out_node_fn (vlib_main_t * vm, } if (next0 == ~0) { - l2_output_dispatch (vm, - am->vnet_main, - node, - acl_out_node.index, - &cached_sw_if_index, - &cached_next_index, - next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); + next0 = + feat_bitmap_get_next_node_index (output_feat_next_node_index, + feature_bitmap0); } diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index fbd75f22..3aa5331b 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -703,10 +703,11 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ shg = 0; /* not used in xconnect */ } - /* set up split-horizon group */ + /* set up split-horizon group and set output feature bit */ config->shg = shg; out_config = l2output_intf_config (sw_if_index); out_config->shg = shg; + out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT; /* * Test: remove this when non-IP features can be configured. diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index c683b1ad..9597205c 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -94,6 +94,7 @@ l2output_main_t l2output_main; /* Mappings from feature ID to graph node name */ #define foreach_l2output_feat \ + _(OUTPUT, "interface-output") \ _(SPAN, "feature-bitmap-drop") \ _(CFM, "feature-bitmap-drop") \ _(QOS, "feature-bitmap-drop") \ @@ -217,9 +218,21 @@ l2_output_dispatch (vlib_main_t * vlib_main, vlib_buffer_t * b0, u32 sw_if_index, u32 feature_bitmap, u32 * next0) { - if (feature_bitmap) + /* + * The output feature bitmap always have at least the output feature bit set + * for a normal L2 interface (or all 0's if the interface is changed from L2 + * to L3 mode). So if next_nodes specified is that from the l2-output node and + * the bitmap is all clear except output feature bit, we know there is no more + * feature and will fall through to output packet. If next_nodes is from a L2 + * output feature node (and not l2-output), we always want to get the node for + * the next L2 output feature, including the last feature being interface- + * output node to output packet. + */ + if ((next_nodes != &l2output_main.next_nodes) + || ((feature_bitmap & ~L2OUTPUT_FEAT_OUTPUT) != 0)) { /* There are some features to execute */ + ASSERT (feature_bitmap != 0); /* Save bitmap for the next feature graph nodes */ vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c index 27d5eb39..832be1a1 100644 --- a/src/vnet/l2/l2_output_classify.c +++ b/src/vnet/l2/l2_output_classify.c @@ -493,7 +493,7 @@ l2_output_classify_init (vlib_main_t * vm) l2_output_classify_node.index, L2OUTPUT_N_FEAT, l2output_get_feat_names (), - cm->feat_next_node_index); + cm->next_nodes.feat_next_node_index); rt->l2cm = cm; rt->vcm = cm->vnet_classify_main; -- cgit 1.2.3-korg From f7f2a9feaa2cad8313afba53b53c32f1928f664c Mon Sep 17 00:00:00 2001 From: Gabriel Ganne Date: Mon, 6 Mar 2017 15:19:40 +0100 Subject: fix gcc 5.4 warning: argument to 'sizeof' in 'memcpy' call is the same expression as the destination warning translates as an invalid write : sizeof(u8* b_dmac) == 8 != sizeof(eth_hdr->dst_address) == 6 ~/vpp/build-data/../src/vnet/l2/l2_vtr.c: In function 'l2pbb_get': ~/vpp/build-data/../src/vnet/l2/l2_vtr.c:734:63: error: argument to 'sizeof' in 'memcpy' call is the same expression as the destination; did you mean to provide an explicit length? [-Werror=sizeof-pointer-memaccess] ~/vpp/build-data/../src/vnet/l2/l2_vtr.c:736:63: error: argument to 'sizeof' in 'memcpy' call is the same expression as the destination; did you mean to provide an explicit length? [-Werror=sizeof-pointer-memaccess] update l2pbb_get to take an ethernet header instead of two u8* pointers for source and dest mac addresses. Change-Id: Ifcf1319a9e22614d57682f940e10f0420dc6fb8c Signed-off-by: Gabriel Ganne --- src/vnet/interface_api.c | 14 +++++++------- src/vnet/l2/l2_vtr.c | 16 +++++++--------- src/vnet/l2/l2_vtr.h | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index bfd2af31..2b6ff0c5 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -205,21 +205,21 @@ send_sw_interface_details (vpe_api_main_t * am, } /* pbb tag rewrite data */ + ethernet_header_t eth_hdr; u32 vtr_op = L2_VTR_DISABLED; u16 outer_tag = 0; - u8 b_dmac[6]; - u8 b_smac[6]; u16 b_vlanid = 0; u32 i_sid = 0; - memset (b_dmac, 0, sizeof (b_dmac)); - memset (b_smac, 0, sizeof (b_smac)); + memset (ð_hdr, 0, sizeof (eth_hdr)); if (!l2pbb_get (am->vlib_main, am->vnet_main, swif->sw_if_index, - &vtr_op, &outer_tag, b_dmac, b_smac, &b_vlanid, &i_sid)) + &vtr_op, &outer_tag, ð_hdr, &b_vlanid, &i_sid)) { mp->sub_dot1ah = 1; - clib_memcpy (mp->b_dmac, b_dmac, sizeof (b_dmac)); - clib_memcpy (mp->b_smac, b_smac, sizeof (b_smac)); + clib_memcpy (mp->b_dmac, eth_hdr.dst_address, + sizeof (eth_hdr.dst_address)); + clib_memcpy (mp->b_smac, eth_hdr.src_address, + sizeof (eth_hdr.src_address)); mp->b_vlanid = b_vlanid; mp->i_sid = i_sid; } diff --git a/src/vnet/l2/l2_vtr.c b/src/vnet/l2/l2_vtr.c index e03a4880..3c5365f9 100644 --- a/src/vnet/l2/l2_vtr.c +++ b/src/vnet/l2/l2_vtr.c @@ -687,7 +687,7 @@ VLIB_CLI_COMMAND (int_l2_vtr_cli, static) = { */ u32 l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, - u32 * vtr_op, u16 * outer_tag, u8 * b_dmac, u8 * b_smac, + u32 * vtr_op, u16 * outer_tag, ethernet_header_t * eth_hdr, u16 * b_vlanid, u32 * i_sid) { u32 error = 1; @@ -702,8 +702,6 @@ l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, *vtr_op = L2_VTR_DISABLED; *outer_tag = 0; - *b_dmac = 0; - *b_smac = 0; *b_vlanid = 0; *i_sid = 0; @@ -731,16 +729,16 @@ l2pbb_get (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index, else if (in_config->push_bytes) *vtr_op = L2_VTR_PUSH_2; - clib_memcpy (b_dmac, in_config->macs_tags.b_dst_address, - sizeof (b_dmac)); - clib_memcpy (b_smac, in_config->macs_tags.b_src_address, - sizeof (b_smac)); + clib_memcpy (ð_hdr->dst_address, in_config->macs_tags.b_dst_address, + sizeof (eth_hdr->dst_address)); + clib_memcpy (ð_hdr->src_address, in_config->macs_tags.b_src_address, + sizeof (eth_hdr->src_address)); *b_vlanid = clib_host_to_net_u16 (in_config->macs_tags.priority_dei_id) & 0xFFF; *i_sid = - clib_host_to_net_u32 (in_config-> - macs_tags.priority_dei_uca_res_sid) & 0xFFFFF; + clib_host_to_net_u32 (in_config->macs_tags. + priority_dei_uca_res_sid) & 0xFFFFF; error = 0; } done: diff --git a/src/vnet/l2/l2_vtr.h b/src/vnet/l2/l2_vtr.h index 99aedc97..0aea618e 100644 --- a/src/vnet/l2/l2_vtr.h +++ b/src/vnet/l2/l2_vtr.h @@ -267,7 +267,7 @@ u32 l2pbb_get (vlib_main_t * vlib_main, u32 sw_if_index, u32 * vtr_op, u16 * outer_tag, - u8 * b_dmac, u8 * b_smac, u16 * b_vlanid, u32 * i_sid); + ethernet_header_t * eth_hdr, u16 * b_vlanid, u32 * i_sid); #endif /* included_vnet_l2_vtr_h */ -- cgit 1.2.3-korg From e9f929b52ddb741ec1e4cb2d92c6be1e798933a0 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 16 Mar 2017 11:32:09 +0100 Subject: vlib: make runtime_data thread-local Change-Id: I4aa3e7e42fb81211de1aed07dc7befee87a1e18b Signed-off-by: Damjan Marion --- src/vlib/init.h | 1 + src/vlib/main.h | 1 + src/vlib/node.c | 4 +- src/vlib/node.h | 81 +++++++++++++++++++++------------------- src/vlib/threads.c | 61 ++++++++++++++++++++++++++++-- src/vnet/gre/node.c | 26 ++++++++++--- src/vnet/hdlc/node.c | 27 +++++++++----- src/vnet/l2/l2_input_classify.c | 15 ++++++++ src/vnet/l2/l2_output_classify.c | 16 ++++++++ src/vnet/l2tp/l2tp.c | 10 +++++ src/vnet/mpls/node.c | 13 +++++++ src/vnet/ppp/node.c | 27 +++++++++----- src/vnet/tcp/tcp_syn_filter4.c | 23 +++++++----- src/vnet/udp/udp_local.c | 74 ++++++++++++++++++++++-------------- 14 files changed, 273 insertions(+), 106 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vlib/init.h b/src/vlib/init.h index 4fa5b304..12db3f90 100644 --- a/src/vlib/init.h +++ b/src/vlib/init.h @@ -109,6 +109,7 @@ static void __vlib_add_##tag##_function_##x (void) \ } #define VLIB_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,init) +#define VLIB_WORKER_INIT_FUNCTION(x) VLIB_DECLARE_INIT_FUNCTION(x,worker_init) #define VLIB_MAIN_LOOP_ENTER_FUNCTION(x) \ VLIB_DECLARE_INIT_FUNCTION(x,main_loop_enter) diff --git a/src/vlib/main.h b/src/vlib/main.h index a6d50b39..98bc823d 100644 --- a/src/vlib/main.h +++ b/src/vlib/main.h @@ -162,6 +162,7 @@ typedef struct vlib_main_t /* List of init functions to call, setup by constructors */ _vlib_init_function_list_elt_t *init_function_registrations; + _vlib_init_function_list_elt_t *worker_init_function_registrations; _vlib_init_function_list_elt_t *main_loop_enter_function_registrations; _vlib_init_function_list_elt_t *main_loop_exit_function_registrations; _vlib_init_function_list_elt_t *api_init_function_registrations; diff --git a/src/vlib/node.c b/src/vlib/node.c index c419a13a..dc0a4de5 100644 --- a/src/vlib/node.c +++ b/src/vlib/node.c @@ -434,9 +434,7 @@ register_node (vlib_main_t * vm, vlib_node_registration_t * r) rt->errors[i] = vlib_error_set (n->index, i); STATIC_ASSERT_SIZEOF (vlib_node_runtime_t, 128); - ASSERT (vec_len (n->runtime_data) <= - sizeof (vlib_node_runtime_t) - - STRUCT_OFFSET_OF (vlib_node_runtime_t, runtime_data)); + ASSERT (vec_len (n->runtime_data) <= VLIB_NODE_RUNTIME_DATA_SIZE); if (vec_len (n->runtime_data) > 0) clib_memcpy (rt->runtime_data, n->runtime_data, diff --git a/src/vlib/node.h b/src/vlib/node.h index b624e9d6..2a532cc3 100644 --- a/src/vlib/node.h +++ b/src/vlib/node.h @@ -411,65 +411,68 @@ typedef struct typedef struct vlib_node_runtime_t { - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - /* Node function to call. */ - vlib_node_function_t *function; + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); /**< cacheline mark */ - /* Vector of errors for this node. */ - vlib_error_t *errors; + vlib_node_function_t *function; /**< Node function to call. */ - /* Number of clock cycles. */ - u32 clocks_since_last_overflow; + vlib_error_t *errors; /**< Vector of errors for this node. */ - /* Maximum clock cycle for an invocation. */ - u32 max_clock; + u32 clocks_since_last_overflow; /**< Number of clock cycles. */ - /* Number of vectors in the recorded max_clock. */ - u32 max_clock_n; + u32 max_clock; /**< Maximum clock cycle for an + invocation. */ - /* Number of calls. */ - u32 calls_since_last_overflow; + u32 max_clock_n; /**< Number of vectors in the recorded + max_clock. */ - /* Number of vector elements processed by this node. */ - u32 vectors_since_last_overflow; + u32 calls_since_last_overflow; /**< Number of calls. */ - /* Start of next frames for this node. */ - u32 next_frame_index; + u32 vectors_since_last_overflow; /**< Number of vector elements + processed by this node. */ - /* Node index. */ - u32 node_index; + u32 next_frame_index; /**< Start of next frames for this + node. */ - /* For input nodes: decremented on each main loop interation until it reaches zero - and function is called. Allows some input nodes to be called - more than others. */ - u32 input_main_loops_per_call; + u32 node_index; /**< Node index. */ - /* Saved main loop counter of last dispatch of this node. */ - u32 main_loop_count_last_dispatch; + u32 input_main_loops_per_call; /**< For input nodes: decremented + on each main loop interation until + it reaches zero and function is + called. Allows some input nodes to + be called more than others. */ + + u32 main_loop_count_last_dispatch; /**< Saved main loop counter of last + dispatch of this node. */ u32 main_loop_vector_stats[2]; - /* Copy of main node flags. */ - u16 flags; + u16 flags; /**< Copy of main node flags. */ - /* Input node state. */ - u16 state; + u16 state; /**< Input node state. */ u16 n_next_nodes; - /* Next frame index that vector arguments were last enqueued to - last time this node ran. Set to zero before first run - of this node. */ - u16 cached_next_index; - - /* CPU this node runs on */ - u16 cpu_index; - - /* Function dependent node-runtime. */ - u8 runtime_data[0]; + u16 cached_next_index; /**< Next frame index that vector + arguments were last enqueued to + last time this node ran. Set to + zero before first run of this + node. */ + + u16 cpu_index; /**< CPU this node runs on */ + + u8 runtime_data[0]; /**< Function dependent + node-runtime data. This data is + thread local, and it is not + cloned from main thread. It needs + to be initialized for each thread + before it is used unless + runtime_data template exists in + vlib_node_t. */ } vlib_node_runtime_t; +#define VLIB_NODE_RUNTIME_DATA_SIZE (sizeof (vlib_node_runtime_t) - STRUCT_OFFSET_OF (vlib_node_runtime_t, runtime_data)) + typedef struct { /* Number of allocated frames for this scalar/vector size. */ diff --git a/src/vlib/threads.c b/src/vlib/threads.c index 07dbff33..3756c3fa 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -633,6 +633,8 @@ start_workers (vlib_main_t * vm) vm_clone->cpu_index = worker_thread_index; vm_clone->heap_base = w->thread_mheap; vm_clone->mbuf_alloc_list = 0; + vm_clone->init_functions_called = + hash_create (0, /* value bytes */ 0); memset (&vm_clone->random_buffer, 0, sizeof (vm_clone->random_buffer)); @@ -674,11 +676,33 @@ start_workers (vlib_main_t * vm) } nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] = vec_dup (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]); + vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) + { + vlib_node_t *n = vlib_get_node (vm, rt->node_index); + rt->cpu_index = vm_clone->cpu_index; + /* copy initial runtime_data from node */ + if (n->runtime_data_bytes > 0) + clib_memcpy (rt->runtime_data, n->runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); + else if (CLIB_DEBUG > 0) + memset (rt->runtime_data, 0xfe, + VLIB_NODE_RUNTIME_DATA_SIZE); + } nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] = vec_dup (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT]); vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) + { + vlib_node_t *n = vlib_get_node (vm, rt->node_index); rt->cpu_index = vm_clone->cpu_index; + /* copy initial runtime_data from node */ + if (n->runtime_data_bytes > 0) + clib_memcpy (rt->runtime_data, n->runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); + else if (CLIB_DEBUG > 0) + memset (rt->runtime_data, 0xfe, + VLIB_NODE_RUNTIME_DATA_SIZE); + } nm_clone->processes = vec_dup (nm->processes); @@ -926,26 +950,51 @@ vlib_worker_thread_node_runtime_update (void) clib_mem_free (old_nodes_clone[j]); vec_free (old_nodes_clone); - vec_free (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]); + /* re-clone internal nodes */ + old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]; nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] = vec_dup (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]); - /* clone input node runtime */ - old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]; + vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]) + { + vlib_node_t *n = vlib_get_node (vm, rt->node_index); + rt->cpu_index = vm_clone->cpu_index; + /* copy runtime_data, will be overwritten later for existing rt */ + clib_memcpy (rt->runtime_data, n->runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); + } + + for (j = 0; j < vec_len (old_rt); j++) + { + rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index); + rt->state = old_rt[j].state; + clib_memcpy (rt->runtime_data, old_rt[j].runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); + } + vec_free (old_rt); + + /* re-clone input nodes */ + old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]; nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] = vec_dup (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT]); vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { + vlib_node_t *n = vlib_get_node (vm, rt->node_index); rt->cpu_index = vm_clone->cpu_index; + /* copy runtime_data, will be overwritten later for existing rt */ + clib_memcpy (rt->runtime_data, n->runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); } for (j = 0; j < vec_len (old_rt); j++) { rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index); rt->state = old_rt[j].state; + clib_memcpy (rt->runtime_data, old_rt[j].runtime_data, + VLIB_NODE_RUNTIME_DATA_SIZE); } vec_free (old_rt); @@ -1342,6 +1391,7 @@ vlib_worker_thread_fn (void *arg) vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg; vlib_thread_main_t *tm = vlib_get_thread_main (); vlib_main_t *vm = vlib_get_main (); + clib_error_t *e; ASSERT (vm->cpu_index == os_get_cpu_number ()); @@ -1349,6 +1399,11 @@ vlib_worker_thread_fn (void *arg) clib_time_init (&vm->clib_time); clib_mem_set_heap (w->thread_mheap); + e = vlib_call_init_exit_functions + (vm, vm->worker_init_function_registrations, 1 /* call_once */ ); + if (e) + clib_error_report (e); + /* Wait until the dpdk init sequence is complete */ while (tm->extern_thread_mgmt && tm->worker_thread_release == 0) vlib_worker_thread_barrier_check (); diff --git a/src/vnet/gre/node.c b/src/vnet/gre/node.c index 86f7a6ee..dd16db5e 100644 --- a/src/vnet/gre/node.c +++ b/src/vnet/gre/node.c @@ -448,7 +448,6 @@ gre_register_input_protocol (vlib_main_t * vm, { gre_main_t * em = &gre_main; gre_protocol_info_t * pi; - gre_input_runtime_t * rt; u16 * n; { @@ -464,10 +463,13 @@ gre_register_input_protocol (vlib_main_t * vm, node_index); /* Setup gre protocol -> next index sparse vector mapping. */ - rt = vlib_node_get_runtime_data (vm, gre_input_node.index); - n = sparse_vec_validate (rt->next_by_protocol, - clib_host_to_net_u16 (protocol)); - n[0] = pi->next_index; + foreach_vlib_main ({ + gre_input_runtime_t * rt; + rt = vlib_node_get_runtime_data (this_vlib_main, gre_input_node.index); + n = sparse_vec_validate (rt->next_by_protocol, + clib_host_to_net_u16 (protocol)); + n[0] = pi->next_index; + }); } static void @@ -529,3 +531,17 @@ static clib_error_t * gre_input_init (vlib_main_t * vm) } VLIB_INIT_FUNCTION (gre_input_init); + +static clib_error_t * gre_input_worker_init (vlib_main_t * vm) +{ + gre_input_runtime_t * rt; + + rt = vlib_node_get_runtime_data (vm, gre_input_node.index); + + rt->next_by_protocol = sparse_vec_new + (/* elt bytes */ sizeof (rt->next_by_protocol[0]), + /* bits in index */ BITS (((gre_header_t *) 0)->protocol)); + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (gre_input_worker_init); diff --git a/src/vnet/hdlc/node.c b/src/vnet/hdlc/node.c index 4fe0296a..57e04c85 100644 --- a/src/vnet/hdlc/node.c +++ b/src/vnet/hdlc/node.c @@ -285,18 +285,9 @@ VLIB_REGISTER_NODE (hdlc_input_node) = { .unformat_buffer = unformat_hdlc_header, }; -static clib_error_t * hdlc_input_init (vlib_main_t * vm) +static clib_error_t * hdlc_input_runtime_init (vlib_main_t * vm) { hdlc_input_runtime_t * rt; - - { - clib_error_t * error = vlib_call_init_function (vm, hdlc_init); - if (error) - clib_error_report (error); - } - - hdlc_setup_node (vm, hdlc_input_node.index); - rt = vlib_node_get_runtime_data (vm, hdlc_input_node.index); rt->next_by_protocol = sparse_vec_new @@ -313,7 +304,23 @@ static clib_error_t * hdlc_input_init (vlib_main_t * vm) return 0; } +static clib_error_t * hdlc_input_init (vlib_main_t * vm) +{ + + { + clib_error_t * error = vlib_call_init_function (vm, hdlc_init); + if (error) + clib_error_report (error); + } + + hdlc_setup_node (vm, hdlc_input_node.index); + hdlc_input_runtime_init (vm); + + return 0; +} + VLIB_INIT_FUNCTION (hdlc_input_init); +VLIB_WORKER_INIT_FUNCTION (hdlc_input_runtime_init); void hdlc_register_input_protocol (vlib_main_t * vm, diff --git a/src/vnet/l2/l2_input_classify.c b/src/vnet/l2/l2_input_classify.c index 497df192..485b9abd 100644 --- a/src/vnet/l2/l2_input_classify.c +++ b/src/vnet/l2/l2_input_classify.c @@ -505,6 +505,21 @@ l2_input_classify_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (l2_input_classify_init); +clib_error_t * +l2_input_classify_worker_init (vlib_main_t * vm) +{ + l2_input_classify_main_t *cm = &l2_input_classify_main; + l2_input_classify_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, l2_input_classify_node.index); + + rt->l2cm = cm; + rt->vcm = cm->vnet_classify_main; + + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (l2_input_classify_worker_init); /** Enable/disable l2 input classification on a specific interface. */ void diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c index 832be1a1..c1bdaddc 100644 --- a/src/vnet/l2/l2_output_classify.c +++ b/src/vnet/l2/l2_output_classify.c @@ -505,6 +505,22 @@ l2_output_classify_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (l2_output_classify_init); +clib_error_t * +l2_output_classify_worker_init (vlib_main_t * vm) +{ + l2_output_classify_main_t *cm = &l2_output_classify_main; + l2_output_classify_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, l2_output_classify_node.index); + + rt->l2cm = cm; + rt->vcm = cm->vnet_classify_main; + + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (l2_output_classify_worker_init); + /** Enable/disable l2 input classification on a specific interface. */ void vnet_l2_output_classify_enable_disable (u32 sw_if_index, int enable_disable) diff --git a/src/vnet/l2tp/l2tp.c b/src/vnet/l2tp/l2tp.c index 2d323397..cb94d7e7 100644 --- a/src/vnet/l2tp/l2tp.c +++ b/src/vnet/l2tp/l2tp.c @@ -747,6 +747,16 @@ l2tp_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (l2tp_init); +clib_error_t * +l2tp_worker_init (vlib_main_t * vm) +{ + l2tp_encap_init (vm); + + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (l2tp_worker_init); + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/mpls/node.c b/src/vnet/mpls/node.c index 18100912..03bfaf56 100644 --- a/src/vnet/mpls/node.c +++ b/src/vnet/mpls/node.c @@ -301,3 +301,16 @@ static clib_error_t * mpls_input_init (vlib_main_t * vm) } VLIB_INIT_FUNCTION (mpls_input_init); + +static clib_error_t * mpls_input_worker_init (vlib_main_t * vm) +{ + mpls_input_runtime_t * rt; + rt = vlib_node_get_runtime_data (vm, mpls_input_node.index); + rt->last_label = (u32) ~0; + rt->last_inner_fib_index = 0; + rt->last_outer_fib_index = 0; + rt->mpls_main = &mpls_main; + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (mpls_input_worker_init); diff --git a/src/vnet/ppp/node.c b/src/vnet/ppp/node.c index 4f1f6a71..2f6e0c33 100644 --- a/src/vnet/ppp/node.c +++ b/src/vnet/ppp/node.c @@ -295,18 +295,10 @@ VLIB_REGISTER_NODE (ppp_input_node) = { /* *INDENT-ON* */ static clib_error_t * -ppp_input_init (vlib_main_t * vm) +ppp_input_runtime_init (vlib_main_t * vm) { ppp_input_runtime_t *rt; - { - clib_error_t *error = vlib_call_init_function (vm, ppp_init); - if (error) - clib_error_report (error); - } - - ppp_setup_node (vm, ppp_input_node.index); - rt = vlib_node_get_runtime_data (vm, ppp_input_node.index); rt->next_by_protocol = sparse_vec_new @@ -323,7 +315,24 @@ ppp_input_init (vlib_main_t * vm) return 0; } +static clib_error_t * +ppp_input_init (vlib_main_t * vm) +{ + + { + clib_error_t *error = vlib_call_init_function (vm, ppp_init); + if (error) + clib_error_report (error); + } + + ppp_setup_node (vm, ppp_input_node.index); + ppp_input_runtime_init (vm); + + return 0; +} + VLIB_INIT_FUNCTION (ppp_input_init); +VLIB_WORKER_INIT_FUNCTION (ppp_input_runtime_init); void ppp_register_input_protocol (vlib_main_t * vm, diff --git a/src/vnet/tcp/tcp_syn_filter4.c b/src/vnet/tcp/tcp_syn_filter4.c index c7605a30..9b2a8ac7 100644 --- a/src/vnet/tcp/tcp_syn_filter4.c +++ b/src/vnet/tcp/tcp_syn_filter4.c @@ -450,18 +450,21 @@ syn_filter_enable_disable (u32 sw_if_index, int enable_disable) if (enable_disable) { - vlib_main_t *vm = vlib_get_main (); syn_filter4_runtime_t *rt; - rt = vlib_node_get_runtime_data (vm, syn_filter4_node.index); - vec_validate (rt->syn_counts, 1023); - /* - * Given perfect disperson / optimal hashing results: - * Allow 128k (successful) syns/sec. 1024, buckets each of which - * absorb 128 syns before filtering. Reset table once a second. - * Reality bites, lets try resetting once every 100ms. - */ - rt->reset_interval = 0.1; /* reset interval in seconds */ + /* *INDENT-OFF* */ + foreach_vlib_main ({ + rt = vlib_node_get_runtime_data (this_vlib_main, syn_filter4_node.index); + vec_validate (rt->syn_counts, 1023); + /* + * Given perfect disperson / optimal hashing results: + * Allow 128k (successful) syns/sec. 1024, buckets each of which + * absorb 128 syns before filtering. Reset table once a second. + * Reality bites, lets try resetting once every 100ms. + */ + rt->reset_interval = 0.1; /* reset interval in seconds */ + }); + /* *INDENT-ON* */ } rv = vnet_feature_enable_disable ("ip4-local", "syn-filter-4", diff --git a/src/vnet/udp/udp_local.c b/src/vnet/udp/udp_local.c index 6b239f73..3a60b29b 100644 --- a/src/vnet/udp/udp_local.c +++ b/src/vnet/udp/udp_local.c @@ -520,11 +520,15 @@ udp_register_dst_port (vlib_main_t * vm, : udp6_input_node.index, node_index); /* Setup udp protocol -> next index sparse vector mapping. */ - rt = vlib_node_get_runtime_data - (vm, is_ip4 ? udp4_input_node.index : udp6_input_node.index); - n = sparse_vec_validate (rt->next_by_dst_port, - clib_host_to_net_u16 (dst_port)); - n[0] = pi->next_index; + /* *INDENT-OFF* */ + foreach_vlib_main({ + rt = vlib_node_get_runtime_data + (this_vlib_main, is_ip4 ? udp4_input_node.index : udp6_input_node.index); + n = sparse_vec_validate (rt->next_by_dst_port, + clib_host_to_net_u16 (dst_port)); + n[0] = pi->next_index; + }); + /* *INDENT-ON* */ } void @@ -541,11 +545,15 @@ udp_unregister_dst_port (vlib_main_t * vm, udp_dst_port_t dst_port, u8 is_ip4) return; /* Kill the mapping. Don't bother killing the pi, it may be back. */ - rt = vlib_node_get_runtime_data - (vm, is_ip4 ? udp4_input_node.index : udp6_input_node.index); - n = sparse_vec_validate (rt->next_by_dst_port, - clib_host_to_net_u16 (dst_port)); - n[0] = SPARSE_VEC_INVALID_INDEX; + /* *INDENT-OFF* */ + foreach_vlib_main({ + rt = vlib_node_get_runtime_data + (this_vlib_main, is_ip4 ? udp4_input_node.index : udp6_input_node.index); + n = sparse_vec_validate (rt->next_by_dst_port, + clib_host_to_net_u16 (dst_port)); + n[0] = SPARSE_VEC_INVALID_INDEX; + }); + /* *INDENT-ON* */ } void @@ -604,10 +612,27 @@ udp_setup_node (vlib_main_t * vm, u32 node_index) pn->unformat_edit = unformat_pg_udp_header; } +static void +udp_local_node_runtime_init (vlib_main_t * vm) +{ + udp_input_runtime_t *rt; + + rt = vlib_node_get_runtime_data (vm, udp4_input_node.index); + rt->next_by_dst_port = sparse_vec_new + ( /* elt bytes */ sizeof (rt->next_by_dst_port[0]), + /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); + rt->punt_unknown = 0; + + rt = vlib_node_get_runtime_data (vm, udp6_input_node.index); + rt->next_by_dst_port = sparse_vec_new + ( /* elt bytes */ sizeof (rt->next_by_dst_port[0]), + /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); + rt->punt_unknown = 0; +} + clib_error_t * udp_local_init (vlib_main_t * vm) { - udp_input_runtime_t *rt; udp_main_t *um = &udp_main; int i; @@ -628,27 +653,13 @@ udp_local_init (vlib_main_t * vm) udp_setup_node (vm, udp4_input_node.index); udp_setup_node (vm, udp6_input_node.index); - rt = vlib_node_get_runtime_data (vm, udp4_input_node.index); - - rt->next_by_dst_port = sparse_vec_new - ( /* elt bytes */ sizeof (rt->next_by_dst_port[0]), - /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); - - rt->punt_unknown = 0; + udp_local_node_runtime_init (vm); #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 1 /* is_ip4 */); foreach_udp4_dst_port #undef _ - rt = vlib_node_get_runtime_data (vm, udp6_input_node.index); - - rt->next_by_dst_port = sparse_vec_new - ( /* elt bytes */ sizeof (rt->next_by_dst_port[0]), - /* bits in index */ BITS (((udp_header_t *) 0)->dst_port)); - - rt->punt_unknown = 0; - #define _(n,s) add_dst_port (um, UDP_DST_PORT_##s, #s, 0 /* is_ip4 */); - foreach_udp6_dst_port + foreach_udp6_dst_port #undef _ ip4_register_protocol (IP_PROTOCOL_UDP, udp4_input_node.index); /* Note: ip6 differs from ip4, UDP is hotwired to ip6-udp-lookup */ @@ -657,6 +668,15 @@ udp_local_init (vlib_main_t * vm) VLIB_INIT_FUNCTION (udp_local_init); +clib_error_t * +udp_local_worker_init (vlib_main_t * vm) +{ + udp_local_node_runtime_init (vm); + return 0; +} + +VLIB_WORKER_INIT_FUNCTION (udp_local_worker_init); + /* * fd.io coding-style-patch-verification: ON * -- cgit 1.2.3-korg From da1f2c7cffb0de4ef05a48ffd107214eb11fa45f Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 24 Mar 2017 20:11:15 -0400 Subject: Implement MAC Flush for BD or Interface from the L2FIB Allow non-static MACs in the L2FIB which is associated with an interface or a bridge domain (BD) be flushed. MAC flush are initiated automatically when an interface is removed from a BD or when a BD is deleted. MAC flush can also be invoked manually via the following CLI: l2fib mac-flush interface l2fib mac-flush bridge-domain Change-Id: Ie33243622834810a765f48ebcd22bdb8e8fc87a4 Signed-off-by: John Lo --- src/vnet/buffer.h | 8 ++- src/vnet/l2/l2_bd.c | 41 +++++++---- src/vnet/l2/l2_bd.h | 3 + src/vnet/l2/l2_fib.c | 188 +++++++++++++++++++++++++++++++++++++++++++++---- src/vnet/l2/l2_fib.h | 39 +++++----- src/vnet/l2/l2_input.c | 14 ++++ src/vnet/l2/l2_input.h | 3 + src/vnet/l2/l2_learn.c | 10 ++- src/vnet/l2/l2_learn.h | 1 + 9 files changed, 258 insertions(+), 49 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index f08b4fc1..ea3ce093 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -169,9 +169,11 @@ typedef struct struct { u32 feature_bitmap; - u16 bd_index; // bridge-domain index - u8 l2_len; // ethernet header length - u8 shg; // split-horizon group + u16 bd_index; /* bridge-domain index */ + u8 l2_len; /* ethernet header length */ + u8 shg; /* split-horizon group */ + u8 bd_sn; /* bridge domain seq# */ + u8 int_sn; /* interface seq# */ } l2; /* l2tpv3 softwire encap, only valid there */ diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index f741b643..6c01368b 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -115,6 +115,8 @@ bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) l2input_main.bd_configs[bd_index].bd_id = ~0; l2input_main.bd_configs[bd_index].feature_bitmap = 0; + l2fib_flush_bd_mac (vlib_get_main (), bd_index); + return 0; } @@ -900,7 +902,6 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 bd_index = ~0; l2_bridge_domain_t *bd_config; u32 start, end; - u32 printed; u32 detail = 0; u32 intf = 0; u32 arp = 0; @@ -942,7 +943,8 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } /* Show all bridge-domains that have been initialized */ - printed = 0; + u32 printed = 0; + u8 *as = 0; for (bd_index = start; bd_index < end; bd_index++) { bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); @@ -952,26 +954,32 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { printed = 1; vlib_cli_output (vm, - "%=5s %=7s %=10s %=10s %=10s %=10s %=10s %=14s", - "ID", "Index", "Learning", "U-Forwrd", - "UU-Flood", "Flooding", "ARP-Term", + "%=5s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", + "ID", "Index", "BSN", "Age(min)", "Learning", + "U-Forwrd", "UU-Flood", "Flooding", "ARP-Term", "BVI-Intf"); } + if (bd_config->mac_age) + as = format (as, "%d", bd_config->mac_age); + else + as = format (as, "off"); vlib_cli_output (vm, - "%=5d %=7d %=10s %=10s %=10s %=10s %=10s %=14U", - bd_config->bd_id, bd_index, + "%=5d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", + bd_config->bd_id, bd_index, bd_config->seq_num, as, bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? "on" : "off", - bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on" - : "off", + bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? + "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_UU_FLOOD ? "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ? "on" : "off", bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ? - "on" : "off", format_vnet_sw_if_index_name_with_NA, + "on" : "off", + format_vnet_sw_if_index_name_with_NA, vnm, bd_config->bvi_sw_if_index); + vec_reset_length (as); if (detail || intf) { @@ -981,19 +989,21 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { l2_flood_member_t *member = vec_elt_at_index (bd_config->members, i); + l2_input_config_t *int_config = + l2input_intf_config (member->sw_if_index); u32 vtr_opr, dot1q, tag1, tag2; if (i == 0) { - vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=9s%=30s", - "Interface", "Index", "SHG", "BVI", - "TxFlood", "VLAN-Tag-Rewrite"); + vlib_cli_output (vm, "\n%=30s%=7s%=5s%=5s%=5s%=9s%=30s", + "Interface", "If-idx", "ISN", "SHG", + "BVI", "TxFlood", "VLAN-Tag-Rewrite"); } l2vtr_get (vm, vnm, member->sw_if_index, &vtr_opr, &dot1q, &tag1, &tag2); - vlib_cli_output (vm, "%=30U%=7d%=5d%=5s%=9s%=30U", + vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U", format_vnet_sw_if_index_name, vnm, member->sw_if_index, member->sw_if_index, - member->shg, + int_config->seq_num, member->shg, member->flags & L2_FLOOD_MEMBER_BVI ? "*" : "-", i < bd_config->flood_count ? "*" : "-", format_vtr, vtr_opr, dot1q, tag1, tag2); @@ -1027,6 +1037,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } } } + vec_free (as); if (!printed) { diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 4bb9bc9b..5c2502d9 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -86,6 +86,9 @@ typedef struct /* mac aging */ u8 mac_age; + /* sequence number for bridge domain based flush of MACs */ + u8 seq_num; + } l2_bridge_domain_t; /* Return 1 if bridge domain has been initialized */ diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index d34836e3..fadd79eb 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -168,10 +168,10 @@ show_l2fib (vlib_main_t * vm, { first_entry = 0; vlib_cli_output (vm, - "%=19s%=7s%=30s%=7s%=8s%=8s%=5s%=16s", - "Mac Address", "BD Idx", "Interface", - "Index", "static", "filter", "bvi", - "Mac Age (min)"); + "%=19s%=7s%=7s%=8s%=9s%=7s%=7s%=5s%=30s", + "Mac-Address", "BD-Idx", "If-Idx", + "BSN-ISN", "Age(min)", "static", "filter", + "bvi", "Interface-Name"); } key.raw = v->kvp[k].key; @@ -183,26 +183,27 @@ show_l2fib (vlib_main_t * vm, bd_config = vec_elt_at_index (l2input_main.bd_configs, key.fields.bd_index); - if (bd_config->mac_age) + if (bd_config->mac_age && !result.fields.static_mac) { i16 delta = now - result.fields.timestamp; delta += delta < 0 ? 256 : 0; s = format (s, "%d", delta); } else - s = format (s, "disabled"); + s = format (s, "-"); vlib_cli_output (vm, - "%=19U%=7d%=30U%=7d%=8d%=8d%=5d%=16v", + "%=19U%=7d%=7d %3d/%-3d%=9v%=7s%=7s%=5s%=30U", format_ethernet_address, key.fields.mac, key.fields.bd_index, - format_vnet_sw_if_index_name_with_NA, - msm->vnet_main, result.fields.sw_if_index, result.fields.sw_if_index == ~0 ? -1 : result.fields.sw_if_index, - result.fields.static_mac, - result.fields.filter, - result.fields.bvi, s); + result.fields.bd_sn, result.fields.int_sn, + s, result.fields.static_mac ? "*" : "-", + result.fields.filter ? "*" : "-", + result.fields.bvi ? "*" : "-", + format_vnet_sw_if_index_name_with_NA, + msm->vnet_main, result.fields.sw_if_index); vec_reset_length (s); } total_entries++; @@ -330,6 +331,15 @@ l2fib_add_entry (u64 mac, result.fields.static_mac = static_mac; result.fields.filter = filter_mac; result.fields.bvi = bvi_mac; + if (!static_mac) + { + l2_input_config_t *int_config = l2input_intf_config (sw_if_index); + l2_bridge_domain_t *bd_config = + vec_elt_at_index (l2input_main.bd_configs, + bd_index); + result.fields.int_sn = int_config->seq_num; + result.fields.bd_sn = bd_config->seq_num; + } kv.key = key.raw; kv.value = result.raw; @@ -703,6 +713,141 @@ VLIB_CLI_COMMAND (l2fib_del_cli, static) = { }; /* *INDENT-ON* */ +/** + Kick off ager to scan MACs to age/delete MAC entries +*/ +void +l2fib_start_ager_scan (vlib_main_t * vm) +{ + l2_bridge_domain_t *bd_config; + int enable = 0; + + /* check if there is at least one bd with mac aging enabled */ + vec_foreach (bd_config, l2input_main.bd_configs) + if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) + enable = 1; + + vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, + enable ? L2_MAC_AGE_PROCESS_EVENT_START : + L2_MAC_AGE_PROCESS_EVENT_ONE_PASS, 0); +} + +/** + Flush all learned MACs from an interface +*/ +void +l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index) +{ + l2_input_config_t *int_config; + int_config = l2input_intf_config (sw_if_index); + int_config->seq_num += 1; + l2fib_start_ager_scan (vm); +} + +/** + Flush all learned MACs in a bridge domain +*/ +void +l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index) +{ + l2_bridge_domain_t *bd_config; + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config->seq_num += 1; + l2fib_start_ager_scan (vm); +} + +/** + Flush MACs, except static ones, associated with an interface + The CLI format is: + l2fib flush-mac interface +*/ +static clib_error_t * +l2fib_flush_mac_int (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + clib_error_t *error = 0; + u32 sw_if_index; + + if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + error = clib_error_return (0, "unknown interface `%U'", + format_unformat_error, input); + goto done; + } + + l2fib_flush_int_mac (vm, sw_if_index); + +done: + return error; +} + +/*? + * This command kick off ager to delete all existing MAC Address entries, + * except static ones, associated with an interface from the L2 FIB table. + * + * @cliexpar + * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table: + * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_flush_mac_int_cli, static) = { + .path = "l2fib flush-mac interface", + .short_help = "l2fib flush-mac interface ", + .function = l2fib_flush_mac_int, +}; +/* *INDENT-ON* */ + +/** + Flush bridge-domain MACs except static ones. + The CLI format is: + l2fib flush-mac bridge-domain +*/ +static clib_error_t * +l2fib_flush_mac_bd (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + bd_main_t *bdm = &bd_main; + clib_error_t *error = 0; + u32 bd_index, bd_id; + uword *p; + + if (!unformat (input, "%d", &bd_id)) + { + error = clib_error_return (0, "expecting bridge-domain id but got `%U'", + format_unformat_error, input); + goto done; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p) + bd_index = *p; + else + return clib_error_return (0, "No such bridge domain %d", bd_id); + + l2fib_flush_bd_mac (vm, bd_index); + +done: + return error; +} + +/*? + * This command kick off ager to delete all existing MAC Address entries, + * except static ones, in a bridge domain from the L2 FIB table. + * + * @cliexpar + * Example of how to flush MAC Address entries learned in a bridge domain from the L2 FIB table: + * @cliexcmd{l2fib flush-mac bridge-domain 1000} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = { + .path = "l2fib flush-mac bridge-domain", + .short_help = "l2fib flush-mac bridge-domain ", + .function = l2fib_flush_mac_bd, +}; +/* *INDENT-ON* */ + BVT (clib_bihash) * get_mac_table (void) { @@ -716,6 +861,7 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, { uword event_type, *event_data = 0; l2fib_main_t *msm = &l2fib_main; + l2_input_config_t *int_config; l2_bridge_domain_t *bd_config; BVT (clib_bihash) * h = &msm->mac_table; clib_bihash_bucket_t *b; @@ -747,6 +893,9 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, case L2_MAC_AGE_PROCESS_EVENT_STOP: enabled = 0; continue; + case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS: + enabled = 0; + break; default: ASSERT (0); } @@ -790,8 +939,19 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (result.fields.static_mac) continue; - bd_config = vec_elt_at_index (l2input_main.bd_configs, - key.fields.bd_index); + int_config = + l2input_intf_config (result.fields.sw_if_index); + bd_config = + vec_elt_at_index (l2input_main.bd_configs, + key.fields.bd_index); + + if ((result.fields.int_sn != int_config->seq_num) || + (result.fields.bd_sn != bd_config->seq_num)) + { + void *p = &key.fields.mac; + l2fib_del_entry (*(u64 *) p, key.fields.bd_index); + continue; + } if (bd_config->mac_age == 0) continue; diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 4a2da59b..7e49d74b 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -66,7 +66,8 @@ typedef struct u8 filter:1; /* drop packets to/from this mac */ u8 unused1:5; u8 timestamp; /* timestamp for aging */ - u16 unused2; + u8 int_sn; /* interface seq num */ + u8 bd_sn; /* bridge domain seq num */ } fields; u64 raw; }; @@ -313,22 +314,28 @@ l2fib_lookup_4 (BVT (clib_bihash) * mac_table, } } +void l2fib_clear_table (uint keep_static); + +void +l2fib_add_entry (u64 mac, + u32 bd_index, + u32 sw_if_index, u32 static_mac, u32 drop_mac, u32 bvi_mac); + +u32 l2fib_del_entry (u64 mac, u32 bd_index); + +void l2fib_start_ager_scan (vlib_main_t * vm); + +void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index); + +void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index); + +void +l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, + l2fib_entry_result_t ** l2fe_res); + +u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); + BVT (clib_bihash) * get_mac_table (void); - void - l2fib_clear_table (uint keep_static); - void - l2fib_add_entry (u64 mac, - u32 bd_index, - u32 sw_if_index, - u32 static_mac, u32 drop_mac, u32 bvi_mac); -u32 -l2fib_del_entry (u64 mac, u32 bd_index); - - void - l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, - l2fib_entry_result_t ** l2fe_res); - - u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); #endif diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 3aa5331b..041ff38d 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -201,6 +202,9 @@ classify_and_dispatch (vlib_main_t * vm, /* Get config for the bridge domain interface */ bd_config = vec_elt_at_index (msm->bd_configs, bd_index0); + /* Save bridge domain seq_num */ + vnet_buffer (b0)->l2.bd_sn = bd_config->seq_num; + /* * Process bridge domain feature enables. * To perform learning/flooding/forwarding, the corresponding bit @@ -214,6 +218,9 @@ classify_and_dispatch (vlib_main_t * vm, /* mask out features from bitmap using packet type and bd config */ feature_bitmap = config->feature_bitmap & feat_mask; + /* Save interface seq_num */ + vnet_buffer (b0)->l2.int_sn = config->seq_num; + /* save for next feature graph nodes */ vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; @@ -561,6 +568,12 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT); } + + /* Clear MACs learned on the interface */ + if ((config->feature_bitmap | L2INPUT_FEAT_LEARN) || + (bd_config->feature_bitmap | L2INPUT_FEAT_LEARN)) + l2fib_flush_int_mac (vm, sw_if_index); + l2_if_adjust--; } else if (config->xconnect) @@ -632,6 +645,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->xconnect = 0; config->bridge = 1; config->bd_index = bd_index; + config->seq_num += 1; /* * Enable forwarding, flooding, learning and ARP termination by default diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index f3fada6a..262f75c7 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -53,6 +53,9 @@ typedef struct /* split horizon group */ u8 shg; + /* sequence number for interface based flush of MACs */ + u8 seq_num; + } l2_input_config_t; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index afe7f478..faed0d66 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -140,7 +140,11 @@ l2learn_process (vlib_node_runtime_t * node, counter_base[L2LEARN_ERROR_HIT] += 1; if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) result0->fields.timestamp = timestamp; - + if (PREDICT_FALSE + (result0->fields.int_sn != vnet_buffer (b0)->l2.int_sn)) + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; + if (PREDICT_FALSE (result0->fields.bd_sn != vnet_buffer (b0)->l2.bd_sn)) + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; } else if (result0->raw == ~0) { @@ -167,6 +171,8 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; kv.key = key0->raw; kv.value = result0->raw; @@ -204,6 +210,8 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; + result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; + result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; kv.key = key0->raw; kv.value = result0->raw; diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index 5bb1130b..0d95de04 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -51,6 +51,7 @@ enum { L2_MAC_AGE_PROCESS_EVENT_START = 1, L2_MAC_AGE_PROCESS_EVENT_STOP = 2, + L2_MAC_AGE_PROCESS_EVENT_ONE_PASS = 3, } l2_mac_age_process_event_t; #endif -- cgit 1.2.3-korg From 054807960a92e477563321720cf8750909d72d7e Mon Sep 17 00:00:00 2001 From: Choonho Son Date: Wed, 29 Mar 2017 20:07:45 +0900 Subject: CLI: create/delete bridge-domain Added new CLI command - create bridge-domain - create bridge-domain del Change-Id: I1a7d632c7daa3c37b7f424a184e8fabd489518e9 Signed-off-by: Choonho Son --- src/vnet/l2/l2_bd.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/vnet/l2/l2_bd.h | 12 ++++ 2 files changed, 201 insertions(+), 1 deletion(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 6c01368b..0375998c 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -104,7 +104,7 @@ bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) - return -1; + return VNET_API_ERROR_NO_SUCH_ENTRY; bd_index = p[0]; @@ -212,6 +212,8 @@ l2bd_init (vlib_main_t * vm) bd_index = bd_find_or_add_bd_index (bdm, 0); ASSERT (bd_index == 0); l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; + + bdm->vlib_main = vm; return 0; } @@ -1081,6 +1083,192 @@ VLIB_CLI_COMMAND (bd_show_cli, static) = { }; /* *INDENT-ON* */ +int +bd_add_del (l2_bridge_domain_add_del_args_t * a) +{ + bd_main_t *bdm = &bd_main; + vlib_main_t *vm = bdm->vlib_main; + u32 enable_flags = 0, disable_flags = 0; + u32 bd_index = ~0; + int rv = 0; + + if (a->is_add) + { + bd_index = bd_find_or_add_bd_index (bdm, a->bd_id); + if (bd_index == ~0) + return bd_index; + + if (a->flood) + enable_flags |= L2_FLOOD; + else + disable_flags |= L2_FLOOD; + + if (a->uu_flood) + enable_flags |= L2_UU_FLOOD; + else + disable_flags |= L2_UU_FLOOD; + + if (a->forward) + enable_flags |= L2_FWD; + else + disable_flags |= L2_FWD; + + if (a->learn) + enable_flags |= L2_LEARN; + else + disable_flags |= L2_LEARN; + + if (a->arp_term) + enable_flags |= L2_ARP_TERM; + else + disable_flags |= L2_ARP_TERM; + + if (enable_flags) + bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); + + if (disable_flags) + bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); + + bd_set_mac_age (vm, bd_index, a->mac_age); + } + else + rv = bd_delete_bd_index (bdm, a->bd_id); + + return rv; +} + +/** + Create or delete bridge-domain. + The CLI format is: + create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] + [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] +*/ + +static clib_error_t * +bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; + u8 is_add = 1; + u32 bd_id = ~0; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 0, arp_term = 0; + u32 mac_age = 0; + l2_bridge_domain_add_del_args_t _a, *a = &_a; + int rv; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%d", &bd_id)) + ; + else if (unformat (line_input, "flood %d", &flood)) + ; + else if (unformat (line_input, "uu-flood %d", &uu_flood)) + ; + else if (unformat (line_input, "forward %d", &forward)) + ; + else if (unformat (line_input, "arp-term %d", &arp_term)) + ; + else if (unformat (line_input, "mac-age %d", &mac_age)) + ; + else if (unformat (line_input, "del")) + { + is_add = 0; + flood = uu_flood = forward = learn = 0; + } + else + break; + } + + if (bd_id == ~0) + { + error = clib_error_return (0, "bridge-domain-id not specified"); + goto done; + } + + if (mac_age > 255) + { + error = clib_error_return (0, "mac age must be less than 256"); + goto done; + } + + memset (a, 0, sizeof (*a)); + a->is_add = is_add; + a->bd_id = bd_id; + a->flood = (u8) flood; + a->uu_flood = (u8) uu_flood; + a->forward = (u8) forward; + a->learn = (u8) learn; + a->arp_term = (u8) arp_term; + a->mac_age = (u8) mac_age; + + rv = bd_add_del (a); + + switch (rv) + { + case 0: + if (is_add) + vlib_cli_output (vm, "bridge-domain %d", bd_id); + break; + case VNET_API_ERROR_NO_SUCH_ENTRY: + error = clib_error_return (0, "bridge domain id does not exist"); + goto done; + default: + error = clib_error_return (0, "bd_add_del returned %d", rv); + goto done; + } + +done: + unformat_free (line_input); + + return error; +} + + +/*? + * Create/Delete bridge-domain instance + * + * @cliexpar + * @parblock + * Example of creating bridge-domain 1: + * @cliexstart{create bridge-domain 1} + * bridge-domain 1 + * @cliexend + * + * Example of creating bridge-domain 2 with enabling arp-term, mac-age 60: + * @cliexstart{create bridge-domain 2 arp-term 1 mac-age 60} + * bridge-domain 2 + * + * vpp# show bridge-domain + * ID Index BSN Age(min) Learning U-Forwrd UU-Flood Flooding ARP-Term BVI-Intf + * 0 0 0 off off off off off off local0 + * 1 1 0 off on on off on off N/A + * 2 2 0 60 on on off on on N/A + * + * @cliexend + * + * Example of delete bridge-domain 1: + * @cliexstart{create bridge-domain 1 del} + * @cliexend + * @endparblock +?*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bd_create_cli, static) = { + .path = "create bridge-domain", + .short_help = "create bridge-domain " + " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]" + " [mac-age ] [del]", + .function = bd_add_del_command_fn, +}; +/* *INDENT-ON* */ + + + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 5c2502d9..83733411 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -91,6 +91,18 @@ typedef struct } l2_bridge_domain_t; +typedef struct +{ + u32 bd_id; + u8 flood; + u8 uu_flood; + u8 forward; + u8 learn; + u8 arp_term; + u8 mac_age; + u8 is_add; +} l2_bridge_domain_add_del_args_t; + /* Return 1 if bridge domain has been initialized */ always_inline u32 bd_is_valid (l2_bridge_domain_t * bd_config) -- cgit 1.2.3-korg From fead670ae0a8323d8cd14e2cfad1fb8c25a48a99 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Tue, 4 Apr 2017 04:46:32 +0300 Subject: BD/API:add bridge_domain_set_mac_age api Change-Id: Ic2d33b31ba88f6d9602a22439865637d98cf4a33 Signed-off-by: Eyal Bari --- src/vat/api_format.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++- src/vnet/l2/l2.api | 24 +++++++++++++++ src/vnet/l2/l2_api.c | 33 +++++++++++++++----- src/vnet/l2/l2_bd.c | 3 +- src/vnet/l2/l2_input.h | 5 +++ src/vpp/api/custom_dump.c | 23 +++++++++++--- 6 files changed, 150 insertions(+), 15 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index fca2b37a..06884eb1 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1458,6 +1458,39 @@ static void vl_api_control_ping_reply_t_handler_json vam->result_ready = 1; } +static void + vl_api_bridge_domain_set_mac_age_reply_t_handler + (vl_api_bridge_domain_set_mac_age_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_bridge_domain_set_mac_age_reply_t_handler_json + (vl_api_bridge_domain_set_mac_age_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_l2_flags_reply_t_handler (vl_api_l2_flags_reply_t * mp) { @@ -4285,6 +4318,7 @@ _(SW_INTERFACE_SET_L2_BRIDGE_REPLY, \ _(BRIDGE_DOMAIN_ADD_DEL_REPLY, bridge_domain_add_del_reply) \ _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ _(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE_REPLY, bridge_domain_set_mac_age_reply) \ _(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ _(L2_FLAGS_REPLY, l2_flags_reply) \ _(BRIDGE_FLAGS_REPLY, bridge_flags_reply) \ @@ -6030,6 +6064,46 @@ api_l2fib_add_del (vat_main_t * vam) return (vam->retval); } +static int +api_bridge_domain_set_mac_age (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_set_mac_age_t *mp; + u32 bd_id = ~0; + u32 mac_age = 0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)); + else if (unformat (i, "mac-age %d", &mac_age)); + else + break; + } + + if (bd_id == ~0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (mac_age > 255) + { + errmsg ("mac age must be less than 256 "); + return -99; + } + + M (BRIDGE_DOMAIN_SET_MAC_AGE, mp); + + mp->bd_id = htonl (bd_id); + mp->mac_age = (u8) mac_age; + + S (mp); + W (ret); + return ret; +} + static int api_l2_flags (vat_main_t * vam) { @@ -18419,8 +18493,9 @@ _(sw_interface_set_l2_bridge, \ " | sw_if_index bd_id \n" \ "[shg ] [bvi]\n" \ "enable | disable") \ +_(bridge_domain_set_mac_age, "bd_id mac-age 0-255\n")\ _(bridge_domain_add_del, \ - "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [del]\n") \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 061990c0..81b75858 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -146,6 +146,30 @@ define l2_flags_reply u32 resulting_feature_bitmap; }; +/** \brief L2 bridge domain set mac age + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the bridge domain to create + @param mac_age - mac aging time in min, 0 for disabled +*/ +define bridge_domain_set_mac_age +{ + u32 client_index; + u32 context; + u32 bd_id; + u8 mac_age; +}; + +/** \brief Set bridge domain response + @param context - sender context, to match reply w/ request + @param retval - return code for the set l2 bits request +*/ +define bridge_domain_set_mac_age_reply +{ + u32 context; + i32 retval; +}; + /** \brief L2 bridge domain add or delete request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a985852c..ffcc7901 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -54,7 +54,8 @@ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ _(BRIDGE_FLAGS, bridge_flags) \ _(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \ -_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) +_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) static void send_l2_xconnect_details (unix_shared_memory_queue_t * q, u32 context, @@ -244,17 +245,13 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) { vl_api_l2_flags_reply_t *rmp; int rv = 0; - u32 sw_if_index = ntohl (mp->sw_if_index); - u32 flags = ntohl (mp->feature_bitmap); u32 rbm = 0; VALIDATE_SW_IF_INDEX (mp); -#define _(a,b) \ - if (flags & L2INPUT_FEAT_ ## a) \ - rbm = l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_ ## a, mp->is_set); - foreach_l2input_feat; -#undef _ + u32 sw_if_index = ntohl (mp->sw_if_index); + u32 flags = ntohl (mp->feature_bitmap) & L2INPUT_VALID_MASK; + rbm = l2input_intf_bitmap_enable (sw_if_index, flags, mp->is_set); BAD_SW_IF_INDEX_LABEL; @@ -266,6 +263,26 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) /* *INDENT-ON* */ } +static void +vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t + * mp) +{ + vlib_main_t *vm = vlib_get_main (); + bd_main_t *bdm = &bd_main; + vl_api_bridge_domain_set_mac_age_reply_t *rmp; + int rv = 0; + u32 bd_id = ntohl (mp->bd_id); + uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + { + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; + } + bd_set_mac_age (vm, *p, mp->mac_age); +out: + REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_MAC_AGE_REPLY); +} + static void vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 0375998c..a222fec9 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -284,8 +284,7 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) /* check if there is at least one bd with mac aging enabled */ vec_foreach (bd_config, l2input_main.bd_configs) - if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) - enable = 1; + enable |= bd_config->bd_id != ~0 && bd_config->mac_age != 0; vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, enable ? L2_MAC_AGE_PROCESS_EVENT_START : diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index 262f75c7..a2ade8d8 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -117,6 +117,11 @@ typedef enum foreach_l2input_feat #undef _ L2INPUT_N_FEAT, + L2INPUT_VALID_MASK = +#define _(sym,str) L2INPUT_FEAT_##sym##_BIT | + foreach_l2input_feat +#undef _ + 0, } l2input_feat_t; /* Feature bit masks */ diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index fd4f7fef..b3fd781e 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -200,7 +200,7 @@ static void *vl_api_sw_interface_set_vxlan_bypass_t_print s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); if (mp->is_ipv6) - s = format (s, "ip6"); + s = format (s, "ip6 "); if (mp->enable) s = format (s, "enable "); @@ -260,9 +260,9 @@ static void *vl_api_bridge_domain_add_del_t_print if (mp->is_add) { - s = format (s, "flood %d uu-flood %d forward %d learn %d arp-term %d", - mp->flood, mp->uu_flood, mp->forward, mp->learn, - mp->arp_term); + s = format (s, "flood %d uu-flood %d ", mp->flood, mp->uu_flood); + s = format (s, "forward %d learn %d ", mp->forward, mp->learn); + s = format (s, "arp-term %d mac-age %d", mp->arp_term, mp->mac_age); } else s = format (s, "del "); @@ -270,6 +270,20 @@ static void *vl_api_bridge_domain_add_del_t_print FINISH; } +static void *vl_api_bridge_domain_set_mac_age_t_print + (vl_api_bridge_domain_set_mac_age_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: bridge_domain_set_mac_age "); + + s = format (s, "bd_id %d ", ntohl (mp->bd_id)); + + s = format (s, "mac-age %d", mp->mac_age); + + FINISH; +} + static void *vl_api_bridge_domain_dump_t_print (vl_api_bridge_domain_dump_t * mp, void *handle) { @@ -2948,6 +2962,7 @@ _(CLASSIFY_ADD_DEL_SESSION, classify_add_del_session) \ _(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ +_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \ _(CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table) \ _(CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables) \ _(ADD_NODE_NEXT, add_node_next) \ -- cgit 1.2.3-korg From f24991cab4a899f9e36e7f12ca61c591fedde249 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 5 Apr 2017 05:33:21 +0300 Subject: L2FIB:add l2fib_flush_bd l2fib_flush_int apis Change-Id: I0a6989c6963956f3e60e8c50835c57845fccef8c Signed-off-by: Eyal Bari --- src/vat/api_format.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-- src/vnet/l2/l2.api | 44 ++++++++++++++++++++++++++++ src/vnet/l2/l2_api.c | 38 ++++++++++++++++++++++++ src/vpp/api/custom_dump.c | 26 +++++++++++++++++ 4 files changed, 180 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 090d990b..61b8e1d8 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -4151,6 +4151,8 @@ _(sw_interface_set_l2_bridge_reply) \ _(bridge_domain_add_del_reply) \ _(sw_interface_set_l2_xconnect_reply) \ _(l2fib_add_del_reply) \ +_(l2fib_flush_int_reply) \ +_(l2fib_flush_bd_reply) \ _(ip_add_del_route_reply) \ _(ip_mroute_add_del_reply) \ _(mpls_route_add_del_reply) \ @@ -4320,6 +4322,8 @@ _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ _(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ _(BRIDGE_DOMAIN_SET_MAC_AGE_REPLY, bridge_domain_set_mac_age_reply) \ _(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ +_(L2FIB_FLUSH_INT_REPLY, l2fib_flush_int_reply) \ +_(L2FIB_FLUSH_BD_REPLY, l2fib_flush_bd_reply) \ _(L2_FLAGS_REPLY, l2_flags_reply) \ _(BRIDGE_FLAGS_REPLY, bridge_flags_reply) \ _(TAP_CONNECT_REPLY, tap_connect_reply) \ @@ -5914,6 +5918,70 @@ api_bridge_domain_add_del (vat_main_t * vam) return ret; } +static int +api_l2fib_flush_bd (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2fib_flush_bd_t *mp; + u32 bd_id = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)); + else + break; + } + + if (bd_id == ~0) + { + errmsg ("missing bridge domain"); + return -99; + } + + M (L2FIB_FLUSH_BD, mp); + + mp->bd_id = htonl (bd_id); + + S (mp); + W (ret); + return ret; +} + +static int +api_l2fib_flush_int (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2fib_flush_int_t *mp; + u32 sw_if_index = ~0; + int ret; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)); + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)); + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2FIB_FLUSH_INT, mp); + + mp->sw_if_index = ntohl (sw_if_index); + + S (mp); + W (ret); + return ret; +} + static int api_l2fib_add_del (vat_main_t * vam) { @@ -18542,15 +18610,17 @@ _(sw_interface_set_l2_xconnect, \ "rx | rx_sw_if_index tx | tx_sw_if_index \n" \ "enable | disable") \ _(sw_interface_set_l2_bridge, \ - " | sw_if_index bd_id \n" \ + "{ | sw_if_index } bd_id \n" \ "[shg ] [bvi]\n" \ "enable | disable") \ -_(bridge_domain_set_mac_age, "bd_id mac-age 0-255\n")\ +_(bridge_domain_set_mac_age, "bd_id mac-age 0-255") \ _(bridge_domain_add_del, \ "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ +_(l2fib_flush_bd, "bd_id ") \ +_(l2fib_flush_int, " | sw_if_index ") \ _(l2_flags, \ "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood]\n") \ _(bridge_flags, \ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 81b75858..c23eebec 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -86,6 +86,50 @@ define l2_fib_clear_table_reply i32 retval; }; +/** \brief L2 FIB flush bridge domain entries + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the entry's bridge domain id +*/ +define l2fib_flush_bd +{ + u32 client_index; + u32 context; + u32 bd_id; +}; + +/** \brief L2 FIB flush bridge domain entries response + @param context - sender context, to match reply w/ request + @param retval - return code for the request +*/ +define l2fib_flush_bd_reply +{ + u32 context; + i32 retval; +}; + +/** \brief L2 FIB flush interface entries + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param bd_id - the entry's bridge domain id +*/ +define l2fib_flush_int +{ + u32 client_index; + u32 context; + u32 sw_if_index; +}; + +/** \brief L2 FIB flush interface entries response + @param context - sender context, to match reply w/ request + @param retval - return code for the request +*/ +define l2fib_flush_int_reply +{ + u32 context; + i32 retval; +}; + /** \brief L2 FIB add entry request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index ffcc7901..026f1706 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -48,6 +48,8 @@ _(L2_XCONNECT_DUMP, l2_xconnect_dump) \ _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ _(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ +_(L2FIB_FLUSH_INT, l2fib_flush_int) \ +_(L2FIB_FLUSH_BD, l2fib_flush_bd) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ @@ -240,6 +242,42 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY); } +static void +vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp) +{ + int rv = 0; + vlib_main_t *vm = vlib_get_main (); + vl_api_l2fib_flush_int_reply_t *rmp; + + VALIDATE_SW_IF_INDEX (mp); + + u32 sw_if_index = ntohl (mp->sw_if_index); + l2fib_flush_int_mac (vm, sw_if_index); + + BAD_SW_IF_INDEX_LABEL; + REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY); +} + +static void +vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp) +{ + int rv = 0; + vlib_main_t *vm = vlib_get_main (); + bd_main_t *bdm = &bd_main; + vl_api_l2fib_flush_bd_reply_t *rmp; + + u32 bd_id = ntohl (mp->bd_id); + uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + if (p == 0) + { + rv = VNET_API_ERROR_NO_SUCH_ENTRY; + goto out; + } + l2fib_flush_bd_mac (vm, *p); +out: + REPLY_MACRO (VL_API_L2FIB_FLUSH_BD_REPLY); +} + static void vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) { diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index b3fd781e..000fe0d4 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -298,6 +298,30 @@ static void *vl_api_bridge_domain_dump_t_print FINISH; } +static void *vl_api_l2fib_flush_bd_t_print + (vl_api_l2fib_flush_bd_t * mp, void *handle) +{ + u8 *s; + u32 bd_id = ntohl (mp->bd_id); + + s = format (0, "SCRIPT: l2fib_flush_bd "); + s = format (s, "bd_id %d ", bd_id); + + FINISH; +} + +static void *vl_api_l2fib_flush_int_t_print + (vl_api_l2fib_flush_int_t * mp, void *handle) +{ + u8 *s; + u32 sw_if_index = ntohl (mp->sw_if_index); + + s = format (0, "SCRIPT: l2fib_flush_int "); + s = format (s, "sw_if_index %d ", sw_if_index); + + FINISH; +} + static void *vl_api_l2fib_add_del_t_print (vl_api_l2fib_add_del_t * mp, void *handle) { @@ -2955,6 +2979,8 @@ _(SR_POLICY_MOD, sr_policy_mod) \ _(SR_POLICY_DEL, sr_policy_del) \ _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ +_(L2FIB_FLUSH_BD, l2fib_flush_bd) \ +_(L2FIB_FLUSH_INT, l2fib_flush_int) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_FLAGS, bridge_flags) \ _(CLASSIFY_ADD_DEL_TABLE, classify_add_del_table) \ -- cgit 1.2.3-korg From 586afd762bfa149f5ca167bd5fd5a0cd59ce94fe Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Wed, 5 Apr 2017 19:18:20 +0200 Subject: Use thread local storage for thread index This patch deprecates stack-based thread identification, Also removes requirement that thread stacks are adjacent. Finally, possibly annoying for some folks, it renames all occurences of cpu_index and cpu_number with thread index. Using word "cpu" is misleading here as thread can be migrated ti different CPU, and also it is not related to linux cpu index. Change-Id: I68cdaf661e701d2336fc953dcb9978d10a70f7c1 Signed-off-by: Damjan Marion --- src/examples/srv6-sample-localsid/node.c | 4 +- src/plugins/dpdk/buffer.c | 2 +- src/plugins/dpdk/device/device.c | 8 +- src/plugins/dpdk/device/dpdk_priv.h | 8 +- src/plugins/dpdk/device/init.c | 2 +- src/plugins/dpdk/device/node.c | 32 +++--- src/plugins/dpdk/hqos/hqos.c | 16 +-- src/plugins/dpdk/ipsec/cli.c | 8 +- src/plugins/dpdk/ipsec/crypto_node.c | 4 +- src/plugins/dpdk/ipsec/esp.h | 4 +- src/plugins/dpdk/ipsec/esp_decrypt.c | 4 +- src/plugins/dpdk/ipsec/esp_encrypt.c | 5 +- src/plugins/dpdk/ipsec/ipsec.c | 2 +- src/plugins/dpdk/ipsec/ipsec.h | 4 +- src/plugins/dpdk/main.c | 2 +- src/plugins/flowperpkt/l2_node.c | 2 +- src/plugins/flowperpkt/node.c | 2 +- src/plugins/ioam/export-common/ioam_export.h | 6 +- .../ioam/ip6/ioam_cache_tunnel_select_node.c | 16 +-- src/plugins/ixge/ixge.c | 2 +- src/plugins/lb/lb.c | 8 +- src/plugins/lb/node.c | 22 ++-- src/plugins/lb/refcount.c | 8 +- src/plugins/lb/refcount.h | 4 +- src/plugins/memif/node.c | 35 +++--- src/plugins/snat/in2out.c | 110 +++++++++--------- src/plugins/snat/out2in.c | 102 ++++++++--------- src/plugins/snat/snat.h | 10 +- src/vlib/buffer.c | 6 +- src/vlib/buffer_funcs.h | 4 +- src/vlib/cli.c | 6 +- src/vlib/counter.h | 16 +-- src/vlib/error.c | 2 +- src/vlib/global_funcs.h | 2 +- src/vlib/main.c | 14 +-- src/vlib/main.h | 2 +- src/vlib/node.c | 2 +- src/vlib/node.h | 6 +- src/vlib/node_funcs.h | 8 +- src/vlib/threads.c | 69 ++++------- src/vlib/threads.h | 21 ++-- src/vlib/unix/cj.c | 7 +- src/vlib/unix/cj.h | 2 +- src/vlib/unix/main.c | 43 +++---- src/vnet/adj/adj_l2.c | 4 +- src/vnet/adj/adj_midchain.c | 8 +- src/vnet/adj/adj_nsh.c | 4 +- src/vnet/classify/vnet_classify.c | 16 +-- src/vnet/cop/ip4_whitelist.c | 8 +- src/vnet/cop/ip6_whitelist.c | 8 +- src/vnet/devices/af_packet/node.c | 20 ++-- src/vnet/devices/devices.c | 61 +++++----- src/vnet/devices/devices.h | 18 +-- src/vnet/devices/netmap/node.c | 24 ++-- src/vnet/devices/ssvm/node.c | 6 +- src/vnet/devices/virtio/vhost-user.c | 127 +++++++++++---------- src/vnet/dpo/lookup_dpo.c | 20 ++-- src/vnet/dpo/replicate_dpo.c | 12 +- src/vnet/ethernet/arp.c | 2 +- src/vnet/ethernet/interface.c | 7 +- src/vnet/ethernet/node.c | 14 +-- src/vnet/gre/node.c | 8 +- src/vnet/interface.h | 2 +- src/vnet/interface_output.c | 53 ++++----- src/vnet/ip/ip4_forward.c | 34 +++--- src/vnet/ip/ip4_input.c | 8 +- src/vnet/ip/ip6_forward.c | 24 ++-- src/vnet/ip/ip6_input.c | 8 +- src/vnet/ip/ip6_neighbor.c | 4 +- src/vnet/ipsec/esp.h | 8 +- src/vnet/ipsec/esp_decrypt.c | 13 ++- src/vnet/ipsec/esp_encrypt.c | 13 ++- src/vnet/ipsec/ikev2.c | 64 ++++++----- src/vnet/ipsec/ipsec.h | 12 +- src/vnet/ipsec/ipsec_if.c | 2 +- src/vnet/l2/l2_bvi.h | 2 +- src/vnet/l2/l2_input.c | 14 +-- src/vnet/l2/l2_output.c | 6 +- src/vnet/l2tp/decap.c | 2 +- src/vnet/l2tp/encap.c | 2 +- src/vnet/l2tp/l2tp.c | 6 +- src/vnet/lisp-gpe/decap.c | 16 +-- src/vnet/lldp/lldp_input.c | 2 +- src/vnet/map/ip4_map.c | 14 +-- src/vnet/map/ip4_map_t.c | 12 +- src/vnet/map/ip6_map.c | 19 +-- src/vnet/map/ip6_map_t.c | 12 +- src/vnet/mpls/mpls_input.c | 8 +- src/vnet/mpls/mpls_lookup.c | 20 ++-- src/vnet/mpls/mpls_output.c | 10 +- src/vnet/pg/input.c | 4 +- src/vnet/replication.c | 20 ++-- src/vnet/replication.h | 2 +- src/vnet/session/node.c | 2 +- src/vnet/sr/sr_localsid.c | 44 +++---- src/vnet/tcp/builtin_client.c | 2 +- src/vnet/tcp/tcp.c | 8 +- src/vnet/tcp/tcp_debug.h | 2 +- src/vnet/tcp/tcp_input.c | 10 +- src/vnet/tcp/tcp_output.c | 20 ++-- src/vnet/udp/udp_input.c | 2 +- src/vnet/unix/tapcli.c | 2 +- src/vnet/unix/tuntap.c | 4 +- src/vnet/vxlan-gpe/decap.c | 10 +- src/vnet/vxlan-gpe/encap.c | 12 +- src/vnet/vxlan/decap.c | 10 +- src/vnet/vxlan/encap.c | 12 +- src/vpp/stats/stats.c | 14 +-- src/vpp/stats/stats.h | 2 +- 109 files changed, 790 insertions(+), 791 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/examples/srv6-sample-localsid/node.c b/src/examples/srv6-sample-localsid/node.c index 7bae9cd7..e83e2352 100644 --- a/src/examples/srv6-sample-localsid/node.c +++ b/src/examples/srv6-sample-localsid/node.c @@ -114,7 +114,7 @@ srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_fram from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -168,7 +168,7 @@ srv6_localsid_sample_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_fram /* This increments the SRv6 per LocalSID counters.*/ vlib_increment_combined_counter (((next0 == SRV6_SAMPLE_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : &(sm->sr_ls_valid_counters)), - cpu_index, + thread_index, ls0 - sm->localsids, 1, vlib_buffer_length_in_chain (vm, b0)); diff --git a/src/plugins/dpdk/buffer.c b/src/plugins/dpdk/buffer.c index 2765c292..c80b3fa8 100644 --- a/src/plugins/dpdk/buffer.c +++ b/src/plugins/dpdk/buffer.c @@ -132,7 +132,7 @@ dpdk_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index) u32 merge_index; int i; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); f = vlib_buffer_get_free_list (vm, free_list_index); diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c index 50b26689..91661246 100644 --- a/src/plugins/dpdk/device/device.c +++ b/src/plugins/dpdk/device/device.c @@ -243,7 +243,7 @@ static_always_inline ASSERT (ring->tx_tail == 0); n_retry = 16; - queue_id = vm->cpu_index; + queue_id = vm->thread_index; do { @@ -266,7 +266,7 @@ static_always_inline { /* no wrap, transmit in one burst */ dpdk_device_hqos_per_worker_thread_t *hqos = - &xd->hqos_wt[vm->cpu_index]; + &xd->hqos_wt[vm->thread_index]; ASSERT (hqos->swq != NULL); @@ -332,7 +332,7 @@ dpdk_buffer_recycle (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t * b, u32 bi, struct rte_mbuf **mbp) { dpdk_main_t *dm = &dpdk_main; - u32 my_cpu = vm->cpu_index; + u32 my_cpu = vm->thread_index; struct rte_mbuf *mb_new; if (PREDICT_FALSE (b->flags & VLIB_BUFFER_RECYCLE) == 0) @@ -376,7 +376,7 @@ dpdk_interface_tx (vlib_main_t * vm, tx_ring_hdr_t *ring; u32 n_on_ring; - my_cpu = vm->cpu_index; + my_cpu = vm->thread_index; queue_id = my_cpu; diff --git a/src/plugins/dpdk/device/dpdk_priv.h b/src/plugins/dpdk/device/dpdk_priv.h index dd40ff48..52b4ca4b 100644 --- a/src/plugins/dpdk/device/dpdk_priv.h +++ b/src/plugins/dpdk/device/dpdk_priv.h @@ -79,7 +79,7 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) { vlib_simple_counter_main_t *cm; vnet_main_t *vnm = vnet_get_main (); - u32 my_cpu = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u64 rxerrors, last_rxerrors; /* only update counters for PMD interfaces */ @@ -96,7 +96,7 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) cm = vec_elt_at_index (vnm->interface_main.sw_if_counters, VNET_INTERFACE_COUNTER_RX_NO_BUF); - vlib_increment_simple_counter (cm, my_cpu, xd->vlib_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, xd->vlib_sw_if_index, xd->stats.rx_nombuf - xd->last_stats.rx_nombuf); } @@ -107,7 +107,7 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) cm = vec_elt_at_index (vnm->interface_main.sw_if_counters, VNET_INTERFACE_COUNTER_RX_MISS); - vlib_increment_simple_counter (cm, my_cpu, xd->vlib_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, xd->vlib_sw_if_index, xd->stats.imissed - xd->last_stats.imissed); } @@ -119,7 +119,7 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) cm = vec_elt_at_index (vnm->interface_main.sw_if_counters, VNET_INTERFACE_COUNTER_RX_ERROR); - vlib_increment_simple_counter (cm, my_cpu, xd->vlib_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, xd->vlib_sw_if_index, rxerrors - last_rxerrors); } diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index 538db6cb..7eaf8da7 100755 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -324,7 +324,7 @@ dpdk_port_setup (dpdk_main_t * dm, dpdk_device_t * xd) int rv; int j; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); if (xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP) { diff --git a/src/plugins/dpdk/device/node.c b/src/plugins/dpdk/device/node.c index e740fd18..b10e0fad 100644 --- a/src/plugins/dpdk/device/node.c +++ b/src/plugins/dpdk/device/node.c @@ -283,7 +283,7 @@ dpdk_buffer_init_from_template (void *d0, void *d1, void *d2, void *d3, */ static_always_inline u32 dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, - vlib_node_runtime_t * node, u32 cpu_index, u16 queue_id, + vlib_node_runtime_t * node, u32 thread_index, u16 queue_id, int maybe_multiseg) { u32 n_buffers; @@ -294,7 +294,7 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, uword n_rx_bytes = 0; u32 n_trace, trace_cnt __attribute__ ((unused)); vlib_buffer_free_list_t *fl; - vlib_buffer_t *bt = vec_elt_at_index (dm->buffer_templates, cpu_index); + vlib_buffer_t *bt = vec_elt_at_index (dm->buffer_templates, thread_index); if ((xd->flags & DPDK_DEVICE_FLAG_ADMIN_UP) == 0) return 0; @@ -306,7 +306,7 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, return 0; } - vec_reset_length (xd->d_trace_buffers[cpu_index]); + vec_reset_length (xd->d_trace_buffers[thread_index]); trace_cnt = n_trace = vlib_get_trace_count (vm, node); if (n_trace > 0) @@ -318,7 +318,7 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, { struct rte_mbuf *mb = xd->rx_vectors[queue_id][mb_index++]; vlib_buffer_t *b = vlib_buffer_from_rte_mbuf (mb); - vec_add1 (xd->d_trace_buffers[cpu_index], + vec_add1 (xd->d_trace_buffers[thread_index], vlib_get_buffer_index (vm, b)); } } @@ -546,20 +546,22 @@ dpdk_device_input (dpdk_main_t * dm, dpdk_device_t * xd, vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - if (PREDICT_FALSE (vec_len (xd->d_trace_buffers[cpu_index]) > 0)) + if (PREDICT_FALSE (vec_len (xd->d_trace_buffers[thread_index]) > 0)) { - dpdk_rx_trace (dm, node, xd, queue_id, xd->d_trace_buffers[cpu_index], - vec_len (xd->d_trace_buffers[cpu_index])); - vlib_set_trace_count (vm, node, n_trace - - vec_len (xd->d_trace_buffers[cpu_index])); + dpdk_rx_trace (dm, node, xd, queue_id, + xd->d_trace_buffers[thread_index], + vec_len (xd->d_trace_buffers[thread_index])); + vlib_set_trace_count (vm, node, + n_trace - + vec_len (xd->d_trace_buffers[thread_index])); } vlib_increment_combined_counter (vnet_get_main ()->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, xd->vlib_sw_if_index, mb_index, n_rx_bytes); + thread_index, xd->vlib_sw_if_index, mb_index, n_rx_bytes); - vnet_device_increment_rx_packets (cpu_index, mb_index); + vnet_device_increment_rx_packets (thread_index, mb_index); return mb_index; } @@ -630,19 +632,19 @@ dpdk_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * f) dpdk_device_t *xd; uword n_rx_packets = 0; dpdk_device_and_queue_t *dq; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); /* * Poll all devices on this cpu for input/interrupts. */ /* *INDENT-OFF* */ - vec_foreach (dq, dm->devices_by_cpu[cpu_index]) + vec_foreach (dq, dm->devices_by_cpu[thread_index]) { xd = vec_elt_at_index(dm->devices, dq->device); if (xd->flags & DPDK_DEVICE_FLAG_MAYBE_MULTISEG) - n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, dq->queue_id, /* maybe_multiseg */ 1); + n_rx_packets += dpdk_device_input (dm, xd, node, thread_index, dq->queue_id, /* maybe_multiseg */ 1); else - n_rx_packets += dpdk_device_input (dm, xd, node, cpu_index, dq->queue_id, /* maybe_multiseg */ 0); + n_rx_packets += dpdk_device_input (dm, xd, node, thread_index, dq->queue_id, /* maybe_multiseg */ 0); } /* *INDENT-ON* */ diff --git a/src/plugins/dpdk/hqos/hqos.c b/src/plugins/dpdk/hqos/hqos.c index a288fca7..8b251beb 100644 --- a/src/plugins/dpdk/hqos/hqos.c +++ b/src/plugins/dpdk/hqos/hqos.c @@ -397,7 +397,7 @@ static_always_inline void dpdk_hqos_thread_internal_hqos_dbg_bypass (vlib_main_t * vm) { dpdk_main_t *dm = &dpdk_main; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; u32 dev_pos; dev_pos = 0; @@ -405,12 +405,12 @@ dpdk_hqos_thread_internal_hqos_dbg_bypass (vlib_main_t * vm) { vlib_worker_thread_barrier_check (); - u32 n_devs = vec_len (dm->devices_by_hqos_cpu[cpu_index]); + u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); if (dev_pos >= n_devs) dev_pos = 0; dpdk_device_and_queue_t *dq = - vec_elt_at_index (dm->devices_by_hqos_cpu[cpu_index], dev_pos); + vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; @@ -479,7 +479,7 @@ static_always_inline void dpdk_hqos_thread_internal (vlib_main_t * vm) { dpdk_main_t *dm = &dpdk_main; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; u32 dev_pos; dev_pos = 0; @@ -487,7 +487,7 @@ dpdk_hqos_thread_internal (vlib_main_t * vm) { vlib_worker_thread_barrier_check (); - u32 n_devs = vec_len (dm->devices_by_hqos_cpu[cpu_index]); + u32 n_devs = vec_len (dm->devices_by_hqos_cpu[thread_index]); if (PREDICT_FALSE (n_devs == 0)) { dev_pos = 0; @@ -497,7 +497,7 @@ dpdk_hqos_thread_internal (vlib_main_t * vm) dev_pos = 0; dpdk_device_and_queue_t *dq = - vec_elt_at_index (dm->devices_by_hqos_cpu[cpu_index], dev_pos); + vec_elt_at_index (dm->devices_by_hqos_cpu[thread_index], dev_pos); dpdk_device_t *xd = vec_elt_at_index (dm->devices, dq->device); dpdk_device_hqos_per_hqos_thread_t *hqos = xd->hqos_ht; @@ -586,7 +586,7 @@ dpdk_hqos_thread (vlib_worker_thread_t * w) vm = vlib_get_main (); - ASSERT (vm->cpu_index == os_get_cpu_number ()); + ASSERT (vm->thread_index == vlib_get_thread_index ()); clib_time_init (&vm->clib_time); clib_mem_set_heap (w->thread_mheap); @@ -595,7 +595,7 @@ dpdk_hqos_thread (vlib_worker_thread_t * w) while (tm->worker_thread_release == 0) vlib_worker_thread_barrier_check (); - if (vec_len (dm->devices_by_hqos_cpu[vm->cpu_index]) == 0) + if (vec_len (dm->devices_by_hqos_cpu[vm->thread_index]) == 0) return clib_error ("current I/O TX thread does not have any devices assigned to it"); diff --git a/src/plugins/dpdk/ipsec/cli.c b/src/plugins/dpdk/ipsec/cli.c index cd0a6037..3ae8c9b8 100644 --- a/src/plugins/dpdk/ipsec/cli.c +++ b/src/plugins/dpdk/ipsec/cli.c @@ -42,8 +42,8 @@ dpdk_ipsec_show_mapping (vlib_main_t * vm, u16 detail_display) for (i = 0; i < tm->n_vlib_mains; i++) { uword key, data; - u32 cpu_index = vlib_mains[i]->cpu_index; - crypto_worker_main_t *cwm = &dcm->workers_main[cpu_index]; + u32 thread_index = vlib_mains[i]->thread_index; + crypto_worker_main_t *cwm = &dcm->workers_main[thread_index]; u8 *s = 0; if (skip_master) @@ -57,7 +57,7 @@ dpdk_ipsec_show_mapping (vlib_main_t * vm, u16 detail_display) i32 last_cdev = -1; crypto_qp_data_t *qpd; - s = format (s, "%u\t", cpu_index); + s = format (s, "%u\t", thread_index); /* *INDENT-OFF* */ vec_foreach (qpd, cwm->qp_data) @@ -95,7 +95,7 @@ dpdk_ipsec_show_mapping (vlib_main_t * vm, u16 detail_display) cap.sym.auth.algo = p_key->auth_algo; check_algo_is_supported (&cap, auth_str); vlib_cli_output (vm, "%u\t%10s\t%15s\t%3s\t%u\t%u\n", - vlib_mains[i]->cpu_index, cipher_str, auth_str, + vlib_mains[i]->thread_index, cipher_str, auth_str, p_key->is_outbound ? "out" : "in", cwm->qp_data[data].dev_id, cwm->qp_data[data].qp_id); diff --git a/src/plugins/dpdk/ipsec/crypto_node.c b/src/plugins/dpdk/ipsec/crypto_node.c index dc3452b2..a3c45902 100644 --- a/src/plugins/dpdk/ipsec/crypto_node.c +++ b/src/plugins/dpdk/ipsec/crypto_node.c @@ -171,9 +171,9 @@ static uword dpdk_crypto_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); dpdk_crypto_main_t *dcm = &dpdk_crypto_main; - crypto_worker_main_t *cwm = &dcm->workers_main[cpu_index]; + crypto_worker_main_t *cwm = &dcm->workers_main[thread_index]; crypto_qp_data_t *qpd; u32 n_deq = 0; diff --git a/src/plugins/dpdk/ipsec/esp.h b/src/plugins/dpdk/ipsec/esp.h index 320295b1..56f0c756 100644 --- a/src/plugins/dpdk/ipsec/esp.h +++ b/src/plugins/dpdk/ipsec/esp.h @@ -170,9 +170,9 @@ static_always_inline int create_sym_sess (ipsec_sa_t * sa, crypto_sa_session_t * sa_sess, u8 is_outbound) { - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); dpdk_crypto_main_t *dcm = &dpdk_crypto_main; - crypto_worker_main_t *cwm = &dcm->workers_main[cpu_index]; + crypto_worker_main_t *cwm = &dcm->workers_main[thread_index]; struct rte_crypto_sym_xform cipher_xform = { 0 }; struct rte_crypto_sym_xform auth_xform = { 0 }; struct rte_crypto_sym_xform *xfs; diff --git a/src/plugins/dpdk/ipsec/esp_decrypt.c b/src/plugins/dpdk/ipsec/esp_decrypt.c index 286e03f8..bab76e3b 100644 --- a/src/plugins/dpdk/ipsec/esp_decrypt.c +++ b/src/plugins/dpdk/ipsec/esp_decrypt.c @@ -88,7 +88,7 @@ dpdk_esp_decrypt_node_fn (vlib_main_t * vm, { u32 n_left_from, *from, *to_next, next_index; ipsec_main_t *im = &ipsec_main; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); dpdk_crypto_main_t * dcm = &dpdk_crypto_main; dpdk_esp_main_t * em = &dpdk_esp_main; u32 i; @@ -104,7 +104,7 @@ dpdk_esp_decrypt_node_fn (vlib_main_t * vm, return n_left_from; } - crypto_worker_main_t *cwm = vec_elt_at_index(dcm->workers_main, cpu_index); + crypto_worker_main_t *cwm = vec_elt_at_index(dcm->workers_main, thread_index); u32 n_qps = vec_len(cwm->qp_data); struct rte_crypto_op ** cops_to_enq[n_qps]; u32 n_cop_qp[n_qps], * bi_to_enq[n_qps]; diff --git a/src/plugins/dpdk/ipsec/esp_encrypt.c b/src/plugins/dpdk/ipsec/esp_encrypt.c index 5b03de73..f996d7df 100644 --- a/src/plugins/dpdk/ipsec/esp_encrypt.c +++ b/src/plugins/dpdk/ipsec/esp_encrypt.c @@ -93,7 +93,7 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm, { u32 n_left_from, *from, *to_next, next_index; ipsec_main_t *im = &ipsec_main; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); dpdk_crypto_main_t *dcm = &dpdk_crypto_main; dpdk_esp_main_t *em = &dpdk_esp_main; u32 i; @@ -111,7 +111,8 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm, return n_left_from; } - crypto_worker_main_t *cwm = vec_elt_at_index (dcm->workers_main, cpu_index); + crypto_worker_main_t *cwm = + vec_elt_at_index (dcm->workers_main, thread_index); u32 n_qps = vec_len (cwm->qp_data); struct rte_crypto_op **cops_to_enq[n_qps]; u32 n_cop_qp[n_qps], *bi_to_enq[n_qps]; diff --git a/src/plugins/dpdk/ipsec/ipsec.c b/src/plugins/dpdk/ipsec/ipsec.c index b0aaaaec..5d8f4fba 100644 --- a/src/plugins/dpdk/ipsec/ipsec.c +++ b/src/plugins/dpdk/ipsec/ipsec.c @@ -289,7 +289,7 @@ dpdk_ipsec_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (!map) { clib_warning ("unable to create hash table for worker %u", - vlib_mains[i]->cpu_index); + vlib_mains[i]->thread_index); goto error; } cwm->algo_qp_map = map; diff --git a/src/plugins/dpdk/ipsec/ipsec.h b/src/plugins/dpdk/ipsec/ipsec.h index 28bffc80..f0f793c0 100644 --- a/src/plugins/dpdk/ipsec/ipsec.h +++ b/src/plugins/dpdk/ipsec/ipsec.h @@ -95,8 +95,8 @@ static_always_inline void crypto_alloc_cops () { dpdk_crypto_main_t *dcm = &dpdk_crypto_main; - u32 cpu_index = os_get_cpu_number (); - crypto_worker_main_t *cwm = &dcm->workers_main[cpu_index]; + u32 thread_index = vlib_get_thread_index (); + crypto_worker_main_t *cwm = &dcm->workers_main[thread_index]; unsigned socket_id = rte_socket_id (); crypto_qp_data_t *qpd; diff --git a/src/plugins/dpdk/main.c b/src/plugins/dpdk/main.c index 7ee2a785..942b8b2d 100644 --- a/src/plugins/dpdk/main.c +++ b/src/plugins/dpdk/main.c @@ -39,7 +39,7 @@ rte_delay_us_override (unsigned us) * thread then do not intercept. (Must not be called from an * independent pthread). */ - if (os_get_cpu_number () == 0) + if (vlib_get_thread_index () == 0) { /* * We're in the vlib main thread or a vlib process. Make sure diff --git a/src/plugins/flowperpkt/l2_node.c b/src/plugins/flowperpkt/l2_node.c index 1c2f681e..fdaf81d1 100644 --- a/src/plugins/flowperpkt/l2_node.c +++ b/src/plugins/flowperpkt/l2_node.c @@ -102,7 +102,7 @@ add_to_flow_record_l2 (vlib_main_t * vm, u8 * src_mac, u8 * dst_mac, u16 ethertype, u64 timestamp, u16 length, int do_flush) { - u32 my_cpu_number = vm->cpu_index; + u32 my_cpu_number = vm->thread_index; flow_report_main_t *frm = &flow_report_main; ip4_header_t *ip; udp_header_t *udp; diff --git a/src/plugins/flowperpkt/node.c b/src/plugins/flowperpkt/node.c index f77f087d..0277682d 100644 --- a/src/plugins/flowperpkt/node.c +++ b/src/plugins/flowperpkt/node.c @@ -101,7 +101,7 @@ add_to_flow_record_ipv4 (vlib_main_t * vm, u32 src_address, u32 dst_address, u8 tos, u64 timestamp, u16 length, int do_flush) { - u32 my_cpu_number = vm->cpu_index; + u32 my_cpu_number = vm->thread_index; flow_report_main_t *frm = &flow_report_main; ip4_header_t *ip; udp_header_t *udp; diff --git a/src/plugins/ioam/export-common/ioam_export.h b/src/plugins/ioam/export-common/ioam_export.h index 2bf3fd54..9de0d13b 100644 --- a/src/plugins/ioam/export-common/ioam_export.h +++ b/src/plugins/ioam/export-common/ioam_export.h @@ -477,8 +477,8 @@ do { \ from = vlib_frame_vector_args (F); \ n_left_from = (F)->n_vectors; \ next_index = (N)->cached_next_index; \ - while (__sync_lock_test_and_set ((EM)->lockp[(VM)->cpu_index], 1)); \ - my_buf = ioam_export_get_my_buffer (EM, (VM)->cpu_index); \ + while (__sync_lock_test_and_set ((EM)->lockp[(VM)->thread_index], 1)); \ + my_buf = ioam_export_get_my_buffer (EM, (VM)->thread_index); \ my_buf->touched_at = vlib_time_now (VM); \ while (n_left_from > 0) \ { \ @@ -620,7 +620,7 @@ do { \ } \ vlib_node_increment_counter (VM, export_node.index, \ EXPORT_ERROR_RECORDED, pkts_recorded); \ - *(EM)->lockp[(VM)->cpu_index] = 0; \ + *(EM)->lockp[(VM)->thread_index] = 0; \ } while(0) #endif /* __included_ioam_export_h__ */ diff --git a/src/plugins/ioam/ip6/ioam_cache_tunnel_select_node.c b/src/plugins/ioam/ip6/ioam_cache_tunnel_select_node.c index a56dc040..0cf742c9 100644 --- a/src/plugins/ioam/ip6/ioam_cache_tunnel_select_node.c +++ b/src/plugins/ioam/ip6/ioam_cache_tunnel_select_node.c @@ -396,7 +396,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, clib_net_to_host_u32 (tcp0->seq_number) + 1, no_of_responses, now, - vm->cpu_index, &pool_index0)) + vm->thread_index, &pool_index0)) { cache_ts_added++; } @@ -419,7 +419,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, e2e = (ioam_e2e_cache_option_t *) ((u8 *) hbh0 + cm->rewrite_pool_index_offset); - e2e->pool_id = (u8) vm->cpu_index; + e2e->pool_id = (u8) vm->thread_index; e2e->pool_index = pool_index0; ioam_e2e_id_rewrite_handler ((ioam_e2e_id_option_t *) ((u8 *) e2e + @@ -455,7 +455,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, clib_net_to_host_u32 (tcp1->seq_number) + 1, no_of_responses, now, - vm->cpu_index, &pool_index1)) + vm->thread_index, &pool_index1)) { cache_ts_added++; } @@ -479,7 +479,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, e2e = (ioam_e2e_cache_option_t *) ((u8 *) hbh1 + cm->rewrite_pool_index_offset); - e2e->pool_id = (u8) vm->cpu_index; + e2e->pool_id = (u8) vm->thread_index; e2e->pool_index = pool_index1; ioam_e2e_id_rewrite_handler ((ioam_e2e_id_option_t *) ((u8 *) e2e + @@ -562,7 +562,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, clib_net_to_host_u32 (tcp0->seq_number) + 1, no_of_responses, now, - vm->cpu_index, &pool_index0)) + vm->thread_index, &pool_index0)) { cache_ts_added++; } @@ -585,7 +585,7 @@ ip6_reset_ts_hbh_node_fn (vlib_main_t * vm, e2e = (ioam_e2e_cache_option_t *) ((u8 *) hbh0 + cm->rewrite_pool_index_offset); - e2e->pool_id = (u8) vm->cpu_index; + e2e->pool_id = (u8) vm->thread_index; e2e->pool_index = pool_index0; ioam_e2e_id_rewrite_handler ((ioam_e2e_id_option_t *) ((u8 *) e2e + @@ -701,7 +701,7 @@ expired_cache_ts_timer_callback (u32 * expired_timers) ioam_cache_main_t *cm = &ioam_cache_main; int i; u32 pool_index; - u32 thread_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 count = 0; for (i = 0; i < vec_len (expired_timers); i++) @@ -724,7 +724,7 @@ ioam_cache_ts_timer_tick_node_fn (vlib_main_t * vm, vlib_frame_t * f) { ioam_cache_main_t *cm = &ioam_cache_main; - u32 my_thread_index = os_get_cpu_number (); + u32 my_thread_index = vlib_get_thread_index (); struct timespec ts, tsrem; tw_timer_expire_timers_16t_2w_512sl (&cm->timer_wheels[my_thread_index], diff --git a/src/plugins/ixge/ixge.c b/src/plugins/ixge/ixge.c index f3c5cc09..08f5b692 100644 --- a/src/plugins/ixge/ixge.c +++ b/src/plugins/ixge/ixge.c @@ -1887,7 +1887,7 @@ done: vlib_increment_combined_counter (vnet_main. interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - 0 /* cpu_index */ , + 0 /* thread_index */ , xd->vlib_sw_if_index, n_packets, dq->rx.n_bytes); diff --git a/src/plugins/lb/lb.c b/src/plugins/lb/lb.c index add81236..addc2a42 100644 --- a/src/plugins/lb/lb.c +++ b/src/plugins/lb/lb.c @@ -63,11 +63,11 @@ u8 *format_lb_main (u8 * s, va_list * args) s = format(s, " #vips: %u\n", pool_elts(lbm->vips)); s = format(s, " #ass: %u\n", pool_elts(lbm->ass) - 1); - u32 cpu_index; - for(cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++ ) { - lb_hash_t *h = lbm->per_cpu[cpu_index].sticky_ht; + u32 thread_index; + for(thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++ ) { + lb_hash_t *h = lbm->per_cpu[thread_index].sticky_ht; if (h) { - s = format(s, "core %d\n", cpu_index); + s = format(s, "core %d\n", thread_index); s = format(s, " timeout: %ds\n", h->timeout); s = format(s, " usage: %d / %d\n", lb_hash_elts(h, lb_hash_time_now(vlib_get_main())), lb_hash_size(h)); } diff --git a/src/plugins/lb/node.c b/src/plugins/lb/node.c index 8b763c53..3171148b 100644 --- a/src/plugins/lb/node.c +++ b/src/plugins/lb/node.c @@ -60,10 +60,10 @@ format_lb_trace (u8 * s, va_list * args) return s; } -lb_hash_t *lb_get_sticky_table(u32 cpu_index) +lb_hash_t *lb_get_sticky_table(u32 thread_index) { lb_main_t *lbm = &lb_main; - lb_hash_t *sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; + lb_hash_t *sticky_ht = lbm->per_cpu[thread_index].sticky_ht; //Check if size changed if (PREDICT_FALSE(sticky_ht && (lbm->per_cpu_sticky_buckets != lb_hash_nbuckets(sticky_ht)))) { @@ -71,8 +71,8 @@ lb_hash_t *lb_get_sticky_table(u32 cpu_index) lb_hash_bucket_t *b; u32 i; lb_hash_foreach_entry(sticky_ht, b, i) { - vlib_refcount_add(&lbm->as_refcount, cpu_index, b->value[i], -1); - vlib_refcount_add(&lbm->as_refcount, cpu_index, 0, 1); + vlib_refcount_add(&lbm->as_refcount, thread_index, b->value[i], -1); + vlib_refcount_add(&lbm->as_refcount, thread_index, 0, 1); } lb_hash_free(sticky_ht); @@ -81,8 +81,8 @@ lb_hash_t *lb_get_sticky_table(u32 cpu_index) //Create if necessary if (PREDICT_FALSE(sticky_ht == NULL)) { - lbm->per_cpu[cpu_index].sticky_ht = lb_hash_alloc(lbm->per_cpu_sticky_buckets, lbm->flow_timeout); - sticky_ht = lbm->per_cpu[cpu_index].sticky_ht; + lbm->per_cpu[thread_index].sticky_ht = lb_hash_alloc(lbm->per_cpu_sticky_buckets, lbm->flow_timeout); + sticky_ht = lbm->per_cpu[thread_index].sticky_ht; clib_warning("Regenerated sticky table %p", sticky_ht); } @@ -153,10 +153,10 @@ lb_node_fn (vlib_main_t * vm, { lb_main_t *lbm = &lb_main; u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u32 lb_time = lb_hash_time_now(vm); - lb_hash_t *sticky_ht = lb_get_sticky_table(cpu_index); + lb_hash_t *sticky_ht = lb_get_sticky_table(thread_index); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; @@ -240,9 +240,9 @@ lb_node_fn (vlib_main_t * vm, //Configuration may be changed, vectors resized, etc... //Dereference previously used - vlib_refcount_add(&lbm->as_refcount, cpu_index, + vlib_refcount_add(&lbm->as_refcount, thread_index, lb_hash_available_value(sticky_ht, hash0, available_index0), -1); - vlib_refcount_add(&lbm->as_refcount, cpu_index, + vlib_refcount_add(&lbm->as_refcount, thread_index, asindex0, 1); //Add sticky entry @@ -260,7 +260,7 @@ lb_node_fn (vlib_main_t * vm, } vlib_increment_simple_counter(&lbm->vip_counters[counter], - cpu_index, + thread_index, vnet_buffer (p0)->ip.adj_index[VLIB_TX], 1); diff --git a/src/plugins/lb/refcount.c b/src/plugins/lb/refcount.c index 22415c88..6f01ab5a 100644 --- a/src/plugins/lb/refcount.c +++ b/src/plugins/lb/refcount.c @@ -31,10 +31,10 @@ u64 vlib_refcount_get(vlib_refcount_t *r, u32 index) { u64 count = 0; vlib_thread_main_t *tm = vlib_get_thread_main (); - u32 cpu_index; - for (cpu_index = 0; cpu_index < tm->n_vlib_mains; cpu_index++) { - if (r->per_cpu[cpu_index].length > index) - count += r->per_cpu[cpu_index].counters[index]; + u32 thread_index; + for (thread_index = 0; thread_index < tm->n_vlib_mains; thread_index++) { + if (r->per_cpu[thread_index].length > index) + count += r->per_cpu[thread_index].counters[index]; } return count; } diff --git a/src/plugins/lb/refcount.h b/src/plugins/lb/refcount.h index 8c26e7be..dcfcb3fe 100644 --- a/src/plugins/lb/refcount.h +++ b/src/plugins/lb/refcount.h @@ -45,9 +45,9 @@ typedef struct { void __vlib_refcount_resize(vlib_refcount_per_cpu_t *per_cpu, u32 size); static_always_inline -void vlib_refcount_add(vlib_refcount_t *r, u32 cpu_index, u32 counter_index, i32 v) +void vlib_refcount_add(vlib_refcount_t *r, u32 thread_index, u32 counter_index, i32 v) { - vlib_refcount_per_cpu_t *per_cpu = &r->per_cpu[cpu_index]; + vlib_refcount_per_cpu_t *per_cpu = &r->per_cpu[thread_index]; if (PREDICT_FALSE(counter_index >= per_cpu->length)) __vlib_refcount_resize(per_cpu, clib_max(counter_index + 16, per_cpu->length * 2)); diff --git a/src/plugins/memif/node.c b/src/plugins/memif/node.c index 659d5dfb..cee1f3d1 100644 --- a/src/plugins/memif/node.c +++ b/src/plugins/memif/node.c @@ -94,7 +94,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, u32 n_rx_bytes = 0; u32 *to_next = 0; u32 n_free_bufs; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 bi0, bi1; vlib_buffer_t *b0, *b1; u16 ring_size = 1 << mif->log2_ring_size; @@ -105,14 +105,15 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (mif->per_interface_next_index != ~0) next_index = mif->per_interface_next_index; - n_free_bufs = vec_len (nm->rx_buffers[cpu_index]); + n_free_bufs = vec_len (nm->rx_buffers[thread_index]); if (PREDICT_FALSE (n_free_bufs < ring_size)) { - vec_validate (nm->rx_buffers[cpu_index], ring_size + n_free_bufs - 1); + vec_validate (nm->rx_buffers[thread_index], + ring_size + n_free_bufs - 1); n_free_bufs += - vlib_buffer_alloc (vm, &nm->rx_buffers[cpu_index][n_free_bufs], + vlib_buffer_alloc (vm, &nm->rx_buffers[thread_index][n_free_bufs], ring_size); - _vec_len (nm->rx_buffers[cpu_index]) = n_free_bufs; + _vec_len (nm->rx_buffers[thread_index]) = n_free_bufs; } head = ring->head; @@ -158,15 +159,15 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, CLIB_CACHE_LINE_BYTES, LOAD); } /* get empty buffer */ - u32 last_buf = vec_len (nm->rx_buffers[cpu_index]) - 1; - bi0 = nm->rx_buffers[cpu_index][last_buf]; - bi1 = nm->rx_buffers[cpu_index][last_buf - 1]; - _vec_len (nm->rx_buffers[cpu_index]) -= 2; + u32 last_buf = vec_len (nm->rx_buffers[thread_index]) - 1; + bi0 = nm->rx_buffers[thread_index][last_buf]; + bi1 = nm->rx_buffers[thread_index][last_buf - 1]; + _vec_len (nm->rx_buffers[thread_index]) -= 2; if (last_buf > 4) { - memif_prefetch (vm, nm->rx_buffers[cpu_index][last_buf - 2]); - memif_prefetch (vm, nm->rx_buffers[cpu_index][last_buf - 3]); + memif_prefetch (vm, nm->rx_buffers[thread_index][last_buf - 2]); + memif_prefetch (vm, nm->rx_buffers[thread_index][last_buf - 3]); } /* enqueue buffer */ @@ -256,9 +257,9 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, while (num_slots && n_left_to_next) { /* get empty buffer */ - u32 last_buf = vec_len (nm->rx_buffers[cpu_index]) - 1; - bi0 = nm->rx_buffers[cpu_index][last_buf]; - _vec_len (nm->rx_buffers[cpu_index]) = last_buf; + u32 last_buf = vec_len (nm->rx_buffers[thread_index]) - 1; + bi0 = nm->rx_buffers[thread_index][last_buf]; + _vec_len (nm->rx_buffers[thread_index]) = last_buf; /* enqueue buffer */ to_next[0] = bi0; @@ -315,7 +316,7 @@ memif_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, ring->tail = head; vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters - + VNET_INTERFACE_COUNTER_RX, cpu_index, + + VNET_INTERFACE_COUNTER_RX, thread_index, mif->hw_if_index, n_rx_packets, n_rx_bytes); @@ -327,7 +328,7 @@ memif_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { u32 n_rx_packets = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); memif_main_t *nm = &memif_main; memif_if_t *mif; @@ -337,7 +338,7 @@ memif_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, if (mif->flags & MEMIF_IF_FLAG_ADMIN_UP && mif->flags & MEMIF_IF_FLAG_CONNECTED && (mif->if_index % nm->input_cpu_count) == - (cpu_index - nm->input_cpu_first_index)) + (thread_index - nm->input_cpu_first_index)) { if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE) n_rx_packets += diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c index b4961365..e5ee965f 100644 --- a/src/plugins/snat/in2out.c +++ b/src/plugins/snat/in2out.c @@ -212,7 +212,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, snat_session_t ** sessionp, vlib_node_runtime_t * node, u32 next0, - u32 cpu_index) + u32 thread_index) { snat_user_t *u; snat_user_key_t user_key; @@ -246,27 +246,27 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) { /* no, make a new one */ - pool_get (sm->per_thread_data[cpu_index].users, u); + pool_get (sm->per_thread_data[thread_index].users, u); memset (u, 0, sizeof (*u)); u->addr = ip0->src_address; u->fib_index = rx_fib_index0; - pool_get (sm->per_thread_data[cpu_index].list_pool, per_user_list_head_elt); + pool_get (sm->per_thread_data[thread_index].list_pool, per_user_list_head_elt); u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[cpu_index].list_pool; + sm->per_thread_data[thread_index].list_pool; - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_init (sm->per_thread_data[thread_index].list_pool, u->sessions_per_user_list_head_index); - kv0.value = u - sm->per_thread_data[cpu_index].users; + kv0.value = u - sm->per_thread_data[thread_index].users; /* add user */ clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); } else { - u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, + u = pool_elt_at_index (sm->per_thread_data[thread_index].users, value0.value); } @@ -276,25 +276,25 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, /* Remove the oldest dynamic translation */ do { oldest_per_user_translation_list_index = - clib_dlist_remove_head (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove_head (sm->per_thread_data[thread_index].list_pool, u->sessions_per_user_list_head_index); ASSERT (oldest_per_user_translation_list_index != ~0); /* add it back to the end of the LRU list */ - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, u->sessions_per_user_list_head_index, oldest_per_user_translation_list_index); /* Get the list element */ oldest_per_user_translation_list_elt = - pool_elt_at_index (sm->per_thread_data[cpu_index].list_pool, + pool_elt_at_index (sm->per_thread_data[thread_index].list_pool, oldest_per_user_translation_list_index); /* Get the session index from the list element */ session_index = oldest_per_user_translation_list_elt->value; /* Get the session */ - s = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, session_index); } while (snat_is_session_static (s)); @@ -346,7 +346,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, } /* Create a new session */ - pool_get (sm->per_thread_data[cpu_index].sessions, s); + pool_get (sm->per_thread_data[thread_index].sessions, s); memset (s, 0, sizeof (*s)); s->outside_address_index = address_index; @@ -362,22 +362,22 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, } /* Create list elts */ - pool_get (sm->per_thread_data[cpu_index].list_pool, + pool_get (sm->per_thread_data[thread_index].list_pool, per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_init (sm->per_thread_data[thread_index].list_pool, per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); + sm->per_thread_data[thread_index].list_pool); per_user_translation_list_elt->value = - s - sm->per_thread_data[cpu_index].sessions; + s - sm->per_thread_data[thread_index].sessions; s->per_user_index = per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool; + sm->per_thread_data[thread_index].list_pool; s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s->per_user_list_head_index, per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); + sm->per_thread_data[thread_index].list_pool); } s->in2out = *key0; @@ -388,12 +388,12 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, /* Add to translation hashes */ kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; + kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) clib_warning ("in2out key add failed"); kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; + kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) clib_warning ("out2in key add failed"); @@ -403,7 +403,7 @@ static u32 slow_path (snat_main_t *sm, vlib_buffer_t *b0, worker_by_out_key.port = s->out2in.port; worker_by_out_key.fib_index = s->out2in.fib_index; kv0.key = worker_by_out_key.as_u64; - kv0.value = cpu_index; + kv0.value = thread_index; clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv0, 1); /* log NAT event */ @@ -465,7 +465,7 @@ snat_in2out_error_t icmp_get_key(icmp46_header_t *icmp0, * * @param[in,out] sm SNAT main * @param[in,out] node SNAT node runtime - * @param[in] cpu_index CPU index + * @param[in] thread_index thread index * @param[in,out] b0 buffer containing packet to be translated * @param[out] p_key address and port before NAT translation * @param[out] p_value address and port after NAT translation @@ -473,7 +473,7 @@ snat_in2out_error_t icmp_get_key(icmp46_header_t *icmp0, * @param d optional parameter */ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d) @@ -524,13 +524,13 @@ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, } next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); + &s0, node, next0, thread_index); if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) goto out; } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); out: @@ -548,7 +548,7 @@ out: * * @param[in] sm SNAT main * @param[in,out] node SNAT node runtime - * @param[in] cpu_index CPU index + * @param[in] thread_index thread index * @param[in,out] b0 buffer containing packet to be translated * @param[out] p_key address and port before NAT translation * @param[out] p_value address and port after NAT translation @@ -556,7 +556,7 @@ out: * @param d optional parameter */ u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d) @@ -624,7 +624,7 @@ static inline u32 icmp_in2out (snat_main_t *sm, u32 rx_fib_index0, vlib_node_runtime_t * node, u32 next0, - u32 cpu_index, + u32 thread_index, void *d) { snat_session_key_t key0, sm0; @@ -641,7 +641,7 @@ static inline u32 icmp_in2out (snat_main_t *sm, echo0 = (icmp_echo_header_t *)(icmp0+1); - next0_tmp = sm->icmp_match_in2out_cb(sm, node, cpu_index, b0, + next0_tmp = sm->icmp_match_in2out_cb(sm, node, thread_index, b0, &key0, &sm0, &dont_translate, d); if (next0_tmp != ~0) next0 = next0_tmp; @@ -847,11 +847,11 @@ static inline u32 icmp_in2out_slow_path (snat_main_t *sm, vlib_node_runtime_t * node, u32 next0, f64 now, - u32 cpu_index, + u32 thread_index, snat_session_t ** p_s0) { next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, cpu_index, p_s0); + next0, thread_index, p_s0); snat_session_t * s0 = *p_s0; if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0)) { @@ -862,9 +862,9 @@ static inline u32 icmp_in2out_slow_path (snat_main_t *sm, /* Per-user LRU list maintenance for dynamic translations */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -884,7 +884,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, snat_runtime_t * rt = (snat_runtime_t *)node->runtime_data; f64 now = vlib_time_now (vm); u32 stats_node_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); stats_node_index = is_slow_path ? snat_in2out_slowpath_node.index : snat_in2out_node.index; @@ -977,7 +977,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { next0 = icmp_in2out_slow_path (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, - node, next0, now, cpu_index, &s0); + node, next0, now, thread_index, &s0); goto trace00; } } @@ -1006,7 +1006,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, goto trace00; next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); + &s0, node, next0, thread_index); if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) goto trace00; } @@ -1017,7 +1017,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); old_addr0 = ip0->src_address.as_u32; @@ -1063,9 +1063,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -1081,7 +1081,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, t->next_index = next0; t->session_index = ~0; if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s0 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; @@ -1117,7 +1117,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { next1 = icmp_in2out_slow_path (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, cpu_index, &s1); + next1, now, thread_index, &s1); goto trace01; } } @@ -1146,7 +1146,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, goto trace01; next1 = slow_path (sm, b1, ip1, rx_fib_index1, &key1, - &s1, node, next1, cpu_index); + &s1, node, next1, thread_index); if (PREDICT_FALSE (next1 == SNAT_IN2OUT_NEXT_DROP)) goto trace01; } @@ -1157,7 +1157,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } } else - s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value1.value); old_addr1 = ip1->src_address.as_u32; @@ -1203,9 +1203,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s1)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s1->per_user_list_head_index, s1->per_user_index); } @@ -1220,7 +1220,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, t->next_index = next1; t->session_index = ~0; if (s1) - t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s1 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next1 != SNAT_IN2OUT_NEXT_DROP; @@ -1292,7 +1292,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, { next0 = icmp_in2out_slow_path (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index, &s0); + next0, now, thread_index, &s0); goto trace0; } } @@ -1321,7 +1321,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, goto trace0; next0 = slow_path (sm, b0, ip0, rx_fib_index0, &key0, - &s0, node, next0, cpu_index); + &s0, node, next0, thread_index); if (PREDICT_FALSE (next0 == SNAT_IN2OUT_NEXT_DROP)) goto trace0; @@ -1333,7 +1333,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); old_addr0 = ip0->src_address.as_u32; @@ -1379,9 +1379,9 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -1397,7 +1397,7 @@ snat_in2out_node_fn_inline (vlib_main_t * vm, t->next_index = next0; t->session_index = ~0; if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s0 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next0 != SNAT_IN2OUT_NEXT_DROP; @@ -2010,7 +2010,7 @@ snat_in2out_worker_handoff_fn (vlib_main_t * vm, u32 n_left_to_next_worker = 0, *to_next_worker = 0; u32 next_worker_index = 0; u32 current_worker_index = ~0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); ASSERT (vec_len (sm->workers)); @@ -2048,7 +2048,7 @@ snat_in2out_worker_handoff_fn (vlib_main_t * vm, next_worker_index = sm->worker_in2out_cb(ip0, rx_fib_index0); - if (PREDICT_FALSE (next_worker_index != cpu_index)) + if (PREDICT_FALSE (next_worker_index != thread_index)) { do_handoff = 1; diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c index 656e42db..5d308d78 100644 --- a/src/plugins/snat/out2in.c +++ b/src/plugins/snat/out2in.c @@ -129,7 +129,7 @@ create_session_for_static_mapping (snat_main_t *sm, snat_session_key_t in2out, snat_session_key_t out2in, vlib_node_runtime_t * node, - u32 cpu_index) + u32 thread_index) { snat_user_t *u; snat_user_key_t user_key; @@ -146,36 +146,36 @@ create_session_for_static_mapping (snat_main_t *sm, if (clib_bihash_search_8_8 (&sm->user_hash, &kv0, &value0)) { /* no, make a new one */ - pool_get (sm->per_thread_data[cpu_index].users, u); + pool_get (sm->per_thread_data[thread_index].users, u); memset (u, 0, sizeof (*u)); u->addr = in2out.addr; u->fib_index = in2out.fib_index; - pool_get (sm->per_thread_data[cpu_index].list_pool, + pool_get (sm->per_thread_data[thread_index].list_pool, per_user_list_head_elt); u->sessions_per_user_list_head_index = per_user_list_head_elt - - sm->per_thread_data[cpu_index].list_pool; + sm->per_thread_data[thread_index].list_pool; - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_init (sm->per_thread_data[thread_index].list_pool, u->sessions_per_user_list_head_index); - kv0.value = u - sm->per_thread_data[cpu_index].users; + kv0.value = u - sm->per_thread_data[thread_index].users; /* add user */ clib_bihash_add_del_8_8 (&sm->user_hash, &kv0, 1 /* is_add */); /* add non-traslated packets worker lookup */ - kv0.value = cpu_index; + kv0.value = thread_index; clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv0, 1); } else { - u = pool_elt_at_index (sm->per_thread_data[cpu_index].users, + u = pool_elt_at_index (sm->per_thread_data[thread_index].users, value0.value); } - pool_get (sm->per_thread_data[cpu_index].sessions, s); + pool_get (sm->per_thread_data[thread_index].sessions, s); memset (s, 0, sizeof (*s)); s->outside_address_index = ~0; @@ -183,22 +183,22 @@ create_session_for_static_mapping (snat_main_t *sm, u->nstaticsessions++; /* Create list elts */ - pool_get (sm->per_thread_data[cpu_index].list_pool, + pool_get (sm->per_thread_data[thread_index].list_pool, per_user_translation_list_elt); - clib_dlist_init (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_init (sm->per_thread_data[thread_index].list_pool, per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); + sm->per_thread_data[thread_index].list_pool); per_user_translation_list_elt->value = - s - sm->per_thread_data[cpu_index].sessions; + s - sm->per_thread_data[thread_index].sessions; s->per_user_index = - per_user_translation_list_elt - sm->per_thread_data[cpu_index].list_pool; + per_user_translation_list_elt - sm->per_thread_data[thread_index].list_pool; s->per_user_list_head_index = u->sessions_per_user_list_head_index; - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s->per_user_list_head_index, per_user_translation_list_elt - - sm->per_thread_data[cpu_index].list_pool); + sm->per_thread_data[thread_index].list_pool); s->in2out = in2out; s->out2in = out2in; @@ -206,12 +206,12 @@ create_session_for_static_mapping (snat_main_t *sm, /* Add to translation hashes */ kv0.key = s->in2out.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; + kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->in2out, &kv0, 1 /* is_add */)) clib_warning ("in2out key add failed"); kv0.key = s->out2in.as_u64; - kv0.value = s - sm->per_thread_data[cpu_index].sessions; + kv0.value = s - sm->per_thread_data[thread_index].sessions; if (clib_bihash_add_del_8_8 (&sm->out2in, &kv0, 1 /* is_add */)) clib_warning ("out2in key add failed"); @@ -298,7 +298,7 @@ is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, * * @param[in,out] sm SNAT main * @param[in,out] node SNAT node runtime - * @param[in] cpu_index CPU index + * @param[in] thread_index thread index * @param[in,out] b0 buffer containing packet to be translated * @param[out] p_key address and port before NAT translation * @param[out] p_value address and port after NAT translation @@ -306,7 +306,7 @@ is_interface_addr(snat_main_t *sm, vlib_node_runtime_t *node, u32 sw_if_index0, * @param d optional parameter */ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d) @@ -366,7 +366,7 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, /* Create session initiated by host from external network */ s0 = create_session_for_static_mapping(sm, b0, sm0, key0, - node, cpu_index); + node, thread_index); if (!s0) { @@ -375,7 +375,7 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, } } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); out: @@ -393,7 +393,7 @@ out: * * @param[in] sm SNAT main * @param[in,out] node SNAT node runtime - * @param[in] cpu_index CPU index + * @param[in] thread_index thread index * @param[in,out] b0 buffer containing packet to be translated * @param[out] p_key address and port before NAT translation * @param[out] p_value address and port after NAT translation @@ -401,7 +401,7 @@ out: * @param d optional parameter */ u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d) @@ -460,7 +460,7 @@ static inline u32 icmp_out2in (snat_main_t *sm, u32 rx_fib_index0, vlib_node_runtime_t * node, u32 next0, - u32 cpu_index, + u32 thread_index, void *d) { snat_session_key_t key0, sm0; @@ -477,7 +477,7 @@ static inline u32 icmp_out2in (snat_main_t *sm, echo0 = (icmp_echo_header_t *)(icmp0+1); - next0_tmp = sm->icmp_match_out2in_cb(sm, node, cpu_index, b0, + next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, &key0, &sm0, &dont_translate, d); if (next0_tmp != ~0) next0 = next0_tmp; @@ -589,11 +589,11 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, u32 rx_fib_index0, vlib_node_runtime_t * node, u32 next0, f64 now, - u32 cpu_index, + u32 thread_index, snat_session_t ** p_s0) { next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, cpu_index, p_s0); + next0, thread_index, p_s0); snat_session_t * s0 = *p_s0; if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0)) { @@ -604,9 +604,9 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -624,7 +624,7 @@ snat_out2in_node_fn (vlib_main_t * vm, u32 pkts_processed = 0; snat_main_t * sm = &snat_main; f64 now = vlib_time_now (vm); - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -712,7 +712,7 @@ snat_out2in_node_fn (vlib_main_t * vm, { next0 = icmp_out2in_slow_path (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index, &s0); + next0, now, thread_index, &s0); goto trace0; } @@ -743,7 +743,7 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Create session initiated by host from external network */ s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - cpu_index); + thread_index); if (!s0) { b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; @@ -752,7 +752,7 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); old_addr0 = ip0->dst_address.as_u32; @@ -796,9 +796,9 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -813,7 +813,7 @@ snat_out2in_node_fn (vlib_main_t * vm, t->next_index = next0; t->session_index = ~0; if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s0 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; @@ -847,7 +847,7 @@ snat_out2in_node_fn (vlib_main_t * vm, { next1 = icmp_out2in_slow_path (sm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, - next1, now, cpu_index, &s1); + next1, now, thread_index, &s1); goto trace1; } @@ -878,7 +878,7 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Create session initiated by host from external network */ s1 = create_session_for_static_mapping(sm, b1, sm1, key1, node, - cpu_index); + thread_index); if (!s1) { b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; @@ -887,7 +887,7 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s1 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s1 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value1.value); old_addr1 = ip1->dst_address.as_u32; @@ -931,9 +931,9 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s1)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s1->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s1->per_user_list_head_index, s1->per_user_index); } @@ -948,7 +948,7 @@ snat_out2in_node_fn (vlib_main_t * vm, t->next_index = next1; t->session_index = ~0; if (s1) - t->session_index = s1 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s1 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next1 != SNAT_OUT2IN_NEXT_DROP; @@ -1016,7 +1016,7 @@ snat_out2in_node_fn (vlib_main_t * vm, { next0 = icmp_out2in_slow_path (sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, now, cpu_index, &s0); + next0, now, thread_index, &s0); goto trace00; } @@ -1048,7 +1048,7 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Create session initiated by host from external network */ s0 = create_session_for_static_mapping(sm, b0, sm0, key0, node, - cpu_index); + thread_index); if (!s0) { b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; @@ -1057,7 +1057,7 @@ snat_out2in_node_fn (vlib_main_t * vm, } } else - s0 = pool_elt_at_index (sm->per_thread_data[cpu_index].sessions, + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, value0.value); old_addr0 = ip0->dst_address.as_u32; @@ -1101,9 +1101,9 @@ snat_out2in_node_fn (vlib_main_t * vm, /* Per-user LRU list maintenance for dynamic translation */ if (!snat_is_session_static (s0)) { - clib_dlist_remove (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_remove (sm->per_thread_data[thread_index].list_pool, s0->per_user_index); - clib_dlist_addtail (sm->per_thread_data[cpu_index].list_pool, + clib_dlist_addtail (sm->per_thread_data[thread_index].list_pool, s0->per_user_list_head_index, s0->per_user_index); } @@ -1118,7 +1118,7 @@ snat_out2in_node_fn (vlib_main_t * vm, t->next_index = next0; t->session_index = ~0; if (s0) - t->session_index = s0 - sm->per_thread_data[cpu_index].sessions; + t->session_index = s0 - sm->per_thread_data[thread_index].sessions; } pkts_processed += next0 != SNAT_OUT2IN_NEXT_DROP; @@ -1599,7 +1599,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, u32 n_left_to_next_worker = 0, *to_next_worker = 0; u32 next_worker_index = 0; u32 current_worker_index = ~0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); ASSERT (vec_len (sm->workers)); @@ -1637,7 +1637,7 @@ snat_out2in_worker_handoff_fn (vlib_main_t * vm, next_worker_index = sm->worker_out2in_cb(ip0, rx_fib_index0); - if (PREDICT_FALSE (next_worker_index != cpu_index)) + if (PREDICT_FALSE (next_worker_index != thread_index)) { do_handoff = 1; diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index 017825c0..f4e1c5c0 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -221,7 +221,7 @@ struct snat_main_s; typedef u32 snat_icmp_match_function_t (struct snat_main_s *sm, vlib_node_runtime_t *node, - u32 cpu_index, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, @@ -402,22 +402,22 @@ typedef struct { } tcp_udp_header_t; u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d); u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d); u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d); u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, - u32 cpu_index, vlib_buffer_t *b0, + u32 thread_index, vlib_buffer_t *b0, snat_session_key_t *p_key, snat_session_key_t *p_value, u8 *p_dont_translate, void *d); diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c index a517a597..be3b41ef 100644 --- a/src/vlib/buffer.c +++ b/src/vlib/buffer.c @@ -299,7 +299,7 @@ vlib_buffer_validate_alloc_free (vlib_main_t * vm, if (CLIB_DEBUG == 0) return; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); /* smp disaster check */ if (vec_len (vlib_mains) > 1) @@ -355,7 +355,7 @@ vlib_buffer_create_free_list_helper (vlib_main_t * vm, vlib_buffer_free_list_t *f; int i; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); if (!is_default && pool_elts (bm->buffer_free_list_pool) == 0) { @@ -474,7 +474,7 @@ vlib_buffer_delete_free_list_internal (vlib_main_t * vm, u32 free_list_index) u32 merge_index; int i; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); f = vlib_buffer_get_free_list (vm, free_list_index); diff --git a/src/vlib/buffer_funcs.h b/src/vlib/buffer_funcs.h index 394c336a..328660a3 100644 --- a/src/vlib/buffer_funcs.h +++ b/src/vlib/buffer_funcs.h @@ -209,7 +209,7 @@ always_inline vlib_buffer_known_state_t vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index) { vlib_buffer_main_t *bm = vm->buffer_main; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); uword *p = hash_get (bm->buffer_known_hash, buffer_index); return p ? p[0] : VLIB_BUFFER_UNKNOWN; @@ -221,7 +221,7 @@ vlib_buffer_set_known_state (vlib_main_t * vm, vlib_buffer_known_state_t state) { vlib_buffer_main_t *bm = vm->buffer_main; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); hash_set (bm->buffer_known_hash, buffer_index, state); } diff --git a/src/vlib/cli.c b/src/vlib/cli.c index f853f655..3cc95076 100644 --- a/src/vlib/cli.c +++ b/src/vlib/cli.c @@ -709,7 +709,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input, { /* *INDENT-OFF* */ foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; + heap = clib_per_cpu_mheaps[this_vlib_main->thread_index]; mheap = mheap_header(heap); mheap->flags |= MHEAP_FLAG_VALIDATE; // Turn off small object cache because it delays detection of errors @@ -722,7 +722,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input, { /* *INDENT-OFF* */ foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; + heap = clib_per_cpu_mheaps[this_vlib_main->thread_index]; mheap = mheap_header(heap); mheap->flags &= ~MHEAP_FLAG_VALIDATE; mheap->flags |= MHEAP_FLAG_SMALL_OBJECT_CACHE; @@ -733,7 +733,7 @@ test_heap_validate (vlib_main_t * vm, unformat_input_t * input, { /* *INDENT-OFF* */ foreach_vlib_main({ - heap = clib_per_cpu_mheaps[this_vlib_main->cpu_index]; + heap = clib_per_cpu_mheaps[this_vlib_main->thread_index]; mheap = mheap_header(heap); mheap_validate(heap); }); diff --git a/src/vlib/counter.h b/src/vlib/counter.h index 17a85217..60e2055d 100644 --- a/src/vlib/counter.h +++ b/src/vlib/counter.h @@ -70,17 +70,17 @@ u32 vlib_simple_counter_n_counters (const vlib_simple_counter_main_t * cm); /** Increment a simple counter @param cm - (vlib_simple_counter_main_t *) simple counter main pointer - @param cpu_index - (u32) the current cpu index + @param thread_index - (u32) the current cpu index @param index - (u32) index of the counter to increment @param increment - (u64) quantitiy to add to the counter */ always_inline void vlib_increment_simple_counter (vlib_simple_counter_main_t * cm, - u32 cpu_index, u32 index, u64 increment) + u32 thread_index, u32 index, u64 increment) { counter_t *my_counters; - my_counters = cm->counters[cpu_index]; + my_counters = cm->counters[thread_index]; my_counters[index] += increment; } @@ -201,7 +201,7 @@ void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm); /** Increment a combined counter @param cm - (vlib_combined_counter_main_t *) comined counter main pointer - @param cpu_index - (u32) the current cpu index + @param thread_index - (u32) the current cpu index @param index - (u32) index of the counter to increment @param packet_increment - (u64) number of packets to add to the counter @param byte_increment - (u64) number of bytes to add to the counter @@ -209,13 +209,13 @@ void vlib_clear_combined_counters (vlib_combined_counter_main_t * cm); always_inline void vlib_increment_combined_counter (vlib_combined_counter_main_t * cm, - u32 cpu_index, + u32 thread_index, u32 index, u64 n_packets, u64 n_bytes) { vlib_counter_t *my_counters; /* Use this CPU's counter array */ - my_counters = cm->counters[cpu_index]; + my_counters = cm->counters[thread_index]; my_counters[index].packets += n_packets; my_counters[index].bytes += n_bytes; @@ -224,14 +224,14 @@ vlib_increment_combined_counter (vlib_combined_counter_main_t * cm, /** Pre-fetch a per-thread combined counter for the given object index */ always_inline void vlib_prefetch_combined_counter (const vlib_combined_counter_main_t * cm, - u32 cpu_index, u32 index) + u32 thread_index, u32 index) { vlib_counter_t *cpu_counters; /* * This CPU's index is assumed to already be in cache */ - cpu_counters = cm->counters[cpu_index]; + cpu_counters = cm->counters[thread_index]; CLIB_PREFETCH (cpu_counters + index, CLIB_CACHE_LINE_BYTES, STORE); } diff --git a/src/vlib/error.c b/src/vlib/error.c index a2c23176..e4ed4ee3 100644 --- a/src/vlib/error.c +++ b/src/vlib/error.c @@ -149,7 +149,7 @@ vlib_register_errors (vlib_main_t * vm, vlib_node_t *n = vlib_get_node (vm, node_index); uword l; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); /* Free up any previous error strings. */ if (n->n_errors > 0) diff --git a/src/vlib/global_funcs.h b/src/vlib/global_funcs.h index f51ec381..9dd01fbf 100644 --- a/src/vlib/global_funcs.h +++ b/src/vlib/global_funcs.h @@ -23,7 +23,7 @@ always_inline vlib_main_t * vlib_get_main (void) { vlib_main_t *vm; - vm = vlib_mains[os_get_cpu_number ()]; + vm = vlib_mains[vlib_get_thread_index ()]; ASSERT (vm); return vm; } diff --git a/src/vlib/main.c b/src/vlib/main.c index b22203f0..422d3e26 100644 --- a/src/vlib/main.c +++ b/src/vlib/main.c @@ -136,18 +136,18 @@ vlib_frame_alloc_to_node (vlib_main_t * vm, u32 to_node_index, else { f = clib_mem_alloc_aligned_no_fail (n, VLIB_FRAME_ALIGN); - f->cpu_index = vm->cpu_index; + f->thread_index = vm->thread_index; fi = vlib_frame_index_no_check (vm, f); } /* Poison frame when debugging. */ if (CLIB_DEBUG > 0) { - u32 save_cpu_index = f->cpu_index; + u32 save_thread_index = f->thread_index; memset (f, 0xfe, n); - f->cpu_index = save_cpu_index; + f->thread_index = save_thread_index; } /* Insert magic number. */ @@ -517,7 +517,7 @@ vlib_put_next_frame (vlib_main_t * vm, * a dangling frame reference. Each thread has its own copy of * the next_frames vector. */ - if (0 && r->cpu_index != next_runtime->cpu_index) + if (0 && r->thread_index != next_runtime->thread_index) { nf->frame_index = ~0; nf->flags &= ~(VLIB_FRAME_PENDING | VLIB_FRAME_IS_ALLOCATED); @@ -866,7 +866,7 @@ vlib_elog_main_loop_event (vlib_main_t * vm, : evm->node_call_elog_event_types, node_index), /* track */ - (vm->cpu_index ? &vlib_worker_threads[vm->cpu_index]. + (vm->thread_index ? &vlib_worker_threads[vm->thread_index]. elog_track : &em->default_track), /* data to log */ n_vectors); } @@ -963,7 +963,7 @@ dispatch_node (vlib_main_t * vm, vm->cpu_time_last_node_dispatch = last_time_stamp; - if (1 /* || vm->cpu_index == node->cpu_index */ ) + if (1 /* || vm->thread_index == node->thread_index */ ) { vlib_main_t *stat_vm; @@ -1029,7 +1029,7 @@ dispatch_node (vlib_main_t * vm, { u32 node_name, vector_length, is_polling; } *ed; - vlib_worker_thread_t *w = vlib_worker_threads + vm->cpu_index; + vlib_worker_thread_t *w = vlib_worker_threads + vm->thread_index; #endif if ((dispatch_state == VLIB_NODE_STATE_INTERRUPT diff --git a/src/vlib/main.h b/src/vlib/main.h index 0197b4f3..329bf073 100644 --- a/src/vlib/main.h +++ b/src/vlib/main.h @@ -156,7 +156,7 @@ typedef struct vlib_main_t uword *init_functions_called; /* to compare with node runtime */ - u32 cpu_index; + u32 thread_index; void **mbuf_alloc_list; diff --git a/src/vlib/node.c b/src/vlib/node.c index dc0a4de5..bbd3a42e 100644 --- a/src/vlib/node.c +++ b/src/vlib/node.c @@ -99,7 +99,7 @@ vlib_node_runtime_update (vlib_main_t * vm, u32 node_index, u32 next_index) vlib_pending_frame_t *pf; i32 i, j, n_insert; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); vlib_worker_thread_barrier_sync (vm); diff --git a/src/vlib/node.h b/src/vlib/node.h index fc7e7da2..1e2f4c38 100644 --- a/src/vlib/node.h +++ b/src/vlib/node.h @@ -344,8 +344,8 @@ typedef struct vlib_frame_t /* Number of vector elements currently in frame. */ u16 n_vectors; - /* Owner cpuid / heap id */ - u16 cpu_index; + /* Owner thread / heap id */ + u16 thread_index; /* Scalar and vector arguments to next node. */ u8 arguments[0]; @@ -459,7 +459,7 @@ typedef struct vlib_node_runtime_t zero before first run of this node. */ - u16 cpu_index; /**< CPU this node runs on */ + u16 thread_index; /**< thread this node runs on */ u8 runtime_data[0]; /**< Function dependent node-runtime data. This data is diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h index 1f7d94e1..54e36874 100644 --- a/src/vlib/node_funcs.h +++ b/src/vlib/node_funcs.h @@ -201,9 +201,9 @@ always_inline vlib_frame_t * vlib_get_frame_no_check (vlib_main_t * vm, uword frame_index) { vlib_frame_t *f; - u32 cpu_index = frame_index & VLIB_CPU_MASK; + u32 thread_index = frame_index & VLIB_CPU_MASK; u32 offset = frame_index & VLIB_OFFSET_MASK; - vm = vlib_mains[cpu_index]; + vm = vlib_mains[thread_index]; f = vm->heap_base + offset; return f; } @@ -215,10 +215,10 @@ vlib_frame_index_no_check (vlib_main_t * vm, vlib_frame_t * f) ASSERT (((uword) f & VLIB_CPU_MASK) == 0); - vm = vlib_mains[f->cpu_index]; + vm = vlib_mains[f->thread_index]; i = ((u8 *) f - (u8 *) vm->heap_base); - return i | f->cpu_index; + return i | f->thread_index; } always_inline vlib_frame_t * diff --git a/src/vlib/threads.c b/src/vlib/threads.c index ef3a24d3..4a111f8d 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -35,27 +35,12 @@ vl (void *p) vlib_worker_thread_t *vlib_worker_threads; vlib_thread_main_t vlib_thread_main; +__thread uword vlib_thread_index = 0; + uword os_get_cpu_number (void) { - void *sp; - uword n; - u32 len; - - len = vec_len (vlib_thread_stacks); - if (len == 0) - return 0; - - /* Get any old stack address. */ - sp = &sp; - - n = ((uword) sp - (uword) vlib_thread_stacks[0]) - >> VLIB_LOG2_THREAD_STACK_SIZE; - - /* "processes" have their own stacks, and they always run in thread 0 */ - n = n >= len ? 0 : n; - - return n; + return vlib_thread_index; } uword @@ -275,21 +260,6 @@ vlib_thread_init (vlib_main_t * vm) return 0; } -vlib_worker_thread_t * -vlib_alloc_thread (vlib_main_t * vm) -{ - vlib_worker_thread_t *w; - - if (vec_len (vlib_worker_threads) >= vec_len (vlib_thread_stacks)) - { - clib_warning ("out of worker threads... Quitting..."); - exit (1); - } - vec_add2 (vlib_worker_threads, w, 1); - w->thread_stack = vlib_thread_stacks[w - vlib_worker_threads]; - return w; -} - vlib_frame_queue_t * vlib_frame_queue_alloc (int nelts) { @@ -427,7 +397,7 @@ vlib_frame_queue_enqueue (vlib_main_t * vm, u32 node_runtime_index, f64 b4 = vlib_time_now_ticks (vm, before); vlib_worker_thread_barrier_check (vm, b4); /* Bad idea. Dequeue -> enqueue -> dequeue -> trouble */ - // vlib_frame_queue_dequeue (vm->cpu_index, vm, nm); + // vlib_frame_queue_dequeue (vm->thread_index, vm, nm); } elt = fq->elts + (new_tail & (fq->nelts - 1)); @@ -497,6 +467,8 @@ vlib_worker_thread_bootstrap_fn (void *arg) w->lwp = syscall (SYS_gettid); w->thread_id = pthread_self (); + vlib_thread_index = w - vlib_worker_threads; + rv = (void *) clib_calljmp ((uword (*)(uword)) w->thread_function, (uword) arg, w->thread_stack + VLIB_THREAD_STACK_SIZE); @@ -610,7 +582,9 @@ start_workers (vlib_main_t * vm) mheap_alloc (0 /* use VM */ , tr->mheap_size); else w->thread_mheap = main_heap; - w->thread_stack = vlib_thread_stacks[w - vlib_worker_threads]; + + w->thread_stack = + vlib_thread_stack_init (w - vlib_worker_threads); w->thread_function = tr->function; w->thread_function_arg = w; w->instance_id = k; @@ -630,7 +604,7 @@ start_workers (vlib_main_t * vm) vm_clone = clib_mem_alloc (sizeof (*vm_clone)); clib_memcpy (vm_clone, vlib_mains[0], sizeof (*vm_clone)); - vm_clone->cpu_index = worker_thread_index; + vm_clone->thread_index = worker_thread_index; vm_clone->heap_base = w->thread_mheap; vm_clone->mbuf_alloc_list = 0; vm_clone->init_functions_called = @@ -679,7 +653,7 @@ start_workers (vlib_main_t * vm) vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { vlib_node_t *n = vlib_get_node (vm, rt->node_index); - rt->cpu_index = vm_clone->cpu_index; + rt->thread_index = vm_clone->thread_index; /* copy initial runtime_data from node */ if (n->runtime_data && n->runtime_data_bytes > 0) clib_memcpy (rt->runtime_data, n->runtime_data, @@ -692,7 +666,7 @@ start_workers (vlib_main_t * vm) vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { vlib_node_t *n = vlib_get_node (vm, rt->node_index); - rt->cpu_index = vm_clone->cpu_index; + rt->thread_index = vm_clone->thread_index; /* copy initial runtime_data from node */ if (n->runtime_data && n->runtime_data_bytes > 0) clib_memcpy (rt->runtime_data, n->runtime_data, @@ -756,7 +730,8 @@ start_workers (vlib_main_t * vm) mheap_alloc (0 /* use VM */ , tr->mheap_size); else w->thread_mheap = main_heap; - w->thread_stack = vlib_thread_stacks[w - vlib_worker_threads]; + w->thread_stack = + vlib_thread_stack_init (w - vlib_worker_threads); w->thread_function = tr->function; w->thread_function_arg = w; w->instance_id = j; @@ -827,7 +802,7 @@ vlib_worker_thread_node_runtime_update (void) uword n_calls, uword n_vectors, uword n_clocks); - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); if (vec_len (vlib_mains) == 1) return; @@ -835,7 +810,7 @@ vlib_worker_thread_node_runtime_update (void) vm = vlib_mains[0]; nm = &vm->node_main; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); ASSERT (*vlib_worker_threads->wait_at_barrier == 1); /* @@ -955,7 +930,7 @@ vlib_worker_thread_node_runtime_update (void) vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL]) { vlib_node_t *n = vlib_get_node (vm, rt->node_index); - rt->cpu_index = vm_clone->cpu_index; + rt->thread_index = vm_clone->thread_index; /* copy runtime_data, will be overwritten later for existing rt */ if (n->runtime_data && n->runtime_data_bytes > 0) clib_memcpy (rt->runtime_data, n->runtime_data, @@ -981,7 +956,7 @@ vlib_worker_thread_node_runtime_update (void) vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { vlib_node_t *n = vlib_get_node (vm, rt->node_index); - rt->cpu_index = vm_clone->cpu_index; + rt->thread_index = vm_clone->thread_index; /* copy runtime_data, will be overwritten later for existing rt */ if (n->runtime_data && n->runtime_data_bytes > 0) clib_memcpy (rt->runtime_data, n->runtime_data, @@ -1180,7 +1155,7 @@ vlib_worker_thread_fork_fixup (vlib_fork_fixup_t which) if (vlib_mains == 0) return; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); vlib_worker_thread_barrier_sync (vm); switch (which) @@ -1212,7 +1187,7 @@ vlib_worker_thread_barrier_sync (vlib_main_t * vm) vlib_worker_threads[0].barrier_sync_count++; - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); deadline = vlib_time_now (vm) + BARRIER_SYNC_TIMEOUT; @@ -1260,7 +1235,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) int vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm) { - u32 thread_id = vm->cpu_index; + u32 thread_id = vm->thread_index; vlib_frame_queue_t *fq = fqm->vlib_frame_queues[thread_id]; vlib_frame_queue_elt_t *elt; u32 *from, *to; @@ -1393,7 +1368,7 @@ vlib_worker_thread_fn (void *arg) vlib_main_t *vm = vlib_get_main (); clib_error_t *e; - ASSERT (vm->cpu_index == os_get_cpu_number ()); + ASSERT (vm->thread_index == vlib_get_thread_index ()); vlib_worker_thread_init (w); clib_time_init (&vm->clib_time); diff --git a/src/vlib/threads.h b/src/vlib/threads.h index eca4fc26..101d3d4a 100644 --- a/src/vlib/threads.h +++ b/src/vlib/threads.h @@ -153,8 +153,6 @@ typedef struct /* Called early, in thread 0's context */ clib_error_t *vlib_thread_init (vlib_main_t * vm); -vlib_worker_thread_t *vlib_alloc_thread (vlib_main_t * vm); - int vlib_frame_queue_enqueue (vlib_main_t * vm, u32 node_runtime_index, u32 frame_queue_index, vlib_frame_t * frame, vlib_frame_queue_msg_type_t type); @@ -183,12 +181,19 @@ u32 vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts); void vlib_worker_thread_barrier_sync (vlib_main_t * vm); void vlib_worker_thread_barrier_release (vlib_main_t * vm); +extern __thread uword vlib_thread_index; +static_always_inline uword +vlib_get_thread_index (void) +{ + return vlib_thread_index; +} + always_inline void vlib_smp_unsafe_warning (void) { if (CLIB_DEBUG > 0) { - if (os_get_cpu_number ()) + if (vlib_get_thread_index ()) fformat (stderr, "%s: SMP unsafe warning...\n", __FUNCTION__); } } @@ -331,21 +336,21 @@ vlib_num_workers () } always_inline u32 -vlib_get_worker_cpu_index (u32 worker_index) +vlib_get_worker_thread_index (u32 worker_index) { return worker_index + 1; } always_inline u32 -vlib_get_worker_index (u32 cpu_index) +vlib_get_worker_index (u32 thread_index) { - return cpu_index - 1; + return thread_index - 1; } always_inline u32 vlib_get_current_worker_index () { - return os_get_cpu_number () - 1; + return vlib_get_thread_index () - 1; } static inline void @@ -467,6 +472,8 @@ vlib_get_worker_handoff_queue_elt (u32 frame_queue_index, return elt; } +u8 *vlib_thread_stack_init (uword thread_index); + int vlib_thread_cb_register (struct vlib_main_t *vm, vlib_thread_callbacks_t * cb); diff --git a/src/vlib/unix/cj.c b/src/vlib/unix/cj.c index 33ba163a..7c1e9475 100644 --- a/src/vlib/unix/cj.c +++ b/src/vlib/unix/cj.c @@ -48,7 +48,7 @@ cj_log (u32 type, void *data0, void *data1) r = (cj_record_t *) & (cjm->records[new_tail & (cjm->num_records - 1)]); r->time = vlib_time_now (cjm->vlib_main); - r->cpu = os_get_cpu_number (); + r->thread_index = vlib_get_thread_index (); r->type = type; r->data[0] = pointer_to_uword (data0); r->data[1] = pointer_to_uword (data1); @@ -133,7 +133,8 @@ static inline void cj_dump_one_record (cj_record_t * r) { fprintf (stderr, "[%d]: %10.6f T%02d %llx %llx\n", - r->cpu, r->time, r->type, (long long unsigned int) r->data[0], + r->thread_index, r->time, r->type, + (long long unsigned int) r->data[0], (long long unsigned int) r->data[1]); } @@ -161,7 +162,7 @@ cj_dump_internal (u8 filter0_enable, u64 filter0, index = (cjm->tail + 1) & (cjm->num_records - 1); r = &(cjm->records[index]); - if (r->cpu != (u32) ~ 0) + if (r->thread_index != (u32) ~ 0) { /* Yes, dump from tail + 1 to the end */ for (i = index; i < cjm->num_records; i++) diff --git a/src/vlib/unix/cj.h b/src/vlib/unix/cj.h index 67626afe..d0a1d46e 100644 --- a/src/vlib/unix/cj.h +++ b/src/vlib/unix/cj.h @@ -23,7 +23,7 @@ typedef struct { f64 time; - u32 cpu; + u32 thread_index; u32 type; u64 data[2]; } cj_record_t; diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c index 6b96cc0d..db5ddd64 100644 --- a/src/vlib/unix/main.c +++ b/src/vlib/unix/main.c @@ -510,13 +510,28 @@ thread0 (uword arg) return i; } +u8 * +vlib_thread_stack_init (uword thread_index) +{ + vec_validate (vlib_thread_stacks, thread_index); + vlib_thread_stacks[thread_index] = clib_mem_alloc_aligned + (VLIB_THREAD_STACK_SIZE, VLIB_THREAD_STACK_SIZE); + + /* + * Disallow writes to the bottom page of the stack, to + * catch stack overflows. + */ + if (mprotect (vlib_thread_stacks[thread_index], + clib_mem_get_page_size (), PROT_READ) < 0) + clib_unix_warning ("thread stack"); + return vlib_thread_stacks[thread_index]; +} + int vlib_unix_main (int argc, char *argv[]) { vlib_main_t *vm = &vlib_global_main; /* one and only time for this! */ - vlib_thread_main_t *tm = &vlib_thread_main; unformat_input_t input; - u8 *thread_stacks; clib_error_t *e; int i; @@ -548,29 +563,9 @@ vlib_unix_main (int argc, char *argv[]) } unformat_free (&input); - /* - * allocate n x VLIB_THREAD_STACK_SIZE stacks, aligned to a - * VLIB_THREAD_STACK_SIZE boundary - * See also: os_get_cpu_number() in vlib/vlib/threads.c - */ - thread_stacks = clib_mem_alloc_aligned - ((uword) tm->n_thread_stacks * VLIB_THREAD_STACK_SIZE, - VLIB_THREAD_STACK_SIZE); - - vec_validate (vlib_thread_stacks, tm->n_thread_stacks - 1); - for (i = 0; i < vec_len (vlib_thread_stacks); i++) - { - vlib_thread_stacks[i] = thread_stacks; - - /* - * Disallow writes to the bottom page of the stack, to - * catch stack overflows. - */ - if (mprotect (thread_stacks, clib_mem_get_page_size (), PROT_READ) < 0) - clib_unix_warning ("thread stack"); + vlib_thread_stack_init (0); - thread_stacks += VLIB_THREAD_STACK_SIZE; - } + vlib_thread_index = 0; i = clib_calljmp (thread0, (uword) vm, (void *) (vlib_thread_stacks[0] + diff --git a/src/vnet/adj/adj_l2.c b/src/vnet/adj/adj_l2.c index f68e54e0..20d70dd4 100644 --- a/src/vnet/adj/adj_l2.c +++ b/src/vnet/adj/adj_l2.c @@ -52,7 +52,7 @@ adj_l2_rewrite_inline (vlib_main_t * vm, { u32 * from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, * to_next, next_index; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); ethernet_main_t * em = ðernet_main; n_left_from = frame->n_vectors; @@ -93,7 +93,7 @@ adj_l2_rewrite_inline (vlib_main_t * vm, vnet_buffer(p0)->sw_if_index[VLIB_TX] = adj0->rewrite_header.sw_if_index; vlib_increment_combined_counter(&adjacency_counters, - cpu_index, + thread_index, adj_index0, /* packet increment */ 0, /* byte increment */ rw_len0); diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c index e8087f08..5756de43 100644 --- a/src/vnet/adj/adj_midchain.c +++ b/src/vnet/adj/adj_midchain.c @@ -49,7 +49,7 @@ adj_midchain_tx_inline (vlib_main_t * vm, u32 next_index; vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; /* Vector of buffer / pkt indices we're supposed to process */ from = vlib_frame_vector_args (frame); @@ -124,13 +124,13 @@ adj_midchain_tx_inline (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, + thread_index, adj0->rewrite_header.sw_if_index, 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, + thread_index, adj1->rewrite_header.sw_if_index, 1, vlib_buffer_length_in_chain (vm, b1)); @@ -181,7 +181,7 @@ adj_midchain_tx_inline (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, + thread_index, adj0->rewrite_header.sw_if_index, 1, vlib_buffer_length_in_chain (vm, b0)); diff --git a/src/vnet/adj/adj_nsh.c b/src/vnet/adj/adj_nsh.c index 9a0f9d8b..128570b0 100644 --- a/src/vnet/adj/adj_nsh.c +++ b/src/vnet/adj/adj_nsh.c @@ -53,7 +53,7 @@ adj_nsh_rewrite_inline (vlib_main_t * vm, { u32 * from = vlib_frame_vector_args (frame); u32 n_left_from, n_left_to_next, * to_next, next_index; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); n_left_from = frame->n_vectors; next_index = node->cached_next_index; @@ -94,7 +94,7 @@ adj_nsh_rewrite_inline (vlib_main_t * vm, vnet_buffer(p0)->ip.save_rewrite_length = rw_len0; vlib_increment_combined_counter(&adjacency_counters, - cpu_index, + thread_index, adj_index0, /* packet increment */ 0, /* byte increment */ rw_len0); diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c index 98842a48..70a189b0 100644 --- a/src/vnet/classify/vnet_classify.c +++ b/src/vnet/classify/vnet_classify.c @@ -251,12 +251,12 @@ static inline void make_working_copy vnet_classify_entry_##size##_t * working_copy##size = 0; foreach_size_in_u32x4; #undef _ - u32 cpu_number = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); - if (cpu_number >= vec_len (t->working_copies)) + if (thread_index >= vec_len (t->working_copies)) { oldheap = clib_mem_set_heap (t->mheap); - vec_validate (t->working_copies, cpu_number); + vec_validate (t->working_copies, thread_index); clib_mem_set_heap (oldheap); } @@ -265,7 +265,7 @@ static inline void make_working_copy * updates from multiple threads will not result in sporadic, spurious * lookup failures. */ - working_copy = t->working_copies[cpu_number]; + working_copy = t->working_copies[thread_index]; t->saved_bucket.as_u64 = b->as_u64; oldheap = clib_mem_set_heap (t->mheap); @@ -290,7 +290,7 @@ static inline void make_working_copy default: abort(); } - t->working_copies[cpu_number] = working_copy; + t->working_copies[thread_index] = working_copy; } _vec_len(working_copy) = (1<log2_pages)*t->entries_per_page; @@ -318,7 +318,7 @@ static inline void make_working_copy working_bucket.offset = vnet_classify_get_offset (t, working_copy); CLIB_MEMORY_BARRIER(); b->as_u64 = working_bucket.as_u64; - t->working_copies[cpu_number] = working_copy; + t->working_copies[thread_index] = working_copy; } static vnet_classify_entry_t * @@ -387,7 +387,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t, int i; u64 hash, new_hash; u32 new_log2_pages; - u32 cpu_number = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u8 * key_minus_skip; ASSERT ((add_v->flags & VNET_CLASSIFY_ENTRY_FREE) == 0); @@ -498,7 +498,7 @@ int vnet_classify_add_del (vnet_classify_table_t * t, new_log2_pages = t->saved_bucket.log2_pages + 1; expand_again: - working_copy = t->working_copies[cpu_number]; + working_copy = t->working_copies[thread_index]; new_v = split_and_rehash (t, working_copy, new_log2_pages); if (new_v == 0) diff --git a/src/vnet/cop/ip4_whitelist.c b/src/vnet/cop/ip4_whitelist.c index 6ef3d7d7..1b5e336b 100644 --- a/src/vnet/cop/ip4_whitelist.c +++ b/src/vnet/cop/ip4_whitelist.c @@ -60,7 +60,7 @@ ip4_cop_whitelist_node_fn (vlib_main_t * vm, cop_feature_type_t next_index; cop_main_t *cm = &cop_main; vlib_combined_counter_main_t * vcm = &load_balance_main.lbm_via_counters; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -177,12 +177,12 @@ ip4_cop_whitelist_node_fn (vlib_main_t * vm, dpo1 = load_balance_get_bucket_i(lb1, 0); vlib_increment_combined_counter - (vcm, cpu_index, lb_index0, 1, + (vcm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, b0) + sizeof(ethernet_header_t)); vlib_increment_combined_counter - (vcm, cpu_index, lb_index1, 1, + (vcm, thread_index, lb_index1, 1, vlib_buffer_length_in_chain (vm, b1) + sizeof(ethernet_header_t)); @@ -273,7 +273,7 @@ ip4_cop_whitelist_node_fn (vlib_main_t * vm, dpo0 = load_balance_get_bucket_i(lb0, 0); vlib_increment_combined_counter - (vcm, cpu_index, lb_index0, 1, + (vcm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, b0) + sizeof(ethernet_header_t)); diff --git a/src/vnet/cop/ip6_whitelist.c b/src/vnet/cop/ip6_whitelist.c index c2e16ccf..f3fe62e3 100644 --- a/src/vnet/cop/ip6_whitelist.c +++ b/src/vnet/cop/ip6_whitelist.c @@ -61,7 +61,7 @@ ip6_cop_whitelist_node_fn (vlib_main_t * vm, cop_main_t *cm = &cop_main; ip6_main_t * im6 = &ip6_main; vlib_combined_counter_main_t * vcm = &load_balance_main.lbm_via_counters; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -153,12 +153,12 @@ ip6_cop_whitelist_node_fn (vlib_main_t * vm, dpo1 = load_balance_get_bucket_i(lb1, 0); vlib_increment_combined_counter - (vcm, cpu_index, lb_index0, 1, + (vcm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, b0) + sizeof(ethernet_header_t)); vlib_increment_combined_counter - (vcm, cpu_index, lb_index1, 1, + (vcm, thread_index, lb_index1, 1, vlib_buffer_length_in_chain (vm, b1) + sizeof(ethernet_header_t)); @@ -233,7 +233,7 @@ ip6_cop_whitelist_node_fn (vlib_main_t * vm, dpo0 = load_balance_get_bucket_i(lb0, 0); vlib_increment_combined_counter - (vcm, cpu_index, lb_index0, 1, + (vcm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, b0) + sizeof(ethernet_header_t)); diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c index ba337f3f..76980102 100644 --- a/src/vnet/devices/af_packet/node.c +++ b/src/vnet/devices/af_packet/node.c @@ -124,7 +124,7 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, u32 frame_num = apif->rx_req->tp_frame_nr; u8 *block_start = apif->rx_ring + block * block_size; uword n_trace = vlib_get_trace_count (vm, node); - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); u32 min_bufs = apif->rx_req->tp_frame_size / n_buffer_bytes; @@ -132,15 +132,15 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, if (apif->per_interface_next_index != ~0) next_index = apif->per_interface_next_index; - n_free_bufs = vec_len (apm->rx_buffers[cpu_index]); + n_free_bufs = vec_len (apm->rx_buffers[thread_index]); if (PREDICT_FALSE (n_free_bufs < VLIB_FRAME_SIZE)) { - vec_validate (apm->rx_buffers[cpu_index], + vec_validate (apm->rx_buffers[thread_index], VLIB_FRAME_SIZE + n_free_bufs - 1); n_free_bufs += - vlib_buffer_alloc (vm, &apm->rx_buffers[cpu_index][n_free_bufs], + vlib_buffer_alloc (vm, &apm->rx_buffers[thread_index][n_free_bufs], VLIB_FRAME_SIZE); - _vec_len (apm->rx_buffers[cpu_index]) = n_free_bufs; + _vec_len (apm->rx_buffers[thread_index]) = n_free_bufs; } rx_frame = apif->next_rx_frame; @@ -163,11 +163,11 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, { /* grab free buffer */ u32 last_empty_buffer = - vec_len (apm->rx_buffers[cpu_index]) - 1; + vec_len (apm->rx_buffers[thread_index]) - 1; prev_bi0 = bi0; - bi0 = apm->rx_buffers[cpu_index][last_empty_buffer]; + bi0 = apm->rx_buffers[thread_index][last_empty_buffer]; b0 = vlib_get_buffer (vm, bi0); - _vec_len (apm->rx_buffers[cpu_index]) = last_empty_buffer; + _vec_len (apm->rx_buffers[thread_index]) = last_empty_buffer; n_free_bufs--; /* copy data */ @@ -236,9 +236,9 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (vnet_get_main ()->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number (), apif->hw_if_index, n_rx_packets, n_rx_bytes); + vlib_get_thread_index (), apif->hw_if_index, n_rx_packets, n_rx_bytes); - vnet_device_increment_rx_packets (cpu_index, n_rx_packets); + vnet_device_increment_rx_packets (thread_index, n_rx_packets); return n_rx_packets; } diff --git a/src/vnet/devices/devices.c b/src/vnet/devices/devices.c index 41645220..5e5e812c 100644 --- a/src/vnet/devices/devices.c +++ b/src/vnet/devices/devices.c @@ -104,7 +104,7 @@ vnet_device_queue_sort (void *a1, void *a2) void vnet_device_input_assign_thread (u32 hw_if_index, - u16 queue_id, uword cpu_index) + u16 queue_id, uword thread_index) { vnet_main_t *vnm = vnet_get_main (); vnet_device_main_t *vdm = &vnet_device_main; @@ -115,19 +115,19 @@ vnet_device_input_assign_thread (u32 hw_if_index, ASSERT (hw->input_node_index > 0); - if (vdm->first_worker_cpu_index == 0) - cpu_index = 0; + if (vdm->first_worker_thread_index == 0) + thread_index = 0; - if (cpu_index != 0 && - (cpu_index < vdm->first_worker_cpu_index || - cpu_index > vdm->last_worker_cpu_index)) + if (thread_index != 0 && + (thread_index < vdm->first_worker_thread_index || + thread_index > vdm->last_worker_thread_index)) { - cpu_index = vdm->next_worker_cpu_index++; - if (vdm->next_worker_cpu_index > vdm->last_worker_cpu_index) - vdm->next_worker_cpu_index = vdm->first_worker_cpu_index; + thread_index = vdm->next_worker_thread_index++; + if (vdm->next_worker_thread_index > vdm->last_worker_thread_index) + vdm->next_worker_thread_index = vdm->first_worker_thread_index; } - vm = vlib_mains[cpu_index]; + vm = vlib_mains[thread_index]; rt = vlib_node_get_runtime_data (vm, hw->input_node_index); vec_add2 (rt->devices_and_queues, dq, 1); @@ -136,33 +136,33 @@ vnet_device_input_assign_thread (u32 hw_if_index, dq->queue_id = queue_id; vec_sort_with_function (rt->devices_and_queues, vnet_device_queue_sort); - vec_validate (hw->input_node_cpu_index_by_queue, queue_id); - hw->input_node_cpu_index_by_queue[queue_id] = cpu_index; + vec_validate (hw->input_node_thread_index_by_queue, queue_id); + hw->input_node_thread_index_by_queue[queue_id] = thread_index; } static int vnet_device_input_unassign_thread (u32 hw_if_index, u16 queue_id, - uword cpu_index) + uword thread_index) { vnet_main_t *vnm = vnet_get_main (); vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); vnet_device_input_runtime_t *rt; vnet_device_and_queue_t *dq; - uword old_cpu_index; + uword old_thread_index; - if (hw->input_node_cpu_index_by_queue == 0) + if (hw->input_node_thread_index_by_queue == 0) return VNET_API_ERROR_INVALID_INTERFACE; - if (vec_len (hw->input_node_cpu_index_by_queue) < queue_id + 1) + if (vec_len (hw->input_node_thread_index_by_queue) < queue_id + 1) return VNET_API_ERROR_INVALID_INTERFACE; - old_cpu_index = hw->input_node_cpu_index_by_queue[queue_id]; + old_thread_index = hw->input_node_thread_index_by_queue[queue_id]; - if (old_cpu_index == cpu_index) + if (old_thread_index == thread_index) return 0; rt = - vlib_node_get_runtime_data (vlib_mains[old_cpu_index], + vlib_node_get_runtime_data (vlib_mains[old_thread_index], hw->input_node_index); vec_foreach (dq, rt->devices_and_queues) @@ -240,7 +240,7 @@ set_device_placement (vlib_main_t * vm, unformat_input_t * input, vnet_device_main_t *vdm = &vnet_device_main; u32 hw_if_index = (u32) ~ 0; u32 queue_id = (u32) 0; - u32 cpu_index = (u32) ~ 0; + u32 thread_index = (u32) ~ 0; int rv; if (!unformat_user (input, unformat_line_input, line_input)) @@ -253,10 +253,10 @@ set_device_placement (vlib_main_t * vm, unformat_input_t * input, ; else if (unformat (line_input, "queue %d", &queue_id)) ; - else if (unformat (line_input, "main", &cpu_index)) - cpu_index = 0; - else if (unformat (line_input, "worker %d", &cpu_index)) - cpu_index += vdm->first_worker_cpu_index; + else if (unformat (line_input, "main", &thread_index)) + thread_index = 0; + else if (unformat (line_input, "worker %d", &thread_index)) + thread_index += vdm->first_worker_thread_index; else { error = clib_error_return (0, "parse error: '%U'", @@ -271,16 +271,17 @@ set_device_placement (vlib_main_t * vm, unformat_input_t * input, if (hw_if_index == (u32) ~ 0) return clib_error_return (0, "please specify valid interface name"); - if (cpu_index > vdm->last_worker_cpu_index) + if (thread_index > vdm->last_worker_thread_index) return clib_error_return (0, "please specify valid worker thread or main"); - rv = vnet_device_input_unassign_thread (hw_if_index, queue_id, cpu_index); + rv = + vnet_device_input_unassign_thread (hw_if_index, queue_id, thread_index); if (rv) return clib_error_return (0, "not found"); - vnet_device_input_assign_thread (hw_if_index, queue_id, cpu_index); + vnet_device_input_assign_thread (hw_if_index, queue_id, thread_index); return 0; } @@ -326,9 +327,9 @@ vnet_device_init (vlib_main_t * vm) tr = p ? (vlib_thread_registration_t *) p[0] : 0; if (tr && tr->count > 0) { - vdm->first_worker_cpu_index = tr->first_index; - vdm->next_worker_cpu_index = tr->first_index; - vdm->last_worker_cpu_index = tr->first_index + tr->count - 1; + vdm->first_worker_thread_index = tr->first_index; + vdm->next_worker_thread_index = tr->first_index; + vdm->last_worker_thread_index = tr->first_index + tr->count - 1; } return 0; } diff --git a/src/vnet/devices/devices.h b/src/vnet/devices/devices.h index bbb29fe3..966f8302 100644 --- a/src/vnet/devices/devices.h +++ b/src/vnet/devices/devices.h @@ -50,9 +50,9 @@ typedef struct typedef struct { vnet_device_per_worker_data_t *workers; - uword first_worker_cpu_index; - uword last_worker_cpu_index; - uword next_worker_cpu_index; + uword first_worker_thread_index; + uword last_worker_thread_index; + uword next_worker_thread_index; } vnet_device_main_t; typedef struct @@ -80,7 +80,7 @@ vnet_set_device_input_node (u32 hw_if_index, u32 node_index) } void vnet_device_input_assign_thread (u32 hw_if_index, u16 queue_id, - uword cpu_index); + uword thread_index); static inline u64 vnet_get_aggregate_rx_packets (void) @@ -95,12 +95,12 @@ vnet_get_aggregate_rx_packets (void) } static inline void -vnet_device_increment_rx_packets (u32 cpu_index, u64 count) +vnet_device_increment_rx_packets (u32 thread_index, u64 count) { vnet_device_main_t *vdm = &vnet_device_main; vnet_device_per_worker_data_t *pwd; - pwd = vec_elt_at_index (vdm->workers, cpu_index); + pwd = vec_elt_at_index (vdm->workers, thread_index); pwd->aggregate_rx_packets += count; } @@ -117,9 +117,9 @@ vnet_device_input_set_interrupt_pending (vnet_main_t * vnm, u32 hw_if_index, { vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index); - ASSERT (queue_id < vec_len (hw->input_node_cpu_index_by_queue)); - u32 cpu_index = hw->input_node_cpu_index_by_queue[queue_id]; - vlib_node_set_interrupt_pending (vlib_mains[cpu_index], + ASSERT (queue_id < vec_len (hw->input_node_thread_index_by_queue)); + u32 thread_index = hw->input_node_thread_index_by_queue[queue_id]; + vlib_node_set_interrupt_pending (vlib_mains[thread_index], hw->input_node_index); } diff --git a/src/vnet/devices/netmap/node.c b/src/vnet/devices/netmap/node.c index 68ea7832..e120eeae 100644 --- a/src/vnet/devices/netmap/node.c +++ b/src/vnet/devices/netmap/node.c @@ -98,22 +98,22 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, u32 n_free_bufs; struct netmap_ring *ring; int cur_ring; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); if (nif->per_interface_next_index != ~0) next_index = nif->per_interface_next_index; - n_free_bufs = vec_len (nm->rx_buffers[cpu_index]); + n_free_bufs = vec_len (nm->rx_buffers[thread_index]); if (PREDICT_FALSE (n_free_bufs < VLIB_FRAME_SIZE)) { - vec_validate (nm->rx_buffers[cpu_index], + vec_validate (nm->rx_buffers[thread_index], VLIB_FRAME_SIZE + n_free_bufs - 1); n_free_bufs += - vlib_buffer_alloc (vm, &nm->rx_buffers[cpu_index][n_free_bufs], + vlib_buffer_alloc (vm, &nm->rx_buffers[thread_index][n_free_bufs], VLIB_FRAME_SIZE); - _vec_len (nm->rx_buffers[cpu_index]) = n_free_bufs; + _vec_len (nm->rx_buffers[thread_index]) = n_free_bufs; } cur_ring = nif->first_rx_ring; @@ -163,11 +163,11 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_buffer_t *b0; /* grab free buffer */ u32 last_empty_buffer = - vec_len (nm->rx_buffers[cpu_index]) - 1; + vec_len (nm->rx_buffers[thread_index]) - 1; prev_bi0 = bi0; - bi0 = nm->rx_buffers[cpu_index][last_empty_buffer]; + bi0 = nm->rx_buffers[thread_index][last_empty_buffer]; b0 = vlib_get_buffer (vm, bi0); - _vec_len (nm->rx_buffers[cpu_index]) = last_empty_buffer; + _vec_len (nm->rx_buffers[thread_index]) = last_empty_buffer; n_free_bufs--; /* copy data */ @@ -247,9 +247,9 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (vnet_get_main ()->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number (), nif->hw_if_index, n_rx_packets, n_rx_bytes); + vlib_get_thread_index (), nif->hw_if_index, n_rx_packets, n_rx_bytes); - vnet_device_increment_rx_packets (cpu_index, n_rx_packets); + vnet_device_increment_rx_packets (thread_index, n_rx_packets); return n_rx_packets; } @@ -260,7 +260,7 @@ netmap_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, { int i; u32 n_rx_packets = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); netmap_main_t *nm = &netmap_main; netmap_if_t *nmi; @@ -269,7 +269,7 @@ netmap_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, nmi = vec_elt_at_index (nm->interfaces, i); if (nmi->is_admin_up && (i % nm->input_cpu_count) == - (cpu_index - nm->input_cpu_first_index)) + (thread_index - nm->input_cpu_first_index)) n_rx_packets += netmap_device_input_fn (vm, node, frame, nmi); } diff --git a/src/vnet/devices/ssvm/node.c b/src/vnet/devices/ssvm/node.c index a6c9dfd7..539b4161 100644 --- a/src/vnet/devices/ssvm/node.c +++ b/src/vnet/devices/ssvm/node.c @@ -89,7 +89,7 @@ ssvm_eth_device_input (ssvm_eth_main_t * em, ethernet_header_t *eh0; u16 type0; u32 n_rx_bytes = 0, l3_offset0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 trace_cnt __attribute__ ((unused)) = vlib_get_trace_count (vm, node); volatile u32 *lock; u32 *elt_indices; @@ -284,10 +284,10 @@ out: vlib_increment_combined_counter (vnet_get_main ()->interface_main.combined_sw_if_counters - + VNET_INTERFACE_COUNTER_RX, cpu_index, + + VNET_INTERFACE_COUNTER_RX, thread_index, intfc->vlib_hw_if_index, rx_queue_index, n_rx_bytes); - vnet_device_increment_rx_packets (cpu_index, rx_queue_index); + vnet_device_increment_rx_packets (thread_index, rx_queue_index); return rx_queue_index; } diff --git a/src/vnet/devices/virtio/vhost-user.c b/src/vnet/devices/virtio/vhost-user.c index 00807dc0..5e720f65 100644 --- a/src/vnet/devices/virtio/vhost-user.c +++ b/src/vnet/devices/virtio/vhost-user.c @@ -331,7 +331,7 @@ vhost_user_tx_thread_placement (vhost_user_intf_t * vui) { //Let's try to assign one queue to each thread u32 qid = 0; - u32 cpu_index = 0; + u32 thread_index = 0; vui->use_tx_spinlock = 0; while (1) { @@ -341,20 +341,21 @@ vhost_user_tx_thread_placement (vhost_user_intf_t * vui) if (!rxvq->started || !rxvq->enabled) continue; - vui->per_cpu_tx_qid[cpu_index] = qid; - cpu_index++; - if (cpu_index == vlib_get_thread_main ()->n_vlib_mains) + vui->per_cpu_tx_qid[thread_index] = qid; + thread_index++; + if (thread_index == vlib_get_thread_main ()->n_vlib_mains) return; } //We need to loop, meaning the spinlock has to be used vui->use_tx_spinlock = 1; - if (cpu_index == 0) + if (thread_index == 0) { //Could not find a single valid one - for (cpu_index = 0; - cpu_index < vlib_get_thread_main ()->n_vlib_mains; cpu_index++) + for (thread_index = 0; + thread_index < vlib_get_thread_main ()->n_vlib_mains; + thread_index++) { - vui->per_cpu_tx_qid[cpu_index] = 0; + vui->per_cpu_tx_qid[thread_index] = 0; } return; } @@ -368,7 +369,7 @@ vhost_user_rx_thread_placement () vhost_user_intf_t *vui; vhost_cpu_t *vhc; u32 *workers = 0; - u32 cpu_index; + u32 thread_index; vlib_main_t *vm; //Let's list all workers cpu indexes @@ -400,9 +401,9 @@ vhost_user_rx_thread_placement () continue; i %= vec_len (vui_workers); - cpu_index = vui_workers[i]; + thread_index = vui_workers[i]; i++; - vhc = &vum->cpus[cpu_index]; + vhc = &vum->cpus[thread_index]; iaq.qid = qid; iaq.vhost_iface_index = vui - vum->vhost_user_interfaces; @@ -429,14 +430,14 @@ vhost_user_rx_thread_placement () vhc->operation_mode = mode; } - for (cpu_index = vum->input_cpu_first_index; - cpu_index < vum->input_cpu_first_index + vum->input_cpu_count; - cpu_index++) + for (thread_index = vum->input_cpu_first_index; + thread_index < vum->input_cpu_first_index + vum->input_cpu_count; + thread_index++) { vlib_node_state_t state = VLIB_NODE_STATE_POLLING; - vhc = &vum->cpus[cpu_index]; - vm = vlib_mains ? vlib_mains[cpu_index] : &vlib_global_main; + vhc = &vum->cpus[thread_index]; + vm = vlib_mains ? vlib_mains[thread_index] : &vlib_global_main; switch (vhc->operation_mode) { case VHOST_USER_INTERRUPT_MODE: @@ -532,7 +533,7 @@ vhost_user_set_interrupt_pending (vhost_user_intf_t * vui, u32 ifq) { vhost_user_main_t *vum = &vhost_user_main; vhost_cpu_t *vhc; - u32 cpu_index; + u32 thread_index; vhost_iface_and_queue_t *vhiq; vlib_main_t *vm; u32 ifq2; @@ -553,8 +554,8 @@ vhost_user_set_interrupt_pending (vhost_user_intf_t * vui, u32 ifq) if ((vhiq->vhost_iface_index == (ifq >> 8)) && (VHOST_VRING_IDX_TX (vhiq->qid) == (ifq & 0xff))) { - cpu_index = vhc - vum->cpus; - vm = vlib_mains ? vlib_mains[cpu_index] : &vlib_global_main; + thread_index = vhc - vum->cpus; + vm = vlib_mains ? vlib_mains[thread_index] : &vlib_global_main; /* * Convert RX virtqueue number in the lower byte to vring * queue index for the input node process. Top bytes contain @@ -1592,7 +1593,7 @@ vhost_user_if_input (vlib_main_t * vm, u32 n_trace = vlib_get_trace_count (vm, node); u16 qsz_mask; u32 map_hint = 0; - u16 cpu_index = os_get_cpu_number (); + u16 thread_index = vlib_get_thread_index (); u16 copy_len = 0; { @@ -1651,32 +1652,32 @@ vhost_user_if_input (vlib_main_t * vm, * in the loop and come back later. This is not an issue as for big packet, * processing cost really comes from the memory copy. */ - if (PREDICT_FALSE (vum->cpus[cpu_index].rx_buffers_len < n_left + 1)) + if (PREDICT_FALSE (vum->cpus[thread_index].rx_buffers_len < n_left + 1)) { - u32 curr_len = vum->cpus[cpu_index].rx_buffers_len; - vum->cpus[cpu_index].rx_buffers_len += + u32 curr_len = vum->cpus[thread_index].rx_buffers_len; + vum->cpus[thread_index].rx_buffers_len += vlib_buffer_alloc_from_free_list (vm, - vum->cpus[cpu_index].rx_buffers + + vum->cpus[thread_index].rx_buffers + curr_len, VHOST_USER_RX_BUFFERS_N - curr_len, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); if (PREDICT_FALSE - (vum->cpus[cpu_index].rx_buffers_len < + (vum->cpus[thread_index].rx_buffers_len < VHOST_USER_RX_BUFFER_STARVATION)) { /* In case of buffer starvation, discard some packets from the queue * and log the event. * We keep doing best effort for the remaining packets. */ - u32 flush = (n_left + 1 > vum->cpus[cpu_index].rx_buffers_len) ? - n_left + 1 - vum->cpus[cpu_index].rx_buffers_len : 1; + u32 flush = (n_left + 1 > vum->cpus[thread_index].rx_buffers_len) ? + n_left + 1 - vum->cpus[thread_index].rx_buffers_len : 1; flush = vhost_user_rx_discard_packet (vm, vui, txvq, flush); n_left -= flush; vlib_increment_simple_counter (vnet_main. interface_main.sw_if_counters + VNET_INTERFACE_COUNTER_DROP, - os_get_cpu_number (), + vlib_get_thread_index (), vui->sw_if_index, flush); vlib_error_count (vm, vhost_user_input_node.index, @@ -1696,7 +1697,7 @@ vhost_user_if_input (vlib_main_t * vm, u32 desc_data_offset; vring_desc_t *desc_table = txvq->desc; - if (PREDICT_FALSE (vum->cpus[cpu_index].rx_buffers_len <= 1)) + if (PREDICT_FALSE (vum->cpus[thread_index].rx_buffers_len <= 1)) { /* Not enough rx_buffers * Note: We yeld on 1 so we don't need to do an additional @@ -1707,17 +1708,18 @@ vhost_user_if_input (vlib_main_t * vm, } desc_current = txvq->avail->ring[txvq->last_avail_idx & qsz_mask]; - vum->cpus[cpu_index].rx_buffers_len--; - bi_current = (vum->cpus[cpu_index].rx_buffers) - [vum->cpus[cpu_index].rx_buffers_len]; + vum->cpus[thread_index].rx_buffers_len--; + bi_current = (vum->cpus[thread_index].rx_buffers) + [vum->cpus[thread_index].rx_buffers_len]; b_head = b_current = vlib_get_buffer (vm, bi_current); to_next[0] = bi_current; //We do that now so we can forget about bi_current to_next++; n_left_to_next--; vlib_prefetch_buffer_with_index (vm, - (vum->cpus[cpu_index].rx_buffers) - [vum->cpus[cpu_index]. + (vum-> + cpus[thread_index].rx_buffers) + [vum->cpus[thread_index]. rx_buffers_len - 1], LOAD); /* Just preset the used descriptor id and length for later */ @@ -1791,7 +1793,7 @@ vhost_user_if_input (vlib_main_t * vm, (b_current->current_length == VLIB_BUFFER_DATA_SIZE)) { if (PREDICT_FALSE - (vum->cpus[cpu_index].rx_buffers_len == 0)) + (vum->cpus[thread_index].rx_buffers_len == 0)) { /* Cancel speculation */ to_next--; @@ -1805,17 +1807,18 @@ vhost_user_if_input (vlib_main_t * vm, * but valid. */ vhost_user_input_rewind_buffers (vm, - &vum->cpus[cpu_index], + &vum->cpus + [thread_index], b_head); n_left = 0; goto stop; } /* Get next output */ - vum->cpus[cpu_index].rx_buffers_len--; + vum->cpus[thread_index].rx_buffers_len--; u32 bi_next = - (vum->cpus[cpu_index].rx_buffers)[vum->cpus - [cpu_index].rx_buffers_len]; + (vum->cpus[thread_index].rx_buffers)[vum->cpus + [thread_index].rx_buffers_len]; b_current->next_buffer = bi_next; b_current->flags |= VLIB_BUFFER_NEXT_PRESENT; bi_current = bi_next; @@ -1823,7 +1826,7 @@ vhost_user_if_input (vlib_main_t * vm, } /* Prepare a copy order executed later for the data */ - vhost_copy_t *cpy = &vum->cpus[cpu_index].copy[copy_len]; + vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len]; copy_len++; u32 desc_data_l = desc_table[desc_current].len - desc_data_offset; @@ -1880,7 +1883,7 @@ vhost_user_if_input (vlib_main_t * vm, if (PREDICT_FALSE (copy_len >= VHOST_USER_RX_COPY_THRESHOLD)) { if (PREDICT_FALSE - (vhost_user_input_copy (vui, vum->cpus[cpu_index].copy, + (vhost_user_input_copy (vui, vum->cpus[thread_index].copy, copy_len, &map_hint))) { clib_warning @@ -1905,7 +1908,7 @@ vhost_user_if_input (vlib_main_t * vm, /* Do the memory copies */ if (PREDICT_FALSE - (vhost_user_input_copy (vui, vum->cpus[cpu_index].copy, + (vhost_user_input_copy (vui, vum->cpus[thread_index].copy, copy_len, &map_hint))) { clib_warning ("Memory mapping error on interface hw_if_index=%d " @@ -1933,9 +1936,9 @@ vhost_user_if_input (vlib_main_t * vm, vlib_increment_combined_counter (vnet_main.interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number (), vui->sw_if_index, n_rx_packets, n_rx_bytes); + vlib_get_thread_index (), vui->sw_if_index, n_rx_packets, n_rx_bytes); - vnet_device_increment_rx_packets (cpu_index, n_rx_packets); + vnet_device_increment_rx_packets (thread_index, n_rx_packets); return n_rx_packets; } @@ -1946,15 +1949,15 @@ vhost_user_input (vlib_main_t * vm, { vhost_user_main_t *vum = &vhost_user_main; uword n_rx_packets = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); vhost_iface_and_queue_t *vhiq; vhost_user_intf_t *vui; vhost_cpu_t *vhc; - vhc = &vum->cpus[cpu_index]; + vhc = &vum->cpus[thread_index]; if (PREDICT_TRUE (vhc->operation_mode == VHOST_USER_POLLING_MODE)) { - vec_foreach (vhiq, vum->cpus[cpu_index].rx_queues) + vec_foreach (vhiq, vum->cpus[thread_index].rx_queues) { vui = &vum->vhost_user_interfaces[vhiq->vhost_iface_index]; n_rx_packets += vhost_user_if_input (vm, vum, vui, vhiq->qid, node); @@ -2096,7 +2099,7 @@ vhost_user_tx (vlib_main_t * vm, vhost_user_vring_t *rxvq; u16 qsz_mask; u8 error; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 map_hint = 0; u8 retry = 8; u16 copy_len; @@ -2116,7 +2119,7 @@ vhost_user_tx (vlib_main_t * vm, qid = VHOST_VRING_IDX_RX (*vec_elt_at_index - (vui->per_cpu_tx_qid, os_get_cpu_number ())); + (vui->per_cpu_tx_qid, vlib_get_thread_index ())); rxvq = &vui->vrings[qid]; if (PREDICT_FALSE (vui->use_tx_spinlock)) vhost_user_vring_lock (vui, qid); @@ -2143,10 +2146,10 @@ retry: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - vum->cpus[cpu_index].current_trace = + vum->cpus[thread_index].current_trace = vlib_add_trace (vm, node, b0, - sizeof (*vum->cpus[cpu_index].current_trace)); - vhost_user_tx_trace (vum->cpus[cpu_index].current_trace, + sizeof (*vum->cpus[thread_index].current_trace)); + vhost_user_tx_trace (vum->cpus[thread_index].current_trace, vui, qid / 2, b0, rxvq); } @@ -2188,14 +2191,14 @@ retry: { // Get a header from the header array virtio_net_hdr_mrg_rxbuf_t *hdr = - &vum->cpus[cpu_index].tx_headers[tx_headers_len]; + &vum->cpus[thread_index].tx_headers[tx_headers_len]; tx_headers_len++; hdr->hdr.flags = 0; hdr->hdr.gso_type = 0; hdr->num_buffers = 1; //This is local, no need to check // Prepare a copy order executed later for the header - vhost_copy_t *cpy = &vum->cpus[cpu_index].copy[copy_len]; + vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len]; copy_len++; cpy->len = vui->virtio_net_hdr_sz; cpy->dst = buffer_map_addr; @@ -2220,7 +2223,7 @@ retry: else if (vui->virtio_net_hdr_sz == 12) //MRG is available { virtio_net_hdr_mrg_rxbuf_t *hdr = - &vum->cpus[cpu_index].tx_headers[tx_headers_len - 1]; + &vum->cpus[thread_index].tx_headers[tx_headers_len - 1]; //Move from available to used buffer rxvq->used->ring[rxvq->last_used_idx & qsz_mask].id = @@ -2282,7 +2285,7 @@ retry: } { - vhost_copy_t *cpy = &vum->cpus[cpu_index].copy[copy_len]; + vhost_copy_t *cpy = &vum->cpus[thread_index].copy[copy_len]; copy_len++; cpy->len = bytes_left; cpy->len = (cpy->len > buffer_len) ? buffer_len : cpy->len; @@ -2325,8 +2328,8 @@ retry: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { - vum->cpus[cpu_index].current_trace->hdr = - vum->cpus[cpu_index].tx_headers[tx_headers_len - 1]; + vum->cpus[thread_index].current_trace->hdr = + vum->cpus[thread_index].tx_headers[tx_headers_len - 1]; } n_left--; //At the end for error counting when 'goto done' is invoked @@ -2336,7 +2339,7 @@ retry: done: //Do the memory copies if (PREDICT_FALSE - (vhost_user_tx_copy (vui, vum->cpus[cpu_index].copy, + (vhost_user_tx_copy (vui, vum->cpus[thread_index].copy, copy_len, &map_hint))) { clib_warning ("Memory mapping error on interface hw_if_index=%d " @@ -2386,7 +2389,7 @@ done3: vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters + VNET_INTERFACE_COUNTER_DROP, - os_get_cpu_number (), vui->sw_if_index, n_left); + vlib_get_thread_index (), vui->sw_if_index, n_left); } vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors); @@ -2773,11 +2776,11 @@ vhost_user_send_interrupt_process (vlib_main_t * vm, case ~0: vec_foreach (vhc, vum->cpus) { - u32 cpu_index = vhc - vum->cpus; + u32 thread_index = vhc - vum->cpus; f64 next_timeout; next_timeout = timeout; - vec_foreach (vhiq, vum->cpus[cpu_index].rx_queues) + vec_foreach (vhiq, vum->cpus[thread_index].rx_queues) { vui = &vum->vhost_user_interfaces[vhiq->vhost_iface_index]; vhost_user_vring_t *rxvq = diff --git a/src/vnet/dpo/lookup_dpo.c b/src/vnet/dpo/lookup_dpo.c index e94e871c..97ad0a44 100644 --- a/src/vnet/dpo/lookup_dpo.c +++ b/src/vnet/dpo/lookup_dpo.c @@ -266,7 +266,7 @@ lookup_dpo_ip4_inline (vlib_main_t * vm, int table_from_interface) { u32 n_left_from, next_index, * from, * to_next; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters; from = vlib_frame_vector_args (from_frame); @@ -407,10 +407,10 @@ lookup_dpo_ip4_inline (vlib_main_t * vm, vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b1)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -511,7 +511,7 @@ lookup_dpo_ip4_inline (vlib_main_t * vm, vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -606,7 +606,7 @@ lookup_dpo_ip6_inline (vlib_main_t * vm, { vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters; u32 n_left_from, next_index, * from, * to_next; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -749,10 +749,10 @@ lookup_dpo_ip6_inline (vlib_main_t * vm, vnet_buffer(b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b1)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -853,7 +853,7 @@ lookup_dpo_ip6_inline (vlib_main_t * vm, vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -930,7 +930,7 @@ lookup_dpo_mpls_inline (vlib_main_t * vm, int table_from_interface) { u32 n_left_from, next_index, * from, * to_next; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters; from = vlib_frame_vector_args (from_frame); @@ -994,7 +994,7 @@ lookup_dpo_mpls_inline (vlib_main_t * vm, vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) diff --git a/src/vnet/dpo/replicate_dpo.c b/src/vnet/dpo/replicate_dpo.c index a9f334be..e25ceae9 100644 --- a/src/vnet/dpo/replicate_dpo.c +++ b/src/vnet/dpo/replicate_dpo.c @@ -627,7 +627,7 @@ replicate_inline (vlib_main_t * vm, vlib_combined_counter_main_t * cm = &replicate_main.repm_counters; replicate_main_t * rm = &replicate_main; u32 n_left_from, * from, * to_next, next_index; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -657,12 +657,12 @@ replicate_inline (vlib_main_t * vm, rep0 = replicate_get(repi0); vlib_increment_combined_counter( - cm, cpu_index, repi0, 1, + cm, thread_index, repi0, 1, vlib_buffer_length_in_chain(vm, b0)); - vec_validate (rm->clones[cpu_index], rep0->rep_n_buckets - 1); + vec_validate (rm->clones[thread_index], rep0->rep_n_buckets - 1); - num_cloned = vlib_buffer_clone (vm, bi0, rm->clones[cpu_index], rep0->rep_n_buckets, 128); + num_cloned = vlib_buffer_clone (vm, bi0, rm->clones[thread_index], rep0->rep_n_buckets, 128); if (num_cloned != rep0->rep_n_buckets) { @@ -673,7 +673,7 @@ replicate_inline (vlib_main_t * vm, for (bucket = 0; bucket < num_cloned; bucket++) { - ci0 = rm->clones[cpu_index][bucket]; + ci0 = rm->clones[thread_index][bucket]; c0 = vlib_get_buffer(vm, ci0); to_next[0] = ci0; @@ -700,7 +700,7 @@ replicate_inline (vlib_main_t * vm, vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); } } - vec_reset_length (rm->clones[cpu_index]); + vec_reset_length (rm->clones[thread_index]); } vlib_put_next_frame (vm, node, next_index, n_left_to_next); diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index ee757505..c74a097e 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -1771,7 +1771,7 @@ set_ip4_over_ethernet_rpc_callback (vnet_arp_set_ip4_over_ethernet_rpc_args_t * a) { vnet_main_t *vm = vnet_get_main (); - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); if (a->flags & ETHERNET_ARP_ARGS_REMOVE) vnet_arp_unset_ip4_over_ethernet_internal (vm, a); diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c index 9894e3c8..335e3f9f 100644 --- a/src/vnet/ethernet/interface.c +++ b/src/vnet/ethernet/interface.c @@ -362,7 +362,7 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, u32 next_index = VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT; u32 i, next_node_index, bvi_flag, sw_if_index; u32 n_pkts = 0, n_bytes = 0; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; vnet_main_t *vnm = vnet_get_main (); vnet_interface_main_t *im = &vnm->interface_main; vlib_node_main_t *nm = &vm->node_main; @@ -420,8 +420,9 @@ simulated_ethernet_interface_tx (vlib_main_t * vm, /* increment TX interface stat */ vlib_increment_combined_counter (im->combined_sw_if_counters + - VNET_INTERFACE_COUNTER_TX, cpu_index, - sw_if_index, n_pkts, n_bytes); + VNET_INTERFACE_COUNTER_TX, + thread_index, sw_if_index, n_pkts, + n_bytes); } return n_left_from; diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index b699e381..f7787ed2 100755 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -291,7 +291,7 @@ ethernet_input_inline (vlib_main_t * vm, vlib_node_runtime_t *error_node; u32 n_left_from, next_index, *from, *to_next; u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 cached_sw_if_index = ~0; u32 cached_is_l2 = 0; /* shut up gcc */ vnet_hw_interface_t *hi = NULL; /* used for main interface only */ @@ -510,7 +510,7 @@ ethernet_input_inline (vlib_main_t * vm, interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, new_sw_if_index0, 1, len0); if (new_sw_if_index1 != old_sw_if_index1 @@ -519,7 +519,7 @@ ethernet_input_inline (vlib_main_t * vm, interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, new_sw_if_index1, 1, len1); @@ -530,7 +530,7 @@ ethernet_input_inline (vlib_main_t * vm, vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = stats_n_bytes = 0; @@ -696,13 +696,13 @@ ethernet_input_inline (vlib_main_t * vm, vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, new_sw_if_index0, 1, len0); + thread_index, new_sw_if_index0, 1, len0); if (stats_n_packets > 0) { vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = stats_n_bytes = 0; } @@ -734,7 +734,7 @@ ethernet_input_inline (vlib_main_t * vm, vlib_increment_combined_counter (vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); node->runtime_data[0] = stats_sw_if_index; } diff --git a/src/vnet/gre/node.c b/src/vnet/gre/node.c index 2683586e..acf15f24 100644 --- a/src/vnet/gre/node.c +++ b/src/vnet/gre/node.c @@ -75,7 +75,7 @@ gre_input (vlib_main_t * vm, u64 cached_tunnel_key6[4]; u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index = 0; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u32 len; vnet_interface_main_t *im = &gm->vnet_main->interface_main; @@ -257,7 +257,7 @@ gre_input (vlib_main_t * vm, len = vlib_buffer_length_in_chain (vm, b0); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, tunnel_sw_if_index, 1 /* packets */, len /* bytes */); @@ -324,7 +324,7 @@ drop0: len = vlib_buffer_length_in_chain (vm, b1); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, tunnel_sw_if_index, 1 /* packets */, len /* bytes */); @@ -502,7 +502,7 @@ drop1: len = vlib_buffer_length_in_chain (vm, b0); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, + thread_index, tunnel_sw_if_index, 1 /* packets */, len /* bytes */); diff --git a/src/vnet/interface.h b/src/vnet/interface.h index a1ea2d61..08f08b10 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -468,7 +468,7 @@ typedef struct vnet_hw_interface_t u32 input_node_index; /* input node cpu index by queue */ - u32 *input_node_cpu_index_by_queue; + u32 *input_node_thread_index_by_queue; } vnet_hw_interface_t; diff --git a/src/vnet/interface_output.c b/src/vnet/interface_output.c index 03f2cdca..663dc309 100644 --- a/src/vnet/interface_output.c +++ b/src/vnet/interface_output.c @@ -196,7 +196,7 @@ slow_path (vlib_main_t * vm, */ static_always_inline void incr_output_stats (vnet_main_t * vnm, - u32 cpu_index, + u32 thread_index, u32 length, u32 sw_if_index, u32 * last_sw_if_index, u32 * n_packets, u32 * n_bytes) @@ -216,7 +216,7 @@ incr_output_stats (vnet_main_t * vnm, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, + thread_index, *last_sw_if_index, *n_packets, *n_bytes); } @@ -240,7 +240,7 @@ vnet_interface_output_node_flatten (vlib_main_t * vm, u32 n_left_to_tx, *from, *from_end, *to_tx; u32 n_bytes, n_buffers, n_packets; u32 last_sw_if_index; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; n_buffers = frame->n_vectors; @@ -266,7 +266,7 @@ vnet_interface_output_node_flatten (vlib_main_t * vm, cm = vec_elt_at_index (vnm->interface_main.sw_if_counters, VNET_INTERFACE_COUNTER_TX_ERROR); - vlib_increment_simple_counter (cm, cpu_index, + vlib_increment_simple_counter (cm, thread_index, rt->sw_if_index, n_buffers); return vlib_error_drop_buffers (vm, node, from, /* buffer stride */ 1, @@ -341,18 +341,18 @@ vnet_interface_output_node_flatten (vlib_main_t * vm, from += 1; to_tx += n_buffers; n_left_to_tx -= n_buffers; - incr_output_stats (vnm, cpu_index, n_slow_bytes, + incr_output_stats (vnm, thread_index, n_slow_bytes, vnet_buffer (b)->sw_if_index[VLIB_TX], &last_sw_if_index, &n_packets, &n_bytes); } } else { - incr_output_stats (vnm, cpu_index, + incr_output_stats (vnm, thread_index, vlib_buffer_length_in_chain (vm, b0), vnet_buffer (b0)->sw_if_index[VLIB_TX], &last_sw_if_index, &n_packets, &n_bytes); - incr_output_stats (vnm, cpu_index, + incr_output_stats (vnm, thread_index, vlib_buffer_length_in_chain (vm, b0), vnet_buffer (b1)->sw_if_index[VLIB_TX], &last_sw_if_index, &n_packets, &n_bytes); @@ -396,7 +396,7 @@ vnet_interface_output_node_flatten (vlib_main_t * vm, to_tx += n_buffers; n_left_to_tx -= n_buffers; } - incr_output_stats (vnm, cpu_index, + incr_output_stats (vnm, thread_index, vlib_buffer_length_in_chain (vm, b0), vnet_buffer (b0)->sw_if_index[VLIB_TX], &last_sw_if_index, &n_packets, &n_bytes); @@ -408,7 +408,7 @@ vnet_interface_output_node_flatten (vlib_main_t * vm, } /* Final update of interface stats. */ - incr_output_stats (vnm, cpu_index, 0, ~0, /* ~0 will flush stats */ + incr_output_stats (vnm, thread_index, 0, ~0, /* ~0 will flush stats */ &last_sw_if_index, &n_packets, &n_bytes); return n_buffers; @@ -428,7 +428,7 @@ vnet_interface_output_node (vlib_main_t * vm, u32 n_left_to_tx, *from, *from_end, *to_tx; u32 n_bytes, n_buffers, n_packets; u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; vnet_interface_main_t *im = &vnm->interface_main; u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX; u32 current_config_index = ~0; @@ -458,7 +458,7 @@ vnet_interface_output_node (vlib_main_t * vm, cm = vec_elt_at_index (vnm->interface_main.sw_if_counters, VNET_INTERFACE_COUNTER_TX_ERROR); - vlib_increment_simple_counter (cm, cpu_index, + vlib_increment_simple_counter (cm, thread_index, rt->sw_if_index, n_buffers); return vlib_error_drop_buffers (vm, node, from, @@ -558,7 +558,7 @@ vnet_interface_output_node (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, tx_swif0, 1, + thread_index, tx_swif0, 1, n_bytes_b0); } @@ -567,7 +567,7 @@ vnet_interface_output_node (vlib_main_t * vm, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, tx_swif1, 1, + thread_index, tx_swif1, 1, n_bytes_b1); } @@ -576,7 +576,7 @@ vnet_interface_output_node (vlib_main_t * vm, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, tx_swif2, 1, + thread_index, tx_swif2, 1, n_bytes_b2); } if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index)) @@ -584,7 +584,7 @@ vnet_interface_output_node (vlib_main_t * vm, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, tx_swif3, 1, + thread_index, tx_swif3, 1, n_bytes_b3); } } @@ -623,7 +623,7 @@ vnet_interface_output_node (vlib_main_t * vm, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, tx_swif0, 1, + thread_index, tx_swif0, 1, n_bytes_b0); } } @@ -634,7 +634,7 @@ vnet_interface_output_node (vlib_main_t * vm, /* Update main interface stats. */ vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, + thread_index, rt->sw_if_index, n_packets, n_bytes); return n_buffers; } @@ -893,7 +893,7 @@ process_drop_punt (vlib_main_t * vm, u32 current_sw_if_index, n_errors_current_sw_if_index; u64 current_counter; vlib_simple_counter_main_t *cm; - u32 cpu_index = vm->cpu_index; + u32 thread_index = vm->thread_index; static vlib_error_t memory[VNET_ERROR_N_DISPOSITION]; static char memory_init[VNET_ERROR_N_DISPOSITION]; @@ -965,19 +965,19 @@ process_drop_punt (vlib_main_t * vm, current_counter -= 2; n_errors_current_sw_if_index -= 2; - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1); /* Increment super-interface drop/punt counters for sub-interfaces. */ sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0); vlib_increment_simple_counter - (cm, cpu_index, sw_if0->sup_sw_if_index, + (cm, thread_index, sw_if0->sup_sw_if_index, sw_if0->sup_sw_if_index != sw_if_index0); sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1); vlib_increment_simple_counter - (cm, cpu_index, sw_if1->sup_sw_if_index, + (cm, thread_index, sw_if1->sup_sw_if_index, sw_if1->sup_sw_if_index != sw_if_index1); em->counters[current_counter_index] = current_counter; @@ -1013,11 +1013,12 @@ process_drop_punt (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; /* Increment drop/punt counters. */ - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); /* Increment super-interface drop/punt counters for sub-interfaces. */ sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0); - vlib_increment_simple_counter (cm, cpu_index, sw_if0->sup_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, + sw_if0->sup_sw_if_index, sw_if0->sup_sw_if_index != sw_if_index0); if (PREDICT_FALSE (e0 != current_error)) @@ -1041,12 +1042,12 @@ process_drop_punt (vlib_main_t * vm, { vnet_sw_interface_t *si; - vlib_increment_simple_counter (cm, cpu_index, current_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, current_sw_if_index, n_errors_current_sw_if_index); si = vnet_get_sw_interface (vnm, current_sw_if_index); if (si->sup_sw_if_index != current_sw_if_index) - vlib_increment_simple_counter (cm, cpu_index, si->sup_sw_if_index, + vlib_increment_simple_counter (cm, thread_index, si->sup_sw_if_index, n_errors_current_sw_if_index); } diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index ee1703e7..fdfe7f63 100644 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -75,7 +75,7 @@ ip4_lookup_inline (vlib_main_t * vm, vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters; u32 n_left_from, n_left_to_next, *from, *to_next; ip_lookup_next_t next; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -292,19 +292,19 @@ ip4_lookup_inline (vlib_main_t * vm, vnet_buffer (p3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lb_index0, 1, + (cm, thread_index, lb_index0, 1, vlib_buffer_length_in_chain (vm, p0) + sizeof (ethernet_header_t)); vlib_increment_combined_counter - (cm, cpu_index, lb_index1, 1, + (cm, thread_index, lb_index1, 1, vlib_buffer_length_in_chain (vm, p1) + sizeof (ethernet_header_t)); vlib_increment_combined_counter - (cm, cpu_index, lb_index2, 1, + (cm, thread_index, lb_index2, 1, vlib_buffer_length_in_chain (vm, p2) + sizeof (ethernet_header_t)); vlib_increment_combined_counter - (cm, cpu_index, lb_index3, 1, + (cm, thread_index, lb_index3, 1, vlib_buffer_length_in_chain (vm, p3) + sizeof (ethernet_header_t)); @@ -392,7 +392,7 @@ ip4_lookup_inline (vlib_main_t * vm, vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); from += 1; to_next += 1; @@ -479,7 +479,7 @@ ip4_load_balance (vlib_main_t * vm, vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters; u32 n_left_from, n_left_to_next, *from, *to_next; ip_lookup_next_t next; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -584,9 +584,9 @@ ip4_load_balance (vlib_main_t * vm, vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); vlib_validate_buffer_enqueue_x2 (vm, node, next, to_next, n_left_to_next, @@ -639,7 +639,7 @@ ip4_load_balance (vlib_main_t * vm, vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next, n_left_to_next, @@ -2330,7 +2330,7 @@ ip4_rewrite_inline (vlib_main_t * vm, n_left_from = frame->n_vectors; next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -2379,9 +2379,9 @@ ip4_rewrite_inline (vlib_main_t * vm, if (do_counters) { vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index0); + thread_index, adj_index0); vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index1); + thread_index, adj_index1); } ip0 = vlib_buffer_get_current (p0); @@ -2527,13 +2527,13 @@ ip4_rewrite_inline (vlib_main_t * vm, { vlib_increment_combined_counter (&adjacency_counters, - cpu_index, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); vlib_increment_combined_counter (&adjacency_counters, - cpu_index, + thread_index, adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1); } @@ -2618,7 +2618,7 @@ ip4_rewrite_inline (vlib_main_t * vm, if (do_counters) vlib_prefetch_combined_counter (&adjacency_counters, - cpu_index, adj_index0); + thread_index, adj_index0); /* Guess we are only writing on simple Ethernet header. */ vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t)); @@ -2637,7 +2637,7 @@ ip4_rewrite_inline (vlib_main_t * vm, if (do_counters) vlib_increment_combined_counter (&adjacency_counters, - cpu_index, adj_index0, 1, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); /* Check MTU of outgoing interface. */ diff --git a/src/vnet/ip/ip4_input.c b/src/vnet/ip/ip4_input.c index ba200a9f..3b08f4b0 100644 --- a/src/vnet/ip/ip4_input.c +++ b/src/vnet/ip/ip4_input.c @@ -85,7 +85,7 @@ ip4_input_inline (vlib_main_t * vm, vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, ip4_input_node.index); vlib_simple_counter_main_t *cm; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -178,8 +178,8 @@ ip4_input_inline (vlib_main_t * vm, vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0); vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1); /* Punt packets with options or wrong version. */ if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45)) @@ -299,7 +299,7 @@ ip4_input_inline (vlib_main_t * vm, vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0; vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); /* Punt packets with options or wrong version. */ if (PREDICT_FALSE (ip0->ip_version_and_header_length != 0x45)) diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index c120f12c..c2fc4f87 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -74,7 +74,7 @@ ip6_lookup_inline (vlib_main_t * vm, vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters; u32 n_left_from, n_left_to_next, *from, *to_next; ip_lookup_next_t next; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -185,9 +185,9 @@ ip6_lookup_inline (vlib_main_t * vm, vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); from += 2; to_next += 2; @@ -291,7 +291,7 @@ ip6_lookup_inline (vlib_main_t * vm, vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); from += 1; to_next += 1; @@ -703,7 +703,7 @@ ip6_load_balance (vlib_main_t * vm, vlib_combined_counter_main_t *cm = &load_balance_main.lbm_via_counters; u32 n_left_from, n_left_to_next, *from, *to_next; ip_lookup_next_t next; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); ip6_main_t *im = &ip6_main; from = vlib_frame_vector_args (frame); @@ -824,9 +824,9 @@ ip6_load_balance (vlib_main_t * vm, vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); vlib_validate_buffer_enqueue_x2 (vm, node, next, to_next, n_left_to_next, @@ -886,7 +886,7 @@ ip6_load_balance (vlib_main_t * vm, } vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next, n_left_to_next, @@ -1897,7 +1897,7 @@ ip6_rewrite_inline (vlib_main_t * vm, n_left_from = frame->n_vectors; next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -2019,11 +2019,11 @@ ip6_rewrite_inline (vlib_main_t * vm, { vlib_increment_combined_counter (&adjacency_counters, - cpu_index, adj_index0, 1, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); vlib_increment_combined_counter (&adjacency_counters, - cpu_index, adj_index1, 1, + thread_index, adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1); } @@ -2156,7 +2156,7 @@ ip6_rewrite_inline (vlib_main_t * vm, { vlib_increment_combined_counter (&adjacency_counters, - cpu_index, adj_index0, 1, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); } diff --git a/src/vnet/ip/ip6_input.c b/src/vnet/ip/ip6_input.c index 20306088..ffdc4727 100644 --- a/src/vnet/ip/ip6_input.c +++ b/src/vnet/ip/ip6_input.c @@ -82,7 +82,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, ip6_input_node.index); vlib_simple_counter_main_t *cm; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -171,8 +171,8 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0); vnet_feature_arc_start (arc1, sw_if_index1, &next1, p1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1); error0 = error1 = IP6_ERROR_NONE; @@ -270,7 +270,7 @@ ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vnet_buffer (p0)->ip.adj_index[VLIB_RX] = ~0; vnet_feature_arc_start (arc0, sw_if_index0, &next0, p0); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); error0 = IP6_ERROR_NONE; /* Version != 6? Drop it. */ diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 5d1fb6f8..2af546df 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -581,7 +581,7 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, u32 next_index; pending_resolution_t *pr, *mc; - if (os_get_cpu_number ()) + if (vlib_get_thread_index ()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, 1 /* set new neighbor */ , is_static, @@ -722,7 +722,7 @@ vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, uword *p; int rv = 0; - if (os_get_cpu_number ()) + if (vlib_get_thread_index ()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, 0 /* unset */ , 0, 0); diff --git a/src/vnet/ipsec/esp.h b/src/vnet/ipsec/esp.h index 50cac806..799003b9 100644 --- a/src/vnet/ipsec/esp.h +++ b/src/vnet/ipsec/esp.h @@ -282,8 +282,8 @@ hmac_calc (ipsec_integ_alg_t alg, u8 * data, int data_len, u8 * signature, u8 use_esn, u32 seq_hi) { esp_main_t *em = &esp_main; - u32 cpu_index = os_get_cpu_number (); - HMAC_CTX *ctx = &(em->per_thread_data[cpu_index].hmac_ctx); + u32 thread_index = vlib_get_thread_index (); + HMAC_CTX *ctx = &(em->per_thread_data[thread_index].hmac_ctx); const EVP_MD *md = NULL; unsigned int len; @@ -292,10 +292,10 @@ hmac_calc (ipsec_integ_alg_t alg, if (PREDICT_FALSE (em->esp_integ_algs[alg].md == 0)) return 0; - if (PREDICT_FALSE (alg != em->per_thread_data[cpu_index].last_integ_alg)) + if (PREDICT_FALSE (alg != em->per_thread_data[thread_index].last_integ_alg)) { md = em->esp_integ_algs[alg].md; - em->per_thread_data[cpu_index].last_integ_alg = alg; + em->per_thread_data[thread_index].last_integ_alg = alg; } HMAC_Init (ctx, key, key_len, md); diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c index 7289b260..925d2b45 100644 --- a/src/vnet/ipsec/esp_decrypt.c +++ b/src/vnet/ipsec/esp_decrypt.c @@ -85,8 +85,8 @@ esp_decrypt_aes_cbc (ipsec_crypto_alg_t alg, u8 * in, u8 * out, size_t in_len, u8 * key, u8 * iv) { esp_main_t *em = &esp_main; - u32 cpu_index = os_get_cpu_number (); - EVP_CIPHER_CTX *ctx = &(em->per_thread_data[cpu_index].decrypt_ctx); + u32 thread_index = vlib_get_thread_index (); + EVP_CIPHER_CTX *ctx = &(em->per_thread_data[thread_index].decrypt_ctx); const EVP_CIPHER *cipher = NULL; int out_len; @@ -95,10 +95,11 @@ esp_decrypt_aes_cbc (ipsec_crypto_alg_t alg, if (PREDICT_FALSE (em->esp_crypto_algs[alg].type == 0)) return; - if (PREDICT_FALSE (alg != em->per_thread_data[cpu_index].last_decrypt_alg)) + if (PREDICT_FALSE + (alg != em->per_thread_data[thread_index].last_decrypt_alg)) { cipher = em->esp_crypto_algs[alg].type; - em->per_thread_data[cpu_index].last_decrypt_alg = alg; + em->per_thread_data[thread_index].last_decrypt_alg = alg; } EVP_DecryptInit_ex (ctx, cipher, NULL, key, iv); @@ -117,11 +118,11 @@ esp_decrypt_node_fn (vlib_main_t * vm, u32 *recycle = 0; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); ipsec_alloc_empty_buffers (vm, im); - u32 *empty_buffers = im->empty_buffers[cpu_index]; + u32 *empty_buffers = im->empty_buffers[thread_index]; if (PREDICT_FALSE (vec_len (empty_buffers) < n_left_from)) { diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index 44ae2297..b2bc4e0b 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -88,8 +88,8 @@ esp_encrypt_aes_cbc (ipsec_crypto_alg_t alg, u8 * in, u8 * out, size_t in_len, u8 * key, u8 * iv) { esp_main_t *em = &esp_main; - u32 cpu_index = os_get_cpu_number (); - EVP_CIPHER_CTX *ctx = &(em->per_thread_data[cpu_index].encrypt_ctx); + u32 thread_index = vlib_get_thread_index (); + EVP_CIPHER_CTX *ctx = &(em->per_thread_data[thread_index].encrypt_ctx); const EVP_CIPHER *cipher = NULL; int out_len; @@ -98,10 +98,11 @@ esp_encrypt_aes_cbc (ipsec_crypto_alg_t alg, if (PREDICT_FALSE (em->esp_crypto_algs[alg].type == IPSEC_CRYPTO_ALG_NONE)) return; - if (PREDICT_FALSE (alg != em->per_thread_data[cpu_index].last_encrypt_alg)) + if (PREDICT_FALSE + (alg != em->per_thread_data[thread_index].last_encrypt_alg)) { cipher = em->esp_crypto_algs[alg].type; - em->per_thread_data[cpu_index].last_encrypt_alg = alg; + em->per_thread_data[thread_index].last_encrypt_alg = alg; } EVP_EncryptInit_ex (ctx, cipher, NULL, key, iv); @@ -119,11 +120,11 @@ esp_encrypt_node_fn (vlib_main_t * vm, n_left_from = from_frame->n_vectors; ipsec_main_t *im = &ipsec_main; u32 *recycle = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); ipsec_alloc_empty_buffers (vm, im); - u32 *empty_buffers = im->empty_buffers[cpu_index]; + u32 *empty_buffers = im->empty_buffers[thread_index]; if (PREDICT_FALSE (vec_len (empty_buffers) < n_left_from)) { diff --git a/src/vnet/ipsec/ikev2.c b/src/vnet/ipsec/ikev2.c index 2c1074d8..3f9978a7 100644 --- a/src/vnet/ipsec/ikev2.c +++ b/src/vnet/ipsec/ikev2.c @@ -303,16 +303,16 @@ static void ikev2_delete_sa (ikev2_sa_t * sa) { ikev2_main_t *km = &ikev2_main; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); uword *p; ikev2_sa_free_all_vec (sa); - p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi, sa->rspi); + p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi); if (p) { - hash_unset (km->per_thread_data[cpu_index].sa_by_rspi, sa->rspi); - pool_put (km->per_thread_data[cpu_index].sas, sa); + hash_unset (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi); + pool_put (km->per_thread_data[thread_index].sas, sa); } } @@ -776,29 +776,31 @@ ikev2_initial_contact_cleanup (ikev2_sa_t * sa) ikev2_sa_t *tmp; u32 i, *delete = 0; ikev2_child_sa_t *c; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); if (!sa->initial_contact) return; /* find old IKE SAs with the same authenticated identity */ /* *INDENT-OFF* */ - pool_foreach (tmp, km->per_thread_data[cpu_index].sas, ({ + pool_foreach (tmp, km->per_thread_data[thread_index].sas, ({ if (tmp->i_id.type != sa->i_id.type || vec_len(tmp->i_id.data) != vec_len(sa->i_id.data) || memcmp(sa->i_id.data, tmp->i_id.data, vec_len(sa->i_id.data))) continue; if (sa->rspi != tmp->rspi) - vec_add1(delete, tmp - km->per_thread_data[cpu_index].sas); + vec_add1(delete, tmp - km->per_thread_data[thread_index].sas); })); /* *INDENT-ON* */ for (i = 0; i < vec_len (delete); i++) { - tmp = pool_elt_at_index (km->per_thread_data[cpu_index].sas, delete[i]); - vec_foreach (c, tmp->childs) - ikev2_delete_tunnel_interface (km->vnet_main, tmp, c); + tmp = + pool_elt_at_index (km->per_thread_data[thread_index].sas, delete[i]); + vec_foreach (c, + tmp->childs) ikev2_delete_tunnel_interface (km->vnet_main, + tmp, c); ikev2_delete_sa (tmp); } @@ -1922,10 +1924,10 @@ ikev2_retransmit_sa_init (ike_header_t * ike, { ikev2_main_t *km = &ikev2_main; ikev2_sa_t *sa; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); /* *INDENT-OFF* */ - pool_foreach (sa, km->per_thread_data[cpu_index].sas, ({ + pool_foreach (sa, km->per_thread_data[thread_index].sas, ({ if (sa->ispi == clib_net_to_host_u64(ike->ispi) && sa->iaddr.as_u32 == iaddr.as_u32 && sa->raddr.as_u32 == raddr.as_u32) @@ -2036,7 +2038,7 @@ ikev2_node_fn (vlib_main_t * vm, u32 n_left_from, *from, *to_next; ikev2_next_t next_index; ikev2_main_t *km = &ikev2_main; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -2134,11 +2136,14 @@ ikev2_node_fn (vlib_main_t * vm, if (sa0->state == IKEV2_STATE_SA_INIT) { /* add SA to the pool */ - pool_get (km->per_thread_data[cpu_index].sas, sa0); + pool_get (km->per_thread_data[thread_index].sas, + sa0); clib_memcpy (sa0, &sa, sizeof (*sa0)); - hash_set (km->per_thread_data[cpu_index].sa_by_rspi, + hash_set (km-> + per_thread_data[thread_index].sa_by_rspi, sa0->rspi, - sa0 - km->per_thread_data[cpu_index].sas); + sa0 - + km->per_thread_data[thread_index].sas); } else { @@ -2169,11 +2174,11 @@ ikev2_node_fn (vlib_main_t * vm, if (sa0->state == IKEV2_STATE_SA_INIT) { /* add SA to the pool */ - pool_get (km->per_thread_data[cpu_index].sas, sa0); + pool_get (km->per_thread_data[thread_index].sas, sa0); clib_memcpy (sa0, &sa, sizeof (*sa0)); - hash_set (km->per_thread_data[cpu_index].sa_by_rspi, + hash_set (km->per_thread_data[thread_index].sa_by_rspi, sa0->rspi, - sa0 - km->per_thread_data[cpu_index].sas); + sa0 - km->per_thread_data[thread_index].sas); } else { @@ -2184,12 +2189,13 @@ ikev2_node_fn (vlib_main_t * vm, else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH) { uword *p; - p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi, + p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); if (p) { - sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas, - p[0]); + sa0 = + pool_elt_at_index (km->per_thread_data[thread_index].sas, + p[0]); r = ikev2_retransmit_resp (sa0, ike0); if (r == 1) @@ -2240,12 +2246,13 @@ ikev2_node_fn (vlib_main_t * vm, else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL) { uword *p; - p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi, + p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); if (p) { - sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas, - p[0]); + sa0 = + pool_elt_at_index (km->per_thread_data[thread_index].sas, + p[0]); r = ikev2_retransmit_resp (sa0, ike0); if (r == 1) @@ -2305,12 +2312,13 @@ ikev2_node_fn (vlib_main_t * vm, else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) { uword *p; - p = hash_get (km->per_thread_data[cpu_index].sa_by_rspi, + p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, clib_net_to_host_u64 (ike0->rspi)); if (p) { - sa0 = pool_elt_at_index (km->per_thread_data[cpu_index].sas, - p[0]); + sa0 = + pool_elt_at_index (km->per_thread_data[thread_index].sas, + p[0]); r = ikev2_retransmit_resp (sa0, ike0); if (r == 1) diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 58f0f145..c884e360 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -324,21 +324,21 @@ int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, always_inline void ipsec_alloc_empty_buffers (vlib_main_t * vm, ipsec_main_t * im) { - u32 cpu_index = os_get_cpu_number (); - uword l = vec_len (im->empty_buffers[cpu_index]); + u32 thread_index = vlib_get_thread_index (); + uword l = vec_len (im->empty_buffers[thread_index]); uword n_alloc = 0; if (PREDICT_FALSE (l < VLIB_FRAME_SIZE)) { - if (!im->empty_buffers[cpu_index]) + if (!im->empty_buffers[thread_index]) { - vec_alloc (im->empty_buffers[cpu_index], 2 * VLIB_FRAME_SIZE); + vec_alloc (im->empty_buffers[thread_index], 2 * VLIB_FRAME_SIZE); } - n_alloc = vlib_buffer_alloc (vm, im->empty_buffers[cpu_index] + l, + n_alloc = vlib_buffer_alloc (vm, im->empty_buffers[thread_index] + l, 2 * VLIB_FRAME_SIZE - l); - _vec_len (im->empty_buffers[cpu_index]) = l + n_alloc; + _vec_len (im->empty_buffers[thread_index]) = l + n_alloc; } } diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index dc882004..ed124894 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -99,7 +99,7 @@ static int ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a) { vnet_main_t *vnm = vnet_get_main (); - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); return ipsec_add_del_tunnel_if_internal (vnm, a); } diff --git a/src/vnet/l2/l2_bvi.h b/src/vnet/l2/l2_bvi.h index dd1130a6..e21a1616 100644 --- a/src/vnet/l2/l2_bvi.h +++ b/src/vnet/l2/l2_bvi.h @@ -97,7 +97,7 @@ l2_to_bvi (vlib_main_t * vlib_main, vlib_increment_combined_counter (vnet_main->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - vlib_main->cpu_index, + vlib_main->thread_index, vnet_buffer (b0)->sw_if_index[VLIB_RX], 1, vlib_buffer_length_in_chain (vlib_main, b0)); return TO_BVI_ERR_OK; diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 041ff38d..e5d6878a 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -117,7 +117,7 @@ typedef enum static_always_inline void classify_and_dispatch (vlib_main_t * vm, vlib_node_runtime_t * node, - u32 cpu_index, + u32 thread_index, l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) { /* @@ -237,7 +237,7 @@ l2input_node_inline (vlib_main_t * vm, u32 n_left_from, *from, *to_next; l2input_next_t next_index; l2input_main_t *msm = &l2input_main; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; /* number of packets to process */ @@ -350,10 +350,10 @@ l2input_node_inline (vlib_main_t * vm, vlib_node_increment_counter (vm, l2input_node.index, L2INPUT_ERROR_L2INPUT, 4); - classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0); - classify_and_dispatch (vm, node, cpu_index, msm, b1, &next1); - classify_and_dispatch (vm, node, cpu_index, msm, b2, &next2); - classify_and_dispatch (vm, node, cpu_index, msm, b3, &next3); + classify_and_dispatch (vm, node, thread_index, msm, b0, &next0); + classify_and_dispatch (vm, node, thread_index, msm, b1, &next1); + classify_and_dispatch (vm, node, thread_index, msm, b2, &next2); + classify_and_dispatch (vm, node, thread_index, msm, b3, &next3); /* verify speculative enqueues, maybe switch current next frame */ /* if next0==next1==next_index then nothing special needs to be done */ @@ -393,7 +393,7 @@ l2input_node_inline (vlib_main_t * vm, vlib_node_increment_counter (vm, l2input_node.index, L2INPUT_ERROR_L2INPUT, 1); - classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0); + classify_and_dispatch (vm, node, thread_index, msm, b0, &next0); /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index 00f22571..e17b2a16 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -643,11 +643,11 @@ l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index); - uword cpu_number; + uword thread_index; - cpu_number = os_get_cpu_number (); + thread_index = vlib_get_thread_index (); - if (cpu_number) + if (thread_index) { u32 oldflags; diff --git a/src/vnet/l2tp/decap.c b/src/vnet/l2tp/decap.c index e8986935..46104129 100644 --- a/src/vnet/l2tp/decap.c +++ b/src/vnet/l2tp/decap.c @@ -149,7 +149,7 @@ last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, u32 bi) /* per-mapping byte stats include the ethernet header */ vlib_increment_combined_counter (&lm->counter_main, - os_get_cpu_number (), + vlib_get_thread_index (), counter_index, 1 /* packet_increment */ , vlib_buffer_length_in_chain (vm, b) + sizeof (ethernet_header_t)); diff --git a/src/vnet/l2tp/encap.c b/src/vnet/l2tp/encap.c index ed7a9580..dcdfde4b 100644 --- a/src/vnet/l2tp/encap.c +++ b/src/vnet/l2tp/encap.c @@ -124,7 +124,7 @@ last_stage (vlib_main_t * vm, vlib_node_runtime_t * node, u32 bi) /* per-mapping byte stats include the ethernet header */ vlib_increment_combined_counter (&lm->counter_main, - os_get_cpu_number (), + vlib_get_thread_index (), counter_index, 1 /* packet_increment */ , vlib_buffer_length_in_chain (vm, b)); diff --git a/src/vnet/l2tp/l2tp.c b/src/vnet/l2tp/l2tp.c index cb94d7e7..3dedc447 100644 --- a/src/vnet/l2tp/l2tp.c +++ b/src/vnet/l2tp/l2tp.c @@ -157,7 +157,7 @@ test_counters_command_fn (vlib_main_t * vm, u32 session_index; u32 counter_index; u32 nincr = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); /* *INDENT-OFF* */ pool_foreach (session, lm->sessions, @@ -167,11 +167,11 @@ test_counters_command_fn (vlib_main_t * vm, session_index_to_counter_index (session_index, SESSION_COUNTER_USER_TO_NETWORK); vlib_increment_combined_counter (&lm->counter_main, - cpu_index, + thread_index, counter_index, 1/*pkt*/, 1111 /*bytes*/); vlib_increment_combined_counter (&lm->counter_main, - cpu_index, + thread_index, counter_index+1, 1/*pkt*/, 2222 /*bytes*/); nincr++; diff --git a/src/vnet/lisp-gpe/decap.c b/src/vnet/lisp-gpe/decap.c index d887a95f..68769710 100644 --- a/src/vnet/lisp-gpe/decap.c +++ b/src/vnet/lisp-gpe/decap.c @@ -103,7 +103,7 @@ next_index_to_iface (lisp_gpe_main_t * lgm, u32 next_index) } static_always_inline void -incr_decap_stats (vnet_main_t * vnm, u32 cpu_index, u32 length, +incr_decap_stats (vnet_main_t * vnm, u32 thread_index, u32 length, u32 sw_if_index, u32 * last_sw_if_index, u32 * n_packets, u32 * n_bytes) { @@ -122,7 +122,7 @@ incr_decap_stats (vnet_main_t * vnm, u32 cpu_index, u32 length, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, *last_sw_if_index, + thread_index, *last_sw_if_index, *n_packets, *n_bytes); } *last_sw_if_index = sw_if_index; @@ -150,11 +150,11 @@ static uword lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, u8 is_v4) { - u32 n_left_from, next_index, *from, *to_next, cpu_index; + u32 n_left_from, next_index, *from, *to_next, thread_index; u32 n_bytes = 0, n_packets = 0, last_sw_if_index = ~0, drops = 0; lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main (); - cpu_index = os_get_cpu_number (); + thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -267,7 +267,7 @@ lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (si0) { - incr_decap_stats (lgm->vnet_main, cpu_index, + incr_decap_stats (lgm->vnet_main, thread_index, vlib_buffer_length_in_chain (vm, b0), si0[0], &last_sw_if_index, &n_packets, &n_bytes); vnet_buffer (b0)->sw_if_index[VLIB_RX] = si0[0]; @@ -282,7 +282,7 @@ lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (si1) { - incr_decap_stats (lgm->vnet_main, cpu_index, + incr_decap_stats (lgm->vnet_main, thread_index, vlib_buffer_length_in_chain (vm, b1), si1[0], &last_sw_if_index, &n_packets, &n_bytes); vnet_buffer (b1)->sw_if_index[VLIB_RX] = si1[0]; @@ -397,7 +397,7 @@ lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (si0) { - incr_decap_stats (lgm->vnet_main, cpu_index, + incr_decap_stats (lgm->vnet_main, thread_index, vlib_buffer_length_in_chain (vm, b0), si0[0], &last_sw_if_index, &n_packets, &n_bytes); vnet_buffer (b0)->sw_if_index[VLIB_RX] = si0[0]; @@ -430,7 +430,7 @@ lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } /* flush iface stats */ - incr_decap_stats (lgm->vnet_main, cpu_index, 0, ~0, &last_sw_if_index, + incr_decap_stats (lgm->vnet_main, thread_index, 0, ~0, &last_sw_if_index, &n_packets, &n_bytes); vlib_node_increment_counter (vm, lisp_gpe_ip4_input_node.index, LISP_GPE_ERROR_NO_TUNNEL, drops); diff --git a/src/vnet/lldp/lldp_input.c b/src/vnet/lldp/lldp_input.c index 762743d0..e88f6fdb 100644 --- a/src/vnet/lldp/lldp_input.c +++ b/src/vnet/lldp/lldp_input.c @@ -35,7 +35,7 @@ typedef struct static void lldp_rpc_update_peer_cb (const lldp_intf_update_t * a) { - ASSERT (os_get_cpu_number () == 0); + ASSERT (vlib_get_thread_index () == 0); lldp_intf_t *n = lldp_get_intf (&lldp_main, a->hw_if_index); if (!n) diff --git a/src/vnet/map/ip4_map.c b/src/vnet/map/ip4_map.c index 1a20d704..e39b6f14 100644 --- a/src/vnet/map/ip4_map.c +++ b/src/vnet/map/ip4_map.c @@ -248,7 +248,7 @@ ip4_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) next_index = node->cached_next_index; map_main_t *mm = &map_main; vlib_combined_counter_main_t *cm = mm->domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -377,7 +377,7 @@ ip4_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip40) ? IP4_MAP_NEXT_IP6_REWRITE : next0; vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, map_domain_index0, 1, clib_net_to_host_u16 (ip6h0->payload_length) + @@ -409,7 +409,7 @@ ip4_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip41) ? IP4_MAP_NEXT_IP6_REWRITE : next1; vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, map_domain_index1, 1, clib_net_to_host_u16 (ip6h1->payload_length) + @@ -520,7 +520,7 @@ ip4_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip40) ? IP4_MAP_NEXT_IP6_REWRITE : next0; vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, map_domain_index0, 1, clib_net_to_host_u16 (ip6h0->payload_length) + @@ -564,7 +564,7 @@ ip4_map_reass (vlib_main_t * vm, next_index = node->cached_next_index; map_main_t *mm = &map_main; vlib_combined_counter_main_t *cm = mm->domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 *fragments_to_drop = NULL; u32 *fragments_to_loopback = NULL; @@ -694,8 +694,8 @@ ip4_map_reass (vlib_main_t * vm, { if (error0 == MAP_ERROR_NONE) vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, map_domain_index0, - 1, + thread_index, + map_domain_index0, 1, clib_net_to_host_u16 (ip60->payload_length) + 40); next0 = diff --git a/src/vnet/map/ip4_map_t.c b/src/vnet/map/ip4_map_t.c index b63d76bf..5f2bcbf9 100644 --- a/src/vnet/map/ip4_map_t.c +++ b/src/vnet/map/ip4_map_t.c @@ -477,7 +477,7 @@ ip4_map_t_icmp (vlib_main_t * vm, n_left_from = frame->n_vectors; next_index = node->cached_next_index; vlib_combined_counter_main_t *cm = map_main.domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -520,7 +520,7 @@ ip4_map_t_icmp (vlib_main_t * vm, if (PREDICT_TRUE (error0 == MAP_ERROR_NONE)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, vnet_buffer (p0)->map_t. map_domain_index, 1, len0); } @@ -1051,7 +1051,7 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) n_left_from = frame->n_vectors; next_index = node->cached_next_index; vlib_combined_counter_main_t *cm = map_main.domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -1158,7 +1158,7 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error0 == MAP_ERROR_NONE && next0 != IP4_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, vnet_buffer (p0)->map_t. map_domain_index, 1, clib_net_to_host_u16 (ip40-> @@ -1169,7 +1169,7 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error1 == MAP_ERROR_NONE && next1 != IP4_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, vnet_buffer (p1)->map_t. map_domain_index, 1, clib_net_to_host_u16 (ip41-> @@ -1252,7 +1252,7 @@ ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error0 == MAP_ERROR_NONE && next0 != IP4_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX, - cpu_index, + thread_index, vnet_buffer (p0)->map_t. map_domain_index, 1, clib_net_to_host_u16 (ip40-> diff --git a/src/vnet/map/ip6_map.c b/src/vnet/map/ip6_map.c index f7eb768f..63ada962 100644 --- a/src/vnet/map/ip6_map.c +++ b/src/vnet/map/ip6_map.c @@ -172,7 +172,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vlib_node_get_runtime (vm, ip6_map_node.index); map_main_t *mm = &map_main; vlib_combined_counter_main_t *cm = mm->domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -319,7 +319,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) IP6_MAP_NEXT_IP4_REWRITE : next0; } vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, map_domain_index0, 1, clib_net_to_host_u16 (ip40->length)); @@ -352,7 +352,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) IP6_MAP_NEXT_IP4_REWRITE : next1; } vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, map_domain_index1, 1, clib_net_to_host_u16 (ip41->length)); @@ -505,7 +505,7 @@ ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) IP6_MAP_NEXT_IP4_REWRITE : next0; } vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, map_domain_index0, 1, clib_net_to_host_u16 (ip40->length)); @@ -820,7 +820,7 @@ ip6_map_ip4_reass (vlib_main_t * vm, vlib_node_get_runtime (vm, ip6_map_ip4_reass_node.index); map_main_t *mm = &map_main; vlib_combined_counter_main_t *cm = mm->domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 *fragments_to_drop = NULL; u32 *fragments_to_loopback = NULL; @@ -958,8 +958,8 @@ ip6_map_ip4_reass (vlib_main_t * vm, { if (error0 == MAP_ERROR_NONE) vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, map_domain_index0, - 1, + thread_index, + map_domain_index0, 1, clib_net_to_host_u16 (ip40->length)); next0 = @@ -1015,7 +1015,7 @@ ip6_map_icmp_relay (vlib_main_t * vm, vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, ip6_map_icmp_relay_node.index); map_main_t *mm = &map_main; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u16 *fragment_ids, *fid; from = vlib_frame_vector_args (frame); @@ -1143,7 +1143,8 @@ ip6_map_icmp_relay (vlib_main_t * vm, ip_csum_t sum = ip_incremental_checksum (0, new_icmp40, nlen - 20); new_icmp40->checksum = ~ip_csum_fold (sum); - vlib_increment_simple_counter (&mm->icmp_relayed, cpu_index, 0, 1); + vlib_increment_simple_counter (&mm->icmp_relayed, thread_index, 0, + 1); error: if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) diff --git a/src/vnet/map/ip6_map_t.c b/src/vnet/map/ip6_map_t.c index eb3996c2..99151678 100644 --- a/src/vnet/map/ip6_map_t.c +++ b/src/vnet/map/ip6_map_t.c @@ -448,7 +448,7 @@ ip6_map_t_icmp (vlib_main_t * vm, n_left_from = frame->n_vectors; next_index = node->cached_next_index; vlib_combined_counter_main_t *cm = map_main.domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -493,7 +493,7 @@ ip6_map_t_icmp (vlib_main_t * vm, if (PREDICT_TRUE (error0 == MAP_ERROR_NONE)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, vnet_buffer (p0)-> map_t.map_domain_index, 1, len0); @@ -1051,7 +1051,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) vlib_node_runtime_t *error_node = vlib_node_get_runtime (vm, ip6_map_t_node.index); vlib_combined_counter_main_t *cm = map_main.domain_counters; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -1218,7 +1218,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error0 == MAP_ERROR_NONE && next0 != IP6_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, vnet_buffer (p0)-> map_t.map_domain_index, 1, clib_net_to_host_u16 @@ -1229,7 +1229,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error1 == MAP_ERROR_NONE && next1 != IP6_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, vnet_buffer (p1)-> map_t.map_domain_index, 1, clib_net_to_host_u16 @@ -1403,7 +1403,7 @@ ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) (error0 == MAP_ERROR_NONE && next0 != IP6_MAPT_NEXT_MAPT_ICMP)) { vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX, - cpu_index, + thread_index, vnet_buffer (p0)-> map_t.map_domain_index, 1, clib_net_to_host_u16 diff --git a/src/vnet/mpls/mpls_input.c b/src/vnet/mpls/mpls_input.c index 893c4511..1b9bdd05 100644 --- a/src/vnet/mpls/mpls_input.c +++ b/src/vnet/mpls/mpls_input.c @@ -76,7 +76,7 @@ mpls_input_inline (vlib_main_t * vm, u32 n_left_from, next_index, * from, * to_next; mpls_input_runtime_t * rt; mpls_main_t * mm; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); vlib_simple_counter_main_t * cm; vnet_main_t * vnm = vnet_get_main(); @@ -151,7 +151,7 @@ mpls_input_inline (vlib_main_t * vm, next0 = MPLS_INPUT_NEXT_LOOKUP; vnet_feature_arc_start(mm->input_feature_arc_index, sw_if_index0, &next0, b0); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); } if (PREDICT_FALSE(h1[3] == 0)) @@ -164,7 +164,7 @@ mpls_input_inline (vlib_main_t * vm, next1 = MPLS_INPUT_NEXT_LOOKUP; vnet_feature_arc_start(mm->input_feature_arc_index, sw_if_index1, &next1, b1); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1); } if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -215,7 +215,7 @@ mpls_input_inline (vlib_main_t * vm, { next0 = MPLS_INPUT_NEXT_LOOKUP; vnet_feature_arc_start(mm->input_feature_arc_index, sw_if_index0, &next0, b0); - vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1); + vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1); } if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) diff --git a/src/vnet/mpls/mpls_lookup.c b/src/vnet/mpls/mpls_lookup.c index 475bb204..ace6a70f 100644 --- a/src/vnet/mpls/mpls_lookup.c +++ b/src/vnet/mpls/mpls_lookup.c @@ -67,7 +67,7 @@ mpls_lookup (vlib_main_t * vm, vlib_combined_counter_main_t * cm = &load_balance_main.lbm_to_counters; u32 n_left_from, next_index, * from, * to_next; mpls_main_t * mm = &mpls_main; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -220,16 +220,16 @@ mpls_lookup (vlib_main_t * vm, vnet_buffer (b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b1)); vlib_increment_combined_counter - (cm, cpu_index, lbi2, 1, + (cm, thread_index, lbi2, 1, vlib_buffer_length_in_chain (vm, b2)); vlib_increment_combined_counter - (cm, cpu_index, lbi3, 1, + (cm, thread_index, lbi3, 1, vlib_buffer_length_in_chain (vm, b3)); /* @@ -351,7 +351,7 @@ mpls_lookup (vlib_main_t * vm, vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b0)); /* @@ -440,7 +440,7 @@ mpls_load_balance (vlib_main_t * vm, { vlib_combined_counter_main_t * cm = &load_balance_main.lbm_via_counters; u32 n_left_from, n_left_to_next, * from, * to_next; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u32 next; from = vlib_frame_vector_args (frame); @@ -536,10 +536,10 @@ mpls_load_balance (vlib_main_t * vm, vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_increment_combined_counter - (cm, cpu_index, lbi1, 1, + (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1)); if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) @@ -597,7 +597,7 @@ mpls_load_balance (vlib_main_t * vm, vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index; vlib_increment_combined_counter - (cm, cpu_index, lbi0, 1, + (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0)); vlib_validate_buffer_enqueue_x1 (vm, node, next, diff --git a/src/vnet/mpls/mpls_output.c b/src/vnet/mpls/mpls_output.c index 08018fd1..d90dec21 100644 --- a/src/vnet/mpls/mpls_output.c +++ b/src/vnet/mpls/mpls_output.c @@ -64,12 +64,12 @@ mpls_output_inline (vlib_main_t * vm, vlib_frame_t * from_frame, int is_midchain) { - u32 n_left_from, next_index, * from, * to_next, cpu_index; + u32 n_left_from, next_index, * from, * to_next, thread_index; vlib_node_runtime_t * error_node; u32 n_left_to_next; mpls_main_t *mm; - cpu_index = os_get_cpu_number(); + thread_index = vlib_get_thread_index(); error_node = vlib_node_get_runtime (vm, mpls_output_node.index); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -137,13 +137,13 @@ mpls_output_inline (vlib_main_t * vm, /* Bump the adj counters for packet and bytes */ vlib_increment_combined_counter (&adjacency_counters, - cpu_index, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); vlib_increment_combined_counter (&adjacency_counters, - cpu_index, + thread_index, adj_index1, 1, vlib_buffer_length_in_chain (vm, p1) + rw_len1); @@ -245,7 +245,7 @@ mpls_output_inline (vlib_main_t * vm, vlib_increment_combined_counter (&adjacency_counters, - cpu_index, + thread_index, adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0); diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index 2649798b..597ae060 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -893,7 +893,7 @@ pg_generate_set_lengths (pg_main_t * pg, vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number (), + vlib_get_thread_index (), si->sw_if_index, n_buffers, length_sum); } @@ -1266,7 +1266,7 @@ pg_stream_fill_helper (pg_main_t * pg, l += vlib_buffer_index_length_in_chain (vm, buffers[i]); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number (), + vlib_get_thread_index (), si->sw_if_index, n_alloc, l); s->current_replay_packet_index += n_alloc; s->current_replay_packet_index %= diff --git a/src/vnet/replication.c b/src/vnet/replication.c index 86d922b5..233a8c2f 100644 --- a/src/vnet/replication.c +++ b/src/vnet/replication.c @@ -31,16 +31,16 @@ replication_prep (vlib_main_t * vm, { replication_main_t *rm = &replication_main; replication_context_t *ctx; - uword cpu_number = vm->cpu_index; + uword thread_index = vm->thread_index; ip4_header_t *ip; u32 ctx_id; /* Allocate a context, reserve context 0 */ - if (PREDICT_FALSE (rm->contexts[cpu_number] == 0)) - pool_get_aligned (rm->contexts[cpu_number], ctx, CLIB_CACHE_LINE_BYTES); + if (PREDICT_FALSE (rm->contexts[thread_index] == 0)) + pool_get_aligned (rm->contexts[thread_index], ctx, CLIB_CACHE_LINE_BYTES); - pool_get_aligned (rm->contexts[cpu_number], ctx, CLIB_CACHE_LINE_BYTES); - ctx_id = ctx - rm->contexts[cpu_number]; + pool_get_aligned (rm->contexts[thread_index], ctx, CLIB_CACHE_LINE_BYTES); + ctx_id = ctx - rm->contexts[thread_index]; /* Save state from vlib buffer */ ctx->saved_free_list_index = b0->free_list_index; @@ -94,11 +94,11 @@ replication_recycle (vlib_main_t * vm, vlib_buffer_t * b0, u32 is_last) { replication_main_t *rm = &replication_main; replication_context_t *ctx; - uword cpu_number = vm->cpu_index; + uword thread_index = vm->thread_index; ip4_header_t *ip; /* Get access to the replication context */ - ctx = pool_elt_at_index (rm->contexts[cpu_number], b0->recycle_count); + ctx = pool_elt_at_index (rm->contexts[thread_index], b0->recycle_count); /* Restore vnet buffer state */ clib_memcpy (vnet_buffer (b0), ctx->vnet_buffer, @@ -133,7 +133,7 @@ replication_recycle (vlib_main_t * vm, vlib_buffer_t * b0, u32 is_last) b0->flags &= ~VLIB_BUFFER_RECYCLE; /* Free context back to its pool */ - pool_put (rm->contexts[cpu_number], ctx); + pool_put (rm->contexts[thread_index], ctx); } return ctx; @@ -160,7 +160,7 @@ replication_recycle_callback (vlib_main_t * vm, vlib_buffer_free_list_t * fl) replication_main_t *rm = &replication_main; replication_context_t *ctx; u32 feature_node_index = 0; - uword cpu_number = vm->cpu_index; + uword thread_index = vm->thread_index; /* * All buffers in the list are destined to the same recycle node. @@ -172,7 +172,7 @@ replication_recycle_callback (vlib_main_t * vm, vlib_buffer_free_list_t * fl) { bi0 = fl->buffers[0]; b0 = vlib_get_buffer (vm, bi0); - ctx = pool_elt_at_index (rm->contexts[cpu_number], b0->recycle_count); + ctx = pool_elt_at_index (rm->contexts[thread_index], b0->recycle_count); feature_node_index = ctx->recycle_node_index; } diff --git a/src/vnet/replication.h b/src/vnet/replication.h index 5dc554c9..ce4b3ff1 100644 --- a/src/vnet/replication.h +++ b/src/vnet/replication.h @@ -100,7 +100,7 @@ replication_get_ctx (vlib_buffer_t * b0) replication_main_t *rm = &replication_main; return replication_is_recycled (b0) ? - pool_elt_at_index (rm->contexts[os_get_cpu_number ()], + pool_elt_at_index (rm->contexts[vlib_get_thread_index ()], b0->recycle_count) : 0; } diff --git a/src/vnet/session/node.c b/src/vnet/session/node.c index b86e87d9..dd211c51 100644 --- a/src/vnet/session/node.c +++ b/src/vnet/session/node.c @@ -311,7 +311,7 @@ session_queue_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, unix_shared_memory_queue_t *q; application_t *app; int n_tx_packets = 0; - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; int i, rv; f64 now = vlib_time_now (vm); diff --git a/src/vnet/sr/sr_localsid.c b/src/vnet/sr/sr_localsid.c index 2e3d56de..6d72a506 100755 --- a/src/vnet/sr/sr_localsid.c +++ b/src/vnet/sr/sr_localsid.c @@ -887,7 +887,7 @@ sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node, from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -974,26 +974,26 @@ sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (((next0 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls0 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b0)); + &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter (((next1 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls1 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b1)); + &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b1)); vlib_increment_combined_counter (((next2 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls2 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b2)); + &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b2)); vlib_increment_combined_counter (((next3 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls3 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b3)); + &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b3)); vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, @@ -1062,8 +1062,8 @@ sr_localsid_d_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (((next0 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls0 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b0)); + &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); @@ -1103,7 +1103,7 @@ sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node, from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; next_index = node->cached_next_index; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); while (n_left_from > 0) { @@ -1205,26 +1205,26 @@ sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (((next0 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls0 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b0)); + &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); vlib_increment_combined_counter (((next1 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls1 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b1)); + &(sm->sr_ls_valid_counters)), thread_index, ls1 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b1)); vlib_increment_combined_counter (((next2 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls2 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b2)); + &(sm->sr_ls_valid_counters)), thread_index, ls2 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b2)); vlib_increment_combined_counter (((next3 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls3 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b3)); + &(sm->sr_ls_valid_counters)), thread_index, ls3 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b3)); vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next, n_left_to_next, bi0, bi1, bi2, bi3, @@ -1295,8 +1295,8 @@ sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_increment_combined_counter (((next0 == SR_LOCALSID_NEXT_ERROR) ? &(sm->sr_ls_invalid_counters) : - &(sm->sr_ls_valid_counters)), cpu_index, ls0 - sm->localsids, 1, - vlib_buffer_length_in_chain (vm, b0)); + &(sm->sr_ls_valid_counters)), thread_index, ls0 - sm->localsids, + 1, vlib_buffer_length_in_chain (vm, b0)); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); diff --git a/src/vnet/tcp/builtin_client.c b/src/vnet/tcp/builtin_client.c index e3705060..c1567aa0 100644 --- a/src/vnet/tcp/builtin_client.c +++ b/src/vnet/tcp/builtin_client.c @@ -174,7 +174,7 @@ tclient_thread_fn (void *arg) pthread_sigmask (SIG_SETMASK, &s, 0); } - clib_per_cpu_mheaps[os_get_cpu_number ()] = clib_per_cpu_mheaps[0]; + clib_per_cpu_mheaps[vlib_get_thread_index ()] = clib_per_cpu_mheaps[0]; while (1) { diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index b2a371e2..b6c34828 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -646,10 +646,10 @@ const static transport_proto_vft_t tcp6_proto = { void tcp_timer_keep_handler (u32 conn_index) { - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); tcp_connection_t *tc; - tc = tcp_connection_get (conn_index, cpu_index); + tc = tcp_connection_get (conn_index, thread_index); tc->timers[TCP_TIMER_KEEP] = TCP_TIMER_HANDLE_INVALID; tcp_connection_close (tc); @@ -675,10 +675,10 @@ tcp_timer_establish_handler (u32 conn_index) void tcp_timer_waitclose_handler (u32 conn_index) { - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); tcp_connection_t *tc; - tc = tcp_connection_get (conn_index, cpu_index); + tc = tcp_connection_get (conn_index, thread_index); tc->timers[TCP_TIMER_WAITCLOSE] = TCP_TIMER_HANDLE_INVALID; /* Session didn't come back with a close(). Send FIN either way diff --git a/src/vnet/tcp/tcp_debug.h b/src/vnet/tcp/tcp_debug.h index 0090e15e..eaca672c 100644 --- a/src/vnet/tcp/tcp_debug.h +++ b/src/vnet/tcp/tcp_debug.h @@ -343,7 +343,7 @@ typedef enum _tcp_dbg_evt } \ else \ { \ - u32 _thread_index = os_get_cpu_number (); \ + u32 _thread_index = vlib_get_thread_index (); \ _tc = tcp_connection_get (_tc_index, _thread_index); \ } \ ELOG_TYPE_DECLARE (_e) = \ diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index a8224dc2..7e9fa47b 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -1142,7 +1142,7 @@ tcp46_established_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int is_ip4) { u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index, errors = 0; + u32 my_thread_index = vm->thread_index, errors = 0; tcp_main_t *tm = vnet_get_tcp_main (); from = vlib_frame_vector_args (from_frame); @@ -1332,7 +1332,7 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { tcp_main_t *tm = vnet_get_tcp_main (); u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index, errors = 0; + u32 my_thread_index = vm->thread_index, errors = 0; u8 sst = is_ip4 ? SESSION_TYPE_IP4_TCP : SESSION_TYPE_IP6_TCP; from = vlib_frame_vector_args (from_frame); @@ -1634,7 +1634,7 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node, { tcp_main_t *tm = vnet_get_tcp_main (); u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index, errors = 0; + u32 my_thread_index = vm->thread_index, errors = 0; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -1989,7 +1989,7 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int is_ip4) { u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; tcp_main_t *tm = vnet_get_tcp_main (); u8 sst = is_ip4 ? SESSION_TYPE_IP4_TCP : SESSION_TYPE_IP6_TCP; @@ -2243,7 +2243,7 @@ tcp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int is_ip4) { u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; tcp_main_t *tm = vnet_get_tcp_main (); from = vlib_frame_vector_args (from_frame); diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c index ea157bd7..e18bfad7 100644 --- a/src/vnet/tcp/tcp_output.c +++ b/src/vnet/tcp/tcp_output.c @@ -387,8 +387,8 @@ tcp_make_options (tcp_connection_t * tc, tcp_options_t * opts, #define tcp_get_free_buffer_index(tm, bidx) \ do { \ u32 *my_tx_buffers, n_free_buffers; \ - u32 cpu_index = os_get_cpu_number(); \ - my_tx_buffers = tm->tx_buffers[cpu_index]; \ + u32 thread_index = vlib_get_thread_index(); \ + my_tx_buffers = tm->tx_buffers[thread_index]; \ if (PREDICT_FALSE(vec_len (my_tx_buffers) == 0)) \ { \ n_free_buffers = 32; /* TODO config or macro */ \ @@ -396,7 +396,7 @@ do { \ _vec_len(my_tx_buffers) = vlib_buffer_alloc_from_free_list ( \ tm->vlib_main, my_tx_buffers, n_free_buffers, \ VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); \ - tm->tx_buffers[cpu_index] = my_tx_buffers; \ + tm->tx_buffers[thread_index] = my_tx_buffers; \ } \ /* buffer shortage */ \ if (PREDICT_FALSE (vec_len (my_tx_buffers) == 0)) \ @@ -408,8 +408,8 @@ do { \ #define tcp_return_buffer(tm) \ do { \ u32 *my_tx_buffers; \ - u32 cpu_index = os_get_cpu_number(); \ - my_tx_buffers = tm->tx_buffers[cpu_index]; \ + u32 thread_index = vlib_get_thread_index(); \ + my_tx_buffers = tm->tx_buffers[thread_index]; \ _vec_len (my_tx_buffers) +=1; \ } while (0) @@ -942,7 +942,7 @@ tcp_send_ack (tcp_connection_t * tc) void tcp_timer_delack_handler (u32 index) { - u32 thread_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); tcp_connection_t *tc; tc = tcp_connection_get (index, thread_index); @@ -1022,7 +1022,7 @@ tcp_timer_retransmit_handler_i (u32 index, u8 is_syn) { tcp_main_t *tm = vnet_get_tcp_main (); vlib_main_t *vm = vlib_get_main (); - u32 thread_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); tcp_connection_t *tc; vlib_buffer_t *b; u32 bi, snd_space, n_bytes; @@ -1152,7 +1152,7 @@ tcp_timer_persist_handler (u32 index) { tcp_main_t *tm = vnet_get_tcp_main (); vlib_main_t *vm = vlib_get_main (); - u32 thread_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); tcp_connection_t *tc; vlib_buffer_t *b; u32 bi, n_bytes; @@ -1313,7 +1313,7 @@ tcp46_output_inline (vlib_main_t * vm, vlib_frame_t * from_frame, int is_ip4) { u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -1524,7 +1524,7 @@ tcp46_send_reset_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, u8 is_ip4) { u32 n_left_from, next_index, *from, *to_next; - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; diff --git a/src/vnet/udp/udp_input.c b/src/vnet/udp/udp_input.c index 4b22109b..810278e6 100644 --- a/src/vnet/udp/udp_input.c +++ b/src/vnet/udp/udp_input.c @@ -70,7 +70,7 @@ udp4_uri_input_node_fn (vlib_main_t * vm, udp4_uri_input_next_t next_index; udp_uri_main_t *um = vnet_get_udp_main (); session_manager_main_t *smm = vnet_get_session_manager_main (); - u32 my_thread_index = vm->cpu_index; + u32 my_thread_index = vm->thread_index; u8 my_enqueue_epoch; u32 *session_indices_to_enqueue; static u32 serial_number; diff --git a/src/vnet/unix/tapcli.c b/src/vnet/unix/tapcli.c index fb1a8bac..0fc62f6c 100644 --- a/src/vnet/unix/tapcli.c +++ b/src/vnet/unix/tapcli.c @@ -366,7 +366,7 @@ static uword tapcli_rx_iface(vlib_main_t * vm, vlib_increment_combined_counter ( vnet_main.interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number(), ti->sw_if_index, + vlib_get_thread_index(), ti->sw_if_index, 1, n_bytes_in_packet); if (PREDICT_FALSE(n_trace > 0)) { diff --git a/src/vnet/unix/tuntap.c b/src/vnet/unix/tuntap.c index 2cfcc92f..ac674653 100644 --- a/src/vnet/unix/tuntap.c +++ b/src/vnet/unix/tuntap.c @@ -189,7 +189,7 @@ tuntap_tx (vlib_main_t * vm, /* Update tuntap interface output stats. */ vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - vm->cpu_index, + vm->thread_index, tm->sw_if_index, n_packets, n_bytes); @@ -297,7 +297,7 @@ tuntap_rx (vlib_main_t * vm, vlib_increment_combined_counter (vnet_main.interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - os_get_cpu_number(), + vlib_get_thread_index(), tm->sw_if_index, 1, n_bytes_in_packet); diff --git a/src/vnet/vxlan-gpe/decap.c b/src/vnet/vxlan-gpe/decap.c index 22ab4b62..d4fe4231 100644 --- a/src/vnet/vxlan-gpe/decap.c +++ b/src/vnet/vxlan-gpe/decap.c @@ -115,7 +115,7 @@ vxlan_gpe_input (vlib_main_t * vm, vxlan4_gpe_tunnel_key_t last_key4; vxlan6_gpe_tunnel_key_t last_key6; u32 pkts_decapsulated = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; if (is_ip4) @@ -342,7 +342,7 @@ vxlan_gpe_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; stats_sw_if_index = sw_if_index0; @@ -427,7 +427,7 @@ vxlan_gpe_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len1; stats_sw_if_index = sw_if_index1; @@ -588,7 +588,7 @@ vxlan_gpe_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; stats_sw_if_index = sw_if_index0; @@ -615,7 +615,7 @@ vxlan_gpe_input (vlib_main_t * vm, if (stats_n_packets) { vlib_increment_combined_counter ( - im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, cpu_index, + im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); node->runtime_data[0] = stats_sw_if_index; } diff --git a/src/vnet/vxlan-gpe/encap.c b/src/vnet/vxlan-gpe/encap.c index 3a486e56..67ed94b4 100644 --- a/src/vnet/vxlan-gpe/encap.c +++ b/src/vnet/vxlan-gpe/encap.c @@ -151,7 +151,7 @@ vxlan_gpe_encap (vlib_main_t * vm, vnet_main_t * vnm = ngm->vnet_main; vnet_interface_main_t * im = &vnm->interface_main; u32 pkts_encapsulated = 0; - u32 cpu_index = os_get_cpu_number (); + u32 thread_index = vlib_get_thread_index (); u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; from = vlib_frame_vector_args (from_frame); @@ -253,7 +253,7 @@ vxlan_gpe_encap (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_sw_if_index = sw_if_index0; stats_n_packets = 2; stats_n_bytes = len0 + len1; @@ -262,10 +262,10 @@ vxlan_gpe_encap (vlib_main_t * vm, { vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, sw_if_index0, 1, len0); + thread_index, sw_if_index0, 1, len0); vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, sw_if_index1, 1, len1); + thread_index, sw_if_index1, 1, len1); } } @@ -335,7 +335,7 @@ vxlan_gpe_encap (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter ( im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; stats_sw_if_index = sw_if_index0; @@ -359,7 +359,7 @@ vxlan_gpe_encap (vlib_main_t * vm, if (stats_n_packets) { vlib_increment_combined_counter ( - im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, cpu_index, + im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); node->runtime_data[0] = stats_sw_if_index; } diff --git a/src/vnet/vxlan/decap.c b/src/vnet/vxlan/decap.c index 514b2c99..2acb1f6f 100644 --- a/src/vnet/vxlan/decap.c +++ b/src/vnet/vxlan/decap.c @@ -81,7 +81,7 @@ vxlan_input (vlib_main_t * vm, vxlan4_tunnel_key_t last_key4; vxlan6_tunnel_key_t last_key6; u32 pkts_decapsulated = 0; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; if (is_ip4) @@ -314,7 +314,7 @@ vxlan_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; @@ -468,7 +468,7 @@ vxlan_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len1; @@ -674,7 +674,7 @@ vxlan_input (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; @@ -711,7 +711,7 @@ vxlan_input (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); node->runtime_data[0] = stats_sw_if_index; } diff --git a/src/vnet/vxlan/encap.c b/src/vnet/vxlan/encap.c index 5b63064a..4cfbbc23 100644 --- a/src/vnet/vxlan/encap.c +++ b/src/vnet/vxlan/encap.c @@ -77,7 +77,7 @@ vxlan_encap_inline (vlib_main_t * vm, vnet_interface_main_t * im = &vnm->interface_main; u32 pkts_encapsulated = 0; u16 old_l0 = 0, old_l1 = 0; - u32 cpu_index = os_get_cpu_number(); + u32 thread_index = vlib_get_thread_index(); u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; u32 sw_if_index0 = 0, sw_if_index1 = 0; u32 next0 = 0, next1 = 0; @@ -301,7 +301,7 @@ vxlan_encap_inline (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, stats_sw_if_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_sw_if_index = sw_if_index0; stats_n_packets = 2; @@ -311,10 +311,10 @@ vxlan_encap_inline (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, sw_if_index0, 1, len0); + thread_index, sw_if_index0, 1, len0); vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, sw_if_index1, 1, len1); + thread_index, sw_if_index1, 1, len1); } } @@ -464,7 +464,7 @@ vxlan_encap_inline (vlib_main_t * vm, if (stats_n_packets) vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, stats_sw_if_index, + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); stats_n_packets = 1; stats_n_bytes = len0; @@ -496,7 +496,7 @@ vxlan_encap_inline (vlib_main_t * vm, { vlib_increment_combined_counter (im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_TX, - cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); + thread_index, stats_sw_if_index, stats_n_packets, stats_n_bytes); node->runtime_data[0] = stats_sw_if_index; } diff --git a/src/vpp/stats/stats.c b/src/vpp/stats/stats.c index 042d02e2..4309cd51 100644 --- a/src/vpp/stats/stats.c +++ b/src/vpp/stats/stats.c @@ -66,14 +66,14 @@ _(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) void dslock (stats_main_t * sm, int release_hint, int tag) { - u32 thread_id; + u32 thread_index; data_structure_lock_t *l = sm->data_structure_lock; if (PREDICT_FALSE (l == 0)) return; - thread_id = os_get_cpu_number (); - if (l->lock && l->thread_id == thread_id) + thread_index = vlib_get_thread_index (); + if (l->lock && l->thread_index == thread_index) { l->count++; return; @@ -85,7 +85,7 @@ dslock (stats_main_t * sm, int release_hint, int tag) while (__sync_lock_test_and_set (&l->lock, 1)) /* zzzz */ ; l->tag = tag; - l->thread_id = thread_id; + l->thread_index = thread_index; l->count = 1; } @@ -99,14 +99,14 @@ stats_dslock_with_hint (int hint, int tag) void dsunlock (stats_main_t * sm) { - u32 thread_id; + u32 thread_index; data_structure_lock_t *l = sm->data_structure_lock; if (PREDICT_FALSE (l == 0)) return; - thread_id = os_get_cpu_number (); - ASSERT (l->lock && l->thread_id == thread_id); + thread_index = vlib_get_thread_index (); + ASSERT (l->lock && l->thread_index == thread_index); l->count--; if (l->count == 0) { diff --git a/src/vpp/stats/stats.h b/src/vpp/stats/stats.h index 118115be..024dc78e 100644 --- a/src/vpp/stats/stats.h +++ b/src/vpp/stats/stats.h @@ -30,7 +30,7 @@ typedef struct { volatile u32 lock; volatile u32 release_hint; - u32 thread_id; + u32 thread_index; u32 count; int tag; } data_structure_lock_t; -- cgit 1.2.3-korg From 5ee51f8ed616f14f3b32ae8857d383fefa02d861 Mon Sep 17 00:00:00 2001 From: Choonho Son Date: Wed, 5 Apr 2017 19:09:52 +0900 Subject: VPP-686: create bridge-domain - update default flags - add missing flag learn Change-Id: I50a1a001848769836468838775b59d3414d27710 Signed-off-by: Choonho Son --- src/vnet/l2/l2_bd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index a222fec9..9d7a43d3 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -1138,7 +1138,7 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) /** Create or delete bridge-domain. - The CLI format is: + The CLI format: create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] */ @@ -1151,7 +1151,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, clib_error_t *error = 0; u8 is_add = 1; u32 bd_id = ~0; - u32 flood = 1, forward = 1, learn = 1, uu_flood = 0, arp_term = 0; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; u32 mac_age = 0; l2_bridge_domain_add_del_args_t _a, *a = &_a; int rv; @@ -1170,6 +1170,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, ; else if (unformat (line_input, "forward %d", &forward)) ; + else if (unformat (line_input, "learn %d", &learn)) + ; else if (unformat (line_input, "arp-term %d", &arp_term)) ; else if (unformat (line_input, "mac-age %d", &mac_age)) -- cgit 1.2.3-korg From b1352ed0ac39aaa7be7542275d1d43fa64ab28ac Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Fri, 7 Apr 2017 23:14:17 +0300 Subject: BD:unify bridge domain creation code Change-Id: I29082e7a0c556069180a157e55b3698cf8cd38c7 Signed-off-by: Eyal Bari --- src/vnet/api_errno.h | 4 +- src/vnet/l2/l2_api.c | 63 +++++++---------------------- src/vnet/l2/l2_bd.c | 92 ++++++++++++++++++++----------------------- src/vnet/l2/l2_bd.h | 37 ++++++++++++----- src/vnet/lisp-gpe/interface.c | 7 ++-- src/vpp/api/api.c | 12 +++--- 6 files changed, 97 insertions(+), 118 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index e939404b..0d5b2227 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -107,7 +107,9 @@ _(ADDRESS_FOUND_FOR_INTERFACE, -114, "Address found for interface") \ _(SESSION_CONNECT_FAIL, -115, "Session failed to connect") \ _(ENTRY_ALREADY_EXISTS, -116, "Entry already exists") \ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ -_(APPLICATION_NOT_ATTACHED, -118, "application not attached") +_(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ +_(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ +_(BD_IN_USE, -120, "Bridge domain has member interfaces") typedef enum { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 026f1706..5a3c8dc2 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -324,54 +324,20 @@ out: static void vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) { - vlib_main_t *vm = vlib_get_main (); - bd_main_t *bdm = &bd_main; - vl_api_bridge_domain_add_del_reply_t *rmp; - int rv = 0; - u32 enable_flags = 0, disable_flags = 0; - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - - if (mp->is_add) - { - bd_index = bd_find_or_add_bd_index (bdm, bd_id); - - if (mp->flood) - enable_flags |= L2_FLOOD; - else - disable_flags |= L2_FLOOD; - - if (mp->uu_flood) - enable_flags |= L2_UU_FLOOD; - else - disable_flags |= L2_UU_FLOOD; - - if (mp->forward) - enable_flags |= L2_FWD; - else - disable_flags |= L2_FWD; - - if (mp->arp_term) - enable_flags |= L2_ARP_TERM; - else - disable_flags |= L2_ARP_TERM; - - if (mp->learn) - enable_flags |= L2_LEARN; - else - disable_flags |= L2_LEARN; - - if (enable_flags) - bd_set_flags (vm, bd_index, enable_flags, 1 /* enable */ ); - - if (disable_flags) - bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); - - bd_set_mac_age (vm, bd_index, mp->mac_age); - } - else - rv = bd_delete_bd_index (bdm, bd_id); + l2_bridge_domain_add_del_args_t a = { + .is_add = mp->is_add, + .flood = mp->flood, + .uu_flood = mp->uu_flood, + .forward = mp->forward, + .learn = mp->learn, + .arp_term = mp->arp_term, + .mac_age = mp->mac_age, + .bd_id = ntohl (mp->bd_id), + }; + + int rv = bd_add_del (&a); + vl_api_bridge_domain_add_del_reply_t *rmp; REPLY_MACRO (VL_API_BRIDGE_DOMAIN_ADD_DEL_REPLY); } @@ -436,7 +402,8 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) bd_id = ntohl (mp->bd_id); - bd_index = (bd_id == ~0) ? 0 : bd_find_or_add_bd_index (bdm, bd_id); + bd_index = (bd_id == ~0) ? 0 : bd_find_index (bdm, bd_id); + ASSERT (bd_index != ~0); end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; for (; bd_index < end; bd_index++) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 9d7a43d3..cfaf4c99 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -50,42 +50,35 @@ bd_main_t bd_main; void bd_validate (l2_bridge_domain_t * bd_config) { - if (!bd_is_valid (bd_config)) - { - bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; - bd_config->bvi_sw_if_index = ~0; - bd_config->members = 0; - bd_config->flood_count = 0; - bd_config->tun_master_count = 0; - bd_config->tun_normal_count = 0; - bd_config->mac_by_ip4 = 0; - bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), - sizeof (uword)); - } + if (bd_is_valid (bd_config)) + return; + bd_config->feature_bitmap = ~L2INPUT_FEAT_ARP_TERM; + bd_config->bvi_sw_if_index = ~0; + bd_config->members = 0; + bd_config->flood_count = 0; + bd_config->tun_master_count = 0; + bd_config->tun_normal_count = 0; + bd_config->mac_by_ip4 = 0; + bd_config->mac_by_ip6 = hash_create_mem (0, sizeof (ip6_address_t), + sizeof (uword)); } u32 -bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +bd_find_index (bd_main_t * bdm, u32 bd_id) { - uword *p; - u32 rv; - - if (bd_id == ~0) - { - bd_id = 0; - while (hash_get (bdm->bd_index_by_bd_id, bd_id)) - bd_id++; - } - else - { - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p) - return (p[0]); - } + u32 *p = (u32 *) hash_get (bdm->bd_index_by_bd_id, bd_id); + if (!p) + return ~0; + return p[0]; +} - rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); +u32 +bd_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + ASSERT (!hash_get (bdm->bd_index_by_bd_id, bd_id)); + u32 rv = clib_bitmap_first_clear (bdm->bd_index_bitmap); - /* mark this index busy */ + /* mark this index taken */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, rv, 1); hash_set (bdm->bd_index_by_bd_id, bd_id, rv); @@ -96,21 +89,14 @@ bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) return rv; } -int -bd_delete_bd_index (bd_main_t * bdm, u32 bd_id) +static int +bd_delete (bd_main_t * bdm, u32 bd_index) { - uword *p; - u32 bd_index; - - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p == 0) - return VNET_API_ERROR_NO_SUCH_ENTRY; - - bd_index = p[0]; + u32 bd_id = l2input_main.bd_configs[bd_index].bd_id; + hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); - hash_unset (bdm->bd_index_by_bd_id, bd_id); l2input_main.bd_configs[bd_index].bd_id = ~0; l2input_main.bd_configs[bd_index].feature_bitmap = 0; @@ -202,14 +188,13 @@ clib_error_t * l2bd_init (vlib_main_t * vm) { bd_main_t *bdm = &bd_main; - u32 bd_index; bdm->bd_index_by_bd_id = hash_create (0, sizeof (uword)); /* * create a dummy bd with bd_id of 0 and bd_index of 0 with feature set * to packet drop only. Thus, packets received from any L2 interface with * uninitialized bd_index of 0 can be dropped safely. */ - bd_index = bd_find_or_add_bd_index (bdm, 0); + u32 bd_index = bd_add_bd_index (bdm, 0); ASSERT (bd_index == 0); l2input_main.bd_configs[0].feature_bitmap = L2INPUT_FEAT_DROP; @@ -1087,16 +1072,16 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { bd_main_t *bdm = &bd_main; vlib_main_t *vm = bdm->vlib_main; - u32 enable_flags = 0, disable_flags = 0; - u32 bd_index = ~0; int rv = 0; + u32 bd_index = bd_find_index (bdm, a->bd_id); if (a->is_add) { - bd_index = bd_find_or_add_bd_index (bdm, a->bd_id); - if (bd_index == ~0) - return bd_index; + if (bd_index != ~0) + return VNET_API_ERROR_BD_ALREADY_EXISTS; + bd_index = bd_add_bd_index (bdm, a->bd_id); + u32 enable_flags = 0, disable_flags = 0; if (a->flood) enable_flags |= L2_FLOOD; else @@ -1131,7 +1116,13 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) bd_set_mac_age (vm, bd_index, a->mac_age); } else - rv = bd_delete_bd_index (bdm, a->bd_id); + { + if (bd_index == ~0) + return VNET_API_ERROR_NO_SUCH_ENTRY; + if (vec_len (l2input_main.bd_configs[bd_index].members)) + return VNET_API_ERROR_BD_IN_USE; + rv = bd_delete (bdm, bd_index); + } return rv; } @@ -1215,6 +1206,9 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, if (is_add) vlib_cli_output (vm, "bridge-domain %d", bd_id); break; + case VNET_API_ERROR_BD_IN_USE: + error = clib_error_return (0, "bridge domain in use - remove members"); + goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: error = clib_error_return (0, "bridge domain id does not exist"); goto done; diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 83733411..e502d497 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -128,28 +128,47 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); +int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** - * \brief Get or create a bridge domain. + * \brief Get a bridge domain. + * + * Get a bridge domain with the given bridge domain ID. + * + * \param bdm bd_main pointer. + * \param bd_id The bridge domain ID + * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. + */ +u32 bd_find_index (bd_main_t * bdm, u32 bd_id); + +/** + * \brief Create a bridge domain. * - * Get or create a bridge domain with the given bridge domain ID. + * Create a bridge domain with the given bridge domain ID * * \param bdm bd_main pointer. - * \param bd_id The bridge domain ID or ~0 if an arbitrary unused bridge domain should be used. * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. */ -u32 bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id); +u32 bd_add_bd_index (bd_main_t * bdm, u32 bd_id); /** - * \brief Delete a bridge domain. + * \brief Get or create a bridge domain. * - * Delete an existing bridge domain with the given bridge domain ID. + * Get a bridge domain with the given bridge domain ID, if one exists, otherwise + * create one with the given ID, or the first unused ID if the given ID is ~0.. * * \param bdm bd_main pointer. - * \param bd_id The bridge domain ID. - * \return 0 on success and -1 if the bridge domain does not exist. + * \param bd_id The bridge domain ID + * \return The bridge domain index in \c l2input_main->l2_bridge_domain_t vector. */ -int bd_delete_bd_index (bd_main_t * bdm, u32 bd_id); +static inline u32 +bd_find_or_add_bd_index (bd_main_t * bdm, u32 bd_id) +{ + u32 bd_index = bd_find_index (bdm, bd_id); + if (bd_index == ~0) + return bd_add_bd_index (bdm, bd_id); + return bd_index; +} u32 bd_add_del_ip_mac (u32 bd_index, u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add); diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index 4760f448..0598c048 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -705,11 +705,10 @@ void lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) { tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces; - u16 bd_index; - uword *hip; - bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); - hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); + u32 bd_index = bd_find_index (&bd_main, bd_id); + ASSERT (bd_index != ~0); + uword *hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); if (hip == 0) { diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 22410fcc..f1b6877f 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -410,21 +410,19 @@ static void bd_main_t *bdm = &bd_main; vl_api_sw_interface_set_l2_bridge_reply_t *rmp; int rv = 0; - u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index); - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 bvi = mp->bvi; - u8 shg = mp->shg; vlib_main_t *vm = vlib_get_main (); vnet_main_t *vnm = vnet_get_main (); VALIDATE_RX_SW_IF_INDEX (mp); + u32 rx_sw_if_index = ntohl (mp->rx_sw_if_index); - bd_index = bd_find_or_add_bd_index (bdm, bd_id); if (mp->enable) { - //VALIDATE_TX_SW_IF_INDEX(mp); + u32 bd_id = ntohl (mp->bd_id); + u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id); + u32 bvi = mp->bvi; + u8 shg = mp->shg; rv = set_int_l2_mode (vm, vnm, MODE_L2_BRIDGE, rx_sw_if_index, bd_index, bvi, shg, 0); } -- cgit 1.2.3-korg From 11b8dbf78af49d270a0e72abe7dea73eec30d85f Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Mon, 24 Apr 2017 10:46:54 -0400 Subject: "autoreply" flag: autogenerate standard xxx_reply_t messages Change-Id: I72298aaae7d172082ece3a8edea4217c11b28d79 Signed-off-by: Dave Barach --- src/examples/sample-plugin/sample/sample.api | 10 +- src/plugins/acl/acl.api | 60 +--- src/plugins/dpdk/api/dpdk.api | 35 +- src/plugins/flowperpkt/flowperpkt.api | 23 +- .../export-vxlan-gpe/vxlan_gpe_ioam_export.api | 10 +- src/plugins/ioam/export/ioam_export.api | 10 +- src/plugins/ioam/ip6/ioam_cache.api | 10 +- src/plugins/ioam/lib-pot/pot.api | 34 +- src/plugins/ioam/lib-trace/trace.api | 26 +- src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api | 82 +---- src/plugins/lb/lb.api | 21 +- src/plugins/memif/memif.api | 12 +- src/plugins/snat/snat.api | 88 +---- src/tools/vppapigen/gram.y | 3 +- src/tools/vppapigen/lex.c | 57 +++- src/tools/vppapigen/lex.h | 1 + src/tools/vppapigen/node.c | 5 + src/tools/vppapigen/node.h | 2 + src/vlibmemory/memclnt.api | 7 +- src/vlibmemory/memory_vlib.c | 8 +- src/vnet/bfd/bfd.api | 132 +------- src/vnet/classify/classify.api | 37 +-- src/vnet/cop/cop.api | 28 +- src/vnet/devices/af_packet/af_packet.api | 12 +- src/vnet/devices/netmap/netmap.api | 24 +- src/vnet/devices/virtio/vhost_user.api | 24 +- src/vnet/dhcp/dhcp.api | 38 +-- src/vnet/flow/flow.api | 32 +- src/vnet/interface.api | 108 +----- src/vnet/ip/ip.api | 108 +----- src/vnet/ipsec/ipsec.api | 224 ++----------- src/vnet/l2/l2.api | 96 +----- src/vnet/l2tp/l2tp.api | 28 +- src/vnet/lisp-cp/lisp.api | 164 +-------- src/vnet/lisp-cp/one.api | 185 +---------- src/vnet/lisp-gpe/lisp_gpe.api | 48 +-- src/vnet/map/map.api | 22 +- src/vnet/mpls/mpls.api | 26 +- src/vnet/session/session.api | 68 +--- src/vnet/span/span.api | 10 +- src/vnet/sr/sr.api | 60 +--- src/vnet/unix/tap.api | 12 +- src/vnet/vxlan/vxlan.api | 12 +- src/vpp/api/vpe.api | 367 ++------------------- 44 files changed, 271 insertions(+), 2098 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/examples/sample-plugin/sample/sample.api b/src/examples/sample-plugin/sample/sample.api index f99cdb38..d565c0b1 100644 --- a/src/examples/sample-plugin/sample/sample.api +++ b/src/examples/sample-plugin/sample/sample.api @@ -16,7 +16,7 @@ /* Define a simple binary API to control the feature */ -define sample_macswap_enable_disable { +autoreply define sample_macswap_enable_disable { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -29,11 +29,3 @@ define sample_macswap_enable_disable { /* Interface handle */ u32 sw_if_index; }; - -define sample_macswap_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/src/plugins/acl/acl.api b/src/plugins/acl/acl.api index d981338d..3b334113 100644 --- a/src/plugins/acl/acl.api +++ b/src/plugins/acl/acl.api @@ -161,24 +161,13 @@ define acl_add_replace_reply @param acl_index - ACL index to delete */ -manual_print define acl_del +autoreply manual_print define acl_del { u32 client_index; u32 context; u32 acl_index; }; -/** \brief Reply to delete the ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define acl_del_reply -{ - u32 context; - i32 retval; -}; - /* acl_interface_add_del(_reply) to be deprecated in lieu of acl_interface_set_acl_list */ /** \brief Use acl_interface_set_acl_list instead Append/remove an ACL index to/from the list of ACLs checked for an interface @@ -190,7 +179,7 @@ define acl_del_reply @param acl_index - index of ACL for the operation */ -manual_print define acl_interface_add_del +autoreply manual_print define acl_interface_add_del { u32 client_index; u32 context; @@ -204,17 +193,6 @@ manual_print define acl_interface_add_del u32 acl_index; }; -/** \brief Reply to alter the ACL list - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define acl_interface_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set the vector of input/output ACLs checked for an interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -224,7 +202,7 @@ define acl_interface_add_del_reply @param acls - vector of ACL indices */ -manual_print define acl_interface_set_acl_list +autoreply manual_print define acl_interface_set_acl_list { u32 client_index; u32 context; @@ -239,12 +217,6 @@ manual_print define acl_interface_set_acl_list @param retval 0 - no error */ -define acl_interface_set_acl_list_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump the specific ACL contents or all of the ACLs' contents @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -341,24 +313,13 @@ define macip_acl_add_reply @param acl_index - MACIP ACL index to delete */ -manual_print define macip_acl_del +autoreply manual_print define macip_acl_del { u32 client_index; u32 context; u32 acl_index; }; -/** \brief Reply to delete the MACIP ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define macip_acl_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add or delete a MACIP ACL to/from interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -367,7 +328,7 @@ define macip_acl_del_reply @param acl_index - MACIP ACL index */ -manual_print define macip_acl_interface_add_del +autoreply manual_print define macip_acl_interface_add_del { u32 client_index; u32 context; @@ -377,17 +338,6 @@ manual_print define macip_acl_interface_add_del u32 acl_index; }; -/** \brief Reply to apply/unapply the MACIP ACL - @param context - returned sender context, to match reply w/ request - @param retval 0 - no error -*/ - -define macip_acl_interface_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump one or all defined MACIP ACLs @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/dpdk/api/dpdk.api b/src/plugins/dpdk/api/dpdk.api index 21215d45..d43f8a36 100644 --- a/src/plugins/dpdk/api/dpdk.api +++ b/src/plugins/dpdk/api/dpdk.api @@ -21,7 +21,7 @@ @param pipe - pipe ID within its subport @param profile - pipe profile ID */ -define sw_interface_set_dpdk_hqos_pipe { +autoreply define sw_interface_set_dpdk_hqos_pipe { u32 client_index; u32 context; u32 sw_if_index; @@ -30,15 +30,6 @@ define sw_interface_set_dpdk_hqos_pipe { u32 profile; }; -/** \brief DPDK interface HQoS pipe profile set reply - @param context - sender context, to match reply w/ request - @param retval - request return code -*/ -define sw_interface_set_dpdk_hqos_pipe_reply { - u32 context; - i32 retval; -}; - /** \brief DPDK interface HQoS subport parameters set request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -49,7 +40,7 @@ define sw_interface_set_dpdk_hqos_pipe_reply { @param tc_rate - subport traffic class 0 .. 3 rates (measured in bytes/second) @param tc_period - enforcement period for rates (measured in milliseconds) */ -define sw_interface_set_dpdk_hqos_subport { +autoreply define sw_interface_set_dpdk_hqos_subport { u32 client_index; u32 context; u32 sw_if_index; @@ -60,15 +51,6 @@ define sw_interface_set_dpdk_hqos_subport { u32 tc_period; }; -/** \brief DPDK interface HQoS subport parameters set reply - @param context - sender context, to match reply w/ request - @param retval - request return code -*/ -define sw_interface_set_dpdk_hqos_subport_reply { - u32 context; - i32 retval; -}; - /** \brief DPDK interface HQoS tctbl entry set request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -77,7 +59,7 @@ define sw_interface_set_dpdk_hqos_subport_reply { @param tc - traffic class (0 .. 3) @param queue - traffic class queue (0 .. 3) */ -define sw_interface_set_dpdk_hqos_tctbl { +autoreply define sw_interface_set_dpdk_hqos_tctbl { u32 client_index; u32 context; u32 sw_if_index; @@ -86,18 +68,9 @@ define sw_interface_set_dpdk_hqos_tctbl { u32 queue; }; -/** \brief DPDK interface HQoS tctbl entry set reply - @param context - sender context, to match reply w/ request - @param retval - request return code -*/ -define sw_interface_set_dpdk_hqos_tctbl_reply { - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") * End: */ - \ No newline at end of file + diff --git a/src/plugins/flowperpkt/flowperpkt.api b/src/plugins/flowperpkt/flowperpkt.api index 1cf62c54..3ff92dca 100644 --- a/src/plugins/flowperpkt/flowperpkt.api +++ b/src/plugins/flowperpkt/flowperpkt.api @@ -12,7 +12,7 @@ @param is_ipv6 - if non-zero the address is ipv6, else ipv4 @param sw_if_index - index of the interface */ -manual_print define flowperpkt_tx_interface_add_del +autoreply manual_print define flowperpkt_tx_interface_add_del { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -28,20 +28,7 @@ manual_print define flowperpkt_tx_interface_add_del u32 sw_if_index; }; -/** \brief Reply to enable/disable per-packet IPFIX recording messages - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define flowperpkt_tx_interface_add_del_reply -{ - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; - -define flowperpkt_params +autoreply define flowperpkt_params { u32 client_index; u32 context; @@ -51,9 +38,3 @@ define flowperpkt_params u32 active_timer; /* ~0 is off, 0 is default */ u32 passive_timer; /* ~0 is off, 0 is default */ }; - -define flowperpkt_params_reply -{ - u32 context; - i32 retval; -}; diff --git a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api index 7b17c3f7..caa97e6e 100644 --- a/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api +++ b/src/plugins/ioam/export-vxlan-gpe/vxlan_gpe_ioam_export.api @@ -16,7 +16,7 @@ /* Define a simple binary API to control the feature */ -define vxlan_gpe_ioam_export_enable_disable { +autoreply define vxlan_gpe_ioam_export_enable_disable { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -32,11 +32,3 @@ define vxlan_gpe_ioam_export_enable_disable { /* Src ip address */ }; - -define vxlan_gpe_ioam_export_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; \ No newline at end of file diff --git a/src/plugins/ioam/export/ioam_export.api b/src/plugins/ioam/export/ioam_export.api index f22d9fc8..bb830561 100644 --- a/src/plugins/ioam/export/ioam_export.api +++ b/src/plugins/ioam/export/ioam_export.api @@ -16,7 +16,7 @@ /* Define a simple binary API to control the feature */ -define ioam_export_ip6_enable_disable { +autoreply define ioam_export_ip6_enable_disable { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -32,11 +32,3 @@ define ioam_export_ip6_enable_disable { /* Src ip address */ }; - -define ioam_export_ip6_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/src/plugins/ioam/ip6/ioam_cache.api b/src/plugins/ioam/ip6/ioam_cache.api index de50d57d..dd9c0186 100644 --- a/src/plugins/ioam/ip6/ioam_cache.api +++ b/src/plugins/ioam/ip6/ioam_cache.api @@ -16,7 +16,7 @@ /* API to control ioam caching */ -define ioam_cache_ip6_enable_disable { +autoreply define ioam_cache_ip6_enable_disable { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -27,11 +27,3 @@ define ioam_cache_ip6_enable_disable { u8 is_disable; }; - -define ioam_cache_ip6_enable_disable_reply { - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/src/plugins/ioam/lib-pot/pot.api b/src/plugins/ioam/lib-pot/pot.api index fa2fc126..c377cde0 100644 --- a/src/plugins/ioam/lib-pot/pot.api +++ b/src/plugins/ioam/lib-pot/pot.api @@ -27,7 +27,7 @@ @param list_name_len - length of the name of this profile list @param list_name - name of this profile list */ -define pot_profile_add { +autoreply define pot_profile_add { u32 client_index; u32 context; u8 id; @@ -42,22 +42,12 @@ define pot_profile_add { u8 list_name[0]; }; -/** \brief Proof of Transit profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_add_reply { - u32 context; - i32 retval; -}; - - /** \brief Proof of Transit(POT): Activate POT profile in the list @param id - id of the profile @param list_name_len - length of the name of this profile list @param list_name - name of this profile list */ -define pot_profile_activate { +autoreply define pot_profile_activate { u32 client_index; u32 context; u8 id; @@ -65,37 +55,19 @@ define pot_profile_activate { u8 list_name[0]; }; -/** \brief Proof of Transit profile activate response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_activate_reply { - u32 context; - i32 retval; -}; - /** \brief Delete POT Profile @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param list_name_len - length of the name of the profile list @param list_name - name of profile list to delete */ -define pot_profile_del { +autoreply define pot_profile_del { u32 client_index; u32 context; u8 list_name_len; u8 list_name[0]; }; -/** \brief Proof of Transit profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pot_profile_del_reply { - u32 context; - i32 retval; -}; - /** \brief Show POT Profiles @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/ioam/lib-trace/trace.api b/src/plugins/ioam/lib-trace/trace.api index cb958325..2f45c6e2 100644 --- a/src/plugins/ioam/lib-trace/trace.api +++ b/src/plugins/ioam/lib-trace/trace.api @@ -22,7 +22,7 @@ @param trace_tsp- Timestamp resolution @param app_data - Application specific opaque */ -define trace_profile_add { +autoreply define trace_profile_add { u32 client_index; u32 context; u8 trace_type; @@ -32,37 +32,15 @@ define trace_profile_add { u32 app_data; }; -/** \brief Trace profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define trace_profile_add_reply { - u32 context; - i32 retval; -}; - - - /** \brief Delete trace Profile @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define trace_profile_del { +autoreply define trace_profile_del { u32 client_index; u32 context; }; -/** \brief Trace profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define trace_profile_del_reply { - u32 context; - i32 retval; -}; - - - /** \brief Show trace Profile @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api b/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api index 056529a4..a6761f07 100644 --- a/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api +++ b/src/plugins/ioam/lib-vxlan-gpe/ioam_vxlan_gpe.api @@ -24,7 +24,7 @@ @param trace_enable - iOAM Trace enabled or not flag */ -define vxlan_gpe_ioam_enable { +autoreply define vxlan_gpe_ioam_enable { u32 client_index; u32 context; u16 id; @@ -33,38 +33,18 @@ define vxlan_gpe_ioam_enable { u8 trace_enable; }; -/** \brief iOAM Over VxLAN-GPE - Set iOAM transport for VXLAN-GPE reply - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define vxlan_gpe_ioam_enable_reply { - u32 context; - i32 retval; -}; - - /** \brief iOAM for VxLAN-GPE disable @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param id - profile id */ -define vxlan_gpe_ioam_disable +autoreply define vxlan_gpe_ioam_disable { u32 client_index; u32 context; u16 id; }; -/** \brief vxlan_gpe_ioam disable response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define vxlan_gpe_ioam_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Enable iOAM for a VNI (VXLAN-GPE) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -73,7 +53,7 @@ define vxlan_gpe_ioam_disable_reply @param remote - IPv4/6 Address of the remote VTEP */ -define vxlan_gpe_ioam_vni_enable { +autoreply define vxlan_gpe_ioam_vni_enable { u32 client_index; u32 context; u32 vni; @@ -82,18 +62,6 @@ define vxlan_gpe_ioam_vni_enable { u8 is_ipv6; }; -/** \brief Reply to enable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_vni_enable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - /** \brief Disable iOAM for a VNI (VXLAN-GPE) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -102,7 +70,7 @@ define vxlan_gpe_ioam_vni_enable_reply { @param remote - IPv4/6 Address of the remote VTEP */ -define vxlan_gpe_ioam_vni_disable { +autoreply define vxlan_gpe_ioam_vni_disable { u32 client_index; u32 context; u32 vni; @@ -111,19 +79,6 @@ define vxlan_gpe_ioam_vni_disable { u8 is_ipv6; }; -/** \brief Reply to disable iOAM for a VNI (VXLAN-GPE) - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_vni_disable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - - /** \brief Enable iOAM for a VXLAN-GPE transit @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -131,7 +86,7 @@ define vxlan_gpe_ioam_vni_disable_reply { @param outer_fib_index- FIB index */ -define vxlan_gpe_ioam_transit_enable { +autoreply define vxlan_gpe_ioam_transit_enable { u32 client_index; u32 context; u32 outer_fib_index; @@ -139,18 +94,6 @@ define vxlan_gpe_ioam_transit_enable { u8 is_ipv6; }; -/** \brief Reply to enable iOAM for VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_transit_enable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - /** \brief Disable iOAM for VXLAN-GPE transit @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -158,7 +101,7 @@ define vxlan_gpe_ioam_transit_enable_reply { @param outer_fib_index- FIB index */ -define vxlan_gpe_ioam_transit_disable { +autoreply define vxlan_gpe_ioam_transit_disable { u32 client_index; u32 context; u32 outer_fib_index; @@ -166,16 +109,3 @@ define vxlan_gpe_ioam_transit_disable { u8 is_ipv6; }; -/** \brief Reply to disable iOAM for VXLAN-GPE transit - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param retval - return value for request - -*/ -define vxlan_gpe_ioam_transit_disable_reply { - u32 client_index; - u32 context; - i32 retval; -}; - - diff --git a/src/plugins/lb/lb.api b/src/plugins/lb/lb.api index 39ee3c8f..32cc669b 100644 --- a/src/plugins/lb/lb.api +++ b/src/plugins/lb/lb.api @@ -8,7 +8,7 @@ @param flow_timeout - Time in seconds after which, if no packet is received for a given flow, the flow is removed from the established flow table. */ -define lb_conf +autoreply define lb_conf { u32 client_index; u32 context; @@ -18,11 +18,6 @@ define lb_conf u32 flow_timeout; }; -define lb_conf_reply { - u32 context; - i32 retval; -}; - /** \brief Add a virtual address (or prefix) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -33,7 +28,7 @@ define lb_conf_reply { for this VIP (must be power of 2). @param is_del - The VIP should be removed. */ -define lb_add_del_vip { +autoreply define lb_add_del_vip { u32 client_index; u32 context; u8 ip_prefix[16]; @@ -43,11 +38,6 @@ define lb_add_del_vip { u8 is_del; }; -define lb_add_del_vip_reply { - u32 context; - i32 retval; -}; - /** \brief Add an application server for a given VIP @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -56,7 +46,7 @@ define lb_add_del_vip_reply { @param as_address - The application server address (IPv4 in lower order 32 bits). @param is_del - The AS should be removed. */ -define lb_add_del_as { +autoreply define lb_add_del_as { u32 client_index; u32 context; u8 vip_ip_prefix[16]; @@ -64,8 +54,3 @@ define lb_add_del_as { u8 as_address[16]; u8 is_del; }; - -define lb_add_del_as_reply { - u32 context; - i32 retval; -}; diff --git a/src/plugins/memif/memif.api b/src/plugins/memif/memif.api index 6f946421..95e016c3 100644 --- a/src/plugins/memif/memif.api +++ b/src/plugins/memif/memif.api @@ -57,7 +57,7 @@ define memif_create_reply @param context - sender context, to match reply w/ request @param sw_if_index - software index of the interface to delete */ -define memif_delete +autoreply define memif_delete { u32 client_index; u32 context; @@ -65,16 +65,6 @@ define memif_delete u32 sw_if_index; }; -/** \brief Delete host-interface response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define memif_delete_reply -{ - u32 context; - i32 retval; -}; - /** \brief Memory interface details structure @param context - sender context, to match reply w/ request (memif_dump) @param sw_if_index - index of the interface diff --git a/src/plugins/snat/snat.api b/src/plugins/snat/snat.api index 9689f5f9..573b6753 100644 --- a/src/plugins/snat/snat.api +++ b/src/plugins/snat/snat.api @@ -29,7 +29,7 @@ @param vrf_id - VRF id of tenant, ~0 means independent of VRF @param is_add - 1 if add, 0 if delete */ -define snat_add_address_range { +autoreply define snat_add_address_range { u32 client_index; u32 context; u8 is_ip4; @@ -39,15 +39,6 @@ define snat_add_address_range { u8 is_add; }; -/** \brief Add S-NAT address range reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_address_range_reply { - u32 context; - i32 retval; -}; - /** \brief Dump S-NAT addresses @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -77,7 +68,7 @@ define snat_address_details { @param is_inside - 1 if inside, 0 if outside @param sw_if_index - software index of the interface */ -define snat_interface_add_del_feature { +autoreply define snat_interface_add_del_feature { u32 client_index; u32 context; u8 is_add; @@ -85,15 +76,6 @@ define snat_interface_add_del_feature { u32 sw_if_index; }; -/** \brief Enable/disable S-NAT feature on the interface reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_interface_add_del_feature_reply { - u32 context; - i32 retval; -}; - /** \brief Dump interfaces with S-NAT feature @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -130,7 +112,7 @@ define snat_interface_details { used) @param vfr_id - VRF ID */ -define snat_add_static_mapping { +autoreply define snat_add_static_mapping { u32 client_index; u32 context; u8 is_add; @@ -145,15 +127,6 @@ define snat_add_static_mapping { u32 vrf_id; }; -/** \brief Add/delete S-NAT static mapping reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_static_mapping_reply { - u32 context; - i32 retval; -}; - /** \brief Dump S-NAT static mappings @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -257,21 +230,12 @@ define snat_show_config_reply @param context - sender context, to match reply w/ request @param worker_mask - S-NAT workers mask */ -define snat_set_workers { +autoreply define snat_set_workers { u32 client_index; u32 context; u64 worker_mask; }; -/** \brief Set S-NAT workers reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_set_workers_reply { - u32 context; - i32 retval; -}; - /** \brief Dump S-NAT workers @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -300,7 +264,7 @@ define snat_worker_details { @param is_add - 1 if add, 0 if delete @param sw_if_index - software index of the interface */ -define snat_add_del_interface_addr { +autoreply define snat_add_del_interface_addr { u32 client_index; u32 context; u8 is_add; @@ -308,15 +272,6 @@ define snat_add_del_interface_addr { u32 sw_if_index; }; -/** \brief Add/delete S-NAT pool address from specific interfce reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_del_interface_addr_reply { - u32 context; - i32 retval; -}; - /** \brief Dump S-NAT pool addresses interfaces @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -342,7 +297,7 @@ define snat_interface_addr_details { @param src_port - source port number @param enable - 1 if enable, 0 if disable */ -define snat_ipfix_enable_disable { +autoreply define snat_ipfix_enable_disable { u32 client_index; u32 context; u32 domain_id; @@ -350,15 +305,6 @@ define snat_ipfix_enable_disable { u8 enable; }; -/** \brief Enable/disable S-NAT IPFIX logging reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_ipfix_enable_disable_reply { - u32 context; - i32 retval; -}; - /** \brief Dump S-NAT users @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -437,7 +383,7 @@ define snat_user_session_details { @param out_addr - outside IP address @param out_addr - outside IP address prefix length */ -define snat_add_det_map { +autoreply define snat_add_det_map { u32 client_index; u32 context; u8 is_add; @@ -449,15 +395,6 @@ define snat_add_det_map { u8 out_plen; }; -/** \brief Add/delete S-NAT deterministic mapping reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_add_det_map_reply { - u32 context; - i32 retval; -}; - /** \brief Get outside address and port range from inside address @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -556,7 +493,7 @@ define snat_det_map_details { @param tcp_transitory - TCP transitory timeout (default 240sec) @param icmp - ICMP timeout (default 60sec) */ -define snat_det_set_timeouts { +autoreply define snat_det_set_timeouts { u32 client_index; u32 context; u32 udp; @@ -565,15 +502,6 @@ define snat_det_set_timeouts { u32 icmp; }; -/** \brief Set values of timeouts for deterministic NAT reply - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define snat_det_set_timeouts_reply { - u32 context; - i32 retval; -}; - /** \brief Get values of timeouts for deterministic NAT (seconds) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/tools/vppapigen/gram.y b/src/tools/vppapigen/gram.y index de26af8d..9cea6023 100644 --- a/src/tools/vppapigen/gram.y +++ b/src/tools/vppapigen/gram.y @@ -38,7 +38,7 @@ void generate (YYSTYPE); %token NAME RPAR LPAR SEMI LBRACK RBRACK NUMBER PRIMTYPE BARF %token TPACKED DEFINE LCURLY RCURLY STRING UNION %token HELPER_STRING COMMA -%token NOVERSION MANUAL_PRINT MANUAL_ENDIAN TYPEONLY DONT_TRACE +%token NOVERSION MANUAL_PRINT MANUAL_ENDIAN TYPEONLY DONT_TRACE AUTOREPLY %% @@ -64,6 +64,7 @@ flag: | MANUAL_ENDIAN {$$ = $1;} | DONT_TRACE {$$ = $1;} | TYPEONLY {$$ = $1;} + | AUTOREPLY {$$ = $1;} ; defn: DEFINE NAME LCURLY defbody RCURLY SEMI diff --git a/src/tools/vppapigen/lex.c b/src/tools/vppapigen/lex.c index 733942ad..e6358143 100644 --- a/src/tools/vppapigen/lex.c +++ b/src/tools/vppapigen/lex.c @@ -27,6 +27,9 @@ #include "lex.h" #include "node.h" #include "tools/vppapigen/gram.h" +#include +#include +#include FILE *ifp, *ofp, *pythonfp, *jsonfp; char *vlib_app_name = "vpp"; @@ -38,6 +41,9 @@ int current_filename_allocated; unsigned long input_crc; unsigned long message_crc; int yydebug; +char *push_input_fifo; +char saved_ungetc_char; +char have_ungetc_char; /* * lexer variable definitions @@ -469,9 +475,50 @@ static char namebuf [MAXNAME]; static inline char getc_char (FILE *ifp) { + char rv; + + if (have_ungetc_char) { + have_ungetc_char = 0; + return saved_ungetc_char; + } + + if (clib_fifo_elts (push_input_fifo)) { + clib_fifo_sub1(push_input_fifo, rv); + return (rv & 0x7f); + } return ((char)(getc(ifp) & 0x7f)); } +u32 fe (char *fifo) +{ + return clib_fifo_elts (fifo); +} + +static inline void +ungetc_char (char c, FILE *ifp) +{ + saved_ungetc_char = c; + have_ungetc_char = 1; +} + +void autoreply (void *np_arg) +{ + static u8 *s; + node_t *np = (node_t *)np_arg; + int i; + + vec_reset_length (s); + + s = format (0, " define %s_reply\n", (char *)(np->data[0])); + s = format (s, "{\n"); + s = format (s, " u32 context;\n"); + s = format (s, " i32 retval;\n"); + s = format (s, "};\n"); + + for (i = 0; i < vec_len (s); i++) + clib_fifo_add1 (push_input_fifo, s[i]); +} + /* * yylex (well, yylex_1: The real yylex below does crc-hackery) */ @@ -595,7 +642,7 @@ static int yylex_1 (void) return (EOF); if (!isalnum (c) && c != '_') { - ungetc (c, ifp); + ungetc_char (c, ifp); namebuf [nameidx] = 0; the_lexer_state = START_STATE; return (name_check (namebuf, &yylval)); @@ -616,7 +663,7 @@ static int yylex_1 (void) return (EOF); if (!isdigit (c)) { - ungetc (c, ifp); + ungetc_char (c, ifp); namebuf [nameidx] = 0; the_lexer_state = START_STATE; yylval = (void *) atol(namebuf); @@ -889,6 +936,7 @@ int yylex (void) case MANUAL_ENDIAN: code = 276; break; case TYPEONLY: code = 278; break; case DONT_TRACE: code = 279; break; + case AUTOREPLY: code = 280; break; case EOF: code = ~0; break; /* hysterical compatibility */ @@ -929,6 +977,7 @@ static struct keytab { } keytab [] = /* Keep the table sorted, binary search used below! */ { + {"autoreply", NODE_AUTOREPLY}, {"define", NODE_DEFINE}, {"dont_trace", NODE_DONT_TRACE}, {"f64", NODE_F64}, @@ -1005,6 +1054,10 @@ static int name_check (const char *s, YYSTYPE *token_value) *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE; return(DONT_TRACE); + case NODE_AUTOREPLY: + *token_value = (YYSTYPE) NODE_FLAG_AUTOREPLY; + return(AUTOREPLY); + case NODE_NOVERSION: return(NOVERSION); diff --git a/src/tools/vppapigen/lex.h b/src/tools/vppapigen/lex.h index a0fdc735..275cf685 100644 --- a/src/tools/vppapigen/lex.h +++ b/src/tools/vppapigen/lex.h @@ -24,6 +24,7 @@ extern int yylex (void); extern void yyerror (char *); extern int yyparse (void); +extern void autoreply (void *); #ifndef YYSTYPE #define YYSTYPE void * diff --git a/src/tools/vppapigen/node.c b/src/tools/vppapigen/node.c index 359ac9c9..9f234037 100644 --- a/src/tools/vppapigen/node.c +++ b/src/tools/vppapigen/node.c @@ -1050,6 +1050,11 @@ YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2) flags = (int)(uword) a1; np->flags |= flags; + + /* Generate a foo_reply_t right here */ + if (flags & NODE_FLAG_AUTOREPLY) + autoreply(np); + return (a2); } /* diff --git a/src/tools/vppapigen/node.h b/src/tools/vppapigen/node.h index 297d6036..65bd5d10 100644 --- a/src/tools/vppapigen/node.h +++ b/src/tools/vppapigen/node.h @@ -53,6 +53,7 @@ enum node_subclass { /* WARNING: indices must match the vft... */ NODE_MANUAL_PRINT, NODE_MANUAL_ENDIAN, NODE_DONT_TRACE, + NODE_AUTOREPLY, }; enum passid { @@ -84,6 +85,7 @@ typedef struct node_ { #define NODE_FLAG_MANUAL_ENDIAN (1<<1) #define NODE_FLAG_TYPEONLY (1<<3) #define NODE_FLAG_DONT_TRACE (1<<4) +#define NODE_FLAG_AUTOREPLY (1<<5) typedef struct node_vft_ { void (*print)(struct node_ *); diff --git a/src/vlibmemory/memclnt.api b/src/vlibmemory/memclnt.api index c38b483c..32e51407 100644 --- a/src/vlibmemory/memclnt.api +++ b/src/vlibmemory/memclnt.api @@ -72,7 +72,7 @@ define memclnt_read_timeout { /* * RPC */ -define rpc_call { +autoreply define rpc_call { u32 client_index; u32 context; u64 function; @@ -82,11 +82,6 @@ define rpc_call { u8 data[0]; }; -define rpc_reply { - i32 retval; - u32 context; -}; - /* * Lookup message-ID base by name */ diff --git a/src/vlibmemory/memory_vlib.c b/src/vlibmemory/memory_vlib.c index 7a536ee8..43574dea 100644 --- a/src/vlibmemory/memory_vlib.c +++ b/src/vlibmemory/memory_vlib.c @@ -1275,7 +1275,7 @@ VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) = { static void vl_api_rpc_call_t_handler (vl_api_rpc_call_t * mp) { - vl_api_rpc_reply_t *rmp; + vl_api_rpc_call_reply_t *rmp; int (*fp) (void *); i32 rv = 0; vlib_main_t *vm = vlib_get_main (); @@ -1305,7 +1305,7 @@ vl_api_rpc_call_t_handler (vl_api_rpc_call_t * mp) if (q) { rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_RPC_REPLY); + rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY); rmp->context = mp->context; rmp->retval = rv; vl_msg_api_send_shmem (q, (u8 *) & rmp); @@ -1318,7 +1318,7 @@ vl_api_rpc_call_t_handler (vl_api_rpc_call_t * mp) } static void -vl_api_rpc_reply_t_handler (vl_api_rpc_reply_t * mp) +vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t * mp) { clib_warning ("unimplemented"); } @@ -1415,7 +1415,7 @@ vl_api_trace_plugin_msg_ids_t_handler (vl_api_trace_plugin_msg_ids_t * mp) #define foreach_rpc_api_msg \ _(RPC_CALL,rpc_call) \ -_(RPC_REPLY,rpc_reply) +_(RPC_CALL_REPLY,rpc_call_reply) #define foreach_plugin_trace_msg \ _(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids) diff --git a/src/vnet/bfd/bfd.api b/src/vnet/bfd/bfd.api index 2cdcfad3..7bcaa4c3 100644 --- a/src/vnet/bfd/bfd.api +++ b/src/vnet/bfd/bfd.api @@ -18,43 +18,23 @@ @param context - sender context, to match reply w/ request @param sw_if_index - interface to use as echo source */ -define bfd_udp_set_echo_source +autoreply define bfd_udp_set_echo_source { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief Set BFD feature response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bfd_udp_set_echo_source_reply -{ - u32 context; - i32 retval; -}; - /** \brief Delete BFD echo source @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define bfd_udp_del_echo_source +autoreply define bfd_udp_del_echo_source { u32 client_index; u32 context; }; -/** \brief Delete BFD echo source response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bfd_udp_del_echo_source_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add UDP BFD session on interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -69,7 +49,7 @@ define bfd_udp_del_echo_source_reply @param bfd_key_id - key id sent out in BFD packets (if is_authenticated) @param conf_key_id - id of already configured key (if is_authenticated) */ -define bfd_udp_add +autoreply define bfd_udp_add { u32 client_index; u32 context; @@ -85,16 +65,6 @@ define bfd_udp_add u32 conf_key_id; }; -/** \brief Add UDP BFD session response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bfd_udp_add_reply -{ - u32 context; - i32 retval; -}; - /** \brief Modify UDP BFD session on interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -106,7 +76,7 @@ define bfd_udp_add_reply @param is_ipv6 - local_addr, peer_addr are IPv6 if non-zero, otherwise IPv4 @param detect_mult - detect multiplier (# of packets missed before connection goes down) */ -define bfd_udp_mod +autoreply define bfd_udp_mod { u32 client_index; u32 context; @@ -119,16 +89,6 @@ define bfd_udp_mod u8 detect_mult; }; -/** \brief Modify UDP BFD session response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bfd_udp_mod_reply -{ - u32 context; - i32 retval; -}; - /** \brief Delete UDP BFD session on interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -137,7 +97,7 @@ define bfd_udp_mod_reply @param peer_addr - peer address @param is_ipv6 - local_addr, peer_addr are IPv6 if non-zero, otherwise IPv4 */ -define bfd_udp_del +autoreply define bfd_udp_del { u32 client_index; u32 context; @@ -147,16 +107,6 @@ define bfd_udp_del u8 is_ipv6; }; -/** \brief Delete UDP BFD session response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bfd_udp_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get all BFD sessions @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -206,7 +156,7 @@ define bfd_udp_session_details @param is_ipv6 - local_addr, peer_addr are IPv6 if non-zero, otherwise IPv4 @param admin_up_down - set the admin state, 1 = up, 0 = down */ -define bfd_udp_session_set_flags +autoreply define bfd_udp_session_set_flags { u32 client_index; u32 context; @@ -217,23 +167,13 @@ define bfd_udp_session_set_flags u8 admin_up_down; }; -/** \brief Reply to bfd_udp_session_set_flags - @param context - sender context which was passed in the request - @param retval - return code of the set flags request -*/ -define bfd_udp_session_set_flags_reply -{ - u32 context; - i32 retval; -}; - /** \brief Register for BFD events @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param enable_disable - 1 => register for events, 0 => cancel registration @param pid - sender's pid */ -define want_bfd_events +autoreply define want_bfd_events { u32 client_index; u32 context; @@ -241,16 +181,6 @@ define want_bfd_events u32 pid; }; -/** \brief Reply for BFD events registration - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define want_bfd_events_reply -{ - u32 context; - i32 retval; -}; - /** \brief BFD UDP - add/replace key to configuration @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -259,7 +189,7 @@ define want_bfd_events_reply @param auth_type - authentication type (RFC 5880/4.1/Auth Type) @param key - key data */ -define bfd_auth_set_key +autoreply define bfd_auth_set_key { u32 client_index; u32 context; @@ -269,16 +199,6 @@ define bfd_auth_set_key u8 key[20]; }; -/** \brief BFD UDP - add/replace key reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define bfd_auth_set_key_reply -{ - u32 context; - i32 retval; -}; - /** \brief BFD UDP - delete key from configuration @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -286,23 +206,13 @@ define bfd_auth_set_key_reply @param key_len - length of key (must be non-zero) @param key - key data */ -define bfd_auth_del_key +autoreply define bfd_auth_del_key { u32 client_index; u32 context; u32 conf_key_id; }; -/** \brief BFD UDP - delete key reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define bfd_auth_del_key_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get a list of configured authentication keys @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -338,7 +248,7 @@ define bfd_auth_keys_details @param bfd_key_id - key id sent out in BFD packets @param conf_key_id - id of already configured key */ -define bfd_udp_auth_activate +autoreply define bfd_udp_auth_activate { u32 client_index; u32 context; @@ -351,16 +261,6 @@ define bfd_udp_auth_activate u32 conf_key_id; }; -/** \brief BFD UDP - activate/change authentication reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define bfd_udp_auth_activate_reply -{ - u32 context; - i32 retval; -}; - /** \brief BFD UDP - deactivate authentication @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -370,7 +270,7 @@ define bfd_udp_auth_activate_reply @param is_ipv6 - local_addr, peer_addr are IPv6 if non-zero, otherwise IPv4 @param is_delayed - change is applied once peer applies the change (on first received non-authenticated packet) */ -define bfd_udp_auth_deactivate +autoreply define bfd_udp_auth_deactivate { u32 client_index; u32 context; @@ -381,16 +281,6 @@ define bfd_udp_auth_deactivate u8 is_delayed; }; -/** \brief BFD UDP - deactivate authentication reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define bfd_udp_auth_deactivate_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/classify/classify.api b/src/vnet/classify/classify.api index 51ebd6c8..cacb9bed 100644 --- a/src/vnet/classify/classify.api +++ b/src/vnet/classify/classify.api @@ -92,7 +92,7 @@ define classify_add_del_table_reply VRF id if action is 1 or 2. @param match[] - for add, match value for session, required */ -define classify_add_del_session +autoreply define classify_add_del_session { u32 client_index; u32 context; @@ -106,16 +106,6 @@ define classify_add_del_session u8 match[0]; }; -/** \brief Classify add / del session response - @param context - sender context, to match reply w/ request - @param retval - return code for the add/del session request -*/ -define classify_add_del_session_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set/unset policer classify interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -127,7 +117,7 @@ define classify_add_del_session_reply Note: User is recommeneded to use just one valid table_index per call. (ip4_table_index, ip6_table_index, or l2_table_index) */ -define policer_classify_set_interface +autoreply define policer_classify_set_interface { u32 client_index; u32 context; @@ -138,16 +128,6 @@ define policer_classify_set_interface u8 is_add; }; -/** \brief Set/unset policer classify interface response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define policer_classify_set_interface_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get list of policer classify interfaces and tables @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -308,7 +288,7 @@ define classify_session_details Note: User is recommeneded to use just one valid table_index per call. (ip4_table_index, ip6_table_index, or l2_table_index) */ -define flow_classify_set_interface { +autoreply define flow_classify_set_interface { u32 client_index; u32 context; u32 sw_if_index; @@ -317,15 +297,6 @@ define flow_classify_set_interface { u8 is_add; }; -/** \brief Set/unset flow classify interface response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define flow_classify_set_interface_reply { - u32 context; - i32 retval; -}; - /** \brief Get list of flow classify interfaces and tables @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -353,4 +324,4 @@ define flow_classify_details { * eval: (c-set-style "gnu") * End: */ - \ No newline at end of file + diff --git a/src/vnet/cop/cop.api b/src/vnet/cop/cop.api index b34dae80..69316001 100644 --- a/src/vnet/cop/cop.api +++ b/src/vnet/cop/cop.api @@ -20,7 +20,7 @@ @param enable_disable - 1 => enable, 0 => disable */ -define cop_interface_enable_disable +autoreply define cop_interface_enable_disable { u32 client_index; u32 context; @@ -28,17 +28,6 @@ define cop_interface_enable_disable u8 enable_disable; }; -/** \brief cop: interface enable/disable junk filtration reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define cop_interface_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief cop: enable/disable whitelist filtration features on an interface Note: the supplied fib_id must match in order to remove the feature! @@ -51,7 +40,7 @@ define cop_interface_enable_disable_reply @param default_cop - 1 => enable non-ip4, non-ip6 filtration 0=> disable it */ -define cop_whitelist_enable_disable +autoreply define cop_whitelist_enable_disable { u32 client_index; u32 context; @@ -62,17 +51,6 @@ define cop_whitelist_enable_disable u8 default_cop; }; -/** \brief cop: interface enable/disable junk filtration reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define cop_whitelist_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief get_node_graph - get a copy of the vpp node graph including the current set of graph arcs. @@ -85,4 +63,4 @@ define cop_whitelist_enable_disable_reply * eval: (c-set-style "gnu") * End: */ - \ No newline at end of file + diff --git a/src/vnet/devices/af_packet/af_packet.api b/src/vnet/devices/af_packet/af_packet.api index 9fb2a207..8d40ad60 100644 --- a/src/vnet/devices/af_packet/af_packet.api +++ b/src/vnet/devices/af_packet/af_packet.api @@ -46,7 +46,7 @@ define af_packet_create_reply @param context - sender context, to match reply w/ request @param host_if_name - interface name */ -define af_packet_delete +autoreply define af_packet_delete { u32 client_index; u32 context; @@ -54,16 +54,6 @@ define af_packet_delete u8 host_if_name[64]; }; -/** \brief Delete host-interface response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define af_packet_delete_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/devices/netmap/netmap.api b/src/vnet/devices/netmap/netmap.api index 377ccffd..8dc698b9 100644 --- a/src/vnet/devices/netmap/netmap.api +++ b/src/vnet/devices/netmap/netmap.api @@ -22,7 +22,7 @@ @param is_pipe - is pipe @param is_master - 0=slave, 1=master */ -define netmap_create +autoreply define netmap_create { u32 client_index; u32 context; @@ -34,22 +34,12 @@ define netmap_create u8 is_master; }; -/** \brief Create netmap response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define netmap_create_reply -{ - u32 context; - i32 retval; -}; - /** \brief Delete netmap @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param netmap_if_name - interface name */ -define netmap_delete +autoreply define netmap_delete { u32 client_index; u32 context; @@ -57,16 +47,6 @@ define netmap_delete u8 netmap_if_name[64]; }; -/** \brief Delete netmap response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define netmap_delete_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/devices/virtio/vhost_user.api b/src/vnet/devices/virtio/vhost_user.api index 4f604e45..df7ce7ab 100644 --- a/src/vnet/devices/virtio/vhost_user.api +++ b/src/vnet/devices/virtio/vhost_user.api @@ -53,7 +53,7 @@ define create_vhost_user_if_reply @param sock_filename - unix socket filename, used to speak with frontend @param operation_mode - polling=0, interrupt=1, or adaptive=2 */ -define modify_vhost_user_if +autoreply define modify_vhost_user_if { u32 client_index; u32 context; @@ -65,36 +65,16 @@ define modify_vhost_user_if u8 operation_mode; }; -/** \brief vhost-user interface modify response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define modify_vhost_user_if_reply -{ - u32 context; - i32 retval; -}; - /** \brief vhost-user interface delete request @param client_index - opaque cookie to identify the sender */ -define delete_vhost_user_if +autoreply define delete_vhost_user_if { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief vhost-user interface delete response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define delete_vhost_user_if_reply -{ - u32 context; - i32 retval; -}; - /** \brief Vhost-user interface details structure (fix this) @param sw_if_index - index of the interface @param interface_name - name of interface diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api index 2db85a79..eb0b070d 100644 --- a/src/vnet/dhcp/dhcp.api +++ b/src/vnet/dhcp/dhcp.api @@ -24,7 +24,7 @@ @param dhcp_server[] - server address @param dhcp_src_address[] - */ -define dhcp_proxy_config +autoreply define dhcp_proxy_config { u32 client_index; u32 context; @@ -36,16 +36,6 @@ define dhcp_proxy_config u8 dhcp_src_address[16]; }; -/** \brief DHCP Proxy config response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define dhcp_proxy_config_reply -{ - u32 context; - i32 retval; -}; - /** \brief DHCP Proxy set / unset vss request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -55,7 +45,7 @@ define dhcp_proxy_config_reply @param is_ipv6 - ip6 if non-zero, else ip4 @param is_add - set vss if non-zero, else delete */ -define dhcp_proxy_set_vss +autoreply define dhcp_proxy_set_vss { u32 client_index; u32 context; @@ -66,16 +56,6 @@ define dhcp_proxy_set_vss u8 is_add; }; -/** \brief DHCP proxy set / unset vss response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define dhcp_proxy_set_vss_reply -{ - u32 context; - i32 retval; -}; - /** \brief DHCP Client config add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -86,7 +66,7 @@ define dhcp_proxy_set_vss_reply via dhcp_compl_event API message if non-zero @param pid - sender's pid */ -define dhcp_client_config +autoreply define dhcp_client_config { u32 client_index; u32 context; @@ -97,16 +77,6 @@ define dhcp_client_config u32 pid; }; -/** \brief DHCP Client config response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define dhcp_client_config_reply -{ - u32 context; - i32 retval; -}; - /** \brief Tell client about a DHCP completion event @param client_index - opaque cookie to identify the sender @param pid - client pid registered to receive notification @@ -162,4 +132,4 @@ manual_endian manual_print define dhcp_proxy_details * Local Variables: * eval: (c-set-style "gnu") * End: - */ \ No newline at end of file + */ diff --git a/src/vnet/flow/flow.api b/src/vnet/flow/flow.api index 0e0f99bf..1c5e8c5c 100644 --- a/src/vnet/flow/flow.api +++ b/src/vnet/flow/flow.api @@ -24,7 +24,7 @@ @param template_interval - number of seconds after which to resend template @param udp_checksum - UDP checksum calculation enable flag */ -define set_ipfix_exporter +autoreply define set_ipfix_exporter { u32 client_index; u32 context; @@ -37,15 +37,6 @@ define set_ipfix_exporter u8 udp_checksum; }; -/** \brief Reply to IPFIX exporter configure request - @param context - sender context which was passed in the request -*/ -define set_ipfix_exporter_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPFIX exporter dump request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -84,22 +75,13 @@ define ipfix_exporter_details @param domain_id - domain ID reported in IPFIX messages for classify stream @param src_port - source port of UDP session for classify stream */ -define set_ipfix_classify_stream { +autoreply define set_ipfix_classify_stream { u32 client_index; u32 context; u32 domain_id; u16 src_port; }; -/** \brief IPFIX classify stream configure response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define set_ipfix_classify_stream_reply { - u32 context; - i32 retval; -}; - /** \brief IPFIX classify stream dump request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -127,7 +109,7 @@ define ipfix_classify_stream_details { @param ip_version - version of IP used in the classifier table @param transport_protocol - transport protocol used in the classifier table or 255 for unspecified */ -define ipfix_classify_table_add_del { +autoreply define ipfix_classify_table_add_del { u32 client_index; u32 context; u32 table_id; @@ -136,14 +118,6 @@ define ipfix_classify_table_add_del { u8 is_add; }; -/** \brief IPFIX add classifier table response - @param context - sender context which was passed in the request -*/ -define ipfix_classify_table_add_del_reply { - u32 context; - i32 retval; -}; - /** \brief IPFIX classify tables dump request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/interface.api b/src/vnet/interface.api index 85fd73fb..9df63f18 100644 --- a/src/vnet/interface.api +++ b/src/vnet/interface.api @@ -6,7 +6,7 @@ @param link_up_down - Oper state sent on change event, not used in config. @param deleted - interface was deleted */ -define sw_interface_set_flags +autoreply define sw_interface_set_flags { u32 client_index; u32 context; @@ -17,23 +17,13 @@ define sw_interface_set_flags u8 deleted; }; -/** \brief Reply to sw_interface_set_flags - @param context - sender context which was passed in the request - @param retval - return code of the set flags request -*/ -define sw_interface_set_flags_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set interface MTU @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - index of the interface to set MTU on @param mtu - MTU */ -define sw_interface_set_mtu +autoreply define sw_interface_set_mtu { u32 client_index; u32 context; @@ -41,23 +31,13 @@ define sw_interface_set_mtu u16 mtu; }; -/** \brief Reply to sw_interface_set_mtu - @param context - sender context which was passed in the request - @param retval - return code of the set flags request -*/ -define sw_interface_set_mtu_reply -{ - u32 context; - i32 retval; -}; - /** \brief Register for interface events @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param enable_disable - 1 => register for events, 0 => cancel registration @param pid - sender's pid */ -define want_interface_events +autoreply define want_interface_events { u32 client_index; u32 context; @@ -65,16 +45,6 @@ define want_interface_events u32 pid; }; -/** \brief Reply for interface events registration - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define want_interface_events_reply -{ - u32 context; - i32 retval; -}; - /** \brief Interface details structure (fix this) @param sw_if_index - index of the interface @param sup_sw_if_index - index of parent interface if any, else same as sw_if_index @@ -184,7 +154,7 @@ define sw_interface_dump @param address_length - address length in bytes, 4 for ip4, 16 for ip6 @param address - array of address bytes */ -define sw_interface_add_del_address +autoreply define sw_interface_add_del_address { u32 client_index; u32 context; @@ -196,16 +166,6 @@ define sw_interface_add_del_address u8 address[16]; }; -/** \brief Reply to sw_interface_add_del_address - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define sw_interface_add_del_address_reply -{ - u32 context; - i32 retval; -}; - /** \brief Associate the specified interface with a fib table @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -213,7 +173,7 @@ define sw_interface_add_del_address_reply @param is_ipv6 - if non-zero ipv6, else ipv4 @param vrf_id - fib table/vrd id to associate the interface with */ -define sw_interface_set_table +autoreply define sw_interface_set_table { u32 client_index; u32 context; @@ -222,16 +182,6 @@ define sw_interface_set_table u32 vrf_id; }; -/** \brief Reply to sw_interface_set_table - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define sw_interface_set_table_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get VRF id assigned to interface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -280,7 +230,7 @@ define vnet_interface_counters @param unnumbered_sw_if_index - interface which will use the address @param is_add - if non-zero set the association, else unset it */ -define sw_interface_set_unnumbered +autoreply define sw_interface_set_unnumbered { u32 client_index; u32 context; @@ -289,38 +239,18 @@ define sw_interface_set_unnumbered u8 is_add; }; -/** \brief Set unnumbered interface add / del response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_set_unnumbered_reply -{ - u32 context; - i32 retval; -}; - /** \brief Clear interface statistics @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - index of the interface to clear statistics */ -define sw_interface_clear_stats +autoreply define sw_interface_clear_stats { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief Reply to sw_interface_clear_stats - @param context - sender context which was passed in the request - @param retval - return code of the set flags request -*/ -define sw_interface_clear_stats_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set / clear software interface tag @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -328,7 +258,7 @@ define sw_interface_clear_stats_reply @param add_del - 1 = add, 0 = delete @param tag - an ascii tag */ -define sw_interface_tag_add_del +autoreply define sw_interface_tag_add_del { u32 client_index; u32 context; @@ -337,23 +267,13 @@ define sw_interface_tag_add_del u8 tag[64]; }; -/** \brief Reply to set / clear software interface tag - @param context - sender context which was passed in the request - @param retval - return code for the request -*/ -define sw_interface_tag_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set an interface's MAC address @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - the interface whose MAC will be set @param mac_addr - the new MAC address */ -define sw_interface_set_mac_address +autoreply define sw_interface_set_mac_address { u32 client_index; u32 context; @@ -361,16 +281,6 @@ define sw_interface_set_mac_address u8 mac_address[6]; }; -/** \brief Reply to setting an interface MAC address request - @param context - sender context which was passed in the request - @param retval - return code for the request -*/ -define sw_interface_set_mac_address_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api index 6af1714f..7097a130 100644 --- a/src/vnet/ip/ip.api +++ b/src/vnet/ip/ip.api @@ -136,7 +136,7 @@ define ip_neighbor_details { @param mac_address - l2 address of the neighbor @param dst_address - ip4 or ip6 address of the neighbor */ -define ip_neighbor_add_del +autoreply define ip_neighbor_add_del { u32 client_index; u32 context; @@ -150,16 +150,6 @@ define ip_neighbor_add_del u8 dst_address[16]; }; -/** \brief Reply for IP Neighbor add / delete request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ip_neighbor_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set the ip flow hash config for a fib request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -172,7 +162,7 @@ define ip_neighbor_add_del_reply @param proto -if non-zero include proto in flow hash @param reverse - if non-zero include reverse in flow hash */ -define set_ip_flow_hash +autoreply define set_ip_flow_hash { u32 client_index; u32 context; @@ -186,16 +176,6 @@ define set_ip_flow_hash u8 reverse; }; -/** \brief Set the ip flow hash config for a fib response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define set_ip_flow_hash_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 router advertisement config request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -213,7 +193,7 @@ define set_ip_flow_hash_reply @param initial_count - @param initial_interval - */ -define sw_interface_ip6nd_ra_config +autoreply define sw_interface_ip6nd_ra_config { u32 client_index; u32 context; @@ -233,16 +213,6 @@ define sw_interface_ip6nd_ra_config u32 initial_interval; }; -/** \brief IPv6 router advertisement config response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_ip6nd_ra_config_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 router advertisement prefix config request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -272,7 +242,7 @@ define sw_interface_ip6nd_ra_config_reply preferred [ADDRCONF]. A value of all one bits (0xffffffff) represents infinity. */ -define sw_interface_ip6nd_ra_prefix +autoreply define sw_interface_ip6nd_ra_prefix { u32 client_index; u32 context; @@ -289,16 +259,6 @@ define sw_interface_ip6nd_ra_prefix u32 pref_lifetime; }; -/** \brief IPv6 router advertisement prefix config response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_ip6nd_ra_prefix_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 ND proxy config @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -306,7 +266,7 @@ define sw_interface_ip6nd_ra_prefix_reply @param address - The address of the host for which to proxy for @param is_add - Adding or deleting */ -define ip6nd_proxy_add_del +autoreply define ip6nd_proxy_add_del { u32 client_index; u32 context; @@ -315,16 +275,6 @@ define ip6nd_proxy_add_del u8 address[16]; }; -/** \brief IPv6 ND proxy response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define ip6nd_proxy_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 ND proxy details returned after request @param context - sender context, to match reply w/ request @param retval - return code for the request @@ -355,7 +305,7 @@ define ip6nd_proxy_dump @param sw_if_index - interface used to reach neighbor @param enable - if non-zero enable ip6 on interface, else disable */ -define sw_interface_ip6_enable_disable +autoreply define sw_interface_ip6_enable_disable { u32 client_index; u32 context; @@ -363,23 +313,13 @@ define sw_interface_ip6_enable_disable u8 enable; /* set to true if enable */ }; -/** \brief IPv6 interface enable / disable response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_ip6_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 set link local address on interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - interface to set link local on @param address[] - the new link local address */ -define sw_interface_ip6_set_link_local_address +autoreply define sw_interface_ip6_set_link_local_address { u32 client_index; u32 context; @@ -387,16 +327,6 @@ define sw_interface_ip6_set_link_local_address u8 address[16]; }; -/** \brief IPv6 set link local address on interface response - @param context - sender context, to match reply w/ request - @param retval - error code for the request -*/ -define sw_interface_ip6_set_link_local_address_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add / del route request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -422,7 +352,7 @@ define sw_interface_ip6_set_link_local_address_reply @param next_hop_out_label_stack - the next-hop output label stack, outer most first @param next_hop_via_label - The next-hop is a resolved via a local label */ -define ip_add_del_route +autoreply define ip_add_del_route { u32 client_index; u32 context; @@ -452,16 +382,6 @@ define ip_add_del_route u32 next_hop_out_label_stack[next_hop_n_out_labels]; }; -/** \brief Reply for add / del route request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ip_add_del_route_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add / del route request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -470,7 +390,7 @@ define ip_add_del_route_reply FIXME */ -define ip_mroute_add_del +autoreply define ip_mroute_add_del { u32 client_index; u32 context; @@ -488,16 +408,6 @@ define ip_mroute_add_del u8 src_address[16]; }; -/** \brief Reply for add / del mroute request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ip_mroute_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump IP multicast fib table @param client_index - opaque cookie to identify the sender */ diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index ef090f84..203c5272 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -20,7 +20,7 @@ @param spd_id - SPD instance id (control plane allocated) */ -define ipsec_spd_add_del +autoreply define ipsec_spd_add_del { u32 client_index; u32 context; @@ -28,17 +28,6 @@ define ipsec_spd_add_del u32 spd_id; }; -/** \brief Reply for IPsec: Add/delete Security Policy Database entry - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define ipsec_spd_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPsec: Add/delete SPD from interface @param client_index - opaque cookie to identify the sender @@ -49,7 +38,7 @@ define ipsec_spd_add_del_reply */ -define ipsec_interface_add_del_spd +autoreply define ipsec_interface_add_del_spd { u32 client_index; u32 context; @@ -59,17 +48,6 @@ define ipsec_interface_add_del_spd u32 spd_id; }; -/** \brief Reply for IPsec: Add/delete SPD from interface - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define ipsec_interface_add_del_spd_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPsec: Add/delete Security Policy Database entry See RFC 4301, 4.4.1.1 on how to match packet to selectors @@ -95,7 +73,7 @@ define ipsec_interface_add_del_spd_reply */ -define ipsec_spd_add_del_entry +autoreply define ipsec_spd_add_del_entry { u32 client_index; u32 context; @@ -125,17 +103,6 @@ define ipsec_spd_add_del_entry u32 sa_id; }; -/** \brief Reply for IPsec: Add/delete Security Policy Database entry - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define ipsec_spd_add_del_entry_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPsec: Add/delete Security Association Database entry @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -167,7 +134,7 @@ define ipsec_spd_add_del_entry_reply IPsec tunnel address copy mode (to support GDOI) */ -define ipsec_sad_add_del_entry +autoreply define ipsec_sad_add_del_entry { u32 client_index; u32 context; @@ -195,17 +162,6 @@ define ipsec_sad_add_del_entry u8 tunnel_dst_address[16]; }; -/** \brief Reply for IPsec: Add/delete Security Association Database entry - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define ipsec_sad_add_del_entry_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPsec: Update Security Association keys @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -219,7 +175,7 @@ define ipsec_sad_add_del_entry_reply @param integrity_key - integrity keying material */ -define ipsec_sa_set_key +autoreply define ipsec_sa_set_key { u32 client_index; u32 context; @@ -233,17 +189,6 @@ define ipsec_sa_set_key u8 integrity_key[128]; }; -/** \brief Reply for IPsec: Update Security Association keys - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define ipsec_sa_set_key_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Add/delete profile @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -251,7 +196,7 @@ define ipsec_sa_set_key_reply @param name - IKEv2 profile name @param is_add - Add IKEv2 profile if non-zero, else delete */ -define ikev2_profile_add_del +autoreply define ikev2_profile_add_del { u32 client_index; u32 context; @@ -260,16 +205,6 @@ define ikev2_profile_add_del u8 is_add; }; -/** \brief Reply for IKEv2: Add/delete profile - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_profile_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 profile authentication method @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -280,7 +215,7 @@ define ikev2_profile_add_del_reply @param data_len - Authentication data length @param data - Authentication data (for rsa-sig cert file path) */ -define ikev2_profile_set_auth +autoreply define ikev2_profile_set_auth { u32 client_index; u32 context; @@ -292,16 +227,6 @@ define ikev2_profile_set_auth u8 data[0]; }; -/** \brief Reply for IKEv2: Set IKEv2 profile authentication method - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_profile_set_auth_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 profile local/remote identification @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -312,7 +237,7 @@ define ikev2_profile_set_auth_reply @param data_len - Identification data length @param data - Identification data */ -define ikev2_profile_set_id +autoreply define ikev2_profile_set_id { u32 client_index; u32 context; @@ -324,16 +249,6 @@ define ikev2_profile_set_id u8 data[0]; }; -/** \brief Reply for IKEv2: - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_profile_set_id_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 profile traffic selector parameters @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -346,7 +261,7 @@ define ikev2_profile_set_id_reply @param start_addr - The smallest address included in traffic selector @param end_addr - The largest address included in traffic selector */ -define ikev2_profile_set_ts +autoreply define ikev2_profile_set_ts { u32 client_index; u32 context; @@ -360,23 +275,13 @@ define ikev2_profile_set_ts u32 end_addr; }; -/** \brief Reply for IKEv2: Set IKEv2 profile traffic selector parameters - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_profile_set_ts_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 local RSA private key @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param key_file - Key file absolute path */ -define ikev2_set_local_key +autoreply define ikev2_set_local_key { u32 client_index; u32 context; @@ -384,16 +289,6 @@ define ikev2_set_local_key u8 key_file[256]; }; -/** \brief Reply for IKEv2: Set IKEv2 local key - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_set_local_key_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 responder interface and IP address @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -402,7 +297,7 @@ define ikev2_set_local_key_reply @param sw_if_index - interface index @param address - interface address */ -define ikev2_set_responder +autoreply define ikev2_set_responder { u32 client_index; u32 context; @@ -412,17 +307,6 @@ define ikev2_set_responder u8 address[4]; }; -/** \brief Reply for IKEv2: Set IKEv2 responder interface and IP address - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_set_responder_reply -{ - u32 context; - i32 retval; -}; - - /** \brief IKEv2: Set IKEv2 IKE transforms in SA_INIT proposal (RFC 7296) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -434,7 +318,7 @@ define ikev2_set_responder_reply @param dh_group - Diffie-Hellman group */ -define ikev2_set_ike_transforms +autoreply define ikev2_set_ike_transforms { u32 client_index; u32 context; @@ -446,16 +330,6 @@ define ikev2_set_ike_transforms u32 dh_group; }; -/** \brief Reply for IKEv2: Set IKEv2 IKE transforms - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_set_ike_transforms_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set IKEv2 ESP transforms in SA_INIT proposal (RFC 7296) @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -467,7 +341,7 @@ define ikev2_set_ike_transforms_reply @param dh_group - Diffie-Hellman group */ -define ikev2_set_esp_transforms +autoreply define ikev2_set_esp_transforms { u32 client_index; u32 context; @@ -479,16 +353,6 @@ define ikev2_set_esp_transforms u32 dh_group; }; -/** \brief Reply for IKEv2: Set IKEv2 ESP transforms - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_set_esp_transforms_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Set Child SA lifetime, limited by time and/or data @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -500,7 +364,7 @@ define ikev2_set_esp_transforms_reply @param lifetime_maxdata - SA maximum life time in bytes (0 to disable) */ -define ikev2_set_sa_lifetime +autoreply define ikev2_set_sa_lifetime { u32 client_index; u32 context; @@ -512,16 +376,6 @@ define ikev2_set_sa_lifetime u64 lifetime_maxdata; }; -/** \brief Reply for IKEv2: Set Child SA lifetime - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_set_sa_lifetime_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Initiate the SA_INIT exchange @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -529,7 +383,7 @@ define ikev2_set_sa_lifetime_reply @param name - IKEv2 profile name */ -define ikev2_initiate_sa_init +autoreply define ikev2_initiate_sa_init { u32 client_index; u32 context; @@ -537,16 +391,6 @@ define ikev2_initiate_sa_init u8 name[64]; }; -/** \brief Reply for IKEv2: Initiate the SA_INIT exchange - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_initiate_sa_init_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Initiate the delete IKE SA exchange @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -554,7 +398,7 @@ define ikev2_initiate_sa_init_reply @param ispi - IKE SA initiator SPI */ -define ikev2_initiate_del_ike_sa +autoreply define ikev2_initiate_del_ike_sa { u32 client_index; u32 context; @@ -562,16 +406,6 @@ define ikev2_initiate_del_ike_sa u64 ispi; }; -/** \brief Reply for IKEv2: Initiate the delete IKE SA exchange - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_initiate_del_ike_sa_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Initiate the delete Child SA exchange @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -579,7 +413,7 @@ define ikev2_initiate_del_ike_sa_reply @param ispi - Child SA initiator SPI */ -define ikev2_initiate_del_child_sa +autoreply define ikev2_initiate_del_child_sa { u32 client_index; u32 context; @@ -587,16 +421,6 @@ define ikev2_initiate_del_child_sa u32 ispi; }; -/** \brief Reply for IKEv2: Initiate the delete Child SA exchange - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_initiate_del_child_sa_reply -{ - u32 context; - i32 retval; -}; - /** \brief IKEv2: Initiate the rekey Child SA exchange @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -604,7 +428,7 @@ define ikev2_initiate_del_child_sa_reply @param ispi - Child SA initiator SPI */ -define ikev2_initiate_rekey_child_sa +autoreply define ikev2_initiate_rekey_child_sa { u32 client_index; u32 context; @@ -612,16 +436,6 @@ define ikev2_initiate_rekey_child_sa u32 ispi; }; -/** \brief Reply for IKEv2: Initiate the rekey Child SA exchange - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ikev2_initiate_rekey_child_sa_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump ipsec policy database data @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -682,4 +496,4 @@ define ipsec_spd_details { * eval: (c-set-style "gnu") * End: */ - \ No newline at end of file + diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index c23eebec..db42d635 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -70,66 +70,36 @@ define l2_fib_table_dump @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ -define l2_fib_clear_table +autoreply define l2_fib_clear_table { u32 client_index; u32 context; }; -/** \brief L2 fib clear table response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_fib_clear_table_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 FIB flush bridge domain entries @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bd_id - the entry's bridge domain id */ -define l2fib_flush_bd +autoreply define l2fib_flush_bd { u32 client_index; u32 context; u32 bd_id; }; -/** \brief L2 FIB flush bridge domain entries response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2fib_flush_bd_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 FIB flush interface entries @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bd_id - the entry's bridge domain id */ -define l2fib_flush_int +autoreply define l2fib_flush_int { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief L2 FIB flush interface entries response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2fib_flush_int_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 FIB add entry request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -140,7 +110,7 @@ define l2fib_flush_int_reply @param static_mac - @param filter_mac - */ -define l2fib_add_del +autoreply define l2fib_add_del { u32 client_index; u32 context; @@ -153,16 +123,6 @@ define l2fib_add_del u8 bvi_mac; }; -/** \brief L2 FIB add entry response - @param context - sender context, to match reply w/ request - @param retval - return code for the add l2fib entry request -*/ -define l2fib_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set L2 flags request !!! TODO - need more info, feature bits in l2_input.h @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -196,7 +156,7 @@ define l2_flags_reply @param bd_id - the bridge domain to create @param mac_age - mac aging time in min, 0 for disabled */ -define bridge_domain_set_mac_age +autoreply define bridge_domain_set_mac_age { u32 client_index; u32 context; @@ -204,16 +164,6 @@ define bridge_domain_set_mac_age u8 mac_age; }; -/** \brief Set bridge domain response - @param context - sender context, to match reply w/ request - @param retval - return code for the set l2 bits request -*/ -define bridge_domain_set_mac_age_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 bridge domain add or delete request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -226,7 +176,7 @@ define bridge_domain_set_mac_age_reply @param mac_age - mac aging time in min, 0 for disabled @param is_add - add or delete flag */ -define bridge_domain_add_del +autoreply define bridge_domain_add_del { u32 client_index; u32 context; @@ -240,16 +190,6 @@ define bridge_domain_add_del u8 is_add; }; -/** \brief L2 bridge domain add or delete response - @param context - sender context, to match reply w/ request - @param retval - return code for the set bridge flags request -*/ -define bridge_domain_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 bridge domain request operational state details @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -337,7 +277,7 @@ define bridge_flags_reply @param tag1 - Needed for any push or translate vtr op @param tag2 - Needed for any push 2 or translate x-2 vtr ops */ -define l2_interface_vlan_tag_rewrite +autoreply define l2_interface_vlan_tag_rewrite { u32 client_index; u32 context; @@ -348,16 +288,6 @@ define l2_interface_vlan_tag_rewrite u32 tag2; // second pushed tag }; -/** \brief L2 interface vlan tag rewrite response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_interface_vlan_tag_rewrite_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 interface pbb tag rewrite configure request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -370,7 +300,7 @@ define l2_interface_vlan_tag_rewrite_reply @param b_vlanid - B-tag vlanid, needed for any push or translate qinq vtr op @param i_sid - I-tag service id, needed for any push or translate qinq vtr op */ -define l2_interface_pbb_tag_rewrite +autoreply define l2_interface_pbb_tag_rewrite { u32 client_index; u32 context; @@ -383,16 +313,6 @@ define l2_interface_pbb_tag_rewrite u32 i_sid; }; -/** \brief L2 interface pbb tag rewrite response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_interface_pbb_tag_rewrite_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/l2tp/l2tp.api b/src/vnet/l2tp/l2tp.api index 5a5a5a48..4587a807 100644 --- a/src/vnet/l2tp/l2tp.api +++ b/src/vnet/l2tp/l2tp.api @@ -52,7 +52,7 @@ define l2tpv3_create_tunnel_reply u32 sw_if_index; }; -define l2tpv3_set_tunnel_cookies +autoreply define l2tpv3_set_tunnel_cookies { u32 client_index; u32 context; @@ -61,16 +61,6 @@ define l2tpv3_set_tunnel_cookies u64 new_remote_cookie; }; -/** \brief L2TP tunnel set cookies response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2tpv3_set_tunnel_cookies_reply -{ - u32 context; - i32 retval; -}; - define sw_if_l2tpv3_tunnel_details { u32 context; @@ -91,7 +81,7 @@ define sw_if_l2tpv3_tunnel_dump u32 context; }; -define l2tpv3_interface_enable_disable +autoreply define l2tpv3_interface_enable_disable { u32 client_index; u32 context; @@ -99,13 +89,7 @@ define l2tpv3_interface_enable_disable u32 sw_if_index; }; -define l2tpv3_interface_enable_disable_reply -{ - u32 context; - i32 retval; -}; - -define l2tpv3_set_lookup_key +autoreply define l2tpv3_set_lookup_key { u32 client_index; u32 context; @@ -113,12 +97,6 @@ define l2tpv3_set_lookup_key u8 key; }; -define l2tpv3_set_lookup_key_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/lisp-cp/lisp.api b/src/vnet/lisp-cp/lisp.api index a50a5ccb..8bed71b3 100644 --- a/src/vnet/lisp-cp/lisp.api +++ b/src/vnet/lisp-cp/lisp.api @@ -59,7 +59,7 @@ define lisp_add_del_locator_set_reply @param priority - priority of the lisp locator @param weight - weight of the lisp locator */ -define lisp_add_del_locator +autoreply define lisp_add_del_locator { u32 client_index; u32 context; @@ -70,16 +70,6 @@ define lisp_add_del_locator u8 weight; }; -/** \brief Reply for locator add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_locator_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete lisp eid-table @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -98,7 +88,7 @@ define lisp_add_del_locator_reply HMAC_SHA_256_128 2 @param key - secret key */ -define lisp_add_del_local_eid +autoreply define lisp_add_del_local_eid { u32 client_index; u32 context; @@ -112,16 +102,6 @@ define lisp_add_del_local_eid u8 key[64]; }; -/** \brief Reply for local_eid add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_local_eid_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add/delete map server @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -129,7 +109,7 @@ define lisp_add_del_local_eid_reply @param is_ipv6 - if non-zero the address is ipv6, else ipv4 @param ip_address - map server IP address */ -define lisp_add_del_map_server +autoreply define lisp_add_del_map_server { u32 client_index; u32 context; @@ -138,16 +118,6 @@ define lisp_add_del_map_server u8 ip_address[16]; }; -/** \brief Reply for lisp_add_del_map_server - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_map_server_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete map-resolver @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -155,7 +125,7 @@ define lisp_add_del_map_server_reply @param is_ipv6 - if non-zero the address is ipv6, else ipv4 @param ip_address - array of address bytes */ -define lisp_add_del_map_resolver +autoreply define lisp_add_del_map_resolver { u32 client_index; u32 context; @@ -164,45 +134,25 @@ define lisp_add_del_map_resolver u8 ip_address[16]; }; -/** \brief Reply for map_resolver add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_map_resolver_reply -{ - u32 context; - i32 retval; -}; - /** \brief enable or disable LISP feature @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_en - enable protocol if non-zero, else disable */ -define lisp_enable_disable +autoreply define lisp_enable_disable { u32 client_index; u32 context; u8 is_en; }; -/** \brief Reply for gpe enable/disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief configure or disable LISP PITR node @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param ls_name - locator set name @param is_add - add locator set if non-zero, else disable pitr */ -define lisp_pitr_set_locator_set +autoreply define lisp_pitr_set_locator_set { u32 client_index; u32 context; @@ -210,16 +160,6 @@ define lisp_pitr_set_locator_set u8 ls_name[64]; }; -/** \brief Reply for lisp_pitr_set_locator_set - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_pitr_set_locator_set_reply -{ - u32 context; - i32 retval; -}; - /** \brief configure or disable use of PETR @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -227,7 +167,7 @@ define lisp_pitr_set_locator_set_reply @param address - PETR IP address @param is_add - add locator set if non-zero, else disable pitr */ -define lisp_use_petr +autoreply define lisp_use_petr { u32 client_index; u32 context; @@ -236,16 +176,6 @@ define lisp_use_petr u8 is_add; }; -/** \brief Reply for lisp_pitr_set_locator_set - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_use_petr_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for LISP PETR status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -298,45 +228,25 @@ define show_lisp_rloc_probe_state_reply @param context - sender context, to match reply w/ request @param is_enable - enable if non-zero; disable otherwise */ -define lisp_rloc_probe_enable_disable +autoreply define lisp_rloc_probe_enable_disable { u32 client_index; u32 context; u8 is_enabled; }; -/** \brief Reply for lisp_rloc_probe_enable_disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_rloc_probe_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief enable/disable LISP map-register @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_enable - enable if non-zero; disable otherwise */ -define lisp_map_register_enable_disable +autoreply define lisp_map_register_enable_disable { u32 client_index; u32 context; u8 is_enabled; }; -/** \brief Reply for lisp_map_register_enable_disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_map_register_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get state of LISP map-register @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -366,23 +276,13 @@ define show_lisp_map_register_state_reply 0 - destination only 1 - source/destaination */ -define lisp_map_request_mode +autoreply define lisp_map_request_mode { u32 client_index; u32 context; u8 mode; }; -/** \brief Reply for lisp_map_request_mode - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_map_request_mode_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for LISP map-request mode @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -430,7 +330,7 @@ typeonly manual_endian manual_print define remote_locator @param rloc_num - number of remote locators @param rlocs - remote locator records */ -manual_print manual_endian define lisp_add_del_remote_mapping +autoreply manual_print manual_endian define lisp_add_del_remote_mapping { u32 client_index; u32 context; @@ -448,16 +348,6 @@ manual_print manual_endian define lisp_add_del_remote_mapping vl_api_remote_locator_t rlocs[rloc_num]; }; -/** \brief Reply for lisp_add_del_remote_mapping - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_remote_mapping_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete LISP adjacency adjacency @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -470,7 +360,7 @@ define lisp_add_del_remote_mapping_reply @param reid - remote EID @param leid - local EID */ -define lisp_add_del_adjacency +autoreply define lisp_add_del_adjacency { u32 client_index; u32 context; @@ -483,23 +373,13 @@ define lisp_add_del_adjacency u8 leid_len; }; -/** \brief Reply for lisp_add_del_adjacency - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_add_del_adjacency_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete map request itr rlocs @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_add - add address if non-zero, else delete @param locator_set_name - locator set name */ -define lisp_add_del_map_request_itr_rlocs +autoreply define lisp_add_del_map_request_itr_rlocs { u32 client_index; u32 context; @@ -512,12 +392,6 @@ define lisp_add_del_map_request_itr_rlocs @param retval - return code */ -define lisp_add_del_map_request_itr_rlocs_reply -{ - u32 context; - i32 retval; -}; - /** \brief map/unmap vni/bd_index to vrf @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -525,7 +399,7 @@ define lisp_add_del_map_request_itr_rlocs_reply @param dp_table - virtual network id/bridge domain index @param vrf - vrf */ -define lisp_eid_table_add_del_map +autoreply define lisp_eid_table_add_del_map { u32 client_index; u32 context; @@ -535,16 +409,6 @@ define lisp_eid_table_add_del_map u8 is_l2; }; -/** \brief Reply for lisp_eid_table_add_del_map - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define lisp_eid_table_add_del_map_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for map lisp locator status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/lisp-cp/one.api b/src/vnet/lisp-cp/one.api index ca82f694..2fa1edf6 100644 --- a/src/vnet/lisp-cp/one.api +++ b/src/vnet/lisp-cp/one.api @@ -59,7 +59,7 @@ define one_add_del_locator_set_reply @param priority - priority of the locator @param weight - weight of the locator */ -define one_add_del_locator +autoreply define one_add_del_locator { u32 client_index; u32 context; @@ -70,16 +70,6 @@ define one_add_del_locator u8 weight; }; -/** \brief Reply for locator add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_locator_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete ONE eid-table @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -98,7 +88,7 @@ define one_add_del_locator_reply HMAC_SHA_256_128 2 @param key - secret key */ -define one_add_del_local_eid +autoreply define one_add_del_local_eid { u32 client_index; u32 context; @@ -112,16 +102,6 @@ define one_add_del_local_eid u8 key[64]; }; -/** \brief Reply for local_eid add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_local_eid_reply -{ - u32 context; - i32 retval; -}; - /** \brief Add/delete map server @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -129,7 +109,7 @@ define one_add_del_local_eid_reply @param is_ipv6 - if non-zero the address is ipv6, else ipv4 @param ip_address - map server IP address */ -define one_add_del_map_server +autoreply define one_add_del_map_server { u32 client_index; u32 context; @@ -138,16 +118,6 @@ define one_add_del_map_server u8 ip_address[16]; }; -/** \brief Reply for one_add_del_map_server - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_map_server_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete map-resolver @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -155,7 +125,7 @@ define one_add_del_map_server_reply @param is_ipv6 - if non-zero the address is ipv6, else ipv4 @param ip_address - array of address bytes */ -define one_add_del_map_resolver +autoreply define one_add_del_map_resolver { u32 client_index; u32 context; @@ -164,45 +134,25 @@ define one_add_del_map_resolver u8 ip_address[16]; }; -/** \brief Reply for map_resolver add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_map_resolver_reply -{ - u32 context; - i32 retval; -}; - /** \brief enable or disable ONE feature @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_en - enable protocol if non-zero, else disable */ -define one_enable_disable +autoreply define one_enable_disable { u32 client_index; u32 context; u8 is_en; }; -/** \brief Reply for gpe enable/disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief configure or disable ONE PITR node @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param ls_name - locator set name @param is_add - add locator set if non-zero, else disable pitr */ -define one_pitr_set_locator_set +autoreply define one_pitr_set_locator_set { u32 client_index; u32 context; @@ -210,16 +160,6 @@ define one_pitr_set_locator_set u8 ls_name[64]; }; -/** \brief Reply for one_pitr_set_locator_set - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_pitr_set_locator_set_reply -{ - u32 context; - i32 retval; -}; - /** \brief configure or disable use of PETR @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -227,7 +167,7 @@ define one_pitr_set_locator_set_reply @param address - PETR IP address @param is_add - add locator set if non-zero, else disable PETR */ -define one_use_petr +autoreply define one_use_petr { u32 client_index; u32 context; @@ -236,16 +176,6 @@ define one_use_petr u8 is_add; }; -/** \brief Reply for one_use_petr - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_use_petr_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for ONE PETR status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -298,45 +228,25 @@ define show_one_rloc_probe_state_reply @param context - sender context, to match reply w/ request @param is_enable - enable if non-zero; disable otherwise */ -define one_rloc_probe_enable_disable +autoreply define one_rloc_probe_enable_disable { u32 client_index; u32 context; u8 is_enabled; }; -/** \brief Reply for one_rloc_probe_enable_disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_rloc_probe_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief enable/disable ONE map-register @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_enable - enable if non-zero; disable otherwise */ -define one_map_register_enable_disable +autoreply define one_map_register_enable_disable { u32 client_index; u32 context; u8 is_enabled; }; -/** \brief Reply for one_map_register_enable_disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_map_register_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get state of ONE map-register @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -366,23 +276,13 @@ define show_one_map_register_state_reply 0 - destination only 1 - source/destaination */ -define one_map_request_mode +autoreply define one_map_request_mode { u32 client_index; u32 context; u8 mode; }; -/** \brief Reply for one_map_request_mode - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_map_request_mode_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for ONE map-request mode @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -430,7 +330,7 @@ typeonly manual_endian manual_print define one_remote_locator @param rloc_num - number of remote locators @param rlocs - remote locator records */ -manual_print manual_endian define one_add_del_remote_mapping +autoreply manual_print manual_endian define one_add_del_remote_mapping { u32 client_index; u32 context; @@ -448,16 +348,6 @@ manual_print manual_endian define one_add_del_remote_mapping vl_api_one_remote_locator_t rlocs[rloc_num]; }; -/** \brief Reply for one_add_del_remote_mapping - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_remote_mapping_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete ONE adjacency adjacency @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -470,7 +360,7 @@ define one_add_del_remote_mapping_reply @param reid - remote EID @param leid - local EID */ -define one_add_del_adjacency +autoreply define one_add_del_adjacency { u32 client_index; u32 context; @@ -483,23 +373,13 @@ define one_add_del_adjacency u8 leid_len; }; -/** \brief Reply for one_add_del_adjacency - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_add_del_adjacency_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete map request itr rlocs @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_add - add address if non-zero, else delete @param locator_set_name - locator set name */ -define one_add_del_map_request_itr_rlocs +autoreply define one_add_del_map_request_itr_rlocs { u32 client_index; u32 context; @@ -507,17 +387,6 @@ define one_add_del_map_request_itr_rlocs u8 locator_set_name[64]; }; -/** \brief Reply for one_add_del_map_request_itr_rlocs - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ - -define one_add_del_map_request_itr_rlocs_reply -{ - u32 context; - i32 retval; -}; - /** \brief map/unmap vni/bd_index to vrf @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -525,7 +394,7 @@ define one_add_del_map_request_itr_rlocs_reply @param dp_table - virtual network id/bridge domain index @param vrf - vrf */ -define one_eid_table_add_del_map +autoreply define one_eid_table_add_del_map { u32 client_index; u32 context; @@ -535,16 +404,6 @@ define one_eid_table_add_del_map u8 is_l2; }; -/** \brief Reply for one_eid_table_add_del_map - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define one_eid_table_add_del_map_reply -{ - u32 context; - i32 retval; -}; - /** \brief Request for map one locator status @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -901,31 +760,19 @@ define one_stats_details u32 bytes; }; -define one_stats_flush +autoreply define one_stats_flush { u32 client_index; u32 context; }; -define one_stats_flush_reply -{ - u32 context; - i32 retval; -}; - -define one_stats_enable_disable +autoreply define one_stats_enable_disable { u32 client_index; u32 context; u8 is_en; }; -define one_stats_enable_disable_reply -{ - u32 context; - i32 retval; -}; - define show_one_stats_enable_disable { u32 client_index; diff --git a/src/vnet/lisp-gpe/lisp_gpe.api b/src/vnet/lisp-gpe/lisp_gpe.api index 43a6a6cd..f79d18c1 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.api +++ b/src/vnet/lisp-gpe/lisp_gpe.api @@ -43,7 +43,7 @@ typeonly manual_print manual_endian define gpe_locator @param loc_num - number of locators @param locs - array of remote locators */ -manual_print manual_endian define gpe_add_del_fwd_entry +autoreply manual_print manual_endian define gpe_add_del_fwd_entry { u32 client_index; u32 context; @@ -60,44 +60,24 @@ manual_print manual_endian define gpe_add_del_fwd_entry vl_api_gpe_locator_t locs[loc_num]; }; -/** \brief Reply for gpe_fwd_entry add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define gpe_add_del_fwd_entry_reply -{ - u32 context; - i32 retval; -}; - /** \brief enable or disable gpe protocol @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_en - enable protocol if non-zero, else disable */ -define gpe_enable_disable +autoreply define gpe_enable_disable { u32 client_index; u32 context; u8 is_en; }; -/** \brief Reply for gpe enable/disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define gpe_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief add or delete gpe_iface @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_add - add address if non-zero, else delete */ -define gpe_add_del_iface +autoreply define gpe_add_del_iface { u32 client_index; u32 context; @@ -107,16 +87,6 @@ define gpe_add_del_iface u32 vni; }; -/** \brief Reply for gpe_iface add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define gpe_add_del_iface_reply -{ - u32 context; - i32 retval; -}; - define gpe_fwd_entries_get { u32 client_index; @@ -163,23 +133,13 @@ manual_endian manual_print define gpe_fwd_entry_path_details @param context - sender context, to match reply w/ request @param mode - LISP (value 0) or VXLAN (value 1) */ -define gpe_set_encap_mode +autoreply define gpe_set_encap_mode { u32 client_index; u32 context; u8 mode; }; -/** \brief Reply for set_encap_mode - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define gpe_set_encap_mode_reply -{ - u32 context; - i32 retval; -}; - /** \brief get GPE encapsulation mode @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/map/map.api b/src/vnet/map/map.api index 4e4be85e..d68f13f0 100644 --- a/src/vnet/map/map.api +++ b/src/vnet/map/map.api @@ -62,22 +62,13 @@ define map_add_domain_reply @param context - sender context, to match reply w/ request @param index - MAP Domain index */ -define map_del_domain +autoreply define map_del_domain { u32 client_index; u32 context; u32 index; }; -/** \brief Reply for MAP domain del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define map_del_domain_reply -{ - u32 context; - i32 retval; -}; /** \brief Add or Delete MAP rule from a domain (Only used for shared IPv4 per subscriber) @param client_index - opaque cookie to identify the sender @@ -87,7 +78,7 @@ define map_del_domain_reply @param ip6_dst - MAP CE IPv6 address @param psid - Rule PSID */ -define map_add_del_rule +autoreply define map_add_del_rule { u32 client_index; u32 context; @@ -97,15 +88,6 @@ define map_add_del_rule u16 psid; }; -/** \brief Reply for MAP rule add/del - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define map_add_del_rule_reply -{ - u32 context; - i32 retval; -}; /** \brief Get list of map domains @param client_index - opaque cookie to identify the sender diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api index a1e1270a..c8a3ffb7 100644 --- a/src/vnet/mpls/mpls.api +++ b/src/vnet/mpls/mpls.api @@ -26,7 +26,7 @@ @param mb_address_length - Length of IP prefix @param mb_address[16] - IP prefix/ */ -define mpls_ip_bind_unbind +autoreply define mpls_ip_bind_unbind { u32 client_index; u32 context; @@ -40,16 +40,6 @@ define mpls_ip_bind_unbind u8 mb_address[16]; }; -/** \brief Reply for MPLS IP bind/unbind request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_ip_bind_unbind_reply -{ - u32 context; - i32 retval; -}; - /** \brief MPLS tunnel Add / del route @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -172,7 +162,7 @@ manual_endian manual_print define mpls_tunnel_details @param mr_next_hop_out_label_stack - the next-hop output label stack, outer most first @param next_hop_via_label - The next-hop is a resolved via a local label */ -define mpls_route_add_del +autoreply define mpls_route_add_del { u32 client_index; u32 context; @@ -199,16 +189,6 @@ define mpls_route_add_del u32 mr_next_hop_out_label_stack[mr_next_hop_n_out_labels]; }; -/** \brief Reply for MPLS route add / del request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define mpls_route_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump MPLS fib table @param client_index - opaque cookie to identify the sender */ @@ -240,4 +220,4 @@ manual_endian manual_print define mpls_fib_details * eval: (c-set-style "gnu") * End: */ - \ No newline at end of file + diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api index e207e46f..4aef09da 100644 --- a/src/vnet/session/session.api +++ b/src/vnet/session/session.api @@ -49,26 +49,17 @@ define application_attach_reply { @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request */ - define application_detach { +autoreply define application_detach { u32 client_index; u32 context; }; - /** \brief detach reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define application_detach_reply { - u32 context; - i32 retval; -}; - /** \brief vpp->client, please map an additional shared memory segment @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param segment_name - */ -define map_another_segment { +autoreply define map_another_segment { u32 client_index; u32 context; u32 segment_size; @@ -83,7 +74,7 @@ define map_another_segment { "tcp://::/0/80" [ipv6] etc. @param options - socket options, fifo sizes, etc. */ -define bind_uri { +autoreply define bind_uri { u32 client_index; u32 context; u32 accept_cookie; @@ -97,7 +88,7 @@ define bind_uri { "tcp://::/0/80" [ipv6], etc. @param options - socket options, fifo sizes, etc. */ -define unbind_uri { +autoreply define unbind_uri { u32 client_index; u32 context; u8 uri[128]; @@ -122,24 +113,6 @@ define connect_uri { u64 options[16]; }; -/** \brief Bind reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define bind_uri_reply { - u32 context; - i32 retval; -}; - -/** \brief unbind reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define unbind_uri_reply { - u32 context; - i32 retval; -}; - /** \brief vpp->client, connect reply @param context - sender context, to match reply w/ request @param retval - return code for the request @@ -165,15 +138,6 @@ define connect_uri_reply { u8 segment_name[128]; }; -/** \brief client->vpp - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define map_another_segment_reply { - u32 context; - i32 retval; -}; - /** \brief vpp->client, accept this session @param context - sender context, to match reply w/ request @param listener_handle - tells client which listener this pertains to @@ -290,7 +254,7 @@ define bind_sock { @param context - sender context, to match reply w/ request @param handle - bind handle obtained from bind reply */ -define unbind_sock { +autoreply define unbind_sock { u32 client_index; u32 context; u64 handle; @@ -339,15 +303,6 @@ define bind_sock_reply { u8 segment_name[128]; }; -/** \brief unbind reply - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define unbind_sock_reply { - u32 context; - i32 retval; -}; - /** \brief vpp/server->client, connect reply @param context - sender context, to match reply w/ request @param retval - return code for the request @@ -378,23 +333,14 @@ define connect_sock_reply { @param context - sender context, to match reply w/ request @param is_enable - disable session layer if 0, enable otherwise */ -define session_enable_disable { +autoreply define session_enable_disable { u32 client_index; u32 context; u8 is_enable; }; -/** \brief Reply for session enable/disable - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define session_enable_disable_reply { - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") * End: - */ \ No newline at end of file + */ diff --git a/src/vnet/span/span.api b/src/vnet/span/span.api index 4babdd83..914fd8d0 100644 --- a/src/vnet/span/span.api +++ b/src/vnet/span/span.api @@ -21,7 +21,7 @@ @param sw_if_index_to - interface where the traffic is mirrored @param state - 0 = disabled, 1 = rx enabled, 2 = tx enabled, 3 tx & rx enabled */ -define sw_interface_span_enable_disable { +autoreply define sw_interface_span_enable_disable { u32 client_index; u32 context; u32 sw_if_index_from; @@ -29,14 +29,6 @@ define sw_interface_span_enable_disable { u8 state; }; -/** \brief Reply to SPAN enable/disable request - @param context - sender context which was passed in the request -*/ -define sw_interface_span_enable_disable_reply { - u32 context; - i32 retval; -}; - /** \brief SPAN dump request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/sr/sr.api b/src/vnet/sr/sr.api index 5feadcb0..9e900741 100644 --- a/src/vnet/sr/sr.api +++ b/src/vnet/sr/sr.api @@ -25,7 +25,7 @@ @param fib_table FIB table in which we should install the localsid entry @param nh_addr Next Hop IPv4/IPv6 address. Only for L2/L3 xconnect. */ -define sr_localsid_add_del +autoreply define sr_localsid_add_del { u32 client_index; u32 context; @@ -39,16 +39,6 @@ define sr_localsid_add_del u8 nh_addr[16]; }; -/** \brief IPv6 SR LocalSID add/del request response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_localsid_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 SR policy add @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -59,7 +49,7 @@ define sr_localsid_add_del_reply @param fib_table is the VRF where to install the FIB entry for the BSID @param segments is a vector of IPv6 address composing the segment list */ -define sr_policy_add +autoreply define sr_policy_add { u32 client_index; u32 context; @@ -72,16 +62,6 @@ define sr_policy_add u8 segments[0]; }; -/** \brief IPv6 SR Policy add request response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_policy_add_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 SR policy modification @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -94,7 +74,7 @@ define sr_policy_add_reply @param weight is the weight of the sid list. optional. @param is_encap Mode. Encapsulation or SRH insertion. */ -define sr_policy_mod +autoreply define sr_policy_mod { u32 client_index; u32 context; @@ -108,23 +88,13 @@ define sr_policy_mod u8 segments[0]; }; -/** \brief IPv6 SR Policy modification request response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_policy_mod_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 SR policy deletion @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bsid is the bindingSID of the SR Policy @param index is the index of the SR policy */ -define sr_policy_del +autoreply define sr_policy_del { u32 client_index; u32 context; @@ -132,16 +102,6 @@ define sr_policy_del u32 sr_policy_index; }; -/** \brief IPv6 SR Policy deletion request response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_policy_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief IPv6 SR steering add/del @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -154,7 +114,7 @@ define sr_policy_del_reply @param sw_if_index is the incoming interface for L2 traffic @param traffic_type describes the type of traffic */ -define sr_steering_add_del +autoreply define sr_steering_add_del { u32 client_index; u32 context; @@ -168,16 +128,6 @@ define sr_steering_add_del u8 traffic_type; }; -/** \brief IPv6 SR steering add/del request response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define sr_steering_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump the list of SR LocalSIDs @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/unix/tap.api b/src/vnet/unix/tap.api index 1fd0bb09..d9fba371 100644 --- a/src/vnet/unix/tap.api +++ b/src/vnet/unix/tap.api @@ -93,23 +93,13 @@ define tap_modify_reply @param context - sender context, to match reply w/ request @param sw_if_index - interface index of existing tap interface */ -define tap_delete +autoreply define tap_delete { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief Reply for tap delete request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define tap_delete_reply -{ - u32 context; - i32 retval; -}; - /** \brief Dump tap interfaces request */ define sw_interface_tap_dump { diff --git a/src/vnet/vxlan/vxlan.api b/src/vnet/vxlan/vxlan.api index 048220fb..6c331a58 100644 --- a/src/vnet/vxlan/vxlan.api +++ b/src/vnet/vxlan/vxlan.api @@ -61,7 +61,7 @@ define vxlan_tunnel_details @param is_ipv6 - if non-zero, enable ipv6-vxlan-bypass, else ipv4-vxlan-bypass @param enable - if non-zero enable, else disable */ -define sw_interface_set_vxlan_bypass +autoreply define sw_interface_set_vxlan_bypass { u32 client_index; u32 context; @@ -69,13 +69,3 @@ define sw_interface_set_vxlan_bypass u8 is_ipv6; u8 enable; }; - -/** \brief Interface set vxlan-bypass response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_set_vxlan_bypass_reply -{ - u32 context; - i32 retval; -}; \ No newline at end of file diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index a4ba180d..7c07c822 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -80,7 +80,7 @@ define create_vlan_subif_reply @param sw_if_index - index of the interface @param enable - if non-zero enable, else disable */ -define sw_interface_set_mpls_enable +autoreply define sw_interface_set_mpls_enable { u32 client_index; u32 context; @@ -88,16 +88,6 @@ define sw_interface_set_mpls_enable u8 enable; }; -/** \brief Reply for MPLS state on an interface - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define sw_interface_set_mpls_enable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Proxy ARP add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -106,7 +96,7 @@ define sw_interface_set_mpls_enable_reply @param low_address[4] - Low address of the Proxy ARP range @param hi_address[4] - High address of the Proxy ARP range */ -define proxy_arp_add_del +autoreply define proxy_arp_add_del { u32 client_index; u32 context; @@ -116,23 +106,13 @@ define proxy_arp_add_del u8 hi_address[4]; }; -/** \brief Reply for proxy arp add / del request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define proxy_arp_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Proxy ARP add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - Which interface to enable / disable Proxy Arp on @param enable_disable - 1 to enable Proxy ARP on interface, 0 to disable */ -define proxy_arp_intfc_enable_disable +autoreply define proxy_arp_intfc_enable_disable { u32 client_index; u32 context; @@ -141,23 +121,13 @@ define proxy_arp_intfc_enable_disable u8 enable_disable; }; -/** \brief Reply for Proxy ARP interface enable / disable request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define proxy_arp_intfc_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Reset VRF (remove all routes etc) request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_ipv6 - 1 for IPv6 neighbor, 0 for IPv4 @param vrf_id - ID of th FIB table / VRF to reset */ -define reset_vrf +autoreply define reset_vrf { u32 client_index; u32 context; @@ -165,16 +135,6 @@ define reset_vrf u32 vrf_id; }; -/** \brief Reply for Reset VRF request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define reset_vrf_reply -{ - u32 context; - i32 retval; -}; - /** \brief Is Address Reachable request - DISABLED @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -200,7 +160,7 @@ define is_address_reachable @param enable_disable - 1 = enable stats, 0 = disable @param pid - pid of process requesting stats updates */ -define want_stats +autoreply define want_stats { u32 client_index; u32 context; @@ -208,16 +168,6 @@ define want_stats u32 pid; }; -/** \brief Reply for Want Stats request - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define want_stats_reply -{ - u32 context; - i32 retval; -}; - typeonly manual_print manual_endian define ip4_fib_counter { u32 address; @@ -331,7 +281,7 @@ define oam_event @param enable_disable- enable if non-zero, else disable @param pid - pid of the requesting process */ -define want_oam_events +autoreply define want_oam_events { u32 client_index; u32 context; @@ -339,16 +289,6 @@ define want_oam_events u32 pid; }; -/** \brief Want OAM events response - @param context - sender context, to match reply w/ request - @param retval - return code for the want oam stats request -*/ -define want_oam_events_reply -{ - u32 context; - i32 retval; -}; - /** \brief OAM add / del target request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -357,7 +297,7 @@ define want_oam_events_reply @param dst_address[] - destination address of the target @param is_add - add target if non-zero, else delete */ -define oam_add_del +autoreply define oam_add_del { u32 client_index; u32 context; @@ -367,23 +307,13 @@ define oam_add_del u8 is_add; }; -/** \brief OAM add / del target response - @param context - sender context, to match reply w/ request - @param retval - return code of the request -*/ -define oam_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Reset fib table request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param vrf_id - vrf/table id of the fib table to reset @param is_ipv6 - an ipv6 fib to reset if non-zero, else ipv4 */ -define reset_fib +autoreply define reset_fib { u32 client_index; u32 context; @@ -391,16 +321,6 @@ define reset_fib u8 is_ipv6; }; -/** \brief Reset fib response - @param context - sender context, to match reply w/ request - @param retval - return code for the reset bfib request -*/ -define reset_fib_reply -{ - u32 context; - i32 retval; -}; - /** \brief Create loopback interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -458,23 +378,13 @@ define create_loopback_instance_reply @param context - sender context, to match reply w/ request @param sw_if_index - sw index of the interface that was created */ -define delete_loopback +autoreply define delete_loopback { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief Delete loopback interface response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define delete_loopback_reply -{ - u32 context; - i32 retval; -}; - /** \brief Control ping from client to api server request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -543,7 +453,7 @@ define cli_inband_reply @param is_ipv6 - neighbor limit if non-zero, else ARP limit @param arp_neighbor_limit - the new limit, defaults are ~ 50k */ -define set_arp_neighbor_limit +autoreply define set_arp_neighbor_limit { u32 client_index; u32 context; @@ -551,16 +461,6 @@ define set_arp_neighbor_limit u32 arp_neighbor_limit; }; -/** \brief Set max allowed ARP or ip6 neighbor entries response - @param context - sender context, to match reply w/ request - @param retval - return code for request -*/ -define set_arp_neighbor_limit_reply -{ - u32 context; - i32 retval; -}; - /** \brief L2 interface patch add / del request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -568,7 +468,7 @@ define set_arp_neighbor_limit_reply @param tx_sw_if_index - transmit side interface @param is_add - if non-zero set up the interface patch, else remove it */ -define l2_patch_add_del +autoreply define l2_patch_add_del { u32 client_index; u32 context; @@ -577,23 +477,13 @@ define l2_patch_add_del u8 is_add; }; -/** \brief L2 interface patch add / del response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_patch_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Interface set vpath request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - interface used to reach neighbor @param enable - if non-zero enable, else disable */ -define sw_interface_set_vpath +autoreply define sw_interface_set_vpath { u32 client_index; u32 context; @@ -601,16 +491,6 @@ define sw_interface_set_vpath u8 enable; }; -/** \brief Interface set vpath response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define sw_interface_set_vpath_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set L2 XConnect between two interfaces request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -618,7 +498,7 @@ define sw_interface_set_vpath_reply @param tx_sw_if_index - Transmit interface index @param enable - enable xconnect if not 0, else set to L3 mode */ -define sw_interface_set_l2_xconnect +autoreply define sw_interface_set_l2_xconnect { u32 client_index; u32 context; @@ -627,16 +507,6 @@ define sw_interface_set_l2_xconnect u8 enable; }; -/** \brief Set L2 XConnect response - @param context - sender context, to match reply w/ request - @param retval - L2 XConnect request return code -*/ -define sw_interface_set_l2_xconnect_reply -{ - u32 context; - i32 retval; -}; - /** \brief Interface bridge mode request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -646,7 +516,7 @@ define sw_interface_set_l2_xconnect_reply @param shg - Shared horizon group, for bridge mode only @param enable - Enable beige mode if not 0, else set to L3 mode */ -define sw_interface_set_l2_bridge +autoreply define sw_interface_set_l2_bridge { u32 client_index; u32 context; @@ -657,16 +527,6 @@ define sw_interface_set_l2_bridge u8 enable; }; -/** \brief Interface bridge mode response - @param context - sender context, to match reply w/ request - @param retval - Bridge mode request return code -*/ -define sw_interface_set_l2_bridge_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set bridge domain ip to mac entry request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -676,7 +536,7 @@ define sw_interface_set_l2_bridge_reply @param mac_address - MAC address @param */ -define bd_ip_mac_add_del +autoreply define bd_ip_mac_add_del { u32 client_index; u32 context; @@ -687,16 +547,6 @@ define bd_ip_mac_add_del u8 mac_address[6]; }; -/** \brief Set bridge domain ip to mac entry response - @param context - sender context, to match reply w/ request - @param retval - return code for the set bridge flags request -*/ -define bd_ip_mac_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set/unset the classification table for an interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -704,7 +554,7 @@ define bd_ip_mac_add_del_reply @param sw_if_index - interface to associate with the table @param table_index - index of the table, if ~0 unset the table */ -define classify_set_interface_ip_table +autoreply define classify_set_interface_ip_table { u32 client_index; u32 context; @@ -713,16 +563,6 @@ define classify_set_interface_ip_table u32 table_index; /* ~0 => off */ }; -/** \brief Set/unset interface classification table response - @param context - sender context, to match reply w/ request - @param retval - return code -*/ -define classify_set_interface_ip_table_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set/unset l2 classification tables for an interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -731,7 +571,7 @@ define classify_set_interface_ip_table_reply @param ip6_table_index - ip6 index @param other_table_index - other index */ -define classify_set_interface_l2_tables +autoreply define classify_set_interface_l2_tables { u32 client_index; u32 context; @@ -743,16 +583,6 @@ define classify_set_interface_l2_tables u8 is_input; }; -/** \brief Set/unset l2 classification tables for an interface response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define classify_set_interface_l2_tables_reply -{ - u32 context; - i32 retval; -}; - /** \brief Get node index using name request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -809,7 +639,7 @@ define add_node_next_reply @param sw_if_index - interface to enable/disable filtering on @param enable_disable - if non-zero enable filtering, else disable */ -define l2_interface_efp_filter +autoreply define l2_interface_efp_filter { u32 client_index; u32 context; @@ -817,16 +647,6 @@ define l2_interface_efp_filter u32 enable_disable; }; -/** \brief L2 interface ethernet flow point filtering response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define l2_interface_efp_filter_reply -{ - u32 context; - i32 retval; -}; - define create_subif { u32 client_index; @@ -882,7 +702,7 @@ define show_version_reply }; /* Gross kludge, DGMS */ -define interface_name_renumber +autoreply define interface_name_renumber { u32 client_index; u32 context; @@ -890,12 +710,6 @@ define interface_name_renumber u32 new_show_dev_instance; }; -define interface_name_renumber_reply -{ - u32 context; - i32 retval; -}; - /** \brief Register for ip4 arp resolution events @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -903,7 +717,7 @@ define interface_name_renumber_reply @param pid - sender's pid @param address - the exact ip4 address of interest */ -define want_ip4_arp_events +autoreply define want_ip4_arp_events { u32 client_index; u32 context; @@ -912,16 +726,6 @@ define want_ip4_arp_events u32 address; }; -/** \brief Reply for interface events registration - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define want_ip4_arp_events_reply -{ - u32 context; - i32 retval; -}; - /** \brief Tell client about an ip4 arp resolution event @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -949,7 +753,7 @@ define ip4_arp_event @param pid - sender's pid @param address - the exact ip6 address of interest */ -define want_ip6_nd_events +autoreply define want_ip6_nd_events { u32 client_index; u32 context; @@ -958,16 +762,6 @@ define want_ip6_nd_events u8 address[16]; }; -/** \brief Reply for ip6 nd resolution events registration - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define want_ip6_nd_events_reply -{ - u32 context; - i32 retval; -}; - /** \brief Tell client about an ip6 nd resolution or mac/ip event @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -999,7 +793,7 @@ define ip6_nd_event Note: User is recommeneded to use just one valid table_index per call. (ip4_table_index, ip6_table_index, or l2_table_index) */ -define input_acl_set_interface +autoreply define input_acl_set_interface { u32 client_index; u32 context; @@ -1010,16 +804,6 @@ define input_acl_set_interface u8 is_add; }; -/** \brief Set/unset input ACL interface response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define input_acl_set_interface_reply -{ - u32 context; - i32 retval; -}; - define get_node_graph { u32 client_index; @@ -1048,7 +832,7 @@ define get_node_graph_reply @param pow_enable - Proof of Work enabled or not flag @param trace_enable - iOAM Trace enabled or not flag */ -define ioam_enable +autoreply define ioam_enable { u32 client_index; u32 context; @@ -1060,38 +844,18 @@ define ioam_enable u32 node_id; }; -/** \brief iOAM Trace profile add / del response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define ioam_enable_reply -{ - u32 context; - i32 retval; -}; - /** \brief iOAM disable @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param index - MAP Domain index */ -define ioam_disable +autoreply define ioam_disable { u32 client_index; u32 context; u16 id; }; -/** \brief iOAM disable response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define ioam_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Query relative index via node names @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1149,7 +913,7 @@ define pg_create_interface_reply @param count - number of packets to be captured @param pcap_file - pacp file name to store captured packets */ -define pg_capture +autoreply define pg_capture { u32 client_index; u32 context; @@ -1160,23 +924,13 @@ define pg_capture u8 pcap_file_name[pcap_name_length]; }; -/** \brief PacketGenerator capture packets response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define pg_capture_reply -{ - u32 context; - i32 retval; -}; - /** \brief Enable / disable packet generator request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param is_enabled - 1 if enabling streams, 0 if disabling @param stream - stream name to be enable/disabled, if not specified handle all streams */ -define pg_enable_disable +autoreply define pg_enable_disable { u32 client_index; u32 context; @@ -1185,16 +939,6 @@ define pg_enable_disable u8 stream_name[stream_name_length]; }; -/** \brief Reply for enable / disable packet generator - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define pg_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /** \brief Configure IP source and L4 port-range check @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1208,7 +952,7 @@ define pg_enable_disable_reply @param vrf_id - fib table/vrf id to associate the source and port-range check with @note To specify a single port set low_port and high_port entry the same */ -define ip_source_and_port_range_check_add_del +autoreply define ip_source_and_port_range_check_add_del { u32 client_index; u32 context; @@ -1222,16 +966,6 @@ define ip_source_and_port_range_check_add_del u32 vrf_id; }; -/** \brief Configure IP source and L4 port-range check reply - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define ip_source_and_port_range_check_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Set interface source and L4 port-range request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1239,7 +973,7 @@ define ip_source_and_port_range_check_add_del_reply @param tcp_vrf_id - VRF associated with source and TCP port-range check @param udp_vrf_id - VRF associated with source and TCP port-range check */ -define ip_source_and_port_range_check_interface_add_del +autoreply define ip_source_and_port_range_check_interface_add_del { u32 client_index; u32 context; @@ -1251,36 +985,17 @@ define ip_source_and_port_range_check_interface_add_del u32 udp_out_vrf_id; }; -/** \brief Set interface source and L4 port-range response - @param context - sender context, to match reply w/ request - @param retval - return value for request -*/ -define ip_source_and_port_range_check_interface_add_del_reply -{ - u32 context; - i32 retval; -}; - /** \brief Delete sub interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - sw index of the interface that was created by create_subif */ -define delete_subif { +autoreply define delete_subif { u32 client_index; u32 context; u32 sw_if_index; }; -/** \brief Delete sub interface response - @param context - sender context, to match reply w/ request - @param retval - return code for the request -*/ -define delete_subif_reply { - u32 context; - i32 retval; -}; - /** \brief Punt traffic to the host @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -1289,7 +1004,7 @@ define delete_subif_reply { @param l4_protocol - L4 protocol to be punted, only UDP (0x11) is supported @param l4_port - TCP/UDP port to be punted */ -define punt { +autoreply define punt { u32 client_index; u32 context; u8 is_add; @@ -1298,23 +1013,13 @@ define punt { u16 l4_port; }; -/** \brief Reply to the punt request - @param context - sender context which was passed in the request - @param retval - return code of punt request -*/ -define punt_reply -{ - u32 context; - i32 retval; -}; - /** \brief Feature path enable/disable request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - the interface @param enable - 1 = on, 0 = off */ -define feature_enable_disable { +autoreply define feature_enable_disable { u32 client_index; u32 context; u32 sw_if_index; @@ -1323,16 +1028,6 @@ define feature_enable_disable { u8 feature_name[64]; }; -/** \brief Reply to the eature path enable/disable request - @param context - sender context which was passed in the request - @param retval - return code for the request -*/ -define feature_enable_disable_reply -{ - u32 context; - i32 retval; -}; - /* * Local Variables: * eval: (c-set-style "gnu") -- cgit 1.2.3-korg From d77630adaf48f05766c33ec60ef19ed50acae161 Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 28 Apr 2017 00:33:36 -0400 Subject: Fix memory leak on deletion of BD (bridge domain) On BD deletion, free memory used by members vector and mac_by_ip4 and mac_by_ip6 hash tables. Change-Id: Ied467e79bb6636fd8788bdeddee660c66391bb7e Signed-off-by: John Lo --- src/vnet/l2/l2_bd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index cfaf4c99..7c55789b 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -92,15 +92,21 @@ bd_add_bd_index (bd_main_t * bdm, u32 bd_id) static int bd_delete (bd_main_t * bdm, u32 bd_index) { - u32 bd_id = l2input_main.bd_configs[bd_index].bd_id; + l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; + u32 bd_id = bd->bd_id; hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ bdm->bd_index_bitmap = clib_bitmap_set (bdm->bd_index_bitmap, bd_index, 0); - l2input_main.bd_configs[bd_index].bd_id = ~0; - l2input_main.bd_configs[bd_index].feature_bitmap = 0; + /* clear BD config for reuse: bd_id to -1 and clear feature_bitmap */ + bd->bd_id = ~0; + bd->feature_bitmap = 0; + /* free memory used by BD and flush non-static MACs in BD */ + vec_free (bd->members); + hash_free (bd->mac_by_ip4); + hash_free (bd->mac_by_ip6); l2fib_flush_bd_mac (vlib_get_main (), bd_index); return 0; -- cgit 1.2.3-korg From 1c7d4858369881ac4cc287c4fa16eff2e9890c1c Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Tue, 2 May 2017 11:06:23 -0500 Subject: Prevent Bridge Domain operations on BD 0. The default bridge domain, 0, is created automatically with static features. It should be modified by neither the CLI nor the API. So add tests for, and reject any operation on BD 0. The new API error message BD_NOT_MODIFIABLE is returned in such cases. Change-Id: Iaf3dd80c4f43cf41689ca55756a0a3525420cd12 Signed-off-by: Jon Loeliger --- src/vnet/api_errno.h | 3 ++- src/vnet/l2/l2_api.c | 19 ++++++++++++++++++- src/vnet/l2/l2_bd.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/vpp/api/api.c | 6 ++++++ 4 files changed, 70 insertions(+), 3 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index b87c197f..e694fbf1 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -110,7 +110,8 @@ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ _(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ -_(UNSUPPORTED, -121, "Unsupported") +_(BD_NOT_MODIFIABLE, -121, "Default bridge domain 0 can be neither deleted nor modified") \ +_(UNSUPPORTED, -122, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 5a3c8dc2..8cc7c794 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -310,7 +310,15 @@ vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t vl_api_bridge_domain_set_mac_age_reply_t *rmp; int rv = 0; u32 bd_id = ntohl (mp->bd_id); - uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); + uword *p; + + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { rv = VNET_API_ERROR_NO_SUCH_ENTRY; @@ -401,10 +409,13 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) return; bd_id = ntohl (mp->bd_id); + if (bd_id == 0) + return; bd_index = (bd_id == ~0) ? 0 : bd_find_index (bdm, bd_id); ASSERT (bd_index != ~0); end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; + for (; bd_index < end; bd_index++) { bd_config = l2input_bd_config_from_index (l2im, bd_index); @@ -437,6 +448,12 @@ vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) u32 flags = ntohl (mp->feature_bitmap); uword *p; + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 7c55789b..4ebbb547 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -304,6 +304,10 @@ bd_learn (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -369,6 +373,10 @@ bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -436,6 +444,10 @@ bd_flood (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -502,6 +514,10 @@ bd_uu_flood (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -568,6 +584,10 @@ bd_arp_term (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) bd_index = *p; @@ -607,6 +627,10 @@ bd_mac_age (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) @@ -780,6 +804,10 @@ bd_arp_entry (vlib_main_t * vm, goto done; } + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) @@ -900,7 +928,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 bd_id = ~0; uword *p; - start = 0; + start = 1; end = vec_len (l2input_main.bd_configs); if (unformat (input, "%d", &bd_id)) @@ -914,6 +942,10 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) if (unformat (input, "arp")) arp = 1; + if (bd_id == 0) + return clib_error_return (0, + "No operations on the default bridge domain are supported"); + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) bd_index = *p; @@ -1125,6 +1157,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { if (bd_index == ~0) return VNET_API_ERROR_NO_SUCH_ENTRY; + if (bd_index == 0) + return VNET_API_ERROR_BD_NOT_MODIFIABLE; if (vec_len (l2input_main.bd_configs[bd_index].members)) return VNET_API_ERROR_BD_IN_USE; rv = bd_delete (bdm, bd_index); @@ -1188,6 +1222,12 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, goto done; } + if (bd_id == 0) + { + error = clib_error_return (0, "bridge domain 0 can not be modified"); + goto done; + } + if (mac_age > 255) { error = clib_error_return (0, "mac age must be less than 256"); @@ -1218,6 +1258,9 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, case VNET_API_ERROR_NO_SUCH_ENTRY: error = clib_error_return (0, "bridge domain id does not exist"); goto done; + case VNET_API_ERROR_BD_NOT_MODIFIABLE: + error = clib_error_return (0, "bridge domain 0 can not be modified"); + goto done; default: error = clib_error_return (0, "bd_add_del returned %d", rv); goto done; diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 9c230574..baf45d5c 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -446,6 +446,12 @@ vl_api_bd_ip_mac_add_del_t_handler (vl_api_bd_ip_mac_add_del_t * mp) u32 bd_index; uword *p; + if (bd_id == 0) + { + rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; + goto out; + } + p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p == 0) { -- cgit 1.2.3-korg From afc47aa36f44d3f865c6e1e48f41eded366a85ac Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Thu, 20 Apr 2017 14:45:17 +0300 Subject: L2FIB:flush interface learned macs on down Change-Id: I80a723f55fcf2ecc3209a35e8297c88b45b1abfb Signed-off-by: Eyal Bari --- src/vnet/l2/l2_bd.c | 15 ++++++--------- src/vnet/l2/l2_fib.c | 13 +++++++++++-- src/vnet/l2/l2_input.c | 42 ++++++++++++++---------------------------- src/vnet/l2/l2_input.h | 11 +++++++++++ 4 files changed, 42 insertions(+), 39 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 4ebbb547..4d540220 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -94,6 +94,8 @@ bd_delete (bd_main_t * bdm, u32 bd_index) { l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; u32 bd_id = bd->bd_id; + l2fib_flush_bd_mac (vlib_get_main (), bd_index); + hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ @@ -107,7 +109,6 @@ bd_delete (bd_main_t * bdm, u32 bd_index) vec_free (bd->members); hash_free (bd->mac_by_ip4); hash_free (bd->mac_by_ip6); - l2fib_flush_bd_mac (vlib_get_main (), bd_index); return 0; } @@ -219,13 +220,9 @@ u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) { - l2_bridge_domain_t *bd_config; - u32 feature_bitmap = 0; - - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); - + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); bd_validate (bd_config); + u32 feature_bitmap = 0; if (flags & L2_LEARN) { @@ -713,13 +710,13 @@ u32 bd_add_del_ip_mac (u32 bd_index, u8 * ip_addr, u8 * mac_addr, u8 is_ip6, u8 is_add) { - l2input_main_t *l2im = &l2input_main; - l2_bridge_domain_t *bd_cfg = l2input_bd_config_from_index (l2im, bd_index); + l2_bridge_domain_t *bd_cfg = l2input_bd_config (bd_index); u64 new_mac = *(u64 *) mac_addr; u64 *old_mac; u16 *mac16 = (u16 *) & new_mac; ASSERT (sizeof (uword) == sizeof (u64)); /* make sure uword is 8 bytes */ + ASSERT (bd_is_valid (bd_cfg)); mac16[3] = 0; /* Clear last 2 unsed bytes of the 8-byte MAC address */ if (is_ip6) diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index fadd79eb..d8fcc319 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -751,8 +751,7 @@ void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index) { l2_bridge_domain_t *bd_config; - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + bd_config = l2input_bd_config (bd_index); bd_config->seq_num += 1; l2fib_start_ager_scan (vm); } @@ -848,6 +847,16 @@ VLIB_CLI_COMMAND (l2fib_flush_mac_bd_cli, static) = { }; /* *INDENT-ON* */ +clib_error_t * +l2fib_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags) +{ + l2_input_config_t *config = l2input_intf_config (sw_if_index); + if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0 && config->bridge) + l2fib_flush_int_mac (vnm->vlib_main, sw_if_index); + return 0; +} + +VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (l2fib_sw_interface_up_down); BVT (clib_bihash) * get_mac_table (void) { diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index e5d6878a..fe65e694 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -481,20 +481,12 @@ l2input_intf_config (u32 sw_if_index) u32 l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) { - l2input_main_t *mp = &l2input_main; - l2_input_config_t *config; - - vec_validate (mp->configs, sw_if_index); - config = vec_elt_at_index (mp->configs, sw_if_index); + l2_input_config_t *config = l2input_intf_config (sw_if_index); if (enable) - { - config->feature_bitmap |= feature_bitmap; - } + config->feature_bitmap |= feature_bitmap; else - { - config->feature_bitmap &= ~feature_bitmap; - } + config->feature_bitmap &= ~feature_bitmap; return config->feature_bitmap; } @@ -502,9 +494,7 @@ l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable) u32 l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value) { - l2_bridge_domain_t *bd_config; - vec_validate (l2input_main.bd_configs, bd_index); - bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);; bd_validate (bd_config); bd_config->feature_bitmap = (bd_config->feature_bitmap & ~feat_mask) | feat_value; @@ -535,7 +525,6 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ l2_output_config_t *out_config; l2_input_config_t *config; l2_bridge_domain_t *bd_config; - l2_flood_member_t member; u64 mac; i32 l2_if_adjust = 0; u32 slot; @@ -570,8 +559,8 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ } /* Clear MACs learned on the interface */ - if ((config->feature_bitmap | L2INPUT_FEAT_LEARN) || - (bd_config->feature_bitmap | L2INPUT_FEAT_LEARN)) + if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) || + (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN)) l2fib_flush_int_mac (vm, sw_if_index); l2_if_adjust--; @@ -661,8 +650,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT; /* Set up bridge domain */ - vec_validate (mp->bd_configs, bd_index); - bd_config = vec_elt_at_index (mp->bd_configs, bd_index); + bd_config = l2input_bd_config (bd_index); bd_validate (bd_config); /* TODO: think: add l2fib entry even for non-bvi interface? */ @@ -694,9 +682,11 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ } /* Add interface to bridge-domain flood vector */ - member.sw_if_index = sw_if_index; - member.flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL; - member.shg = shg; + l2_flood_member_t member = { + .sw_if_index = sw_if_index, + .flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL, + .shg = shg, + }; bd_add_member (bd_config, &member); } @@ -997,10 +987,8 @@ show_int_mode (vlib_main_t * vm, char *mode; u8 *args; vnet_interface_main_t *im = &vnm->interface_main; - vnet_sw_interface_t *si, *sis = 0; - l2input_main_t *mp = &l2input_main; - l2_input_config_t *config; + vnet_sw_interface_t *si, *sis = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { u32 sw_if_index; @@ -1018,7 +1006,6 @@ show_int_mode (vlib_main_t * vm, format_unformat_error, input); goto done; } - } if (vec_len (sis) == 0) /* Get all interfaces */ @@ -1033,8 +1020,7 @@ show_int_mode (vlib_main_t * vm, vec_foreach (si, sis) { - vec_validate (mp->configs, si->sw_if_index); - config = vec_elt_at_index (mp->configs, si->sw_if_index); + l2_input_config_t *config = l2input_intf_config (si->sw_if_index); if (config->bridge) { u32 bd_id; diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index a2ade8d8..cb67cb9d 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -89,6 +89,17 @@ l2input_bd_config_from_index (l2input_main_t * l2im, u32 bd_index) return bd_is_valid (bd_config) ? bd_config : NULL; } +static_always_inline l2_bridge_domain_t * +l2input_bd_config (u32 bd_index) +{ + l2input_main_t *mp = &l2input_main; + l2_bridge_domain_t *bd_config; + + vec_validate (mp->bd_configs, bd_index); + bd_config = vec_elt_at_index (mp->bd_configs, bd_index); + return bd_config; +} + /* L2 input indication packet is from BVI, using -2 */ #define L2INPUT_BVI ((u32) (~0-1)) -- cgit 1.2.3-korg From d48c8eb7354c6c8b5b875dc70d616d11c17e9fb8 Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 5 May 2017 12:35:25 -0400 Subject: Fix L2FIB learn counter and memory cleanup of mac_by_ip6 hash table Fix global_learn_count to be incremented or decremented by add and deletion of non-static MAC entries from L2FIB only. Without this fix, the counter may reach the threshold of 1M and stop MAC leanring even though number of MAC entries in L2FIB is less than the threshold. Cleanup indirect hash key memory used by mac_by_ip6 hash table on BD deletion. Change-Id: I13986c4e6304c7956122520dd3f83d6bb6e65a15 Signed-off-by: John Lo --- src/vnet/l2/l2_bd.c | 13 +++++++++++-- src/vnet/l2/l2_fib.c | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 4d540220..351e6987 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -94,8 +94,11 @@ bd_delete (bd_main_t * bdm, u32 bd_index) { l2_bridge_domain_t *bd = &l2input_main.bd_configs[bd_index]; u32 bd_id = bd->bd_id; - l2fib_flush_bd_mac (vlib_get_main (), bd_index); + u64 mac_addr; + ip6_address_t *ip6_addr_key; + /* flush non-static MACs in BD and removed bd_id from hash table */ + l2fib_flush_bd_mac (vlib_get_main (), bd_index); hash_unset (bdm->bd_index_by_bd_id, bd_id); /* mark this index clear */ @@ -105,9 +108,15 @@ bd_delete (bd_main_t * bdm, u32 bd_index) bd->bd_id = ~0; bd->feature_bitmap = 0; - /* free memory used by BD and flush non-static MACs in BD */ + /* free memory used by BD */ vec_free (bd->members); hash_free (bd->mac_by_ip4); + /* *INDENT-OFF* */ + hash_foreach_mem (ip6_addr_key, mac_addr, bd->mac_by_ip6, + ({ + clib_mem_free (ip6_addr_key); /* free memory used for ip6 addr key */ + })); + /* *INDENT-ON* */ hash_free (bd->mac_by_ip6); return 0; diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index d8fcc319..028a7326 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -215,7 +215,9 @@ show_l2fib (vlib_main_t * vm, if (total_entries == 0) vlib_cli_output (vm, "no l2fib entries"); else - vlib_cli_output (vm, "%lld l2fib entries", total_entries); + vlib_cli_output (vm, + "%lld l2fib entries with %d learned (or non-static) entries", + total_entries, l2learn_main.global_learn_count); if (raw) vlib_cli_output (vm, "Raw Hash Table:\n%U\n", @@ -347,7 +349,7 @@ l2fib_add_entry (u64 mac, BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ ); /* increment counter if dynamically learned mac */ - if (result.fields.static_mac) + if (result.fields.static_mac == 0) { l2learn_main.global_learn_count++; } @@ -635,7 +637,7 @@ l2fib_del_entry (u64 mac, u32 bd_index) result.raw = kv.value; /* decrement counter if dynamically learned mac */ - if (result.fields.static_mac) + if (result.fields.static_mac == 0) { if (l2learn_main.global_learn_count > 0) { -- cgit 1.2.3-korg From 7537e717d1ca6de0e33478bc50b9f7125f04c808 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Thu, 27 Apr 2017 14:07:55 +0300 Subject: L2FIB:CLI/API to flush all non-static entries added CLI l2fib flush-mac all added API l2fib_flush_all flushes all non static l2fib entries on all valid BDs Change-Id: Ic963c88f4bed56308c03ab43106033132a0e87be Signed-off-by: Eyal Bari --- src/vnet/buffer.h | 3 +- src/vnet/l2/l2.api | 10 +++ src/vnet/l2/l2_api.c | 18 +++-- src/vnet/l2/l2_fib.c | 168 ++++++++++++++++++++++++++++------------------ src/vnet/l2/l2_fib.h | 21 +++++- src/vnet/l2/l2_input.c | 13 ++-- src/vnet/l2/l2_learn.c | 12 ++-- src/vpp/api/custom_dump.c | 12 ++++ 8 files changed, 169 insertions(+), 88 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 5d1b1c4d..ec5e2f75 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -176,8 +176,7 @@ typedef struct u16 bd_index; /* bridge-domain index */ u8 l2_len; /* ethernet header length */ u8 shg; /* split-horizon group */ - u8 bd_sn; /* bridge domain seq# */ - u8 int_sn; /* interface seq# */ + u16 l2fib_sn; /* l2fib bd/int seq_num */ } l2; /* l2tpv3 softwire encap, only valid there */ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index db42d635..e9a1f361 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -76,6 +76,16 @@ autoreply define l2_fib_clear_table u32 context; }; +/** \brief L2 FIB flush all entries + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +autoreply define l2fib_flush_all +{ + u32 client_index; + u32 context; +}; + /** \brief L2 FIB flush bridge domain entries @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 8cc7c794..5f371ccd 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -48,6 +48,7 @@ _(L2_XCONNECT_DUMP, l2_xconnect_dump) \ _(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \ _(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \ +_(L2FIB_FLUSH_ALL, l2fib_flush_all) \ _(L2FIB_FLUSH_INT, l2fib_flush_int) \ _(L2FIB_FLUSH_BD, l2fib_flush_bd) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ @@ -106,11 +107,8 @@ vl_api_l2_fib_clear_table_t_handler (vl_api_l2_fib_clear_table_t * mp) int rv = 0; vl_api_l2_fib_clear_table_reply_t *rmp; - /* DAW-FIXME: This API should only clear non-static l2fib entries, but - * that is not currently implemented. When that TODO is fixed - * this call should be changed to pass 1 instead of 0. - */ - l2fib_clear_table (0); + /* Clear all MACs including static MACs */ + l2fib_clear_table (); REPLY_MACRO (VL_API_L2_FIB_CLEAR_TABLE_REPLY); } @@ -258,6 +256,16 @@ vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp) REPLY_MACRO (VL_API_L2FIB_FLUSH_INT_REPLY); } +static void +vl_api_l2fib_flush_all_t_handler (vl_api_l2fib_flush_all_t * mp) +{ + int rv = 0; + vl_api_l2fib_flush_all_reply_t *rmp; + + l2fib_flush_all_mac (vlib_get_main ()); + REPLY_MACRO (VL_API_L2FIB_FLUSH_ALL_REPLY); +} + static void vl_api_l2fib_flush_bd_t_handler (vl_api_l2fib_flush_bd_t * mp) { diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 028a7326..d4207e35 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -54,7 +54,6 @@ typedef struct l2fib_main_t l2fib_main; - /** Format sw_if_index. If the value is ~0, use the text "N/A" */ u8 * format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args) @@ -198,7 +197,7 @@ show_l2fib (vlib_main_t * vm, key.fields.bd_index, result.fields.sw_if_index == ~0 ? -1 : result.fields.sw_if_index, - result.fields.bd_sn, result.fields.int_sn, + result.fields.sn.bd, result.fields.sn.swif, s, result.fields.static_mac ? "*" : "-", result.fields.filter ? "*" : "-", result.fields.bvi ? "*" : "-", @@ -259,22 +258,14 @@ VLIB_CLI_COMMAND (show_l2fib_cli, static) = { /* Remove all entries from the l2fib */ void -l2fib_clear_table (uint keep_static) +l2fib_clear_table (void) { l2fib_main_t *mp = &l2fib_main; - if (keep_static) - { - /* TODO: remove only non-static entries */ - } - else - { - /* Remove all entries */ - BV (clib_bihash_free) (&mp->mac_table); - BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table", - L2FIB_NUM_BUCKETS, L2FIB_MEMORY_SIZE); - } - + /* Remove all entries */ + BV (clib_bihash_free) (&mp->mac_table); + BV (clib_bihash_init) (&mp->mac_table, "l2fib mac table", + L2FIB_NUM_BUCKETS, L2FIB_MEMORY_SIZE); l2learn_main.global_learn_count = 0; } @@ -285,7 +276,7 @@ static clib_error_t * clear_l2fib (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - l2fib_clear_table (0); + l2fib_clear_table (); return 0; } @@ -308,14 +299,25 @@ VLIB_CLI_COMMAND (clear_l2fib_cli, static) = { }; /* *INDENT-ON* */ +static inline l2fib_seq_num_t +l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index) +{ + l2_input_config_t *int_config = l2input_intf_config (sw_if_index); + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); + /* *INDENT-OFF* */ + return (l2fib_seq_num_t) { + .swif = int_config->seq_num, + .bd = bd_config->seq_num, + }; + /* *INDENT-ON* */ +} /** * Add an entry to the l2fib. * If the entry already exists then overwrite it */ void -l2fib_add_entry (u64 mac, - u32 bd_index, +l2fib_add_entry (u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac) { l2fib_entry_key_t key; @@ -334,14 +336,7 @@ l2fib_add_entry (u64 mac, result.fields.filter = filter_mac; result.fields.bvi = bvi_mac; if (!static_mac) - { - l2_input_config_t *int_config = l2input_intf_config (sw_if_index); - l2_bridge_domain_t *bd_config = - vec_elt_at_index (l2input_main.bd_configs, - bd_index); - result.fields.int_sn = int_config->seq_num; - result.fields.bd_sn = bd_config->seq_num; - } + result.fields.sn = l2fib_cur_seq_num (bd_index, sw_if_index); kv.key = key.raw; kv.value = result.raw; @@ -620,8 +615,8 @@ VLIB_CLI_COMMAND (l2fib_test_command, static) = { * Delete an entry from the l2fib. * Return 0 if the entry was deleted, or 1 if it was not found */ -u32 -l2fib_del_entry (u64 mac, u32 bd_index) +static u32 +l2fib_del_entry_by_key (u64 raw_key) { l2fib_entry_result_t result; @@ -629,7 +624,7 @@ l2fib_del_entry (u64 mac, u32 bd_index) BVT (clib_bihash_kv) kv; /* set up key */ - kv.key = l2fib_make_key ((u8 *) & mac, bd_index); + kv.key = raw_key; if (BV (clib_bihash_search) (&mp->mac_table, &kv, &kv)) return 1; @@ -650,6 +645,16 @@ l2fib_del_entry (u64 mac, u32 bd_index) return 0; } +/** + * Delete an entry from the l2fib. + * Return 0 if the entry was deleted, or 1 if it was not found + */ +u32 +l2fib_del_entry (u64 mac, u32 bd_index) +{ + return l2fib_del_entry_by_key (l2fib_make_key ((u8 *) & mac, bd_index)); +} + /** * Delete an entry from the L2FIB. * The CLI format is: @@ -735,29 +740,42 @@ l2fib_start_ager_scan (vlib_main_t * vm) } /** - Flush all learned MACs from an interface + Flush all non static MACs from an interface */ void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index) { - l2_input_config_t *int_config; - int_config = l2input_intf_config (sw_if_index); + l2_input_config_t *int_config = l2input_intf_config (sw_if_index); int_config->seq_num += 1; l2fib_start_ager_scan (vm); } /** - Flush all learned MACs in a bridge domain + Flush all non static MACs in a bridge domain */ void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index) { - l2_bridge_domain_t *bd_config; - bd_config = l2input_bd_config (bd_index); + l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); bd_config->seq_num += 1; l2fib_start_ager_scan (vm); } +/** + Flush all non static MACs - flushes all valid BDs +*/ +void +l2fib_flush_all_mac (vlib_main_t * vm) +{ + l2_bridge_domain_t *bd_config; + vec_foreach (bd_config, l2input_main.bd_configs) + if (bd_is_valid (bd_config)) + bd_config->seq_num += 1; + + l2fib_start_ager_scan (vm); +} + + /** Flush MACs, except static ones, associated with an interface The CLI format is: @@ -784,6 +802,35 @@ done: return error; } +/** + Flush all MACs, except static ones + The CLI format is: + l2fib flush-mac all +*/ +static clib_error_t * +l2fib_flush_mac_all (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + l2fib_flush_all_mac (vm); + return 0; +} + +/*? + * This command kick off ager to delete all existing MAC Address entries, + * except static ones, associated with an interface from the L2 FIB table. + * + * @cliexpar + * Example of how to flush MAC Address entries learned on an interface from the L2 FIB table: + * @cliexcmd{l2fib flush-mac interface GigabitEthernet2/1/0} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (l2fib_flush_mac_all_cli, static) = { + .path = "l2fib flush-mac all", + .short_help = "l2fib flush-mac all", + .function = l2fib_flush_mac_all, +}; +/* *INDENT-ON* */ + /*? * This command kick off ager to delete all existing MAC Address entries, * except static ones, associated with an interface from the L2 FIB table. @@ -872,17 +919,8 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, { uword event_type, *event_data = 0; l2fib_main_t *msm = &l2fib_main; - l2_input_config_t *int_config; - l2_bridge_domain_t *bd_config; - BVT (clib_bihash) * h = &msm->mac_table; - clib_bihash_bucket_t *b; - BVT (clib_bihash_value) * v; - l2fib_entry_key_t key; - l2fib_entry_result_t result; - int i, j, k; bool enabled = 0; f64 start_time, last_run_duration = 0, t; - i16 delta; while (1) { @@ -911,6 +949,9 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, ASSERT (0); } last_run_duration = start_time = vlib_time_now (vm); + + BVT (clib_bihash) * h = &msm->mac_table; + int i, j, k; for (i = 0; i < h->nbuckets; i++) { /* Allow no more than 10us without a pause */ @@ -923,20 +964,22 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (i < (h->nbuckets - 3)) { - b = &h->buckets[i + 3]; + clib_bihash_bucket_t *b = &h->buckets[i + 3]; CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); b = &h->buckets[i + 1]; if (b->offset) { - v = BV (clib_bihash_get_value) (h, b->offset); + BVT (clib_bihash_value) * v = + BV (clib_bihash_get_value) (h, b->offset); CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); } } - b = &h->buckets[i]; + clib_bihash_bucket_t *b = &h->buckets[i]; if (b->offset == 0) continue; - v = BV (clib_bihash_get_value) (h, b->offset); + BVT (clib_bihash_value) * v = + BV (clib_bihash_get_value) (h, b->offset); for (j = 0; j < (1 << b->log2_pages); j++) { for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) @@ -944,37 +987,32 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) continue; - key.raw = v->kvp[k].key; - result.raw = v->kvp[k].value; + l2fib_entry_key_t key = {.raw = v->kvp[k].key }; + l2fib_entry_result_t result = {.raw = v->kvp[k].value }; if (result.fields.static_mac) continue; - int_config = - l2input_intf_config (result.fields.sw_if_index); - bd_config = - vec_elt_at_index (l2input_main.bd_configs, - key.fields.bd_index); - - if ((result.fields.int_sn != int_config->seq_num) || - (result.fields.bd_sn != bd_config->seq_num)) + u32 bd_index = key.fields.bd_index; + u32 sw_if_index = result.fields.sw_if_index; + u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index).as_u16; + if (result.fields.sn.as_u16 != sn) { - void *p = &key.fields.mac; - l2fib_del_entry (*(u64 *) p, key.fields.bd_index); + l2fib_del_entry_by_key (key.raw); continue; } + l2_bridge_domain_t *bd_config = + vec_elt_at_index (l2input_main.bd_configs, bd_index); if (bd_config->mac_age == 0) continue; - delta = (u8) (start_time / 60) - result.fields.timestamp; + i16 delta = + (u8) (start_time / 60) - result.fields.timestamp; delta += delta < 0 ? 256 : 0; if (delta > bd_config->mac_age) - { - void *p = &key.fields.mac; - l2fib_del_entry (*(u64 *) p, key.fields.bd_index); - } + l2fib_del_entry_by_key (key.raw); } v++; } diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 7e49d74b..e571a210 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -50,6 +50,20 @@ typedef struct STATIC_ASSERT_SIZEOF (l2fib_entry_key_t, 8); + +typedef struct +{ + union + { + struct + { + u8 swif; + u8 bd; + }; + u16 as_u16; + }; +} l2fib_seq_num_t; + /* * The l2fib entry results */ @@ -66,8 +80,7 @@ typedef struct u8 filter:1; /* drop packets to/from this mac */ u8 unused1:5; u8 timestamp; /* timestamp for aging */ - u8 int_sn; /* interface seq num */ - u8 bd_sn; /* bridge domain seq num */ + l2fib_seq_num_t sn; /* bd/int seq num */ } fields; u64 raw; }; @@ -314,7 +327,7 @@ l2fib_lookup_4 (BVT (clib_bihash) * mac_table, } } -void l2fib_clear_table (uint keep_static); +void l2fib_clear_table (void); void l2fib_add_entry (u64 mac, @@ -329,6 +342,8 @@ void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index); void l2fib_flush_bd_mac (vlib_main_t * vm, u32 bd_index); +void l2fib_flush_all_mac (vlib_main_t * vm); + void l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, l2fib_entry_result_t ** l2fe_res); diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index fe65e694..41a93f56 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -202,8 +202,14 @@ classify_and_dispatch (vlib_main_t * vm, /* Get config for the bridge domain interface */ bd_config = vec_elt_at_index (msm->bd_configs, bd_index0); - /* Save bridge domain seq_num */ - vnet_buffer (b0)->l2.bd_sn = bd_config->seq_num; + /* Save bridge domain and interface seq_num */ + /* *INDENT-OFF* */ + l2fib_seq_num_t sn = { + .swif = config->seq_num, + .bd = bd_config->seq_num, + }; + /* *INDENT-ON* */ + vnet_buffer (b0)->l2.l2fib_sn = sn.as_u16;; /* * Process bridge domain feature enables. @@ -218,9 +224,6 @@ classify_and_dispatch (vlib_main_t * vm, /* mask out features from bitmap using packet type and bd config */ feature_bitmap = config->feature_bitmap & feat_mask; - /* Save interface seq_num */ - vnet_buffer (b0)->l2.int_sn = config->seq_num; - /* save for next feature graph nodes */ vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index faed0d66..adc5e70f 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -141,10 +141,8 @@ l2learn_process (vlib_node_runtime_t * node, if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) result0->fields.timestamp = timestamp; if (PREDICT_FALSE - (result0->fields.int_sn != vnet_buffer (b0)->l2.int_sn)) - result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; - if (PREDICT_FALSE (result0->fields.bd_sn != vnet_buffer (b0)->l2.bd_sn)) - result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; + (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; } else if (result0->raw == ~0) { @@ -171,8 +169,7 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; - result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; - result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; kv.key = key0->raw; kv.value = result0->raw; @@ -210,8 +207,7 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.timestamp = timestamp; - result0->fields.bd_sn = vnet_buffer (b0)->l2.bd_sn; - result0->fields.int_sn = vnet_buffer (b0)->l2.int_sn; + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; kv.key = key0->raw; kv.value = result0->raw; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 107e83f3..c073c52d 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -298,6 +298,17 @@ static void *vl_api_bridge_domain_dump_t_print FINISH; } +static void *vl_api_l2fib_flush_all_t_print + (vl_api_l2fib_flush_all_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: l2fib_flush_all "); + + FINISH; +} + + static void *vl_api_l2fib_flush_bd_t_print (vl_api_l2fib_flush_bd_t * mp, void *handle) { @@ -2979,6 +2990,7 @@ _(SR_POLICY_MOD, sr_policy_mod) \ _(SR_POLICY_DEL, sr_policy_del) \ _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ +_(L2FIB_FLUSH_ALL, l2fib_flush_all) \ _(L2FIB_FLUSH_BD, l2fib_flush_bd) \ _(L2FIB_FLUSH_INT, l2fib_flush_int) \ _(L2_FLAGS, l2_flags) \ -- cgit 1.2.3-korg From 259fca789a9f02c5bf60fd0734ba97045d4595bc Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Sun, 14 May 2017 10:38:39 +0300 Subject: L2BD/API:fix bd dump to ignore unknown bd_id Change-Id: I417dfeba902ca8c3a080773942d4d2ce4335a9c1 Signed-off-by: Eyal Bari --- src/vnet/l2/l2_api.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 5f371ccd..7c4b0423 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -406,27 +406,32 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) { bd_main_t *bdm = &bd_main; l2input_main_t *l2im = &l2input_main; - unix_shared_memory_queue_t *q; - l2_bridge_domain_t *bd_config; - u32 bd_id, bd_index; - u32 end; - - q = vl_api_client_index_to_input_queue (mp->client_index); + unix_shared_memory_queue_t *q = + vl_api_client_index_to_input_queue (mp->client_index); if (q == 0) return; - bd_id = ntohl (mp->bd_id); + u32 bd_id = ntohl (mp->bd_id); if (bd_id == 0) return; - bd_index = (bd_id == ~0) ? 0 : bd_find_index (bdm, bd_id); - ASSERT (bd_index != ~0); - end = (bd_id == ~0) ? vec_len (l2im->bd_configs) : bd_index + 1; + u32 bd_index, end; + if (bd_id == ~0) + bd_index = 0, end = vec_len (l2im->bd_configs); + else + { + bd_index = bd_find_index (bdm, bd_id); + if (bd_index == ~0) + return; + + end = bd_index + 1; + } for (; bd_index < end; bd_index++) { - bd_config = l2input_bd_config_from_index (l2im, bd_index); + l2_bridge_domain_t *bd_config = + l2input_bd_config_from_index (l2im, bd_index); /* skip dummy bd_id 0 */ if (bd_config && (bd_config->bd_id > 0)) { @@ -451,26 +456,22 @@ vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) bd_main_t *bdm = &bd_main; vl_api_bridge_flags_reply_t *rmp; int rv = 0; - u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 flags = ntohl (mp->feature_bitmap); - uword *p; + u32 flags = ntohl (mp->feature_bitmap); + u32 bd_id = ntohl (mp->bd_id); if (bd_id == 0) { rv = VNET_API_ERROR_BD_NOT_MODIFIABLE; goto out; } - p = hash_get (bdm->bd_index_by_bd_id, bd_id); - if (p == 0) + u32 bd_index = bd_find_index (bdm, bd_id); + if (bd_index == ~0) { rv = VNET_API_ERROR_NO_SUCH_ENTRY; goto out; } - bd_index = p[0]; - bd_set_flags (vm, bd_index, flags, mp->is_set); out: -- cgit 1.2.3-korg From 9793477a28c45e4eb5bba3f2050fe415e57e8ad8 Mon Sep 17 00:00:00 2001 From: John Lo Date: Thu, 18 May 2017 22:26:47 -0400 Subject: Enforce Bridge Domain ID range to match 24-bit VNI range Enforce bridge domain ID range to allow a maximum value of 16M which matches the range of 24-bit VNI used for virtual overlay network ID. Fix "show bridge-domain" output to allow full 16M BD ID range to be displayed using 8-digit spaces. Change-Id: I80d9c76ea7c001bcccd3c19df1f3e55d2970f01c Signed-off-by: John Lo --- src/vlibapi/api_helper_macros.h | 14 ++++++++++++++ src/vnet/api_errno.h | 5 +++-- src/vnet/l2/l2_bd.c | 17 +++++++++++------ src/vnet/l2/l2_bd.h | 4 +++- src/vnet/l2/l2_input.c | 6 ++++++ src/vnet/lisp-gpe/interface.c | 6 ++++++ src/vpp/api/api.c | 2 ++ 7 files changed, 45 insertions(+), 9 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h index a492c3f4..2e29d4d7 100644 --- a/src/vlibapi/api_helper_macros.h +++ b/src/vlibapi/api_helper_macros.h @@ -155,6 +155,20 @@ bad_tx_sw_if_index: \ ; \ } while (0); +#define VALIDATE_BD_ID(mp) \ + do { u32 __rx_bd_id = ntohl(mp->bd_id); \ + if (__rx_bd_id > L2_BD_ID_MAX) { \ + rv = VNET_API_ERROR_BD_ID_EXCEED_MAX; \ + goto bad_bd_id; \ + } \ +} while(0); + +#define BAD_BD_ID_LABEL \ +do { \ +bad_bd_id: \ + ; \ +} while (0); + #define pub_sub_handler(lca,UCA) \ static void vl_api_want_##lca##_t_handler ( \ vl_api_want_##lca##_t *mp) \ diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index e694fbf1..b22bb3a8 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -110,8 +110,9 @@ _(SVM_SEGMENT_CREATE_FAIL, -117, "svm segment create fail") \ _(APPLICATION_NOT_ATTACHED, -118, "application not attached") \ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ -_(BD_NOT_MODIFIABLE, -121, "Default bridge domain 0 can be neither deleted nor modified") \ -_(UNSUPPORTED, -122, "Unsupported") +_(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \ +_(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \ +_(UNSUPPORTED, -123, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 351e6987..f68b6638 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -984,10 +984,10 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { printed = 1; vlib_cli_output (vm, - "%=5s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", - "ID", "Index", "BSN", "Age(min)", "Learning", - "U-Forwrd", "UU-Flood", "Flooding", "ARP-Term", - "BVI-Intf"); + "%=8s %=7s %=4s %=9s %=9s %=9s %=9s %=9s %=9s %=9s", + "BD-ID", "Index", "BSN", "Age(min)", + "Learning", "U-Forwrd", "UU-Flood", "Flooding", + "ARP-Term", "BVI-Intf"); } if (bd_config->mac_age) @@ -995,7 +995,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) else as = format (as, "off"); vlib_cli_output (vm, - "%=5d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", + "%=8d %=7d %=4d %=9v %=9s %=9s %=9s %=9s %=9s %=9U", bd_config->bd_id, bd_index, bd_config->seq_num, as, bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? "on" : "off", @@ -1123,6 +1123,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) { if (bd_index != ~0) return VNET_API_ERROR_BD_ALREADY_EXISTS; + if (a->bd_id > L2_BD_ID_MAX) + return VNET_API_ERROR_BD_ID_EXCEED_MAX; bd_index = bd_add_bd_index (bdm, a->bd_id); u32 enable_flags = 0, disable_flags = 0; @@ -1262,11 +1264,14 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, error = clib_error_return (0, "bridge domain in use - remove members"); goto done; case VNET_API_ERROR_NO_SUCH_ENTRY: - error = clib_error_return (0, "bridge domain id does not exist"); + error = clib_error_return (0, "bridge domain ID does not exist"); goto done; case VNET_API_ERROR_BD_NOT_MODIFIABLE: error = clib_error_return (0, "bridge domain 0 can not be modified"); goto done; + case VNET_API_ERROR_BD_ID_EXCEED_MAX: + error = clib_error_return (0, "bridge domain ID exceed 16M limit"); + goto done; default: error = clib_error_return (0, "bd_add_del returned %d", rv); goto done; diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index e502d497..93ed1a85 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -49,7 +49,6 @@ typedef struct u16 spare; } l2_flood_member_t; - /* Per-bridge domain configuration */ typedef struct @@ -91,6 +90,9 @@ typedef struct } l2_bridge_domain_t; +/* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */ +#define L2_BD_ID_MAX ((1<<24)-1) + typedef struct { u32 bd_id; diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 41a93f56..aca23fe0 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -791,6 +791,12 @@ int_l2_bridge (vlib_main_t * vm, goto done; } + if (bd_id > L2_BD_ID_MAX) + { + error = clib_error_return (0, "bridge domain ID exceed 16M limit", + format_unformat_error, input); + goto done; + } bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); /* optional bvi */ diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c index ff750563..94703abc 100644 --- a/src/vnet/lisp-gpe/interface.c +++ b/src/vnet/lisp-gpe/interface.c @@ -653,6 +653,12 @@ lisp_gpe_add_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id) uword *hip, *si; u16 bd_index; + if (bd_id > L2_BD_ID_MAX) + { + clib_warning ("bridge domain ID %d exceed 16M limit", bd_id); + return ~0; + } + bd_index = bd_find_or_add_bd_index (&bd_main, bd_id); hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index); diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 16d51225..7e4c341e 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -419,6 +419,7 @@ static void if (mp->enable) { + VALIDATE_BD_ID (mp); u32 bd_id = ntohl (mp->bd_id); u32 bd_index = bd_find_or_add_bd_index (bdm, bd_id); u32 bvi = mp->bvi; @@ -432,6 +433,7 @@ static void } BAD_RX_SW_IF_INDEX_LABEL; + BAD_BD_ID_LABEL; REPLY_MACRO (VL_API_SW_INTERFACE_SET_L2_BRIDGE_REPLY); } -- cgit 1.2.3-korg From 01384fe3d4c8f9d5c082cd602087a8eb71facd15 Mon Sep 17 00:00:00 2001 From: Ole Troan Date: Fri, 12 May 2017 11:55:35 +0200 Subject: API: Cleaning up message naming that does not follow the conventions is_address_reachable - Disabled so deleted cli_request - Renamed to cli vnet_summary_stats_reply - Renamed to vnet_get_summary_stats_reply bridge_domain_sw_if_details - Deleted, incorporated in main message l2_fib_table_entry - Renamed to l2_fib_table_details Change-Id: I93b7e8769a3ba7b4989b3c270270f575f386464f Signed-off-by: Ole Troan Signed-off-by: Marek Gradzki Signed-off-by: Ole Troan --- src/vat/api_format.c | 114 +++++++++++---------- src/vnet/l2/l2.api | 32 +++--- src/vnet/l2/l2_api.c | 61 +++++------ .../io/fd/vpp/jvpp/core/test/FutureApiTest.java | 4 +- src/vpp-api/java/jvpp/gen/jvppgen/util.py | 9 +- src/vpp/api/api.c | 85 +-------------- src/vpp/api/custom_dump.c | 8 +- src/vpp/api/summary_stats_client.c | 6 +- src/vpp/api/vpe.api | 23 +---- 9 files changed, 116 insertions(+), 226 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index efb71ef6..22a91666 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1323,6 +1323,9 @@ vl_api_ip6_nd_event_t_handler_json (vl_api_ip6_nd_event_t * mp) /* JSON output not supported */ } +#define vl_api_bridge_domain_details_t_endian vl_noop_handler +#define vl_api_bridge_domain_details_t_print vl_noop_handler + /* * Special-case: build the bridge domain table, maintain * the next bd id vbl. @@ -1332,6 +1335,7 @@ static void vl_api_bridge_domain_details_t_handler { vat_main_t *vam = &vat_main; u32 n_sw_ifs = ntohl (mp->n_sw_ifs); + int i; print (vam->ofp, "\n%-3s %-3s %-3s %-3s %-3s %-3s", " ID", "LRN", "FWD", "FLD", "BVI", "#IF"); @@ -1341,7 +1345,37 @@ static void vl_api_bridge_domain_details_t_handler mp->flood, ntohl (mp->bvi_sw_if_index), n_sw_ifs); if (n_sw_ifs) - print (vam->ofp, "\n\n%s %s %s", "sw_if_index", "SHG", "Interface Name"); + { + vl_api_bridge_domain_sw_if_t *sw_ifs; + print (vam->ofp, "\n\n%s %s %s", "sw_if_index", "SHG", + "Interface Name"); + + sw_ifs = mp->sw_if_details; + for (i = 0; i < n_sw_ifs; i++) + { + u8 *sw_if_name = 0; + u32 sw_if_index; + hash_pair_t *p; + + sw_if_index = ntohl (sw_ifs->sw_if_index); + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index) + { + sw_if_name = (u8 *)(p->key); + break; + } + })); + /* *INDENT-ON* */ + print (vam->ofp, "%7d %3d %s", sw_if_index, + sw_ifs->shg, sw_if_name ? (char *) sw_if_name : + "sw_if_index not found!"); + + sw_ifs++; + } + } } static void vl_api_bridge_domain_details_t_handler_json @@ -1349,6 +1383,7 @@ static void vl_api_bridge_domain_details_t_handler_json { vat_main_t *vam = &vat_main; vat_json_node_t *node, *array = NULL; + u32 n_sw_ifs = ntohl (mp->n_sw_ifs); if (VAT_JSON_ARRAY != vam->json_tree.type) { @@ -1364,58 +1399,28 @@ static void vl_api_bridge_domain_details_t_handler_json vat_json_object_add_uint (node, "learn", mp->learn); vat_json_object_add_uint (node, "bvi_sw_if_index", ntohl (mp->bvi_sw_if_index)); - vat_json_object_add_uint (node, "n_sw_ifs", ntohl (mp->n_sw_ifs)); + vat_json_object_add_uint (node, "n_sw_ifs", n_sw_ifs); array = vat_json_object_add (node, "sw_if"); vat_json_init_array (array); -} - -/* - * Special-case: build the bridge domain sw if table. - */ -static void vl_api_bridge_domain_sw_if_details_t_handler - (vl_api_bridge_domain_sw_if_details_t * mp) -{ - vat_main_t *vam = &vat_main; - hash_pair_t *p; - u8 *sw_if_name = 0; - u32 sw_if_index; - - sw_if_index = ntohl (mp->sw_if_index); - /* *INDENT-OFF* */ - hash_foreach_pair (p, vam->sw_if_index_by_interface_name, - ({ - if ((u32) p->value[0] == sw_if_index) - { - sw_if_name = (u8 *)(p->key); - break; - } - })); - /* *INDENT-ON* */ - print (vam->ofp, "%7d %3d %s", sw_if_index, - mp->shg, sw_if_name ? (char *) sw_if_name : - "sw_if_index not found!"); -} -static void vl_api_bridge_domain_sw_if_details_t_handler_json - (vl_api_bridge_domain_sw_if_details_t * mp) -{ - vat_main_t *vam = &vat_main; - vat_json_node_t *node = NULL; - uword last_index = 0; - ASSERT (VAT_JSON_ARRAY == vam->json_tree.type); - ASSERT (vec_len (vam->json_tree.array) >= 1); - last_index = vec_len (vam->json_tree.array) - 1; - node = &vam->json_tree.array[last_index]; - node = vat_json_object_get_element (node, "sw_if"); - ASSERT (NULL != node); - node = vat_json_array_add (node); + if (n_sw_ifs) + { + vl_api_bridge_domain_sw_if_t *sw_ifs; + int i; - vat_json_init_object (node); - vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); - vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); - vat_json_object_add_uint (node, "shg", mp->shg); + sw_ifs = mp->sw_if_details; + for (i = 0; i < n_sw_ifs; i++) + { + node = vat_json_array_add (array); + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", + ntohl (sw_ifs->sw_if_index)); + vat_json_object_add_uint (node, "shg", sw_ifs->shg); + sw_ifs++; + } + } } static void vl_api_control_ping_reply_t_handler @@ -4334,7 +4339,6 @@ _(SW_INTERFACE_SET_L2_BRIDGE_REPLY, \ sw_interface_set_l2_bridge_reply) \ _(BRIDGE_DOMAIN_ADD_DEL_REPLY, bridge_domain_add_del_reply) \ _(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ -_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ _(BRIDGE_DOMAIN_SET_MAC_AGE_REPLY, bridge_domain_set_mac_age_reply) \ _(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ _(L2FIB_FLUSH_INT_REPLY, l2fib_flush_int_reply) \ @@ -4409,7 +4413,7 @@ _(CREATE_VHOST_USER_IF_REPLY, create_vhost_user_if_reply) \ _(MODIFY_VHOST_USER_IF_REPLY, modify_vhost_user_if_reply) \ _(DELETE_VHOST_USER_IF_REPLY, delete_vhost_user_if_reply) \ _(SHOW_VERSION_REPLY, show_version_reply) \ -_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ +_(L2_FIB_TABLE_DETAILS, l2_fib_table_details) \ _(VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, vxlan_gpe_add_del_tunnel_reply) \ _(VXLAN_GPE_TUNNEL_DETAILS, vxlan_gpe_tunnel_details) \ _(INTERFACE_NAME_RENUMBER_REPLY, interface_name_renumber_reply) \ @@ -4935,7 +4939,7 @@ int exec (vat_main_t * vam) { api_main_t *am = &api_main; - vl_api_cli_request_t *mp; + vl_api_cli_t *mp; f64 timeout; void *oldheap; u8 *cmd = 0; @@ -4956,7 +4960,7 @@ exec (vat_main_t * vam) } - M (CLI_REQUEST, mp); + M (CLI, mp); /* * Copy cmd into shared memory. @@ -11896,8 +11900,8 @@ format_l2_fib_mac_address (u8 * s, va_list * args) a[2], a[3], a[4], a[5], a[6], a[7]); } -static void vl_api_l2_fib_table_entry_t_handler - (vl_api_l2_fib_table_entry_t * mp) +static void vl_api_l2_fib_table_details_t_handler + (vl_api_l2_fib_table_details_t * mp) { vat_main_t *vam = &vat_main; @@ -11908,8 +11912,8 @@ static void vl_api_l2_fib_table_entry_t_handler mp->bvi_mac); } -static void vl_api_l2_fib_table_entry_t_handler_json - (vl_api_l2_fib_table_entry_t * mp) +static void vl_api_l2_fib_table_details_t_handler_json + (vl_api_l2_fib_table_details_t * mp) { vat_main_t *vam = &vat_main; vat_json_node_t *node = NULL; diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index e9a1f361..bb3990c6 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -36,7 +36,7 @@ define l2_xconnect_dump u32 context; }; -/** \brief l2 fib table entry structure +/** \brief l2 fib table details structure @param bd_id - the l2 fib / bridge domain table id @param mac - the entry's mac address @param sw_if_index - index of the interface @@ -44,7 +44,7 @@ define l2_xconnect_dump @param filter_mac - the entry is a mac filter entry. @param bvi_mac - the mac address is a bridge virtual interface */ -define l2_fib_table_entry +define l2_fib_table_details { u32 context; u32 bd_id; @@ -212,6 +212,18 @@ define bridge_domain_dump u32 bd_id; }; +/** \brief L2 bridge domain sw interface operational state response + @param bd_id - the bridge domain id + @param sw_if_index - sw_if_index in the domain + @param shg - split horizon group for the interface +*/ +typeonly manual_print manual_endian define bridge_domain_sw_if +{ + u32 context; + u32 sw_if_index; + u8 shg; +}; + /** \brief L2 bridge domain operational state response @param bd_id - the bridge domain id @param flood - bcast/mcast flooding state on all interfaces in the bd @@ -222,7 +234,7 @@ define bridge_domain_dump @param mac_age - mac aging time in min, 0 for disabled @param n_sw_ifs - number of sw_if_index's in the domain */ -define bridge_domain_details +manual_print manual_endian define bridge_domain_details { u32 context; u32 bd_id; @@ -234,19 +246,7 @@ define bridge_domain_details u8 mac_age; u32 bvi_sw_if_index; u32 n_sw_ifs; -}; - -/** \brief L2 bridge domain sw interface operational state response - @param bd_id - the bridge domain id - @param sw_if_index - sw_if_index in the domain - @param shg - split horizon group for the interface -*/ -define bridge_domain_sw_if_details -{ - u32 context; - u32 bd_id; - u32 sw_if_index; - u8 shg; + vl_api_bridge_domain_sw_if_t sw_if_details[n_sw_ifs]; }; /** \brief Set bridge flags (such as L2_LEARN, L2_FWD, L2_FLOOD, diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 7c4b0423..aa3dcb7e 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -36,6 +36,9 @@ #include #undef vl_endianfun +#define vl_api_bridge_domain_details_t_endian vl_noop_handler +#define vl_api_bridge_domain_details_t_print vl_noop_handler + /* instantiate all the print functions we know about */ #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) #define vl_printfun @@ -119,11 +122,11 @@ send_l2fib_table_entry (vpe_api_main_t * am, l2fib_entry_key_t * l2fe_key, l2fib_entry_result_t * l2fe_res, u32 context) { - vl_api_l2_fib_table_entry_t *mp; + vl_api_l2_fib_table_details_t *mp; mp = vl_msg_api_alloc (sizeof (*mp)); memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_ENTRY); + mp->_vl_msg_id = ntohs (VL_API_L2_FIB_TABLE_DETAILS); mp->bd_id = ntohl (l2input_main.bd_configs[l2fe_key->fields.bd_index].bd_id); @@ -358,13 +361,18 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) } static void -send_bridge_domain_details (unix_shared_memory_queue_t * q, +send_bridge_domain_details (l2input_main_t * l2im, + unix_shared_memory_queue_t * q, l2_bridge_domain_t * bd_config, u32 n_sw_ifs, u32 context) { vl_api_bridge_domain_details_t *mp; + l2_flood_member_t *m; + vl_api_bridge_domain_sw_if_t *sw_ifs; + l2_input_config_t *input_cfg; - mp = vl_msg_api_alloc (sizeof (*mp)); + mp = vl_msg_api_alloc (sizeof (*mp) + + (n_sw_ifs * sizeof (vl_api_bridge_domain_sw_if_t))); memset (mp, 0, sizeof (*mp)); mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_DETAILS); mp->bd_id = ntohl (bd_config->bd_id); @@ -375,28 +383,18 @@ send_bridge_domain_details (unix_shared_memory_queue_t * q, mp->arp_term = bd_feature_arp_term (bd_config); mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index); mp->mac_age = bd_config->mac_age; - mp->n_sw_ifs = ntohl (n_sw_ifs); mp->context = context; - vl_msg_api_send_shmem (q, (u8 *) & mp); -} - -static void -send_bd_sw_if_details (l2input_main_t * l2im, - unix_shared_memory_queue_t * q, - l2_flood_member_t * member, u32 bd_id, u32 context) -{ - vl_api_bridge_domain_sw_if_details_t *mp; - l2_input_config_t *input_cfg; - - mp = vl_msg_api_alloc (sizeof (*mp)); - memset (mp, 0, sizeof (*mp)); - mp->_vl_msg_id = ntohs (VL_API_BRIDGE_DOMAIN_SW_IF_DETAILS); - mp->bd_id = ntohl (bd_id); - mp->sw_if_index = ntohl (member->sw_if_index); - input_cfg = vec_elt_at_index (l2im->configs, member->sw_if_index); - mp->shg = input_cfg->shg; - mp->context = context; + sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details; + vec_foreach (m, bd_config->members) + { + sw_ifs->sw_if_index = ntohl (m->sw_if_index); + input_cfg = vec_elt_at_index (l2im->configs, m->sw_if_index); + sw_ifs->shg = input_cfg->shg; + sw_ifs++; + mp->n_sw_ifs++; + } + mp->n_sw_ifs = htonl (mp->n_sw_ifs); vl_msg_api_send_shmem (q, (u8 *) & mp); } @@ -434,18 +432,9 @@ vl_api_bridge_domain_dump_t_handler (vl_api_bridge_domain_dump_t * mp) l2input_bd_config_from_index (l2im, bd_index); /* skip dummy bd_id 0 */ if (bd_config && (bd_config->bd_id > 0)) - { - u32 n_sw_ifs; - l2_flood_member_t *m; - - n_sw_ifs = vec_len (bd_config->members); - send_bridge_domain_details (q, bd_config, n_sw_ifs, mp->context); - - vec_foreach (m, bd_config->members) - { - send_bd_sw_if_details (l2im, q, m, bd_config->bd_id, mp->context); - } - } + send_bridge_domain_details (l2im, q, bd_config, + vec_len (bd_config->members), + mp->context); } } diff --git a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java index 0d7c7471..63659f82 100644 --- a/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java +++ b/src/vpp-api/java/jvpp-core/io/fd/vpp/jvpp/core/test/FutureApiTest.java @@ -67,8 +67,8 @@ public class FutureApiTest { } else { LOG.info( String.format( - "Received empty bridge-domain dump reply with list of bridge-domains: %s, %s", - reply.bridgeDomainDetails, reply.bridgeDomainSwIfDetails)); + "Received bridge-domain dump reply with list of bridge-domains: %s", + reply.bridgeDomainDetails)); } } diff --git a/src/vpp-api/java/jvpp/gen/jvppgen/util.py b/src/vpp-api/java/jvpp/gen/jvppgen/util.py index fc971c17..947fc31d 100644 --- a/src/vpp-api/java/jvpp/gen/jvppgen/util.py +++ b/src/vpp-api/java/jvpp/gen/jvppgen/util.py @@ -156,13 +156,6 @@ jni_field_accessors = {'u8': 'ByteField', # vpe.api calls that do not follow naming conventions and have to be handled exceptionally when finding reply -> request mapping # FIXME in vpe.api unconventional_naming_rep_req = { - 'cli_reply': 'cli_request', - 'vnet_summary_stats_reply': 'vnet_get_summary_stats', - # This below is actually a sub-details callback. We cannot derive the mapping of dump request - # belonging to this sub-details from naming conventions. We need special mapping - 'bridge_domain_sw_if_details': 'bridge_domain', - # This is standard dump call + details reply. However it's not called details but entry - 'l2_fib_table_entry': 'l2_fib_table' } # @@ -172,7 +165,7 @@ notification_messages_reused = ["sw_interface_set_flags"] # messages that must be ignored. These messages are INSUFFICIENTLY marked as disabled in vpe.api # FIXME -ignored_messages = ["is_address_reachable"] +ignored_messages = [] def is_notification(name): diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index 7e4c341e..60eb5331 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -104,7 +104,6 @@ #define foreach_vpe_api_msg \ _(WANT_OAM_EVENTS, want_oam_events) \ _(OAM_ADD_DEL, oam_add_del) \ -_(IS_ADDRESS_REACHABLE, is_address_reachable) \ _(SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable) \ _(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \ _(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \ @@ -118,7 +117,7 @@ _(RESET_FIB, reset_fib) \ _(CREATE_LOOPBACK, create_loopback) \ _(CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \ _(CONTROL_PING, control_ping) \ -_(CLI_REQUEST, cli_request) \ +_(CLI, cli) \ _(CLI_INBAND, cli_inband) \ _(SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit) \ _(L2_PATCH_ADD_DEL, l2_patch_add_del) \ @@ -693,82 +692,6 @@ out: REPLY_MACRO (VL_API_PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY); } -static void -vl_api_is_address_reachable_t_handler (vl_api_is_address_reachable_t * mp) -{ -#if 0 - vpe_main_t *rm = &vpe_main; - ip4_main_t *im4 = &ip4_main; - ip6_main_t *im6 = &ip6_main; - ip_lookup_main_t *lm; - union - { - ip4_address_t ip4; - ip6_address_t ip6; - } addr; - u32 adj_index, sw_if_index; - vl_api_is_address_reachable_t *rmp; - ip_adjacency_t *adj; - unix_shared_memory_queue_t *q; - - q = vl_api_client_index_to_input_queue (mp->client_index); - if (!q) - { - increment_missing_api_client_counter (rm->vlib_main); - return; - } - - rmp = vl_msg_api_alloc (sizeof (*rmp)); - clib_memcpy (rmp, mp, sizeof (*rmp)); - - sw_if_index = mp->next_hop_sw_if_index; - clib_memcpy (&addr, mp->address, sizeof (addr)); - if (mp->is_ipv6) - { - lm = &im6->lookup_main; - adj_index = ip6_fib_lookup (im6, sw_if_index, &addr.ip6); - } - else - { - lm = &im4->lookup_main; - // FIXME NOT an ADJ - adj_index = ip4_fib_lookup (im4, sw_if_index, &addr.ip4); - } - if (adj_index == ~0) - { - rmp->is_error = 1; - goto send; - } - adj = ip_get_adjacency (lm, adj_index); - - if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE - && adj->rewrite_header.sw_if_index == sw_if_index) - { - rmp->is_known = 1; - } - else - { - if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP - && adj->rewrite_header.sw_if_index == sw_if_index) - { - if (mp->is_ipv6) - ip6_probe_neighbor (rm->vlib_main, &addr.ip6, sw_if_index); - else - ip4_probe_neighbor (rm->vlib_main, &addr.ip4, sw_if_index); - } - else if (adj->lookup_next_index == IP_LOOKUP_NEXT_DROP) - { - rmp->is_known = 1; - goto send; - } - rmp->is_known = 0; - } - -send: - vl_msg_api_send_shmem (q, (u8 *) & rmp); -#endif -} - static void vl_api_sw_interface_set_mpls_enable_t_handler (vl_api_sw_interface_set_mpls_enable_t * mp) @@ -828,7 +751,7 @@ vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp) { stats_main_t *sm = &stats_main; vnet_interface_main_t *im = sm->interface_main; - vl_api_vnet_summary_stats_reply_t *rmp; + vl_api_vnet_get_summary_stats_reply_t *rmp; vlib_combined_counter_main_t *cm; vlib_counter_t v; int i, which; @@ -842,7 +765,7 @@ vl_api_vnet_get_summary_stats_t_handler (vl_api_vnet_get_summary_stats_t * mp) return; rmp = vl_msg_api_alloc (sizeof (*rmp)); - rmp->_vl_msg_id = ntohs (VL_API_VNET_SUMMARY_STATS_REPLY); + rmp->_vl_msg_id = ntohs (VL_API_VNET_GET_SUMMARY_STATS_REPLY); rmp->context = mp->context; rmp->retval = 0; @@ -1115,7 +1038,7 @@ shmem_cli_output (uword arg, u8 * buffer, uword buffer_bytes) static void -vl_api_cli_request_t_handler (vl_api_cli_request_t * mp) +vl_api_cli_t_handler (vl_api_cli_t * mp) { vl_api_cli_reply_t *rp; unix_shared_memory_queue_t *q; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index c073c52d..9071883b 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -1656,12 +1656,12 @@ static void *vl_api_want_interface_events_t_print FINISH; } -static void *vl_api_cli_request_t_print - (vl_api_cli_request_t * mp, void *handle) +static void * +vl_api_cli_t_print (vl_api_cli_t * mp, void *handle) { u8 *s; - s = format (0, "SCRIPT: cli_request "); + s = format (0, "SCRIPT: cli "); FINISH; } @@ -3023,7 +3023,7 @@ _(DELETE_VHOST_USER_IF, delete_vhost_user_if) \ _(SW_INTERFACE_DUMP, sw_interface_dump) \ _(CONTROL_PING, control_ping) \ _(WANT_INTERFACE_EVENTS, want_interface_events) \ -_(CLI_REQUEST, cli_request) \ +_(CLI, cli) \ _(CLI_INBAND, cli_inband) \ _(MEMCLNT_CREATE, memclnt_create) \ _(SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump) \ diff --git a/src/vpp/api/summary_stats_client.c b/src/vpp/api/summary_stats_client.c index 03999567..2c81d667 100644 --- a/src/vpp/api/summary_stats_client.c +++ b/src/vpp/api/summary_stats_client.c @@ -101,8 +101,8 @@ vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...) static void -vl_api_vnet_summary_stats_reply_t_handler (vl_api_vnet_summary_stats_reply_t * - mp) + vl_api_vnet_get_summary_stats_reply_t_handler + (vl_api_vnet_get_summary_stats_reply_t * mp) { test_main_t *tm = &test_main; static u8 *sb; @@ -134,7 +134,7 @@ vl_api_vnet_summary_stats_reply_t_handler (vl_api_vnet_summary_stats_reply_t * } #define foreach_api_msg \ -_(VNET_SUMMARY_STATS_REPLY, vnet_summary_stats_reply) +_(VNET_GET_SUMMARY_STATS_REPLY, vnet_get_summary_stats_reply) int connect_to_vpe (char *name) diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 99ae4784..d3c7e985 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -135,25 +135,6 @@ autoreply define reset_vrf u32 vrf_id; }; -/** \brief Is Address Reachable request - DISABLED - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param next_hop_sw_if_index - index of interface used to get to next hop - @param is_ipv6 - 1 for IPv6, 0 for IPv4 - @param is_error - address not found or does not match intf - @param address[] - Address in question -*/ -define is_address_reachable -{ - u32 client_index; /* (api_main_t *) am->my_client_index */ - u32 context; - u32 next_hop_sw_if_index; - u8 is_known; /* on reply, this is the answer */ - u8 is_ipv6; - u8 is_error; /* address not found or does not match intf */ - u8 address[16]; -}; - /** \brief Want Stats, register for stats updates @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -256,7 +237,7 @@ define vnet_get_summary_stats @param total_bytes - @param vector_rate - */ -define vnet_summary_stats_reply +define vnet_get_summary_stats_reply { u32 context; i32 retval; @@ -414,7 +395,7 @@ define control_ping_reply @param context - sender context, to match reply w/ request @param cmd_in_shmem - pointer to cli command string */ -define cli_request +define cli { u32 client_index; u32 context; -- cgit 1.2.3-korg From b823df5a7db8208f0162a50ba034a2037f7e7c67 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Mon, 12 Jun 2017 17:07:22 +0300 Subject: L2FIB:fix crash in show with deleted subif entries after deleting a sub interface it's l2fib entries are left with a dangling sw_if_index (while waiting for the ager to delete them). changed "show l2fib" to reflect that state with "Deleted" as the interface name. added sleep in test_l2_fib as a workaround for packets still passing after flush will investigate... Change-Id: Id998d7d3c6a073ef5005c5f3009e1cfb7febf7db Signed-off-by: Eyal Bari --- src/vnet/l2/l2_fib.c | 11 +++++++---- test/test_l2_fib.py | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index d4207e35..f17eee2a 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -62,10 +62,13 @@ format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args) u32 sw_if_index = va_arg (*args, u32); if (sw_if_index == ~0) return format (s, "N/A"); - else - return format (s, "%U", - format_vnet_sw_interface_name, vnm, - vnet_get_sw_interface (vnm, sw_if_index)); + + vnet_sw_interface_t *swif = vnet_get_sw_interface_safe (vnm, sw_if_index); + if (!swif) + return format (s, "Deleted"); + + return format (s, "%U", format_vnet_sw_interface_name, vnm, + vnet_get_sw_interface_safe (vnm, sw_if_index)); } void diff --git a/test/test_l2_fib.py b/test/test_l2_fib.py index 9249a2ce..f9a78efc 100644 --- a/test/test_l2_fib.py +++ b/test/test_l2_fib.py @@ -490,6 +490,7 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_int(self.pg_interfaces[0].sw_if_index) + self.sleep(1) self.run_verify_test(bd_id=1, dst_hosts=self.learned_hosts) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) @@ -503,6 +504,7 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_bd(bd_id=1) + self.sleep(1) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_test(bd_id=2, dst_hosts=self.learned_hosts) @@ -516,6 +518,7 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_all() + self.sleep(2) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_negat_test(bd_id=2, dst_hosts=flushed) -- cgit 1.2.3-korg From 6f7ebf900e6c65b73f8bb8f60ab5190cc2c893bc Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Tue, 13 Jun 2017 12:09:37 +0300 Subject: ETH:fix l2_len/vlan count mismatch for > 2 tags l2_len was not updated for the third tag as the ethernet node retracts by the vlan count after parse_header (using ethernet_buffer_header_size) it ends up pointing before the ethernet header + some minor cleanups Change-Id: I4ccaedd33928912e5d837376f146503b27071741 Signed-off-by: Eyal Bari --- src/vnet/ethernet/node.c | 5 ++++- src/vnet/l2/l2_input_vtr.c | 15 +++------------ src/vnet/l2/l2_vtr.c | 3 --- 3 files changed, 7 insertions(+), 16 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index 8967cebe..4529ca6a 100755 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -165,11 +165,12 @@ parse_header (ethernet_input_variant_t variant, vlib_buffer_advance (b0, sizeof (h0[0])); vlan_count = 2; - if (*type == ETHERNET_TYPE_VLAN) { // More than double tagged packet *match_flags = SUBINT_CONFIG_VALID | SUBINT_CONFIG_MATCH_3_TAG; + + vlib_buffer_advance (b0, sizeof (h0[0])); vlan_count = 3; // "unknown" number, aka, 3-or-more } } @@ -239,6 +240,8 @@ determine_next_node (ethernet_main_t * em, // record the L2 len and reset the buffer so the L2 header is preserved u32 eth_start = vnet_buffer (b0)->ethernet.start_of_ethernet_header; vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start; + ASSERT (vnet_buffer (b0)->l2.l2_len == + ethernet_buffer_header_size (b0)); vlib_buffer_advance (b0, -ethernet_buffer_header_size (b0)); // check for common IP/MPLS ethertypes diff --git a/src/vnet/l2/l2_input_vtr.c b/src/vnet/l2/l2_input_vtr.c index 60a39631..ded23095 100644 --- a/src/vnet/l2/l2_input_vtr.c +++ b/src/vnet/l2/l2_input_vtr.c @@ -188,10 +188,7 @@ l2_invtr_node_fn (vlib_main_t * vm, if (config0->output_vtr.push_and_pop_bytes) { /* perform the tag rewrite on two packets */ - if (l2_vtr_process - (b0, - &(vec_elt_at_index - (l2output_main.configs, sw_if_index0)->input_vtr))) + if (l2_vtr_process (b0, &config0->input_vtr)) { /* Drop packet */ next0 = L2_INVTR_NEXT_DROP; @@ -212,10 +209,7 @@ l2_invtr_node_fn (vlib_main_t * vm, { if (config1->output_vtr.push_and_pop_bytes) { - if (l2_vtr_process - (b1, - &(vec_elt_at_index - (l2output_main.configs, sw_if_index1)->input_vtr))) + if (l2_vtr_process (b1, &config1->input_vtr)) { /* Drop packet */ next1 = L2_INVTR_NEXT_DROP; @@ -305,10 +299,7 @@ l2_invtr_node_fn (vlib_main_t * vm, if (config0->output_vtr.push_and_pop_bytes) { /* perform the tag rewrite on one packet */ - if (l2_vtr_process - (b0, - &(vec_elt_at_index - (l2output_main.configs, sw_if_index0)->input_vtr))) + if (l2_vtr_process (b0, &config0->input_vtr)) { /* Drop packet */ next0 = L2_INVTR_NEXT_DROP; diff --git a/src/vnet/l2/l2_vtr.c b/src/vnet/l2/l2_vtr.c index 3c5365f9..02a68991 100644 --- a/src/vnet/l2/l2_vtr.c +++ b/src/vnet/l2/l2_vtr.c @@ -229,9 +229,6 @@ l2vtr_configure (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_ind } in_config->pop_bytes = 8; in_config->push_bytes = 0; - - out_config->push_bytes = in_config->pop_bytes; - out_config->pop_bytes = in_config->push_bytes; break; case L2_VTR_PUSH_1: -- cgit 1.2.3-korg From 0f360dc3aa40d0654198bd3f3850bd31a0d78f7e Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 14 Jun 2017 13:11:20 +0300 Subject: L2FWD:fix seq_num overwritten + validate l2fib entries when forwarding l2_classify memeber table_index was overlaid over l2.l2fib_seq_num which over written when table_index gets initialized in l2_input_classify solved by overlaying both table_index and opaque_index as only one is used seperated l2fib seq num from l2_input configs for better handling of theoretical ABA issue where an entry for a deleted interface is considered valid by the ager because a different interface with same sw_if_index and seq_num was created before the ager got a chance to delete Change-Id: I7b0eeded971627406f1c80834d7e02c0ebe62136 Signed-off-by: Eyal Bari --- src/vnet/buffer.h | 15 ++++++++--- src/vnet/l2/l2_bd.c | 5 ++-- src/vnet/l2/l2_fib.c | 19 +++---------- src/vnet/l2/l2_fib.h | 24 +++++++++++++++++ src/vnet/l2/l2_fwd.c | 72 +++++++++++++++++++++++++++++++++----------------- src/vnet/l2/l2_input.c | 4 +-- src/vnet/l2/l2_input.h | 3 --- src/vnet/l2/l2_learn.c | 13 +++++---- test/test_l2_fib.py | 3 --- 9 files changed, 99 insertions(+), 59 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index ec5e2f75..795bbd96 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -195,9 +195,13 @@ typedef struct /* L2 classify */ struct { - u64 pad; - u32 table_index; - u32 opaque_index; + u64 pad; /* paddind for l2 */ + u16 pad1; + union + { + u32 table_index; + u32 opaque_index; + }; u64 hash; } l2_classify; @@ -296,6 +300,11 @@ typedef struct STATIC_ASSERT (sizeof (vnet_buffer_opaque_t) <= STRUCT_SIZE_OF (vlib_buffer_t, opaque), "VNET buffer meta-data too large for vlib_buffer"); +STATIC_ASSERT (STRUCT_OFFSET_OF + (vnet_buffer_opaque_t, + l2_classify.table_index) >= + STRUCT_SIZE_OF (vnet_buffer_opaque_t, l2), + "l2_classify padding smaller than l2"); #define vnet_buffer(b) ((vnet_buffer_opaque_t *) (b)->opaque) diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index f68b6638..a87d02f2 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -1019,8 +1019,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { l2_flood_member_t *member = vec_elt_at_index (bd_config->members, i); - l2_input_config_t *int_config = - l2input_intf_config (member->sw_if_index); + u8 swif_seq_num = *l2fib_swif_seq_num (member->sw_if_index); u32 vtr_opr, dot1q, tag1, tag2; if (i == 0) { @@ -1033,7 +1032,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) vlib_cli_output (vm, "%=30U%=7d%=5d%=5d%=5s%=9s%=30U", format_vnet_sw_if_index_name, vnm, member->sw_if_index, member->sw_if_index, - int_config->seq_num, member->shg, + swif_seq_num, member->shg, member->flags & L2_FLOOD_MEMBER_BVI ? "*" : "-", i < bd_config->flood_count ? "*" : "-", format_vtr, vtr_opr, dot1q, tag1, tag2); diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index f17eee2a..2bb6d105 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -41,17 +41,6 @@ * */ -typedef struct -{ - - /* hash table */ - BVT (clib_bihash) mac_table; - - /* convenience variables */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} l2fib_main_t; - l2fib_main_t l2fib_main; /** Format sw_if_index. If the value is ~0, use the text "N/A" */ @@ -65,7 +54,7 @@ format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args) vnet_sw_interface_t *swif = vnet_get_sw_interface_safe (vnm, sw_if_index); if (!swif) - return format (s, "Deleted"); + return format (s, "Stale"); return format (s, "%U", format_vnet_sw_interface_name, vnm, vnet_get_sw_interface_safe (vnm, sw_if_index)); @@ -305,11 +294,10 @@ VLIB_CLI_COMMAND (clear_l2fib_cli, static) = { static inline l2fib_seq_num_t l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index) { - l2_input_config_t *int_config = l2input_intf_config (sw_if_index); l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index); /* *INDENT-OFF* */ return (l2fib_seq_num_t) { - .swif = int_config->seq_num, + .swif = *l2fib_swif_seq_num (sw_if_index), .bd = bd_config->seq_num, }; /* *INDENT-ON* */ @@ -748,8 +736,7 @@ l2fib_start_ager_scan (vlib_main_t * vm) void l2fib_flush_int_mac (vlib_main_t * vm, u32 sw_if_index) { - l2_input_config_t *int_config = l2input_intf_config (sw_if_index); - int_config->seq_num += 1; + *l2fib_swif_seq_num (sw_if_index) += 1; l2fib_start_ager_scan (vm); } diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index e571a210..03184502 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -27,6 +27,22 @@ #define L2FIB_NUM_BUCKETS (64 * 1024) #define L2FIB_MEMORY_SIZE (256<<20) +typedef struct +{ + + /* hash table */ + BVT (clib_bihash) mac_table; + + /* per swif vector of sequence number for interface based flush of MACs */ + u8 *swif_seq_num; + + /* convenience variables */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} l2fib_main_t; + +extern l2fib_main_t l2fib_main; + /* * The L2fib key is the mac address and bridge domain ID */ @@ -350,6 +366,14 @@ l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, u8 *format_vnet_sw_if_index_name_with_NA (u8 * s, va_list * args); +static_always_inline u8 * +l2fib_swif_seq_num (u32 sw_if_index) +{ + l2fib_main_t *mp = &l2fib_main; + vec_validate (mp->swif_seq_num, sw_if_index); + return vec_elt_at_index (mp->swif_seq_num, sw_if_index); +} + BVT (clib_bihash) * get_mac_table (void); #endif diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c index f7e2ccb6..8140728b 100644 --- a/src/vnet/l2/l2_fwd.c +++ b/src/vnet/l2/l2_fwd.c @@ -89,7 +89,8 @@ _(HIT, "L2 forward hits") \ _(BVI_BAD_MAC, "BVI L3 MAC mismatch") \ _(BVI_ETHERTYPE, "BVI packet with unhandled ethertype") \ _(FILTER_DROP, "Filter Mac Drop") \ -_(REFLECT_DROP, "Reflection Drop") +_(REFLECT_DROP, "Reflection Drop") \ +_(STALE_DROP, "Stale entry Drop") typedef enum { @@ -123,28 +124,15 @@ l2fwd_process (vlib_main_t * vm, vlib_buffer_t * b0, u32 sw_if_index0, l2fib_entry_result_t * result0, u32 * next0) { - if (PREDICT_FALSE (result0->raw == ~0)) - { - /* - * lookup miss, so flood - * TODO:replicate packet to each intf in bridge-domain - * For now just drop - */ - if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD) - { - *next0 = L2FWD_NEXT_FLOOD; - } - else - { - /* Flooding is disabled */ - b0->error = node->errors[L2FWD_ERROR_FLOOD]; - *next0 = L2FWD_NEXT_DROP; - } + int try_flood = result0->raw == ~0; + int flood_error; + if (PREDICT_FALSE (try_flood)) + { + flood_error = L2FWD_ERROR_FLOOD; } else { - /* lookup hit, forward packet */ #ifdef COUNTERS em->counters[node_counter_base_index + L2FWD_ERROR_HIT] += 1; @@ -152,22 +140,37 @@ l2fwd_process (vlib_main_t * vm, vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index; *next0 = L2FWD_NEXT_L2_OUTPUT; + int l2fib_seq_num_valid = 1; + /* check l2fib seq num for stale entries */ + if (!result0->fields.static_mac) + { + l2fib_seq_num_t in_sn = {.as_u16 = vnet_buffer (b0)->l2.l2fib_sn }; + l2fib_seq_num_t expected_sn = { + .bd = in_sn.bd, + .swif = *l2fib_swif_seq_num (result0->fields.sw_if_index), + }; + l2fib_seq_num_valid = + expected_sn.as_u16 == result0->fields.sn.as_u16; + } + if (PREDICT_FALSE (!l2fib_seq_num_valid)) + { + flood_error = L2FWD_ERROR_STALE_DROP; + try_flood = 1; + } /* perform reflection check */ - if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index)) + else if (PREDICT_FALSE (sw_if_index0 == result0->fields.sw_if_index)) { b0->error = node->errors[L2FWD_ERROR_REFLECT_DROP]; *next0 = L2FWD_NEXT_DROP; - - /* perform filter check */ } + /* perform filter check */ else if (PREDICT_FALSE (result0->fields.filter)) { b0->error = node->errors[L2FWD_ERROR_FILTER_DROP]; *next0 = L2FWD_NEXT_DROP; - - /* perform BVI check */ } + /* perform BVI check */ else if (PREDICT_FALSE (result0->fields.bvi)) { u32 rc; @@ -192,6 +195,27 @@ l2fwd_process (vlib_main_t * vm, } } } + + /* flood */ + if (PREDICT_FALSE (try_flood)) + { + /* + * lookup miss, so flood + * TODO:replicate packet to each intf in bridge-domain + * For now just drop + */ + if (vnet_buffer (b0)->l2.feature_bitmap & L2INPUT_FEAT_UU_FLOOD) + { + *next0 = L2FWD_NEXT_FLOOD; + } + else + { + /* Flooding is disabled */ + b0->error = node->errors[flood_error]; + *next0 = L2FWD_NEXT_DROP; + } + } + } diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index aca23fe0..22fc2a98 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -205,7 +205,7 @@ classify_and_dispatch (vlib_main_t * vm, /* Save bridge domain and interface seq_num */ /* *INDENT-OFF* */ l2fib_seq_num_t sn = { - .swif = config->seq_num, + .swif = *l2fib_swif_seq_num(sw_if_index0), .bd = bd_config->seq_num, }; /* *INDENT-ON* */ @@ -637,7 +637,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->xconnect = 0; config->bridge = 1; config->bd_index = bd_index; - config->seq_num += 1; + *l2fib_swif_seq_num (sw_if_index) += 1; /* * Enable forwarding, flooding, learning and ARP termination by default diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index cb67cb9d..c1b669b4 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -53,9 +53,6 @@ typedef struct /* split horizon group */ u8 shg; - /* sequence number for interface based flush of MACs */ - u8 seq_num; - } l2_input_config_t; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index adc5e70f..3ff2e704 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -138,11 +138,14 @@ l2learn_process (vlib_node_runtime_t * node, * The entry was in the table, and the sw_if_index matched, the normal case */ counter_base[L2LEARN_ERROR_HIT] += 1; - if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) - result0->fields.timestamp = timestamp; - if (PREDICT_FALSE - (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) - result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; + if (!result0->fields.static_mac) + { + if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) + result0->fields.timestamp = timestamp; + if (PREDICT_FALSE + (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; + } } else if (result0->raw == ~0) { diff --git a/test/test_l2_fib.py b/test/test_l2_fib.py index f9a78efc..9249a2ce 100644 --- a/test/test_l2_fib.py +++ b/test/test_l2_fib.py @@ -490,7 +490,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_int(self.pg_interfaces[0].sw_if_index) - self.sleep(1) self.run_verify_test(bd_id=1, dst_hosts=self.learned_hosts) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) @@ -504,7 +503,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_bd(bd_id=1) - self.sleep(1) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_test(bd_id=2, dst_hosts=self.learned_hosts) @@ -518,7 +516,6 @@ class TestL2fib(VppTestCase): self.config_l2_fib_entries(bd_id=1, n_hosts_per_if=10) self.config_l2_fib_entries(bd_id=2, n_hosts_per_if=10) flushed = self.flush_all() - self.sleep(2) self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_negat_test(bd_id=2, dst_hosts=flushed) -- cgit 1.2.3-korg From 31a71ab497616940c105fa1719515fe7ae37f37a Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Sun, 25 Jun 2017 14:42:33 +0300 Subject: L2-LEARN:fix l2fib entry seq num not updated on hit (VPP-888) fixed instability in l2bd_multi_instnce test - sometimes failing with extra packets captured it appears l2-learn was not updating hit entries but rather a copy of them. if the ager did not have a chance to run before the test was running the learning cycle - entries were not updated with the packet's seq num - causing packets to flood when hitting the stale seq_num in l2-fwd - hence the extra packets fixed handling of filter entries revert workaround for instability in test Change-Id: I16d918e6310a5bf40bad5b7335b2140c2867cb71 Signed-off-by: Eyal Bari (cherry picked from commit 25ff2ea3a31e422094f6d91eab46222a29a77c4b) --- src/vnet/l2/l2_api.c | 28 +++++------- src/vnet/l2/l2_fib.c | 10 ++-- src/vnet/l2/l2_fib.h | 13 ++++++ src/vnet/l2/l2_input.c | 2 +- src/vnet/l2/l2_learn.c | 98 ++++++++++++++-------------------------- test/test_l2bd_multi_instance.py | 58 ++++++++++++------------ 6 files changed, 93 insertions(+), 116 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index aa3dcb7e..a0b40d6d 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -187,30 +187,24 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) l2input_main_t *l2im = &l2input_main; vl_api_l2fib_add_del_reply_t *rmp; int rv = 0; - u64 mac = 0; - u32 sw_if_index = ntohl (mp->sw_if_index); u32 bd_id = ntohl (mp->bd_id); - u32 bd_index; - u32 static_mac; - u32 filter_mac; - u32 bvi_mac; - uword *p; - - mac = mp->mac; + uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); - p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (!p) { rv = VNET_API_ERROR_NO_SUCH_ENTRY; goto bad_sw_if_index; } - bd_index = p[0]; + u32 bd_index = p[0]; + u64 mac = mp->mac; if (mp->is_add) { - filter_mac = mp->filter_mac ? 1 : 0; - if (filter_mac == 0) + if (mp->filter_mac) + l2fib_add_filter_entry (mac, bd_index); + else { + u32 sw_if_index = ntohl (mp->sw_if_index); VALIDATE_SW_IF_INDEX (mp); if (vec_len (l2im->configs) <= sw_if_index) { @@ -227,11 +221,11 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) goto bad_sw_if_index; } } + u32 static_mac = mp->static_mac ? 1 : 0; + u32 bvi_mac = mp->bvi_mac ? 1 : 0; + l2fib_add_fwd_entry (mac, bd_index, sw_if_index, static_mac, + bvi_mac); } - static_mac = mp->static_mac ? 1 : 0; - bvi_mac = mp->bvi_mac ? 1 : 0; - l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac, - bvi_mac); } else { diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 2bb6d105..6f8f6e06 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -413,8 +413,10 @@ l2fib_add (vlib_main_t * vm, } } - l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, filter_mac, - bvi_mac); + if (filter_mac) + l2fib_add_filter_entry (mac, bd_index); + else + l2fib_add_fwd_entry (mac, bd_index, sw_if_index, static_mac, bvi_mac); done: return error; @@ -464,7 +466,6 @@ l2fib_test_command_fn (vlib_main_t * vm, u64 mac, save_mac; u32 bd_index = 0; u32 sw_if_index = 8; - u32 filter_mac = 0; u32 bvi_mac = 0; u32 is_add = 0; u32 is_del = 0; @@ -503,8 +504,7 @@ l2fib_test_command_fn (vlib_main_t * vm, for (i = 0; i < count; i++) { u64 tmp; - l2fib_add_entry (mac, bd_index, sw_if_index, mac, - filter_mac, bvi_mac); + l2fib_add_fwd_entry (mac, bd_index, sw_if_index, mac, bvi_mac); tmp = clib_net_to_host_u64 (mac); tmp >>= 16; tmp++; diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 03184502..21dcc451 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -350,6 +350,19 @@ l2fib_add_entry (u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, u32 drop_mac, u32 bvi_mac); +static inline void +l2fib_add_fwd_entry (u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, + u32 bvi_mac) +{ + l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, 0, bvi_mac); +} + +static inline void +l2fib_add_filter_entry (u64 mac, u32 bd_index) +{ + l2fib_add_entry (mac, bd_index, ~0, 1, 1, 0); +} + u32 l2fib_del_entry (u64 mac, u32 bd_index); void l2fib_start_ager_scan (vlib_main_t * vm); diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 22fc2a98..d536d15b 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -671,7 +671,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ /* create the l2fib entry for the bvi interface */ mac = *((u64 *) hi->hw_address); - l2fib_add_entry (mac, bd_index, sw_if_index, 1, 0, 1); /* static + bvi */ + l2fib_add_fwd_entry (mac, bd_index, sw_if_index, 1, 1); /* static + bvi */ /* Disable learning by default. no use since l2fib entry is static. */ config->feature_bitmap &= ~L2INPUT_FEAT_LEARN; diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 3ff2e704..b9904d3e 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -131,27 +131,22 @@ l2learn_process (vlib_node_runtime_t * node, feature_bitmap); /* Check mac table lookup result */ - if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) { /* * The entry was in the table, and the sw_if_index matched, the normal case */ counter_base[L2LEARN_ERROR_HIT] += 1; - if (!result0->fields.static_mac) - { - if (PREDICT_FALSE (result0->fields.timestamp != timestamp)) - result0->fields.timestamp = timestamp; - if (PREDICT_FALSE - (result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn)) - result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; - } + int update = !result0->fields.static_mac && + (result0->fields.timestamp != timestamp || + result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn); + + if (PREDICT_TRUE (!update)) + return; } else if (result0->raw == ~0) { - /* The entry was not in table, so add it */ - counter_base[L2LEARN_ERROR_MISS] += 1; if (msm->global_learn_count == msm->global_learn_limit) @@ -161,32 +156,27 @@ l2learn_process (vlib_node_runtime_t * node, * In the future, limits could also be per-interface or bridge-domain. */ counter_base[L2LEARN_ERROR_LIMIT] += 1; - goto done; - - } - else - { - BVT (clib_bihash_kv) kv; - /* It is ok to learn */ - - result0->raw = 0; /* clear all fields */ - result0->fields.sw_if_index = sw_if_index0; - result0->fields.timestamp = timestamp; - result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; - kv.key = key0->raw; - kv.value = result0->raw; - - BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); - - cached_key->raw = ~0; /* invalidate the cache */ - msm->global_learn_count++; + return; } + /* It is ok to learn */ + msm->global_learn_count++; + result0->raw = 0; /* clear all fields */ + result0->fields.sw_if_index = sw_if_index0; + cached_key->raw = ~0; /* invalidate the cache */ } else { - /* The entry was in the table, but with the wrong sw_if_index mapping (mac move) */ + if (result0->fields.filter) + { + ASSERT (result0->fields.sw_if_index == ~0); + /* drop packet because lookup matched a filter mac entry */ + b0->error = node->errors[L2LEARN_ERROR_FILTER_DROP]; + *next0 = L2LEARN_NEXT_DROP; + return; + } + counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; if (result0->fields.static_mac) @@ -197,44 +187,24 @@ l2learn_process (vlib_node_runtime_t * node, */ b0->error = node->errors[L2LEARN_ERROR_MAC_MOVE_VIOLATE]; *next0 = L2LEARN_NEXT_DROP; + return; } - else - { - /* - * Update the entry - * TODO: may want to rate limit mac moves - * TODO: check global/bridge domain/interface learn limits - */ - BVT (clib_bihash_kv) kv; - - result0->raw = 0; /* clear all fields */ - result0->fields.sw_if_index = sw_if_index0; - result0->fields.timestamp = timestamp; - result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; - kv.key = key0->raw; - kv.value = result0->raw; - - cached_key->raw = ~0; /* invalidate the cache */ - - BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); - } + /* + * TODO: may want to rate limit mac moves + * TODO: check global/bridge domain/interface learn limits + */ + result0->fields.sw_if_index = sw_if_index0; } - if (result0->fields.filter) - { - /* drop packet because lookup matched a filter mac entry */ + /* Update the entry */ + result0->fields.timestamp = timestamp; + result0->fields.sn.as_u16 = vnet_buffer (b0)->l2.l2fib_sn; - if (*next0 != L2LEARN_NEXT_DROP) - { - /* if we're not already dropping the packet, do it now */ - b0->error = node->errors[L2LEARN_ERROR_FILTER_DROP]; - *next0 = L2LEARN_NEXT_DROP; - } - } - -done: - return; + BVT (clib_bihash_kv) kv; + kv.key = key0->raw; + kv.value = result0->raw; + BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); } diff --git a/test/test_l2bd_multi_instance.py b/test/test_l2bd_multi_instance.py index 0bb9e597..7dd27fb2 100644 --- a/test/test_l2bd_multi_instance.py +++ b/test/test_l2bd_multi_instance.py @@ -403,7 +403,33 @@ class TestL2bdMultiInst(VppTestCase): self.run_verify_test() def test_l2bd_inst_02(self): - """ L2BD Multi-instance test 2 - delete 2 BDs + """ L2BD Multi-instance test 2 - update data of 5 BDs + """ + # Config 2 + # Update data of 5 BDs (disable learn, forward, flood, uu-flood) + self.set_bd_flags(self.bd_list[0], learn=False, forward=False, + flood=False, uu_flood=False) + self.set_bd_flags(self.bd_list[1], forward=False) + self.set_bd_flags(self.bd_list[2], flood=False) + self.set_bd_flags(self.bd_list[3], uu_flood=False) + self.set_bd_flags(self.bd_list[4], learn=False) + + # Verify 2 + # Skipping check of uu_flood as it is not returned by + # bridge_domain_dump api command + self.verify_bd(self.bd_list[0], learn=False, forward=False, + flood=False, uu_flood=False) + self.verify_bd(self.bd_list[1], learn=True, forward=False, + flood=True, uu_flood=True) + self.verify_bd(self.bd_list[2], learn=True, forward=True, + flood=False, uu_flood=True) + self.verify_bd(self.bd_list[3], learn=True, forward=True, + flood=True, uu_flood=False) + self.verify_bd(self.bd_list[4], learn=False, forward=True, + flood=True, uu_flood=True) + + def test_l2bd_inst_03(self): + """ L2BD Multi-instance test 3 - delete 2 BDs """ # Config 3 # Delete 2 BDs @@ -418,8 +444,8 @@ class TestL2bdMultiInst(VppTestCase): # Test 3 self.run_verify_test() - def test_l2bd_inst_03(self): - """ L2BD Multi-instance test 3 - add 2 BDs + def test_l2bd_inst_04(self): + """ L2BD Multi-instance test 4 - add 2 BDs """ # Config 4 # Create 5 BDs, put interfaces to these BDs and send MAC learning @@ -434,32 +460,6 @@ class TestL2bdMultiInst(VppTestCase): # self.vapi.cli("clear trace") self.run_verify_test() - def test_l2bd_inst_04(self): - """ L2BD Multi-instance test 4 - update data of 5 BDs - """ - # Config 2 - # Update data of 5 BDs (disable learn, forward, flood, uu-flood) - self.set_bd_flags(self.bd_list[0], learn=False, forward=False, - flood=False, uu_flood=False) - self.set_bd_flags(self.bd_list[1], forward=False) - self.set_bd_flags(self.bd_list[2], flood=False) - self.set_bd_flags(self.bd_list[3], uu_flood=False) - self.set_bd_flags(self.bd_list[4], learn=False) - - # Verify 2 - # Skipping check of uu_flood as it is not returned by - # bridge_domain_dump api command - self.verify_bd(self.bd_list[0], learn=False, forward=False, - flood=False, uu_flood=False) - self.verify_bd(self.bd_list[1], learn=True, forward=False, - flood=True, uu_flood=True) - self.verify_bd(self.bd_list[2], learn=True, forward=True, - flood=False, uu_flood=True) - self.verify_bd(self.bd_list[3], learn=True, forward=True, - flood=True, uu_flood=False) - self.verify_bd(self.bd_list[4], learn=False, forward=True, - flood=True, uu_flood=True) - def test_l2bd_inst_05(self): """ L2BD Multi-instance test 5 - delete 5 BDs """ -- cgit 1.2.3-korg From 8af1b2fdecc883eadfec6b91434adc6044e24cb2 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Tue, 11 Jul 2017 14:24:37 +0300 Subject: L2INPUT:fix features mask cailculation Change-Id: I84cea7530b01302a0adeef95b4924f54dc2e41ec Signed-off-by: Eyal Bari --- src/vnet/l2/l2_input.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index c1b669b4..244ef445 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -124,22 +124,26 @@ typedef enum #define _(sym,str) L2INPUT_FEAT_##sym##_BIT, foreach_l2input_feat #undef _ - L2INPUT_N_FEAT, - L2INPUT_VALID_MASK = -#define _(sym,str) L2INPUT_FEAT_##sym##_BIT | - foreach_l2input_feat -#undef _ - 0, + L2INPUT_N_FEAT } l2input_feat_t; +STATIC_ASSERT (L2INPUT_N_FEAT <= 32, "too many l2 input features"); + /* Feature bit masks */ typedef enum { #define _(sym,str) L2INPUT_FEAT_##sym = (1< Date: Wed, 12 Jul 2017 19:56:45 -0400 Subject: Fix crash with worker threads on 4K VXLAN/BD setup (VPP-907) Cleanup mapping of interface output node for the l2-output node when interface is configured to L2 or L3 modes. The mapping is now always done in the main thread as part of API/CLI processing, instead of initiate mapping in the forwarding path which can be in the worker threads. Change-Id: Ia789493e7d9f5c76d68edfaf34db43f3e3f53506 Signed-off-by: John Lo (cherry picked from commit bea5ebf205e0bec922bf26c6c1a6a9392b4cad67) --- src/vnet/interface.h | 8 +--- src/vnet/l2/l2_efp_filter.c | 3 -- src/vnet/l2/l2_fib.c | 7 ++++ src/vnet/l2/l2_input.c | 49 ++++++++++++------------ src/vnet/l2/l2_output.c | 83 +++++----------------------------------- src/vnet/l2/l2_output.h | 68 ++++---------------------------- src/vnet/l2/l2_output_acl.c | 3 -- src/vnet/l2/l2_output_classify.c | 3 -- 8 files changed, 51 insertions(+), 173 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/interface.h b/src/vnet/interface.h index ce7700e4..9d64fc28 100644 --- a/src/vnet/interface.h +++ b/src/vnet/interface.h @@ -416,10 +416,6 @@ typedef struct vnet_hw_interface_t VNET_HW_INTERFACE_FLAG_SPEED_40G | \ VNET_HW_INTERFACE_FLAG_SPEED_100G) - /* l2output node flags */ -#define VNET_HW_INTERFACE_FLAG_L2OUTPUT_SHIFT 9 -#define VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED (1 << 9) - /* rx mode flags */ #define VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE (1 << 10) @@ -569,10 +565,10 @@ typedef struct #define VNET_SW_INTERFACE_FLAG_BOND_SLAVE (1 << 4) -/* Interface does not appear in CLI/API */ + /* Interface does not appear in CLI/API */ #define VNET_SW_INTERFACE_FLAG_HIDDEN (1 << 5) -/* Interface in ERROR state */ + /* Interface in ERROR state */ #define VNET_SW_INTERFACE_FLAG_ERROR (1 << 6) /* Index for this interface. */ diff --git a/src/vnet/l2/l2_efp_filter.c b/src/vnet/l2/l2_efp_filter.c index 2db4dc69..f9ba8f2f 100644 --- a/src/vnet/l2/l2_efp_filter.c +++ b/src/vnet/l2/l2_efp_filter.c @@ -530,9 +530,6 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_efp_filter_node, l2_efp_filter_node_fn) l2output_get_feat_names (), mp->next_nodes.feat_next_node_index); - /* Initialize the output node mapping table */ - l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); - return 0; } diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 6f8f6e06..4ed16987 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -413,6 +413,13 @@ l2fib_add (vlib_main_t * vm, } } + if (vec_len (l2input_main.configs) <= sw_if_index) + { + error = clib_error_return (0, "Interface sw_if_index %d not in L2 mode", + sw_if_index); + goto done; + } + if (filter_mac) l2fib_add_filter_entry (mac, bd_index); else diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index d536d15b..9a3148c5 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -573,13 +573,9 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ l2_if_adjust--; } - /* - * Directs the l2 output path to work out the interface - * output next-arc itself. Needed when recycling a sw_if_index. - */ + /* Make sure vector is big enough */ vec_validate_init_empty (l2om->next_nodes.output_node_index_vec, - sw_if_index, ~0); - l2om->next_nodes.output_node_index_vec[sw_if_index] = ~0; + sw_if_index, L2OUTPUT_NEXT_DROP); /* Initialize the l2-input configuration for the interface */ if (mode == MODE_L3) @@ -601,26 +597,11 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ l2om->next_nodes.output_node_index_vec[sw_if_index] = L2OUTPUT_NEXT_BAD_INTF; } - else if (mode == MODE_L2_CLASSIFY) - { - config->xconnect = 1; - config->bridge = 0; - config->output_sw_if_index = xc_sw_if_index; - - /* Make sure last-chance drop is configured */ - config->feature_bitmap |= - L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY; - - /* Make sure bridging features are disabled */ - config->feature_bitmap &= - ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD); - shg = 0; /* not used in xconnect */ - - /* Insure all packets go to ethernet-input */ - ethernet_set_rx_redirect (vnet_main, hi, 1); - } else { + /* Add or update l2-output node next-arc and output_node_index_vec table + * for the interface */ + l2output_create_output_node_mapping (vm, vnet_main, sw_if_index); if (mode == MODE_L2_BRIDGE) { @@ -693,7 +674,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ bd_add_member (bd_config, &member); } - else + else if (mode == MODE_L2_XC) { config->xconnect = 1; config->bridge = 0; @@ -709,6 +690,24 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->feature_bitmap |= L2INPUT_FEAT_XCONNECT; shg = 0; /* not used in xconnect */ } + else if (mode == MODE_L2_CLASSIFY) + { + config->xconnect = 1; + config->bridge = 0; + config->output_sw_if_index = xc_sw_if_index; + + /* Make sure last-chance drop is configured */ + config->feature_bitmap |= + L2INPUT_FEAT_DROP | L2INPUT_FEAT_INPUT_CLASSIFY; + + /* Make sure bridging features are disabled */ + config->feature_bitmap &= + ~(L2INPUT_FEAT_LEARN | L2INPUT_FEAT_FWD | L2INPUT_FEAT_FLOOD); + shg = 0; /* not used in xconnect */ + + /* Insure all packets go to ethernet-input */ + ethernet_set_rx_redirect (vnet_main, hi, 1); + } /* set up split-horizon group and set output feature bit */ config->shg = shg; diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index e17b2a16..51d5e145 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -601,90 +601,27 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn) mp->next_nodes.feat_next_node_index); /* Initialize the output node mapping table */ - l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); + vec_validate_init_empty (mp->next_nodes.output_node_index_vec, 100, + L2OUTPUT_NEXT_DROP); return 0; } VLIB_INIT_FUNCTION (l2output_init); -typedef struct -{ - u32 node_index; - u32 sw_if_index; -} output_node_mapping_rpc_args_t; - -static void output_node_rpc_callback (output_node_mapping_rpc_args_t * a); - -static void -output_node_mapping_send_rpc (u32 node_index, u32 sw_if_index) -{ - output_node_mapping_rpc_args_t args; - void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); - - args.node_index = node_index; - args.sw_if_index = sw_if_index; - - vl_api_rpc_call_main_thread (output_node_rpc_callback, - (u8 *) & args, sizeof (args)); -} - /** Create a mapping in the next node mapping table for the given sw_if_index. */ -u32 -l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 node_index, /* index of current node */ - u32 * output_node_index_vec, - u32 sw_if_index) -{ - - u32 next; /* index of next graph node */ - vnet_hw_interface_t *hw0; - u32 *node; - - hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index); - - uword thread_index; - - thread_index = vlib_get_thread_index (); - - if (thread_index) - { - u32 oldflags; - - oldflags = __sync_fetch_and_or (&hw0->flags, - VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED); - - if ((oldflags & VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED)) - return L2OUTPUT_NEXT_DROP; - - output_node_mapping_send_rpc (node_index, sw_if_index); - return L2OUTPUT_NEXT_DROP; - } - - /* dynamically create graph node arc */ - next = vlib_node_add_next (vlib_main, node_index, hw0->output_node_index); - - /* Initialize vector with the mapping */ - - node = vec_elt_at_index (output_node_index_vec, sw_if_index); - *node = next; - - /* reset mapping bit, includes memory barrier */ - __sync_fetch_and_and (&hw0->flags, ~VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED); - - return next; -} - void -output_node_rpc_callback (output_node_mapping_rpc_args_t * a) +l2output_create_output_node_mapping (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, u32 sw_if_index) { - vlib_main_t *vm = vlib_get_main (); - vnet_main_t *vnm = vnet_get_main (); - l2output_main_t *mp = &l2output_main; + vnet_hw_interface_t *hw0 = + vnet_get_sup_hw_interface (vnet_main, sw_if_index); - (void) l2output_create_output_node_mapping - (vm, vnm, a->node_index, mp->next_nodes.output_node_index_vec, - a->sw_if_index); + /* dynamically create graph node arc */ + u32 next = vlib_node_add_next (vlib_main, l2output_node.index, + hw0->output_node_index); + l2output_main.next_nodes.output_node_index_vec[sw_if_index] = next; } /* Get a pointer to the config for the given interface */ diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index 9597205c..82cefd2c 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -130,7 +130,7 @@ _(EFP_DROP, "L2 EFP filter pre-rewrite drops") \ _(VTR_DROP, "L2 output tag rewrite drops") \ _(SHG_DROP, "L2 split horizon drops") \ _(DROP, "L2 output drops") \ -_(MAPPING_DROP, "L2 Output interface mapping in progress") +_(MAPPING_DROP, "L2 Output interface not valid") typedef enum { @@ -159,52 +159,9 @@ char **l2output_get_feat_names (void); */ /* Create a mapping to the output graph node for the given sw_if_index */ -u32 l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 node_index, /* index of current node */ - u32 * output_node_index_vec, - u32 sw_if_index); - -/* Initialize the next node mapping table */ -always_inline void -l2output_init_output_node_vec (u32 ** output_node_index_vec) -{ - - /* - * Size it at 100 sw_if_indexes initially - * Uninitialized mappings are set to ~0 - */ - vec_validate_init_empty (*output_node_index_vec, 100, ~0); -} - - -/** - * Get a mapping from the output node mapping table, - * creating the entry if necessary. - */ -always_inline u32 -l2output_get_output_node (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 node_index, /* index of current node */ - u32 sw_if_index, u32 ** output_node_index_vec) /* may be updated */ -{ - u32 next; /* index of next graph node */ - - /* Insure the vector is big enough */ - vec_validate_init_empty (*output_node_index_vec, sw_if_index, ~0); - - /* Get the mapping for the sw_if_index */ - next = vec_elt (*output_node_index_vec, sw_if_index); - - if (next == ~0) - { - /* Mapping doesn't exist so create it */ - next = l2output_create_output_node_mapping (vlib_main, - vnet_main, - node_index, - *output_node_index_vec, - sw_if_index); - } - - return next; -} - +void l2output_create_output_node_mapping (vlib_main_t * vlib_main, + vnet_main_t * vnet_main, + u32 sw_if_index); /** Determine the next L2 node based on the output feature bitmap */ always_inline void @@ -257,21 +214,12 @@ l2_output_dispatch (vlib_main_t * vlib_main, } else { - /* Look up the output TX node */ - *next0 = l2output_get_output_node (vlib_main, - vnet_main, - node_index, - sw_if_index, - &next_nodes->output_node_index_vec); + /* Look up the output TX node for the sw_if_index */ + *next0 = vec_elt (l2output_main.next_nodes.output_node_index_vec, + sw_if_index); if (*next0 == L2OUTPUT_NEXT_DROP) - { - vnet_hw_interface_t *hw0; - hw0 = vnet_get_sup_hw_interface (vnet_main, sw_if_index); - - if (hw0->flags & VNET_HW_INTERFACE_FLAG_L2OUTPUT_MAPPED) - b0->error = node->errors[L2OUTPUT_ERROR_MAPPING_DROP]; - } + b0->error = node->errors[L2OUTPUT_ERROR_MAPPING_DROP]; /* Update the one-entry cache */ *cached_sw_if_index = sw_if_index; diff --git a/src/vnet/l2/l2_output_acl.c b/src/vnet/l2/l2_output_acl.c index 94a4d66b..1d1971a5 100644 --- a/src/vnet/l2/l2_output_acl.c +++ b/src/vnet/l2/l2_output_acl.c @@ -297,9 +297,6 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn) l2output_get_feat_names (), mp->next_nodes.feat_next_node_index); - /* Initialize the output node mapping table */ - l2output_init_output_node_vec (&mp->next_nodes.output_node_index_vec); - return 0; } diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c index c1bdaddc..869b0656 100644 --- a/src/vnet/l2/l2_output_classify.c +++ b/src/vnet/l2/l2_output_classify.c @@ -497,9 +497,6 @@ l2_output_classify_init (vlib_main_t * vm) rt->l2cm = cm; rt->vcm = cm->vnet_classify_main; - /* Initialize the output node mapping table */ - l2output_init_output_node_vec (&cm->next_nodes.output_node_index_vec); - return 0; } -- cgit 1.2.3-korg From 072401e8096c648b91f958bd911f64ce24fecff9 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 13 Jul 2017 18:53:27 +0200 Subject: Introduce l{2,3,4}_hdr_offset fields in the buffer metadata To save space in the first cacheline following is changed: - total_length_not_including_first_buffer moved to the 2nd cacheline. This field is used only when VLIB_BUFFER_TOTAL_LENGTH_VALID and VLIB_BUFFER_NEXT_PRESENT are both set. - free_list_index is now stored in 4bits inside flags, which allows up to 16 free lists. In case we need more we can store index in the 2nd cachelin Change-Id: Ic8521350819391af470d31d3fa1013e67ecb7681 Signed-off-by: Damjan Marion --- src/plugins/dpdk/device/node.c | 8 ++++++- src/vlib/buffer.c | 16 ++++++++----- src/vlib/buffer.h | 40 +++++++++++++++++--------------- src/vlib/buffer_funcs.h | 50 +++++++++++++++++++++++++++++----------- src/vnet/bfd/bfd_udp.c | 4 ++-- src/vnet/buffer.h | 14 +++-------- src/vnet/dhcp/dhcp4_proxy_node.c | 2 +- src/vnet/dhcp/dhcp6_proxy_node.c | 2 +- src/vnet/ethernet/ethernet.h | 3 +-- src/vnet/ethernet/node.c | 23 ++++++++---------- src/vnet/ip/ip4_forward.c | 6 ++--- src/vnet/ip/ip6_forward.c | 6 ++--- src/vnet/ip/ip6_neighbor.c | 19 +++++++-------- src/vnet/l2/l2_bvi.h | 2 +- src/vnet/lisp-cp/control.c | 2 +- src/vnet/replication.c | 6 ++--- 16 files changed, 111 insertions(+), 92 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/plugins/dpdk/device/node.c b/src/plugins/dpdk/device/node.c index 69acc529..74fb8da1 100644 --- a/src/plugins/dpdk/device/node.c +++ b/src/plugins/dpdk/device/node.c @@ -208,7 +208,13 @@ dpdk_process_subseq_segs (vlib_main_t * vm, vlib_buffer_t * b, mb_seg = mb->next; b_chain = b; - while ((mb->nb_segs > 1) && (nb_seg < mb->nb_segs)) + if (mb->nb_segs < 2) + return; + + b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID; + b->total_length_not_including_first_buffer = 0; + + while (nb_seg < mb->nb_segs) { ASSERT (mb_seg != 0); diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c index b2a095cf..53b60c16 100644 --- a/src/vlib/buffer.c +++ b/src/vlib/buffer.c @@ -72,8 +72,8 @@ format_vlib_buffer (u8 * s, va_list * args) uword indent = format_get_indent (s); s = format (s, "current data %d, length %d, free-list %d, clone-count %u", - b->current_data, b->current_length, b->free_list_index, - b->n_add_refs); + b->current_data, b->current_length, + vlib_buffer_get_free_list_index (b), b->n_add_refs); if (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID) s = format (s, ", totlen-nifb %d", @@ -163,10 +163,14 @@ vlib_validate_buffer_helper (vlib_main_t * vm, vlib_buffer_main_t *bm = vm->buffer_main; vlib_buffer_free_list_t *fl; - if (pool_is_free_index (bm->buffer_free_list_pool, b->free_list_index)) - return format (0, "unknown free list 0x%x", b->free_list_index); + if (pool_is_free_index + (bm->buffer_free_list_pool, vlib_buffer_get_free_list_index (b))) + return format (0, "unknown free list 0x%x", + vlib_buffer_get_free_list_index (b)); - fl = pool_elt_at_index (bm->buffer_free_list_pool, b->free_list_index); + fl = + pool_elt_at_index (bm->buffer_free_list_pool, + vlib_buffer_get_free_list_index (b)); if ((signed) b->current_data < (signed) -VLIB_BUFFER_PRE_DATA_SIZE) return format (0, "current data %d before pre-data", b->current_data); @@ -388,7 +392,7 @@ vlib_buffer_create_free_list_helper (vlib_main_t * vm, f->name = clib_mem_is_vec (name) ? name : format (0, "%s", name); /* Setup free buffer template. */ - f->buffer_init_template.free_list_index = f->index; + vlib_buffer_set_free_list_index (&f->buffer_init_template, f->index); f->buffer_init_template.n_add_refs = 0; if (is_public) diff --git a/src/vlib/buffer.h b/src/vlib/buffer.h index b20538b7..c810db4e 100644 --- a/src/vlib/buffer.h +++ b/src/vlib/buffer.h @@ -72,6 +72,7 @@ typedef struct the end of this buffer. */ u32 flags; /**< buffer flags: +
VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,
VLIB_BUFFER_IS_TRACED: trace this buffer.
VLIB_BUFFER_NEXT_PRESENT: this is a multi-chunk buffer.
VLIB_BUFFER_TOTAL_LENGTH_VALID: as it says @@ -82,28 +83,26 @@ typedef struct set to avoid adding it to a flow report
VLIB_BUFFER_FLAG_USER(n): user-defined bit N */ -#define VLIB_BUFFER_IS_TRACED (1 << 0) -#define VLIB_BUFFER_LOG2_NEXT_PRESENT (1) + +/* any change to the following line requres update of + * vlib_buffer_get_free_list_index(...) and + * vlib_buffer_set_free_list_index(...) functions */ +#define VLIB_BUFFER_FREE_LIST_INDEX_MASK ((1 << 4) - 1) + +#define VLIB_BUFFER_IS_TRACED (1 << 4) +#define VLIB_BUFFER_LOG2_NEXT_PRESENT (5) #define VLIB_BUFFER_NEXT_PRESENT (1 << VLIB_BUFFER_LOG2_NEXT_PRESENT) -#define VLIB_BUFFER_IS_RECYCLED (1 << 2) -#define VLIB_BUFFER_TOTAL_LENGTH_VALID (1 << 3) -#define VLIB_BUFFER_REPL_FAIL (1 << 4) -#define VLIB_BUFFER_RECYCLE (1 << 5) -#define VLIB_BUFFER_FLOW_REPORT (1 << 6) -#define VLIB_BUFFER_EXT_HDR_VALID (1 << 7) +#define VLIB_BUFFER_IS_RECYCLED (1 << 6) +#define VLIB_BUFFER_TOTAL_LENGTH_VALID (1 << 7) +#define VLIB_BUFFER_REPL_FAIL (1 << 8) +#define VLIB_BUFFER_RECYCLE (1 << 9) +#define VLIB_BUFFER_FLOW_REPORT (1 << 10) +#define VLIB_BUFFER_EXT_HDR_VALID (1 << 11) /* User defined buffer flags. */ #define LOG2_VLIB_BUFFER_FLAG_USER(n) (32 - (n)) #define VLIB_BUFFER_FLAG_USER(n) (1 << LOG2_VLIB_BUFFER_FLAG_USER(n)) - u32 free_list_index; /**< Buffer free list that this buffer was - allocated from and will be freed to. - */ - - u32 total_length_not_including_first_buffer; - /**< Only valid for first buffer in chain. Current length plus - total length given here give total number of bytes in buffer chain. - */ STRUCT_MARK (template_end); u32 next_buffer; /**< Next buffer for this linked-list of buffers. @@ -128,7 +127,7 @@ typedef struct Before allocating any of it, discussion required! */ - u32 opaque[8]; /**< Opaque data used by sub-graphs for their own purposes. + u32 opaque[10]; /**< Opaque data used by sub-graphs for their own purposes. See .../vnet/vnet/buffer.h */ CLIB_CACHE_LINE_ALIGN_MARK (cacheline1); @@ -137,7 +136,12 @@ typedef struct if VLIB_PACKET_IS_TRACED flag is set. */ u32 recycle_count; /**< Used by L2 path recycle code */ - u32 opaque2[14]; /**< More opaque data, currently unused */ + + u32 total_length_not_including_first_buffer; + /**< Only valid for first buffer in chain. Current length plus + total length given here give total number of bytes in buffer chain. + */ + u32 opaque2[13]; /**< More opaque data, currently unused */ /***** end of second cache line */ CLIB_CACHE_LINE_ALIGN_MARK (cacheline2); diff --git a/src/vlib/buffer_funcs.h b/src/vlib/buffer_funcs.h index 97442e12..1aaac0b2 100644 --- a/src/vlib/buffer_funcs.h +++ b/src/vlib/buffer_funcs.h @@ -106,12 +106,15 @@ uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm, always_inline uword vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b) { - uword l = b->current_length + b->total_length_not_including_first_buffer; - if (PREDICT_FALSE ((b->flags & (VLIB_BUFFER_NEXT_PRESENT - | VLIB_BUFFER_TOTAL_LENGTH_VALID)) - == VLIB_BUFFER_NEXT_PRESENT)) - return vlib_buffer_length_in_chain_slow_path (vm, b); - return l; + uword len = b->current_length; + + if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0)) + return len; + + if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)) + return len + b->total_length_not_including_first_buffer; + + return vlib_buffer_length_in_chain_slow_path (vm, b); } /** \brief Get length in bytes of the buffer index buffer chain @@ -261,6 +264,24 @@ vlib_buffer_round_size (u32 size) return round_pow2 (size, sizeof (vlib_buffer_t)); } +always_inline u32 +vlib_buffer_get_free_list_index (vlib_buffer_t * b) +{ + return b->flags & VLIB_BUFFER_FREE_LIST_INDEX_MASK; +} + +always_inline void +vlib_buffer_set_free_list_index (vlib_buffer_t * b, u32 index) +{ + /* if there is an need for more free lists we should consider + storig data in the 2nd cacheline */ + ASSERT (VLIB_BUFFER_FREE_LIST_INDEX_MASK & 1); + ASSERT (index <= VLIB_BUFFER_FREE_LIST_INDEX_MASK); + + b->flags &= ~VLIB_BUFFER_FREE_LIST_INDEX_MASK; + b->flags |= index & VLIB_BUFFER_FREE_LIST_INDEX_MASK; +} + /** \brief Allocate buffers from specific freelist into supplied array @param vm - (vlib_main_t *) vlib main data structure pointer @@ -381,7 +402,7 @@ vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b, vlib_buffer_main_t *bm = vm->buffer_main; u32 i; - *index = i = b->free_list_index; + *index = i = vlib_buffer_get_free_list_index (b); return pool_elt_at_index (bm->buffer_free_list_pool, i); } @@ -569,7 +590,8 @@ vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers, } n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers, - s->free_list_index); + vlib_buffer_get_free_list_index + (s)); if (PREDICT_FALSE (n_buffers == 0)) { buffers[0] = src_buffer; @@ -581,7 +603,8 @@ vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers, vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]); d->current_data = s->current_data; d->current_length = head_end_offset; - d->free_list_index = s->free_list_index; + vlib_buffer_set_free_list_index (d, + vlib_buffer_get_free_list_index (s)); d->total_length_not_including_first_buffer = s->total_length_not_including_first_buffer + s->current_length - head_end_offset; @@ -615,7 +638,8 @@ vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head, vlib_buffer_t * tail) { ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0); - ASSERT (head->free_list_index == tail->free_list_index); + ASSERT (vlib_buffer_get_free_list_index (head) == + vlib_buffer_get_free_list_index (tail)); head->flags |= VLIB_BUFFER_NEXT_PRESENT; head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID; @@ -791,7 +815,7 @@ vlib_buffer_init_for_free_list (vlib_buffer_t * dst, CLIB_CACHE_LINE_BYTES * 2); /* Make sure buffer template is sane. */ - ASSERT (fl->index == fl->buffer_init_template.free_list_index); + ASSERT (fl->index == vlib_buffer_get_free_list_index (src)); clib_memcpy (STRUCT_MARK_PTR (dst, template_start), STRUCT_MARK_PTR (src, template_start), @@ -806,7 +830,6 @@ vlib_buffer_init_for_free_list (vlib_buffer_t * dst, _(current_data); _(current_length); _(flags); - _(free_list_index); #undef _ ASSERT (dst->total_length_not_including_first_buffer == 0); ASSERT (dst->n_add_refs == 0); @@ -832,7 +855,7 @@ vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0, vlib_buffer_t *src = &fl->buffer_init_template; /* Make sure buffer template is sane. */ - ASSERT (fl->index == fl->buffer_init_template.free_list_index); + ASSERT (fl->index == vlib_buffer_get_free_list_index (src)); clib_memcpy (STRUCT_MARK_PTR (dst0, template_start), STRUCT_MARK_PTR (src, template_start), @@ -853,7 +876,6 @@ vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0, _(current_data); _(current_length); _(flags); - _(free_list_index); #undef _ ASSERT (dst0->total_length_not_including_first_buffer == 0); diff --git a/src/vnet/bfd/bfd_udp.c b/src/vnet/bfd/bfd_udp.c index 346c5495..06b843c6 100644 --- a/src/vnet/bfd/bfd_udp.c +++ b/src/vnet/bfd/bfd_udp.c @@ -843,7 +843,7 @@ bfd_udp4_find_headers (vlib_buffer_t * b, ip4_header_t ** ip4, udp_header_t ** udp) { /* sanity check first */ - const i32 start = vnet_buffer (b)->ip.start_of_ip_header; + const i32 start = vnet_buffer (b)->l3_hdr_offset; if (start < 0 && start < sizeof (b->pre_data)) { BFD_ERR ("Start of ip header is before pre_data, ignoring"); @@ -1000,7 +1000,7 @@ bfd_udp6_find_headers (vlib_buffer_t * b, ip6_header_t ** ip6, udp_header_t ** udp) { /* sanity check first */ - const i32 start = vnet_buffer (b)->ip.start_of_ip_header; + const i32 start = vnet_buffer (b)->l3_hdr_offset; if (start < 0 && start < sizeof (b->pre_data)) { BFD_ERR ("Start of ip header is before pre_data, ignoring"); diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 9aba34da..8647db00 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -71,7 +71,6 @@ #define VNET_BUFFER_SPAN_CLONE (1 << LOG2_VNET_BUFFER_SPAN_CLONE) #define foreach_buffer_opaque_union_subtype \ -_(ethernet) \ _(ip) \ _(swt) \ _(l2) \ @@ -100,16 +99,12 @@ _(tcp) typedef struct { u32 sw_if_index[VLIB_N_RX_TX]; + i16 l2_hdr_offset; + i16 l3_hdr_offset; + i16 l4_hdr_offset; union { - /* Ethernet. */ - struct - { - /* Saved value of current header by ethernet-input. */ - i32 start_of_ethernet_header; - } ethernet; - /* IP4/6 buffer opaque. */ struct { @@ -143,9 +138,6 @@ typedef struct u8 code; u32 data; } icmp; - - /* IP header offset from vlib_buffer.data - saved by ip*_local nodes */ - i32 start_of_ip_header; }; } ip; diff --git a/src/vnet/dhcp/dhcp4_proxy_node.c b/src/vnet/dhcp/dhcp4_proxy_node.c index 26e1e65c..1b59cdea 100644 --- a/src/vnet/dhcp/dhcp4_proxy_node.c +++ b/src/vnet/dhcp/dhcp4_proxy_node.c @@ -231,7 +231,7 @@ dhcp_proxy_to_server_input (vlib_main_t * vm, o = (dhcp_option_t *) (((uword) o) + (o->length + 2)); } - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0)); // start write at (option*)o, some packets have padding if (((u8 *)o - (u8 *)b0->data + VPP_DHCP_OPTION82_SIZE) > fl->n_data_bytes) { diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c index 885313a5..e109cc4c 100644 --- a/src/vnet/dhcp/dhcp6_proxy_node.c +++ b/src/vnet/dhcp/dhcp6_proxy_node.c @@ -306,7 +306,7 @@ dhcpv6_proxy_to_server_input (vlib_main_t * vm, copy_ip6_address(&r1->link_addr, ia0); link_address_set: - fl = vlib_buffer_get_free_list (vm, b0->free_list_index); + fl = vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b0)); if ((b0->current_length+sizeof(*id1)+sizeof(*vss1)+sizeof(*cmac)) > fl->n_data_bytes) diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index dcc656a7..2fc5b804 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -344,8 +344,7 @@ ethernet_setup_node (vlib_main_t * vm, u32 node_index) always_inline ethernet_header_t * ethernet_buffer_get_header (vlib_buffer_t * b) { - return (void *) - (b->data + vnet_buffer (b)->ethernet.start_of_ethernet_header); + return (void *) (b->data + vnet_buffer (b)->l2_hdr_offset); } /** Returns the number of VLAN headers in the current Ethernet frame in the diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index d9fdff48..421d501a 100755 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -101,7 +101,7 @@ parse_header (ethernet_input_variant_t variant, e0 = (void *) (b0->data + b0->current_data); - vnet_buffer (b0)->ethernet.start_of_ethernet_header = b0->current_data; + vnet_buffer (b0)->l2_hdr_offset = b0->current_data; vlib_buffer_advance (b0, sizeof (e0[0])); @@ -205,9 +205,7 @@ identify_subint (vnet_hw_interface_t * hi, if (!(*is_l2)) { ethernet_header_t *e0; - e0 = - (void *) (b0->data + - vnet_buffer (b0)->ethernet.start_of_ethernet_header); + e0 = (void *) (b0->data + vnet_buffer (b0)->l2_hdr_offset); if (!(ethernet_address_cast (e0->dst_address))) { @@ -238,7 +236,7 @@ determine_next_node (ethernet_main_t * em, { *next0 = em->l2_next; // record the L2 len and reset the buffer so the L2 header is preserved - u32 eth_start = vnet_buffer (b0)->ethernet.start_of_ethernet_header; + u32 eth_start = vnet_buffer (b0)->l2_hdr_offset; vnet_buffer (b0)->l2.l2_len = b0->current_data - eth_start; ASSERT (vnet_buffer (b0)->l2.l2_len == ethernet_buffer_header_size (b0)); @@ -424,10 +422,8 @@ ethernet_input_inline (vlib_main_t * vm, cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2; } - vnet_buffer (b0)->ethernet.start_of_ethernet_header = - b0->current_data; - vnet_buffer (b1)->ethernet.start_of_ethernet_header = - b1->current_data; + vnet_buffer (b0)->l2_hdr_offset = b0->current_data; + vnet_buffer (b1)->l2_hdr_offset = b1->current_data; if (PREDICT_TRUE (is_l20 != 0)) { @@ -519,9 +515,9 @@ ethernet_input_inline (vlib_main_t * vm, { len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data - - vnet_buffer (b0)->ethernet.start_of_ethernet_header; + - vnet_buffer (b0)->l2_hdr_offset; len1 = vlib_buffer_length_in_chain (vm, b1) + b1->current_data - - vnet_buffer (b1)->ethernet.start_of_ethernet_header; + - vnet_buffer (b1)->l2_hdr_offset; stats_n_packets += 2; stats_n_bytes += len0 + len1; @@ -646,8 +642,7 @@ ethernet_input_inline (vlib_main_t * vm, cached_is_l2 = is_l20 = subint0->flags & SUBINT_CONFIG_L2; } - vnet_buffer (b0)->ethernet.start_of_ethernet_header = - b0->current_data; + vnet_buffer (b0)->l2_hdr_offset = b0->current_data; if (PREDICT_TRUE (is_l20 != 0)) { @@ -710,7 +705,7 @@ ethernet_input_inline (vlib_main_t * vm, { len0 = vlib_buffer_length_in_chain (vm, b0) + b0->current_data - - vnet_buffer (b0)->ethernet.start_of_ethernet_header; + - vnet_buffer (b0)->l2_hdr_offset; stats_n_packets += 1; stats_n_bytes += len0; diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c index 8263e01c..b8dfa847 100755 --- a/src/vnet/ip/ip4_forward.c +++ b/src/vnet/ip/ip4_forward.c @@ -1585,8 +1585,8 @@ ip4_local_inline (vlib_main_t * vm, ip0 = vlib_buffer_get_current (p0); ip1 = vlib_buffer_get_current (p1); - vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data; - vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; + vnet_buffer (p1)->l3_hdr_offset = p1->current_data; sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX]; sw_if_index1 = vnet_buffer (p1)->sw_if_index[VLIB_RX]; @@ -1788,7 +1788,7 @@ ip4_local_inline (vlib_main_t * vm, ip0 = vlib_buffer_get_current (p0); - vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX]; diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c index 4b574b9a..2b8c2bd2 100644 --- a/src/vnet/ip/ip6_forward.c +++ b/src/vnet/ip/ip6_forward.c @@ -1362,8 +1362,8 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip0 = vlib_buffer_get_current (p0); ip1 = vlib_buffer_get_current (p1); - vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data; - vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; + vnet_buffer (p1)->l3_hdr_offset = p1->current_data; type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol]; type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol]; @@ -1493,7 +1493,7 @@ ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) ip0 = vlib_buffer_get_current (p0); - vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data; + vnet_buffer (p0)->l3_hdr_offset = p0->current_data; type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol]; next0 = lm->local_next_by_ip_protocol[ip0->protocol]; diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index b8f6f9b1..68a8cbbc 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -1479,9 +1479,8 @@ icmp6_router_solicitation (vlib_main_t * vm, sizeof (icmp6_router_advertisement_header_t); vlib_buffer_add_data (vm, - p0->free_list_index, - bi0, - (void *) &rh, + vlib_buffer_get_free_list_index + (p0), bi0, (void *) &rh, sizeof (icmp6_router_advertisement_header_t)); @@ -1499,9 +1498,8 @@ icmp6_router_solicitation (vlib_main_t * vm, eth_if0->address, 6); vlib_buffer_add_data (vm, - p0->free_list_index, - bi0, - (void *) &h, + vlib_buffer_get_free_list_index + (p0), bi0, (void *) &h, sizeof (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t)); @@ -1525,9 +1523,8 @@ icmp6_router_solicitation (vlib_main_t * vm, sizeof (icmp6_neighbor_discovery_mtu_option_t); vlib_buffer_add_data (vm, - p0->free_list_index, - bi0, - (void *) &h, + vlib_buffer_get_free_list_index + (p0), bi0, (void *) &h, sizeof (icmp6_neighbor_discovery_mtu_option_t)); } @@ -1579,7 +1576,7 @@ icmp6_router_solicitation (vlib_main_t * vm, payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t); vlib_buffer_add_data (vm, - p0->free_list_index, + vlib_buffer_get_free_list_index (p0), bi0, (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t)); @@ -2326,7 +2323,7 @@ ip6_neighbor_send_mldpv2_report (u32 sw_if_index) num_addr_records++; vlib_buffer_add_data - (vm, b0->free_list_index, bo0, + (vm, vlib_buffer_get_free_list_index (b0), bo0, (void *)&rr, sizeof(icmp6_multicast_address_record_t)); payload_length += sizeof( icmp6_multicast_address_record_t); diff --git a/src/vnet/l2/l2_bvi.h b/src/vnet/l2/l2_bvi.h index e21a1616..662ec402 100644 --- a/src/vnet/l2/l2_bvi.h +++ b/src/vnet/l2/l2_bvi.h @@ -57,7 +57,7 @@ l2_to_bvi (vlib_main_t * vlib_main, } /* Save L2 header position which may be changed due to packet replication */ - vnet_buffer (b0)->ethernet.start_of_ethernet_header = b0->current_data; + vnet_buffer (b0)->l2_hdr_offset = b0->current_data; /* Strip L2 header */ l2_len = vnet_buffer (b0)->l2.l2_len; diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 22b5c82c..d8a1372d 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -3706,7 +3706,7 @@ send_map_reply (lisp_cp_main_t * lcm, u32 mi, ip_address_t * dst, static void find_ip_header (vlib_buffer_t * b, u8 ** ip_hdr) { - const i32 start = vnet_buffer (b)->ip.start_of_ip_header; + const i32 start = vnet_buffer (b)->l3_hdr_offset; if (start < 0 && start < -sizeof (b->pre_data)) { *ip_hdr = 0; diff --git a/src/vnet/replication.c b/src/vnet/replication.c index 1c6f28d2..0fdca0bf 100644 --- a/src/vnet/replication.c +++ b/src/vnet/replication.c @@ -43,12 +43,12 @@ replication_prep (vlib_main_t * vm, ctx_id = ctx - rm->contexts[thread_index]; /* Save state from vlib buffer */ - ctx->saved_free_list_index = b0->free_list_index; + ctx->saved_free_list_index = vlib_buffer_get_free_list_index (b0); ctx->current_data = b0->current_data; /* Set up vlib buffer hooks */ b0->recycle_count = ctx_id; - b0->free_list_index = rm->recycle_list_index; + vlib_buffer_set_free_list_index (b0, rm->recycle_list_index); b0->flags |= VLIB_BUFFER_RECYCLE; /* Save feature state */ @@ -129,7 +129,7 @@ replication_recycle (vlib_main_t * vm, vlib_buffer_t * b0, u32 is_last) * This is the last replication in the list. * Restore original buffer free functionality. */ - b0->free_list_index = ctx->saved_free_list_index; + vlib_buffer_set_free_list_index (b0, ctx->saved_free_list_index); b0->flags &= ~VLIB_BUFFER_RECYCLE; /* Free context back to its pool */ -- cgit 1.2.3-korg From 908a5ea6e247b4a15f0ec7e8ee8ebff799abdc4f Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Fri, 14 Jul 2017 12:42:21 -0400 Subject: Add a bihash prefetchable bucket-level cache According to Maciek, the easiest way to leverage the csit "performance trend" job is to actually merge the patch once verified. Manual testing indicates that the patch improves l2 path performance. Other use-cases are TBD. It's possible that we'll need to back out the patch depending on what happens. Change-Id: Ic0a0363de35ef9be953ad7709c57c3936b73fd5a Signed-off-by: Dave Barach --- src/vnet/fib/ip6_fib.c | 4 +- src/vnet/fib/ip6_fib.h | 2 +- src/vnet/l2/l2_fib.c | 8 +- src/vppinfra.am | 2 + src/vppinfra/bihash_16_8.h | 3 + src/vppinfra/bihash_24_8.h | 3 + src/vppinfra/bihash_48_8.h | 3 + src/vppinfra/bihash_8_8.h | 3 + src/vppinfra/bihash_template.c | 78 ++++++++++++-- src/vppinfra/bihash_template.h | 206 ++++++++++++++++++++++++++++++++---- src/vppinfra/test_bihash_template.c | 61 +++++++++-- 11 files changed, 329 insertions(+), 44 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/fib/ip6_fib.c b/src/vnet/fib/ip6_fib.c index 527f9114..8fde6f9f 100644 --- a/src/vnet/fib/ip6_fib.c +++ b/src/vnet/fib/ip6_fib.c @@ -200,7 +200,7 @@ ip6_fib_table_lookup (u32 fib_index, const ip6_address_t *addr, u32 len) { - const ip6_fib_table_instance_t *table; + ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv, value; int i, n_p, rv; u64 fib; @@ -246,7 +246,7 @@ ip6_fib_table_lookup_exact_match (u32 fib_index, const ip6_address_t *addr, u32 len) { - const ip6_fib_table_instance_t *table; + ip6_fib_table_instance_t *table; BVT(clib_bihash_kv) kv, value; ip6_address_t *mask; u64 fib; diff --git a/src/vnet/fib/ip6_fib.h b/src/vnet/fib/ip6_fib.h index 9789da4f..aad8305c 100644 --- a/src/vnet/fib/ip6_fib.h +++ b/src/vnet/fib/ip6_fib.h @@ -68,7 +68,7 @@ ip6_fib_table_fwding_lookup (ip6_main_t * im, u32 fib_index, const ip6_address_t * dst) { - const ip6_fib_table_instance_t *table; + ip6_fib_table_instance_t *table; int i, len; int rv; BVT(clib_bihash_kv) kv, value; diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 4ed16987..7e59b098 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -66,7 +66,7 @@ l2fib_table_dump (u32 bd_index, l2fib_entry_key_t ** l2fe_key, { l2fib_main_t *msm = &l2fib_main; BVT (clib_bihash) * h = &msm->mac_table; - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; BVT (clib_bihash_value) * v; l2fib_entry_key_t key; l2fib_entry_result_t result; @@ -108,7 +108,7 @@ show_l2fib (vlib_main_t * vm, l2fib_main_t *msm = &l2fib_main; l2_bridge_domain_t *bd_config; BVT (clib_bihash) * h = &msm->mac_table; - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; BVT (clib_bihash_value) * v; l2fib_entry_key_t key; l2fib_entry_result_t result; @@ -961,7 +961,7 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (i < (h->nbuckets - 3)) { - clib_bihash_bucket_t *b = &h->buckets[i + 3]; + BVT (clib_bihash_bucket) * b = &h->buckets[i + 3]; CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); b = &h->buckets[i + 1]; if (b->offset) @@ -972,7 +972,7 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, } } - clib_bihash_bucket_t *b = &h->buckets[i]; + BVT (clib_bihash_bucket) * b = &h->buckets[i]; if (b->offset == 0) continue; BVT (clib_bihash_value) * v = diff --git a/src/vppinfra.am b/src/vppinfra.am index 785445a6..533bacd6 100644 --- a/src/vppinfra.am +++ b/src/vppinfra.am @@ -42,6 +42,8 @@ TESTS += test_bihash_template \ test_zvec endif +TESTS += test_bihash_template + noinst_PROGRAMS = $(TESTS) check_PROGRAMS = $(TESTS) diff --git a/src/vppinfra/bihash_16_8.h b/src/vppinfra/bihash_16_8.h index 6b1b563e..361665be 100644 --- a/src/vppinfra/bihash_16_8.h +++ b/src/vppinfra/bihash_16_8.h @@ -13,9 +13,12 @@ * limitations under the License. */ #undef BIHASH_TYPE +#undef BIHASH_KVP_CACHE_SIZE +#undef BIHASH_KVP_PER_PAGE #define BIHASH_TYPE _16_8 #define BIHASH_KVP_PER_PAGE 4 +#define BIHASH_KVP_CACHE_SIZE 5 #ifndef __included_bihash_16_8_h__ #define __included_bihash_16_8_h__ diff --git a/src/vppinfra/bihash_24_8.h b/src/vppinfra/bihash_24_8.h index db77daa4..d0be028c 100644 --- a/src/vppinfra/bihash_24_8.h +++ b/src/vppinfra/bihash_24_8.h @@ -13,9 +13,12 @@ * limitations under the License. */ #undef BIHASH_TYPE +#undef BIHASH_KVP_CACHE_SIZE +#undef BIHASH_KVP_PER_PAGE #define BIHASH_TYPE _24_8 #define BIHASH_KVP_PER_PAGE 4 +#define BIHASH_KVP_CACHE_SIZE 3 #ifndef __included_bihash_24_8_h__ #define __included_bihash_24_8_h__ diff --git a/src/vppinfra/bihash_48_8.h b/src/vppinfra/bihash_48_8.h index 48079e0a..107bcace 100644 --- a/src/vppinfra/bihash_48_8.h +++ b/src/vppinfra/bihash_48_8.h @@ -14,9 +14,12 @@ */ #undef BIHASH_TYPE +#undef BIHASH_KVP_CACHE_SIZE +#undef BIHASH_KVP_PER_PAGE #define BIHASH_TYPE _48_8 #define BIHASH_KVP_PER_PAGE 4 +#define BIHASH_KVP_CACHE_SIZE 2 #ifndef __included_bihash_48_8_h__ #define __included_bihash_48_8_h__ diff --git a/src/vppinfra/bihash_8_8.h b/src/vppinfra/bihash_8_8.h index 68049351..f81002d6 100644 --- a/src/vppinfra/bihash_8_8.h +++ b/src/vppinfra/bihash_8_8.h @@ -13,9 +13,12 @@ * limitations under the License. */ #undef BIHASH_TYPE +#undef BIHASH_KVP_CACHE_SIZE +#undef BIHASH_KVP_PER_PAGE #define BIHASH_TYPE _8_8 #define BIHASH_KVP_PER_PAGE 4 +#define BIHASH_KVP_CACHE_SIZE 5 #ifndef __included_bihash_8_8_h__ #define __included_bihash_8_8_h__ diff --git a/src/vppinfra/bihash_template.c b/src/vppinfra/bihash_template.c index 004e8a9a..e3a5759d 100644 --- a/src/vppinfra/bihash_template.c +++ b/src/vppinfra/bihash_template.c @@ -19,12 +19,15 @@ void BV (clib_bihash_init) (BVT (clib_bihash) * h, char *name, u32 nbuckets, uword memory_size) { void *oldheap; + int i; nbuckets = 1 << (max_log2 (nbuckets)); h->name = (u8 *) name; h->nbuckets = nbuckets; h->log2_nbuckets = max_log2 (nbuckets); + h->cache_hits = 0; + h->cache_misses = 0; h->mheap = mheap_alloc (0 /* use VM */ , memory_size); @@ -33,6 +36,9 @@ void BV (clib_bihash_init) h->writer_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES); + for (i = 0; i < nbuckets; i++) + BV (clib_bihash_reset_cache) (h->buckets + i); + clib_mem_set_heap (oldheap); } @@ -87,10 +93,10 @@ BV (value_free) (BVT (clib_bihash) * h, BVT (clib_bihash_value) * v, } static inline void -BV (make_working_copy) (BVT (clib_bihash) * h, clib_bihash_bucket_t * b) +BV (make_working_copy) (BVT (clib_bihash) * h, BVT (clib_bihash_bucket) * b) { BVT (clib_bihash_value) * v; - clib_bihash_bucket_t working_bucket __attribute__ ((aligned (8))); + BVT (clib_bihash_bucket) working_bucket __attribute__ ((aligned (8))); void *oldheap; BVT (clib_bihash_value) * working_copy; u32 thread_index = os_get_thread_index (); @@ -129,6 +135,9 @@ BV (make_working_copy) (BVT (clib_bihash) * h, clib_bihash_bucket_t * b) clib_mem_set_heap (oldheap); + /* Turn off the cache */ + BV (clib_bihash_cache_enable_disable) (b, 0); + v = BV (clib_bihash_get_value) (h, b->offset); clib_memcpy (working_copy, v, sizeof (*v) * (1 << b->log2_pages)); @@ -235,7 +244,7 @@ int BV (clib_bihash_add_del) (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * add_v, int is_add) { u32 bucket_index; - clib_bihash_bucket_t *b, tmp_b; + BVT (clib_bihash_bucket) * b, tmp_b; BVT (clib_bihash_value) * v, *new_v, *save_new_v, *working_copy; int rv = 0; int i, limit; @@ -276,6 +285,7 @@ int BV (clib_bihash_add_del) goto unlock; } + /* Note: this leaves the cache disabled */ BV (make_working_copy) (h, b); v = BV (clib_bihash_get_value) (h, h->saved_bucket.offset); @@ -405,19 +415,22 @@ expand_ok: BV (value_free) (h, v, old_log2_pages); unlock: + BV (clib_bihash_reset_cache) (b); + BV (clib_bihash_cache_enable_disable) (b, 1 /* enable */ ); CLIB_MEMORY_BARRIER (); h->writer_lock[0] = 0; return rv; } int BV (clib_bihash_search) - (const BVT (clib_bihash) * h, + (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep) { u64 hash; u32 bucket_index; BVT (clib_bihash_value) * v; - clib_bihash_bucket_t *b; + BVT (clib_bihash_kv) * kvp; + BVT (clib_bihash_bucket) * b; int i, limit; ASSERT (valuep); @@ -430,6 +443,22 @@ int BV (clib_bihash_search) if (b->offset == 0) return -1; + /* Check the cache, if currently enabled */ + if (PREDICT_TRUE (b->cache_lru & (1 << 15))) + { + limit = BIHASH_KVP_CACHE_SIZE; + kvp = b->cache; + for (i = 0; i < limit; i++) + { + if (BV (clib_bihash_key_compare) (kvp[i].key, search_key->key)) + { + *valuep = kvp[i]; + h->cache_hits++; + return 0; + } + } + } + hash >>= h->log2_nbuckets; v = BV (clib_bihash_get_value) (h, b->offset); @@ -442,18 +471,50 @@ int BV (clib_bihash_search) { if (BV (clib_bihash_key_compare) (v->kvp[i].key, search_key->key)) { + u8 cache_slot; *valuep = v->kvp[i]; + + /* Shut off the cache */ + BV (clib_bihash_cache_enable_disable) (b, 0); + CLIB_MEMORY_BARRIER (); + + cache_slot = BV (clib_bihash_get_lru) (b); + b->cache[cache_slot] = v->kvp[i]; + BV (clib_bihash_update_lru) (b, cache_slot); + + /* Reenable the cache */ + BV (clib_bihash_cache_enable_disable) (b, 1); + h->cache_misses++; return 0; } } return -1; } +u8 *BV (format_bihash_lru) (u8 * s, va_list * args) +{ + int i; + BVT (clib_bihash_bucket) * b = va_arg (*args, BVT (clib_bihash_bucket) *); + u16 cache_lru = b->cache_lru; + + s = format (s, "cache %s, order ", cache_lru & (1 << 15) ? "on" : "off"); + + for (i = 0; i < BIHASH_KVP_CACHE_SIZE; i++) + s = format (s, "[%d] ", ((cache_lru >> (3 * i)) & 7)); + return (s); +} + +void +BV (clib_bihash_update_lru_not_inline) (BVT (clib_bihash_bucket) * b, u8 slot) +{ + BV (clib_bihash_update_lru) (b, slot); +} + u8 *BV (format_bihash) (u8 * s, va_list * args) { BVT (clib_bihash) * h = va_arg (*args, BVT (clib_bihash) *); int verbose = va_arg (*args, int); - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; BVT (clib_bihash_value) * v; int i, j, k; u64 active_elements = 0; @@ -503,7 +564,8 @@ u8 *BV (format_bihash) (u8 * s, va_list * args) s = format (s, " %lld active elements\n", active_elements); s = format (s, " %d free lists\n", vec_len (h->freelists)); s = format (s, " %d linear search buckets\n", h->linear_buckets); - + s = format (s, " %lld cache hits, %lld cache misses\n", + h->cache_hits, h->cache_misses); return s; } @@ -511,7 +573,7 @@ void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h, void *callback, void *arg) { int i, j, k; - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; BVT (clib_bihash_value) * v; void (*fp) (BVT (clib_bihash_kv) *, void *) = callback; diff --git a/src/vppinfra/bihash_template.h b/src/vppinfra/bihash_template.h index 4ea14ff0..feb6fb68 100644 --- a/src/vppinfra/bihash_template.h +++ b/src/vppinfra/bihash_template.h @@ -48,12 +48,10 @@ typedef struct BV (clib_bihash_value) }; } BVT (clib_bihash_value); -/* - * This is shared across all uses of the template, so it needs - * a "personal" #include recursion block - */ -#ifndef __defined_clib_bihash_bucket_t__ -#define __defined_clib_bihash_bucket_t__ +#if BIHASH_KVP_CACHE_SIZE > 5 +#error Requested KVP cache LRU data exceeds 16 bits +#endif + typedef struct { union @@ -62,36 +60,139 @@ typedef struct { u32 offset; u8 linear_search; - u8 pad[2]; u8 log2_pages; + u16 cache_lru; }; u64 as_u64; }; -} clib_bihash_bucket_t; -#endif /* __defined_clib_bihash_bucket_t__ */ + BVT (clib_bihash_kv) cache[BIHASH_KVP_CACHE_SIZE]; +} BVT (clib_bihash_bucket); typedef struct { BVT (clib_bihash_value) * values; - clib_bihash_bucket_t *buckets; + BVT (clib_bihash_bucket) * buckets; volatile u32 *writer_lock; BVT (clib_bihash_value) ** working_copies; int *working_copy_lengths; - clib_bihash_bucket_t saved_bucket; + BVT (clib_bihash_bucket) saved_bucket; u32 nbuckets; u32 log2_nbuckets; u32 linear_buckets; u8 *name; + u64 cache_hits; + u64 cache_misses; + BVT (clib_bihash_value) ** freelists; void *mheap; } BVT (clib_bihash); -static inline void *BV (clib_bihash_get_value) (const BVT (clib_bihash) * h, +static inline void +BV (clib_bihash_update_lru) (BVT (clib_bihash_bucket) * b, u8 slot) +{ + u16 value, tmp, mask; + u8 found_lru_pos; + u16 save_hi; + + if (BIHASH_KVP_CACHE_SIZE < 2) + return; + + ASSERT (slot < BIHASH_KVP_CACHE_SIZE); + + /* First, find the slot in cache_lru */ + mask = slot; + if (BIHASH_KVP_CACHE_SIZE > 1) + mask |= slot << 3; + if (BIHASH_KVP_CACHE_SIZE > 2) + mask |= slot << 6; + if (BIHASH_KVP_CACHE_SIZE > 3) + mask |= slot << 9; + if (BIHASH_KVP_CACHE_SIZE > 4) + mask |= slot << 12; + + value = b->cache_lru; + tmp = value ^ mask; + + /* Already the most-recently used? */ + if ((tmp & 7) == 0) + return; + + found_lru_pos = ((tmp & (7 << 3)) == 0) ? 1 : 0; + if (BIHASH_KVP_CACHE_SIZE > 2) + found_lru_pos = ((tmp & (7 << 6)) == 0) ? 2 : found_lru_pos; + if (BIHASH_KVP_CACHE_SIZE > 3) + found_lru_pos = ((tmp & (7 << 9)) == 0) ? 3 : found_lru_pos; + if (BIHASH_KVP_CACHE_SIZE > 4) + found_lru_pos = ((tmp & (7 << 12)) == 0) ? 4 : found_lru_pos; + + ASSERT (found_lru_pos); + + /* create a mask to kill bits in or above slot */ + mask = 0xFFFF << found_lru_pos; + mask <<= found_lru_pos; + mask <<= found_lru_pos; + mask ^= 0xFFFF; + tmp = value & mask; + + /* Save bits above slot */ + mask ^= 0xFFFF; + mask <<= 3; + save_hi = value & mask; + + value = save_hi | (tmp << 3) | slot; + + b->cache_lru = value; +} + +void +BV (clib_bihash_update_lru_not_inline) (BVT (clib_bihash_bucket) * b, + u8 slot); + +static inline u8 BV (clib_bihash_get_lru) (BVT (clib_bihash_bucket) * b) +{ + return (b->cache_lru >> (3 * (BIHASH_KVP_CACHE_SIZE - 1))) & 7; +} + +static inline void BV (clib_bihash_reset_cache) (BVT (clib_bihash_bucket) * b) +{ + u16 initial_lru_value; + + memset (b->cache, 0xff, sizeof (b->cache)); + + /* + * We'll want the cache to be loaded from slot 0 -> slot N, so + * the initial LRU order is reverse index order. + */ + if (BIHASH_KVP_CACHE_SIZE == 1) + initial_lru_value = 0; + else if (BIHASH_KVP_CACHE_SIZE == 2) + initial_lru_value = (0 << 3) | (1 << 0); + else if (BIHASH_KVP_CACHE_SIZE == 3) + initial_lru_value = (0 << 6) | (1 << 3) | (2 << 0); + else if (BIHASH_KVP_CACHE_SIZE == 4) + initial_lru_value = (0 << 9) | (1 << 6) | (2 << 3) | (3 << 0); + else if (BIHASH_KVP_CACHE_SIZE == 5) + initial_lru_value = (0 << 12) | (1 << 9) | (2 << 6) | (3 << 3) | (4 << 0); + + b->cache_lru = initial_lru_value; +} + +static inline void BV (clib_bihash_cache_enable_disable) + (BVT (clib_bihash_bucket) * b, u8 enable) +{ + BVT (clib_bihash_bucket) tmp_b; + tmp_b.as_u64 = b->as_u64; + tmp_b.cache_lru &= 0x7FFF; + tmp_b.cache_lru |= enable << 15; + b->as_u64 = tmp_b.as_u64; +} + +static inline void *BV (clib_bihash_get_value) (BVT (clib_bihash) * h, uword offset) { u8 *hp = h->mheap; @@ -100,7 +201,7 @@ static inline void *BV (clib_bihash_get_value) (const BVT (clib_bihash) * h, return (void *) vp; } -static inline uword BV (clib_bihash_get_offset) (const BVT (clib_bihash) * h, +static inline uword BV (clib_bihash_get_offset) (BVT (clib_bihash) * h, void *v) { u8 *hp, *vp; @@ -119,7 +220,7 @@ void BV (clib_bihash_free) (BVT (clib_bihash) * h); int BV (clib_bihash_add_del) (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * add_v, int is_add); -int BV (clib_bihash_search) (const BVT (clib_bihash) * h, +int BV (clib_bihash_search) (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * search_v, BVT (clib_bihash_kv) * return_v); @@ -128,18 +229,19 @@ void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h, format_function_t BV (format_bihash); format_function_t BV (format_bihash_kvp); - +format_function_t BV (format_bihash_lru); static inline int BV (clib_bihash_search_inline) - (const BVT (clib_bihash) * h, BVT (clib_bihash_kv) * kvp) + (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * key_result) { u64 hash; u32 bucket_index; BVT (clib_bihash_value) * v; - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; + BVT (clib_bihash_kv) * kvp; int i, limit; - hash = BV (clib_bihash_hash) (kvp); + hash = BV (clib_bihash_hash) (key_result); bucket_index = hash & (h->nbuckets - 1); b = &h->buckets[bucket_index]; @@ -147,6 +249,22 @@ static inline int BV (clib_bihash_search_inline) if (b->offset == 0) return -1; + /* Check the cache, if currently enabled */ + if (PREDICT_TRUE (b->cache_lru & (1 << 15))) + { + limit = BIHASH_KVP_CACHE_SIZE; + kvp = b->cache; + for (i = 0; i < limit; i++) + { + if (BV (clib_bihash_key_compare) (kvp[i].key, key_result->key)) + { + *key_result = kvp[i]; + h->cache_hits++; + return 0; + } + } + } + hash >>= h->log2_nbuckets; v = BV (clib_bihash_get_value) (h, b->offset); @@ -159,9 +277,22 @@ static inline int BV (clib_bihash_search_inline) for (i = 0; i < limit; i++) { - if (BV (clib_bihash_key_compare) (v->kvp[i].key, kvp->key)) + if (BV (clib_bihash_key_compare) (v->kvp[i].key, key_result->key)) { - *kvp = v->kvp[i]; + u8 cache_slot; + *key_result = v->kvp[i]; + + /* Shut off the cache */ + BV (clib_bihash_cache_enable_disable) (b, 0); + CLIB_MEMORY_BARRIER (); + + cache_slot = BV (clib_bihash_get_lru) (b); + b->cache[cache_slot] = v->kvp[i]; + BV (clib_bihash_update_lru) (b, cache_slot); + + /* Reenable the cache */ + BV (clib_bihash_cache_enable_disable) (b, 1); + h->cache_misses++; return 0; } } @@ -169,13 +300,14 @@ static inline int BV (clib_bihash_search_inline) } static inline int BV (clib_bihash_search_inline_2) - (const BVT (clib_bihash) * h, + (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep) { u64 hash; u32 bucket_index; BVT (clib_bihash_value) * v; - clib_bihash_bucket_t *b; + BVT (clib_bihash_bucket) * b; + BVT (clib_bihash_kv) * kvp; int i, limit; ASSERT (valuep); @@ -188,6 +320,22 @@ static inline int BV (clib_bihash_search_inline_2) if (b->offset == 0) return -1; + /* Check the cache, if currently enabled */ + if (PREDICT_TRUE (b->cache_lru & (1 << 15))) + { + limit = BIHASH_KVP_CACHE_SIZE; + kvp = b->cache; + for (i = 0; i < limit; i++) + { + if (BV (clib_bihash_key_compare) (kvp[i].key, search_key->key)) + { + *valuep = kvp[i]; + h->cache_hits++; + return 0; + } + } + } + hash >>= h->log2_nbuckets; v = BV (clib_bihash_get_value) (h, b->offset); @@ -201,14 +349,26 @@ static inline int BV (clib_bihash_search_inline_2) { if (BV (clib_bihash_key_compare) (v->kvp[i].key, search_key->key)) { + u8 cache_slot; *valuep = v->kvp[i]; + + /* Shut off the cache */ + BV (clib_bihash_cache_enable_disable) (b, 0); + CLIB_MEMORY_BARRIER (); + + cache_slot = BV (clib_bihash_get_lru) (b); + b->cache[cache_slot] = v->kvp[i]; + BV (clib_bihash_update_lru) (b, cache_slot); + + /* Reenable the cache */ + BV (clib_bihash_cache_enable_disable) (b, 1); + h->cache_misses++; return 0; } } return -1; } - #endif /* __included_bihash_template_h__ */ /** @endcond */ diff --git a/src/vppinfra/test_bihash_template.c b/src/vppinfra/test_bihash_template.c index 1e262430..589c815d 100644 --- a/src/vppinfra/test_bihash_template.c +++ b/src/vppinfra/test_bihash_template.c @@ -236,12 +236,45 @@ test_bihash (test_main_t * tm) return 0; } +clib_error_t * +test_bihash_cache (test_main_t * tm) +{ + u32 lru; + BVT (clib_bihash_bucket) _b, *b = &_b; + + BV (clib_bihash_reset_cache) (b); + + fformat (stdout, "Initial LRU config: %U\n", BV (format_bihash_lru), b); + + BV (clib_bihash_update_lru_not_inline) (b, 3); + + fformat (stdout, "use slot 3, LRU config: %U\n", BV (format_bihash_lru), b); + + BV (clib_bihash_update_lru) (b, 1); + + fformat (stdout, "use slot 1 LRU config: %U\n", BV (format_bihash_lru), b); + + lru = BV (clib_bihash_get_lru) (b); + + fformat (stdout, "least-recently-used is %d\n", lru); + + BV (clib_bihash_update_lru) (b, 4); + + fformat (stdout, "use slot 4 LRU config: %U\n", BV (format_bihash_lru), b); + + lru = BV (clib_bihash_get_lru) (b); + + fformat (stdout, "least-recently-used is %d\n", lru); + + return 0; +} + clib_error_t * test_bihash_main (test_main_t * tm) { unformat_input_t *i = tm->input; clib_error_t *error; - int test_vec64 = 0; + int which = 0; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { @@ -261,7 +294,10 @@ test_bihash_main (test_main_t * tm) else if (unformat (i, "search %d", &tm->search_iter)) ; else if (unformat (i, "vec64")) - test_vec64 = 1; + which = 1; + else if (unformat (i, "cache")) + which = 2; + else if (unformat (i, "verbose")) tm->verbose = 1; else @@ -269,10 +305,23 @@ test_bihash_main (test_main_t * tm) format_unformat_error, i); } - if (test_vec64) - error = test_bihash_vec64 (tm); - else - error = test_bihash (tm); + switch (which) + { + case 0: + error = test_bihash (tm); + break; + + case 1: + error = test_bihash_vec64 (tm); + break; + + case 2: + error = test_bihash_cache (tm); + break; + + default: + return clib_error_return (0, "no such test?"); + } return error; } -- cgit 1.2.3-korg From b12ac56c44f4f6d4d5e3bc37bba39b19bc6b2551 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Tue, 18 Jul 2017 13:25:19 +0300 Subject: L2FWD:move vec_validate out of access function Change-Id: Id9737b6aa2b6fe3032f4627dfdbd2ea728cc3fb1 Signed-off-by: Eyal Bari --- src/vnet/l2/l2_fib.h | 9 ++++++++- src/vnet/l2/l2_input.c | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 21dcc451..ee6f0dc5 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -383,10 +383,17 @@ static_always_inline u8 * l2fib_swif_seq_num (u32 sw_if_index) { l2fib_main_t *mp = &l2fib_main; - vec_validate (mp->swif_seq_num, sw_if_index); return vec_elt_at_index (mp->swif_seq_num, sw_if_index); } +static_always_inline u8 * +l2fib_valid_swif_seq_num (u32 sw_if_index) +{ + l2fib_main_t *mp = &l2fib_main; + vec_validate (mp->swif_seq_num, sw_if_index); + return l2fib_swif_seq_num (sw_if_index); +} + BVT (clib_bihash) * get_mac_table (void); #endif diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 9a3148c5..aa156213 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -618,7 +618,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ config->xconnect = 0; config->bridge = 1; config->bd_index = bd_index; - *l2fib_swif_seq_num (sw_if_index) += 1; + *l2fib_valid_swif_seq_num (sw_if_index) += 1; /* * Enable forwarding, flooding, learning and ARP termination by default -- cgit 1.2.3-korg From beb0b2e346c63e21ffe892ae0e04b67bb10fba5e Mon Sep 17 00:00:00 2001 From: John Lo Date: Sat, 22 Jul 2017 00:21:36 -0400 Subject: Improve L2 Input/Output Feature Infrastructure and Usage Simplify L2 output feature infra to unify with L2 input feature infra using the newly improved feature bitmap mechanism. Updated all L2 features to use the more efficient infra functions. Change-Id: If8f463826b0af0717129befe92a27ea8cfc40449 Signed-off-by: John Lo --- src/plugins/acl/fa_node.c | 7 +-- src/vnet/ethernet/arp.c | 8 +-- src/vnet/l2/feat_bitmap.h | 18 +++++- src/vnet/l2/l2_classify.h | 8 +-- src/vnet/l2/l2_efp_filter.c | 54 +++--------------- src/vnet/l2/l2_input.c | 37 ++++++------- src/vnet/l2/l2_input_acl.c | 9 +-- src/vnet/l2/l2_input_classify.c | 22 +++----- src/vnet/l2/l2_input_vtr.c | 35 ++---------- src/vnet/l2/l2_learn.c | 14 +---- src/vnet/l2/l2_output.c | 115 +++++++++++++++++++++++---------------- src/vnet/l2/l2_output.h | 80 +-------------------------- src/vnet/l2/l2_output_acl.c | 24 ++------ src/vnet/l2/l2_output_classify.c | 30 +++------- src/vnet/l2/l2_rw.c | 27 +++------ src/vnet/policer/node_funcs.c | 11 +--- 16 files changed, 160 insertions(+), 339 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/plugins/acl/fa_node.c b/src/plugins/acl/fa_node.c index 0bbc7423..c483044d 100644 --- a/src/plugins/acl/fa_node.c +++ b/src/plugins/acl/fa_node.c @@ -931,7 +931,6 @@ acl_fa_node_fn (vlib_main_t * vm, u32 pkts_acl_permit = 0; u32 pkts_restart_session_timer = 0; u32 trace_bitmap = 0; - u32 feature_bitmap0; acl_main_t *am = &acl_main; fa_5tuple_t fa_5tuple, kv_sess; clib_bihash_kv_40_8_t value_sess; @@ -977,8 +976,6 @@ acl_fa_node_fn (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; else sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - if (is_l2_path) - feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap; /* * Extract the L3/L4 matching info into a 5-tuple structure, @@ -1089,9 +1086,7 @@ acl_fa_node_fn (vlib_main_t * vm, if (action > 0) { if (is_l2_path) - next0 = - feat_bitmap_get_next_node_index (l2_feat_next_node_index, - feature_bitmap0); + next0 = vnet_l2_feature_next (b0, l2_feat_next_node_index, 0); else vnet_feature_next (sw_if_index0, &next0, b0); } diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c index df681750..1bce3328 100644 --- a/src/vnet/ethernet/arp.c +++ b/src/vnet/ethernet/arp.c @@ -2291,12 +2291,8 @@ arp_term_l2bd (vlib_main_t * vm, next_l2_feature: { - u32 feature_bitmap0 = - vnet_buffer (p0)->l2.feature_bitmap & ~L2INPUT_FEAT_ARP_TERM; - vnet_buffer (p0)->l2.feature_bitmap = feature_bitmap0; - next0 = - feat_bitmap_get_next_node_index (arp_term_next_node_index, - feature_bitmap0); + next0 = vnet_l2_feature_next (p0, arp_term_next_node_index, + L2INPUT_FEAT_ARP_TERM); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); diff --git a/src/vnet/l2/feat_bitmap.h b/src/vnet/l2/feat_bitmap.h index c6e02ecc..5940ff7e 100644 --- a/src/vnet/l2/feat_bitmap.h +++ b/src/vnet/l2/feat_bitmap.h @@ -75,8 +75,8 @@ feat_bitmap_init_next_nodes (vlib_main_t * vm, u32 node_index, /* the current gr Return the graph node index for the feature corresponding to the first set bit in the bitmap. */ -always_inline - u32 feat_bitmap_get_next_node_index (u32 * next_nodes, u32 bitmap) +always_inline u32 +feat_bitmap_get_next_node_index (u32 * next_nodes, u32 bitmap) { u32 first_bit; @@ -85,6 +85,20 @@ always_inline return next_nodes[first_bit]; } +/** + Return the graph node index for the feature corresponding to the next + set bit after clearing the current feature bit in the feature_bitmap + of the current packet. +*/ +always_inline u32 +vnet_l2_feature_next (vlib_buffer_t * b, u32 * next_nodes, u32 feat_bit) +{ + vnet_buffer (b)->l2.feature_bitmap &= ~feat_bit; + u32 fb = vnet_buffer (b)->l2.feature_bitmap; + ASSERT (fb != 0); + return feat_bitmap_get_next_node_index (next_nodes, fb); +} + #endif /* included_vnet_l2_feat_bitmap_h */ /* diff --git a/src/vnet/l2/l2_classify.h b/src/vnet/l2/l2_classify.h index 184187ff..100c584a 100644 --- a/src/vnet/l2/l2_classify.h +++ b/src/vnet/l2/l2_classify.h @@ -68,15 +68,13 @@ typedef enum typedef struct _l2_classify_main { - /* Next nodes for each feature */ - u32 feat_next_node_index[32]; + /* Next nodes for L2 input and output features */ + u32 l2_inp_feat_next[32]; + u32 l2_out_feat_next[32]; /* Per-address-family classifier table vectors */ u32 *classify_table_index_by_sw_if_index[L2_INPUT_CLASSIFY_N_TABLES]; - /* Next nodes for features and output interfaces */ - l2_output_next_nodes_st next_nodes; - /* convenience variables */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; diff --git a/src/vnet/l2/l2_efp_filter.c b/src/vnet/l2/l2_efp_filter.c index f9ba8f2f..faf78153 100644 --- a/src/vnet/l2/l2_efp_filter.c +++ b/src/vnet/l2/l2_efp_filter.c @@ -43,9 +43,8 @@ */ typedef struct { - - /* Next nodes for features and output interfaces */ - l2_output_next_nodes_st next_nodes; + /* Next nodes for L2 output features */ + u32 l2_out_feat_next[32]; /* convenience variables */ vlib_main_t *vlib_main; @@ -180,11 +179,6 @@ l2_efp_filter_node_fn (vlib_main_t * vm, vlib_node_t *n = vlib_get_node (vm, l2_efp_filter_node.index); u32 node_counter_base_index = n->error_heap_index; vlib_error_main_t *em = &vm->error_main; - u32 cached_sw_if_index = ~0; - u32 cached_next_index = ~0; - - /* invalidate cache to begin with */ - cached_sw_if_index = ~0; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; /* number of packets to process */ @@ -203,7 +197,6 @@ l2_efp_filter_node_fn (vlib_main_t * vm, vlib_buffer_t *b0, *b1; u32 next0, next1; u32 sw_if_index0, sw_if_index1; - u32 feature_bitmap0, feature_bitmap1; u16 first_ethertype0, first_ethertype1; u16 outer_id0, inner_id0, outer_id1, inner_id1; u32 match_flags0, match_flags1; @@ -267,29 +260,11 @@ l2_efp_filter_node_fn (vlib_main_t * vm, em->counters[node_counter_base_index + L2_EFP_FILTER_ERROR_L2_EFP_FILTER] += 2; - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; - feature_bitmap1 = - vnet_buffer (b1)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; - /* Determine next node */ - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2_efp_filter_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2_efp_filter_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b1, sw_if_index1, feature_bitmap1, &next1); + next0 = vnet_l2_feature_next (b0, msm->l2_out_feat_next, + L2OUTPUT_FEAT_EFP_FILTER); + next1 = vnet_l2_feature_next (b1, msm->l2_out_feat_next, + L2OUTPUT_FEAT_EFP_FILTER); /* perform the efp filter check on two packets */ @@ -394,7 +369,6 @@ l2_efp_filter_node_fn (vlib_main_t * vm, vlib_buffer_t *b0; u32 next0; u32 sw_if_index0; - u32 feature_bitmap0; u16 first_ethertype0; u16 outer_id0, inner_id0; u32 match_flags0; @@ -422,19 +396,9 @@ l2_efp_filter_node_fn (vlib_main_t * vm, em->counters[node_counter_base_index + L2_EFP_FILTER_ERROR_L2_EFP_FILTER] += 1; - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_EFP_FILTER; - /* Determine next node */ - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2_efp_filter_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); + next0 = vnet_l2_feature_next (b0, msm->l2_out_feat_next, + L2OUTPUT_FEAT_EFP_FILTER); /* perform the efp filter check on one packet */ @@ -528,7 +492,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_efp_filter_node, l2_efp_filter_node_fn) l2_efp_filter_node.index, L2OUTPUT_N_FEAT, l2output_get_feat_names (), - mp->next_nodes.feat_next_node_index); + mp->l2_out_feat_next); return 0; } diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index aa156213..26c832ad 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -115,10 +115,7 @@ typedef enum static_always_inline void -classify_and_dispatch (vlib_main_t * vm, - vlib_node_runtime_t * node, - u32 thread_index, - l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) +classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) { /* * Load L2 input feature struct @@ -187,12 +184,7 @@ classify_and_dispatch (vlib_main_t * vm, } - if (config->xconnect) - { - /* Set the output interface */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = config->output_sw_if_index; - } - else + if (config->bridge) { /* Do bridge-domain processing */ bd_index0 = config->bd_index; @@ -220,6 +212,13 @@ classify_and_dispatch (vlib_main_t * vm, */ feat_mask = feat_mask & bd_config->feature_bitmap; } + else if (config->xconnect) + { + /* Set the output interface */ + vnet_buffer (b0)->sw_if_index[VLIB_TX] = config->output_sw_if_index; + } + else + feat_mask = L2INPUT_FEAT_DROP; /* mask out features from bitmap using packet type and bd config */ feature_bitmap = config->feature_bitmap & feat_mask; @@ -240,7 +239,6 @@ l2input_node_inline (vlib_main_t * vm, u32 n_left_from, *from, *to_next; l2input_next_t next_index; l2input_main_t *msm = &l2input_main; - u32 thread_index = vlib_get_thread_index (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; /* number of packets to process */ @@ -353,10 +351,10 @@ l2input_node_inline (vlib_main_t * vm, vlib_node_increment_counter (vm, l2input_node.index, L2INPUT_ERROR_L2INPUT, 4); - classify_and_dispatch (vm, node, thread_index, msm, b0, &next0); - classify_and_dispatch (vm, node, thread_index, msm, b1, &next1); - classify_and_dispatch (vm, node, thread_index, msm, b2, &next2); - classify_and_dispatch (vm, node, thread_index, msm, b3, &next3); + classify_and_dispatch (msm, b0, &next0); + classify_and_dispatch (msm, b1, &next1); + classify_and_dispatch (msm, b2, &next2); + classify_and_dispatch (msm, b3, &next3); /* verify speculative enqueues, maybe switch current next frame */ /* if next0==next1==next_index then nothing special needs to be done */ @@ -396,7 +394,7 @@ l2input_node_inline (vlib_main_t * vm, vlib_node_increment_counter (vm, l2input_node.index, L2INPUT_ERROR_L2INPUT, 1); - classify_and_dispatch (vm, node, thread_index, msm, b0, &next0); + classify_and_dispatch (msm, b0, &next0); /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, @@ -574,8 +572,8 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ } /* Make sure vector is big enough */ - vec_validate_init_empty (l2om->next_nodes.output_node_index_vec, - sw_if_index, L2OUTPUT_NEXT_DROP); + vec_validate_init_empty (l2om->output_node_index_vec, sw_if_index, + L2OUTPUT_NEXT_DROP); /* Initialize the l2-input configuration for the interface */ if (mode == MODE_L3) @@ -594,8 +592,7 @@ set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */ /* Make sure any L2-output packet to this interface now in L3 mode is * dropped. This may happen if L2 FIB MAC entry is stale */ - l2om->next_nodes.output_node_index_vec[sw_if_index] = - L2OUTPUT_NEXT_BAD_INTF; + l2om->output_node_index_vec[sw_if_index] = L2OUTPUT_NEXT_BAD_INTF; } else { diff --git a/src/vnet/l2/l2_input_acl.c b/src/vnet/l2/l2_input_acl.c index 104fcd15..84030888 100644 --- a/src/vnet/l2/l2_input_acl.c +++ b/src/vnet/l2/l2_input_acl.c @@ -269,14 +269,11 @@ l2_inacl_node_fn (vlib_main_t * vm, e0 = 0; t0 = 0; - /* Feature bitmap update */ - vnet_buffer (b0)->l2.feature_bitmap &= ~L2INPUT_FEAT_ACL; - vnet_buffer (b0)->l2_classify.opaque_index = ~0; + /* Determine the next node */ - next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, - vnet_buffer (b0)-> - l2.feature_bitmap); + next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index, + L2INPUT_FEAT_ACL); if (PREDICT_TRUE (table_index0 != ~0)) { diff --git a/src/vnet/l2/l2_input_classify.c b/src/vnet/l2/l2_input_classify.c index 485b9abd..ee8042a0 100644 --- a/src/vnet/l2/l2_input_classify.c +++ b/src/vnet/l2/l2_input_classify.c @@ -152,7 +152,6 @@ l2_input_classify_node_fn (vlib_main_t * vm, vnet_classify_main_t *vcm = cm->vnet_classify_main; l2_input_classify_runtime_t *rt = (l2_input_classify_runtime_t *) node->runtime_data; - u32 feature_bitmap; u32 hits = 0; u32 misses = 0; u32 chain_hits = 0; @@ -354,13 +353,6 @@ l2_input_classify_node_fn (vlib_main_t * vm, e0 = 0; vnet_buffer (b0)->l2_classify.opaque_index = ~0; - /* Remove ourself from the feature bitmap */ - feature_bitmap = vnet_buffer (b0)->l2.feature_bitmap - & ~L2INPUT_FEAT_INPUT_CLASSIFY; - - /* save for next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; - if (PREDICT_TRUE (table_index0 != ~0)) { hash0 = vnet_buffer (b0)->l2_classify.hash; @@ -412,13 +404,13 @@ l2_input_classify_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (next0 == 0)) b0->error = node->errors[L2_INPUT_CLASSIFY_ERROR_DROP]; + /* Determine the next node and remove ourself from bitmap */ if (PREDICT_TRUE (next0 == ~0)) - { - // Determine the next node - next0 = - feat_bitmap_get_next_node_index (cm->feat_next_node_index, - feature_bitmap); - } + next0 = vnet_l2_feature_next (b0, cm->l2_inp_feat_next, + L2INPUT_FEAT_INPUT_CLASSIFY); + else + vnet_buffer (b0)->l2.feature_bitmap &= + ~L2INPUT_FEAT_INPUT_CLASSIFY; if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) @@ -496,7 +488,7 @@ l2_input_classify_init (vlib_main_t * vm) l2_input_classify_node.index, L2INPUT_N_FEAT, l2input_get_feat_names (), - cm->feat_next_node_index); + cm->l2_inp_feat_next); rt->l2cm = cm; rt->vcm = cm->vnet_classify_main; diff --git a/src/vnet/l2/l2_input_vtr.c b/src/vnet/l2/l2_input_vtr.c index ded23095..9470752f 100644 --- a/src/vnet/l2/l2_input_vtr.c +++ b/src/vnet/l2/l2_input_vtr.c @@ -111,7 +111,6 @@ l2_invtr_node_fn (vlib_main_t * vm, vlib_buffer_t *b0, *b1; u32 next0, next1; u32 sw_if_index0, sw_if_index1; - u32 feature_bitmap0, feature_bitmap1; /* Prefetch next iteration. */ { @@ -160,23 +159,11 @@ l2_invtr_node_fn (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - /* process 2 packets */ - - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; - feature_bitmap1 = - vnet_buffer (b1)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; - - /* save for next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; - vnet_buffer (b1)->l2.feature_bitmap = feature_bitmap1; - /* Determine the next node */ - next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, - feature_bitmap0); - next1 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, - feature_bitmap1); + next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index, + L2INPUT_FEAT_VTR); + next1 = vnet_l2_feature_next (b1, msm->feat_next_node_index, + L2INPUT_FEAT_VTR); l2_output_config_t *config0; l2_output_config_t *config1; @@ -264,7 +251,6 @@ l2_invtr_node_fn (vlib_main_t * vm, vlib_buffer_t *b0; u32 next0; u32 sw_if_index0; - u32 feature_bitmap0; /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; @@ -278,18 +264,9 @@ l2_invtr_node_fn (vlib_main_t * vm, sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - /* process 1 packet */ - - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_VTR; - - /* save for next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; - /* Determine the next node */ - next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, - feature_bitmap0); + next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index, + L2INPUT_FEAT_VTR); l2_output_config_t *config0; config0 = vec_elt_at_index (l2output_main.configs, sw_if_index0); diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index b9904d3e..65406292 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -116,19 +116,9 @@ l2learn_process (vlib_node_runtime_t * node, u32 * bucket0, l2fib_entry_result_t * result0, u32 * next0, u8 timestamp) { - u32 feature_bitmap; - /* Set up the default next node (typically L2FWD) */ - - /* Remove ourself from the feature bitmap */ - feature_bitmap = vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_LEARN; - - /* Save for next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; - - /* Determine the next node */ - *next0 = feat_bitmap_get_next_node_index (msm->feat_next_node_index, - feature_bitmap); + *next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index, + L2INPUT_FEAT_LEARN); /* Check mac table lookup result */ if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index 51d5e145..b3537a35 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -98,6 +98,57 @@ split_horizon_violation (u8 shg1, u8 shg2) } } +/** Determine the next L2 node based on the output feature bitmap */ +static_always_inline void +l2_output_dispatch (vlib_buffer_t * b0, vlib_node_runtime_t * node, + u32 * cached_sw_if_index, u32 * cached_next_index, + u32 sw_if_index, u32 feature_bitmap, u32 * next0) +{ + /* + * The output feature bitmap always have at least the L2 output bit set + * for a normal L2 interface (or 0 if the interface is changed from L2 + * to L3 mode). So if the feature bitmap is 0 or just have L2 output bits set, + * we know there is no more feature and will just output packets on interface. + * Otherwise, get the index of the next feature node. + */ + if (PREDICT_FALSE ((feature_bitmap & ~L2OUTPUT_FEAT_OUTPUT) != 0)) + { + /* Save bitmap for the next feature graph nodes */ + vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; + + /* Determine the next node */ + *next0 = + feat_bitmap_get_next_node_index (l2output_main.l2_out_feat_next, + feature_bitmap); + } + else + { + /* + * There are no features. Send packet to TX node for sw_if_index0 + * This is a little tricky in that the output interface next node indexes + * are not precomputed at init time. + */ + + if (sw_if_index == *cached_sw_if_index) + { + /* We hit in the one-entry cache. Use it. */ + *next0 = *cached_next_index; + } + else + { + /* Look up the output TX node for the sw_if_index */ + *next0 = vec_elt (l2output_main.output_node_index_vec, sw_if_index); + + if (PREDICT_FALSE (*next0 == L2OUTPUT_NEXT_DROP)) + b0->error = node->errors[L2OUTPUT_ERROR_MAPPING_DROP]; + + /* Update the one-entry cache */ + *cached_sw_if_index = sw_if_index; + *cached_next_index = *next0; + } + } +} + static_always_inline void l2output_vtr (vlib_node_runtime_t * node, l2_output_config_t * config, u32 feature_bitmap, vlib_buffer_t * b, u32 * next) @@ -239,41 +290,18 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, feature_bitmap3 = config3->feature_bitmap; /* Determine next node */ - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2output_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); - - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2output_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b1, sw_if_index1, feature_bitmap1, &next1); - - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2output_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b2, sw_if_index2, feature_bitmap2, &next2); - - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2output_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b3, sw_if_index3, feature_bitmap3, &next3); + l2_output_dispatch (b0, node, &cached_sw_if_index, + &cached_next_index, sw_if_index0, + feature_bitmap0, &next0); + l2_output_dispatch (b1, node, &cached_sw_if_index, + &cached_next_index, sw_if_index1, + feature_bitmap1, &next1); + l2_output_dispatch (b2, node, &cached_sw_if_index, + &cached_next_index, sw_if_index2, + feature_bitmap2, &next2); + l2_output_dispatch (b3, node, &cached_sw_if_index, + &cached_next_index, sw_if_index3, + feature_bitmap3, &next3); l2output_vtr (node, config0, feature_bitmap0, b0, &next0); l2output_vtr (node, config1, feature_bitmap1, b1, &next1); @@ -401,14 +429,9 @@ l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, feature_bitmap0 = config0->feature_bitmap; /* Determine next node */ - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2output_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); + l2_output_dispatch (b0, node, &cached_sw_if_index, + &cached_next_index, sw_if_index0, + feature_bitmap0, &next0); l2output_vtr (node, config0, feature_bitmap0, b0, &next0); @@ -598,10 +621,10 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn) l2output_node.index, L2OUTPUT_N_FEAT, l2output_get_feat_names (), - mp->next_nodes.feat_next_node_index); + mp->l2_out_feat_next); /* Initialize the output node mapping table */ - vec_validate_init_empty (mp->next_nodes.output_node_index_vec, 100, + vec_validate_init_empty (mp->output_node_index_vec, 100, L2OUTPUT_NEXT_DROP); return 0; @@ -621,7 +644,7 @@ l2output_create_output_node_mapping (vlib_main_t * vlib_main, /* dynamically create graph node arc */ u32 next = vlib_node_add_next (vlib_main, l2output_node.index, hw0->output_node_index); - l2output_main.next_nodes.output_node_index_vec[sw_if_index] = next; + l2output_main.output_node_index_vec[sw_if_index] = next; } /* Get a pointer to the config for the given interface */ diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index 82cefd2c..6da3e303 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -52,11 +52,6 @@ typedef struct } l2_output_config_t; - -/* - * The set of next nodes for features and interface output. - * Each output feature node should include this. - */ typedef struct { /* @@ -70,15 +65,7 @@ typedef struct * array of next node index for each output feature, indexed * by l2output_feat_t. Used to determine next feature node. */ - u32 feat_next_node_index[32]; - -} l2_output_next_nodes_st; - - -typedef struct -{ - /* Next nodes for features and output interfaces */ - l2_output_next_nodes_st next_nodes; + u32 l2_out_feat_next[32]; /* config vector indexed by sw_if_index */ l2_output_config_t *configs; @@ -163,71 +150,6 @@ void l2output_create_output_node_mapping (vlib_main_t * vlib_main, vnet_main_t * vnet_main, u32 sw_if_index); -/** Determine the next L2 node based on the output feature bitmap */ -always_inline void -l2_output_dispatch (vlib_main_t * vlib_main, - vnet_main_t * vnet_main, - vlib_node_runtime_t * node, - u32 node_index, - u32 * cached_sw_if_index, - u32 * cached_next_index, - l2_output_next_nodes_st * next_nodes, - vlib_buffer_t * b0, - u32 sw_if_index, u32 feature_bitmap, u32 * next0) -{ - /* - * The output feature bitmap always have at least the output feature bit set - * for a normal L2 interface (or all 0's if the interface is changed from L2 - * to L3 mode). So if next_nodes specified is that from the l2-output node and - * the bitmap is all clear except output feature bit, we know there is no more - * feature and will fall through to output packet. If next_nodes is from a L2 - * output feature node (and not l2-output), we always want to get the node for - * the next L2 output feature, including the last feature being interface- - * output node to output packet. - */ - if ((next_nodes != &l2output_main.next_nodes) - || ((feature_bitmap & ~L2OUTPUT_FEAT_OUTPUT) != 0)) - { - /* There are some features to execute */ - ASSERT (feature_bitmap != 0); - - /* Save bitmap for the next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap; - - /* Determine the next node */ - *next0 = - feat_bitmap_get_next_node_index (next_nodes->feat_next_node_index, - feature_bitmap); - } - else - { - /* - * There are no features. Send packet to TX node for sw_if_index0 - * This is a little tricky in that the output interface next node indexes - * are not precomputed at init time. - */ - - if (sw_if_index == *cached_sw_if_index) - { - /* We hit in the one-entry cache. Use it. */ - *next0 = *cached_next_index; - } - else - { - /* Look up the output TX node for the sw_if_index */ - *next0 = vec_elt (l2output_main.next_nodes.output_node_index_vec, - sw_if_index); - - if (*next0 == L2OUTPUT_NEXT_DROP) - b0->error = node->errors[L2OUTPUT_ERROR_MAPPING_DROP]; - - /* Update the one-entry cache */ - *cached_sw_if_index = sw_if_index; - *cached_next_index = *next0; - } - } -} - /** Get a pointer to the config for the given interface */ l2_output_config_t *l2output_intf_config (u32 sw_if_index); diff --git a/src/vnet/l2/l2_output_acl.c b/src/vnet/l2/l2_output_acl.c index 1d1971a5..7d051326 100644 --- a/src/vnet/l2/l2_output_acl.c +++ b/src/vnet/l2/l2_output_acl.c @@ -34,8 +34,8 @@ typedef struct { - /* Next nodes for features and output interfaces */ - l2_output_next_nodes_st next_nodes; + /* Next nodes for L2 output features */ + u32 l2_out_feat_next[32]; /* convenience variables */ vlib_main_t *vlib_main; @@ -108,8 +108,6 @@ l2_outacl_node_fn (vlib_main_t * vm, vlib_node_t *n = vlib_get_node (vm, l2_outacl_node.index); u32 node_counter_base_index = n->error_heap_index; vlib_error_main_t *em = &vm->error_main; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; /* number of packets to process */ @@ -201,7 +199,6 @@ l2_outacl_node_fn (vlib_main_t * vm, u32 next0; u32 sw_if_index0; ethernet_header_t *h0; - u32 feature_bitmap0; /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; @@ -234,20 +231,9 @@ l2_outacl_node_fn (vlib_main_t * vm, * Dummy for now, just go to next feature node */ - - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2OUTPUT_FEAT_ACL; - /* Determine next node */ - l2_output_dispatch (msm->vlib_main, - msm->vnet_main, - node, - l2_outacl_node.index, - &cached_sw_if_index, - &cached_next_index, - &msm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); + next0 = vnet_l2_feature_next (b0, msm->l2_out_feat_next, + L2OUTPUT_FEAT_ACL); /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, @@ -295,7 +281,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2_outacl_node, l2_outacl_node_fn) l2_outacl_node.index, L2OUTPUT_N_FEAT, l2output_get_feat_names (), - mp->next_nodes.feat_next_node_index); + mp->l2_out_feat_next); return 0; } diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c index 869b0656..a49abec2 100644 --- a/src/vnet/l2/l2_output_classify.c +++ b/src/vnet/l2/l2_output_classify.c @@ -144,14 +144,11 @@ l2_output_classify_node_fn (vlib_main_t * vm, vnet_classify_main_t *vcm = cm->vnet_classify_main; l2_output_classify_runtime_t *rt = (l2_output_classify_runtime_t *) node->runtime_data; - u32 feature_bitmap0; u32 hits = 0; u32 misses = 0; u32 chain_hits = 0; f64 now; u32 n_next_nodes; - u32 cached_sw_if_index = (u32) ~ 0; - u32 cached_next_index = (u32) ~ 0; u32 sw_if_index0; n_next_nodes = node->n_next_nodes; @@ -347,12 +344,6 @@ l2_output_classify_node_fn (vlib_main_t * vm, table_index0 = vnet_buffer (b0)->l2_classify.table_index; e0 = 0; vnet_buffer (b0)->l2_classify.opaque_index = ~0; - /* Remove ourself from the feature bitmap */ - feature_bitmap0 = vnet_buffer (b0)->l2.feature_bitmap - & ~L2OUTPUT_FEAT_OUTPUT_CLASSIFY; - - /* save for next feature graph nodes */ - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; if (PREDICT_TRUE (table_index0 != ~0)) { @@ -405,20 +396,13 @@ l2_output_classify_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (next0 == 0)) b0->error = node->errors[L2_OUTPUT_CLASSIFY_ERROR_DROP]; + /* Determine the next node and remove ourself from bitmap */ if (PREDICT_FALSE (next0 == ~0)) - { - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - - /* Determine next node */ - l2_output_dispatch (cm->vlib_main, - cm->vnet_main, - node, - l2_output_classify_node.index, - &cached_sw_if_index, - &cached_next_index, - &cm->next_nodes, - b0, sw_if_index0, feature_bitmap0, &next0); - } + next0 = vnet_l2_feature_next (b0, cm->l2_out_feat_next, + L2OUTPUT_FEAT_OUTPUT_CLASSIFY); + else + vnet_buffer (b0)->l2.feature_bitmap &= + ~L2OUTPUT_FEAT_OUTPUT_CLASSIFY; if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) && (b0->flags & VLIB_BUFFER_IS_TRACED))) @@ -493,7 +477,7 @@ l2_output_classify_init (vlib_main_t * vm) l2_output_classify_node.index, L2OUTPUT_N_FEAT, l2output_get_feat_names (), - cm->next_nodes.feat_next_node_index); + cm->l2_out_feat_next); rt->l2cm = cm; rt->vcm = cm->vnet_classify_main; diff --git a/src/vnet/l2/l2_rw.c b/src/vnet/l2/l2_rw.c index c54509d0..fec04774 100644 --- a/src/vnet/l2/l2_rw.c +++ b/src/vnet/l2/l2_rw.c @@ -179,8 +179,8 @@ l2_rw_node_fn (vlib_main_t * vm, while (n_left_from >= 4 && n_left_to_next >= 2) { - u32 bi0, next0, sw_if_index0, feature_bitmap0, rwe_index0; - u32 bi1, next1, sw_if_index1, feature_bitmap1, rwe_index1; + u32 bi0, next0, sw_if_index0, rwe_index0; + u32 bi1, next1, sw_if_index1, rwe_index1; vlib_buffer_t *b0, *b1; ethernet_header_t *h0, *h1; l2_rw_config_t *config0, *config1; @@ -273,16 +273,10 @@ l2_rw_node_fn (vlib_main_t * vm, } /* Update feature bitmap and get next feature index */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; - feature_bitmap1 = - vnet_buffer (b1)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; - vnet_buffer (b1)->l2.feature_bitmap = feature_bitmap1; - next0 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, - feature_bitmap0); - next1 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, - feature_bitmap1); + next0 = vnet_l2_feature_next (b0, rw->feat_next_node_index, + L2INPUT_FEAT_RW); + next1 = vnet_l2_feature_next (b1, rw->feat_next_node_index, + L2INPUT_FEAT_RW); vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, n_left_to_next, @@ -291,7 +285,7 @@ l2_rw_node_fn (vlib_main_t * vm, while (n_left_from > 0 && n_left_to_next > 0) { - u32 bi0, next0, sw_if_index0, feature_bitmap0, rwe_index0; + u32 bi0, next0, sw_if_index0, rwe_index0; vlib_buffer_t *b0; ethernet_header_t *h0; l2_rw_config_t *config0; @@ -341,11 +335,8 @@ l2_rw_node_fn (vlib_main_t * vm, } /* Update feature bitmap and get next feature index */ - feature_bitmap0 = - vnet_buffer (b0)->l2.feature_bitmap & ~L2INPUT_FEAT_RW; - vnet_buffer (b0)->l2.feature_bitmap = feature_bitmap0; - next0 = feat_bitmap_get_next_node_index (rw->feat_next_node_index, - feature_bitmap0); + next0 = vnet_l2_feature_next (b0, rw->feat_next_node_index, + L2INPUT_FEAT_RW); vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, diff --git a/src/vnet/policer/node_funcs.c b/src/vnet/policer/node_funcs.c index 457dd09f..fd031d02 100644 --- a/src/vnet/policer/node_funcs.c +++ b/src/vnet/policer/node_funcs.c @@ -736,14 +736,9 @@ policer_classify_inline (vlib_main_t * vm, if (tid == POLICER_CLASSIFY_TABLE_L2) { - /* Feature bitmap update */ - vnet_buffer (b0)->l2.feature_bitmap &= - ~L2INPUT_FEAT_POLICER_CLAS; - /* Determine the next node */ - next0 = - feat_bitmap_get_next_node_index (pcm->feat_next_node_index, - vnet_buffer (b0)-> - l2.feature_bitmap); + /* Feature bitmap update and determine the next node */ + next0 = vnet_l2_feature_next (b0, pcm->feat_next_node_index, + L2INPUT_FEAT_POLICER_CLAS); } else vnet_get_config_data (pcm->vnet_config_main[tid], -- cgit 1.2.3-korg From 001fd406df771f1cf73ca0dea440c8bde309e077 Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Sun, 16 Jul 2017 09:34:53 +0300 Subject: SPAN:add l2 mirror added span feature nodes for l2-input / l2-output Change-Id: Ib6e0ce60d0811901b6edd70209e6a4c4a35cd8ff Signed-off-by: Eyal Bari --- src/vat/api_format.c | 6 +- src/vnet/l2/l2_input.h | 5 +- src/vnet/l2/l2_output.c | 13 +- src/vnet/l2/l2_output.h | 8 +- src/vnet/span/node.c | 198 ++++++++++++++++++-------- src/vnet/span/span.api | 1 + src/vnet/span/span.c | 148 +++++++++++--------- src/vnet/span/span.h | 25 +++- src/vnet/span/span_api.c | 15 +- src/vpp/api/custom_dump.c | 3 + test/test_span.py | 348 +++++++++++++++++++++++++++++++++++++++++----- test/vpp_papi_provider.py | 7 +- 12 files changed, 606 insertions(+), 171 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 40eca8c5..932e162d 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -18082,6 +18082,7 @@ api_sw_interface_span_enable_disable (vat_main_t * vam) u32 dst_sw_if_index = ~0; u8 state = 3; int ret; + u8 is_l2 = 0; while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) { @@ -18104,6 +18105,8 @@ api_sw_interface_span_enable_disable (vat_main_t * vam) state = 2; else if (unformat (i, "both")) state = 3; + else if (unformat (i, "l2")) + is_l2 = 1; else break; } @@ -18113,6 +18116,7 @@ api_sw_interface_span_enable_disable (vat_main_t * vam) mp->sw_if_index_from = htonl (src_sw_if_index); mp->sw_if_index_to = htonl (dst_sw_if_index); mp->state = state; + mp->is_l2 = is_l2; S (mp); W (ret); @@ -20044,7 +20048,7 @@ _(set_ipfix_classify_stream, "[domain ] [src_port ]") \ _(ipfix_classify_stream_dump, "") \ _(ipfix_classify_table_add_del, "table ip4|ip6 [tcp|udp]") \ _(ipfix_classify_table_dump, "") \ -_(sw_interface_span_enable_disable, "[src | src_sw_if_index ] [disable | [[dst | dst_sw_if_index ] [both|rx|tx]]]") \ +_(sw_interface_span_enable_disable, "[l2] [src | src_sw_if_index ] [disable | [[dst | dst_sw_if_index ] [both|rx|tx]]]") \ _(sw_interface_span_dump, "") \ _(get_next_index, "node-name next-node-name ") \ _(pg_create_interface, "if_id ") \ diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index 244ef445..e6b3bc7f 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -102,7 +102,7 @@ l2input_bd_config (u32 bd_index) /* L2 input features */ -/* Mappings from feature ID to graph node name */ +/* Mappings from feature ID to graph node name in reverse order */ #define foreach_l2input_feat \ _(DROP, "feature-bitmap-drop") \ _(XCONNECT, "l2-output") \ @@ -116,7 +116,8 @@ l2input_bd_config (u32 bd_index) _(VPATH, "vpath-input-l2") \ _(ACL, "l2-input-acl") \ _(POLICER_CLAS, "l2-policer-classify") \ - _(INPUT_CLASSIFY, "l2-input-classify") + _(INPUT_CLASSIFY, "l2-input-classify") \ + _(SPAN, "span-l2-input") /* Feature bitmap positions */ typedef enum diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index b3537a35..fbee590c 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -195,8 +195,6 @@ l2output_vtr (vlib_node_runtime_t * node, l2_output_config_t * config, } -static vlib_node_registration_t l2output_node; - static_always_inline uword l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, int do_trace) @@ -477,7 +475,7 @@ l2output_node_fn (vlib_main_t * vm, } /* *INDENT-OFF* */ -VLIB_REGISTER_NODE (l2output_node,static) = { +VLIB_REGISTER_NODE (l2output_node) = { .function = l2output_node_fn, .name = "l2-output", .vector_size = sizeof (u32), @@ -495,6 +493,8 @@ VLIB_REGISTER_NODE (l2output_node,static) = { [L2OUTPUT_NEXT_BAD_INTF] = "l2-output-bad-intf", }, }; + +VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn); /* *INDENT-ON* */ @@ -601,11 +601,12 @@ VLIB_REGISTER_NODE (l2output_bad_intf_node,static) = { [0] = "error-drop", }, }; -/* *INDENT-ON* */ +VLIB_NODE_FUNCTION_MULTIARCH (l2output_bad_intf_node, l2output_bad_intf_node_fn); +/* *INDENT-ON* */ -VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn) - clib_error_t *l2output_init (vlib_main_t * vm) +static clib_error_t * +l2output_init (vlib_main_t * vm) { l2output_main_t *mp = &l2output_main; diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index 6da3e303..a54b8d67 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -77,12 +77,14 @@ typedef struct l2output_main_t l2output_main; +extern vlib_node_registration_t l2output_node; + /* L2 output features */ -/* Mappings from feature ID to graph node name */ +/* Mappings from feature ID to graph node name in reverse order */ #define foreach_l2output_feat \ _(OUTPUT, "interface-output") \ - _(SPAN, "feature-bitmap-drop") \ + _(SPAN, "span-l2-output") \ _(CFM, "feature-bitmap-drop") \ _(QOS, "feature-bitmap-drop") \ _(ACL, "l2-output-acl") \ @@ -103,6 +105,8 @@ typedef enum L2OUTPUT_N_FEAT, } l2output_feat_t; +STATIC_ASSERT (L2OUTPUT_N_FEAT <= 32, "too many l2 output features"); + /* Feature bit masks */ typedef enum { diff --git a/src/vnet/span/node.c b/src/vnet/span/node.c index 3a461b0a..9d83d4ef 100644 --- a/src/vnet/span/node.c +++ b/src/vnet/span/node.c @@ -18,6 +18,9 @@ #include #include +#include +#include +#include #include #include @@ -59,21 +62,19 @@ static char *span_error_strings[] = { static_always_inline void span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0, - vlib_buffer_t * b0, vlib_frame_t ** mirror_frames, int is_rx) + vlib_buffer_t * b0, vlib_frame_t ** mirror_frames, + vlib_rx_or_tx_t rxtx, span_feat_t sf) { vlib_buffer_t *c0; span_main_t *sm = &span_main; vnet_main_t *vnm = &vnet_main; - span_interface_t *si0 = 0; u32 *to_mirror_next = 0; u32 i; - si0 = vec_elt_at_index (sm->interfaces, sw_if_index0); + span_interface_t *si0 = vec_elt_at_index (sm->interfaces, sw_if_index0); + span_mirror_t *sm0 = &si0->mirror_rxtx[sf][rxtx]; - if (is_rx != 0 && si0->num_rx_mirror_ports == 0) - return; - - if (is_rx == 0 && si0->num_tx_mirror_ports == 0) + if (sm0->num_mirror_ports == 0) return; /* Don't do it again */ @@ -81,10 +82,15 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0, return; /* *INDENT-OFF* */ - clib_bitmap_foreach (i, is_rx ? si0->rx_mirror_ports : si0->tx_mirror_ports, ( + clib_bitmap_foreach (i, sm0->mirror_ports, ( { if (mirror_frames[i] == 0) - mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i); + { + if (sf == SPAN_FEAT_L2) + mirror_frames[i] = vlib_get_frame_to_node (vnm->vlib_main, l2output_node.index); + else + mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i); + } to_mirror_next = vlib_frame_vector_args (mirror_frames[i]); to_mirror_next += mirror_frames[i]->n_vectors; /* This can fail */ @@ -93,6 +99,8 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0, { vnet_buffer (c0)->sw_if_index[VLIB_TX] = i; c0->flags |= VNET_BUFFER_F_SPAN_CLONE; + if (sf == SPAN_FEAT_L2) + vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT; to_mirror_next[0] = vlib_get_buffer_index (vm, c0); mirror_frames[i]->n_vectors++; if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -108,7 +116,8 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0, static_always_inline uword span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame, int is_rx) + vlib_frame_t * frame, vlib_rx_or_tx_t rxtx, + span_feat_t sf) { span_main_t *sm = &span_main; vnet_main_t *vnm = &vnet_main; @@ -117,7 +126,6 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, u32 next_index; u32 sw_if_index; static __thread vlib_frame_t **mirror_frames = 0; - vlib_rx_or_tx_t rxtx = is_rx ? VLIB_RX : VLIB_TX; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -156,11 +164,33 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx]; sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx]; - span_mirror (vm, node, sw_if_index0, b0, mirror_frames, is_rx); - span_mirror (vm, node, sw_if_index1, b1, mirror_frames, is_rx); - - vnet_feature_next (sw_if_index0, &next0, b0); - vnet_feature_next (sw_if_index1, &next1, b1); + span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf); + span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf); + + switch (sf) + { + case SPAN_FEAT_L2: + if (rxtx == VLIB_RX) + { + next0 = vnet_l2_feature_next (b0, sm->l2_input_next, + L2INPUT_FEAT_SPAN); + next1 = vnet_l2_feature_next (b1, sm->l2_input_next, + L2INPUT_FEAT_SPAN); + } + else + { + next0 = vnet_l2_feature_next (b0, sm->l2_output_next, + L2OUTPUT_FEAT_SPAN); + next1 = vnet_l2_feature_next (b1, sm->l2_output_next, + L2OUTPUT_FEAT_SPAN); + } + break; + case SPAN_FEAT_DEVICE: + default: + vnet_feature_next (sw_if_index0, &next0, b0); + vnet_feature_next (sw_if_index1, &next1, b1); + break; + } /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x2 (vm, node, next_index, @@ -184,9 +214,23 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, b0 = vlib_get_buffer (vm, bi0); sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx]; - span_mirror (vm, node, sw_if_index0, b0, mirror_frames, is_rx); - - vnet_feature_next (sw_if_index0, &next0, b0); + span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf); + + switch (sf) + { + case SPAN_FEAT_L2: + if (rxtx == VLIB_RX) + next0 = vnet_l2_feature_next (b0, sm->l2_input_next, + L2INPUT_FEAT_SPAN); + else + next0 = vnet_l2_feature_next (b0, sm->l2_output_next, + L2OUTPUT_FEAT_SPAN); + break; + case SPAN_FEAT_DEVICE: + default: + vnet_feature_next (sw_if_index0, &next0, b0); + break; + } /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, @@ -199,11 +243,14 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++) { - if (mirror_frames[sw_if_index] == 0) + vlib_frame_t *f = mirror_frames[sw_if_index]; + if (f == 0) continue; - vnet_put_frame_to_sw_interface (vnm, sw_if_index, - mirror_frames[sw_if_index]); + if (sf == SPAN_FEAT_L2) + vlib_put_frame_to_node (vnm->vlib_main, l2output_node.index, f); + else + vnet_put_frame_to_sw_interface (vnm, sw_if_index, f); mirror_frames[sw_if_index] = 0; } vlib_node_increment_counter (vm, span_node.index, SPAN_ERROR_HITS, @@ -213,62 +260,103 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node, } static uword -span_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +span_device_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return span_node_inline_fn (vm, node, frame, 1); + return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE); } static uword -span_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) +span_device_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) { - return span_node_inline_fn (vm, node, frame, 0); + return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE); } -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (span_input_node) = { - .function = span_input_node_fn, - .name = "span-input", - .vector_size = sizeof (u32), - .format_trace = format_span_trace, - .type = VLIB_NODE_TYPE_INTERNAL, +static uword +span_l2_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2); +} - .n_errors = ARRAY_LEN(span_error_strings), - .error_strings = span_error_strings, +static uword +span_l2_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, + vlib_frame_t * frame) +{ + return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2); +} - .n_next_nodes = 0, +#define span_node_defs \ + .vector_size = sizeof (u32), \ + .format_trace = format_span_trace, \ + .type = VLIB_NODE_TYPE_INTERNAL, \ + .n_errors = ARRAY_LEN(span_error_strings), \ + .error_strings = span_error_strings, \ + .n_next_nodes = 0, \ + .next_nodes = { \ + [0] = "error-drop" \ + } - /* edit / add dispositions here */ - .next_nodes = { - [0] = "error-drop", - }, +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (span_input_node) = { + span_node_defs, + .function = span_device_input_node_fn, + .name = "span-input", }; -VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_input_node_fn) +VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_device_input_node_fn) VLIB_REGISTER_NODE (span_output_node) = { - .function = span_output_node_fn, + span_node_defs, + .function = span_device_output_node_fn, .name = "span-output", - .vector_size = sizeof (u32), - .format_trace = format_span_trace, - .type = VLIB_NODE_TYPE_INTERNAL, +}; - .n_errors = ARRAY_LEN(span_error_strings), - .error_strings = span_error_strings, +VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_device_output_node_fn) - .n_next_nodes = 0, +VLIB_REGISTER_NODE (span_l2_input_node) = { + span_node_defs, + .function = span_l2_input_node_fn, + .name = "span-l2-input", +}; - /* edit / add dispositions here */ - .next_nodes = { - [0] = "error-drop", - }, +VLIB_NODE_FUNCTION_MULTIARCH (span_l2_input_node, span_l2_input_node_fn) + +VLIB_REGISTER_NODE (span_l2_output_node) = { + span_node_defs, + .function = span_l2_output_node_fn, + .name = "span-l2-output", }; -VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_output_node_fn) +VLIB_NODE_FUNCTION_MULTIARCH (span_l2_output_node, span_l2_output_node_fn) + +clib_error_t *span_init (vlib_main_t * vm) +{ + span_main_t *sm = &span_main; + + sm->vlib_main = vm; + sm->vnet_main = vnet_get_main (); + + /* Initialize the feature next-node indexes */ + feat_bitmap_init_next_nodes (vm, + span_l2_input_node.index, + L2INPUT_N_FEAT, + l2input_get_feat_names (), + sm->l2_input_next); + + feat_bitmap_init_next_nodes (vm, + span_l2_output_node.index, + L2OUTPUT_N_FEAT, + l2output_get_feat_names (), + sm->l2_output_next); + return 0; +} +VLIB_INIT_FUNCTION (span_init); /* *INDENT-ON* */ +#undef span_node_defs /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/span/span.api b/src/vnet/span/span.api index 914fd8d0..2a762ac2 100644 --- a/src/vnet/span/span.api +++ b/src/vnet/span/span.api @@ -27,6 +27,7 @@ autoreply define sw_interface_span_enable_disable { u32 sw_if_index_from; u32 sw_if_index_to; u8 state; + u8 is_l2; }; /** \brief SPAN dump request diff --git a/src/vnet/span/span.c b/src/vnet/span/span.c index c5b43e34..6ecd1789 100644 --- a/src/vnet/span/span.c +++ b/src/vnet/span/span.c @@ -16,60 +16,81 @@ #include #include #include +#include +#include #include +typedef enum +{ + SPAN_DISABLE = 0, + SPAN_RX = 1, + SPAN_TX = 2, + SPAN_BOTH = SPAN_RX | SPAN_TX +} span_state_t; + +static_always_inline u32 +span_dst_set (span_mirror_t * sm, u32 dst_sw_if_index, int enable) +{ + sm->mirror_ports = + clib_bitmap_set (sm->mirror_ports, dst_sw_if_index, enable); + u32 last = sm->num_mirror_ports; + sm->num_mirror_ports = clib_bitmap_count_set_bits (sm->mirror_ports); + return last; +} + int span_add_delete_entry (vlib_main_t * vm, - u32 src_sw_if_index, u32 dst_sw_if_index, u8 state) + u32 src_sw_if_index, u32 dst_sw_if_index, u8 state, + span_feat_t sf) { span_main_t *sm = &span_main; - span_interface_t *si; - u32 new_num_rx_mirror_ports, new_num_tx_mirror_ports; - if (state > 3) + if (state > SPAN_BOTH) return VNET_API_ERROR_UNIMPLEMENTED; if ((src_sw_if_index == ~0) || (dst_sw_if_index == ~0 && state > 0) || (src_sw_if_index == dst_sw_if_index)) return VNET_API_ERROR_INVALID_INTERFACE; - vnet_sw_interface_t *sw_if; - - sw_if = vnet_get_sw_interface (vnet_get_main (), src_sw_if_index); - if (sw_if->type == VNET_SW_INTERFACE_TYPE_SUB) - return VNET_API_ERROR_UNIMPLEMENTED; - vec_validate_aligned (sm->interfaces, src_sw_if_index, CLIB_CACHE_LINE_BYTES); - si = vec_elt_at_index (sm->interfaces, src_sw_if_index); - - si->rx_mirror_ports = clib_bitmap_set (si->rx_mirror_ports, dst_sw_if_index, - (state & 1) != 0); - si->tx_mirror_ports = clib_bitmap_set (si->tx_mirror_ports, dst_sw_if_index, - (state & 2) != 0); - new_num_rx_mirror_ports = clib_bitmap_count_set_bits (si->rx_mirror_ports); - new_num_tx_mirror_ports = clib_bitmap_count_set_bits (si->tx_mirror_ports); + span_interface_t *si = vec_elt_at_index (sm->interfaces, src_sw_if_index); - if (new_num_rx_mirror_ports == 1 && si->num_rx_mirror_ports == 0) - vnet_feature_enable_disable ("device-input", "span-input", - src_sw_if_index, 1, 0, 0); + int rx = ! !(state & SPAN_RX); + int tx = ! !(state & SPAN_TX); - if (new_num_rx_mirror_ports == 0 && si->num_rx_mirror_ports == 1) - vnet_feature_enable_disable ("device-input", "span-input", - src_sw_if_index, 0, 0, 0); + span_mirror_t *rxm = &si->mirror_rxtx[sf][VLIB_RX]; + span_mirror_t *txm = &si->mirror_rxtx[sf][VLIB_TX]; - if (new_num_rx_mirror_ports == 1 && si->num_rx_mirror_ports == 0) - vnet_feature_enable_disable ("interface-output", "span-output", - src_sw_if_index, 1, 0, 0); + u32 last_rx_ports_count = span_dst_set (rxm, dst_sw_if_index, rx); + u32 last_tx_ports_count = span_dst_set (txm, dst_sw_if_index, tx); - if (new_num_rx_mirror_ports == 0 && si->num_rx_mirror_ports == 1) - vnet_feature_enable_disable ("interface-output", "span-output", - src_sw_if_index, 0, 0, 0); + int enable_rx = last_rx_ports_count == 0 && rxm->num_mirror_ports == 1; + int disable_rx = last_rx_ports_count == 1 && rxm->num_mirror_ports == 0; + int enable_tx = last_tx_ports_count == 0 && txm->num_mirror_ports == 1; + int disable_tx = last_tx_ports_count == 1 && txm->num_mirror_ports == 0; - si->num_rx_mirror_ports = new_num_rx_mirror_ports; - si->num_tx_mirror_ports = new_num_tx_mirror_ports; + switch (sf) + { + case SPAN_FEAT_DEVICE: + if (enable_rx || disable_rx) + vnet_feature_enable_disable ("device-input", "span-input", + src_sw_if_index, rx, 0, 0); + if (enable_tx || disable_tx) + vnet_feature_enable_disable ("interface-output", "span-output", + src_sw_if_index, tx, 0, 0); + break; + case SPAN_FEAT_L2: + if (enable_rx || disable_rx) + l2input_intf_bitmap_enable (src_sw_if_index, L2INPUT_FEAT_SPAN, rx); + if (enable_tx || disable_tx) + l2output_intf_bitmap_enable (src_sw_if_index, L2OUTPUT_FEAT_SPAN, tx); + break; + default: + return VNET_API_ERROR_UNIMPLEMENTED; + } if (dst_sw_if_index > sm->max_sw_if_index) sm->max_sw_if_index = dst_sw_if_index; @@ -85,7 +106,8 @@ set_interface_span_command_fn (vlib_main_t * vm, span_main_t *sm = &span_main; u32 src_sw_if_index = ~0; u32 dst_sw_if_index = ~0; - u8 state = 3; + u8 state = SPAN_BOTH; + span_feat_t sf = SPAN_FEAT_DEVICE; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -96,19 +118,21 @@ set_interface_span_command_fn (vlib_main_t * vm, sm->vnet_main, &dst_sw_if_index)) ; else if (unformat (input, "disable")) - state = 0; + state = SPAN_DISABLE; else if (unformat (input, "rx")) - state = 1; + state = SPAN_RX; else if (unformat (input, "tx")) - state = 2; + state = SPAN_TX; else if (unformat (input, "both")) - state = 3; + state = SPAN_BOTH; + else if (unformat (input, "l2")) + sf = SPAN_FEAT_L2; else break; } int rv = - span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state); + span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state, sf); if (rv == VNET_API_ERROR_INVALID_INTERFACE) return clib_error_return (0, "Invalid interface"); return 0; @@ -117,7 +141,7 @@ set_interface_span_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_interface_span_command, static) = { .path = "set interface span", - .short_help = "set interface span [disable | destination [both|rx|tx]]", + .short_help = "set interface span [l2] {disable | destination [both|rx|tx]}", .function = set_interface_span_command_fn, }; /* *INDENT-ON* */ @@ -136,31 +160,44 @@ show_interfaces_span_command_fn (vlib_main_t * vm, /* *INDENT-OFF* */ vec_foreach (si, sm->interfaces) - if (si->num_rx_mirror_ports || si->num_tx_mirror_ports) + { + span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX]; + span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX]; + + span_mirror_t * lrxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_RX]; + span_mirror_t * ltxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_TX]; + + if (drxm->num_mirror_ports || dtxm->num_mirror_ports || + lrxm->num_mirror_ports || ltxm->num_mirror_ports) { - clib_bitmap_t *b; u32 i; - b = clib_bitmap_dup_or (si->rx_mirror_ports, si->tx_mirror_ports); + clib_bitmap_t *d = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports); + clib_bitmap_t *l = clib_bitmap_dup_or (lrxm->mirror_ports, ltxm->mirror_ports); + clib_bitmap_t *b = clib_bitmap_dup_or (d, l); if (header) { - vlib_cli_output (vm, "%-40s %s", "Source interface", - "Mirror interface (direction)"); + vlib_cli_output (vm, "%-20s %-20s %6s %6s", "Source", "Destination", + "Device", "L2"); header = 0; } s = format (s, "%U", format_vnet_sw_if_index_name, vnm, si - sm->interfaces); clib_bitmap_foreach (i, b, ( { - int state; - state = (clib_bitmap_get (si->rx_mirror_ports, i) + - clib_bitmap_get (si->tx_mirror_ports, i) * 2); + int device = (clib_bitmap_get (drxm->mirror_ports, i) + + clib_bitmap_get (dtxm->mirror_ports, i) * 2); + int l2 = (clib_bitmap_get (lrxm->mirror_ports, i) + + clib_bitmap_get (ltxm->mirror_ports, i) * 2); - vlib_cli_output (vm, "%-40v %U (%s)", s, + vlib_cli_output (vm, "%-20v %-20U (%6s) (%6s)", s, format_vnet_sw_if_index_name, vnm, i, - states[state]); + states[device], states[l2]); vec_reset_length (s); })); clib_bitmap_free (b); + clib_bitmap_free (l); + clib_bitmap_free (d); + } } /* *INDENT-ON* */ vec_free (s); @@ -175,19 +212,6 @@ VLIB_CLI_COMMAND (show_interfaces_span_command, static) = { }; /* *INDENT-ON* */ -static clib_error_t * -span_init (vlib_main_t * vm) -{ - span_main_t *sm = &span_main; - - sm->vlib_main = vm; - sm->vnet_main = vnet_get_main (); - - return 0; -} - -VLIB_INIT_FUNCTION (span_init); - /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/span/span.h b/src/vnet/span/span.h index a98b010b..10de8272 100644 --- a/src/vnet/span/span.h +++ b/src/vnet/span/span.h @@ -18,17 +18,32 @@ #include #include +#include + +typedef enum +{ + SPAN_FEAT_DEVICE, + SPAN_FEAT_L2, + SPAN_FEAT_N +} span_feat_t; + +typedef struct +{ + clib_bitmap_t *mirror_ports; + u32 num_mirror_ports; +} span_mirror_t; typedef struct { - clib_bitmap_t *rx_mirror_ports; - clib_bitmap_t *tx_mirror_ports; - u32 num_rx_mirror_ports; - u32 num_tx_mirror_ports; + span_mirror_t mirror_rxtx[SPAN_FEAT_N][VLIB_N_RX_TX]; } span_interface_t; typedef struct { + /* l2 feature Next nodes */ + u32 l2_input_next[32]; + u32 l2_output_next[32]; + /* per-interface vector of span instances */ span_interface_t *interfaces; @@ -52,7 +67,7 @@ typedef struct int span_add_delete_entry (vlib_main_t * vm, u32 src_sw_if_index, - u32 dst_sw_if_index, u8 is_add); + u32 dst_sw_if_index, u8 state, span_feat_t sf); /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/span/span_api.c b/src/vnet/span/span_api.c index b4565663..69fa8e97 100644 --- a/src/vnet/span/span_api.c +++ b/src/vnet/span/span_api.c @@ -56,7 +56,8 @@ static void vlib_main_t *vm = vlib_get_main (); rv = span_add_delete_entry (vm, ntohl (mp->sw_if_index_from), - ntohl (mp->sw_if_index_to), mp->state); + ntohl (mp->sw_if_index_to), mp->state, + mp->is_l2 ? SPAN_FEAT_L2 : SPAN_FEAT_DEVICE); REPLY_MACRO (VL_API_SW_INTERFACE_SPAN_ENABLE_DISABLE_REPLY); } @@ -76,11 +77,14 @@ vl_api_sw_interface_span_dump_t_handler (vl_api_sw_interface_span_dump_t * mp) /* *INDENT-OFF* */ vec_foreach (si, sm->interfaces) - if (si->num_rx_mirror_ports || si->num_tx_mirror_ports) + { + span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX]; + span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX]; + if (drxm->num_mirror_ports || dtxm->num_mirror_ports) { clib_bitmap_t *b; u32 i; - b = clib_bitmap_dup_or (si->rx_mirror_ports, si->tx_mirror_ports); + b = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports); clib_bitmap_foreach (i, b, ( { rmp = vl_msg_api_alloc (sizeof (*rmp)); @@ -90,13 +94,14 @@ vl_api_sw_interface_span_dump_t_handler (vl_api_sw_interface_span_dump_t * mp) rmp->sw_if_index_from = htonl (si - sm->interfaces); rmp->sw_if_index_to = htonl (i); - rmp->state = (u8) (clib_bitmap_get (si->rx_mirror_ports, i) + - clib_bitmap_get (si->tx_mirror_ports, i) * 2); + rmp->state = (u8) (clib_bitmap_get (drxm->mirror_ports, i) + + clib_bitmap_get (dtxm->mirror_ports, i) * 2); vl_msg_api_send_shmem (q, (u8 *) & rmp); })); clib_bitmap_free (b); } + } /* *INDENT-ON* */ } diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 7f3a58d9..55a362a3 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -2227,6 +2227,9 @@ static void *vl_api_sw_interface_span_enable_disable_t_print s = format (s, "src_sw_if_index %u ", ntohl (mp->sw_if_index_from)); s = format (s, "dst_sw_if_index %u ", ntohl (mp->sw_if_index_to)); + if (mp->is_l2) + s = format (s, "l2 "); + switch (mp->state) { case 0: diff --git a/test/test_span.py b/test/test_span.py index d8b65252..f2529e8f 100644 --- a/test/test_span.py +++ b/test/test_span.py @@ -3,63 +3,121 @@ import unittest from scapy.packet import Raw -from scapy.layers.l2 import Ether +from scapy.layers.l2 import Ether, Dot1Q, GRE from scapy.layers.inet import IP, UDP +from scapy.layers.vxlan import VXLAN from framework import VppTestCase, VppTestRunner from util import Host, ppp +from vpp_sub_interface import VppDot1QSubint, VppDot1ADSubint +from vpp_gre_interface import VppGreInterface, VppGre6Interface +from vpp_papi_provider import L2_VTR_OP +from collections import namedtuple + +Tag = namedtuple('Tag', ['dot1', 'vlan']) +DOT1AD = 0x88A8 +DOT1Q = 0x8100 class TestSpan(VppTestCase): """ SPAN Test Case """ - # Test variables - hosts_nr = 10 # Number of hosts - pkts_per_burst = 257 # Number of packets per burst - @classmethod def setUpClass(cls): super(TestSpan, cls).setUpClass() - - def setUp(self): - super(TestSpan, self).setUp() - + # Test variables + cls.hosts_nr = 10 # Number of hosts + cls.pkts_per_burst = 257 # Number of packets per burst # create 3 pg interfaces - self.create_pg_interfaces(range(3)) + cls.create_pg_interfaces(range(3)) + cls.bd_id = 55 + cls.sub_if = VppDot1QSubint(cls, cls.pg0, 100) + cls.dst_sub_if = VppDot1QSubint(cls, cls.pg2, 300) + cls.dst_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=300) # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc. - self.flows = dict() - self.flows[self.pg0] = [self.pg1] + cls.flows = dict() + cls.flows[cls.pg0] = [cls.pg1] # packet sizes - self.pg_if_packet_sizes = [64, 512] # , 1518, 9018] + cls.pg_if_packet_sizes = [64, 512] # , 1518, 9018] - self.interfaces = list(self.pg_interfaces) + cls.interfaces = list(cls.pg_interfaces) # Create host MAC and IPv4 lists - # self.MY_MACS = dict() - # self.MY_IP4S = dict() - self.create_host_lists(TestSpan.hosts_nr) - - # Create bi-directional cross-connects between pg0 and pg1 - self.vapi.sw_interface_set_l2_xconnect( - self.pg0.sw_if_index, self.pg1.sw_if_index, enable=1) - self.vapi.sw_interface_set_l2_xconnect( - self.pg1.sw_if_index, self.pg0.sw_if_index, enable=1) + # cls.MY_MACS = dict() + # cls.MY_IP4S = dict() + cls.create_host_lists(cls.hosts_nr) # setup all interfaces - for i in self.interfaces: + for i in cls.interfaces: i.admin_up() i.config_ip4() i.resolve_arp() - # Enable SPAN on pg0 (mirrored to pg2) - self.vapi.sw_interface_span_enable_disable( - self.pg0.sw_if_index, self.pg2.sw_if_index) + cls.vxlan = cls.vapi.vxlan_add_del_tunnel( + src_addr=cls.pg2.local_ip4n, + dst_addr=cls.pg2.remote_ip4n, + vni=1111, + is_add=1) + + def setUp(self): + super(TestSpan, self).setUp() + self.reset_packet_infos() def tearDown(self): super(TestSpan, self).tearDown() + if not self.vpp_dead: + self.logger.info(self.vapi.ppcli("show interface span")) + + def xconnect(self, a, b, is_add=1): + self.vapi.sw_interface_set_l2_xconnect(a, b, enable=is_add) + self.vapi.sw_interface_set_l2_xconnect(b, a, enable=is_add) + + def bridge(self, sw_if_index, is_add=1): + self.vapi.sw_interface_set_l2_bridge( + sw_if_index, bd_id=self.bd_id, enable=is_add) + + def _remove_tag(self, packet, vlan, tag_type): + self.assertEqual(packet.type, tag_type) + payload = packet.payload + self.assertEqual(payload.vlan, vlan) + inner_type = payload.type + payload = payload.payload + packet.remove_payload() + packet.add_payload(payload) + packet.type = inner_type + + def remove_tags(self, packet, tags): + for t in tags: + self._remove_tag(packet, t.vlan, t.dot1) + return packet + def decap_gre(self, pkt): + """ + Decapsulate the original payload frame by removing GRE header + """ + self.assertEqual(pkt[Ether].src, self.pg2.local_mac) + self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac) + + self.assertEqual(pkt[IP].src, self.pg2.local_ip4) + self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4) + + return pkt[GRE].payload + + def decap_vxlan(self, pkt): + """ + Decapsulate the original payload frame by removing VXLAN header + """ + self.assertEqual(pkt[Ether].src, self.pg2.local_mac) + self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac) + + self.assertEqual(pkt[IP].src, self.pg2.local_ip4) + self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4) + + return pkt[VXLAN].payload + + @classmethod def create_host_lists(self, count): """ Method to create required number of MAC and IPv4 addresses. Create required number of host MAC addresses and distribute them among @@ -81,9 +139,9 @@ class TestSpan(VppTestCase): "172.17.1%02x.%u" % (pg_if.sw_if_index, j)) hosts.append(host) - def create_stream(self, src_if, packet_sizes): + def create_stream(self, src_if, packet_sizes, do_dot1=False): pkts = [] - for i in range(0, TestSpan.pkts_per_burst): + for i in range(0, self.pkts_per_burst): dst_if = self.flows[src_if][0] pkt_info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(pkt_info) @@ -91,6 +149,8 @@ class TestSpan(VppTestCase): IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(payload)) + if do_dot1: + p = self.sub_if.add_dot1_layer(p) pkt_info.data = p.copy() size = packet_sizes[(i / 2) % len(packet_sizes)] self.extend_packet(p, size) @@ -161,8 +221,8 @@ class TestSpan(VppTestCase): "Port %u: Packet expected from source %u didn't" " arrive" % (dst_sw_if_index, i.sw_if_index)) - def test_span(self): - """ SPAN test + def test_device_span(self): + """ SPAN device rx mirror test Test scenario: 1. config @@ -173,10 +233,17 @@ class TestSpan(VppTestCase): burst of packets per interface """ + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index) # Create incoming packet streams for packet-generator interfaces pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes) self.pg0.add_stream(pkts) + # Enable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.pg0.sw_if_index, self.pg2.sw_if_index) + + self.logger.info(self.vapi.ppcli("show interface span")) # Enable packet capturing and start packet sending self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -190,6 +257,225 @@ class TestSpan(VppTestCase): self.pg1.get_capture(), self.pg2.get_capture(pg2_expected)) + # Disable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.pg0.sw_if_index, self.pg2.sw_if_index, state=0) + self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index, is_add=0) + + def test_span_l2_rx(self): + """ SPAN l2 rx mirror test """ + + self.sub_if.admin_up() + + self.bridge(self.pg2.sw_if_index) + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index) + # Create incoming packet streams for packet-generator interfaces + pkts = self.create_stream( + self.pg0, self.pg_if_packet_sizes, do_dot1=True) + self.pg0.add_stream(pkts) + + # Enable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1) + + self.logger.info(self.vapi.ppcli("show interface span")) + # Enable packet capturing and start packet sending + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # Verify packets outgoing packet streams on mirrored interface (pg2) + self.logger.info("Verifying capture on interfaces %s and %s" % + (self.pg1.name, self.pg2.name)) + pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) + pg1_pkts = self.pg1.get_capture() + pg2_pkts = self.pg2.get_capture(pg2_expected) + self.verify_capture( + self.pg1, + pg1_pkts, + pg2_pkts) + + self.bridge(self.pg2.sw_if_index, is_add=0) + # Disable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1) + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) + + def test_span_l2_rx_dst_vxlan(self): + """ SPAN l2 rx mirror into vxlan test """ + + self.sub_if.admin_up() + self.vapi.sw_interface_set_flags(self.vxlan.sw_if_index, + admin_up_down=1) + + self.bridge(self.vxlan.sw_if_index, is_add=1) + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index) + # Create incoming packet streams for packet-generator interfaces + pkts = self.create_stream( + self.pg0, self.pg_if_packet_sizes, do_dot1=True) + self.pg0.add_stream(pkts) + + # Enable SPAN on pg0 sub if (mirrored to vxlan) + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.vxlan.sw_if_index, is_l2=1) + + self.logger.info(self.vapi.ppcli("show interface span")) + # Enable packet capturing and start packet sending + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # Verify packets outgoing packet streams on mirrored interface (pg2) + self.logger.info("Verifying capture on interfaces %s and %s" % + (self.pg1.name, self.pg2.name)) + pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) + pg1_pkts = self.pg1.get_capture() + pg2_pkts = [self.decap_vxlan(p) + for p in self.pg2.get_capture(pg2_expected)] + self.verify_capture( + self.pg1, + pg1_pkts, + pg2_pkts) + + self.bridge(self.vxlan.sw_if_index, is_add=0) + # Disable SPAN on pg0 sub if (mirrored to vxlan) + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.vxlan.sw_if_index, state=0, is_l2=1) + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) + + def test_span_l2_rx_dst_gre_subif_vtr(self): + """ SPAN l2 rx mirror into gre-subif+vtr """ + + self.sub_if.admin_up() + + gre_if = VppGreInterface(self, self.pg2.local_ip4, + self.pg2.remote_ip4, + is_teb=1) + + gre_if.add_vpp_config() + gre_if.admin_up() + + gre_sub_if = VppDot1QSubint(self, gre_if, 500) + gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500) + gre_sub_if.admin_up() + + self.bridge(gre_sub_if.sw_if_index) + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) + + # Create incoming packet streams for packet-generator interfaces + pkts = self.create_stream( + self.pg0, self.pg_if_packet_sizes, do_dot1=True) + self.pg0.add_stream(pkts) + + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1) + + # Enable packet capturing and start packet sending + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # Verify packets outgoing packet streams on mirrored interface (pg2) + self.logger.info("Verifying capture on interfaces %s and %s" % + (self.pg1.name, self.pg2.name)) + pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) + pg1_pkts = self.pg1.get_capture() + pg2_pkts = self.pg2.get_capture(pg2_expected) + pg2_decaped = [self.remove_tags(self.decap_gre( + p), [Tag(dot1=DOT1Q, vlan=500)]) for p in pg2_pkts] + self.verify_capture( + self.pg1, + pg1_pkts, + pg2_decaped) + + self.bridge(gre_sub_if.sw_if_index, is_add=0) + # Disable SPAN on pg0 sub if + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, + is_l2=1) + gre_if.remove_vpp_config() + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) + + def test_span_l2_rx_dst_vtr(self): + """ SPAN l2 rx mirror into subif+vtr """ + + self.sub_if.admin_up() + self.dst_sub_if.admin_up() + + self.bridge(self.dst_sub_if.sw_if_index) + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1) + + # Create incoming packet streams for packet-generator interfaces + pkts = self.create_stream( + self.pg0, self.pg_if_packet_sizes, do_dot1=True) + self.pg0.add_stream(pkts) + + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.dst_sub_if.sw_if_index, is_l2=1) + + # Enable packet capturing and start packet sending + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # Verify packets outgoing packet streams on mirrored interface (pg2) + self.logger.info("Verifying capture on interfaces %s and %s" % + (self.pg1.name, self.pg2.name)) + pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) + pg1_pkts = self.pg1.get_capture() + pg2_pkts = self.pg2.get_capture(pg2_expected) + pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1Q, vlan=300)]) + for p in pg2_pkts] + self.verify_capture( + self.pg1, + pg1_pkts, + pg2_untagged) + + self.bridge(self.dst_sub_if.sw_if_index, is_add=0) + # Disable SPAN on pg0 sub if (mirrored to vxlan) + self.vapi.sw_interface_span_enable_disable( + self.sub_if.sw_if_index, self.dst_sub_if.sw_if_index, state=0, + is_l2=1) + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) + + def test_l2_tx_span(self): + """ SPAN l2 tx mirror test """ + + self.sub_if.admin_up() + self.bridge(self.pg2.sw_if_index) + # Create bi-directional cross-connects between pg0 and pg1 + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index) + # Create incoming packet streams for packet-generator interfaces + pkts = self.create_stream( + self.pg0, self.pg_if_packet_sizes, do_dot1=True) + self.pg0.add_stream(pkts) + + # Enable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.pg1.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=2) + + self.logger.info(self.vapi.ppcli("show interface span")) + # Enable packet capturing and start packet sending + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + # Verify packets outgoing packet streams on mirrored interface (pg2) + self.logger.info("Verifying capture on interfaces %s and %s" % + (self.pg1.name, self.pg2.name)) + pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index) + pg1_pkts = self.pg1.get_capture() + pg2_pkts = self.pg2.get_capture(pg2_expected) + self.verify_capture( + self.pg1, + pg1_pkts, + pg2_pkts) + + self.bridge(self.pg2.sw_if_index, is_add=0) + # Disable SPAN on pg0 (mirrored to pg2) + self.vapi.sw_interface_span_enable_disable( + self.pg1.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1) + self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0) + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 11e16e49..204d9e31 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -847,17 +847,20 @@ class VppPapiProvider(object): ) def sw_interface_span_enable_disable( - self, sw_if_index_from, sw_if_index_to, state=1): + self, sw_if_index_from, sw_if_index_to, state=1, is_l2=0): """ :param sw_if_index_from: :param sw_if_index_to: :param state: + :param is_l2: """ return self.api(self.papi.sw_interface_span_enable_disable, {'sw_if_index_from': sw_if_index_from, 'sw_if_index_to': sw_if_index_to, - 'state': state}) + 'state': state, + 'is_l2': is_l2, + }) def gre_tunnel_add_del(self, src_address, -- cgit 1.2.3-korg From 942402b02096af1c966f10e3e2a3d235787b962e Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 26 Jul 2017 11:57:04 +0300 Subject: CLI:add l2 input/outut to "sh int features" Change-Id: If608bbc7f4c8b0d5c3a237098a20279e407c82d3 Signed-off-by: Eyal Bari --- src/vnet/interface_cli.c | 42 ++++++++++++++++++++++++++++-------------- src/vnet/l2/l2_bd.h | 2 +- src/vnet/l2/l2_input.c | 23 +++++++++++++++++++++++ src/vnet/l2/l2_input.h | 2 ++ src/vnet/l2/l2_output.c | 23 +++++++++++++++++++++++ src/vnet/l2/l2_output.h | 2 ++ 6 files changed, 79 insertions(+), 15 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/interface_cli.c b/src/vnet/interface_cli.c index fe7ae38f..a8aa3056 100644 --- a/src/vnet/interface_cli.c +++ b/src/vnet/interface_cli.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include static int compare_interface_names (void *a1, void *a2) @@ -262,6 +264,20 @@ show_sw_interfaces (vlib_main_t * vm, if (show_features) { vnet_interface_features_show (vm, sw_if_index); + + l2_input_config_t *l2_input = l2input_intf_config (sw_if_index); + u32 fb = l2_input->feature_bitmap; + /* intf input features are masked by bridge domain */ + if (l2_input->bridge) + fb &= l2input_bd_config (l2_input->bd_index)->feature_bitmap; + vlib_cli_output (vm, "\nl2-input:\n%U", format_l2_input_features, fb); + + l2_output_config_t *l2_output = l2output_intf_config (sw_if_index); + vlib_cli_output (vm, "\nl2-output:"); + if (l2_output->out_vtr_flag) + vlib_cli_output (vm, "%10s (%s)", "VTR", "--internal--"); + vlib_cli_output (vm, "%U", format_l2_output_features, + l2_output->feature_bitmap); return 0; } if (show_tag) @@ -285,9 +301,10 @@ show_sw_interfaces (vlib_main_t * vm, _vec_len (sorted_sis) = 0; pool_foreach (si, im->sw_interfaces, ( { - if (vnet_swif_is_api_visible - (si)) vec_add1 (sorted_sis, - si[0]);} + int visible = + vnet_swif_is_api_visible (si); + if (visible) + vec_add1 (sorted_sis, si[0]);} )); /* Sort by name. */ @@ -298,7 +315,6 @@ show_sw_interfaces (vlib_main_t * vm, { vec_foreach (si, sorted_sis) { - l2input_main_t *l2m = &l2input_main; ip4_main_t *im4 = &ip4_main; ip6_main_t *im6 = &ip6_main; ip_lookup_main_t *lm4 = &im4->lookup_main; @@ -309,7 +325,6 @@ show_sw_interfaces (vlib_main_t * vm, u32 fib_index4 = 0, fib_index6 = 0; ip4_fib_t *fib4; ip6_fib_t *fib6; - l2_input_config_t *config; if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index) fib_index4 = vec_elt (im4->fib_index_by_sw_if_index, @@ -339,21 +354,20 @@ show_sw_interfaces (vlib_main_t * vm, ? "up" : "dn"); } - /* Display any L2 addressing info */ - vec_validate (l2m->configs, si->sw_if_index); - config = vec_elt_at_index (l2m->configs, si->sw_if_index); - if (config->bridge) + /* Display any L2 info */ + l2_input_config_t *l2_input = l2input_intf_config (si->sw_if_index); + if (l2_input->bridge) { - u32 bd_id = l2input_main.bd_configs[config->bd_index].bd_id; + u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id; vlib_cli_output (vm, " l2 bridge bd_id %d%s%d", bd_id, - config->bvi ? " bvi shg " : " shg ", - config->shg); + l2_input->bvi ? " bvi shg " : " shg ", + l2_input->shg); } - else if (config->xconnect) + else if (l2_input->xconnect) { vlib_cli_output (vm, " l2 xconnect %U", format_vnet_sw_if_index_name, - vnm, config->output_sw_if_index); + vnm, l2_input->output_sw_if_index); } /* Display any IP4 addressing info */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 93ed1a85..0e070651 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -34,7 +34,7 @@ typedef struct vnet_main_t *vnet_main; } bd_main_t; -bd_main_t bd_main; +extern bd_main_t bd_main; /* Bridge domain member */ diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 26c832ad..faed7c7f 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -60,6 +60,29 @@ l2input_get_feat_names (void) return l2input_feat_names; } +u8 * +format_l2_input_features (u8 * s, va_list * args) +{ + static char *display_names[] = { +#define _(sym,name) #sym, + foreach_l2input_feat +#undef _ + }; + u32 feature_bitmap = va_arg (*args, u32); + + if (feature_bitmap == 0) + { + s = format (s, " none configured"); + return s; + } + + feature_bitmap &= ~L2INPUT_FEAT_DROP; /* Not a feature */ + int i; + for (i = L2INPUT_N_FEAT; i >= 0; i--) + if (feature_bitmap & (1 << i)) + s = format (s, "%10s (%s)\n", display_names[i], l2input_feat_names[i]); + return s; +} typedef struct { diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h index e6b3bc7f..e8a6c776 100644 --- a/src/vnet/l2/l2_input.h +++ b/src/vnet/l2/l2_input.h @@ -148,6 +148,8 @@ STATIC_ASSERT ((u64) L2INPUT_VALID_MASK == (1ull << L2INPUT_N_FEAT) - 1, ""); /** Return an array of strings containing graph node names of each feature */ char **l2input_get_feat_names (void); +/* arg0 - u32 feature_bitmap */ +u8 *format_l2_input_features (u8 * s, va_list * args); static_always_inline u8 bd_feature_flood (l2_bridge_domain_t * bd_config) diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c index fbee590c..500fc5d0 100644 --- a/src/vnet/l2/l2_output.c +++ b/src/vnet/l2/l2_output.c @@ -40,6 +40,29 @@ l2output_get_feat_names (void) return l2output_feat_names; } +u8 * +format_l2_output_features (u8 * s, va_list * args) +{ + static char *display_names[] = { +#define _(sym,name) #sym, + foreach_l2output_feat +#undef _ + }; + u32 feature_bitmap = va_arg (*args, u32); + + if (feature_bitmap == 0) + { + s = format (s, " none configured"); + return s; + } + + int i; + for (i = L2OUTPUT_N_FEAT - 1; i >= 0; i--) + if (feature_bitmap & (1 << i)) + s = format (s, "%10s (%s)\n", display_names[i], l2output_feat_names[i]); + return s; +} + l2output_main_t l2output_main; typedef struct diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h index a54b8d67..1a73fdf9 100644 --- a/src/vnet/l2/l2_output.h +++ b/src/vnet/l2/l2_output.h @@ -141,6 +141,8 @@ typedef enum /* Return an array of strings containing graph node names of each feature */ char **l2output_get_feat_names (void); +/* arg0 - u32 feature_bitmap */ +u8 *format_l2_output_features (u8 * s, va_list * args); /** * The next set of functions is for use by output feature graph nodes. -- cgit 1.2.3-korg From 8d00fff8dff4e449767601645422e03df92a83af Mon Sep 17 00:00:00 2001 From: John Lo Date: Thu, 3 Aug 2017 00:35:36 -0400 Subject: Add support for API client to receive L2 MAC events Added APIs want_l2_macs_events and l2_macs_event to allow an API client to receive notification events from VPP for MAC learned or aged in L2FIB. Only one API client is allowed for L2 MAC events. The want_l2_macs_events API allow caller to specify MAC learn limit, event scan delay and max number of MACs that can be included in a event message. These parameters should be choosen properly as to not have too many MAC events sent by VPP and overwhelm the API share memory. They can all be left as 0's so VPP will setup reasonable defaults which are: 1000 learn limit, 100 msec scan delay and 100 MACs per event message. If want_l2_macs_events is never called, VPP learning and aging should behave as before except that MAC entries provisioned by API or CLI will not be aged, even if it is not set as static_mac. These non static MACs, however, can be overwritten by MAC learning on a MAC move as a leared MAC. Only learned MACs are subject to aging. Change-Id: Ia3757a80cf8adb2811a089d2eafbd6439461285c Signed-off-by: John Lo --- src/vat/api_format.c | 86 +++++++++- src/vnet/api_errno.h | 5 +- src/vnet/l2/l2.api | 65 +++++++- src/vnet/l2/l2_api.c | 83 +++++++++- src/vnet/l2/l2_bd.c | 37 +---- src/vnet/l2/l2_fib.c | 394 ++++++++++++++++++++++++++++++++++------------ src/vnet/l2/l2_fib.h | 37 ++++- src/vnet/l2/l2_fwd.c | 3 +- src/vnet/l2/l2_learn.c | 30 ++-- src/vnet/l2/l2_learn.h | 5 + src/vpp/api/custom_dump.c | 33 +++- 11 files changed, 605 insertions(+), 173 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index bbd97ba1..27286686 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -1283,6 +1283,30 @@ vl_api_ip6_nd_event_t_handler_json (vl_api_ip6_nd_event_t * mp) /* JSON output not supported */ } +static void +vl_api_l2_macs_event_t_handler (vl_api_l2_macs_event_t * mp) +{ + u32 n_macs = ntohl (mp->n_macs); + errmsg ("L2MAC event recived with pid %d cl-idx %d for %d macs: \n", + ntohl (mp->pid), mp->client_index, n_macs); + int i; + for (i = 0; i < n_macs; i++) + { + vl_api_mac_entry_t *mac = &mp->mac[i]; + errmsg (" [%d] sw_if_index %d mac_addr %U is_del %d \n", + i + 1, ntohl (mac->sw_if_index), + format_ethernet_address, mac->mac_addr, mac->is_del); + if (i == 1000) + break; + } +} + +static void +vl_api_l2_macs_event_t_handler_json (vl_api_l2_macs_event_t * mp) +{ + /* JSON output not supported */ +} + #define vl_api_bridge_domain_details_t_endian vl_noop_handler #define vl_api_bridge_domain_details_t_print vl_noop_handler @@ -4597,6 +4621,7 @@ _(modify_vhost_user_if_reply) \ _(delete_vhost_user_if_reply) \ _(want_ip4_arp_events_reply) \ _(want_ip6_nd_events_reply) \ +_(want_l2_macs_events_reply) \ _(input_acl_set_interface_reply) \ _(ipsec_spd_add_del_reply) \ _(ipsec_interface_add_del_spd_reply) \ @@ -4813,6 +4838,8 @@ _(WANT_IP4_ARP_EVENTS_REPLY, want_ip4_arp_events_reply) \ _(IP4_ARP_EVENT, ip4_arp_event) \ _(WANT_IP6_ND_EVENTS_REPLY, want_ip6_nd_events_reply) \ _(IP6_ND_EVENT, ip6_nd_event) \ +_(WANT_L2_MACS_EVENTS_REPLY, want_l2_macs_events_reply) \ +_(L2_MACS_EVENT, l2_macs_event) \ _(INPUT_ACL_SET_INTERFACE_REPLY, input_acl_set_interface_reply) \ _(IP_ADDRESS_DETAILS, ip_address_details) \ _(IP_DETAILS, ip_details) \ @@ -6607,8 +6634,9 @@ api_l2_flags (vat_main_t * vam) unformat_input_t *i = vam->input; vl_api_l2_flags_t *mp; u32 sw_if_index; - u32 feature_bitmap = 0; + u32 flags = 0; u8 sw_if_index_set = 0; + u8 is_set = 0; int ret; /* Parse args required to build the message */ @@ -6628,13 +6656,19 @@ api_l2_flags (vat_main_t * vam) break; } else if (unformat (i, "learn")) - feature_bitmap |= L2INPUT_FEAT_LEARN; + flags |= L2_LEARN; else if (unformat (i, "forward")) - feature_bitmap |= L2INPUT_FEAT_FWD; + flags |= L2_FWD; else if (unformat (i, "flood")) - feature_bitmap |= L2INPUT_FEAT_FLOOD; + flags |= L2_FLOOD; else if (unformat (i, "uu-flood")) - feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + flags |= L2_UU_FLOOD; + else if (unformat (i, "arp-term")) + flags |= L2_ARP_TERM; + else if (unformat (i, "off")) + is_set = 0; + else if (unformat (i, "disable")) + is_set = 0; else break; } @@ -6648,7 +6682,8 @@ api_l2_flags (vat_main_t * vam) M (L2_FLAGS, mp); mp->sw_if_index = ntohl (sw_if_index); - mp->feature_bitmap = ntohl (feature_bitmap); + mp->feature_bitmap = ntohl (flags); + mp->is_set = is_set; S (mp); W (ret); @@ -12534,6 +12569,42 @@ api_want_ip6_nd_events (vat_main_t * vam) return ret; } +static int +api_want_l2_macs_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_l2_macs_events_t *mp; + u8 enable_disable = 1; + u32 scan_delay = 0; + u32 max_macs_in_event = 0; + u32 learn_limit = 0; + int ret; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "learn-limit %d", &learn_limit)) + ; + else if (unformat (line_input, "scan-delay %d", &scan_delay)) + ; + else if (unformat (line_input, "max-entries %d", &max_macs_in_event)) + ; + else if (unformat (line_input, "disable")) + enable_disable = 0; + else + break; + } + + M (WANT_L2_MACS_EVENTS, mp); + mp->enable_disable = enable_disable; + mp->pid = htonl (getpid ()); + mp->learn_limit = htonl (learn_limit); + mp->scan_delay = (u8) scan_delay; + mp->max_macs_in_event = (u8) (max_macs_in_event / 10); + S (mp); + W (ret); + return ret; +} + static int api_input_acl_set_interface (vat_main_t * vam) { @@ -19831,7 +19902,7 @@ _(l2fib_add_del, \ _(l2fib_flush_bd, "bd_id ") \ _(l2fib_flush_int, " | sw_if_index ") \ _(l2_flags, \ - "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood]\n") \ + "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ _(bridge_flags, \ "bd_id [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ _(tap_connect, \ @@ -19974,6 +20045,7 @@ _(input_acl_set_interface, \ " [l2-table ] [del]") \ _(want_ip4_arp_events, "address [del]") \ _(want_ip6_nd_events, "address [del]") \ +_(want_l2_macs_events, "[disable] [learn-limit ] [scan-delay ] [max-entries ]") \ _(ip_address_dump, "(ipv4 | ipv6) ( | sw_if_index )") \ _(ip_dump, "ipv4 | ipv6") \ _(ipsec_spd_add_del, "spd_id [del]") \ diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h index 747c65e7..22522f34 100644 --- a/src/vnet/api_errno.h +++ b/src/vnet/api_errno.h @@ -112,8 +112,9 @@ _(BD_ALREADY_EXISTS, -119, "Bridge domain already exists") \ _(BD_IN_USE, -120, "Bridge domain has member interfaces") \ _(BD_NOT_MODIFIABLE, -121, "Bridge domain 0 can't be deleted/modified") \ _(BD_ID_EXCEED_MAX, -122, "Bridge domain ID exceed 16M limit") \ -_(UNSUPPORTED, -123, "Unsupported") \ -_(SUBIF_DOESNT_EXIST, -124, "Subinterface doesn't exist") +_(SUBIF_DOESNT_EXIST, -123, "Subinterface doesn't exist") \ +_(L2_MACS_EVENT_CLINET_PRESENT, -124, "Client already exist for L2 MACs events") \ +_(UNSUPPORTED, -125, "Unsupported") typedef enum { diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index bb3990c6..e508bfb5 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -133,12 +133,64 @@ autoreply define l2fib_add_del u8 bvi_mac; }; -/** \brief Set L2 flags request !!! TODO - need more info, feature bits in l2_input.h +/** \brief Register to recive L2 MAC events for leanred and aged MAC + Will also change MAC learn limit to L2LEARN_INFORM_LIMIT + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param learn_limit - MAC learn limit, 0 => default to 1000 + @param scan_delay - event scan delay in 10 msec unit, 0 => default to 100 msec + @param max_macs_in_event - in units of 10 mac entries, 0 => default to 100 entries + @param enable_disable - 1 => register for MAC events, 0 => cancel registration + @param pid - sender's pid +*/ +autoreply define want_l2_macs_events +{ + u32 client_index; + u32 context; + u32 learn_limit; + u8 scan_delay; + u8 max_macs_in_event; + u8 enable_disable; + u32 pid; +}; + +/** \brief Entry for learned or aged MAC in L2 MAC Events + @param sw_if_index - sw_if_index in the domain + @param mac_addr - mac_address + @is_del - 0 => newly learned MAC, 1 => aged out MAC +*/ +typeonly define mac_entry +{ + u32 sw_if_index; + u8 mac_addr[6]; + u8 is_del; + u8 spare; +}; + +/** \brief L2 MAC event for a list of learned or aged MACs + @param client_index - opaque cookie to identify the sender + @param pid - client pid registered to receive notification + @param n_macs - number of learned/aged MAC enntries + @param mac - array of learned/aged MAC entries +*/ +define l2_macs_event +{ + u32 client_index; + u32 pid; + u32 n_macs; + vl_api_mac_entry_t mac[n_macs]; +}; + +/** \brief Set interface L2 flags (such as L2_LEARN, L2_FWD, + L2_FLOOD, L2_UU_FLOOD, or L2_ARP_TERM bits). This can be used + to disable one or more of the features represented by the + flag bits on an interface to override what is set as default + for all interfaces in the bridge domain @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param sw_if_index - interface @param is_set - if non-zero, set the bits, else clear them - @param feature_bitmap - non-zero bits to set or clear + @param feature_bitmap - non-zero bits (as above) to set or clear */ define l2_flags { @@ -149,9 +201,10 @@ define l2_flags u32 feature_bitmap; }; -/** \brief Set L2 bits response +/** \brief Set interface L2 flags response @param context - sender context, to match reply w/ request @param retval - return code for the set l2 bits request + @param resulting_feature_bitmap - the internal l2 feature bitmap after the request is implemented */ define l2_flags_reply { @@ -250,12 +303,12 @@ manual_print manual_endian define bridge_domain_details }; /** \brief Set bridge flags (such as L2_LEARN, L2_FWD, L2_FLOOD, - L2_UU_FLOOD, or L2_ARP_TERM) request + L2_UU_FLOOD, or L2_ARP_TERM bits) request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param bd_id - the bridge domain to set the flags for @param is_set - if non-zero, set the flags, else clear them - @param feature_bitmap - bits that are non-zero to set or clear + @param feature_bitmap - bits (as above) that are non-zero to set or clear */ define bridge_flags { @@ -269,7 +322,7 @@ define bridge_flags /** \brief Set bridge flags response @param context - sender context, to match reply w/ request @param retval - return code for the set bridge flags request - @param resulting_feature_bitmap - the feature bitmap value after the request is implemented + @param resulting_feature_bitmap - the internal L2 feature bitmap after the request is implemented */ define bridge_flags_reply { diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index a0b40d6d..c81cbad7 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -55,6 +56,7 @@ _(L2FIB_FLUSH_ALL, l2fib_flush_all) \ _(L2FIB_FLUSH_INT, l2fib_flush_int) \ _(L2FIB_FLUSH_BD, l2fib_flush_bd) \ _(L2FIB_ADD_DEL, l2fib_add_del) \ +_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \ _(L2_FLAGS, l2_flags) \ _(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \ _(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \ @@ -221,8 +223,8 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) goto bad_sw_if_index; } } - u32 static_mac = mp->static_mac ? 1 : 0; - u32 bvi_mac = mp->bvi_mac ? 1 : 0; + u8 static_mac = mp->static_mac ? 1 : 0; + u8 bvi_mac = mp->bvi_mac ? 1 : 0; l2fib_add_fwd_entry (mac, bd_index, sw_if_index, static_mac, bvi_mac); } @@ -237,6 +239,58 @@ vl_api_l2fib_add_del_t_handler (vl_api_l2fib_add_del_t * mp) REPLY_MACRO (VL_API_L2FIB_ADD_DEL_REPLY); } +static void +vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t * mp) +{ + int rv = 0; + vl_api_want_l2_macs_events_reply_t *rmp; + l2learn_main_t *lm = &l2learn_main; + l2fib_main_t *fm = &l2fib_main; + u32 pid = ntohl (mp->pid); + u32 learn_limit = ntohl (mp->learn_limit); + + if (mp->enable_disable) + { + if (lm->client_pid == 0) + { + lm->client_pid = pid; + lm->client_index = mp->client_index; + + if (mp->max_macs_in_event) + fm->max_macs_in_event = mp->max_macs_in_event * 10; + else + fm->max_macs_in_event = L2FIB_EVENT_MAX_MACS_DEFAULT; + + if (mp->scan_delay) + fm->event_scan_delay = (f64) (mp->scan_delay) * 10e-3; + else + fm->event_scan_delay = L2FIB_EVENT_SCAN_DELAY_DEFAULT; + + /* change learn limit and flush all learned MACs */ + if (learn_limit && (learn_limit < L2LEARN_DEFAULT_LIMIT)) + lm->global_learn_limit = learn_limit; + else + lm->global_learn_limit = L2FIB_EVENT_LEARN_LIMIT_DEFAULT; + + l2fib_flush_all_mac (vlib_get_main ()); + } + else if (lm->client_pid != pid) + { + rv = VNET_API_ERROR_L2_MACS_EVENT_CLINET_PRESENT; + goto exit; + } + } + else if (lm->client_pid) + { + lm->client_pid = 0; + lm->client_index = 0; + lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT; + } + +exit: + REPLY_MACRO (VL_API_WANT_L2_MACS_EVENTS_REPLY); +} + static void vl_api_l2fib_flush_int_t_handler (vl_api_l2fib_flush_int_t * mp) { @@ -293,8 +347,25 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp) VALIDATE_SW_IF_INDEX (mp); u32 sw_if_index = ntohl (mp->sw_if_index); - u32 flags = ntohl (mp->feature_bitmap) & L2INPUT_VALID_MASK; - rbm = l2input_intf_bitmap_enable (sw_if_index, flags, mp->is_set); + u32 flags = ntohl (mp->feature_bitmap); + u32 bitmap = 0; + + if (flags & L2_LEARN) + bitmap |= L2INPUT_FEAT_LEARN; + + if (flags & L2_FWD) + bitmap |= L2INPUT_FEAT_FWD; + + if (flags & L2_FLOOD) + bitmap |= L2INPUT_FEAT_FLOOD; + + if (flags & L2_UU_FLOOD) + bitmap |= L2INPUT_FEAT_UU_FLOOD; + + if (flags & L2_ARP_TERM) + bitmap |= L2INPUT_FEAT_ARP_TERM; + + rbm = l2input_intf_bitmap_enable (sw_if_index, bitmap, mp->is_set); BAD_SW_IF_INDEX_LABEL; @@ -455,13 +526,13 @@ vl_api_bridge_flags_t_handler (vl_api_bridge_flags_t * mp) goto out; } - bd_set_flags (vm, bd_index, flags, mp->is_set); + u32 bitmap = bd_set_flags (vm, bd_index, flags, mp->is_set); out: /* *INDENT-OFF* */ REPLY_MACRO2(VL_API_BRIDGE_FLAGS_REPLY, ({ - rmp->resulting_feature_bitmap = ntohl(flags); + rmp->resulting_feature_bitmap = ntohl(bitmap); })); /* *INDENT-ON* */ } diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index a87d02f2..6e0db058 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -263,7 +263,7 @@ bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable) bd_config->feature_bitmap &= ~feature_bitmap; } - return 0; + return bd_config->feature_bitmap; } /** @@ -328,12 +328,7 @@ bd_learn (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_LEARN, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_LEARN, enable); done: return error; @@ -397,12 +392,7 @@ bd_fwd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_FWD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_FWD, enable); done: return error; @@ -468,12 +458,7 @@ bd_flood (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_FLOOD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_FLOOD, enable); done: return error; @@ -538,12 +523,7 @@ bd_uu_flood (vlib_main_t * vm, } /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_UU_FLOOD, enable); done: return error; @@ -605,12 +585,7 @@ bd_arp_term (vlib_main_t * vm, enable = 0; /* set the bridge domain flag */ - if (bd_set_flags (vm, bd_index, L2_ARP_TERM, enable)) - { - error = - clib_error_return (0, "bridge-domain id %d out of range", bd_index); - goto done; - } + bd_set_flags (vm, bd_index, L2_ARP_TERM, enable); done: return error; diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 7e59b098..8aa0ac29 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -31,6 +31,17 @@ #include +#include +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + /** * @file * @brief Ethernet MAC Address FIB Table Management. @@ -117,6 +128,7 @@ show_l2fib (vlib_main_t * vm, int i, j, k; u8 verbose = 0; u8 raw = 0; + u8 learn = 0; u32 bd_id, bd_index = ~0; u8 now = (u8) (vlib_time_now (vm) / 60); u8 *s = 0; @@ -127,12 +139,18 @@ show_l2fib (vlib_main_t * vm, verbose = 1; else if (unformat (input, "bd_index %d", &bd_index)) verbose = 1; + else if (unformat (input, "learn")) + { + learn = 1; + verbose = 0; + } else if (unformat (input, "bd_id %d", &bd_id)) { uword *p = hash_get (bdm->bd_index_by_bd_id, bd_id); if (p) { - verbose = 1; + if (learn == 0) + verbose = 1; bd_index = p[0]; } else @@ -155,7 +173,7 @@ show_l2fib (vlib_main_t * vm, if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) continue; - if (verbose && first_entry) + if ((verbose || learn) && first_entry) { first_entry = 0; vlib_cli_output (vm, @@ -168,13 +186,19 @@ show_l2fib (vlib_main_t * vm, key.raw = v->kvp[k].key; result.raw = v->kvp[k].value; - if (verbose + if ((verbose || learn) & ((bd_index >> 31) || (bd_index == key.fields.bd_index))) { + if (learn && result.fields.age_not) + { + total_entries++; + continue; /* skip provisioned macs */ + } + bd_config = vec_elt_at_index (l2input_main.bd_configs, key.fields.bd_index); - if (bd_config->mac_age && !result.fields.static_mac) + if (bd_config->mac_age && !result.fields.age_not) { i16 delta = now - result.fields.timestamp; delta += delta < 0 ? 256 : 0; @@ -206,9 +230,19 @@ show_l2fib (vlib_main_t * vm, if (total_entries == 0) vlib_cli_output (vm, "no l2fib entries"); else - vlib_cli_output (vm, - "%lld l2fib entries with %d learned (or non-static) entries", - total_entries, l2learn_main.global_learn_count); + { + l2learn_main_t *lm = &l2learn_main; + vlib_cli_output (vm, "L2FIB total/learned entries: %d/%d " + "Last scan time: %.4esec Learn limit: %d ", + total_entries, lm->global_learn_count, + msm->age_scan_duration, lm->global_learn_limit); + if (lm->client_pid) + vlib_cli_output (vm, "L2MAC events client PID: %d " + "Last e-scan time: %.4esec Delay: %.2esec " + "Max macs in event: %d", + lm->client_pid, msm->evt_scan_duration, + msm->event_scan_delay, msm->max_macs_in_event); + } if (raw) vlib_cli_output (vm, "Raw Hash Table:\n%U\n", @@ -242,7 +276,7 @@ show_l2fib (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_l2fib_cli, static) = { .path = "show l2fib", - .short_help = "show l2fib [verbose | bd_id | bd_index | raw]", + .short_help = "show l2fib [verbose | learn | bd_id | bd_index | raw", .function = show_l2fib, }; /* *INDENT-ON* */ @@ -309,36 +343,39 @@ l2fib_cur_seq_num (u32 bd_index, u32 sw_if_index) */ void l2fib_add_entry (u64 mac, u32 bd_index, - u32 sw_if_index, u32 static_mac, u32 filter_mac, u32 bvi_mac) + u32 sw_if_index, u8 static_mac, u8 filter_mac, u8 bvi_mac) { l2fib_entry_key_t key; l2fib_entry_result_t result; __attribute__ ((unused)) u32 bucket_contents; - l2fib_main_t *mp = &l2fib_main; + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; BVT (clib_bihash_kv) kv; /* set up key */ key.raw = l2fib_make_key ((u8 *) & mac, bd_index); + /* check if entry alread exist */ + if (BV (clib_bihash_search) (&fm->mac_table, &kv, &kv)) + { + /* decrement counter if overwriting a learned mac */ + result.raw = kv.value; + if ((result.fields.age_not == 0) && (lm->global_learn_count)) + lm->global_learn_count--; + } + /* set up result */ result.raw = 0; /* clear all fields */ result.fields.sw_if_index = sw_if_index; result.fields.static_mac = static_mac; result.fields.filter = filter_mac; result.fields.bvi = bvi_mac; - if (!static_mac) - result.fields.sn = l2fib_cur_seq_num (bd_index, sw_if_index); + result.fields.age_not = 1; /* no aging for provisioned entry */ kv.key = key.raw; kv.value = result.raw; - BV (clib_bihash_add_del) (&mp->mac_table, &kv, 1 /* is_add */ ); - - /* increment counter if dynamically learned mac */ - if (result.fields.static_mac == 0) - { - l2learn_main.global_learn_count++; - } + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1 /* is_add */ ); } /** @@ -630,13 +667,8 @@ l2fib_del_entry_by_key (u64 raw_key) result.raw = kv.value; /* decrement counter if dynamically learned mac */ - if (result.fields.static_mac == 0) - { - if (l2learn_main.global_learn_count > 0) - { - l2learn_main.global_learn_count--; - } - } + if ((result.fields.age_not == 0) && (l2learn_main.global_learn_count)) + l2learn_main.global_learn_count--; /* Remove entry from hash table */ BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ ); @@ -910,111 +942,273 @@ BVT (clib_bihash) * get_mac_table (void) return &mp->mac_table; } +static_always_inline void * +allocate_mac_evt_buf (u32 client, u32 client_index) +{ + l2fib_main_t *fm = &l2fib_main; + vl_api_l2_macs_event_t *mp = vl_msg_api_alloc + (sizeof (*mp) + (fm->max_macs_in_event * sizeof (vl_api_mac_entry_t))); + mp->_vl_msg_id = htons (VL_API_L2_MACS_EVENT); + mp->pid = htonl (client); + mp->client_index = client_index; + return mp; +} + +static_always_inline f64 +l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only) +{ + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; + + BVT (clib_bihash) * h = &fm->mac_table; + int i, j, k; + f64 last_start = start_time; + f64 accum_t = 0; + f64 delta_t = 0; + u32 evt_idx = 0; + u32 learn_count = 0; + u32 client = lm->client_pid; + u32 cl_idx = lm->client_index; + vl_api_l2_macs_event_t *mp = 0; + unix_shared_memory_queue_t *q = 0; + + if (client) + { + mp = allocate_mac_evt_buf (client, cl_idx); + q = vl_api_client_index_to_input_queue (lm->client_index); + } + + for (i = 0; i < h->nbuckets; i++) + { + /* allow no more than 20us without a pause */ + delta_t = vlib_time_now (vm) - last_start; + if (delta_t > 20e-6) + { + vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */ + last_start = vlib_time_now (vm); + accum_t += delta_t; + } + + if (i < (h->nbuckets - 3)) + { + BVT (clib_bihash_bucket) * b = &h->buckets[i + 3]; + CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); + b = &h->buckets[i + 1]; + if (b->offset) + { + BVT (clib_bihash_value) * v = + BV (clib_bihash_get_value) (h, b->offset); + CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); + } + } + + BVT (clib_bihash_bucket) * b = &h->buckets[i]; + if (b->offset == 0) + continue; + BVT (clib_bihash_value) * v = BV (clib_bihash_get_value) (h, b->offset); + for (j = 0; j < (1 << b->log2_pages); j++) + { + for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) + { + if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) + continue; + + l2fib_entry_key_t key = {.raw = v->kvp[k].key }; + l2fib_entry_result_t result = {.raw = v->kvp[k].value }; + + if (result.fields.age_not == 0) + learn_count++; + + if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event)) + { + /* evet message full, sent it and start a new one */ + if (q && (q->cursize < q->maxsize)) + { + mp->n_macs = htonl (evt_idx); + vl_msg_api_send_shmem (q, (u8 *) & mp); + mp = allocate_mac_evt_buf (client, cl_idx); + } + else + { + clib_warning ("MAC event to pid %d queue stuffed!" + " %d MAC entries lost", client, evt_idx); + } + evt_idx = 0; + } + + if (client) + { + if (result.fields.lrn_evt) + { + /* copy mac entry to event msg */ + clib_memcpy (mp->mac[evt_idx].mac_addr, key.fields.mac, + 6); + mp->mac[evt_idx].is_del = 0; + mp->mac[evt_idx].sw_if_index = + htonl (result.fields.sw_if_index); + /* clear event bit and update mac entry */ + result.fields.lrn_evt = 0; + BVT (clib_bihash_kv) kv; + kv.key = key.raw; + kv.value = result.raw; + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 1); + evt_idx++; + continue; /* skip aging */ + } + } + + if (event_only || result.fields.age_not) + continue; /* skip aging - static_mac alsways age_not */ + + /* start aging processing */ + u32 bd_index = key.fields.bd_index; + u32 sw_if_index = result.fields.sw_if_index; + u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index).as_u16; + if (result.fields.sn.as_u16 != sn) + goto age_out; /* stale mac */ + + l2_bridge_domain_t *bd_config = + vec_elt_at_index (l2input_main.bd_configs, bd_index); + + if (bd_config->mac_age == 0) + continue; /* skip aging */ + + i16 delta = (u8) (start_time / 60) - result.fields.timestamp; + delta += delta < 0 ? 256 : 0; + + if (delta < bd_config->mac_age) + continue; /* still valid */ + + age_out: + if (client) + { + /* copy mac entry to event msg */ + clib_memcpy (mp->mac[evt_idx].mac_addr, key.fields.mac, 6); + mp->mac[evt_idx].is_del = 1; + mp->mac[evt_idx].sw_if_index = + htonl (result.fields.sw_if_index); + evt_idx++; + } + /* delete mac entry */ + BVT (clib_bihash_kv) kv; + kv.key = key.raw; + BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0); + learn_count--; + } + v++; + } + } + + /* keep learn count consistent */ + l2learn_main.global_learn_count = learn_count; + + if (mp) + { + /* send any outstanding mac event message else free message buffer */ + if (evt_idx) + { + if (q && (q->cursize < q->maxsize)) + { + mp->n_macs = htonl (evt_idx); + vl_msg_api_send_shmem (q, (u8 *) & mp); + } + else + { + clib_warning ("MAC event to pid %d queue stuffed!" + " %d MAC entries lost", client, evt_idx); + vl_msg_api_free (mp); + } + } + else + vl_msg_api_free (mp); + } + return delta_t + accum_t; +} + +/* Type of scan */ +#define SCAN_MAC_AGE 0 +#define SCAN_MAC_EVENT 1 + +/* Maximum f64 value */ +#define TIME_MAX (1.7976931348623157e+308) + static uword l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) { uword event_type, *event_data = 0; - l2fib_main_t *msm = &l2fib_main; + l2fib_main_t *fm = &l2fib_main; + l2learn_main_t *lm = &l2learn_main; bool enabled = 0; - f64 start_time, last_run_duration = 0, t; + bool scan = SCAN_MAC_AGE; /* SCAN_FOR_AGE or SCAN_FOR_EVENT */ + f64 start_time, next_age_scan_time = TIME_MAX; while (1) { if (enabled) - vlib_process_wait_for_event_or_clock (vm, 60 - last_run_duration); + { + if (lm->client_pid) /* mac event client waiting */ + vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay); + else /* agin only */ + { + f64 t = next_age_scan_time - vlib_time_now (vm); + if (t < fm->event_scan_delay) + t = fm->event_scan_delay; + vlib_process_wait_for_event_or_clock (vm, t); + } + } else vlib_process_wait_for_event (vm); event_type = vlib_process_get_events (vm, &event_data); vec_reset_length (event_data); + start_time = vlib_time_now (vm); + switch (event_type) { - case ~0: + case ~0: /* timer expired */ + if ((lm->client_pid == 0) || (start_time >= next_age_scan_time)) + { + scan = SCAN_MAC_AGE; + if (enabled) + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; + else + next_age_scan_time = TIME_MAX; + } + else + scan = SCAN_MAC_EVENT; break; + case L2_MAC_AGE_PROCESS_EVENT_START: + scan = SCAN_MAC_AGE; + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; enabled = 1; break; + case L2_MAC_AGE_PROCESS_EVENT_STOP: enabled = 0; + next_age_scan_time = TIME_MAX; + l2fib_main.age_scan_duration = 0; + l2fib_main.evt_scan_duration = 0; continue; + case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS: - enabled = 0; + scan = SCAN_MAC_AGE; + if (enabled) + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; + else + next_age_scan_time = TIME_MAX; break; + default: ASSERT (0); } - last_run_duration = start_time = vlib_time_now (vm); - BVT (clib_bihash) * h = &msm->mac_table; - int i, j, k; - for (i = 0; i < h->nbuckets; i++) - { - /* Allow no more than 10us without a pause */ - t = vlib_time_now (vm); - if (t > start_time + 10e-6) - { - vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */ - start_time = vlib_time_now (vm); - } - - if (i < (h->nbuckets - 3)) - { - BVT (clib_bihash_bucket) * b = &h->buckets[i + 3]; - CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD); - b = &h->buckets[i + 1]; - if (b->offset) - { - BVT (clib_bihash_value) * v = - BV (clib_bihash_get_value) (h, b->offset); - CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD); - } - } - - BVT (clib_bihash_bucket) * b = &h->buckets[i]; - if (b->offset == 0) - continue; - BVT (clib_bihash_value) * v = - BV (clib_bihash_get_value) (h, b->offset); - for (j = 0; j < (1 << b->log2_pages); j++) - { - for (k = 0; k < BIHASH_KVP_PER_PAGE; k++) - { - if (v->kvp[k].key == ~0ULL && v->kvp[k].value == ~0ULL) - continue; - - l2fib_entry_key_t key = {.raw = v->kvp[k].key }; - l2fib_entry_result_t result = {.raw = v->kvp[k].value }; - - if (result.fields.static_mac) - continue; - - u32 bd_index = key.fields.bd_index; - u32 sw_if_index = result.fields.sw_if_index; - u16 sn = l2fib_cur_seq_num (bd_index, sw_if_index).as_u16; - if (result.fields.sn.as_u16 != sn) - { - l2fib_del_entry_by_key (key.raw); - continue; - } - l2_bridge_domain_t *bd_config = - vec_elt_at_index (l2input_main.bd_configs, bd_index); - - if (bd_config->mac_age == 0) - continue; - - i16 delta = - (u8) (start_time / 60) - result.fields.timestamp; - delta += delta < 0 ? 256 : 0; - - if (delta > bd_config->mac_age) - l2fib_del_entry_by_key (key.raw); - } - v++; - } - } - last_run_duration = vlib_time_now (vm) - last_run_duration; + if (scan == SCAN_MAC_EVENT) + l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1); + else + l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0); } return 0; } diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index ee6f0dc5..49a8b5b6 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -27,6 +27,18 @@ #define L2FIB_NUM_BUCKETS (64 * 1024) #define L2FIB_MEMORY_SIZE (256<<20) +/* Ager scan interval is 1 minute for aging */ +#define L2FIB_AGE_SCAN_INTERVAL (60.0) + +/* MAC event scan delay is 100 msec unless specified by MAC event client */ +#define L2FIB_EVENT_SCAN_DELAY_DEFAULT (0.1) + +/* Max MACs in a event message is 100 unless specified by MAC event client */ +#define L2FIB_EVENT_MAX_MACS_DEFAULT (100) + +/* MAC event learn limit is 1000 unless specified by MAC event client */ +#define L2FIB_EVENT_LEARN_LIMIT_DEFAULT (1000) + typedef struct { @@ -36,6 +48,16 @@ typedef struct /* per swif vector of sequence number for interface based flush of MACs */ u8 *swif_seq_num; + /* last event or ager scan duration */ + f64 evt_scan_duration; + f64 age_scan_duration; + + /* delay between event scans, default to 100 msec */ + f64 event_scan_delay; + + /* max macs in evet message, default to 100 entries */ + u32 max_macs_in_event; + /* convenience variables */ vlib_main_t *vlib_main; vnet_main_t *vnet_main; @@ -89,12 +111,15 @@ typedef struct { struct { - u32 sw_if_index; /* output sw_if_index (L3 interface if bvi==1) */ + u32 sw_if_index; /* output sw_if_index (L3 intf if bvi==1) */ - u8 static_mac:1; /* static mac, no dataplane learning */ + u8 static_mac:1; /* static mac, no MAC move */ + u8 age_not:1; /* not subject to age */ u8 bvi:1; /* mac is for a bridged virtual interface */ u8 filter:1; /* drop packets to/from this mac */ - u8 unused1:5; + u8 lrn_evt:1; /* MAC learned to be sent in L2 MAC event */ + u8 unused:3; + u8 timestamp; /* timestamp for aging */ l2fib_seq_num_t sn; /* bd/int seq num */ } fields; @@ -348,11 +373,11 @@ void l2fib_clear_table (void); void l2fib_add_entry (u64 mac, u32 bd_index, - u32 sw_if_index, u32 static_mac, u32 drop_mac, u32 bvi_mac); + u32 sw_if_index, u8 static_mac, u8 drop_mac, u8 bvi_mac); static inline void -l2fib_add_fwd_entry (u64 mac, u32 bd_index, u32 sw_if_index, u32 static_mac, - u32 bvi_mac) +l2fib_add_fwd_entry (u64 mac, u32 bd_index, u32 sw_if_index, u8 static_mac, + u8 bvi_mac) { l2fib_add_entry (mac, bd_index, sw_if_index, static_mac, 0, bvi_mac); } diff --git a/src/vnet/l2/l2_fwd.c b/src/vnet/l2/l2_fwd.c index 8140728b..2bb7307c 100644 --- a/src/vnet/l2/l2_fwd.c +++ b/src/vnet/l2/l2_fwd.c @@ -141,8 +141,9 @@ l2fwd_process (vlib_main_t * vm, vnet_buffer (b0)->sw_if_index[VLIB_TX] = result0->fields.sw_if_index; *next0 = L2FWD_NEXT_L2_OUTPUT; int l2fib_seq_num_valid = 1; + /* check l2fib seq num for stale entries */ - if (!result0->fields.static_mac) + if (!result0->fields.age_not) { l2fib_seq_num_t in_sn = {.as_u16 = vnet_buffer (b0)->l2.l2fib_sn }; l2fib_seq_num_t expected_sn = { diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 65406292..47c036b0 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -123,11 +123,9 @@ l2learn_process (vlib_node_runtime_t * node, /* Check mac table lookup result */ if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) { - /* - * The entry was in the table, and the sw_if_index matched, the normal case - */ + /* Entry in L2FIB with matching sw_if_index matched - normal fast path */ counter_base[L2LEARN_ERROR_HIT] += 1; - int update = !result0->fields.static_mac && + int update = !result0->fields.age_not && /* static_mac always age_not */ (result0->fields.timestamp != timestamp || result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn); @@ -136,10 +134,10 @@ l2learn_process (vlib_node_runtime_t * node, } else if (result0->raw == ~0) { - /* The entry was not in table, so add it */ + /* Entry not in L2FIB - add it */ counter_base[L2LEARN_ERROR_MISS] += 1; - if (msm->global_learn_count == msm->global_learn_limit) + if (msm->global_learn_count >= msm->global_learn_limit) { /* * Global limit reached. Do not learn the mac but forward the packet. @@ -149,15 +147,22 @@ l2learn_process (vlib_node_runtime_t * node, return; } + /* Do not learn if mac is 0 */ + l2fib_entry_key_t key = *key0; + key.fields.bd_index = 0; + if (key.raw == 0) + return; + /* It is ok to learn */ msm->global_learn_count++; result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; + result0->fields.lrn_evt = (msm->client_pid != 0); cached_key->raw = ~0; /* invalidate the cache */ } else { - /* The entry was in the table, but with the wrong sw_if_index mapping (mac move) */ + /* Entry in L2FIB with different sw_if_index - mac move or filter */ if (result0->fields.filter) { ASSERT (result0->fields.sw_if_index == ~0); @@ -167,8 +172,6 @@ l2learn_process (vlib_node_runtime_t * node, return; } - counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; - if (result0->fields.static_mac) { /* @@ -185,6 +188,13 @@ l2learn_process (vlib_node_runtime_t * node, * TODO: check global/bridge domain/interface learn limits */ result0->fields.sw_if_index = sw_if_index0; + if (result0->fields.age_not) /* The mac was provisioned */ + { + msm->global_learn_count++; + result0->fields.age_not = 0; + } + result0->fields.lrn_evt = (msm->client_pid != 0); + counter_base[L2LEARN_ERROR_MAC_MOVE] += 1; } /* Update the entry */ @@ -479,7 +489,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (l2learn_node, l2learn_node_fn) * Set the default number of dynamically learned macs to the number * of buckets. */ - mp->global_learn_limit = L2FIB_NUM_BUCKETS * 16; + mp->global_learn_limit = L2LEARN_DEFAULT_LIMIT; return 0; } diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index 0d95de04..000ab59e 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -34,6 +34,10 @@ typedef struct /* maximum number of dynamically learned mac entries */ u32 global_learn_limit; + /* client waiting for L2 MAC events for learned and aged MACs */ + u32 client_pid; + u32 client_index; + /* Next nodes for each feature */ u32 feat_next_node_index[32]; @@ -42,6 +46,7 @@ typedef struct vnet_main_t *vnet_main; } l2learn_main_t; +#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 16) l2learn_main_t l2learn_main; diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index 520361f6..a57799cb 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -373,10 +373,19 @@ vl_api_l2_flags_t_print (vl_api_l2_flags_t * mp, void *handle) s = format (s, "sw_if_index %d ", ntohl (mp->sw_if_index)); -#define _(a,b) \ - if (flags & L2INPUT_FEAT_ ## a) s = format (s, #a " "); - foreach_l2input_feat; -#undef _ + if (flags & L2_LEARN) + s = format (s, "learn "); + if (flags & L2_FWD) + s = format (s, "forward "); + if (flags & L2_FLOOD) + s = format (s, "flood "); + if (flags & L2_UU_FLOOD) + s = format (s, "uu-flood "); + if (flags & L2_ARP_TERM) + s = format (s, "arp-term "); + + if (mp->is_set == 0) + s = format (s, "clear "); FINISH; } @@ -1783,6 +1792,21 @@ static void *vl_api_want_ip6_nd_events_t_print FINISH; } +static void *vl_api_want_l2_macs_events_t_print + (vl_api_want_l2_macs_events_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: want_l2_macs_events "); + s = format (s, "learn-limit %d ", ntohl (mp->learn_limit)); + s = format (s, "scan-delay %d ", (u32) mp->scan_delay); + s = format (s, "max-entries %d ", (u32) mp->max_macs_in_event * 10); + if (mp->enable_disable == 0) + s = format (s, "disable"); + + FINISH; +} + static void *vl_api_input_acl_set_interface_t_print (vl_api_input_acl_set_interface_t * mp, void *handle) { @@ -3066,6 +3090,7 @@ _(VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump) \ _(INTERFACE_NAME_RENUMBER, interface_name_renumber) \ _(WANT_IP4_ARP_EVENTS, want_ip4_arp_events) \ _(WANT_IP6_ND_EVENTS, want_ip6_nd_events) \ +_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \ _(INPUT_ACL_SET_INTERFACE, input_acl_set_interface) \ _(IP_ADDRESS_DUMP, ip_address_dump) \ _(IP_DUMP, ip_dump) \ -- cgit 1.2.3-korg From e531f4cb5766fbf27e7a8af8e19ccf667b53852b Mon Sep 17 00:00:00 2001 From: John Lo Date: Tue, 22 Aug 2017 09:16:50 -0400 Subject: Increase default MAC learn limit and check it in learn-update path 1. Increase default MAC learn limit from 1M to 8M entries. 2. Check MAC learn limit in MAC learning update path. 3. Allow disable of want_l2_macs_events to set MAC learn limit 4. Other minor cleanups Change-Id: I62438440937b5fa455e16f4a2e4d910277753395 Signed-off-by: John Lo --- src/vnet/l2/l2.api | 1 - src/vnet/l2/l2_api.c | 5 ++++- src/vnet/l2/l2_fib.c | 2 +- src/vnet/l2/l2_learn.c | 2 ++ src/vnet/l2/l2_learn.h | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index e508bfb5..9f97ebbe 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -134,7 +134,6 @@ autoreply define l2fib_add_del }; /** \brief Register to recive L2 MAC events for leanred and aged MAC - Will also change MAC learn limit to L2LEARN_INFORM_LIMIT @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param learn_limit - MAC learn limit, 0 => default to 1000 diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index c81cbad7..7e79d6fa 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -284,7 +284,10 @@ vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t * mp) { lm->client_pid = 0; lm->client_index = 0; - lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT; + if (learn_limit) + lm->global_learn_limit = learn_limit; + else + lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT; } exit: diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 8aa0ac29..9f4c823f 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -1021,7 +1021,7 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only) if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event)) { - /* evet message full, sent it and start a new one */ + /* event message full, send it and start a new one */ if (q && (q->cursize < q->maxsize)) { mp->n_macs = htonl (evt_idx); diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 47c036b0..623c2de2 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -131,6 +131,8 @@ l2learn_process (vlib_node_runtime_t * node, if (PREDICT_TRUE (!update)) return; + else if (msm->global_learn_count > msm->global_learn_limit) + return; /* Above learn limit - do not update */ } else if (result0->raw == ~0) { diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index 000ab59e..d6f41d40 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -46,7 +46,7 @@ typedef struct vnet_main_t *vnet_main; } l2learn_main_t; -#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 16) +#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 128) l2learn_main_t l2learn_main; -- cgit 1.2.3-korg From dbfa574a1d5ebb68a81fed20dcd4bb2f47c47066 Mon Sep 17 00:00:00 2001 From: John Lo Date: Sat, 2 Sep 2017 08:27:36 -0400 Subject: Improve L2FIB PDR/NDR performance (VPP-963) 1. Limit MAC entry update per l2-learn call to reduce update burst when wall clock advance to the the next minute so all MAC time stamps are behind current time needing update. 2. Optimize l2-learn node fast path code sequence. 3. Invalidate cache_key when update MAC entry. 4. Change L2 learn hit counter to L2 learn hit-update counter. 5. Increase L2FIB table memory size to 512MB to fit 4M entries 6. Set MAC learn limit at 4M entries Change-Id: I3075ee8fb59645a56850126bac2e3e6d341cef4d Signed-off-by: John Lo --- src/vnet/l2/l2_api.c | 2 +- src/vnet/l2/l2_fib.h | 2 +- src/vnet/l2/l2_learn.c | 42 +++++++++++++++++++++++++++--------------- src/vnet/l2/l2_learn.h | 2 +- 4 files changed, 30 insertions(+), 18 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 7e79d6fa..989081fb 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -284,7 +284,7 @@ vl_api_want_l2_macs_events_t_handler (vl_api_want_l2_macs_events_t * mp) { lm->client_pid = 0; lm->client_index = 0; - if (learn_limit) + if (learn_limit && (learn_limit < L2LEARN_DEFAULT_LIMIT)) lm->global_learn_limit = learn_limit; else lm->global_learn_limit = L2LEARN_DEFAULT_LIMIT; diff --git a/src/vnet/l2/l2_fib.h b/src/vnet/l2/l2_fib.h index 49a8b5b6..7cc2dc5e 100644 --- a/src/vnet/l2/l2_fib.h +++ b/src/vnet/l2/l2_fib.h @@ -25,7 +25,7 @@ * The size of the hash table */ #define L2FIB_NUM_BUCKETS (64 * 1024) -#define L2FIB_MEMORY_SIZE (256<<20) +#define L2FIB_MEMORY_SIZE (512<<20) /* Ager scan interval is 1 minute for aging */ #define L2FIB_AGE_SCAN_INTERVAL (60.0) diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 623c2de2..066bb54f 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -78,7 +78,7 @@ _(MISS, "L2 learn misses") \ _(MAC_MOVE, "L2 mac moves") \ _(MAC_MOVE_VIOLATE, "L2 mac move violations") \ _(LIMIT, "L2 not learned due to limit") \ -_(HIT, "L2 learn hits") \ +_(HIT_UPDATE, "L2 learn hit updates") \ _(FILTER_DROP, "L2 filter mac drops") typedef enum @@ -113,7 +113,7 @@ l2learn_process (vlib_node_runtime_t * node, u32 sw_if_index0, l2fib_entry_key_t * key0, l2fib_entry_key_t * cached_key, - u32 * bucket0, + u32 * count, l2fib_entry_result_t * result0, u32 * next0, u8 timestamp) { /* Set up the default next node (typically L2FWD) */ @@ -124,15 +124,24 @@ l2learn_process (vlib_node_runtime_t * node, if (PREDICT_TRUE (result0->fields.sw_if_index == sw_if_index0)) { /* Entry in L2FIB with matching sw_if_index matched - normal fast path */ - counter_base[L2LEARN_ERROR_HIT] += 1; - int update = !result0->fields.age_not && /* static_mac always age_not */ - (result0->fields.timestamp != timestamp || - result0->fields.sn.as_u16 != vnet_buffer (b0)->l2.l2fib_sn); + u32 dtime = timestamp - result0->fields.timestamp; + u32 dsn = result0->fields.sn.as_u16 - vnet_buffer (b0)->l2.l2fib_sn; + u32 check = dtime | dsn; + + if (PREDICT_TRUE (check == 0)) + return; /* MAC entry up to date */ + if (result0->fields.age_not) + return; /* Static MAC always age_not */ + if (msm->global_learn_count > msm->global_learn_limit) + return; /* Above learn limit - do not update */ - if (PREDICT_TRUE (!update)) + /* Limit updates per l2-learn node call to avoid prolonged update burst + * as dtime advance over 1 minute mark, unless more than 1 min behind */ + if ((*count > 2) && (dtime == 1)) return; - else if (msm->global_learn_count > msm->global_learn_limit) - return; /* Above learn limit - do not update */ + + counter_base[L2LEARN_ERROR_HIT_UPDATE] += 1; + *count += 1; } else if (result0->raw == ~0) { @@ -160,7 +169,6 @@ l2learn_process (vlib_node_runtime_t * node, result0->raw = 0; /* clear all fields */ result0->fields.sw_if_index = sw_if_index0; result0->fields.lrn_evt = (msm->client_pid != 0); - cached_key->raw = ~0; /* invalidate the cache */ } else { @@ -207,6 +215,9 @@ l2learn_process (vlib_node_runtime_t * node, kv.key = key0->raw; kv.value = result0->raw; BV (clib_bihash_add_del) (msm->mac_table, &kv, 1 /* is_add */ ); + + /* Invalidate the cache */ + cached_key->raw = ~0; } @@ -223,6 +234,7 @@ l2learn_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, l2fib_entry_key_t cached_key; l2fib_entry_result_t cached_result; u8 timestamp = (u8) (vlib_time_now (vm) / 60); + u32 count = 0; from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; /* number of packets to process */ @@ -358,19 +370,19 @@ l2learn_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, l2learn_process (node, msm, &em->counters[node_counter_base_index], b0, sw_if_index0, &key0, &cached_key, - &bucket0, &result0, &next0, timestamp); + &count, &result0, &next0, timestamp); l2learn_process (node, msm, &em->counters[node_counter_base_index], b1, sw_if_index1, &key1, &cached_key, - &bucket1, &result1, &next1, timestamp); + &count, &result1, &next1, timestamp); l2learn_process (node, msm, &em->counters[node_counter_base_index], b2, sw_if_index2, &key2, &cached_key, - &bucket2, &result2, &next2, timestamp); + &count, &result2, &next2, timestamp); l2learn_process (node, msm, &em->counters[node_counter_base_index], b3, sw_if_index3, &key3, &cached_key, - &bucket3, &result3, &next3, timestamp); + &count, &result3, &next3, timestamp); /* verify speculative enqueues, maybe switch current next frame */ /* if next0==next1==next_index then nothing special needs to be done */ @@ -425,7 +437,7 @@ l2learn_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node, l2learn_process (node, msm, &em->counters[node_counter_base_index], b0, sw_if_index0, &key0, &cached_key, - &bucket0, &result0, &next0, timestamp); + &count, &result0, &next0, timestamp); /* verify speculative enqueue, maybe switch current next frame */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, diff --git a/src/vnet/l2/l2_learn.h b/src/vnet/l2/l2_learn.h index d6f41d40..3aaf48e2 100644 --- a/src/vnet/l2/l2_learn.h +++ b/src/vnet/l2/l2_learn.h @@ -46,7 +46,7 @@ typedef struct vnet_main_t *vnet_main; } l2learn_main_t; -#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 128) +#define L2LEARN_DEFAULT_LIMIT (L2FIB_NUM_BUCKETS * 64) l2learn_main_t l2learn_main; -- cgit 1.2.3-korg From 483041413842e04f6958ae8cae4135dc2262d43b Mon Sep 17 00:00:00 2001 From: Jerome Tollet Date: Tue, 5 Sep 2017 12:13:22 +0100 Subject: Support for bridge domain free text tag Change-Id: I9a75fdafd0c1d87b6f071fda5b77ff5f6b79deb7 Signed-off-by: Jerome Tollet --- src/vnet/l2/l2.api | 2 ++ src/vnet/l2/l2_api.c | 8 ++++++++ src/vnet/l2/l2_bd.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/vnet/l2/l2_bd.h | 5 +++++ 4 files changed, 66 insertions(+), 2 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index 9f97ebbe..baf830fa 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -249,6 +249,7 @@ autoreply define bridge_domain_add_del u8 learn; u8 arp_term; u8 mac_age; + u8 bd_tag[64]; u8 is_add; }; @@ -296,6 +297,7 @@ manual_print manual_endian define bridge_domain_details u8 learn; u8 arp_term; u8 mac_age; + u8 bd_tag[64]; u32 bvi_sw_if_index; u32 n_sw_ifs; vl_api_bridge_domain_sw_if_t sw_if_details[n_sw_ifs]; diff --git a/src/vnet/l2/l2_api.c b/src/vnet/l2/l2_api.c index 989081fb..20d6ab32 100644 --- a/src/vnet/l2/l2_api.c +++ b/src/vnet/l2/l2_api.c @@ -420,6 +420,7 @@ vl_api_bridge_domain_add_del_t_handler (vl_api_bridge_domain_add_del_t * mp) .arp_term = mp->arp_term, .mac_age = mp->mac_age, .bd_id = ntohl (mp->bd_id), + .bd_tag = mp->bd_tag }; int rv = bd_add_del (&a); @@ -451,6 +452,13 @@ send_bridge_domain_details (l2input_main_t * l2im, mp->arp_term = bd_feature_arp_term (bd_config); mp->bvi_sw_if_index = ntohl (bd_config->bvi_sw_if_index); mp->mac_age = bd_config->mac_age; + if (bd_config->bd_tag) + { + strncpy ((char *) mp->bd_tag, (char *) bd_config->bd_tag, + ARRAY_LEN (mp->bd_tag) - 1); + mp->bd_tag[ARRAY_LEN (mp->bd_tag) - 1] = 0; + } + mp->context = context; sw_ifs = (vl_api_bridge_domain_sw_if_t *) mp->sw_if_details; diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 6e0db058..3670a4f0 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -108,6 +108,9 @@ bd_delete (bd_main_t * bdm, u32 bd_index) bd->bd_id = ~0; bd->feature_bitmap = 0; + /* free BD tag */ + vec_free (bd->bd_tag); + /* free memory used by BD */ vec_free (bd->members); hash_free (bd->mac_by_ip4); @@ -288,6 +291,29 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) L2_MAC_AGE_PROCESS_EVENT_STOP, 0); } + +void +bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag) +{ + u8 *old; + l2_bridge_domain_t *bd_config; + vec_validate (l2input_main.bd_configs, bd_index); + bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index); + + old = bd_config->bd_tag; + + if (bd_tag[0]) + { + bd_config->bd_tag = format (0, "%s%c", bd_tag, 0); + } + else + { + bd_config->bd_tag = NULL; + } + + vec_free (old); +} + /** Set bridge-domain learn enable/disable. The CLI format is: @@ -906,6 +932,7 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) u32 detail = 0; u32 intf = 0; u32 arp = 0; + u32 bd_tag = 0; u32 bd_id = ~0; uword *p; @@ -922,6 +949,8 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) intf = 1; if (unformat (input, "arp")) arp = 1; + if (unformat (input, "bd-tag")) + bd_tag = 1; if (bd_id == 0) return clib_error_return (0, @@ -1039,6 +1068,12 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) })); /* *INDENT-ON* */ } + + if ((detail || bd_tag) && (bd_config->bd_tag)) + { + vlib_cli_output (vm, "\n BD-Tag: %s", bd_config->bd_tag); + + } } } vec_free (as); @@ -1080,7 +1115,7 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (bd_show_cli, static) = { .path = "show bridge-domain", - .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp]]", + .short_help = "show bridge-domain [bridge-domain-id [detail|int|arp|bd-tag]]", .function = bd_show, }; /* *INDENT-ON* */ @@ -1134,6 +1169,10 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) bd_set_flags (vm, bd_index, disable_flags, 0 /* disable */ ); bd_set_mac_age (vm, bd_index, a->mac_age); + + if (a->bd_tag) + bd_set_bd_tag (vm, bd_index, a->bd_tag); + } else { @@ -1166,6 +1205,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, u32 bd_id = ~0; u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; u32 mac_age = 0; + u8 *bd_tag = NULL; l2_bridge_domain_add_del_args_t _a, *a = &_a; int rv; @@ -1189,6 +1229,8 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, ; else if (unformat (line_input, "mac-age %d", &mac_age)) ; + else if (unformat (line_input, "bd-tag %s", &bd_tag)) + ; else if (unformat (line_input, "del")) { is_add = 0; @@ -1215,6 +1257,11 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, error = clib_error_return (0, "mac age must be less than 256"); goto done; } + if ((bd_tag) && (strlen ((char *) bd_tag) > 63)) + { + error = clib_error_return (0, "bd-tag cannot be longer than 63"); + goto done; + } memset (a, 0, sizeof (*a)); a->is_add = is_add; @@ -1225,6 +1272,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, a->learn = (u8) learn; a->arp_term = (u8) arp_term; a->mac_age = (u8) mac_age; + a->bd_tag = bd_tag; rv = bd_add_del (a); @@ -1252,6 +1300,7 @@ bd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, } done: + vec_free (bd_tag); unformat_free (line_input); return error; @@ -1291,7 +1340,7 @@ VLIB_CLI_COMMAND (bd_create_cli, static) = { .path = "create bridge-domain", .short_help = "create bridge-domain " " [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] [arp-term <0|1>]" - " [mac-age ] [del]", + " [mac-age ] [bd-tag ] [del]", .function = bd_add_del_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index 0e070651..e60f1ab3 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -88,6 +88,9 @@ typedef struct /* sequence number for bridge domain based flush of MACs */ u8 seq_num; + /* Bridge domain tag (C string NULL terminated) */ + u8 *bd_tag; + } l2_bridge_domain_t; /* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */ @@ -102,6 +105,7 @@ typedef struct u8 learn; u8 arp_term; u8 mac_age; + u8 *bd_tag; u8 is_add; } l2_bridge_domain_add_del_args_t; @@ -130,6 +134,7 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); +void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag); int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** -- cgit 1.2.3-korg From 50570ecef6d37b0c9d8c002f6dadb4ed0e138aa3 Mon Sep 17 00:00:00 2001 From: Jerome Tollet Date: Thu, 14 Sep 2017 12:53:56 +0100 Subject: Update of free text tag patch for BD Change-Id: Ia886ff2bfa2cf33ffbaa35ec89494d4300ec2769 Signed-off-by: Jerome Tollet --- src/vat/api_format.c | 23 ++++++++++++++++++++--- src/vnet/l2/l2.api | 1 + src/vnet/l2/l2_bd.c | 9 ++++++--- src/vnet/l2/l2_bd.h | 1 - src/vpp/api/custom_dump.c | 2 ++ 5 files changed, 29 insertions(+), 7 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 43d1eb3d..ff3354c9 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -6356,6 +6356,7 @@ api_bridge_domain_add_del (vat_main_t * vam) u32 bd_id = ~0; u8 is_add = 1; u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; + u8 *bd_tag = NULL; u32 mac_age = 0; int ret; @@ -6376,6 +6377,8 @@ api_bridge_domain_add_del (vat_main_t * vam) ; else if (unformat (i, "mac-age %d", &mac_age)) ; + else if (unformat (i, "bd-tag %s", &bd_tag)) + ; else if (unformat (i, "del")) { is_add = 0; @@ -6388,13 +6391,22 @@ api_bridge_domain_add_del (vat_main_t * vam) if (bd_id == ~0) { errmsg ("missing bridge domain"); - return -99; + ret = -99; + goto done; } if (mac_age > 255) { errmsg ("mac age must be less than 256 "); - return -99; + ret = -99; + goto done; + } + + if ((bd_tag) && (strlen ((char *) bd_tag) > 63)) + { + errmsg ("bd-tag cannot be longer than 63"); + ret = -99; + goto done; } M (BRIDGE_DOMAIN_ADD_DEL, mp); @@ -6407,9 +6419,14 @@ api_bridge_domain_add_del (vat_main_t * vam) mp->arp_term = arp_term; mp->is_add = is_add; mp->mac_age = (u8) mac_age; + if (bd_tag) + strcpy ((char *) mp->bd_tag, (char *) bd_tag); S (mp); W (ret); + +done: + vec_free (bd_tag); return ret; } @@ -20152,7 +20169,7 @@ _(sw_interface_set_l2_bridge, \ "enable | disable") \ _(bridge_domain_set_mac_age, "bd_id mac-age 0-255") \ _(bridge_domain_add_del, \ - "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [del]\n") \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [mac-age 0-255] [bd-tag ] [del]\n") \ _(bridge_domain_dump, "[bd_id ]\n") \ _(l2fib_add_del, \ "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ diff --git a/src/vnet/l2/l2.api b/src/vnet/l2/l2.api index baf830fa..ac923de4 100644 --- a/src/vnet/l2/l2.api +++ b/src/vnet/l2/l2.api @@ -285,6 +285,7 @@ typeonly manual_print manual_endian define bridge_domain_sw_if @param learn - learning state on all interfaces in the bd @param arp_term - arp termination state on all interfaces in the bd @param mac_age - mac aging time in min, 0 for disabled + @param bd_tag - optional textual tag for the bridge domain @param n_sw_ifs - number of sw_if_index's in the domain */ manual_print manual_endian define bridge_domain_details diff --git a/src/vnet/l2/l2_bd.c b/src/vnet/l2/l2_bd.c index 3670a4f0..b1abb4c0 100644 --- a/src/vnet/l2/l2_bd.c +++ b/src/vnet/l2/l2_bd.c @@ -291,8 +291,11 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age) L2_MAC_AGE_PROCESS_EVENT_STOP, 0); } +/** + Set the tag for the bridge domain. +*/ -void +static void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag) { u8 *old; @@ -1191,8 +1194,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a) /** Create or delete bridge-domain. The CLI format: - create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] - [flood <0|1>] [arp-term <0|1>] [mac-age ] [del] + create bridge-domain [learn <0|1>] [forward <0|1>] [uu-flood <0|1>] [flood <0|1>] + [arp-term <0|1>] [mac-age ] [bd-tag ] [del] */ static clib_error_t * diff --git a/src/vnet/l2/l2_bd.h b/src/vnet/l2/l2_bd.h index e60f1ab3..fd34ae67 100644 --- a/src/vnet/l2/l2_bd.h +++ b/src/vnet/l2/l2_bd.h @@ -134,7 +134,6 @@ u32 bd_remove_member (l2_bridge_domain_t * bd_config, u32 sw_if_index); u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, u32 flags, u32 enable); void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age); -void bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag); int bd_add_del (l2_bridge_domain_add_del_args_t * args); /** diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index be74b83a..2e1f980e 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -279,6 +279,8 @@ static void *vl_api_bridge_domain_add_del_t_print if (mp->is_add) { + if (mp->bd_tag[0]) + s = format (s, "bd_tag %s ", mp->bd_tag); s = format (s, "flood %d uu-flood %d ", mp->flood, mp->uu_flood); s = format (s, "forward %d learn %d ", mp->forward, mp->learn); s = format (s, "arp-term %d mac-age %d", mp->arp_term, mp->mac_age); -- cgit 1.2.3-korg From bd70c2f2e39b85939714aa025355eac973b2451f Mon Sep 17 00:00:00 2001 From: Eyal Bari Date: Wed, 27 Sep 2017 21:43:51 +0300 Subject: L2-FIB:add mac learn events test fixes an issue where events were not sent if BD doesn't enable mac aging Change-Id: Iddc53cb5c45e560633e6c5cff2731dccfc70ad5b Signed-off-by: Eyal Bari (cherry picked from commit 24db0ec78fb651c4c585ebf30e07108240574045) --- src/vnet/l2/l2_fib.c | 105 ++++++++++++++++++++++------------------------ test/test_l2_fib.py | 18 ++++++++ test/vpp_papi_provider.py | 9 ++++ 3 files changed, 76 insertions(+), 56 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_fib.c b/src/vnet/l2/l2_fib.c index 9f4c823f..64b3275b 100644 --- a/src/vnet/l2/l2_fib.c +++ b/src/vnet/l2/l2_fib.c @@ -756,17 +756,21 @@ VLIB_CLI_COMMAND (l2fib_del_cli, static) = { void l2fib_start_ager_scan (vlib_main_t * vm) { - l2_bridge_domain_t *bd_config; - int enable = 0; + uword evt = L2_MAC_AGE_PROCESS_EVENT_ONE_PASS; /* check if there is at least one bd with mac aging enabled */ + l2_bridge_domain_t *bd_config; vec_foreach (bd_config, l2input_main.bd_configs) + { if (bd_config->bd_id != ~0 && bd_config->mac_age != 0) - enable = 1; + { + evt = L2_MAC_AGE_PROCESS_EVENT_START; + break; + } + } vlib_process_signal_event (vm, l2fib_mac_age_scanner_process_node.index, - enable ? L2_MAC_AGE_PROCESS_EVENT_START : - L2_MAC_AGE_PROCESS_EVENT_ONE_PASS, 0); + evt, 0); } /** @@ -1019,25 +1023,26 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only) if (result.fields.age_not == 0) learn_count++; - if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event)) + if (client) { - /* event message full, send it and start a new one */ - if (q && (q->cursize < q->maxsize)) + if (PREDICT_FALSE (evt_idx >= fm->max_macs_in_event)) { - mp->n_macs = htonl (evt_idx); - vl_msg_api_send_shmem (q, (u8 *) & mp); - mp = allocate_mac_evt_buf (client, cl_idx); + /* event message full, send it and start a new one */ + if (q && (q->cursize < q->maxsize)) + { + mp->n_macs = htonl (evt_idx); + vl_msg_api_send_shmem (q, (u8 *) & mp); + mp = allocate_mac_evt_buf (client, cl_idx); + } + else + { + clib_warning ("MAC event to pid %d queue stuffed!" + " %d MAC entries lost", client, + evt_idx); + } + evt_idx = 0; } - else - { - clib_warning ("MAC event to pid %d queue stuffed!" - " %d MAC entries lost", client, evt_idx); - } - evt_idx = 0; - } - if (client) - { if (result.fields.lrn_evt) { /* copy mac entry to event msg */ @@ -1125,10 +1130,6 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only) return delta_t + accum_t; } -/* Type of scan */ -#define SCAN_MAC_AGE 0 -#define SCAN_MAC_EVENT 1 - /* Maximum f64 value */ #define TIME_MAX (1.7976931348623157e+308) @@ -1140,22 +1141,16 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, l2fib_main_t *fm = &l2fib_main; l2learn_main_t *lm = &l2learn_main; bool enabled = 0; - bool scan = SCAN_MAC_AGE; /* SCAN_FOR_AGE or SCAN_FOR_EVENT */ f64 start_time, next_age_scan_time = TIME_MAX; while (1) { - if (enabled) + if (lm->client_pid) + vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay); + else if (enabled) { - if (lm->client_pid) /* mac event client waiting */ - vlib_process_wait_for_event_or_clock (vm, fm->event_scan_delay); - else /* agin only */ - { - f64 t = next_age_scan_time - vlib_time_now (vm); - if (t < fm->event_scan_delay) - t = fm->event_scan_delay; - vlib_process_wait_for_event_or_clock (vm, t); - } + f64 t = next_age_scan_time - vlib_time_now (vm); + vlib_process_wait_for_event_or_clock (vm, t); } else vlib_process_wait_for_event (vm); @@ -1164,41 +1159,26 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vec_reset_length (event_data); start_time = vlib_time_now (vm); + enum + { SCAN_MAC_AGE, SCAN_MAC_EVENT, SCAN_DISABLE } scan = SCAN_MAC_AGE; switch (event_type) { case ~0: /* timer expired */ - if ((lm->client_pid == 0) || (start_time >= next_age_scan_time)) - { - scan = SCAN_MAC_AGE; - if (enabled) - next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; - else - next_age_scan_time = TIME_MAX; - } - else + if (lm->client_pid != 0 && start_time < next_age_scan_time) scan = SCAN_MAC_EVENT; break; case L2_MAC_AGE_PROCESS_EVENT_START: - scan = SCAN_MAC_AGE; - next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; enabled = 1; break; case L2_MAC_AGE_PROCESS_EVENT_STOP: enabled = 0; - next_age_scan_time = TIME_MAX; - l2fib_main.age_scan_duration = 0; - l2fib_main.evt_scan_duration = 0; - continue; + scan = SCAN_DISABLE; + break; case L2_MAC_AGE_PROCESS_EVENT_ONE_PASS: - scan = SCAN_MAC_AGE; - if (enabled) - next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; - else - next_age_scan_time = TIME_MAX; break; default: @@ -1208,7 +1188,20 @@ l2fib_mac_age_scanner_process (vlib_main_t * vm, vlib_node_runtime_t * rt, if (scan == SCAN_MAC_EVENT) l2fib_main.evt_scan_duration = l2fib_scan (vm, start_time, 1); else - l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0); + { + if (scan == SCAN_MAC_AGE) + l2fib_main.age_scan_duration = l2fib_scan (vm, start_time, 0); + if (scan == SCAN_DISABLE) + { + l2fib_main.age_scan_duration = 0; + l2fib_main.evt_scan_duration = 0; + } + /* schedule next scan */ + if (enabled) + next_age_scan_time = start_time + L2FIB_AGE_SCAN_INTERVAL; + else + next_age_scan_time = TIME_MAX; + } } return 0; } diff --git a/test/test_l2_fib.py b/test/test_l2_fib.py index 9249a2ce..52bf9c86 100644 --- a/test/test_l2_fib.py +++ b/test/test_l2_fib.py @@ -519,6 +519,24 @@ class TestL2fib(VppTestCase): self.run_verify_negat_test(bd_id=1, dst_hosts=flushed) self.run_verify_negat_test(bd_id=2, dst_hosts=flushed) + def test_l2_fib_09(self): + """ L2 FIB test 9 - mac learning events + """ + self.create_hosts(10, subnet=39) + + self.vapi.want_macs_learn_events() + self.learn_hosts(bd_id=1, n_hosts_per_if=10) + + self.sleep(1) + self.logger.info(self.vapi.ppcli("show l2fib")) + evs = self.vapi.collect_events() + learned_macs = { + e.mac[i].mac_addr for e in evs for i in range(e.n_macs)} + macs = {h.bin_mac for swif_hs in self.learned_hosts.itervalues() + for h in swif_hs} + self.vapi.want_macs_learn_events(enable_disable=0) + self.assertEqual(len(learned_macs ^ macs), 0) + if __name__ == '__main__': unittest.main(testRunner=VppTestRunner) diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 634dabea..b6759ec3 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -431,6 +431,15 @@ class VppPapiProvider(object): 'address': address, 'pid': os.getpid(), }) + def want_macs_learn_events(self, enable_disable=1, scan_delay=0, + max_macs_in_event=0, learn_limit=0): + return self.api(self.papi.want_l2_macs_events, + {'enable_disable': enable_disable, + 'scan_delay': scan_delay, + 'max_macs_in_event': max_macs_in_event, + 'learn_limit': learn_limit, + 'pid': os.getpid(), }) + def l2fib_add_del(self, mac, bd_id, sw_if_index, is_add=1, static_mac=0, filter_mac=0, bvi_mac=0): """Create/delete L2 FIB entry. -- cgit 1.2.3-korg From dab7eb87bc2ed33f8fee8c3e9aa0fce50606de21 Mon Sep 17 00:00:00 2001 From: John Lo Date: Tue, 3 Oct 2017 13:13:47 -0400 Subject: Update L2FIB entry timestamp only if BD aging enabled (VPP-1002) Change L2 learning path so it update stale timestamp in MAC entry only if aging is enabled on the BD for the MAC entry. Change-Id: I7babe986ceef3c030d8ef9185076c42b405f7b0f Signed-off-by: John Lo (cherry picked from commit 5a6508d7269266b4a3ecacdd197ea3514a0c0e28) --- src/vnet/buffer.h | 1 + src/vnet/l2/l2_input.c | 1 + src/vnet/l2/l2_learn.c | 7 ++++--- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h index 7dfc6b99..fbefe7c2 100644 --- a/src/vnet/buffer.h +++ b/src/vnet/buffer.h @@ -173,6 +173,7 @@ typedef struct u8 l2_len; /* ethernet header length */ u8 shg; /* split-horizon group */ u16 l2fib_sn; /* l2fib bd/int seq_num */ + u8 bd_age; /* aging enabled */ } l2; /* l2tpv3 softwire encap, only valid there */ diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index faed7c7f..e556b141 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -225,6 +225,7 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) }; /* *INDENT-ON* */ vnet_buffer (b0)->l2.l2fib_sn = sn.as_u16;; + vnet_buffer (b0)->l2.bd_age = bd_config->mac_age; /* * Process bridge domain feature enables. diff --git a/src/vnet/l2/l2_learn.c b/src/vnet/l2/l2_learn.c index 066bb54f..fddab824 100644 --- a/src/vnet/l2/l2_learn.c +++ b/src/vnet/l2/l2_learn.c @@ -126,7 +126,7 @@ l2learn_process (vlib_node_runtime_t * node, /* Entry in L2FIB with matching sw_if_index matched - normal fast path */ u32 dtime = timestamp - result0->fields.timestamp; u32 dsn = result0->fields.sn.as_u16 - vnet_buffer (b0)->l2.l2fib_sn; - u32 check = dtime | dsn; + u32 check = (dtime && vnet_buffer (b0)->l2.bd_age) || dsn; if (PREDICT_TRUE (check == 0)) return; /* MAC entry up to date */ @@ -136,8 +136,9 @@ l2learn_process (vlib_node_runtime_t * node, return; /* Above learn limit - do not update */ /* Limit updates per l2-learn node call to avoid prolonged update burst - * as dtime advance over 1 minute mark, unless more than 1 min behind */ - if ((*count > 2) && (dtime == 1)) + * as dtime advance over 1 minute mark, unless more than 1 min behind + * or SN obsolete */ + if ((*count > 2) && (dtime == 1) && (dsn == 0)) return; counter_base[L2LEARN_ERROR_HIT_UPDATE] += 1; -- cgit 1.2.3-korg From c97b4aca0db8d84b17ceb03a14ab44346a2b3466 Mon Sep 17 00:00:00 2001 From: John Lo Date: Tue, 7 Nov 2017 17:23:49 -0500 Subject: Fix SHG handling for ARP/ICMPv6 received from BVI in a BD This change makes sure ARP/ICMPv6 brodcast packets received from the BVI of a BD can be flooded to all remote VTEPs via its VXLAN tunnels irrespective of SHG setting. Similar processing was done for unicast packets already and needs to be extpanded to ARP and ICMPv6 broadcast packets. Change-Id: I26ac43ecdbc81a769f742a583a156506f7e70d49 Signed-off-by: John Lo --- src/vnet/l2/l2_input.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index e556b141..9038363c 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -193,6 +193,14 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) if (ethertype != ETHERNET_TYPE_ARP && (ethertype != ETHERNET_TYPE_IP6 || protocol != IP_PROTOCOL_ICMP6)) feat_mask &= ~(L2INPUT_FEAT_ARP_TERM); + /* + * Check for from-BVI processing - set SHG of ARP/ICMP6 packets from BVI + * to 0 so it can also flood to VXLAN tunnels or other ports with the + * same SHG as that of the BVI. + */ + else if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] == + L2INPUT_BVI)) + vnet_buffer (b0)->l2.shg = 0; } else { -- cgit 1.2.3-korg From 5b99133cff1ff0eb9043dd8bd3648b0b3aafa47e Mon Sep 17 00:00:00 2001 From: John Lo Date: Fri, 10 Nov 2017 12:24:32 -0500 Subject: Further fix to SHG handling for ARP/ICMPv6 from BVI in a BD For ARP/ICMPv6 packets received from a BVI in a BD, allow flood to all remote VTEPs via VXLAN tunnels irrespective of SHG check for ARP request or ICMPv6 neighbor solicitation packets only. All other packets types will flood normally as per SHG check. Change-Id: I17b1cef9015e363fb684c2b6506ed6c4efe70bba Signed-off-by: John Lo --- src/vnet/l2/l2_input.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'src/vnet/l2') diff --git a/src/vnet/l2/l2_input.c b/src/vnet/l2/l2_input.c index 9038363c..3933dae5 100644 --- a/src/vnet/l2/l2_input.c +++ b/src/vnet/l2/l2_input.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -193,20 +195,37 @@ classify_and_dispatch (l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0) if (ethertype != ETHERNET_TYPE_ARP && (ethertype != ETHERNET_TYPE_IP6 || protocol != IP_PROTOCOL_ICMP6)) feat_mask &= ~(L2INPUT_FEAT_ARP_TERM); + /* - * Check for from-BVI processing - set SHG of ARP/ICMP6 packets from BVI - * to 0 so it can also flood to VXLAN tunnels or other ports with the - * same SHG as that of the BVI. + * For packet from BVI - set SHG of ARP request or ICMPv6 neighbor + * solicitation packet from BVI to 0 so it can also flood to VXLAN + * tunnels or other ports with the same SHG as that of the BVI. */ else if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] == L2INPUT_BVI)) - vnet_buffer (b0)->l2.shg = 0; + { + if (ethertype == ETHERNET_TYPE_ARP) + { + ethernet_arp_header_t *arp0 = (ethernet_arp_header_t *) l3h0; + if (arp0->opcode == + clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request)) + vnet_buffer (b0)->l2.shg = 0; + } + else /* must be ICMPv6 */ + { + ip6_header_t *iph0 = (ip6_header_t *) l3h0; + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh0; + ndh0 = ip6_next_header (iph0); + if (ndh0->icmp.type == ICMP6_neighbor_solicitation) + vnet_buffer (b0)->l2.shg = 0; + } + } } else { /* - * Check for from-BVI processing - set SHG of unicast packets from BVI - * to 0 so it is not dropped for VXLAN tunnels or other ports with the + * For packet from BVI - set SHG of unicast packet from BVI to 0 so it + * is not dropped on output to VXLAN tunnels or other ports with the * same SHG as that of the BVI. */ if (PREDICT_FALSE (vnet_buffer (b0)->sw_if_index[VLIB_TX] == -- cgit 1.2.3-korg