Line data Source code
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>
19 : #include <vnet/l2/l2_input.h>
20 : #include <vnet/l2/l2_output.h>
21 :
22 : #include <vnet/span/span.h>
23 :
24 : span_main_t span_main;
25 :
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 40 : span_dst_set (span_mirror_t * sm, u32 dst_sw_if_index, int enable)
36 : {
37 40 : if (dst_sw_if_index == ~0)
38 : {
39 0 : ASSERT (enable == 0);
40 0 : clib_bitmap_zero (sm->mirror_ports);
41 : }
42 : else
43 40 : sm->mirror_ports =
44 40 : clib_bitmap_set (sm->mirror_ports, dst_sw_if_index, enable);
45 :
46 40 : u32 last = sm->num_mirror_ports;
47 40 : sm->num_mirror_ports = clib_bitmap_count_set_bits (sm->mirror_ports);
48 40 : return last;
49 : }
50 :
51 : int
52 20 : span_add_delete_entry (vlib_main_t * vm,
53 : u32 src_sw_if_index, u32 dst_sw_if_index, u8 state,
54 : span_feat_t sf)
55 : {
56 20 : span_main_t *sm = &span_main;
57 :
58 20 : if (state > SPAN_BOTH)
59 0 : return VNET_API_ERROR_UNIMPLEMENTED;
60 :
61 20 : if ((src_sw_if_index == ~0) || (dst_sw_if_index == ~0 && state > 0)
62 20 : || (src_sw_if_index == dst_sw_if_index))
63 0 : return VNET_API_ERROR_INVALID_INTERFACE;
64 :
65 20 : vec_validate_aligned (sm->interfaces, src_sw_if_index,
66 : CLIB_CACHE_LINE_BYTES);
67 :
68 20 : span_interface_t *si = vec_elt_at_index (sm->interfaces, src_sw_if_index);
69 :
70 20 : int rx = ! !(state & SPAN_RX);
71 20 : int tx = ! !(state & SPAN_TX);
72 :
73 20 : span_mirror_t *rxm = &si->mirror_rxtx[sf][VLIB_RX];
74 20 : span_mirror_t *txm = &si->mirror_rxtx[sf][VLIB_TX];
75 :
76 20 : u32 last_rx_ports_count = span_dst_set (rxm, dst_sw_if_index, rx);
77 20 : u32 last_tx_ports_count = span_dst_set (txm, dst_sw_if_index, tx);
78 :
79 20 : int enable_rx = last_rx_ports_count == 0 && rxm->num_mirror_ports == 1;
80 20 : int disable_rx = last_rx_ports_count > 0 && rxm->num_mirror_ports == 0;
81 20 : int enable_tx = last_tx_ports_count == 0 && txm->num_mirror_ports == 1;
82 20 : int disable_tx = last_tx_ports_count > 0 && txm->num_mirror_ports == 0;
83 :
84 20 : switch (sf)
85 : {
86 2 : case SPAN_FEAT_DEVICE:
87 2 : if (enable_rx || disable_rx)
88 2 : vnet_feature_enable_disable ("device-input", "span-input",
89 : src_sw_if_index, rx, 0, 0);
90 2 : if (enable_tx || disable_tx)
91 0 : vnet_feature_enable_disable ("interface-output", "span-output",
92 : src_sw_if_index, tx, 0, 0);
93 2 : break;
94 18 : case SPAN_FEAT_L2:
95 18 : if (enable_rx || disable_rx)
96 16 : l2input_intf_bitmap_enable (src_sw_if_index, L2INPUT_FEAT_SPAN, rx);
97 18 : if (enable_tx || disable_tx)
98 6 : l2output_intf_bitmap_enable (src_sw_if_index, L2OUTPUT_FEAT_SPAN, tx);
99 18 : break;
100 0 : default:
101 0 : return VNET_API_ERROR_UNIMPLEMENTED;
102 : }
103 :
104 20 : if (dst_sw_if_index != ~0 && dst_sw_if_index > sm->max_sw_if_index)
105 4 : sm->max_sw_if_index = dst_sw_if_index;
106 :
107 20 : return 0;
108 : }
109 :
110 : static uword
111 0 : unformat_span_state (unformat_input_t * input, va_list * args)
112 : {
113 0 : span_state_t *state = va_arg (*args, span_state_t *);
114 0 : if (unformat (input, "disable"))
115 0 : *state = SPAN_DISABLE;
116 0 : else if (unformat (input, "rx"))
117 0 : *state = SPAN_RX;
118 0 : else if (unformat (input, "tx"))
119 0 : *state = SPAN_TX;
120 0 : else if (unformat (input, "both"))
121 0 : *state = SPAN_BOTH;
122 : else
123 0 : return 0;
124 0 : return 1;
125 : }
126 :
127 : static clib_error_t *
128 0 : set_interface_span_command_fn (vlib_main_t * vm,
129 : unformat_input_t * input,
130 : vlib_cli_command_t * cmd)
131 : {
132 0 : span_main_t *sm = &span_main;
133 0 : u32 src_sw_if_index = ~0;
134 0 : u32 dst_sw_if_index = ~0;
135 0 : span_feat_t sf = SPAN_FEAT_DEVICE;
136 0 : span_state_t state = SPAN_BOTH;
137 0 : int state_set = 0;
138 :
139 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
140 : {
141 0 : if (unformat (input, "%U", unformat_vnet_sw_interface,
142 : sm->vnet_main, &src_sw_if_index))
143 : ;
144 0 : else if (unformat (input, "destination %U", unformat_vnet_sw_interface,
145 : sm->vnet_main, &dst_sw_if_index))
146 : ;
147 0 : else if (unformat (input, "%U", unformat_span_state, &state))
148 : {
149 0 : if (state_set)
150 0 : return clib_error_return (0, "Multiple mirror states in input");
151 0 : state_set = 1;
152 : }
153 0 : else if (unformat (input, "l2"))
154 0 : sf = SPAN_FEAT_L2;
155 : else
156 0 : return clib_error_return (0, "Invalid input");
157 : }
158 :
159 : int rv =
160 0 : span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state, sf);
161 0 : if (rv == VNET_API_ERROR_INVALID_INTERFACE)
162 0 : return clib_error_return (0, "Invalid interface");
163 0 : return 0;
164 : }
165 :
166 : /* *INDENT-OFF* */
167 285289 : VLIB_CLI_COMMAND (set_interface_span_command, static) = {
168 : .path = "set interface span",
169 : .short_help = "set interface span <if-name> [l2] {disable | destination <if-name> [both|rx|tx]}",
170 : .function = set_interface_span_command_fn,
171 : };
172 : /* *INDENT-ON* */
173 :
174 : static clib_error_t *
175 16 : show_interfaces_span_command_fn (vlib_main_t * vm,
176 : unformat_input_t * input,
177 : vlib_cli_command_t * cmd)
178 : {
179 16 : span_main_t *sm = &span_main;
180 : span_interface_t *si;
181 16 : vnet_main_t *vnm = &vnet_main;
182 16 : u8 header = 1;
183 : static const char *states[] = {
184 : [SPAN_DISABLE] = "none",
185 : [SPAN_RX] = "rx",
186 : [SPAN_TX] = "tx",
187 : [SPAN_BOTH] = "both"
188 : };
189 16 : u8 *s = 0;
190 :
191 : /* *INDENT-OFF* */
192 90 : vec_foreach (si, sm->interfaces)
193 : {
194 74 : span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX];
195 74 : span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX];
196 :
197 74 : span_mirror_t * lrxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_RX];
198 74 : span_mirror_t * ltxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_TX];
199 :
200 74 : if (drxm->num_mirror_ports || dtxm->num_mirror_ports ||
201 73 : lrxm->num_mirror_ports || ltxm->num_mirror_ports)
202 : {
203 : u32 i;
204 6 : clib_bitmap_t *d = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports);
205 6 : clib_bitmap_t *l = clib_bitmap_dup_or (lrxm->mirror_ports, ltxm->mirror_ports);
206 6 : clib_bitmap_t *b = clib_bitmap_dup_or (d, l);
207 6 : if (header)
208 : {
209 6 : vlib_cli_output (vm, "%-32s %-32s %6s %6s", "Source", "Destination",
210 : "Device", "L2");
211 6 : header = 0;
212 : }
213 12 : s = format (s, "%U", format_vnet_sw_if_index_name, vnm,
214 6 : si - sm->interfaces);
215 12 : clib_bitmap_foreach (i, b)
216 : {
217 6 : int device = (clib_bitmap_get (drxm->mirror_ports, i) +
218 6 : clib_bitmap_get (dtxm->mirror_ports, i) * 2);
219 6 : int l2 = (clib_bitmap_get (lrxm->mirror_ports, i) +
220 6 : clib_bitmap_get (ltxm->mirror_ports, i) * 2);
221 :
222 6 : vlib_cli_output (vm, "%-32v %-32U (%6s) (%6s)", s,
223 : format_vnet_sw_if_index_name, vnm, i,
224 : states[device], states[l2]);
225 6 : vec_reset_length (s);
226 : }
227 6 : clib_bitmap_free (b);
228 6 : clib_bitmap_free (l);
229 6 : clib_bitmap_free (d);
230 : }
231 : }
232 : /* *INDENT-ON* */
233 16 : vec_free (s);
234 16 : return 0;
235 : }
236 :
237 : /* *INDENT-OFF* */
238 285289 : VLIB_CLI_COMMAND (show_interfaces_span_command, static) = {
239 : .path = "show interface span",
240 : .short_help = "Shows SPAN mirror table",
241 : .function = show_interfaces_span_command_fn,
242 : };
243 : /* *INDENT-ON* */
244 :
245 : /*
246 : * fd.io coding-style-patch-verification: ON
247 : *
248 : * Local Variables:
249 : * eval: (c-set-style "gnu")
250 : * End:
251 : */
|