Line data Source code
1 : /*
2 : * l2_in_out_feat_arc.c : layer 2 input/output acl processing
3 : *
4 : * Copyright (c) 2013,2018 Cisco and/or its affiliates.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <vlib/vlib.h>
19 : #include <vnet/ethernet/ethernet.h>
20 : #include <vnet/ip/ip_packet.h>
21 : #include <vnet/l2/l2_input.h>
22 : #include <vnet/l2/l2_output.h>
23 : #include <vnet/l2/l2_in_out_feat_arc.h>
24 :
25 : #include <vppinfra/error.h>
26 : #include <vppinfra/hash.h>
27 : #include <vppinfra/cache.h>
28 :
29 :
30 : typedef struct
31 : {
32 :
33 : /* Next nodes for each feature */
34 : u32 feat_next_node_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS][32];
35 : u8 ip4_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
36 : u8 ip6_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
37 : u8 nonip_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
38 : u32 next_slot[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
39 : } l2_in_out_feat_arc_main_t __attribute__ ((aligned (CLIB_CACHE_LINE_BYTES)));
40 :
41 : typedef struct
42 : {
43 : u32 sw_if_index;
44 : u32 next_index;
45 : u32 feature_bitmap;
46 : u16 ethertype;
47 : u8 arc_head;
48 : } l2_in_out_feat_arc_trace_t;
49 :
50 : /* packet trace format function */
51 : static u8 *
52 3878 : format_l2_in_out_feat_arc_trace (u8 * s, u32 is_output, va_list * args)
53 : {
54 3878 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
55 3878 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
56 3878 : l2_in_out_feat_arc_trace_t *t =
57 : va_arg (*args, l2_in_out_feat_arc_trace_t *);
58 :
59 : s =
60 3878 : format (s,
61 : "%s: head %d feature_bitmap %x ethertype %x sw_if_index %d, next_index %d",
62 3878 : is_output ? "OUT-FEAT-ARC" : "IN-FEAT-ARC", t->arc_head,
63 3878 : t->feature_bitmap, t->ethertype, t->sw_if_index, t->next_index);
64 3878 : return s;
65 : }
66 :
67 : static u8 *
68 3562 : format_l2_in_feat_arc_trace (u8 * s, va_list * args)
69 : {
70 3562 : return format_l2_in_out_feat_arc_trace (s,
71 : IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
72 : args);
73 : }
74 :
75 : static u8 *
76 316 : format_l2_out_feat_arc_trace (u8 * s, va_list * args)
77 : {
78 316 : return format_l2_in_out_feat_arc_trace (s,
79 : IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
80 : args);
81 : }
82 :
83 :
84 : #define foreach_l2_in_feat_arc_error \
85 : _(DEFAULT, "in default") \
86 :
87 :
88 : #define foreach_l2_out_feat_arc_error \
89 : _(DEFAULT, "out default") \
90 :
91 :
92 : typedef enum
93 : {
94 : #define _(sym,str) L2_IN_FEAT_ARC_ERROR_##sym,
95 : foreach_l2_in_feat_arc_error
96 : #undef _
97 : L2_IN_FEAT_ARC_N_ERROR,
98 : } l2_in_feat_arc_error_t;
99 :
100 : static char *l2_in_feat_arc_error_strings[] = {
101 : #define _(sym,string) string,
102 : foreach_l2_in_feat_arc_error
103 : #undef _
104 : };
105 :
106 : typedef enum
107 : {
108 : #define _(sym,str) L2_OUT_FEAT_ARC_ERROR_##sym,
109 : foreach_l2_out_feat_arc_error
110 : #undef _
111 : L2_OUT_FEAT_ARC_N_ERROR,
112 : } l2_out_feat_arc_error_t;
113 :
114 : static char *l2_out_feat_arc_error_strings[] = {
115 : #define _(sym,string) string,
116 : foreach_l2_out_feat_arc_error
117 : #undef _
118 : };
119 :
120 : extern l2_in_out_feat_arc_main_t l2_in_out_feat_arc_main;
121 :
122 : #ifndef CLIB_MARCH_VARIANT
123 : l2_in_out_feat_arc_main_t l2_in_out_feat_arc_main;
124 : #endif /* CLIB_MARCH_VARIANT */
125 :
126 : #define get_u16(addr) ( *((u16 *)(addr)) )
127 : #define L2_FEAT_ARC_VEC_SIZE 2
128 :
129 : static_always_inline void
130 20233100 : buffer_prefetch_xN (int vector_sz, vlib_buffer_t ** b)
131 : {
132 : int ii;
133 60699400 : for (ii = 0; ii < vector_sz; ii++)
134 40466200 : clib_prefetch_store (b[ii]);
135 20233100 : }
136 :
137 : static_always_inline void
138 11706800 : get_sw_if_index_xN (int vector_sz, int is_output, vlib_buffer_t ** b,
139 : u32 * out_sw_if_index)
140 : {
141 : int ii;
142 32598800 : for (ii = 0; ii < vector_sz; ii++)
143 20891900 : if (is_output)
144 20889600 : out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_TX];
145 : else
146 2311 : out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_RX];
147 11706800 : }
148 :
149 : static_always_inline void
150 11706800 : get_ethertype_xN (int vector_sz, int is_output, vlib_buffer_t ** b,
151 : u16 * out_ethertype)
152 : {
153 : int ii;
154 32598800 : for (ii = 0; ii < vector_sz; ii++)
155 : {
156 20891900 : ethernet_header_t *h0 = vlib_buffer_get_current (b[ii]);
157 20891900 : u8 *l3h0 = (u8 *) h0 + vnet_buffer (b[ii])->l2.l2_len;
158 20891900 : out_ethertype[ii] = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
159 : }
160 11706800 : }
161 :
162 :
163 : static_always_inline void
164 11706800 : set_next_in_arc_head_xN (int vector_sz, int is_output, u32 * next_nodes,
165 : vlib_buffer_t ** b, u32 * sw_if_index,
166 : u16 * ethertype, u8 ip4_arc, u8 ip6_arc,
167 : u8 nonip_arc, u16 * out_next)
168 : {
169 : int ii;
170 32598800 : for (ii = 0; ii < vector_sz; ii++)
171 : {
172 20891900 : u32 next_index = 0;
173 : u8 feature_arc;
174 20891900 : switch (ethertype[ii])
175 : {
176 11168300 : case ETHERNET_TYPE_IP4:
177 11168300 : feature_arc = ip4_arc;
178 11168300 : break;
179 9723320 : case ETHERNET_TYPE_IP6:
180 9723320 : feature_arc = ip6_arc;
181 9723320 : break;
182 336 : default:
183 336 : feature_arc = nonip_arc;
184 : }
185 20891900 : if (PREDICT_TRUE (vnet_have_features (feature_arc, sw_if_index[ii])))
186 20870800 : vnet_feature_arc_start (feature_arc,
187 20870800 : sw_if_index[ii], &next_index, b[ii]);
188 : else
189 21164 : next_index =
190 21164 : vnet_l2_feature_next (b[ii], next_nodes,
191 : is_output ? L2OUTPUT_FEAT_OUTPUT_FEAT_ARC :
192 : L2INPUT_FEAT_INPUT_FEAT_ARC);
193 :
194 20891900 : out_next[ii] = next_index;
195 : }
196 11706800 : }
197 :
198 : static_always_inline void
199 13814900 : set_next_in_arc_tail_xN (int vector_sz, int is_output, u32 * next_nodes,
200 : vlib_buffer_t ** b, u16 * out_next)
201 : {
202 : int ii;
203 38677700 : for (ii = 0; ii < vector_sz; ii++)
204 : {
205 24862900 : out_next[ii] =
206 24862900 : vnet_l2_feature_next (b[ii], next_nodes,
207 : is_output ? L2OUTPUT_FEAT_OUTPUT_FEAT_ARC :
208 : L2INPUT_FEAT_INPUT_FEAT_ARC);
209 : }
210 :
211 13814900 : }
212 :
213 :
214 : static_always_inline void
215 2618 : maybe_trace_xN (int vector_sz, int arc_head, vlib_main_t * vm,
216 : vlib_node_runtime_t * node, vlib_buffer_t ** b,
217 : u32 * sw_if_index, u16 * ethertype, u16 * next)
218 : {
219 : int ii;
220 6818 : for (ii = 0; ii < vector_sz; ii++)
221 4200 : if (PREDICT_FALSE (b[ii]->flags & VLIB_BUFFER_IS_TRACED))
222 : {
223 : l2_in_out_feat_arc_trace_t *t =
224 4200 : vlib_add_trace (vm, node, b[ii], sizeof (*t));
225 4200 : t->arc_head = arc_head;
226 4200 : t->sw_if_index = arc_head ? sw_if_index[ii] : ~0;
227 4200 : t->feature_bitmap = vnet_buffer (b[ii])->l2.feature_bitmap;
228 4200 : t->ethertype = arc_head ? ethertype[ii] : 0;
229 4200 : t->next_index = next[ii];
230 : }
231 2618 : }
232 :
233 : always_inline uword
234 1102100 : l2_in_out_feat_arc_node_fn (vlib_main_t * vm,
235 : vlib_node_runtime_t * node, vlib_frame_t * frame,
236 : int is_output, vlib_node_registration_t * fa_node,
237 : int arc_head, int do_trace)
238 : {
239 : u32 n_left, *from;
240 : u16 nexts[VLIB_FRAME_SIZE], *next;
241 : u16 ethertypes[VLIB_FRAME_SIZE], *ethertype;
242 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
243 : u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
244 1102100 : l2_in_out_feat_arc_main_t *fam = &l2_in_out_feat_arc_main;
245 :
246 1102100 : u8 ip4_arc_index = fam->ip4_feat_arc_index[is_output];
247 1102100 : u8 ip6_arc_index = fam->ip6_feat_arc_index[is_output];
248 1102100 : u8 nonip_arc_index = fam->nonip_feat_arc_index[is_output];
249 1102100 : u32 *next_node_indices = fam->feat_next_node_index[is_output];
250 :
251 1102100 : from = vlib_frame_vector_args (frame);
252 1102100 : vlib_get_buffers (vm, from, bufs, frame->n_vectors);
253 : /* set the initial values for the current buffer the next pointers */
254 1102100 : b = bufs;
255 1102100 : next = nexts;
256 1102100 : ethertype = ethertypes;
257 1102100 : sw_if_index = sw_if_indices;
258 1102100 : n_left = frame->n_vectors;
259 :
260 1102100 : CLIB_PREFETCH (next_node_indices,
261 : sizeof (fam->feat_next_node_index[is_output]), LOAD);
262 :
263 21335200 : while (n_left > 3 * L2_FEAT_ARC_VEC_SIZE)
264 : {
265 20233100 : const int vec_sz = L2_FEAT_ARC_VEC_SIZE;
266 : /* prefetch next N buffers */
267 20233100 : buffer_prefetch_xN (vec_sz, b + 2 * vec_sz);
268 :
269 20233100 : if (arc_head)
270 : {
271 9185100 : get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
272 9185100 : get_ethertype_xN (vec_sz, is_output, b, ethertype);
273 9185100 : set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
274 : sw_if_index, ethertype, ip4_arc_index,
275 : ip6_arc_index, nonip_arc_index, next);
276 : }
277 : else
278 : {
279 11048000 : set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
280 : next);
281 : }
282 20233100 : if (do_trace)
283 1582 : maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
284 : next);
285 :
286 20233100 : next += vec_sz;
287 20233100 : b += vec_sz;
288 20233100 : sw_if_index += vec_sz;
289 20233100 : ethertype += vec_sz;
290 :
291 20233100 : n_left -= vec_sz;
292 : }
293 :
294 6390670 : while (n_left > 0)
295 : {
296 5288570 : const int vec_sz = 1;
297 :
298 5288570 : if (arc_head)
299 : {
300 2521740 : get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
301 2521740 : get_ethertype_xN (vec_sz, is_output, b, ethertype);
302 2521740 : set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
303 : sw_if_index, ethertype, ip4_arc_index,
304 : ip6_arc_index, nonip_arc_index, next);
305 : }
306 : else
307 : {
308 2766830 : set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
309 : next);
310 : }
311 5288570 : if (do_trace)
312 1036 : maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
313 : next);
314 :
315 5288570 : next += vec_sz;
316 5288570 : b += vec_sz;
317 5288570 : sw_if_index += vec_sz;
318 5288570 : ethertype += vec_sz;
319 :
320 5288570 : n_left -= vec_sz;
321 : }
322 :
323 1102100 : vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
324 :
325 1102100 : return frame->n_vectors;
326 : }
327 :
328 2304 : VLIB_NODE_FN (l2_in_feat_arc_node) (vlib_main_t * vm,
329 : vlib_node_runtime_t * node,
330 : vlib_frame_t * frame)
331 : {
332 68 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
333 68 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
334 : IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
335 : &l2_in_feat_arc_node, 1, 1);
336 : else
337 0 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
338 : IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
339 : &l2_in_feat_arc_node, 1, 0);
340 : }
341 :
342 558860 : VLIB_NODE_FN (l2_out_feat_arc_node) (vlib_main_t * vm,
343 : vlib_node_runtime_t * node,
344 : vlib_frame_t * frame)
345 : {
346 556624 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
347 35 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
348 : IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
349 : &l2_out_feat_arc_node, 1, 1);
350 : else
351 556589 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
352 : IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
353 : &l2_out_feat_arc_node, 1, 0);
354 : }
355 :
356 2291 : VLIB_NODE_FN (l2_in_feat_arc_end_node) (vlib_main_t * vm,
357 : vlib_node_runtime_t * node,
358 : vlib_frame_t * frame)
359 : {
360 55 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
361 55 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
362 : IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
363 : &l2_in_feat_arc_end_node, 0, 1);
364 : else
365 0 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
366 : IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
367 : &l2_in_feat_arc_end_node, 0, 0);
368 : }
369 :
370 547588 : VLIB_NODE_FN (l2_out_feat_arc_end_node) (vlib_main_t * vm,
371 : vlib_node_runtime_t * node,
372 : vlib_frame_t * frame)
373 : {
374 545352 : if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
375 32 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
376 : IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
377 : &l2_out_feat_arc_end_node, 0, 1);
378 : else
379 545320 : return l2_in_out_feat_arc_node_fn (vm, node, frame,
380 : IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
381 : &l2_out_feat_arc_end_node, 0, 0);
382 : }
383 :
384 :
385 : #ifndef CLIB_MARCH_VARIANT
386 : void
387 1790 : vnet_l2_in_out_feat_arc_enable_disable (u32 sw_if_index, int is_output,
388 : int enable_disable)
389 : {
390 1790 : if (is_output)
391 972 : l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_OUTPUT_FEAT_ARC,
392 : (u32) enable_disable);
393 : else
394 818 : l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_INPUT_FEAT_ARC,
395 : (u32) enable_disable);
396 1790 : }
397 : #endif /* CLIB_MARCH_VARIANT */
398 :
399 : /* *INDENT-OFF* */
400 1119 : VNET_FEATURE_ARC_INIT (l2_in_ip4_arc, static) =
401 : {
402 : .arc_name = "l2-input-ip4",
403 : .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
404 : .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
405 : };
406 :
407 1119 : VNET_FEATURE_ARC_INIT (l2_out_ip4_arc, static) =
408 : {
409 : .arc_name = "l2-output-ip4",
410 : .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
411 : .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
412 : };
413 :
414 1119 : VNET_FEATURE_ARC_INIT (l2_out_ip6_arc, static) =
415 : {
416 : .arc_name = "l2-input-ip6",
417 : .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
418 : .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
419 : };
420 1119 : VNET_FEATURE_ARC_INIT (l2_in_ip6_arc, static) =
421 : {
422 : .arc_name = "l2-output-ip6",
423 : .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
424 : .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
425 : };
426 :
427 1119 : VNET_FEATURE_ARC_INIT (l2_out_nonip_arc, static) =
428 : {
429 : .arc_name = "l2-input-nonip",
430 : .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
431 : .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
432 : };
433 1119 : VNET_FEATURE_ARC_INIT (l2_in_nonip_arc, static) =
434 : {
435 : .arc_name = "l2-output-nonip",
436 : .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
437 : .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
438 : };
439 :
440 :
441 : /* *INDENT-ON* */
442 :
443 :
444 : /* *INDENT-OFF* */
445 178120 : VLIB_REGISTER_NODE (l2_in_feat_arc_node) = {
446 : .name = "l2-input-feat-arc",
447 : .vector_size = sizeof (u32),
448 : .format_trace = format_l2_in_feat_arc_trace,
449 : .type = VLIB_NODE_TYPE_INTERNAL,
450 :
451 : .n_errors = ARRAY_LEN(l2_in_feat_arc_error_strings),
452 : .error_strings = l2_in_feat_arc_error_strings,
453 :
454 : };
455 :
456 178120 : VLIB_REGISTER_NODE (l2_out_feat_arc_node) = {
457 : .name = "l2-output-feat-arc",
458 : .vector_size = sizeof (u32),
459 : .format_trace = format_l2_out_feat_arc_trace,
460 : .type = VLIB_NODE_TYPE_INTERNAL,
461 :
462 : .n_errors = ARRAY_LEN(l2_out_feat_arc_error_strings),
463 : .error_strings = l2_out_feat_arc_error_strings,
464 :
465 : };
466 :
467 178120 : VLIB_REGISTER_NODE (l2_in_feat_arc_end_node) = {
468 : .name = "l2-input-feat-arc-end",
469 : .vector_size = sizeof (u32),
470 : .format_trace = format_l2_in_feat_arc_trace,
471 : .sibling_of = "l2-input-feat-arc",
472 : };
473 :
474 178120 : VLIB_REGISTER_NODE (l2_out_feat_arc_end_node) = {
475 : .name = "l2-output-feat-arc-end",
476 : .vector_size = sizeof (u32),
477 : .format_trace = format_l2_out_feat_arc_trace,
478 : .sibling_of = "l2-output-feat-arc",
479 : };
480 :
481 70583 : VNET_FEATURE_INIT (l2_in_ip4_arc_end, static) =
482 : {
483 : .arc_name = "l2-input-ip4",
484 : .node_name = "l2-input-feat-arc-end",
485 : .runs_before = 0, /* not before any other features */
486 : };
487 :
488 70583 : VNET_FEATURE_INIT (l2_out_ip4_arc_end, static) =
489 : {
490 : .arc_name = "l2-output-ip4",
491 : .node_name = "l2-output-feat-arc-end",
492 : .runs_before = 0, /* not before any other features */
493 : };
494 :
495 70583 : VNET_FEATURE_INIT (l2_in_ip6_arc_end, static) =
496 : {
497 : .arc_name = "l2-input-ip6",
498 : .node_name = "l2-input-feat-arc-end",
499 : .runs_before = 0, /* not before any other features */
500 : };
501 :
502 :
503 70583 : VNET_FEATURE_INIT (l2_out_ip6_arc_end, static) =
504 : {
505 : .arc_name = "l2-output-ip6",
506 : .node_name = "l2-output-feat-arc-end",
507 : .runs_before = 0, /* not before any other features */
508 : };
509 :
510 70583 : VNET_FEATURE_INIT (l2_in_nonip_arc_end, static) =
511 : {
512 : .arc_name = "l2-input-nonip",
513 : .node_name = "l2-input-feat-arc-end",
514 : .runs_before = 0, /* not before any other features */
515 : };
516 :
517 :
518 70583 : VNET_FEATURE_INIT (l2_out_nonip_arc_end, static) =
519 : {
520 : .arc_name = "l2-output-nonip",
521 : .node_name = "l2-output-feat-arc-end",
522 : .runs_before = 0, /* not before any other features */
523 : };
524 : /* *INDENT-ON* */
525 :
526 :
527 : #ifndef CLIB_MARCH_VARIANT
528 : clib_error_t *
529 559 : l2_in_out_feat_arc_init (vlib_main_t * vm)
530 : {
531 559 : l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
532 :
533 : /* Initialize the feature next-node indexes */
534 559 : feat_bitmap_init_next_nodes (vm,
535 : l2_in_feat_arc_end_node.index,
536 : L2INPUT_N_FEAT,
537 : l2input_get_feat_names (),
538 : mp->feat_next_node_index
539 559 : [IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP]);
540 559 : feat_bitmap_init_next_nodes (vm, l2_out_feat_arc_end_node.index,
541 : L2OUTPUT_N_FEAT, l2output_get_feat_names (),
542 : mp->feat_next_node_index
543 559 : [IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP]);
544 559 : return 0;
545 : }
546 :
547 :
548 : static int
549 1790 : l2_has_features (u32 sw_if_index, int is_output)
550 : {
551 1790 : int has_features = 0;
552 1790 : l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
553 1790 : has_features +=
554 1790 : vnet_have_features (mp->ip4_feat_arc_index[is_output], sw_if_index);
555 1790 : has_features +=
556 1790 : vnet_have_features (mp->ip6_feat_arc_index[is_output], sw_if_index);
557 1790 : has_features +=
558 1790 : vnet_have_features (mp->nonip_feat_arc_index[is_output], sw_if_index);
559 1790 : return has_features > 0;
560 : }
561 :
562 : static int
563 1790 : l2_is_output_arc (u8 arc_index)
564 : {
565 1790 : l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
566 1790 : int idx = IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP;
567 1790 : return (mp->ip4_feat_arc_index[idx] == arc_index
568 1304 : || mp->ip6_feat_arc_index[idx] == arc_index
569 3094 : || mp->nonip_feat_arc_index[idx] == arc_index);
570 : }
571 :
572 : static int
573 1790 : l2_is_input_arc (u8 arc_index)
574 : {
575 1790 : l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
576 1790 : int idx = IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP;
577 1790 : return (mp->ip4_feat_arc_index[idx] == arc_index
578 1386 : || mp->ip6_feat_arc_index[idx] == arc_index
579 3176 : || mp->nonip_feat_arc_index[idx] == arc_index);
580 : }
581 :
582 : int
583 3011 : vnet_l2_feature_enable_disable (const char *arc_name, const char *node_name,
584 : u32 sw_if_index, int enable_disable,
585 : void *feature_config,
586 : u32 n_feature_config_bytes)
587 : {
588 3011 : u8 arc_index = vnet_get_feature_arc_index (arc_name);
589 3011 : if (arc_index == (u8) ~ 0)
590 0 : return VNET_API_ERROR_INVALID_VALUE;
591 :
592 : /* check the state before we tried to enable/disable */
593 3011 : int had_features = vnet_have_features (arc_index, sw_if_index);
594 :
595 3011 : int ret = vnet_feature_enable_disable (arc_name, node_name, sw_if_index,
596 : enable_disable, feature_config,
597 : n_feature_config_bytes);
598 3011 : if (ret)
599 569 : return ret;
600 :
601 2442 : int has_features = vnet_have_features (arc_index, sw_if_index);
602 :
603 2442 : if (had_features != has_features)
604 : {
605 1790 : if (l2_is_output_arc (arc_index))
606 : {
607 972 : vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 1,
608 : l2_has_features
609 : (sw_if_index, 1));
610 : }
611 1790 : if (l2_is_input_arc (arc_index))
612 : {
613 818 : vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 0,
614 : l2_has_features
615 : (sw_if_index, 0));
616 : }
617 : }
618 2442 : return 0;
619 : }
620 :
621 :
622 22959 : VLIB_INIT_FUNCTION (l2_in_out_feat_arc_init);
623 : #endif /* CLIB_MARCH_VARIANT */
624 :
625 : /*
626 : * fd.io coding-style-patch-verification: ON
627 : *
628 : * Local Variables:
629 : * eval: (c-set-style "gnu")
630 : * End:
631 : */
|