policer: output interface policer
[vpp.git] / src / vnet / policer / policer.c
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 #include <stdint.h>
16 #include <stdbool.h>
17 #include <vnet/policer/policer.h>
18 #include <vnet/policer/police_inlines.h>
19 #include <vnet/classify/vnet_classify.h>
20 #include <vnet/ip/ip_packet.h>
21
22 vnet_policer_main_t vnet_policer_main;
23
24 u8 *
25 format_policer_handoff_trace (u8 *s, va_list *args)
26 {
27   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
28   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
29   policer_handoff_trace_t *t = va_arg (*args, policer_handoff_trace_t *);
30
31   s = format (s, "policer %d, handoff thread %d to %d", t->policer_index,
32               t->current_worker_index, t->next_worker_index);
33
34   return s;
35 }
36
37 vlib_combined_counter_main_t policer_counters[] = {
38   {
39     .name = "Policer-Conform",
40     .stat_segment_name = "/net/policer/conform",
41   },
42   {
43     .name = "Policer-Exceed",
44     .stat_segment_name = "/net/policer/exceed",
45   },
46   {
47     .name = "Policer-Violate",
48     .stat_segment_name = "/net/policer/violate",
49   },
50 };
51
52 clib_error_t *
53 policer_add_del (vlib_main_t *vm, u8 *name, qos_pol_cfg_params_st *cfg,
54                  u32 *policer_index, u8 is_add)
55 {
56   vnet_policer_main_t *pm = &vnet_policer_main;
57   policer_t test_policer;
58   policer_t *policer;
59   uword *p;
60   u32 pi;
61   int rv;
62
63   p = hash_get_mem (pm->policer_config_by_name, name);
64
65   if (is_add == 0)
66     {
67       /* free policer config and template */
68       if (p == 0)
69         {
70           vec_free (name);
71           return clib_error_return (0, "No such policer configuration");
72         }
73       pool_put_index (pm->configs, p[0]);
74       pool_put_index (pm->policer_templates, p[0]);
75       hash_unset_mem (pm->policer_config_by_name, name);
76
77       /* free policer */
78       p = hash_get_mem (pm->policer_index_by_name, name);
79       if (p == 0)
80         {
81           vec_free (name);
82           return clib_error_return (0, "No such policer");
83         }
84       pool_put_index (pm->policers, p[0]);
85       hash_unset_mem (pm->policer_index_by_name, name);
86
87       vec_free (name);
88       return 0;
89     }
90
91   if (p != 0)
92     {
93       vec_free (name);
94       return clib_error_return (0, "Policer already exists");
95     }
96
97   /* Vet the configuration before adding it to the table */
98   rv = pol_logical_2_physical (cfg, &test_policer);
99
100   if (rv == 0)
101     {
102       policer_t *pp;
103       qos_pol_cfg_params_st *cp;
104       int i;
105
106       pool_get (pm->configs, cp);
107       pool_get (pm->policer_templates, pp);
108
109       ASSERT (cp - pm->configs == pp - pm->policer_templates);
110
111       clib_memcpy (cp, cfg, sizeof (*cp));
112       clib_memcpy (pp, &test_policer, sizeof (*pp));
113
114       hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs);
115       pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
116       policer[0] = pp[0];
117       pi = policer - pm->policers;
118       hash_set_mem (pm->policer_index_by_name, name, pi);
119       *policer_index = pi;
120       policer->thread_index = ~0;
121
122       for (i = 0; i < NUM_POLICE_RESULTS; i++)
123         {
124           vlib_validate_combined_counter (&policer_counters[i], pi);
125           vlib_zero_combined_counter (&policer_counters[i], pi);
126         }
127     }
128   else
129     {
130       vec_free (name);
131       return clib_error_return (0, "Config failed sanity check");
132     }
133
134   return 0;
135 }
136
137 int
138 policer_bind_worker (u8 *name, u32 worker, bool bind)
139 {
140   vnet_policer_main_t *pm = &vnet_policer_main;
141   policer_t *policer;
142   uword *p;
143
144   p = hash_get_mem (pm->policer_index_by_name, name);
145   if (p == 0)
146     {
147       return VNET_API_ERROR_NO_SUCH_ENTRY;
148     }
149
150   policer = &pm->policers[p[0]];
151
152   if (bind)
153     {
154       if (worker >= vlib_num_workers ())
155         {
156           return VNET_API_ERROR_INVALID_WORKER;
157         }
158
159       policer->thread_index = vlib_get_worker_thread_index (worker);
160     }
161   else
162     {
163       policer->thread_index = ~0;
164     }
165   return 0;
166 }
167
168 int
169 policer_input (u8 *name, u32 sw_if_index, vlib_dir_t dir, bool apply)
170 {
171   vnet_policer_main_t *pm = &vnet_policer_main;
172   policer_t *policer;
173   u32 policer_index;
174   uword *p;
175
176   p = hash_get_mem (pm->policer_index_by_name, name);
177   if (p == 0)
178     {
179       return VNET_API_ERROR_NO_SUCH_ENTRY;
180     }
181
182   policer = &pm->policers[p[0]];
183   policer_index = policer - pm->policers;
184
185   if (apply)
186     {
187       vec_validate (pm->policer_index_by_sw_if_index[dir], sw_if_index);
188       pm->policer_index_by_sw_if_index[dir][sw_if_index] = policer_index;
189     }
190   else
191     {
192       pm->policer_index_by_sw_if_index[dir][sw_if_index] = ~0;
193     }
194
195   if (dir == VLIB_RX)
196     {
197       vnet_feature_enable_disable ("device-input", "policer-input",
198                                    sw_if_index, apply, 0, 0);
199     }
200   else
201     {
202       vnet_feature_enable_disable ("ip4-output", "policer-output", sw_if_index,
203                                    apply, 0, 0);
204       vnet_feature_enable_disable ("ip6-output", "policer-output", sw_if_index,
205                                    apply, 0, 0);
206     }
207   return 0;
208 }
209
210 u8 *
211 format_policer_instance (u8 * s, va_list * va)
212 {
213   policer_t *i = va_arg (*va, policer_t *);
214   uword pi = va_arg (*va, uword);
215   int result;
216   vlib_counter_t counts[NUM_POLICE_RESULTS];
217
218   for (result = 0; result < NUM_POLICE_RESULTS; result++)
219     {
220       vlib_get_combined_counter (&policer_counters[result], pi,
221                                  &counts[result]);
222     }
223
224   s = format (s, "policer at %llx: %s rate, %s color-aware\n",
225               i, i->single_rate ? "single" : "dual",
226               i->color_aware ? "is" : "not");
227   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
228               i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
229   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
230               i->current_limit,
231               i->current_bucket, i->extended_limit, i->extended_bucket);
232   s = format (s, "last update %llu\n", i->last_update_time);
233   s = format (s, "conform %llu packets, %llu bytes\n",
234               counts[POLICE_CONFORM].packets, counts[POLICE_CONFORM].bytes);
235   s = format (s, "exceed %llu packets, %llu bytes\n",
236               counts[POLICE_EXCEED].packets, counts[POLICE_EXCEED].bytes);
237   s = format (s, "violate %llu packets, %llu bytes\n",
238               counts[POLICE_VIOLATE].packets, counts[POLICE_VIOLATE].bytes);
239   return s;
240 }
241
242 static u8 *
243 format_policer_round_type (u8 * s, va_list * va)
244 {
245   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
246
247   if (c->rnd_type == QOS_ROUND_TO_CLOSEST)
248     s = format (s, "closest");
249   else if (c->rnd_type == QOS_ROUND_TO_UP)
250     s = format (s, "up");
251   else if (c->rnd_type == QOS_ROUND_TO_DOWN)
252     s = format (s, "down");
253   else
254     s = format (s, "ILLEGAL");
255   return s;
256 }
257
258
259 static u8 *
260 format_policer_rate_type (u8 * s, va_list * va)
261 {
262   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
263
264   if (c->rate_type == QOS_RATE_KBPS)
265     s = format (s, "kbps");
266   else if (c->rate_type == QOS_RATE_PPS)
267     s = format (s, "pps");
268   else
269     s = format (s, "ILLEGAL");
270   return s;
271 }
272
273 static u8 *
274 format_policer_type (u8 * s, va_list * va)
275 {
276   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
277
278   if (c->rfc == QOS_POLICER_TYPE_1R2C)
279     s = format (s, "1r2c");
280
281   else if (c->rfc == QOS_POLICER_TYPE_1R3C_RFC_2697)
282     s = format (s, "1r3c");
283
284   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_2698)
285     s = format (s, "2r3c-2698");
286
287   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_4115)
288     s = format (s, "2r3c-4115");
289
290   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
291     s = format (s, "2r3c-mef5cf1");
292   else
293     s = format (s, "ILLEGAL");
294   return s;
295 }
296
297 static u8 *
298 format_policer_action_type (u8 * s, va_list * va)
299 {
300   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
301
302   if (a->action_type == QOS_ACTION_DROP)
303     s = format (s, "drop");
304   else if (a->action_type == QOS_ACTION_TRANSMIT)
305     s = format (s, "transmit");
306   else if (a->action_type == QOS_ACTION_MARK_AND_TRANSMIT)
307     s = format (s, "mark-and-transmit %U", format_ip_dscp, a->dscp);
308   else
309     s = format (s, "ILLEGAL");
310   return s;
311 }
312
313 u8 *
314 format_policer_config (u8 * s, va_list * va)
315 {
316   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
317
318   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
319               format_policer_type, c,
320               c->rb.kbps.cir_kbps,
321               c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes);
322   s = format (s, "rate type %U, round type %U\n",
323               format_policer_rate_type, c, format_policer_round_type, c);
324   s = format (s, "conform action %U, exceed action %U, violate action %U\n",
325               format_policer_action_type, &c->conform_action,
326               format_policer_action_type, &c->exceed_action,
327               format_policer_action_type, &c->violate_action);
328   return s;
329 }
330
331 static uword
332 unformat_policer_type (unformat_input_t * input, va_list * va)
333 {
334   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
335
336   if (!unformat (input, "type"))
337     return 0;
338
339   if (unformat (input, "1r2c"))
340     c->rfc = QOS_POLICER_TYPE_1R2C;
341   else if (unformat (input, "1r3c"))
342     c->rfc = QOS_POLICER_TYPE_1R3C_RFC_2697;
343   else if (unformat (input, "2r3c-2698"))
344     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_2698;
345   else if (unformat (input, "2r3c-4115"))
346     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_4115;
347   else if (unformat (input, "2r3c-mef5cf1"))
348     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
349   else
350     return 0;
351   return 1;
352 }
353
354 static uword
355 unformat_policer_round_type (unformat_input_t * input, va_list * va)
356 {
357   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
358
359   if (!unformat (input, "round"))
360     return 0;
361
362   if (unformat (input, "closest"))
363     c->rnd_type = QOS_ROUND_TO_CLOSEST;
364   else if (unformat (input, "up"))
365     c->rnd_type = QOS_ROUND_TO_UP;
366   else if (unformat (input, "down"))
367     c->rnd_type = QOS_ROUND_TO_DOWN;
368   else
369     return 0;
370   return 1;
371 }
372
373 static uword
374 unformat_policer_rate_type (unformat_input_t * input, va_list * va)
375 {
376   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
377
378   if (!unformat (input, "rate"))
379     return 0;
380
381   if (unformat (input, "kbps"))
382     c->rate_type = QOS_RATE_KBPS;
383   else if (unformat (input, "pps"))
384     c->rate_type = QOS_RATE_PPS;
385   else
386     return 0;
387   return 1;
388 }
389
390 static uword
391 unformat_policer_cir (unformat_input_t * input, va_list * va)
392 {
393   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
394
395   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
396     return 1;
397   return 0;
398 }
399
400 static uword
401 unformat_policer_eir (unformat_input_t * input, va_list * va)
402 {
403   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
404
405   if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps))
406     return 1;
407   return 0;
408 }
409
410 static uword
411 unformat_policer_cb (unformat_input_t * input, va_list * va)
412 {
413   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
414
415   if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes))
416     return 1;
417   return 0;
418 }
419
420 static uword
421 unformat_policer_eb (unformat_input_t * input, va_list * va)
422 {
423   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
424
425   if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes))
426     return 1;
427   return 0;
428 }
429
430 static uword
431 unformat_policer_action_type (unformat_input_t * input, va_list * va)
432 {
433   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
434
435   if (unformat (input, "drop"))
436     a->action_type = QOS_ACTION_DROP;
437   else if (unformat (input, "transmit"))
438     a->action_type = QOS_ACTION_TRANSMIT;
439   else if (unformat (input, "mark-and-transmit %U", unformat_ip_dscp,
440                      &a->dscp))
441     a->action_type = QOS_ACTION_MARK_AND_TRANSMIT;
442   else
443     return 0;
444   return 1;
445 }
446
447 static uword
448 unformat_policer_action (unformat_input_t * input, va_list * va)
449 {
450   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
451
452   if (unformat (input, "conform-action %U", unformat_policer_action_type,
453                 &c->conform_action))
454     return 1;
455   else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
456                      &c->exceed_action))
457     return 1;
458   else if (unformat (input, "violate-action %U", unformat_policer_action_type,
459                      &c->violate_action))
460     return 1;
461   return 0;
462 }
463
464 static uword
465 unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
466 {
467   u32 *r = va_arg (*va, u32 *);
468   vnet_policer_main_t *pm = &vnet_policer_main;
469   uword *p;
470   u8 *match_name = 0;
471
472   if (unformat (input, "%s", &match_name))
473     ;
474   else
475     return 0;
476
477   p = hash_get_mem (pm->policer_index_by_name, match_name);
478
479   if (p == 0)
480     return 0;
481
482   *r = p[0];
483
484   return 1;
485 }
486
487 static uword
488 unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
489 {
490   u32 *r = va_arg (*va, u32 *);
491
492   if (unformat (input, "conform-color"))
493     *r = POLICE_CONFORM;
494   else if (unformat (input, "exceed-color"))
495     *r = POLICE_EXCEED;
496   else
497     return 0;
498
499   return 1;
500 }
501
502 #define foreach_config_param                    \
503 _(eb)                                           \
504 _(cb)                                           \
505 _(eir)                                          \
506 _(cir)                                          \
507 _(rate_type)                                    \
508 _(round_type)                                   \
509 _(type)                                         \
510 _(action)
511
512 static clib_error_t *
513 policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
514                         vlib_cli_command_t *cmd)
515 {
516   qos_pol_cfg_params_st c;
517   unformat_input_t _line_input, *line_input = &_line_input;
518   u8 is_add = 1;
519   u8 *name = 0;
520   u32 pi;
521   clib_error_t *error = NULL;
522
523   /* Get a line of input. */
524   if (!unformat_user (input, unformat_line_input, line_input))
525     return 0;
526
527   clib_memset (&c, 0, sizeof (c));
528
529   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
530     {
531       if (unformat (line_input, "del"))
532         is_add = 0;
533       else if (unformat (line_input, "name %s", &name))
534         ;
535       else if (unformat (line_input, "color-aware"))
536         c.color_aware = 1;
537
538 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
539       foreach_config_param
540 #undef _
541         else
542         {
543           error = clib_error_return (0, "unknown input `%U'",
544                                      format_unformat_error, line_input);
545           goto done;
546         }
547     }
548
549   error = policer_add_del (vm, name, &c, &pi, is_add);
550
551 done:
552   unformat_free (line_input);
553
554   return error;
555 }
556
557 static clib_error_t *
558 policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
559                         vlib_cli_command_t *cmd)
560 {
561   unformat_input_t _line_input, *line_input = &_line_input;
562   clib_error_t *error = NULL;
563   u8 *name = 0;
564
565   /* Get a line of input. */
566   if (!unformat_user (input, unformat_line_input, line_input))
567     return 0;
568
569   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
570     {
571       if (unformat (line_input, "name %s", &name))
572         ;
573       else
574         {
575           error = clib_error_return (0, "unknown input `%U'",
576                                      format_unformat_error, line_input);
577           goto done;
578         }
579     }
580
581   error = policer_add_del (vm, name, NULL, NULL, 0);
582
583 done:
584   unformat_free (line_input);
585
586   return error;
587 }
588
589 static clib_error_t *
590 policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
591                          vlib_cli_command_t *cmd)
592 {
593   unformat_input_t _line_input, *line_input = &_line_input;
594   clib_error_t *error = NULL;
595   u8 bind, *name = 0;
596   u32 worker;
597   int rv;
598
599   bind = 1;
600   worker = ~0;
601
602   /* Get a line of input. */
603   if (!unformat_user (input, unformat_line_input, line_input))
604     return 0;
605
606   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
607     {
608       if (unformat (line_input, "name %s", &name))
609         ;
610       else if (unformat (line_input, "unbind"))
611         bind = 0;
612       else if (unformat (line_input, "%d", &worker))
613         ;
614       else
615         {
616           error = clib_error_return (0, "unknown input `%U'",
617                                      format_unformat_error, line_input);
618           goto done;
619         }
620     }
621
622   if (bind && ~0 == worker)
623     {
624       error = clib_error_return (0, "specify worker to bind to: `%U'",
625                                  format_unformat_error, line_input);
626     }
627   else
628     {
629       rv = policer_bind_worker (name, worker, bind);
630
631       if (rv)
632         error = clib_error_return (0, "failed: `%d'", rv);
633     }
634
635 done:
636   unformat_free (line_input);
637
638   return error;
639 }
640
641 static clib_error_t *
642 policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
643                           vlib_cli_command_t *cmd)
644 {
645   unformat_input_t _line_input, *line_input = &_line_input;
646   clib_error_t *error = NULL;
647   u8 apply, *name = 0;
648   u32 sw_if_index;
649   int rv;
650   vlib_dir_t dir = cmd->function_arg;
651
652   apply = 1;
653   sw_if_index = ~0;
654
655   /* Get a line of input. */
656   if (!unformat_user (input, unformat_line_input, line_input))
657     return 0;
658
659   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
660     {
661       if (unformat (line_input, "name %s", &name))
662         ;
663       else if (unformat (line_input, "unapply"))
664         apply = 0;
665       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
666                          vnet_get_main (), &sw_if_index))
667         ;
668       else
669         {
670           error = clib_error_return (0, "unknown input `%U'",
671                                      format_unformat_error, line_input);
672           goto done;
673         }
674     }
675
676   if (~0 == sw_if_index)
677     {
678       error = clib_error_return (0, "specify interface to apply to: `%U'",
679                                  format_unformat_error, line_input);
680     }
681   else
682     {
683       rv = policer_input (name, sw_if_index, dir, apply);
684
685       if (rv)
686         error = clib_error_return (0, "failed: `%d'", rv);
687     }
688
689 done:
690   unformat_free (line_input);
691
692   return error;
693 }
694
695 VLIB_CLI_COMMAND (configure_policer_command, static) = {
696   .path = "configure policer",
697   .short_help = "configure policer name <name> <params> ",
698   .function = policer_add_command_fn,
699 };
700
701 VLIB_CLI_COMMAND (policer_add_command, static) = {
702   .path = "policer add",
703   .short_help = "policer name <name> <params> ",
704   .function = policer_add_command_fn,
705 };
706
707 VLIB_CLI_COMMAND (policer_del_command, static) = {
708   .path = "policer del",
709   .short_help = "policer del name <name> ",
710   .function = policer_del_command_fn,
711 };
712
713 VLIB_CLI_COMMAND (policer_bind_command, static) = {
714   .path = "policer bind",
715   .short_help = "policer bind [unbind] name <name> <worker>",
716   .function = policer_bind_command_fn,
717 };
718
719 VLIB_CLI_COMMAND (policer_input_command, static) = {
720   .path = "policer input",
721   .short_help = "policer input [unapply] name <name> <interfac>",
722   .function = policer_input_command_fn,
723   .function_arg = VLIB_RX,
724 };
725
726 VLIB_CLI_COMMAND (policer_output_command, static) = {
727   .path = "policer output",
728   .short_help = "policer output [unapply] name <name> <interfac>",
729   .function = policer_input_command_fn,
730   .function_arg = VLIB_TX,
731 };
732
733 static clib_error_t *
734 show_policer_command_fn (vlib_main_t * vm,
735                          unformat_input_t * input, vlib_cli_command_t * cmd)
736 {
737   vnet_policer_main_t *pm = &vnet_policer_main;
738   hash_pair_t *p;
739   u32 pool_index;
740   u8 *match_name = 0;
741   u8 *name;
742   uword *pi;
743   qos_pol_cfg_params_st *config;
744   policer_t *templ;
745
746   (void) unformat (input, "name %s", &match_name);
747
748   /* *INDENT-OFF* */
749   hash_foreach_pair (p, pm->policer_config_by_name,
750   ({
751     name = (u8 *) p->key;
752     if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
753       {
754         pi = hash_get_mem (pm->policer_index_by_name, name);
755
756         pool_index = p->value[0];
757         config = pool_elt_at_index (pm->configs, pool_index);
758         templ = pool_elt_at_index (pm->policer_templates, pool_index);
759         vlib_cli_output (vm, "Name \"%s\" %U ", name, format_policer_config,
760                          config);
761         if (pi)
762           {
763             vlib_cli_output (vm, "Template %U", format_policer_instance, templ,
764                              pi[0]);
765           }
766         else
767           {
768             vlib_cli_output (
769               vm, "Cannot print template - policer index hash lookup failed");
770           }
771         vlib_cli_output (vm, "-----------");
772       }
773   }));
774   /* *INDENT-ON* */
775   return 0;
776 }
777
778
779 /* *INDENT-OFF* */
780 VLIB_CLI_COMMAND (show_policer_command, static) = {
781     .path = "show policer",
782     .short_help = "show policer [name]",
783     .function = show_policer_command_fn,
784 };
785 /* *INDENT-ON* */
786
787 static clib_error_t *
788 show_policer_pools_command_fn (vlib_main_t * vm,
789                                unformat_input_t * input,
790                                vlib_cli_command_t * cmd)
791 {
792   vnet_policer_main_t *pm = &vnet_policer_main;
793
794   vlib_cli_output (vm, "pool sizes: configs=%d templates=%d policers=%d",
795                    pool_elts (pm->configs),
796                    pool_elts (pm->policer_templates),
797                    pool_elts (pm->policers));
798   return 0;
799 }
800 /* *INDENT-OFF* */
801 VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
802     .path = "show policer pools",
803     .short_help = "show policer pools",
804     .function = show_policer_pools_command_fn,
805 };
806 /* *INDENT-ON* */
807
808 clib_error_t *
809 policer_init (vlib_main_t * vm)
810 {
811   vnet_policer_main_t *pm = &vnet_policer_main;
812
813   pm->vlib_main = vm;
814   pm->vnet_main = vnet_get_main ();
815   pm->log_class = vlib_log_register_class ("policer", 0);
816   pm->fq_index[VLIB_RX] =
817     vlib_frame_queue_main_init (policer_input_node.index, 0);
818   pm->fq_index[VLIB_TX] =
819     vlib_frame_queue_main_init (policer_output_node.index, 0);
820
821   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
822   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
823
824   vnet_classify_register_unformat_policer_next_index_fn
825     (unformat_policer_classify_next_index);
826   vnet_classify_register_unformat_opaque_index_fn
827     (unformat_policer_classify_precolor);
828
829   return 0;
830 }
831
832 VLIB_INIT_FUNCTION (policer_init);
833
834
835
836 /*
837  * fd.io coding-style-patch-verification: ON
838  *
839  * Local Variables:
840  * eval: (c-set-style "gnu")
841  * End:
842  */