Line data Source code
1 : /*
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:
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 <stdint.h>
17 :
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>
25 : #include <vnet/l2/feat_bitmap.h>
26 : #include <vnet/l2/l2_input.h>
27 :
28 :
29 : /* Dispatch functions meant to be instantiated elsewhere */
30 :
31 : typedef struct
32 : {
33 : u32 next_index;
34 : u32 sw_if_index;
35 : u32 policer_index;
36 : } vnet_policer_trace_t;
37 :
38 : /* packet trace format function */
39 : static u8 *
40 2936 : format_policer_trace (u8 * s, va_list * args)
41 : {
42 2936 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
43 2936 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
44 2936 : vnet_policer_trace_t *t = va_arg (*args, vnet_policer_trace_t *);
45 :
46 2936 : s = format (s, "VNET_POLICER: sw_if_index %d policer_index %d next %d",
47 : t->sw_if_index, t->policer_index, t->next_index);
48 2936 : return s;
49 : }
50 :
51 : #define foreach_vnet_policer_error \
52 : _(TRANSMIT, "Packets Transmitted") \
53 : _(DROP, "Packets Dropped")
54 :
55 : typedef enum
56 : {
57 : #define _(sym,str) VNET_POLICER_ERROR_##sym,
58 : foreach_vnet_policer_error
59 : #undef _
60 : VNET_POLICER_N_ERROR,
61 : } vnet_policer_error_t;
62 :
63 : static char *vnet_policer_error_strings[] = {
64 : #define _(sym,string) string,
65 : foreach_vnet_policer_error
66 : #undef _
67 : };
68 :
69 : static inline uword
70 43 : vnet_policer_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
71 : vlib_frame_t *frame, vlib_dir_t dir)
72 : {
73 : u32 n_left_from, *from, *to_next;
74 : vnet_policer_next_t next_index;
75 43 : vnet_policer_main_t *pm = &vnet_policer_main;
76 : u64 time_in_policer_periods;
77 43 : u32 transmitted = 0;
78 :
79 43 : time_in_policer_periods =
80 43 : clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
81 :
82 43 : from = vlib_frame_vector_args (frame);
83 43 : n_left_from = frame->n_vectors;
84 43 : next_index = node->cached_next_index;
85 :
86 86 : while (n_left_from > 0)
87 : {
88 : u32 n_left_to_next;
89 :
90 43 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
91 :
92 855 : while (n_left_from >= 4 && n_left_to_next >= 2)
93 : {
94 : u32 bi0, bi1;
95 : vlib_buffer_t *b0, *b1;
96 : u32 next0, next1;
97 : u32 sw_if_index0, sw_if_index1;
98 812 : u32 pi0 = 0, pi1 = 0;
99 : u8 act0, act1;
100 :
101 : /* Prefetch next iteration. */
102 : {
103 : vlib_buffer_t *b2, *b3;
104 :
105 812 : b2 = vlib_get_buffer (vm, from[2]);
106 812 : b3 = vlib_get_buffer (vm, from[3]);
107 :
108 812 : vlib_prefetch_buffer_header (b2, LOAD);
109 812 : vlib_prefetch_buffer_header (b3, LOAD);
110 : }
111 :
112 : /* speculatively enqueue b0 and b1 to the current next frame */
113 812 : to_next[0] = bi0 = from[0];
114 812 : to_next[1] = bi1 = from[1];
115 812 : from += 2;
116 812 : to_next += 2;
117 812 : n_left_from -= 2;
118 812 : n_left_to_next -= 2;
119 :
120 812 : b0 = vlib_get_buffer (vm, bi0);
121 812 : b1 = vlib_get_buffer (vm, bi1);
122 :
123 812 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[dir];
124 812 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[dir];
125 :
126 812 : pi0 = pm->policer_index_by_sw_if_index[dir][sw_if_index0];
127 812 : pi1 = pm->policer_index_by_sw_if_index[dir][sw_if_index1];
128 :
129 812 : act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
130 : POLICE_CONFORM /* no chaining */, true);
131 :
132 812 : act1 = vnet_policer_police (vm, b1, pi1, time_in_policer_periods,
133 : POLICE_CONFORM /* no chaining */, true);
134 :
135 812 : if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
136 : {
137 176 : next0 = VNET_POLICER_NEXT_HANDOFF;
138 176 : vnet_buffer (b0)->policer.index = pi0;
139 : }
140 636 : else if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
141 : {
142 0 : next0 = VNET_POLICER_NEXT_DROP;
143 0 : b0->error = node->errors[VNET_POLICER_ERROR_DROP];
144 : }
145 : else /* transmit or mark-and-transmit action */
146 : {
147 636 : transmitted++;
148 636 : vnet_feature_next (&next0, b0);
149 : }
150 :
151 812 : if (PREDICT_FALSE (act1 == QOS_ACTION_HANDOFF))
152 : {
153 176 : next1 = VNET_POLICER_NEXT_HANDOFF;
154 176 : vnet_buffer (b1)->policer.index = pi1;
155 : }
156 636 : else if (PREDICT_FALSE (act1 == QOS_ACTION_DROP)) /* drop action */
157 : {
158 0 : next1 = VNET_POLICER_NEXT_DROP;
159 0 : b1->error = node->errors[VNET_POLICER_ERROR_DROP];
160 : }
161 : else /* transmit or mark-and-transmit action */
162 : {
163 636 : transmitted++;
164 636 : vnet_feature_next (&next1, b1);
165 : }
166 :
167 812 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
168 : {
169 812 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
170 : {
171 : vnet_policer_trace_t *t =
172 812 : vlib_add_trace (vm, node, b0, sizeof (*t));
173 812 : t->sw_if_index = sw_if_index0;
174 812 : t->next_index = next0;
175 : }
176 812 : if (b1->flags & VLIB_BUFFER_IS_TRACED)
177 : {
178 : vnet_policer_trace_t *t =
179 812 : vlib_add_trace (vm, node, b1, sizeof (*t));
180 812 : t->sw_if_index = sw_if_index1;
181 812 : t->next_index = next1;
182 : }
183 : }
184 :
185 : /* verify speculative enqueues, maybe switch current next frame */
186 812 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
187 : to_next, n_left_to_next,
188 : bi0, bi1, next0, next1);
189 : }
190 :
191 172 : while (n_left_from > 0 && n_left_to_next > 0)
192 : {
193 : u32 bi0;
194 : vlib_buffer_t *b0;
195 : u32 next0;
196 : u32 sw_if_index0;
197 129 : u32 pi0 = 0;
198 : u8 act0;
199 :
200 129 : bi0 = from[0];
201 129 : to_next[0] = bi0;
202 129 : from += 1;
203 129 : to_next += 1;
204 129 : n_left_from -= 1;
205 129 : n_left_to_next -= 1;
206 :
207 129 : b0 = vlib_get_buffer (vm, bi0);
208 :
209 129 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[dir];
210 129 : pi0 = pm->policer_index_by_sw_if_index[dir][sw_if_index0];
211 :
212 129 : act0 = vnet_policer_police (vm, b0, pi0, time_in_policer_periods,
213 : POLICE_CONFORM /* no chaining */, true);
214 :
215 129 : if (PREDICT_FALSE (act0 == QOS_ACTION_HANDOFF))
216 : {
217 36 : next0 = VNET_POLICER_NEXT_HANDOFF;
218 36 : vnet_buffer (b0)->policer.index = pi0;
219 : }
220 93 : else if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
221 : {
222 0 : next0 = VNET_POLICER_NEXT_DROP;
223 0 : b0->error = node->errors[VNET_POLICER_ERROR_DROP];
224 : }
225 : else /* transmit or mark-and-transmit action */
226 : {
227 93 : transmitted++;
228 93 : vnet_feature_next (&next0, b0);
229 : }
230 :
231 129 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
232 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
233 : {
234 : vnet_policer_trace_t *t =
235 129 : vlib_add_trace (vm, node, b0, sizeof (*t));
236 129 : t->sw_if_index = sw_if_index0;
237 129 : t->next_index = next0;
238 129 : t->policer_index = pi0;
239 : }
240 :
241 : /* verify speculative enqueue, maybe switch current next frame */
242 129 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
243 : to_next, n_left_to_next,
244 : bi0, next0);
245 : }
246 :
247 43 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
248 : }
249 :
250 43 : vlib_node_increment_counter (vm, node->node_index,
251 : VNET_POLICER_ERROR_TRANSMIT, transmitted);
252 43 : return frame->n_vectors;
253 : }
254 :
255 2336 : VLIB_NODE_FN (policer_input_node)
256 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
257 : {
258 36 : return vnet_policer_inline (vm, node, frame, VLIB_RX);
259 : }
260 :
261 183788 : VLIB_REGISTER_NODE (policer_input_node) = {
262 : .name = "policer-input",
263 : .vector_size = sizeof (u32),
264 : .format_trace = format_policer_trace,
265 : .type = VLIB_NODE_TYPE_INTERNAL,
266 : .n_errors = ARRAY_LEN(vnet_policer_error_strings),
267 : .error_strings = vnet_policer_error_strings,
268 : .n_next_nodes = VNET_POLICER_N_NEXT,
269 : .next_nodes = {
270 : [VNET_POLICER_NEXT_DROP] = "error-drop",
271 : [VNET_POLICER_NEXT_HANDOFF] = "policer-input-handoff",
272 : },
273 : };
274 :
275 76635 : VNET_FEATURE_INIT (policer_input_node, static) = {
276 : .arc_name = "device-input",
277 : .node_name = "policer-input",
278 : .runs_before = VNET_FEATURES ("ethernet-input"),
279 : };
280 :
281 2307 : VLIB_NODE_FN (policer_output_node)
282 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
283 : {
284 7 : return vnet_policer_inline (vm, node, frame, VLIB_TX);
285 : }
286 :
287 183788 : VLIB_REGISTER_NODE (policer_output_node) = {
288 : .name = "policer-output",
289 : .vector_size = sizeof (u32),
290 : .format_trace = format_policer_trace,
291 : .type = VLIB_NODE_TYPE_INTERNAL,
292 : .n_errors = ARRAY_LEN(vnet_policer_error_strings),
293 : .error_strings = vnet_policer_error_strings,
294 : .n_next_nodes = VNET_POLICER_N_NEXT,
295 : .next_nodes = {
296 : [VNET_POLICER_NEXT_DROP] = "error-drop",
297 : [VNET_POLICER_NEXT_HANDOFF] = "policer-output-handoff",
298 : },
299 : };
300 :
301 76635 : VNET_FEATURE_INIT (policer_output_node, static) = {
302 : .arc_name = "ip4-output",
303 : .node_name = "policer-output",
304 : };
305 :
306 76635 : VNET_FEATURE_INIT (policer6_output_node, static) = {
307 : .arc_name = "ip6-output",
308 : .node_name = "policer-output",
309 : };
310 :
311 : static char *policer_input_handoff_error_strings[] = { "congestion drop" };
312 :
313 2310 : VLIB_NODE_FN (policer_input_handoff_node)
314 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
315 : {
316 10 : return policer_handoff (vm, node, frame, vnet_policer_main.fq_index[VLIB_RX],
317 : ~0);
318 : }
319 :
320 183788 : VLIB_REGISTER_NODE (policer_input_handoff_node) = {
321 : .name = "policer-input-handoff",
322 : .vector_size = sizeof (u32),
323 : .format_trace = format_policer_handoff_trace,
324 : .type = VLIB_NODE_TYPE_INTERNAL,
325 : .n_errors = ARRAY_LEN(policer_input_handoff_error_strings),
326 : .error_strings = policer_input_handoff_error_strings,
327 :
328 : .n_next_nodes = 1,
329 : .next_nodes = {
330 : [0] = "error-drop",
331 : },
332 : };
333 :
334 2302 : VLIB_NODE_FN (policer_output_handoff_node)
335 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
336 : {
337 2 : return policer_handoff (vm, node, frame, vnet_policer_main.fq_index[VLIB_TX],
338 : ~0);
339 : }
340 :
341 183788 : VLIB_REGISTER_NODE (policer_output_handoff_node) = {
342 : .name = "policer-output-handoff",
343 : .vector_size = sizeof (u32),
344 : .format_trace = format_policer_handoff_trace,
345 : .type = VLIB_NODE_TYPE_INTERNAL,
346 : .n_errors = ARRAY_LEN(policer_input_handoff_error_strings),
347 : .error_strings = policer_input_handoff_error_strings,
348 :
349 : .n_next_nodes = 1,
350 : .next_nodes = {
351 : [0] = "error-drop",
352 : },
353 : };
354 : typedef struct
355 : {
356 : u32 sw_if_index;
357 : u32 next_index;
358 : u32 table_index;
359 : u32 offset;
360 : u32 policer_index;
361 : } policer_classify_trace_t;
362 :
363 : static u8 *
364 0 : format_policer_classify_trace (u8 * s, va_list * args)
365 : {
366 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
367 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
368 0 : policer_classify_trace_t *t = va_arg (*args, policer_classify_trace_t *);
369 :
370 0 : s = format (s, "POLICER_CLASSIFY: sw_if_index %d next %d table %d offset %d"
371 : " policer_index %d",
372 : t->sw_if_index, t->next_index, t->table_index, t->offset,
373 : t->policer_index);
374 0 : return s;
375 : }
376 :
377 : #define foreach_policer_classify_error \
378 : _(MISS, "Policer classify misses") \
379 : _(HIT, "Policer classify hits") \
380 : _(CHAIN_HIT, "Policer classify hits after chain walk") \
381 : _(DROP, "Policer classify action drop")
382 :
383 : typedef enum
384 : {
385 : #define _(sym,str) POLICER_CLASSIFY_ERROR_##sym,
386 : foreach_policer_classify_error
387 : #undef _
388 : POLICER_CLASSIFY_N_ERROR,
389 : } policer_classify_error_t;
390 :
391 : static char *policer_classify_error_strings[] = {
392 : #define _(sym,string) string,
393 : foreach_policer_classify_error
394 : #undef _
395 : };
396 :
397 : static inline uword
398 0 : policer_classify_inline (vlib_main_t * vm,
399 : vlib_node_runtime_t * node,
400 : vlib_frame_t * frame,
401 : policer_classify_table_id_t tid)
402 : {
403 : u32 n_left_from, *from, *to_next;
404 : policer_classify_next_index_t next_index;
405 0 : policer_classify_main_t *pcm = &policer_classify_main;
406 0 : vnet_classify_main_t *vcm = pcm->vnet_classify_main;
407 0 : f64 now = vlib_time_now (vm);
408 0 : u32 hits = 0;
409 0 : u32 misses = 0;
410 0 : u32 chain_hits = 0;
411 : u32 n_next_nodes;
412 : u64 time_in_policer_periods;
413 :
414 0 : time_in_policer_periods =
415 0 : clib_cpu_time_now () >> POLICER_TICKS_PER_PERIOD_SHIFT;
416 :
417 0 : n_next_nodes = node->n_next_nodes;
418 :
419 0 : from = vlib_frame_vector_args (frame);
420 0 : n_left_from = frame->n_vectors;
421 :
422 : /* First pass: compute hashes */
423 0 : while (n_left_from > 2)
424 : {
425 : vlib_buffer_t *b0, *b1;
426 : u32 bi0, bi1;
427 : u8 *h0, *h1;
428 : u32 sw_if_index0, sw_if_index1;
429 : u32 table_index0, table_index1;
430 : vnet_classify_table_t *t0, *t1;
431 :
432 : /* Prefetch next iteration */
433 : {
434 : vlib_buffer_t *p1, *p2;
435 :
436 0 : p1 = vlib_get_buffer (vm, from[1]);
437 0 : p2 = vlib_get_buffer (vm, from[2]);
438 :
439 0 : vlib_prefetch_buffer_header (p1, STORE);
440 0 : clib_prefetch_store (p1->data);
441 0 : vlib_prefetch_buffer_header (p2, STORE);
442 0 : clib_prefetch_store (p2->data);
443 : }
444 :
445 0 : bi0 = from[0];
446 0 : b0 = vlib_get_buffer (vm, bi0);
447 0 : h0 = b0->data;
448 :
449 0 : bi1 = from[1];
450 0 : b1 = vlib_get_buffer (vm, bi1);
451 0 : h1 = b1->data;
452 :
453 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
454 0 : table_index0 =
455 0 : pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
456 :
457 0 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
458 0 : table_index1 =
459 0 : pcm->classify_table_index_by_sw_if_index[tid][sw_if_index1];
460 :
461 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
462 :
463 0 : t1 = pool_elt_at_index (vcm->tables, table_index1);
464 :
465 0 : vnet_buffer (b0)->l2_classify.hash =
466 0 : vnet_classify_hash_packet (t0, (u8 *) h0);
467 :
468 0 : vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
469 :
470 0 : vnet_buffer (b1)->l2_classify.hash =
471 0 : vnet_classify_hash_packet (t1, (u8 *) h1);
472 :
473 0 : vnet_classify_prefetch_bucket (t1, vnet_buffer (b1)->l2_classify.hash);
474 :
475 0 : vnet_buffer (b0)->l2_classify.table_index = table_index0;
476 :
477 0 : vnet_buffer (b1)->l2_classify.table_index = table_index1;
478 :
479 0 : from += 2;
480 0 : n_left_from -= 2;
481 : }
482 :
483 0 : while (n_left_from > 0)
484 : {
485 : vlib_buffer_t *b0;
486 : u32 bi0;
487 : u8 *h0;
488 : u32 sw_if_index0;
489 : u32 table_index0;
490 : vnet_classify_table_t *t0;
491 :
492 0 : bi0 = from[0];
493 0 : b0 = vlib_get_buffer (vm, bi0);
494 0 : h0 = b0->data;
495 :
496 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
497 0 : table_index0 =
498 0 : pcm->classify_table_index_by_sw_if_index[tid][sw_if_index0];
499 :
500 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
501 0 : vnet_buffer (b0)->l2_classify.hash =
502 0 : vnet_classify_hash_packet (t0, (u8 *) h0);
503 :
504 0 : vnet_buffer (b0)->l2_classify.table_index = table_index0;
505 0 : vnet_classify_prefetch_bucket (t0, vnet_buffer (b0)->l2_classify.hash);
506 :
507 0 : from++;
508 0 : n_left_from--;
509 : }
510 :
511 0 : next_index = node->cached_next_index;
512 0 : from = vlib_frame_vector_args (frame);
513 0 : n_left_from = frame->n_vectors;
514 :
515 0 : while (n_left_from > 0)
516 : {
517 : u32 n_left_to_next;
518 :
519 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
520 :
521 : /* Not enough load/store slots to dual loop... */
522 0 : while (n_left_from > 0 && n_left_to_next > 0)
523 : {
524 : u32 bi0;
525 : vlib_buffer_t *b0;
526 0 : u32 next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
527 : u32 table_index0;
528 : vnet_classify_table_t *t0;
529 : vnet_classify_entry_t *e0;
530 : u32 hash0;
531 : u8 *h0;
532 : u8 act0;
533 :
534 : /* Stride 3 seems to work best */
535 0 : if (PREDICT_TRUE (n_left_from > 3))
536 : {
537 0 : vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
538 : vnet_classify_table_t *tp1;
539 : u32 table_index1;
540 : u32 phash1;
541 :
542 0 : table_index1 = vnet_buffer (p1)->l2_classify.table_index;
543 :
544 0 : if (PREDICT_TRUE (table_index1 != ~0))
545 : {
546 0 : tp1 = pool_elt_at_index (vcm->tables, table_index1);
547 0 : phash1 = vnet_buffer (p1)->l2_classify.hash;
548 0 : vnet_classify_prefetch_entry (tp1, phash1);
549 : }
550 : }
551 :
552 : /* Speculatively enqueue b0 to the current next frame */
553 0 : bi0 = from[0];
554 0 : to_next[0] = bi0;
555 0 : from += 1;
556 0 : to_next += 1;
557 0 : n_left_from -= 1;
558 0 : n_left_to_next -= 1;
559 :
560 0 : b0 = vlib_get_buffer (vm, bi0);
561 0 : h0 = b0->data;
562 0 : table_index0 = vnet_buffer (b0)->l2_classify.table_index;
563 0 : e0 = 0;
564 0 : t0 = 0;
565 :
566 0 : if (tid == POLICER_CLASSIFY_TABLE_L2)
567 : {
568 : /* Feature bitmap update and determine the next node */
569 0 : next0 = vnet_l2_feature_next (b0, pcm->feat_next_node_index,
570 : L2INPUT_FEAT_POLICER_CLAS);
571 : }
572 : else
573 0 : vnet_get_config_data (pcm->vnet_config_main[tid],
574 : &b0->current_config_index, &next0,
575 : /* # bytes of config data */ 0);
576 :
577 0 : vnet_buffer (b0)->l2_classify.opaque_index = ~0;
578 :
579 0 : if (PREDICT_TRUE (table_index0 != ~0))
580 : {
581 0 : hash0 = vnet_buffer (b0)->l2_classify.hash;
582 0 : t0 = pool_elt_at_index (vcm->tables, table_index0);
583 0 : e0 = vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
584 :
585 0 : if (e0)
586 : {
587 0 : act0 = vnet_policer_police (vm, b0, e0->next_index,
588 : time_in_policer_periods,
589 0 : e0->opaque_index, false);
590 0 : if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
591 : {
592 0 : next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
593 0 : b0->error = node->errors[POLICER_CLASSIFY_ERROR_DROP];
594 : }
595 0 : hits++;
596 : }
597 : else
598 : {
599 : while (1)
600 : {
601 0 : if (PREDICT_TRUE (t0->next_table_index != ~0))
602 : {
603 0 : t0 = pool_elt_at_index (vcm->tables,
604 : t0->next_table_index);
605 : }
606 : else
607 : {
608 0 : next0 = (t0->miss_next_index < n_next_nodes) ?
609 0 : t0->miss_next_index : next0;
610 0 : misses++;
611 0 : break;
612 : }
613 :
614 0 : hash0 = vnet_classify_hash_packet (t0, (u8 *) h0);
615 : e0 =
616 0 : vnet_classify_find_entry (t0, (u8 *) h0, hash0, now);
617 0 : if (e0)
618 : {
619 0 : act0 = vnet_policer_police (vm, b0, e0->next_index,
620 : time_in_policer_periods,
621 0 : e0->opaque_index, false);
622 0 : if (PREDICT_FALSE (act0 == QOS_ACTION_DROP))
623 : {
624 0 : next0 = POLICER_CLASSIFY_NEXT_INDEX_DROP;
625 0 : b0->error =
626 0 : node->errors[POLICER_CLASSIFY_ERROR_DROP];
627 : }
628 0 : hits++;
629 0 : chain_hits++;
630 0 : break;
631 : }
632 : }
633 : }
634 : }
635 0 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
636 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
637 : {
638 : policer_classify_trace_t *t =
639 0 : vlib_add_trace (vm, node, b0, sizeof (*t));
640 0 : t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
641 0 : t->next_index = next0;
642 0 : t->table_index = t0 ? t0 - vcm->tables : ~0;
643 0 : t->offset = (e0 && t0) ? vnet_classify_get_offset (t0, e0) : ~0;
644 0 : t->policer_index = e0 ? e0->next_index : ~0;
645 : }
646 :
647 : /* Verify speculative enqueue, maybe switch current next frame */
648 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
649 : n_left_to_next, bi0, next0);
650 : }
651 :
652 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
653 : }
654 :
655 0 : vlib_node_increment_counter (vm, node->node_index,
656 : POLICER_CLASSIFY_ERROR_MISS, misses);
657 0 : vlib_node_increment_counter (vm, node->node_index,
658 : POLICER_CLASSIFY_ERROR_HIT, hits);
659 0 : vlib_node_increment_counter (vm, node->node_index,
660 : POLICER_CLASSIFY_ERROR_CHAIN_HIT, chain_hits);
661 :
662 0 : return frame->n_vectors;
663 : }
664 :
665 2300 : VLIB_NODE_FN (ip4_policer_classify_node) (vlib_main_t * vm,
666 : vlib_node_runtime_t * node,
667 : vlib_frame_t * frame)
668 : {
669 0 : return policer_classify_inline (vm, node, frame,
670 : POLICER_CLASSIFY_TABLE_IP4);
671 : }
672 :
673 : /* *INDENT-OFF* */
674 183788 : VLIB_REGISTER_NODE (ip4_policer_classify_node) = {
675 : .name = "ip4-policer-classify",
676 : .vector_size = sizeof (u32),
677 : .format_trace = format_policer_classify_trace,
678 : .n_errors = ARRAY_LEN(policer_classify_error_strings),
679 : .error_strings = policer_classify_error_strings,
680 : .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
681 : .next_nodes = {
682 : [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
683 : },
684 : };
685 : /* *INDENT-ON* */
686 :
687 2300 : VLIB_NODE_FN (ip6_policer_classify_node) (vlib_main_t * vm,
688 : vlib_node_runtime_t * node,
689 : vlib_frame_t * frame)
690 : {
691 0 : return policer_classify_inline (vm, node, frame,
692 : POLICER_CLASSIFY_TABLE_IP6);
693 : }
694 :
695 : /* *INDENT-OFF* */
696 183788 : VLIB_REGISTER_NODE (ip6_policer_classify_node) = {
697 : .name = "ip6-policer-classify",
698 : .vector_size = sizeof (u32),
699 : .format_trace = format_policer_classify_trace,
700 : .n_errors = ARRAY_LEN(policer_classify_error_strings),
701 : .error_strings = policer_classify_error_strings,
702 : .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
703 : .next_nodes = {
704 : [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
705 : },
706 : };
707 : /* *INDENT-ON* */
708 :
709 2300 : VLIB_NODE_FN (l2_policer_classify_node) (vlib_main_t * vm,
710 : vlib_node_runtime_t * node,
711 : vlib_frame_t * frame)
712 : {
713 0 : return policer_classify_inline (vm, node, frame, POLICER_CLASSIFY_TABLE_L2);
714 : }
715 :
716 : /* *INDENT-OFF* */
717 183788 : VLIB_REGISTER_NODE (l2_policer_classify_node) = {
718 : .name = "l2-policer-classify",
719 : .vector_size = sizeof (u32),
720 : .format_trace = format_policer_classify_trace,
721 : .n_errors = ARRAY_LEN (policer_classify_error_strings),
722 : .error_strings = policer_classify_error_strings,
723 : .n_next_nodes = POLICER_CLASSIFY_NEXT_INDEX_N_NEXT,
724 : .next_nodes = {
725 : [POLICER_CLASSIFY_NEXT_INDEX_DROP] = "error-drop",
726 : },
727 : };
728 : /* *INDENT-ON* */
729 :
730 : #ifndef CLIB_MARCH_VARIANT
731 : static clib_error_t *
732 575 : policer_classify_init (vlib_main_t * vm)
733 : {
734 575 : policer_classify_main_t *pcm = &policer_classify_main;
735 :
736 575 : pcm->vlib_main = vm;
737 575 : pcm->vnet_main = vnet_get_main ();
738 575 : pcm->vnet_classify_main = &vnet_classify_main;
739 :
740 : /* Initialize L2 feature next-node indexes */
741 575 : feat_bitmap_init_next_nodes (vm,
742 : l2_policer_classify_node.index,
743 : L2INPUT_N_FEAT,
744 : l2input_get_feat_names (),
745 575 : pcm->feat_next_node_index);
746 :
747 575 : return 0;
748 : }
749 :
750 12095 : VLIB_INIT_FUNCTION (policer_classify_init);
751 : #endif /* CLIB_MARCH_VARIANT */
752 :
753 : /*
754 : * fd.io coding-style-patch-verification: ON
755 : *
756 : * Local Variables:
757 : * eval: (c-set-style "gnu")
758 : * End:
759 : */
|