2 * l2_in_out_feat_arc.c : layer 2 input/output acl processing
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vnet/pg/pg.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/ethernet/packet.h>
23 #include <vnet/ip/ip_packet.h>
24 #include <vnet/ip/ip4_packet.h>
25 #include <vnet/ip/ip6_packet.h>
27 #include <vnet/l2/l2_input.h>
28 #include <vnet/l2/l2_output.h>
29 #include <vnet/l2/feat_bitmap.h>
30 #include <vnet/l2/l2_in_out_feat_arc.h>
32 #include <vppinfra/error.h>
33 #include <vppinfra/hash.h>
34 #include <vppinfra/cache.h>
40 /* Next nodes for each feature */
41 u32 feat_next_node_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS][32];
42 u8 ip4_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
43 u8 ip6_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
44 u8 nonip_feat_arc_index[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
45 u32 next_slot[IN_OUT_FEAT_ARC_N_TABLE_GROUPS];
47 /* convenience variables */
48 vlib_main_t *vlib_main;
49 vnet_main_t *vnet_main;
50 } l2_in_out_feat_arc_main_t __attribute__ ((aligned (CLIB_CACHE_LINE_BYTES)));
59 } l2_in_out_feat_arc_trace_t;
61 /* packet trace format function */
63 format_l2_in_out_feat_arc_trace (u8 * s, u32 is_output, va_list * args)
65 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67 l2_in_out_feat_arc_trace_t *t =
68 va_arg (*args, l2_in_out_feat_arc_trace_t *);
72 "%s: head %d feature_bitmap %x ethertype %x sw_if_index %d, next_index %d",
73 is_output ? "OUT-FEAT-ARC" : "IN-FEAT-ARC", t->arc_head,
74 t->feature_bitmap, t->ethertype, t->sw_if_index, t->next_index);
79 format_l2_in_feat_arc_trace (u8 * s, va_list * args)
81 return format_l2_in_out_feat_arc_trace (s,
82 IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
87 format_l2_out_feat_arc_trace (u8 * s, va_list * args)
89 return format_l2_in_out_feat_arc_trace (s,
90 IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
95 #define foreach_l2_in_feat_arc_error \
96 _(DEFAULT, "in default") \
99 #define foreach_l2_out_feat_arc_error \
100 _(DEFAULT, "out default") \
105 #define _(sym,str) L2_IN_FEAT_ARC_ERROR_##sym,
106 foreach_l2_in_feat_arc_error
108 L2_IN_FEAT_ARC_N_ERROR,
109 } l2_in_feat_arc_error_t;
111 static char *l2_in_feat_arc_error_strings[] = {
112 #define _(sym,string) string,
113 foreach_l2_in_feat_arc_error
119 #define _(sym,str) L2_OUT_FEAT_ARC_ERROR_##sym,
120 foreach_l2_out_feat_arc_error
122 L2_OUT_FEAT_ARC_N_ERROR,
123 } l2_out_feat_arc_error_t;
125 static char *l2_out_feat_arc_error_strings[] = {
126 #define _(sym,string) string,
127 foreach_l2_out_feat_arc_error
132 l2_in_out_feat_arc_main_t l2_in_out_feat_arc_main;
134 #define get_u16(addr) ( *((u16 *)(addr)) )
135 #define L2_FEAT_ARC_VEC_SIZE 2
137 static_always_inline void
138 buffer_prefetch_xN (int vector_sz, vlib_buffer_t ** b)
141 for (ii = 0; ii < vector_sz; ii++)
142 CLIB_PREFETCH (b[ii], CLIB_CACHE_LINE_BYTES, STORE);
145 static_always_inline void
146 get_sw_if_index_xN (int vector_sz, int is_output, vlib_buffer_t ** b,
147 u32 * out_sw_if_index)
150 for (ii = 0; ii < vector_sz; ii++)
152 out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_TX];
154 out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_RX];
157 static_always_inline void
158 get_ethertype_xN (int vector_sz, int is_output, vlib_buffer_t ** b,
162 for (ii = 0; ii < vector_sz; ii++)
164 ethernet_header_t *h0 = vlib_buffer_get_current (b[ii]);
165 u8 *l3h0 = (u8 *) h0 + vnet_buffer (b[ii])->l2.l2_len;
166 out_ethertype[ii] = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
171 static_always_inline void
172 set_next_in_arc_head_xN (int vector_sz, int is_output, u32 * next_nodes,
173 vlib_buffer_t ** b, u32 * sw_if_index,
174 u16 * ethertype, u8 ip4_arc, u8 ip6_arc,
175 u8 nonip_arc, u16 * out_next)
178 for (ii = 0; ii < vector_sz; ii++)
182 switch (ethertype[ii])
184 case ETHERNET_TYPE_IP4:
185 feature_arc = ip4_arc;
187 case ETHERNET_TYPE_IP6:
188 feature_arc = ip6_arc;
191 feature_arc = nonip_arc;
193 if (PREDICT_TRUE (vnet_have_features (feature_arc, sw_if_index[ii])))
194 vnet_feature_arc_start (feature_arc,
195 sw_if_index[ii], &next_index, b[ii]);
198 vnet_l2_feature_next (b[ii], next_nodes,
199 is_output ? L2OUTPUT_FEAT_OUTPUT_FEAT_ARC :
200 L2INPUT_FEAT_INPUT_FEAT_ARC);
202 out_next[ii] = next_index;
206 static_always_inline void
207 set_next_in_arc_tail_xN (int vector_sz, int is_output, u32 * next_nodes,
208 vlib_buffer_t ** b, u16 * out_next)
211 for (ii = 0; ii < vector_sz; ii++)
214 vnet_l2_feature_next (b[ii], next_nodes,
215 is_output ? L2OUTPUT_FEAT_OUTPUT_FEAT_ARC :
216 L2INPUT_FEAT_INPUT_FEAT_ARC);
222 static_always_inline void
223 maybe_trace_xN (int vector_sz, int arc_head, vlib_main_t * vm,
224 vlib_node_runtime_t * node, vlib_buffer_t ** b,
225 u32 * sw_if_index, u16 * ethertype, u16 * next)
228 for (ii = 0; ii < vector_sz; ii++)
229 if (PREDICT_FALSE (b[ii]->flags & VLIB_BUFFER_IS_TRACED))
231 l2_in_out_feat_arc_trace_t *t =
232 vlib_add_trace (vm, node, b[ii], sizeof (*t));
233 t->arc_head = arc_head;
234 t->sw_if_index = arc_head ? sw_if_index[ii] : ~0;
235 t->feature_bitmap = vnet_buffer (b[ii])->l2.feature_bitmap;
236 t->ethertype = arc_head ? ethertype[ii] : 0;
237 t->next_index = next[ii];
242 l2_in_out_feat_arc_node_fn (vlib_main_t * vm,
243 vlib_node_runtime_t * node, vlib_frame_t * frame,
244 int is_output, vlib_node_registration_t * fa_node,
245 int arc_head, int do_trace)
248 u16 nexts[VLIB_FRAME_SIZE], *next;
249 u16 ethertypes[VLIB_FRAME_SIZE], *ethertype;
250 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
251 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
252 l2_in_out_feat_arc_main_t *fam = &l2_in_out_feat_arc_main;
254 u8 ip4_arc_index = fam->ip4_feat_arc_index[is_output];
255 u8 ip6_arc_index = fam->ip6_feat_arc_index[is_output];
256 u8 nonip_arc_index = fam->nonip_feat_arc_index[is_output];
257 u32 *next_node_indices = fam->feat_next_node_index[is_output];
259 from = vlib_frame_vector_args (frame);
260 vlib_get_buffers (vm, from, bufs, frame->n_vectors);
261 /* set the initial values for the current buffer the next pointers */
264 ethertype = ethertypes;
265 sw_if_index = sw_if_indices;
266 n_left = frame->n_vectors;
268 CLIB_PREFETCH (next_node_indices, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
270 while (n_left > 3 * L2_FEAT_ARC_VEC_SIZE)
272 const int vec_sz = L2_FEAT_ARC_VEC_SIZE;
273 /* prefetch next N buffers */
274 buffer_prefetch_xN (vec_sz, b + 2 * vec_sz);
278 get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
279 get_ethertype_xN (vec_sz, is_output, b, ethertype);
280 set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
281 sw_if_index, ethertype, ip4_arc_index,
282 ip6_arc_index, nonip_arc_index, next);
286 set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
290 maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
295 sw_if_index += vec_sz;
303 const int vec_sz = 1;
307 get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
308 get_ethertype_xN (vec_sz, is_output, b, ethertype);
309 set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
310 sw_if_index, ethertype, ip4_arc_index,
311 ip6_arc_index, nonip_arc_index, next);
315 set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
319 maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
324 sw_if_index += vec_sz;
330 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
332 return frame->n_vectors;
335 static vlib_node_registration_t l2_in_feat_arc_node;
337 l2_in_feat_arc_node_fn (vlib_main_t * vm,
338 vlib_node_runtime_t * node, vlib_frame_t * frame)
340 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
341 return l2_in_out_feat_arc_node_fn (vm, node, frame,
342 IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
343 &l2_in_feat_arc_node, 1, 1);
345 return l2_in_out_feat_arc_node_fn (vm, node, frame,
346 IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
347 &l2_in_feat_arc_node, 1, 0);
350 static vlib_node_registration_t l2_out_feat_arc_node;
352 l2_out_feat_arc_node_fn (vlib_main_t * vm,
353 vlib_node_runtime_t * node, vlib_frame_t * frame)
355 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
356 return l2_in_out_feat_arc_node_fn (vm, node, frame,
357 IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
358 &l2_out_feat_arc_node, 1, 1);
360 return l2_in_out_feat_arc_node_fn (vm, node, frame,
361 IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
362 &l2_out_feat_arc_node, 1, 0);
365 static vlib_node_registration_t l2_in_feat_arc_end_node;
367 l2_in_feat_arc_end_node_fn (vlib_main_t * vm,
368 vlib_node_runtime_t * node, vlib_frame_t * frame)
370 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
371 return l2_in_out_feat_arc_node_fn (vm, node, frame,
372 IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
373 &l2_in_feat_arc_end_node, 0, 1);
375 return l2_in_out_feat_arc_node_fn (vm, node, frame,
376 IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
377 &l2_in_feat_arc_end_node, 0, 0);
380 static vlib_node_registration_t l2_out_feat_arc_end_node;
382 l2_out_feat_arc_end_node_fn (vlib_main_t * vm,
383 vlib_node_runtime_t * node, vlib_frame_t * frame)
385 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
386 return l2_in_out_feat_arc_node_fn (vm, node, frame,
387 IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
388 &l2_out_feat_arc_end_node, 0, 1);
390 return l2_in_out_feat_arc_node_fn (vm, node, frame,
391 IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
392 &l2_out_feat_arc_end_node, 0, 0);
397 vnet_l2_in_out_feat_arc_enable_disable (u32 sw_if_index, int is_output,
401 l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_OUTPUT_FEAT_ARC,
402 (u32) enable_disable);
404 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_INPUT_FEAT_ARC,
405 (u32) enable_disable);
409 VNET_FEATURE_ARC_INIT (l2_in_ip4_arc, static) =
411 .arc_name = "l2-input-ip4",
412 .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
413 .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
416 VNET_FEATURE_ARC_INIT (l2_out_ip4_arc, static) =
418 .arc_name = "l2-output-ip4",
419 .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
420 .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
423 VNET_FEATURE_ARC_INIT (l2_out_ip6_arc, static) =
425 .arc_name = "l2-input-ip6",
426 .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
427 .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
429 VNET_FEATURE_ARC_INIT (l2_in_ip6_arc, static) =
431 .arc_name = "l2-output-ip6",
432 .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
433 .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
436 VNET_FEATURE_ARC_INIT (l2_out_nonip_arc, static) =
438 .arc_name = "l2-input-nonip",
439 .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
440 .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
442 VNET_FEATURE_ARC_INIT (l2_in_nonip_arc, static) =
444 .arc_name = "l2-output-nonip",
445 .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
446 .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
454 VLIB_REGISTER_NODE (l2_in_feat_arc_node,static) = {
455 .name = "l2-input-feat-arc",
456 .function = l2_in_feat_arc_node_fn,
457 .vector_size = sizeof (u32),
458 .format_trace = format_l2_in_feat_arc_trace,
459 .type = VLIB_NODE_TYPE_INTERNAL,
461 .n_errors = ARRAY_LEN(l2_in_feat_arc_error_strings),
462 .error_strings = l2_in_feat_arc_error_strings,
466 VLIB_REGISTER_NODE (l2_out_feat_arc_node,static) = {
467 .name = "l2-output-feat-arc",
468 .function = l2_out_feat_arc_node_fn,
469 .vector_size = sizeof (u32),
470 .format_trace = format_l2_out_feat_arc_trace,
471 .type = VLIB_NODE_TYPE_INTERNAL,
473 .n_errors = ARRAY_LEN(l2_out_feat_arc_error_strings),
474 .error_strings = l2_out_feat_arc_error_strings,
478 VLIB_REGISTER_NODE (l2_in_feat_arc_end_node,static) = {
479 .name = "l2-input-feat-arc-end",
480 .function = l2_in_feat_arc_end_node_fn,
481 .vector_size = sizeof (u32),
482 .format_trace = format_l2_in_feat_arc_trace,
483 .sibling_of = "l2-input-feat-arc",
486 VLIB_REGISTER_NODE (l2_out_feat_arc_end_node,static) = {
487 .name = "l2-output-feat-arc-end",
488 .function = l2_out_feat_arc_end_node_fn,
489 .vector_size = sizeof (u32),
490 .format_trace = format_l2_out_feat_arc_trace,
491 .sibling_of = "l2-output-feat-arc",
494 VNET_FEATURE_INIT (l2_in_ip4_arc_end, static) =
496 .arc_name = "l2-input-ip4",
497 .node_name = "l2-input-feat-arc-end",
498 .runs_before = 0, /* not before any other features */
501 VNET_FEATURE_INIT (l2_out_ip4_arc_end, static) =
503 .arc_name = "l2-output-ip4",
504 .node_name = "l2-output-feat-arc-end",
505 .runs_before = 0, /* not before any other features */
508 VNET_FEATURE_INIT (l2_in_ip6_arc_end, static) =
510 .arc_name = "l2-input-ip6",
511 .node_name = "l2-input-feat-arc-end",
512 .runs_before = 0, /* not before any other features */
516 VNET_FEATURE_INIT (l2_out_ip6_arc_end, static) =
518 .arc_name = "l2-output-ip6",
519 .node_name = "l2-output-feat-arc-end",
520 .runs_before = 0, /* not before any other features */
523 VNET_FEATURE_INIT (l2_in_nonip_arc_end, static) =
525 .arc_name = "l2-input-nonip",
526 .node_name = "l2-input-feat-arc-end",
527 .runs_before = 0, /* not before any other features */
531 VNET_FEATURE_INIT (l2_out_nonip_arc_end, static) =
533 .arc_name = "l2-output-nonip",
534 .node_name = "l2-output-feat-arc-end",
535 .runs_before = 0, /* not before any other features */
539 VLIB_NODE_FUNCTION_MULTIARCH (l2_in_feat_arc_node, l2_in_feat_arc_node_fn)
540 VLIB_NODE_FUNCTION_MULTIARCH (l2_out_feat_arc_node, l2_out_feat_arc_node_fn)
541 VLIB_NODE_FUNCTION_MULTIARCH (l2_in_feat_arc_end_node, l2_in_feat_arc_end_node_fn)
542 VLIB_NODE_FUNCTION_MULTIARCH (l2_out_feat_arc_end_node, l2_out_feat_arc_end_node_fn)
548 l2_in_out_feat_arc_init (vlib_main_t * vm)
550 l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
553 mp->vnet_main = vnet_get_main ();
555 /* Initialize the feature next-node indexes */
556 feat_bitmap_init_next_nodes (vm,
557 l2_in_feat_arc_end_node.index,
559 l2input_get_feat_names (),
560 mp->feat_next_node_index
561 [IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP]);
562 feat_bitmap_init_next_nodes (vm, l2_out_feat_arc_end_node.index,
563 L2OUTPUT_N_FEAT, l2output_get_feat_names (),
564 mp->feat_next_node_index
565 [IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP]);
571 l2_has_features (u32 sw_if_index, int is_output)
573 int has_features = 0;
574 l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
576 vnet_have_features (mp->ip4_feat_arc_index[is_output], sw_if_index);
578 vnet_have_features (mp->ip6_feat_arc_index[is_output], sw_if_index);
580 vnet_have_features (mp->nonip_feat_arc_index[is_output], sw_if_index);
581 return has_features > 0;
585 l2_is_output_arc (u8 arc_index)
587 l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
588 int idx = IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP;
589 return (mp->ip4_feat_arc_index[idx] == arc_index
590 || mp->ip6_feat_arc_index[idx] == arc_index
591 || mp->nonip_feat_arc_index[idx] == arc_index);
595 l2_is_input_arc (u8 arc_index)
597 l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
598 int idx = IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP;
599 return (mp->ip4_feat_arc_index[idx] == arc_index
600 || mp->ip6_feat_arc_index[idx] == arc_index
601 || mp->nonip_feat_arc_index[idx] == arc_index);
605 vnet_l2_feature_enable_disable (const char *arc_name, const char *node_name,
606 u32 sw_if_index, int enable_disable,
607 void *feature_config,
608 u32 n_feature_config_bytes)
610 u8 arc_index = vnet_get_feature_arc_index (arc_name);
611 if (arc_index == (u8) ~ 0)
612 return VNET_API_ERROR_INVALID_VALUE;
614 /* check the state before we tried to enable/disable */
615 int had_features = vnet_have_features (arc_index, sw_if_index);
617 int ret = vnet_feature_enable_disable (arc_name, node_name, sw_if_index,
618 enable_disable, feature_config,
619 n_feature_config_bytes);
623 int has_features = vnet_have_features (arc_index, sw_if_index);
625 if (had_features != has_features)
627 if (l2_is_output_arc (arc_index))
629 vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 1,
633 if (l2_is_input_arc (arc_index))
635 vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 0,
644 VLIB_INIT_FUNCTION (l2_in_out_feat_arc_init);
647 * fd.io coding-style-patch-verification: ON
650 * eval: (c-set-style "gnu")