Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016 Cisco and/or its affiliates. |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at: |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | #include <vlib/vlib.h> |
| 17 | #include <vppinfra/error.h> |
| 18 | #include <vnet/feature/feature.h> |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 19 | #include <vnet/l2/l2_input.h> |
| 20 | #include <vnet/l2/l2_output.h> |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 21 | |
| 22 | #include <vnet/span/span.h> |
| 23 | |
Dave Wallace | 71612d6 | 2017-10-24 01:32:41 -0400 | [diff] [blame] | 24 | span_main_t span_main; |
| 25 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 26 | typedef enum |
| 27 | { |
| 28 | SPAN_DISABLE = 0, |
| 29 | SPAN_RX = 1, |
| 30 | SPAN_TX = 2, |
| 31 | SPAN_BOTH = SPAN_RX | SPAN_TX |
| 32 | } span_state_t; |
| 33 | |
| 34 | static_always_inline u32 |
| 35 | span_dst_set (span_mirror_t * sm, u32 dst_sw_if_index, int enable) |
| 36 | { |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 37 | if (dst_sw_if_index == ~0) |
| 38 | { |
| 39 | ASSERT (enable == 0); |
| 40 | clib_bitmap_zero (sm->mirror_ports); |
| 41 | } |
| 42 | else |
| 43 | sm->mirror_ports = |
| 44 | clib_bitmap_set (sm->mirror_ports, dst_sw_if_index, enable); |
| 45 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 46 | u32 last = sm->num_mirror_ports; |
| 47 | sm->num_mirror_ports = clib_bitmap_count_set_bits (sm->mirror_ports); |
| 48 | return last; |
| 49 | } |
| 50 | |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 51 | int |
| 52 | span_add_delete_entry (vlib_main_t * vm, |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 53 | u32 src_sw_if_index, u32 dst_sw_if_index, u8 state, |
| 54 | span_feat_t sf) |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 55 | { |
| 56 | span_main_t *sm = &span_main; |
| 57 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 58 | if (state > SPAN_BOTH) |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 59 | return VNET_API_ERROR_UNIMPLEMENTED; |
| 60 | |
| 61 | if ((src_sw_if_index == ~0) || (dst_sw_if_index == ~0 && state > 0) |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 62 | || (src_sw_if_index == dst_sw_if_index)) |
| 63 | return VNET_API_ERROR_INVALID_INTERFACE; |
| 64 | |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 65 | vec_validate_aligned (sm->interfaces, src_sw_if_index, |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 66 | CLIB_CACHE_LINE_BYTES); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 67 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 68 | span_interface_t *si = vec_elt_at_index (sm->interfaces, src_sw_if_index); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 69 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 70 | int rx = ! !(state & SPAN_RX); |
| 71 | int tx = ! !(state & SPAN_TX); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 72 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 73 | span_mirror_t *rxm = &si->mirror_rxtx[sf][VLIB_RX]; |
| 74 | span_mirror_t *txm = &si->mirror_rxtx[sf][VLIB_TX]; |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 75 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 76 | u32 last_rx_ports_count = span_dst_set (rxm, dst_sw_if_index, rx); |
| 77 | u32 last_tx_ports_count = span_dst_set (txm, dst_sw_if_index, tx); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 78 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 79 | int enable_rx = last_rx_ports_count == 0 && rxm->num_mirror_ports == 1; |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 80 | int disable_rx = last_rx_ports_count > 0 && rxm->num_mirror_ports == 0; |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 81 | int enable_tx = last_tx_ports_count == 0 && txm->num_mirror_ports == 1; |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 82 | int disable_tx = last_tx_ports_count > 0 && txm->num_mirror_ports == 0; |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 83 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 84 | switch (sf) |
| 85 | { |
| 86 | case SPAN_FEAT_DEVICE: |
| 87 | if (enable_rx || disable_rx) |
| 88 | vnet_feature_enable_disable ("device-input", "span-input", |
| 89 | src_sw_if_index, rx, 0, 0); |
| 90 | if (enable_tx || disable_tx) |
| 91 | vnet_feature_enable_disable ("interface-output", "span-output", |
| 92 | src_sw_if_index, tx, 0, 0); |
| 93 | break; |
| 94 | case SPAN_FEAT_L2: |
| 95 | if (enable_rx || disable_rx) |
| 96 | l2input_intf_bitmap_enable (src_sw_if_index, L2INPUT_FEAT_SPAN, rx); |
| 97 | if (enable_tx || disable_tx) |
| 98 | l2output_intf_bitmap_enable (src_sw_if_index, L2OUTPUT_FEAT_SPAN, tx); |
| 99 | break; |
| 100 | default: |
| 101 | return VNET_API_ERROR_UNIMPLEMENTED; |
| 102 | } |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 103 | |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 104 | if (dst_sw_if_index != ~0 && dst_sw_if_index > sm->max_sw_if_index) |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 105 | sm->max_sw_if_index = dst_sw_if_index; |
| 106 | |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 107 | return 0; |
| 108 | } |
| 109 | |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 110 | static uword |
| 111 | unformat_span_state (unformat_input_t * input, va_list * args) |
| 112 | { |
| 113 | span_state_t *state = va_arg (*args, span_state_t *); |
| 114 | if (unformat (input, "disable")) |
| 115 | *state = SPAN_DISABLE; |
| 116 | else if (unformat (input, "rx")) |
| 117 | *state = SPAN_RX; |
| 118 | else if (unformat (input, "tx")) |
| 119 | *state = SPAN_TX; |
| 120 | else if (unformat (input, "both")) |
| 121 | *state = SPAN_BOTH; |
| 122 | else |
| 123 | return 0; |
| 124 | return 1; |
| 125 | } |
| 126 | |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 127 | static clib_error_t * |
| 128 | set_interface_span_command_fn (vlib_main_t * vm, |
| 129 | unformat_input_t * input, |
| 130 | vlib_cli_command_t * cmd) |
| 131 | { |
| 132 | span_main_t *sm = &span_main; |
| 133 | u32 src_sw_if_index = ~0; |
| 134 | u32 dst_sw_if_index = ~0; |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 135 | span_feat_t sf = SPAN_FEAT_DEVICE; |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 136 | span_state_t state = SPAN_BOTH; |
| 137 | int state_set = 0; |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 138 | |
| 139 | while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| 140 | { |
| 141 | if (unformat (input, "%U", unformat_vnet_sw_interface, |
| 142 | sm->vnet_main, &src_sw_if_index)) |
| 143 | ; |
| 144 | else if (unformat (input, "destination %U", unformat_vnet_sw_interface, |
| 145 | sm->vnet_main, &dst_sw_if_index)) |
| 146 | ; |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 147 | else if (unformat (input, "%U", unformat_span_state, &state)) |
| 148 | { |
| 149 | if (state_set) |
| 150 | return clib_error_return (0, "Multiple mirror states in input"); |
| 151 | state_set = 1; |
| 152 | } |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 153 | else if (unformat (input, "l2")) |
| 154 | sf = SPAN_FEAT_L2; |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 155 | else |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 156 | return clib_error_return (0, "Invalid input"); |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | int rv = |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 160 | span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state, sf); |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 161 | if (rv == VNET_API_ERROR_INVALID_INTERFACE) |
| 162 | return clib_error_return (0, "Invalid interface"); |
| 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | /* *INDENT-OFF* */ |
| 167 | VLIB_CLI_COMMAND (set_interface_span_command, static) = { |
| 168 | .path = "set interface span", |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 169 | .short_help = "set interface span <if-name> [l2] {disable | destination <if-name> [both|rx|tx]}", |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 170 | .function = set_interface_span_command_fn, |
| 171 | }; |
| 172 | /* *INDENT-ON* */ |
| 173 | |
| 174 | static clib_error_t * |
| 175 | show_interfaces_span_command_fn (vlib_main_t * vm, |
| 176 | unformat_input_t * input, |
| 177 | vlib_cli_command_t * cmd) |
| 178 | { |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 179 | span_main_t *sm = &span_main; |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 180 | span_interface_t *si; |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 181 | vnet_main_t *vnm = &vnet_main; |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 182 | u8 header = 1; |
Eyal Bari | 4a7d50e | 2017-07-30 13:27:46 +0300 | [diff] [blame] | 183 | static const char *states[] = { |
| 184 | [SPAN_DISABLE] = "none", |
| 185 | [SPAN_RX] = "rx", |
| 186 | [SPAN_TX] = "tx", |
| 187 | [SPAN_BOTH] = "both" |
| 188 | }; |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 189 | u8 *s = 0; |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 190 | |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 191 | /* *INDENT-OFF* */ |
| 192 | vec_foreach (si, sm->interfaces) |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 193 | { |
| 194 | span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX]; |
| 195 | span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX]; |
| 196 | |
| 197 | span_mirror_t * lrxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_RX]; |
| 198 | span_mirror_t * ltxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_TX]; |
| 199 | |
| 200 | if (drxm->num_mirror_ports || dtxm->num_mirror_ports || |
| 201 | lrxm->num_mirror_ports || ltxm->num_mirror_ports) |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 202 | { |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 203 | u32 i; |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 204 | clib_bitmap_t *d = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports); |
| 205 | clib_bitmap_t *l = clib_bitmap_dup_or (lrxm->mirror_ports, ltxm->mirror_ports); |
| 206 | clib_bitmap_t *b = clib_bitmap_dup_or (d, l); |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 207 | if (header) |
| 208 | { |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 209 | vlib_cli_output (vm, "%-20s %-20s %6s %6s", "Source", "Destination", |
| 210 | "Device", "L2"); |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 211 | header = 0; |
| 212 | } |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 213 | s = format (s, "%U", format_vnet_sw_if_index_name, vnm, |
| 214 | si - sm->interfaces); |
| 215 | clib_bitmap_foreach (i, b, ( |
| 216 | { |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 217 | int device = (clib_bitmap_get (drxm->mirror_ports, i) + |
| 218 | clib_bitmap_get (dtxm->mirror_ports, i) * 2); |
| 219 | int l2 = (clib_bitmap_get (lrxm->mirror_ports, i) + |
| 220 | clib_bitmap_get (ltxm->mirror_ports, i) * 2); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 221 | |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 222 | vlib_cli_output (vm, "%-20v %-20U (%6s) (%6s)", s, |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 223 | format_vnet_sw_if_index_name, vnm, i, |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 224 | states[device], states[l2]); |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 225 | vec_reset_length (s); |
| 226 | })); |
| 227 | clib_bitmap_free (b); |
Eyal Bari | 001fd40 | 2017-07-16 09:34:53 +0300 | [diff] [blame] | 228 | clib_bitmap_free (l); |
| 229 | clib_bitmap_free (d); |
| 230 | } |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 231 | } |
Pavel Kotucek | 3a2a1c4 | 2016-12-06 10:10:10 +0100 | [diff] [blame] | 232 | /* *INDENT-ON* */ |
| 233 | vec_free (s); |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 234 | return 0; |
| 235 | } |
| 236 | |
| 237 | /* *INDENT-OFF* */ |
| 238 | VLIB_CLI_COMMAND (show_interfaces_span_command, static) = { |
Dave Barach | 13ad1f0 | 2017-03-26 19:36:18 -0400 | [diff] [blame] | 239 | .path = "show interface span", |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 240 | .short_help = "Shows SPAN mirror table", |
| 241 | .function = show_interfaces_span_command_fn, |
| 242 | }; |
| 243 | /* *INDENT-ON* */ |
| 244 | |
Pavel Kotucek | f6e3dc4 | 2016-11-04 09:58:01 +0100 | [diff] [blame] | 245 | /* |
| 246 | * fd.io coding-style-patch-verification: ON |
| 247 | * |
| 248 | * Local Variables: |
| 249 | * eval: (c-set-style "gnu") |
| 250 | * End: |
| 251 | */ |