diff options
Diffstat (limited to 'src/vnet/span/span.c')
-rw-r--r-- | src/vnet/span/span.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/vnet/span/span.c b/src/vnet/span/span.c new file mode 100644 index 00000000000..7b5816c79f2 --- /dev/null +++ b/src/vnet/span/span.c @@ -0,0 +1,197 @@ +/* + * 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 <vlib/vlib.h> +#include <vppinfra/error.h> +#include <vnet/feature/feature.h> + +#include <vnet/span/span.h> + +int +span_add_delete_entry (vlib_main_t * vm, + u32 src_sw_if_index, u32 dst_sw_if_index, u8 state) +{ + span_main_t *sm = &span_main; + span_interface_t *si; + u32 new_num_rx_mirror_ports, new_num_tx_mirror_ports; + + if (state > 3) + 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); + + 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); + + 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); + + if (new_num_rx_mirror_ports == 1 && si->num_rx_mirror_ports == 0) + vnet_feature_enable_disable ("device-input", "span-output", + src_sw_if_index, 1, 0, 0); + + if (new_num_rx_mirror_ports == 0 && si->num_rx_mirror_ports == 1) + vnet_feature_enable_disable ("device-input", "span-output", + src_sw_if_index, 0, 0, 0); + + si->num_rx_mirror_ports = new_num_rx_mirror_ports; + si->num_tx_mirror_ports = new_num_tx_mirror_ports; + + if (dst_sw_if_index > sm->max_sw_if_index) + sm->max_sw_if_index = dst_sw_if_index; + + return 0; +} + +static clib_error_t * +set_interface_span_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + span_main_t *sm = &span_main; + u32 src_sw_if_index = ~0; + u32 dst_sw_if_index = ~0; + u8 state = 3; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", unformat_vnet_sw_interface, + sm->vnet_main, &src_sw_if_index)) + ; + else if (unformat (input, "destination %U", unformat_vnet_sw_interface, + sm->vnet_main, &dst_sw_if_index)) + ; + else if (unformat (input, "disable")) + state = 0; + else if (unformat (input, "rx")) + state = 1; + else if (unformat (input, "tx")) + state = 2; + else if (unformat (input, "both")) + state = 3; + else + break; + } + + int rv = + span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state); + if (rv == VNET_API_ERROR_INVALID_INTERFACE) + return clib_error_return (0, "Invalid interface"); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (set_interface_span_command, static) = { + .path = "set interface span", + .short_help = "set interface span <if-name> [disable | destination <if-name> [both|rx|tx]]", + .function = set_interface_span_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +show_interfaces_span_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + span_main_t *sm = &span_main; + span_interface_t *si; + vnet_main_t *vnm = &vnet_main; + u8 header = 1; + char *states[] = { "none", "rx", "tx", "both" }; + u8 *s = 0; + + /* *INDENT-OFF* */ + vec_foreach (si, sm->interfaces) + if (si->num_rx_mirror_ports || si->num_tx_mirror_ports) + { + clib_bitmap_t *b; + u32 i; + b = clib_bitmap_dup_or (si->rx_mirror_ports, si->tx_mirror_ports); + if (header) + { + vlib_cli_output (vm, "%-40s %s", "Source interface", + "Mirror interface (direction)"); + 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); + + vlib_cli_output (vm, "%-40v %U (%s)", s, + format_vnet_sw_if_index_name, vnm, i, + states[state]); + vec_reset_length (s); + })); + clib_bitmap_free (b); + } + /* *INDENT-ON* */ + vec_free (s); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_interfaces_span_command, static) = { + .path = "show interfaces span", + .short_help = "Shows SPAN mirror table", + .function = show_interfaces_span_command_fn, +}; +/* *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 + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |