l2: remove unused types and includes form feature arc code
[vpp.git] / src / vnet / l2 / l2_in_out_feat_arc.c
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 format_l2_in_out_feat_arc_trace (u8 * s, u32 is_output, va_list * args)
53 {
54   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
55   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
56   l2_in_out_feat_arc_trace_t *t =
57     va_arg (*args, l2_in_out_feat_arc_trace_t *);
58
59   s =
60     format (s,
61             "%s: head %d feature_bitmap %x ethertype %x sw_if_index %d, next_index %d",
62             is_output ? "OUT-FEAT-ARC" : "IN-FEAT-ARC", t->arc_head,
63             t->feature_bitmap, t->ethertype, t->sw_if_index, t->next_index);
64   return s;
65 }
66
67 static u8 *
68 format_l2_in_feat_arc_trace (u8 * s, va_list * args)
69 {
70   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 format_l2_out_feat_arc_trace (u8 * s, va_list * args)
77 {
78   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 buffer_prefetch_xN (int vector_sz, vlib_buffer_t ** b)
131 {
132   int ii;
133   for (ii = 0; ii < vector_sz; ii++)
134     CLIB_PREFETCH (b[ii], CLIB_CACHE_LINE_BYTES, STORE);
135 }
136
137 static_always_inline void
138 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   for (ii = 0; ii < vector_sz; ii++)
143     if (is_output)
144       out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_TX];
145     else
146       out_sw_if_index[ii] = vnet_buffer (b[ii])->sw_if_index[VLIB_RX];
147 }
148
149 static_always_inline void
150 get_ethertype_xN (int vector_sz, int is_output, vlib_buffer_t ** b,
151                   u16 * out_ethertype)
152 {
153   int ii;
154   for (ii = 0; ii < vector_sz; ii++)
155     {
156       ethernet_header_t *h0 = vlib_buffer_get_current (b[ii]);
157       u8 *l3h0 = (u8 *) h0 + vnet_buffer (b[ii])->l2.l2_len;
158       out_ethertype[ii] = clib_net_to_host_u16 (get_u16 (l3h0 - 2));
159     }
160 }
161
162
163 static_always_inline void
164 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   for (ii = 0; ii < vector_sz; ii++)
171     {
172       u32 next_index = 0;
173       u8 feature_arc;
174       switch (ethertype[ii])
175         {
176         case ETHERNET_TYPE_IP4:
177           feature_arc = ip4_arc;
178           break;
179         case ETHERNET_TYPE_IP6:
180           feature_arc = ip6_arc;
181           break;
182         default:
183           feature_arc = nonip_arc;
184         }
185       if (PREDICT_TRUE (vnet_have_features (feature_arc, sw_if_index[ii])))
186         vnet_feature_arc_start (feature_arc,
187                                 sw_if_index[ii], &next_index, b[ii]);
188       else
189         next_index =
190           vnet_l2_feature_next (b[ii], next_nodes,
191                                 is_output ? L2OUTPUT_FEAT_OUTPUT_FEAT_ARC :
192                                 L2INPUT_FEAT_INPUT_FEAT_ARC);
193
194       out_next[ii] = next_index;
195     }
196 }
197
198 static_always_inline void
199 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   for (ii = 0; ii < vector_sz; ii++)
204     {
205       out_next[ii] =
206         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 }
212
213
214 static_always_inline void
215 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   for (ii = 0; ii < vector_sz; ii++)
221     if (PREDICT_FALSE (b[ii]->flags & VLIB_BUFFER_IS_TRACED))
222       {
223         l2_in_out_feat_arc_trace_t *t =
224           vlib_add_trace (vm, node, b[ii], sizeof (*t));
225         t->arc_head = arc_head;
226         t->sw_if_index = arc_head ? sw_if_index[ii] : ~0;
227         t->feature_bitmap = vnet_buffer (b[ii])->l2.feature_bitmap;
228         t->ethertype = arc_head ? ethertype[ii] : 0;
229         t->next_index = next[ii];
230       }
231 }
232
233 always_inline uword
234 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   l2_in_out_feat_arc_main_t *fam = &l2_in_out_feat_arc_main;
245
246   u8 ip4_arc_index = fam->ip4_feat_arc_index[is_output];
247   u8 ip6_arc_index = fam->ip6_feat_arc_index[is_output];
248   u8 nonip_arc_index = fam->nonip_feat_arc_index[is_output];
249   u32 *next_node_indices = fam->feat_next_node_index[is_output];
250
251   from = vlib_frame_vector_args (frame);
252   vlib_get_buffers (vm, from, bufs, frame->n_vectors);
253   /* set the initial values for the current buffer the next pointers */
254   b = bufs;
255   next = nexts;
256   ethertype = ethertypes;
257   sw_if_index = sw_if_indices;
258   n_left = frame->n_vectors;
259
260   CLIB_PREFETCH (next_node_indices, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
261
262   while (n_left > 3 * L2_FEAT_ARC_VEC_SIZE)
263     {
264       const int vec_sz = L2_FEAT_ARC_VEC_SIZE;
265       /* prefetch next N buffers */
266       buffer_prefetch_xN (vec_sz, b + 2 * vec_sz);
267
268       if (arc_head)
269         {
270           get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
271           get_ethertype_xN (vec_sz, is_output, b, ethertype);
272           set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
273                                    sw_if_index, ethertype, ip4_arc_index,
274                                    ip6_arc_index, nonip_arc_index, next);
275         }
276       else
277         {
278           set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
279                                    next);
280         }
281       if (do_trace)
282         maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
283                         next);
284
285       next += vec_sz;
286       b += vec_sz;
287       sw_if_index += vec_sz;
288       ethertype += vec_sz;
289
290       n_left -= vec_sz;
291     }
292
293   while (n_left > 0)
294     {
295       const int vec_sz = 1;
296
297       if (arc_head)
298         {
299           get_sw_if_index_xN (vec_sz, is_output, b, sw_if_index);
300           get_ethertype_xN (vec_sz, is_output, b, ethertype);
301           set_next_in_arc_head_xN (vec_sz, is_output, next_node_indices, b,
302                                    sw_if_index, ethertype, ip4_arc_index,
303                                    ip6_arc_index, nonip_arc_index, next);
304         }
305       else
306         {
307           set_next_in_arc_tail_xN (vec_sz, is_output, next_node_indices, b,
308                                    next);
309         }
310       if (do_trace)
311         maybe_trace_xN (vec_sz, arc_head, vm, node, b, sw_if_index, ethertype,
312                         next);
313
314       next += vec_sz;
315       b += vec_sz;
316       sw_if_index += vec_sz;
317       ethertype += vec_sz;
318
319       n_left -= vec_sz;
320     }
321
322   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
323
324   return frame->n_vectors;
325 }
326
327 VLIB_NODE_FN (l2_in_feat_arc_node) (vlib_main_t * vm,
328                                     vlib_node_runtime_t * node,
329                                     vlib_frame_t * frame)
330 {
331   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
332     return l2_in_out_feat_arc_node_fn (vm, node, frame,
333                                        IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
334                                        &l2_in_feat_arc_node, 1, 1);
335   else
336     return l2_in_out_feat_arc_node_fn (vm, node, frame,
337                                        IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
338                                        &l2_in_feat_arc_node, 1, 0);
339 }
340
341 VLIB_NODE_FN (l2_out_feat_arc_node) (vlib_main_t * vm,
342                                      vlib_node_runtime_t * node,
343                                      vlib_frame_t * frame)
344 {
345   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
346     return l2_in_out_feat_arc_node_fn (vm, node, frame,
347                                        IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
348                                        &l2_out_feat_arc_node, 1, 1);
349   else
350     return l2_in_out_feat_arc_node_fn (vm, node, frame,
351                                        IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
352                                        &l2_out_feat_arc_node, 1, 0);
353 }
354
355 VLIB_NODE_FN (l2_in_feat_arc_end_node) (vlib_main_t * vm,
356                                         vlib_node_runtime_t * node,
357                                         vlib_frame_t * frame)
358 {
359   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
360     return l2_in_out_feat_arc_node_fn (vm, node, frame,
361                                        IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
362                                        &l2_in_feat_arc_end_node, 0, 1);
363   else
364     return l2_in_out_feat_arc_node_fn (vm, node, frame,
365                                        IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP,
366                                        &l2_in_feat_arc_end_node, 0, 0);
367 }
368
369 VLIB_NODE_FN (l2_out_feat_arc_end_node) (vlib_main_t * vm,
370                                          vlib_node_runtime_t * node,
371                                          vlib_frame_t * frame)
372 {
373   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
374     return l2_in_out_feat_arc_node_fn (vm, node, frame,
375                                        IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
376                                        &l2_out_feat_arc_end_node, 0, 1);
377   else
378     return l2_in_out_feat_arc_node_fn (vm, node, frame,
379                                        IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP,
380                                        &l2_out_feat_arc_end_node, 0, 0);
381 }
382
383
384 #ifndef CLIB_MARCH_VARIANT
385 void
386 vnet_l2_in_out_feat_arc_enable_disable (u32 sw_if_index, int is_output,
387                                         int enable_disable)
388 {
389   if (is_output)
390     l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_OUTPUT_FEAT_ARC,
391                                  (u32) enable_disable);
392   else
393     l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_INPUT_FEAT_ARC,
394                                 (u32) enable_disable);
395 }
396 #endif /* CLIB_MARCH_VARIANT */
397
398 /* *INDENT-OFF* */
399 VNET_FEATURE_ARC_INIT (l2_in_ip4_arc, static) =
400 {
401   .arc_name  = "l2-input-ip4",
402   .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
403   .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
404 };
405
406 VNET_FEATURE_ARC_INIT (l2_out_ip4_arc, static) =
407 {
408   .arc_name  = "l2-output-ip4",
409   .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
410   .arc_index_ptr = &l2_in_out_feat_arc_main.ip4_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
411 };
412
413 VNET_FEATURE_ARC_INIT (l2_out_ip6_arc, static) =
414 {
415   .arc_name  = "l2-input-ip6",
416   .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
417   .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
418 };
419 VNET_FEATURE_ARC_INIT (l2_in_ip6_arc, static) =
420 {
421   .arc_name  = "l2-output-ip6",
422   .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
423   .arc_index_ptr = &l2_in_out_feat_arc_main.ip6_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
424 };
425
426 VNET_FEATURE_ARC_INIT (l2_out_nonip_arc, static) =
427 {
428   .arc_name  = "l2-input-nonip",
429   .start_nodes = VNET_FEATURES ("l2-input-feat-arc"),
430   .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP],
431 };
432 VNET_FEATURE_ARC_INIT (l2_in_nonip_arc, static) =
433 {
434   .arc_name  = "l2-output-nonip",
435   .start_nodes = VNET_FEATURES ("l2-output-feat-arc"),
436   .arc_index_ptr = &l2_in_out_feat_arc_main.nonip_feat_arc_index[IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP],
437 };
438
439
440 /* *INDENT-ON* */
441
442
443 /* *INDENT-OFF* */
444 VLIB_REGISTER_NODE (l2_in_feat_arc_node) = {
445   .name = "l2-input-feat-arc",
446   .vector_size = sizeof (u32),
447   .format_trace = format_l2_in_feat_arc_trace,
448   .type = VLIB_NODE_TYPE_INTERNAL,
449
450   .n_errors = ARRAY_LEN(l2_in_feat_arc_error_strings),
451   .error_strings = l2_in_feat_arc_error_strings,
452
453 };
454
455 VLIB_REGISTER_NODE (l2_out_feat_arc_node) = {
456   .name = "l2-output-feat-arc",
457   .vector_size = sizeof (u32),
458   .format_trace = format_l2_out_feat_arc_trace,
459   .type = VLIB_NODE_TYPE_INTERNAL,
460
461   .n_errors = ARRAY_LEN(l2_out_feat_arc_error_strings),
462   .error_strings = l2_out_feat_arc_error_strings,
463
464 };
465
466 VLIB_REGISTER_NODE (l2_in_feat_arc_end_node) = {
467   .name = "l2-input-feat-arc-end",
468   .vector_size = sizeof (u32),
469   .format_trace = format_l2_in_feat_arc_trace,
470   .sibling_of = "l2-input-feat-arc",
471 };
472
473 VLIB_REGISTER_NODE (l2_out_feat_arc_end_node) = {
474   .name = "l2-output-feat-arc-end",
475   .vector_size = sizeof (u32),
476   .format_trace = format_l2_out_feat_arc_trace,
477   .sibling_of = "l2-output-feat-arc",
478 };
479
480 VNET_FEATURE_INIT (l2_in_ip4_arc_end, static) =
481 {
482   .arc_name = "l2-input-ip4",
483   .node_name = "l2-input-feat-arc-end",
484   .runs_before = 0,     /* not before any other features */
485 };
486
487 VNET_FEATURE_INIT (l2_out_ip4_arc_end, static) =
488 {
489   .arc_name = "l2-output-ip4",
490   .node_name = "l2-output-feat-arc-end",
491   .runs_before = 0,     /* not before any other features */
492 };
493
494 VNET_FEATURE_INIT (l2_in_ip6_arc_end, static) =
495 {
496   .arc_name = "l2-input-ip6",
497   .node_name = "l2-input-feat-arc-end",
498   .runs_before = 0,     /* not before any other features */
499 };
500
501
502 VNET_FEATURE_INIT (l2_out_ip6_arc_end, static) =
503 {
504   .arc_name = "l2-output-ip6",
505   .node_name = "l2-output-feat-arc-end",
506   .runs_before = 0,     /* not before any other features */
507 };
508
509 VNET_FEATURE_INIT (l2_in_nonip_arc_end, static) =
510 {
511   .arc_name = "l2-input-nonip",
512   .node_name = "l2-input-feat-arc-end",
513   .runs_before = 0,     /* not before any other features */
514 };
515
516
517 VNET_FEATURE_INIT (l2_out_nonip_arc_end, static) =
518 {
519   .arc_name = "l2-output-nonip",
520   .node_name = "l2-output-feat-arc-end",
521   .runs_before = 0,     /* not before any other features */
522 };
523 /* *INDENT-ON* */
524
525
526 #ifndef CLIB_MARCH_VARIANT
527 clib_error_t *
528 l2_in_out_feat_arc_init (vlib_main_t * vm)
529 {
530   l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
531
532   /* Initialize the feature next-node indexes */
533   feat_bitmap_init_next_nodes (vm,
534                                l2_in_feat_arc_end_node.index,
535                                L2INPUT_N_FEAT,
536                                l2input_get_feat_names (),
537                                mp->feat_next_node_index
538                                [IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP]);
539   feat_bitmap_init_next_nodes (vm, l2_out_feat_arc_end_node.index,
540                                L2OUTPUT_N_FEAT, l2output_get_feat_names (),
541                                mp->feat_next_node_index
542                                [IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP]);
543   return 0;
544 }
545
546
547 static int
548 l2_has_features (u32 sw_if_index, int is_output)
549 {
550   int has_features = 0;
551   l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
552   has_features +=
553     vnet_have_features (mp->ip4_feat_arc_index[is_output], sw_if_index);
554   has_features +=
555     vnet_have_features (mp->ip6_feat_arc_index[is_output], sw_if_index);
556   has_features +=
557     vnet_have_features (mp->nonip_feat_arc_index[is_output], sw_if_index);
558   return has_features > 0;
559 }
560
561 static int
562 l2_is_output_arc (u8 arc_index)
563 {
564   l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
565   int idx = IN_OUT_FEAT_ARC_OUTPUT_TABLE_GROUP;
566   return (mp->ip4_feat_arc_index[idx] == arc_index
567           || mp->ip6_feat_arc_index[idx] == arc_index
568           || mp->nonip_feat_arc_index[idx] == arc_index);
569 }
570
571 static int
572 l2_is_input_arc (u8 arc_index)
573 {
574   l2_in_out_feat_arc_main_t *mp = &l2_in_out_feat_arc_main;
575   int idx = IN_OUT_FEAT_ARC_INPUT_TABLE_GROUP;
576   return (mp->ip4_feat_arc_index[idx] == arc_index
577           || mp->ip6_feat_arc_index[idx] == arc_index
578           || mp->nonip_feat_arc_index[idx] == arc_index);
579 }
580
581 int
582 vnet_l2_feature_enable_disable (const char *arc_name, const char *node_name,
583                                 u32 sw_if_index, int enable_disable,
584                                 void *feature_config,
585                                 u32 n_feature_config_bytes)
586 {
587   u8 arc_index = vnet_get_feature_arc_index (arc_name);
588   if (arc_index == (u8) ~ 0)
589     return VNET_API_ERROR_INVALID_VALUE;
590
591   /* check the state before we tried to enable/disable */
592   int had_features = vnet_have_features (arc_index, sw_if_index);
593
594   int ret = vnet_feature_enable_disable (arc_name, node_name, sw_if_index,
595                                          enable_disable, feature_config,
596                                          n_feature_config_bytes);
597   if (ret)
598     return ret;
599
600   int has_features = vnet_have_features (arc_index, sw_if_index);
601
602   if (had_features != has_features)
603     {
604       if (l2_is_output_arc (arc_index))
605         {
606           vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 1,
607                                                   l2_has_features
608                                                   (sw_if_index, 1));
609         }
610       if (l2_is_input_arc (arc_index))
611         {
612           vnet_l2_in_out_feat_arc_enable_disable (sw_if_index, 0,
613                                                   l2_has_features
614                                                   (sw_if_index, 0));
615         }
616     }
617   return 0;
618 }
619
620
621 VLIB_INIT_FUNCTION (l2_in_out_feat_arc_init);
622 #endif /* CLIB_MARCH_VARIANT */
623
624 /*
625  * fd.io coding-style-patch-verification: ON
626  *
627  * Local Variables:
628  * eval: (c-set-style "gnu")
629  * End:
630  */