policer: fix coverity warning/NULL dereference
[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, 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, sw_if_index);
188       pm->policer_index_by_sw_if_index[sw_if_index] = policer_index;
189     }
190   else
191     {
192       pm->policer_index_by_sw_if_index[sw_if_index] = ~0;
193     }
194
195   vnet_feature_enable_disable ("device-input", "policer-input", sw_if_index,
196                                apply, 0, 0);
197   return 0;
198 }
199
200 u8 *
201 format_policer_instance (u8 * s, va_list * va)
202 {
203   policer_t *i = va_arg (*va, policer_t *);
204   uword pi = va_arg (*va, uword);
205   int result;
206   vlib_counter_t counts[NUM_POLICE_RESULTS];
207
208   for (result = 0; result < NUM_POLICE_RESULTS; result++)
209     {
210       vlib_get_combined_counter (&policer_counters[result], pi,
211                                  &counts[result]);
212     }
213
214   s = format (s, "policer at %llx: %s rate, %s color-aware\n",
215               i, i->single_rate ? "single" : "dual",
216               i->color_aware ? "is" : "not");
217   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
218               i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
219   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
220               i->current_limit,
221               i->current_bucket, i->extended_limit, i->extended_bucket);
222   s = format (s, "last update %llu\n", i->last_update_time);
223   s = format (s, "conform %llu packets, %llu bytes\n",
224               counts[POLICE_CONFORM].packets, counts[POLICE_CONFORM].bytes);
225   s = format (s, "exceed %llu packets, %llu bytes\n",
226               counts[POLICE_EXCEED].packets, counts[POLICE_EXCEED].bytes);
227   s = format (s, "violate %llu packets, %llu bytes\n",
228               counts[POLICE_VIOLATE].packets, counts[POLICE_VIOLATE].bytes);
229   return s;
230 }
231
232 static u8 *
233 format_policer_round_type (u8 * s, va_list * va)
234 {
235   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
236
237   if (c->rnd_type == QOS_ROUND_TO_CLOSEST)
238     s = format (s, "closest");
239   else if (c->rnd_type == QOS_ROUND_TO_UP)
240     s = format (s, "up");
241   else if (c->rnd_type == QOS_ROUND_TO_DOWN)
242     s = format (s, "down");
243   else
244     s = format (s, "ILLEGAL");
245   return s;
246 }
247
248
249 static u8 *
250 format_policer_rate_type (u8 * s, va_list * va)
251 {
252   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
253
254   if (c->rate_type == QOS_RATE_KBPS)
255     s = format (s, "kbps");
256   else if (c->rate_type == QOS_RATE_PPS)
257     s = format (s, "pps");
258   else
259     s = format (s, "ILLEGAL");
260   return s;
261 }
262
263 static u8 *
264 format_policer_type (u8 * s, va_list * va)
265 {
266   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
267
268   if (c->rfc == QOS_POLICER_TYPE_1R2C)
269     s = format (s, "1r2c");
270
271   else if (c->rfc == QOS_POLICER_TYPE_1R3C_RFC_2697)
272     s = format (s, "1r3c");
273
274   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_2698)
275     s = format (s, "2r3c-2698");
276
277   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_4115)
278     s = format (s, "2r3c-4115");
279
280   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
281     s = format (s, "2r3c-mef5cf1");
282   else
283     s = format (s, "ILLEGAL");
284   return s;
285 }
286
287 static u8 *
288 format_policer_action_type (u8 * s, va_list * va)
289 {
290   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
291
292   if (a->action_type == QOS_ACTION_DROP)
293     s = format (s, "drop");
294   else if (a->action_type == QOS_ACTION_TRANSMIT)
295     s = format (s, "transmit");
296   else if (a->action_type == QOS_ACTION_MARK_AND_TRANSMIT)
297     s = format (s, "mark-and-transmit %U", format_ip_dscp, a->dscp);
298   else
299     s = format (s, "ILLEGAL");
300   return s;
301 }
302
303 u8 *
304 format_policer_config (u8 * s, va_list * va)
305 {
306   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
307
308   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
309               format_policer_type, c,
310               c->rb.kbps.cir_kbps,
311               c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes);
312   s = format (s, "rate type %U, round type %U\n",
313               format_policer_rate_type, c, format_policer_round_type, c);
314   s = format (s, "conform action %U, exceed action %U, violate action %U\n",
315               format_policer_action_type, &c->conform_action,
316               format_policer_action_type, &c->exceed_action,
317               format_policer_action_type, &c->violate_action);
318   return s;
319 }
320
321 static uword
322 unformat_policer_type (unformat_input_t * input, va_list * va)
323 {
324   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
325
326   if (!unformat (input, "type"))
327     return 0;
328
329   if (unformat (input, "1r2c"))
330     c->rfc = QOS_POLICER_TYPE_1R2C;
331   else if (unformat (input, "1r3c"))
332     c->rfc = QOS_POLICER_TYPE_1R3C_RFC_2697;
333   else if (unformat (input, "2r3c-2698"))
334     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_2698;
335   else if (unformat (input, "2r3c-4115"))
336     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_4115;
337   else if (unformat (input, "2r3c-mef5cf1"))
338     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
339   else
340     return 0;
341   return 1;
342 }
343
344 static uword
345 unformat_policer_round_type (unformat_input_t * input, va_list * va)
346 {
347   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
348
349   if (!unformat (input, "round"))
350     return 0;
351
352   if (unformat (input, "closest"))
353     c->rnd_type = QOS_ROUND_TO_CLOSEST;
354   else if (unformat (input, "up"))
355     c->rnd_type = QOS_ROUND_TO_UP;
356   else if (unformat (input, "down"))
357     c->rnd_type = QOS_ROUND_TO_DOWN;
358   else
359     return 0;
360   return 1;
361 }
362
363 static uword
364 unformat_policer_rate_type (unformat_input_t * input, va_list * va)
365 {
366   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
367
368   if (!unformat (input, "rate"))
369     return 0;
370
371   if (unformat (input, "kbps"))
372     c->rate_type = QOS_RATE_KBPS;
373   else if (unformat (input, "pps"))
374     c->rate_type = QOS_RATE_PPS;
375   else
376     return 0;
377   return 1;
378 }
379
380 static uword
381 unformat_policer_cir (unformat_input_t * input, va_list * va)
382 {
383   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
384
385   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
386     return 1;
387   return 0;
388 }
389
390 static uword
391 unformat_policer_eir (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, "eir %u", &c->rb.kbps.eir_kbps))
396     return 1;
397   return 0;
398 }
399
400 static uword
401 unformat_policer_cb (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, "cb %u", &c->rb.kbps.cb_bytes))
406     return 1;
407   return 0;
408 }
409
410 static uword
411 unformat_policer_eb (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, "eb %u", &c->rb.kbps.eb_bytes))
416     return 1;
417   return 0;
418 }
419
420 static uword
421 unformat_policer_action_type (unformat_input_t * input, va_list * va)
422 {
423   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
424
425   if (unformat (input, "drop"))
426     a->action_type = QOS_ACTION_DROP;
427   else if (unformat (input, "transmit"))
428     a->action_type = QOS_ACTION_TRANSMIT;
429   else if (unformat (input, "mark-and-transmit %U", unformat_ip_dscp,
430                      &a->dscp))
431     a->action_type = QOS_ACTION_MARK_AND_TRANSMIT;
432   else
433     return 0;
434   return 1;
435 }
436
437 static uword
438 unformat_policer_action (unformat_input_t * input, va_list * va)
439 {
440   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
441
442   if (unformat (input, "conform-action %U", unformat_policer_action_type,
443                 &c->conform_action))
444     return 1;
445   else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
446                      &c->exceed_action))
447     return 1;
448   else if (unformat (input, "violate-action %U", unformat_policer_action_type,
449                      &c->violate_action))
450     return 1;
451   return 0;
452 }
453
454 static uword
455 unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
456 {
457   u32 *r = va_arg (*va, u32 *);
458   vnet_policer_main_t *pm = &vnet_policer_main;
459   uword *p;
460   u8 *match_name = 0;
461
462   if (unformat (input, "%s", &match_name))
463     ;
464   else
465     return 0;
466
467   p = hash_get_mem (pm->policer_index_by_name, match_name);
468
469   if (p == 0)
470     return 0;
471
472   *r = p[0];
473
474   return 1;
475 }
476
477 static uword
478 unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
479 {
480   u32 *r = va_arg (*va, u32 *);
481
482   if (unformat (input, "conform-color"))
483     *r = POLICE_CONFORM;
484   else if (unformat (input, "exceed-color"))
485     *r = POLICE_EXCEED;
486   else
487     return 0;
488
489   return 1;
490 }
491
492 #define foreach_config_param                    \
493 _(eb)                                           \
494 _(cb)                                           \
495 _(eir)                                          \
496 _(cir)                                          \
497 _(rate_type)                                    \
498 _(round_type)                                   \
499 _(type)                                         \
500 _(action)
501
502 static clib_error_t *
503 policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
504                         vlib_cli_command_t *cmd)
505 {
506   qos_pol_cfg_params_st c;
507   unformat_input_t _line_input, *line_input = &_line_input;
508   u8 is_add = 1;
509   u8 *name = 0;
510   u32 pi;
511   clib_error_t *error = NULL;
512
513   /* Get a line of input. */
514   if (!unformat_user (input, unformat_line_input, line_input))
515     return 0;
516
517   clib_memset (&c, 0, sizeof (c));
518
519   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
520     {
521       if (unformat (line_input, "del"))
522         is_add = 0;
523       else if (unformat (line_input, "name %s", &name))
524         ;
525       else if (unformat (line_input, "color-aware"))
526         c.color_aware = 1;
527
528 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
529       foreach_config_param
530 #undef _
531         else
532         {
533           error = clib_error_return (0, "unknown input `%U'",
534                                      format_unformat_error, line_input);
535           goto done;
536         }
537     }
538
539   error = policer_add_del (vm, name, &c, &pi, is_add);
540
541 done:
542   unformat_free (line_input);
543
544   return error;
545 }
546
547 static clib_error_t *
548 policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
549                         vlib_cli_command_t *cmd)
550 {
551   unformat_input_t _line_input, *line_input = &_line_input;
552   clib_error_t *error = NULL;
553   u8 *name = 0;
554
555   /* Get a line of input. */
556   if (!unformat_user (input, unformat_line_input, line_input))
557     return 0;
558
559   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
560     {
561       if (unformat (line_input, "name %s", &name))
562         ;
563       else
564         {
565           error = clib_error_return (0, "unknown input `%U'",
566                                      format_unformat_error, line_input);
567           goto done;
568         }
569     }
570
571   error = policer_add_del (vm, name, NULL, NULL, 0);
572
573 done:
574   unformat_free (line_input);
575
576   return error;
577 }
578
579 static clib_error_t *
580 policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
581                          vlib_cli_command_t *cmd)
582 {
583   unformat_input_t _line_input, *line_input = &_line_input;
584   clib_error_t *error = NULL;
585   u8 bind, *name = 0;
586   u32 worker;
587   int rv;
588
589   bind = 1;
590   worker = ~0;
591
592   /* Get a line of input. */
593   if (!unformat_user (input, unformat_line_input, line_input))
594     return 0;
595
596   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
597     {
598       if (unformat (line_input, "name %s", &name))
599         ;
600       else if (unformat (line_input, "unbind"))
601         bind = 0;
602       else if (unformat (line_input, "%d", &worker))
603         ;
604       else
605         {
606           error = clib_error_return (0, "unknown input `%U'",
607                                      format_unformat_error, line_input);
608           goto done;
609         }
610     }
611
612   if (bind && ~0 == worker)
613     {
614       error = clib_error_return (0, "specify worker to bind to: `%U'",
615                                  format_unformat_error, line_input);
616     }
617   else
618     {
619       rv = policer_bind_worker (name, worker, bind);
620
621       if (rv)
622         error = clib_error_return (0, "failed: `%d'", rv);
623     }
624
625 done:
626   unformat_free (line_input);
627
628   return error;
629 }
630
631 static clib_error_t *
632 policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
633                           vlib_cli_command_t *cmd)
634 {
635   unformat_input_t _line_input, *line_input = &_line_input;
636   clib_error_t *error = NULL;
637   u8 apply, *name = 0;
638   u32 sw_if_index;
639   int rv;
640
641   apply = 1;
642   sw_if_index = ~0;
643
644   /* Get a line of input. */
645   if (!unformat_user (input, unformat_line_input, line_input))
646     return 0;
647
648   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
649     {
650       if (unformat (line_input, "name %s", &name))
651         ;
652       else if (unformat (line_input, "unapply"))
653         apply = 0;
654       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
655                          vnet_get_main (), &sw_if_index))
656         ;
657       else
658         {
659           error = clib_error_return (0, "unknown input `%U'",
660                                      format_unformat_error, line_input);
661           goto done;
662         }
663     }
664
665   if (~0 == sw_if_index)
666     {
667       error = clib_error_return (0, "specify interface to apply to: `%U'",
668                                  format_unformat_error, line_input);
669     }
670   else
671     {
672       rv = policer_input (name, sw_if_index, apply);
673
674       if (rv)
675         error = clib_error_return (0, "failed: `%d'", rv);
676     }
677
678 done:
679   unformat_free (line_input);
680
681   return error;
682 }
683
684 /* *INDENT-OFF* */
685 VLIB_CLI_COMMAND (configure_policer_command, static) = {
686   .path = "configure policer",
687   .short_help = "configure policer name <name> <params> ",
688   .function = policer_add_command_fn,
689 };
690 VLIB_CLI_COMMAND (policer_add_command, static) = {
691   .path = "policer add",
692   .short_help = "policer name <name> <params> ",
693   .function = policer_add_command_fn,
694 };
695 VLIB_CLI_COMMAND (policer_del_command, static) = {
696   .path = "policer del",
697   .short_help = "policer del name <name> ",
698   .function = policer_del_command_fn,
699 };
700 VLIB_CLI_COMMAND (policer_bind_command, static) = {
701   .path = "policer bind",
702   .short_help = "policer bind [unbind] name <name> <worker>",
703   .function = policer_bind_command_fn,
704 };
705 VLIB_CLI_COMMAND (policer_input_command, static) = {
706   .path = "policer input",
707   .short_help = "policer input [unapply] name <name> <interfac>",
708   .function = policer_input_command_fn,
709 };
710 /* *INDENT-ON* */
711
712 static clib_error_t *
713 show_policer_command_fn (vlib_main_t * vm,
714                          unformat_input_t * input, vlib_cli_command_t * cmd)
715 {
716   vnet_policer_main_t *pm = &vnet_policer_main;
717   hash_pair_t *p;
718   u32 pool_index;
719   u8 *match_name = 0;
720   u8 *name;
721   uword *pi;
722   qos_pol_cfg_params_st *config;
723   policer_t *templ;
724
725   (void) unformat (input, "name %s", &match_name);
726
727   /* *INDENT-OFF* */
728   hash_foreach_pair (p, pm->policer_config_by_name,
729   ({
730     name = (u8 *) p->key;
731     if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
732       {
733         pi = hash_get_mem (pm->policer_index_by_name, name);
734
735         pool_index = p->value[0];
736         config = pool_elt_at_index (pm->configs, pool_index);
737         templ = pool_elt_at_index (pm->policer_templates, pool_index);
738         vlib_cli_output (vm, "Name \"%s\" %U ", name, format_policer_config,
739                          config);
740         if (pi)
741           {
742             vlib_cli_output (vm, "Template %U", format_policer_instance, templ,
743                              pi[0]);
744           }
745         else
746           {
747             vlib_cli_output (
748               vm, "Cannot print template - policer index hash lookup failed");
749           }
750         vlib_cli_output (vm, "-----------");
751       }
752   }));
753   /* *INDENT-ON* */
754   return 0;
755 }
756
757
758 /* *INDENT-OFF* */
759 VLIB_CLI_COMMAND (show_policer_command, static) = {
760     .path = "show policer",
761     .short_help = "show policer [name]",
762     .function = show_policer_command_fn,
763 };
764 /* *INDENT-ON* */
765
766 static clib_error_t *
767 show_policer_pools_command_fn (vlib_main_t * vm,
768                                unformat_input_t * input,
769                                vlib_cli_command_t * cmd)
770 {
771   vnet_policer_main_t *pm = &vnet_policer_main;
772
773   vlib_cli_output (vm, "pool sizes: configs=%d templates=%d policers=%d",
774                    pool_elts (pm->configs),
775                    pool_elts (pm->policer_templates),
776                    pool_elts (pm->policers));
777   return 0;
778 }
779 /* *INDENT-OFF* */
780 VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
781     .path = "show policer pools",
782     .short_help = "show policer pools",
783     .function = show_policer_pools_command_fn,
784 };
785 /* *INDENT-ON* */
786
787 clib_error_t *
788 policer_init (vlib_main_t * vm)
789 {
790   vnet_policer_main_t *pm = &vnet_policer_main;
791
792   pm->vlib_main = vm;
793   pm->vnet_main = vnet_get_main ();
794   pm->log_class = vlib_log_register_class ("policer", 0);
795   pm->fq_index = vlib_frame_queue_main_init (policer_input_node.index, 0);
796
797   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
798   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
799
800   vnet_classify_register_unformat_policer_next_index_fn
801     (unformat_policer_classify_next_index);
802   vnet_classify_register_unformat_opaque_index_fn
803     (unformat_policer_classify_precolor);
804
805   return 0;
806 }
807
808 VLIB_INIT_FUNCTION (policer_init);
809
810
811
812 /*
813  * fd.io coding-style-patch-verification: ON
814  *
815  * Local Variables:
816  * eval: (c-set-style "gnu")
817  * End:
818  */