2 * Copyright (c) 2015 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vlib/vlib.h>
19 #include <vnet/vnet.h>
20 #include <vnet/policer/policer.h>
21 #include <vnet/policer/police_inlines.h>
22 #include <vnet/ip/ip.h>
23 #include <vnet/classify/policer_classify.h>
24 #include <vnet/classify/vnet_classify.h>
27 /* Dispatch functions meant to be instantiated elsewhere */
34 } vnet_policer_trace_t;
36 /* packet trace format function */
38 format_policer_trace (u8 * s, va_list * args)
40 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
41 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
42 vnet_policer_trace_t *t = va_arg (*args, vnet_policer_trace_t *);
44 s = format (s, "VNET_POLICER: sw_if_index %d policer_index %d next %d",
45 t->sw_if_index, t->policer_index, t->next_index);
49 #define foreach_vnet_policer_error \
50 _(TRANSMIT, "Packets Transmitted") \
51 _(DROP, "Packets Dropped")
55 #define _(sym,str) VNET_POLICER_ERROR_##sym,
56 foreach_vnet_policer_error
59 } vnet_policer_error_t;
61 static char *vnet_policer_error_strings[] = {
62 #define _(sym,string) string,
63 foreach_vnet_policer_error
68 vnet_policer_inline (vlib_main_t * vm,
69 vlib_node_runtime_t * node,
70 vlib_frame_t * frame, vnet_policer_index_t which)
72 u32 n_left_from, *from, *to_next;
73 vnet_policer_next_t next_index;
74 vnet_policer_main_t *pm = &vnet_policer_main;
75 u64 time_in_policer_periods;
78 time_in_policer_periods =
79 clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
81 from = vlib_frame_vector_args (frame);
82 n_left_from = frame->n_vectors;
83 next_index = node->cached_next_index;
85 while (n_left_from > 0)
89 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
91 while (n_left_from >= 4 && n_left_to_next >= 2)
94 vlib_buffer_t *b0, *b1;
96 u32 sw_if_index0, sw_if_index1;
100 /* Prefetch next iteration. */
102 vlib_buffer_t *b2, *b3;
104 b2 = vlib_get_buffer (vm, from[2]);
105 b3 = vlib_get_buffer (vm, from[3]);
107 vlib_prefetch_buffer_header (b2, LOAD);
108 vlib_prefetch_buffer_header (b3, LOAD);
111 /* speculatively enqueue b0 and b1 to the current next frame */
112 to_next[0] = bi0 = from[0];
113 to_next[1] = bi1 = from[1];
119 b0 = vlib_get_buffer (vm, bi0);
120 b1 = vlib_get_buffer (vm, bi1);
122 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
123 next0 = VNET_POLICER_NEXT_TRANSMIT;
125 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
126 next1 = VNET_POLICER_NEXT_TRANSMIT;
129 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
131 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
132 pi1 = pm->policer_index_by_sw_if_index[sw_if_index1];
135 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
137 pi0 = vnet_buffer (b0)->policer.index;
138 pi1 = vnet_buffer (b1)->policer.index;
141 if (which == VNET_POLICER_INDEX_BY_EITHER)
143 pi0 = vnet_buffer (b0)->policer.index;
144 pi0 = (pi0 != ~0) ? pi0 :
145 pm->policer_index_by_sw_if_index[sw_if_index0];
146 pi1 = vnet_buffer (b1)->policer.index;
147 pi1 = (pi1 != ~0) ? pi1 :
148 pm->policer_index_by_sw_if_index[sw_if_index1];
151 act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
152 POLICE_CONFORM /* no chaining */ );
154 act1 = vnet_policer_police (vm, b1, pi1, time_in_policer_periods,
155 POLICE_CONFORM /* no chaining */ );
157 if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
159 next0 = VNET_POLICER_NEXT_DROP;
160 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
162 else /* transmit or mark-and-transmit action */
167 if (PREDICT_FALSE (act1 == SSE2_QOS_ACTION_DROP)) /* drop action */
169 next1 = VNET_POLICER_NEXT_DROP;
170 b1->error = node->errors[VNET_POLICER_ERROR_DROP];
172 else /* transmit or mark-and-transmit action */
178 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
180 if (b0->flags & VLIB_BUFFER_IS_TRACED)
182 vnet_policer_trace_t *t =
183 vlib_add_trace (vm, node, b0, sizeof (*t));
184 t->sw_if_index = sw_if_index0;
185 t->next_index = next0;
187 if (b1->flags & VLIB_BUFFER_IS_TRACED)
189 vnet_policer_trace_t *t =
190 vlib_add_trace (vm, node, b1, sizeof (*t));
191 t->sw_if_index = sw_if_index1;
192 t->next_index = next1;
196 /* verify speculative enqueues, maybe switch current next frame */
197 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
198 to_next, n_left_to_next,
199 bi0, bi1, next0, next1);
202 while (n_left_from > 0 && n_left_to_next > 0)
218 b0 = vlib_get_buffer (vm, bi0);
220 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
221 next0 = VNET_POLICER_NEXT_TRANSMIT;
223 if (which == VNET_POLICER_INDEX_BY_SW_IF_INDEX)
224 pi0 = pm->policer_index_by_sw_if_index[sw_if_index0];
226 if (which == VNET_POLICER_INDEX_BY_OPAQUE)
227 pi0 = vnet_buffer (b0)->policer.index;
229 if (which == VNET_POLICER_INDEX_BY_EITHER)
231 pi0 = vnet_buffer (b0)->policer.index;
232 pi0 = (pi0 != ~0) ? pi0 :
233 pm->policer_index_by_sw_if_index[sw_if_index0];
236 act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
237 POLICE_CONFORM /* no chaining */ );
239 if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP)) /* drop action */
241 next0 = VNET_POLICER_NEXT_DROP;
242 b0->error = node->errors[VNET_POLICER_ERROR_DROP];
244 else /* transmit or mark-and-transmit action */
249 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
250 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
252 vnet_policer_trace_t *t =
253 vlib_add_trace (vm, node, b0, sizeof (*t));
254 t->sw_if_index = sw_if_index0;
255 t->next_index = next0;
256 t->policer_index = pi0;
259 /* verify speculative enqueue, maybe switch current next frame */
260 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
261 to_next, n_left_to_next,
265 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
268 vlib_node_increment_counter (vm, node->node_index,
269 VNET_POLICER_ERROR_TRANSMIT, transmitted);
270 return frame->n_vectors;
274 vnet_policer_by_sw_if_index (vlib_main_t * vm,
275 vlib_node_runtime_t * node, vlib_frame_t * frame)
277 return vnet_policer_inline (vm, node, frame,
278 VNET_POLICER_INDEX_BY_SW_IF_INDEX);
282 vnet_policer_by_opaque (vlib_main_t * vm,
283 vlib_node_runtime_t * node, vlib_frame_t * frame)
285 return vnet_policer_inline (vm, node, frame, VNET_POLICER_INDEX_BY_OPAQUE);
289 vnet_policer_by_either (vlib_main_t * vm,
290 vlib_node_runtime_t * node, vlib_frame_t * frame)
292 return vnet_policer_inline (vm, node, frame, VNET_POLICER_INDEX_BY_EITHER);
296 vnet_policer_node_funcs_reference (void)
306 VLIB_REGISTER_NODE (policer_by_sw_if_index_node, static) = {
307 .function = vnet_policer_by_sw_if_index,
308 .name = "policer-by-sw-if-index",
309 .vector_size = sizeof (u32),
310 .format_trace = format_policer_trace,
311 .type = VLIB_NODE_TYPE_INTERNAL,
313 .n_errors = ARRAY_LEN(vnet_policer_error_strings),
314 .error_strings = vnet_policer_error_strings,
316 .n_next_nodes = VNET_POLICER_N_NEXT,
318 /* edit / add dispositions here */
320 [VNET_POLICER_NEXT_TRANSMIT] = "ethernet-input",
321 [VNET_POLICER_NEXT_DROP] = "error-drop",
325 VLIB_NODE_FUNCTION_MULTIARCH (policer_by_sw_if_index_node,
326 vnet_policer_by_sw_if_index);
331 test_policer_add_del (u32 rx_sw_if_index, u8 * config_name, int is_add)
333 vnet_policer_main_t *pm = &vnet_policer_main;
334 policer_read_response_type_st *template;
335 policer_read_response_type_st *policer;
336 vnet_hw_interface_t *rxhi;
339 rxhi = vnet_get_sup_hw_interface (pm->vnet_main, rx_sw_if_index);
341 /* Make sure caller didn't pass a vlan subif, etc. */
342 if (rxhi->sw_if_index != rx_sw_if_index)
343 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
348 p = hash_get_mem (pm->policer_config_by_name, config_name);
353 template = pool_elt_at_index (pm->policer_templates, p[0]);
355 vnet_hw_interface_rx_redirect_to_node
356 (pm->vnet_main, rxhi->hw_if_index, policer_by_sw_if_index_node.index);
358 pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
360 policer[0] = template[0];
362 vec_validate (pm->policer_index_by_sw_if_index, rx_sw_if_index);
363 pm->policer_index_by_sw_if_index[rx_sw_if_index]
364 = policer - pm->policers;
369 vnet_hw_interface_rx_redirect_to_node (pm->vnet_main,
373 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
374 pm->policer_index_by_sw_if_index[rx_sw_if_index] = ~0;
375 pool_put_index (pm->policers, pi);
381 static clib_error_t *
382 test_policer_command_fn (vlib_main_t * vm,
383 unformat_input_t * input, vlib_cli_command_t * cmd)
385 vnet_policer_main_t *pm = &vnet_policer_main;
386 unformat_input_t _line_input, *line_input = &_line_input;
393 clib_error_t *error = NULL;
395 /* Get a line of input. */
396 if (!unformat_user (input, unformat_line_input, line_input))
399 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
401 if (unformat (line_input, "intfc %U", unformat_vnet_sw_interface,
402 pm->vnet_main, &rx_sw_if_index))
404 else if (unformat (line_input, "show"))
406 else if (unformat (line_input, "policer %s", &config_name))
408 else if (unformat (line_input, "del"))
416 error = clib_error_return (0, "interface not set");
422 u32 pi = pm->policer_index_by_sw_if_index[rx_sw_if_index];
423 policer_read_response_type_st *policer;
424 policer = pool_elt_at_index (pm->policers, pi);
426 vlib_cli_output (vm, "%U", format_policer_instance, policer);
430 if (is_add && config_name == 0)
432 error = clib_error_return (0, "policer config name required");
436 rv = test_policer_add_del (rx_sw_if_index, config_name, is_add);
444 error = clib_error_return
445 (0, "WARNING: vnet_vnet_policer_add_del returned %d", rv);
450 unformat_free (line_input);
456 VLIB_CLI_COMMAND (test_patch_command, static) = {
457 .path = "test policer",
459 "intfc <intfc> policer <policer-config-name> [del]",
460 .function = test_policer_command_fn,
464 #endif /* TEST_CODE */
474 } policer_classify_trace_t;
477 format_policer_classify_trace (u8 * s, va_list * args)
479 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
480 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
481 policer_classify_trace_t *t = va_arg (*args, policer_classify_trace_t *);
483 s = format (s, "POLICER_CLASSIFY: sw_if_index %d next %d table %d offset %d"
485 t->sw_if_index, t->next_index, t->table_index, t->offset,
490 #define foreach_policer_classify_error \
491 _(MISS, "Policer classify misses") \
492 _(HIT, "Policer classify hits") \
493 _(CHAIN_HIT, "Polcier classify hits after chain walk") \
494 _(DROP, "Policer classify action drop")
498 #define _(sym,str) POLICER_CLASSIFY_ERROR_##sym,
499 foreach_policer_classify_error
501 POLICER_CLASSIFY_N_ERROR,
502 } policer_classify_error_t;
504 static char *policer_classify_error_strings[] = {
505 #define _(sym,string) string,
506 foreach_policer_classify_error
511 policer_classify_inline (vlib_main_t * vm,
512 vlib_node_runtime_t * node,
513 vlib_frame_t * frame,
514 policer_classify_table_id_t tid)
516 u32 n_left_from, *from, *to_next;
517 policer_classify_next_index_t next_index;
518 policer_classify_main_t *pcm = &policer_classify_main;
519 vnet_classify_main_t *vcm = pcm->vnet_classify_main;
520 f64 now = vlib_time_now (vm);
526 u64 time_in_policer_periods;
528 time_in_policer_periods =
529 clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
531 n_next_nodes = node->n_next_nodes;
533 from = vlib_frame_vector_args (frame);
534 n_left_from = frame->n_vectors;
536 /* First pass: compute hashes */
537 while (n_left_from > 2)
539 vlib_buffer_t *b0, *b1;
542 u32 sw_if_index0, sw_if_index1;
543 u32 table_index0, table_index1;
544 vnet_classify_table_t *t0, *t1;
546 /* Prefetch next iteration */
548 vlib_buffer_t *p1, *p2;
550 p1 = vlib_get_buffer (vm, from[1]);
551 p2 = vlib_get_buffer (vm, from[2]);
553 vlib_prefetch_buffer_header (p1, STORE);
554 CLIB_PREFETCH (p1->data, CLIB_CACHE_LINE_BYTES, STORE);
555 vlib_prefetch_buffer_header (p2, STORE);
556 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
560 b0 = vlib_get_buffer (vm, bi0);
564 b1 = vlib_get_buffer (vm, bi1);
567 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
569 pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
571 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
573 pcm->classify_table_index_by_sw_if_index[tid][sw_if_index1];
575 t0 = pool_elt_at_index (vcm->tables, table_index0);
577 t1 = pool_elt_at_index (vcm->tables, table_index1);
579 vnet_buffer (b0)->l2_classify.hash =
580 vnet_classify_hash_packet (t0, (u8 *) h0);
582 vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
584 vnet_buffer (b1)->l2_classify.hash =
585 vnet_classify_hash_packet (t1, (u8 *) h1);
587 vnet_classify_prefetch_bucket (t1, vnet_buffer (b1)->l2_classify.hash);
589 vnet_buffer (b0)->l2_classify.table_index = table_index0;
591 vnet_buffer (b1)->l2_classify.table_index = table_index1;
597 while (n_left_from > 0)
604 vnet_classify_table_t *t0;
607 b0 = vlib_get_buffer (vm, bi0);
610 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
612 pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
614 t0 = pool_elt_at_index (vcm->tables, table_index0);
615 vnet_buffer (b0)->l2_classify.hash =
616 vnet_classify_hash_packet (t0, (u8 *) h0);
618 vnet_buffer (b0)->l2_classify.table_index = table_index0;
619 vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
625 next_index = node->cached_next_index;
626 from = vlib_frame_vector_args (frame);
627 n_left_from = frame->n_vectors;
629 while (n_left_from > 0)
633 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
635 /* Not enough load/store slots to dual loop... */
636 while (n_left_from > 0 && n_left_to_next > 0)
640 u32 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
642 vnet_classify_table_t *t0;
643 vnet_classify_entry_t *e0;
648 /* Stride 3 seems to work best */
649 if (PREDICT_TRUE (n_left_from > 3))
651 vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
652 vnet_classify_table_t *tp1;
656 table_index1 = vnet_buffer (p1)->l2_classify.table_index;
658 if (PREDICT_TRUE (table_index1 != ~0))
660 tp1 = pool_elt_at_index (vcm->tables, table_index1);
661 phash1 = vnet_buffer (p1)->l2_classify.hash;
662 vnet_classify_prefetch_entry (tp1, phash1);
666 /* Speculatively enqueue b0 to the current next frame */
674 b0 = vlib_get_buffer (vm, bi0);
676 table_index0 = vnet_buffer (b0)->l2_classify.table_index;
680 if (tid == POLICER_CLASSIFY_TABLE_L2)
682 /* Feature bitmap update and determine the next node */
683 next0 = vnet_l2_feature_next (b0, pcm->feat_next_node_index,
684 L2INPUT_FEAT_POLICER_CLAS);
687 vnet_get_config_data (pcm->vnet_config_main[tid],
688 &b0->current_config_index, &next0,
689 /* # bytes of config data */ 0);
691 vnet_buffer (b0)->l2_classify.opaque_index = ~0;
693 if (PREDICT_TRUE (table_index0 != ~0))
695 hash0 = vnet_buffer (b0)->l2_classify.hash;
696 t0 = pool_elt_at_index (vcm->tables, table_index0);
697 e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
701 act0 = vnet_policer_police (vm,
704 time_in_policer_periods,
706 if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
708 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
709 b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
718 if (PREDICT_TRUE (t0->next_table_index != ~0))
720 t0 = pool_elt_at_index (vcm->tables,
721 t0->next_table_index);
725 next0 = (t0->miss_next_index < n_next_nodes) ?
726 t0->miss_next_index : next0;
731 hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
733 vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
736 act0 = vnet_policer_police (vm,
739 time_in_policer_periods,
741 if (PREDICT_FALSE (act0 == SSE2_QOS_ACTION_DROP))
743 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
745 node->errors[POLICER_CLASSIFY_ERROR_DROP];
755 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
756 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
758 policer_classify_trace_t *t =
759 vlib_add_trace (vm, node, b0, sizeof (*t));
760 t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
761 t->next_index = next0;
762 t->table_index = t0 ? t0 - vcm->tables : ~0;
763 t->offset = (e0 && t0) ? vnet_classify_get_offset (t0, e0) : ~0;
764 t->policer_index = e0 ? e0->next_index : ~0;
767 /* Verify speculative enqueue, maybe switch current next frame */
768 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
769 n_left_to_next, bi0, next0);
772 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
775 vlib_node_increment_counter (vm, node->node_index,
776 POLICER_CLASSIFY_ERROR_MISS, misses);
777 vlib_node_increment_counter (vm, node->node_index,
778 POLICER_CLASSIFY_ERROR_HIT, hits);
779 vlib_node_increment_counter (vm, node->node_index,
780 POLICER_CLASSIFY_ERROR_CHAIN_HIT, chain_hits);
781 vlib_node_increment_counter (vm, node->node_index,
782 POLICER_CLASSIFY_ERROR_DROP, drop);
784 return frame->n_vectors;
788 ip4_policer_classify (vlib_main_t * vm,
789 vlib_node_runtime_t * node, vlib_frame_t * frame)
791 return policer_classify_inline (vm, node, frame,
792 POLICER_CLASSIFY_TABLE_IP4);
796 VLIB_REGISTER_NODE (ip4_policer_classify_node) = {
797 .function = ip4_policer_classify,
798 .name = "ip4-policer-classify",
799 .vector_size = sizeof (u32),
800 .format_trace = format_policer_classify_trace,
801 .n_errors = ARRAY_LEN(policer_classify_error_strings),
802 .error_strings = policer_classify_error_strings,
803 .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
805 [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
809 VLIB_NODE_FUNCTION_MULTIARCH (ip4_policer_classify_node, ip4_policer_classify);
813 ip6_policer_classify (vlib_main_t * vm,
814 vlib_node_runtime_t * node, vlib_frame_t * frame)
816 return policer_classify_inline (vm, node, frame,
817 POLICER_CLASSIFY_TABLE_IP6);
821 VLIB_REGISTER_NODE (ip6_policer_classify_node) = {
822 .function = ip6_policer_classify,
823 .name = "ip6-policer-classify",
824 .vector_size = sizeof (u32),
825 .format_trace = format_policer_classify_trace,
826 .n_errors = ARRAY_LEN(policer_classify_error_strings),
827 .error_strings = policer_classify_error_strings,
828 .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
830 [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
834 VLIB_NODE_FUNCTION_MULTIARCH (ip6_policer_classify_node, ip6_policer_classify);
838 l2_policer_classify (vlib_main_t * vm,
839 vlib_node_runtime_t * node, vlib_frame_t * frame)
841 return policer_classify_inline (vm, node, frame, POLICER_CLASSIFY_TABLE_L2);
845 VLIB_REGISTER_NODE (l2_policer_classify_node) = {
846 .function = l2_policer_classify,
847 .name = "l2-policer-classify",
848 .vector_size = sizeof (u32),
849 .format_trace = format_policer_classify_trace,
850 .n_errors = ARRAY_LEN (policer_classify_error_strings),
851 .error_strings = policer_classify_error_strings,
852 .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
854 [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
858 VLIB_NODE_FUNCTION_MULTIARCH (l2_policer_classify_node, l2_policer_classify);
861 static clib_error_t *
862 policer_classify_init (vlib_main_t * vm)
864 policer_classify_main_t *pcm = &policer_classify_main;
867 pcm->vnet_main = vnet_get_main ();
868 pcm->vnet_classify_main = &vnet_classify_main;
870 /* Initialize L2 feature next-node indexes */
871 feat_bitmap_init_next_nodes (vm,
872 l2_policer_classify_node.index,
874 l2input_get_feat_names (),
875 pcm->feat_next_node_index);
880 VLIB_INIT_FUNCTION (policer_classify_init);
883 * fd.io coding-style-patch-verification: ON
886 * eval: (c-set-style "gnu")