misc: remove GNU Indent directives
[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 int
53 policer_add (vlib_main_t *vm, const u8 *name, const qos_pol_cfg_params_st *cfg,
54              u32 *policer_index)
55 {
56   vnet_policer_main_t *pm = &vnet_policer_main;
57   policer_t test_policer;
58   policer_t *policer;
59   policer_t *pp;
60   qos_pol_cfg_params_st *cp;
61   uword *p;
62   u32 pi;
63   int rv;
64   int i;
65
66   p = hash_get_mem (pm->policer_config_by_name, name);
67
68   if (p != NULL)
69     return VNET_API_ERROR_VALUE_EXIST;
70
71   /* Vet the configuration before adding it to the table */
72   rv = pol_logical_2_physical (cfg, &test_policer);
73
74   if (rv != 0)
75     return VNET_API_ERROR_INVALID_VALUE;
76
77   pool_get (pm->configs, cp);
78   pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
79
80   clib_memcpy (cp, cfg, sizeof (*cp));
81   clib_memcpy (policer, &test_policer, sizeof (*pp));
82
83   policer->name = format (0, "%s%c", name, 0);
84   pi = policer - pm->policers;
85
86   hash_set_mem (pm->policer_config_by_name, policer->name, cp - pm->configs);
87   hash_set_mem (pm->policer_index_by_name, policer->name, pi);
88   *policer_index = pi;
89   policer->thread_index = ~0;
90
91   for (i = 0; i < NUM_POLICE_RESULTS; i++)
92     {
93       vlib_validate_combined_counter (&policer_counters[i], pi);
94       vlib_zero_combined_counter (&policer_counters[i], pi);
95     }
96
97   return 0;
98 }
99
100 int
101 policer_del (vlib_main_t *vm, u32 policer_index)
102 {
103   vnet_policer_main_t *pm = &vnet_policer_main;
104   policer_t *policer;
105   uword *p;
106
107   if (pool_is_free_index (pm->policers, policer_index))
108     return VNET_API_ERROR_NO_SUCH_ENTRY;
109
110   policer = &pm->policers[policer_index];
111
112   p = hash_get_mem (pm->policer_config_by_name, policer->name);
113
114   /* free policer config */
115   if (p != NULL)
116     {
117       pool_put_index (pm->configs, p[0]);
118       hash_unset_mem (pm->policer_config_by_name, policer->name);
119     }
120
121   /* free policer */
122   hash_unset_mem (pm->policer_index_by_name, policer->name);
123   vec_free (policer->name);
124   pool_put_index (pm->policers, policer_index);
125
126   return 0;
127 }
128
129 int
130 policer_update (vlib_main_t *vm, u32 policer_index,
131                 const qos_pol_cfg_params_st *cfg)
132 {
133   vnet_policer_main_t *pm = &vnet_policer_main;
134   policer_t test_policer;
135   policer_t *policer;
136   qos_pol_cfg_params_st *cp;
137   uword *p;
138   u8 *name;
139   int rv;
140   int i;
141
142   if (pool_is_free_index (pm->policers, policer_index))
143     return VNET_API_ERROR_NO_SUCH_ENTRY;
144
145   policer = &pm->policers[policer_index];
146
147   /* Vet the configuration before adding it to the table */
148   rv = pol_logical_2_physical (cfg, &test_policer);
149   if (rv != 0)
150     return VNET_API_ERROR_INVALID_VALUE;
151
152   p = hash_get_mem (pm->policer_config_by_name, policer->name);
153
154   if (PREDICT_TRUE (p != NULL))
155     {
156       cp = &pm->configs[p[0]];
157     }
158   else
159     {
160       /* recover from a missing configuration */
161       pool_get (pm->configs, cp);
162       hash_set_mem (pm->policer_config_by_name, policer->name,
163                     cp - pm->configs);
164     }
165
166   name = policer->name;
167
168   clib_memcpy (cp, cfg, sizeof (*cp));
169   clib_memcpy (policer, &test_policer, sizeof (*policer));
170
171   policer->name = name;
172   policer->thread_index = ~0;
173
174   for (i = 0; i < NUM_POLICE_RESULTS; i++)
175     vlib_zero_combined_counter (&policer_counters[i], policer_index);
176
177   return 0;
178 }
179
180 int
181 policer_reset (vlib_main_t *vm, u32 policer_index)
182 {
183   vnet_policer_main_t *pm = &vnet_policer_main;
184   policer_t *policer;
185
186   if (pool_is_free_index (pm->policers, policer_index))
187     return VNET_API_ERROR_NO_SUCH_ENTRY;
188
189   policer = &pm->policers[policer_index];
190
191   policer->current_bucket = policer->current_limit;
192   policer->extended_bucket = policer->extended_limit;
193
194   return 0;
195 }
196
197 int
198 policer_bind_worker (u32 policer_index, u32 worker, bool bind)
199 {
200   vnet_policer_main_t *pm = &vnet_policer_main;
201   policer_t *policer;
202
203   if (pool_is_free_index (pm->policers, policer_index))
204     return VNET_API_ERROR_NO_SUCH_ENTRY;
205
206   policer = &pm->policers[policer_index];
207
208   if (bind)
209     {
210       if (worker >= vlib_num_workers ())
211         {
212           return VNET_API_ERROR_INVALID_WORKER;
213         }
214
215       policer->thread_index = vlib_get_worker_thread_index (worker);
216     }
217   else
218     {
219       policer->thread_index = ~0;
220     }
221   return 0;
222 }
223
224 int
225 policer_input (u32 policer_index, u32 sw_if_index, vlib_dir_t dir, bool apply)
226 {
227   vnet_policer_main_t *pm = &vnet_policer_main;
228
229   if (apply)
230     {
231       vec_validate (pm->policer_index_by_sw_if_index[dir], sw_if_index);
232       pm->policer_index_by_sw_if_index[dir][sw_if_index] = policer_index;
233     }
234   else
235     {
236       pm->policer_index_by_sw_if_index[dir][sw_if_index] = ~0;
237     }
238
239   if (dir == VLIB_RX)
240     {
241       vnet_feature_enable_disable ("device-input", "policer-input",
242                                    sw_if_index, apply, 0, 0);
243     }
244   else
245     {
246       vnet_feature_enable_disable ("ip4-output", "policer-output", sw_if_index,
247                                    apply, 0, 0);
248       vnet_feature_enable_disable ("ip6-output", "policer-output", sw_if_index,
249                                    apply, 0, 0);
250     }
251   return 0;
252 }
253
254 u8 *
255 format_policer_instance (u8 * s, va_list * va)
256 {
257   vnet_policer_main_t *pm = &vnet_policer_main;
258   policer_t *i = va_arg (*va, policer_t *);
259   u32 policer_index = i - pm->policers;
260   int result;
261   vlib_counter_t counts[NUM_POLICE_RESULTS];
262
263   for (result = 0; result < NUM_POLICE_RESULTS; result++)
264     {
265       vlib_get_combined_counter (&policer_counters[result], policer_index,
266                                  &counts[result]);
267     }
268
269   s =
270     format (s, "Policer at index %d: %s rate, %s color-aware\n", policer_index,
271             i->single_rate ? "single" : "dual", i->color_aware ? "is" : "not");
272   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
273               i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
274   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
275               i->current_limit,
276               i->current_bucket, i->extended_limit, i->extended_bucket);
277   s = format (s, "last update %llu\n", i->last_update_time);
278   s = format (s, "conform %llu packets, %llu bytes\n",
279               counts[POLICE_CONFORM].packets, counts[POLICE_CONFORM].bytes);
280   s = format (s, "exceed %llu packets, %llu bytes\n",
281               counts[POLICE_EXCEED].packets, counts[POLICE_EXCEED].bytes);
282   s = format (s, "violate %llu packets, %llu bytes\n",
283               counts[POLICE_VIOLATE].packets, counts[POLICE_VIOLATE].bytes);
284   return s;
285 }
286
287 static u8 *
288 format_policer_round_type (u8 * s, va_list * va)
289 {
290   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
291
292   if (c->rnd_type == QOS_ROUND_TO_CLOSEST)
293     s = format (s, "closest");
294   else if (c->rnd_type == QOS_ROUND_TO_UP)
295     s = format (s, "up");
296   else if (c->rnd_type == QOS_ROUND_TO_DOWN)
297     s = format (s, "down");
298   else
299     s = format (s, "ILLEGAL");
300   return s;
301 }
302
303
304 static u8 *
305 format_policer_rate_type (u8 * s, va_list * va)
306 {
307   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
308
309   if (c->rate_type == QOS_RATE_KBPS)
310     s = format (s, "kbps");
311   else if (c->rate_type == QOS_RATE_PPS)
312     s = format (s, "pps");
313   else
314     s = format (s, "ILLEGAL");
315   return s;
316 }
317
318 static u8 *
319 format_policer_type (u8 * s, va_list * va)
320 {
321   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
322
323   if (c->rfc == QOS_POLICER_TYPE_1R2C)
324     s = format (s, "1r2c");
325
326   else if (c->rfc == QOS_POLICER_TYPE_1R3C_RFC_2697)
327     s = format (s, "1r3c");
328
329   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_2698)
330     s = format (s, "2r3c-2698");
331
332   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_4115)
333     s = format (s, "2r3c-4115");
334
335   else if (c->rfc == QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
336     s = format (s, "2r3c-mef5cf1");
337   else
338     s = format (s, "ILLEGAL");
339   return s;
340 }
341
342 static u8 *
343 format_policer_action_type (u8 * s, va_list * va)
344 {
345   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
346
347   if (a->action_type == QOS_ACTION_DROP)
348     s = format (s, "drop");
349   else if (a->action_type == QOS_ACTION_TRANSMIT)
350     s = format (s, "transmit");
351   else if (a->action_type == QOS_ACTION_MARK_AND_TRANSMIT)
352     s = format (s, "mark-and-transmit %U", format_ip_dscp, a->dscp);
353   else
354     s = format (s, "ILLEGAL");
355   return s;
356 }
357
358 u8 *
359 format_policer_config (u8 * s, va_list * va)
360 {
361   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
362
363   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
364               format_policer_type, c,
365               c->rb.kbps.cir_kbps,
366               c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes);
367   s = format (s, "rate type %U, round type %U\n",
368               format_policer_rate_type, c, format_policer_round_type, c);
369   s = format (s, "conform action %U, exceed action %U, violate action %U\n",
370               format_policer_action_type, &c->conform_action,
371               format_policer_action_type, &c->exceed_action,
372               format_policer_action_type, &c->violate_action);
373   return s;
374 }
375
376 static uword
377 unformat_policer_type (unformat_input_t * input, va_list * va)
378 {
379   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
380
381   if (!unformat (input, "type"))
382     return 0;
383
384   if (unformat (input, "1r2c"))
385     c->rfc = QOS_POLICER_TYPE_1R2C;
386   else if (unformat (input, "1r3c"))
387     c->rfc = QOS_POLICER_TYPE_1R3C_RFC_2697;
388   else if (unformat (input, "2r3c-2698"))
389     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_2698;
390   else if (unformat (input, "2r3c-4115"))
391     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_4115;
392   else if (unformat (input, "2r3c-mef5cf1"))
393     c->rfc = QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
394   else
395     return 0;
396   return 1;
397 }
398
399 static uword
400 unformat_policer_round_type (unformat_input_t * input, va_list * va)
401 {
402   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
403
404   if (!unformat (input, "round"))
405     return 0;
406
407   if (unformat (input, "closest"))
408     c->rnd_type = QOS_ROUND_TO_CLOSEST;
409   else if (unformat (input, "up"))
410     c->rnd_type = QOS_ROUND_TO_UP;
411   else if (unformat (input, "down"))
412     c->rnd_type = QOS_ROUND_TO_DOWN;
413   else
414     return 0;
415   return 1;
416 }
417
418 static uword
419 unformat_policer_rate_type (unformat_input_t * input, va_list * va)
420 {
421   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
422
423   if (!unformat (input, "rate"))
424     return 0;
425
426   if (unformat (input, "kbps"))
427     c->rate_type = QOS_RATE_KBPS;
428   else if (unformat (input, "pps"))
429     c->rate_type = QOS_RATE_PPS;
430   else
431     return 0;
432   return 1;
433 }
434
435 static uword
436 unformat_policer_cir (unformat_input_t * input, va_list * va)
437 {
438   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
439
440   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
441     return 1;
442   return 0;
443 }
444
445 static uword
446 unformat_policer_eir (unformat_input_t * input, va_list * va)
447 {
448   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
449
450   if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps))
451     return 1;
452   return 0;
453 }
454
455 static uword
456 unformat_policer_cb (unformat_input_t * input, va_list * va)
457 {
458   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
459
460   if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes))
461     return 1;
462   return 0;
463 }
464
465 static uword
466 unformat_policer_eb (unformat_input_t * input, va_list * va)
467 {
468   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
469
470   if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes))
471     return 1;
472   return 0;
473 }
474
475 static uword
476 unformat_policer_action_type (unformat_input_t * input, va_list * va)
477 {
478   qos_pol_action_params_st *a = va_arg (*va, qos_pol_action_params_st *);
479
480   if (unformat (input, "drop"))
481     a->action_type = QOS_ACTION_DROP;
482   else if (unformat (input, "transmit"))
483     a->action_type = QOS_ACTION_TRANSMIT;
484   else if (unformat (input, "mark-and-transmit %U", unformat_ip_dscp,
485                      &a->dscp))
486     a->action_type = QOS_ACTION_MARK_AND_TRANSMIT;
487   else
488     return 0;
489   return 1;
490 }
491
492 static uword
493 unformat_policer_action (unformat_input_t * input, va_list * va)
494 {
495   qos_pol_cfg_params_st *c = va_arg (*va, qos_pol_cfg_params_st *);
496
497   if (unformat (input, "conform-action %U", unformat_policer_action_type,
498                 &c->conform_action))
499     return 1;
500   else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
501                      &c->exceed_action))
502     return 1;
503   else if (unformat (input, "violate-action %U", unformat_policer_action_type,
504                      &c->violate_action))
505     return 1;
506   return 0;
507 }
508
509 static uword
510 unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
511 {
512   u32 *r = va_arg (*va, u32 *);
513   vnet_policer_main_t *pm = &vnet_policer_main;
514   uword *p;
515   u8 *match_name = 0;
516
517   if (unformat (input, "%s", &match_name))
518     ;
519   else
520     return 0;
521
522   p = hash_get_mem (pm->policer_index_by_name, match_name);
523   vec_free (match_name);
524
525   if (p == 0)
526     return 0;
527
528   *r = p[0];
529
530   return 1;
531 }
532
533 static uword
534 unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
535 {
536   u32 *r = va_arg (*va, u32 *);
537
538   if (unformat (input, "conform-color"))
539     *r = POLICE_CONFORM;
540   else if (unformat (input, "exceed-color"))
541     *r = POLICE_EXCEED;
542   else
543     return 0;
544
545   return 1;
546 }
547
548 #define foreach_config_param                    \
549 _(eb)                                           \
550 _(cb)                                           \
551 _(eir)                                          \
552 _(cir)                                          \
553 _(rate_type)                                    \
554 _(round_type)                                   \
555 _(type)                                         \
556 _(action)
557
558 static clib_error_t *
559 policer_add_command_fn (vlib_main_t *vm, unformat_input_t *input,
560                         vlib_cli_command_t *cmd)
561 {
562   vnet_policer_main_t *pm = &vnet_policer_main;
563   qos_pol_cfg_params_st c;
564   unformat_input_t _line_input, *line_input = &_line_input;
565   u8 *name = 0;
566   uword *p;
567   u32 pi;
568   u32 policer_index = ~0;
569   int rv = 0;
570   clib_error_t *error = NULL;
571   u8 is_update = cmd->function_arg;
572
573   /* Get a line of input. */
574   if (!unformat_user (input, unformat_line_input, line_input))
575     return 0;
576
577   clib_memset (&c, 0, sizeof (c));
578
579   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
580     {
581       if (unformat (line_input, "name %s", &name))
582         ;
583       else if (is_update && unformat (line_input, "index %u", &policer_index))
584         ;
585       else if (unformat (line_input, "color-aware"))
586         c.color_aware = 1;
587
588 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
589       foreach_config_param
590 #undef _
591         else
592         {
593           error = clib_error_return (0, "unknown input `%U'",
594                                      format_unformat_error, line_input);
595           goto done;
596         }
597     }
598
599   if (is_update)
600     {
601       if (~0 == policer_index && 0 != name)
602         {
603           p = hash_get_mem (pm->policer_index_by_name, name);
604           if (p != NULL)
605             policer_index = p[0];
606         }
607
608       if (~0 != policer_index)
609         {
610           rv = policer_update (vm, policer_index, &c);
611         }
612     }
613   else
614     {
615       rv = policer_add (vm, name, &c, &pi);
616     }
617
618   switch (rv)
619     {
620     case VNET_API_ERROR_NO_SUCH_ENTRY:
621       error = clib_error_return (0, "No such policer");
622       break;
623     case VNET_API_ERROR_VALUE_EXIST:
624       error = clib_error_return (0, "Policer already exists");
625       break;
626     case VNET_API_ERROR_INVALID_VALUE:
627       error = clib_error_return (0, "Config failed sanity check");
628       break;
629     }
630
631 done:
632   unformat_free (line_input);
633   vec_free (name);
634
635   return error;
636 }
637
638 static clib_error_t *
639 policer_del_command_fn (vlib_main_t *vm, unformat_input_t *input,
640                         vlib_cli_command_t *cmd)
641 {
642   unformat_input_t _line_input, *line_input = &_line_input;
643   clib_error_t *error = NULL;
644   vnet_policer_main_t *pm = &vnet_policer_main;
645   int rv;
646   u32 policer_index = ~0;
647   uword *p;
648   u8 *name = 0;
649
650   /* Get a line of input. */
651   if (!unformat_user (input, unformat_line_input, line_input))
652     return 0;
653
654   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
655     {
656       if (unformat (line_input, "name %s", &name))
657         ;
658       else if (unformat (line_input, "index %u", &policer_index))
659         ;
660       else
661         {
662           error = clib_error_return (0, "unknown input `%U'",
663                                      format_unformat_error, line_input);
664           goto done;
665         }
666     }
667
668   if (~0 == policer_index && 0 != name)
669     {
670       p = hash_get_mem (pm->policer_index_by_name, name);
671       if (p != NULL)
672         policer_index = p[0];
673     }
674
675   rv = VNET_API_ERROR_NO_SUCH_ENTRY;
676   if (~0 != policer_index)
677     rv = policer_del (vm, policer_index);
678
679   switch (rv)
680     {
681     case VNET_API_ERROR_INVALID_VALUE:
682       error = clib_error_return (0, "No such policer configuration");
683       break;
684     case VNET_API_ERROR_NO_SUCH_ENTRY:
685       error = clib_error_return (0, "No such policer");
686       break;
687     }
688
689 done:
690   unformat_free (line_input);
691   vec_free (name);
692
693   return error;
694 }
695
696 static clib_error_t *
697 policer_bind_command_fn (vlib_main_t *vm, unformat_input_t *input,
698                          vlib_cli_command_t *cmd)
699 {
700   unformat_input_t _line_input, *line_input = &_line_input;
701   clib_error_t *error = NULL;
702   vnet_policer_main_t *pm = &vnet_policer_main;
703   u8 bind = 1;
704   u8 *name = 0;
705   u32 worker = ~0;
706   u32 policer_index = ~0;
707   uword *p;
708   int rv;
709
710   /* Get a line of input. */
711   if (!unformat_user (input, unformat_line_input, line_input))
712     return 0;
713
714   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
715     {
716       if (unformat (line_input, "name %s", &name))
717         ;
718       else if (unformat (line_input, "index %u", &policer_index))
719         ;
720       else if (unformat (line_input, "unbind"))
721         bind = 0;
722       else if (unformat (line_input, "%d", &worker))
723         ;
724       else
725         {
726           error = clib_error_return (0, "unknown input `%U'",
727                                      format_unformat_error, line_input);
728           goto done;
729         }
730     }
731
732   if (bind && ~0 == worker)
733     {
734       error = clib_error_return (0, "specify worker to bind to: `%U'",
735                                  format_unformat_error, line_input);
736     }
737   else
738     {
739       if (~0 == policer_index && 0 != name)
740         {
741           p = hash_get_mem (pm->policer_index_by_name, name);
742           if (p != NULL)
743             policer_index = p[0];
744         }
745
746       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
747       if (~0 != policer_index)
748         rv = policer_bind_worker (policer_index, worker, bind);
749
750       if (rv)
751         error = clib_error_return (0, "failed: `%d'", rv);
752     }
753
754 done:
755   unformat_free (line_input);
756   vec_free (name);
757
758   return error;
759 }
760
761 static clib_error_t *
762 policer_input_command_fn (vlib_main_t *vm, unformat_input_t *input,
763                           vlib_cli_command_t *cmd)
764 {
765   unformat_input_t _line_input, *line_input = &_line_input;
766   clib_error_t *error = NULL;
767   vnet_policer_main_t *pm = &vnet_policer_main;
768   u8 apply = 1;
769   u8 *name = 0;
770   u32 sw_if_index = ~0;
771   u32 policer_index = ~0;
772   uword *p;
773   int rv;
774   vlib_dir_t dir = cmd->function_arg;
775
776   /* Get a line of input. */
777   if (!unformat_user (input, unformat_line_input, line_input))
778     return 0;
779
780   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
781     {
782       if (unformat (line_input, "name %s", &name))
783         ;
784       else if (unformat (line_input, "index %u", &policer_index))
785         ;
786       else if (unformat (line_input, "unapply"))
787         apply = 0;
788       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
789                          vnet_get_main (), &sw_if_index))
790         ;
791       else
792         {
793           error = clib_error_return (0, "unknown input `%U'",
794                                      format_unformat_error, line_input);
795           goto done;
796         }
797     }
798
799   if (~0 == sw_if_index)
800     {
801       error = clib_error_return (0, "specify interface to apply to: `%U'",
802                                  format_unformat_error, line_input);
803     }
804   else
805     {
806       if (~0 == policer_index && 0 != name)
807         {
808           p = hash_get_mem (pm->policer_index_by_name, name);
809           if (p != NULL)
810             policer_index = p[0];
811         }
812
813       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
814       if (~0 != policer_index)
815         rv = policer_input (policer_index, sw_if_index, dir, apply);
816
817       if (rv)
818         error = clib_error_return (0, "failed: `%d'", rv);
819     }
820
821 done:
822   unformat_free (line_input);
823   vec_free (name);
824
825   return error;
826 }
827
828 static clib_error_t *
829 policer_reset_command_fn (vlib_main_t *vm, unformat_input_t *input,
830                           vlib_cli_command_t *cmd)
831 {
832   unformat_input_t _line_input, *line_input = &_line_input;
833   clib_error_t *error = NULL;
834   vnet_policer_main_t *pm = &vnet_policer_main;
835   int rv;
836   u32 policer_index = ~0;
837   uword *p;
838   u8 *name = 0;
839
840   /* Get a line of input. */
841   if (!unformat_user (input, unformat_line_input, line_input))
842     return 0;
843
844   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
845     {
846       if (unformat (line_input, "name %s", &name))
847         ;
848       else if (unformat (line_input, "index %u", &policer_index))
849         ;
850       else
851         {
852           error = clib_error_return (0, "unknown input `%U'",
853                                      format_unformat_error, line_input);
854           goto done;
855         }
856     }
857
858   if (~0 == policer_index && 0 != name)
859     {
860       p = hash_get_mem (pm->policer_index_by_name, name);
861       if (p != NULL)
862         policer_index = p[0];
863     }
864
865   rv = VNET_API_ERROR_NO_SUCH_ENTRY;
866   if (~0 != policer_index)
867     rv = policer_reset (vm, policer_index);
868
869   switch (rv)
870     {
871     case VNET_API_ERROR_NO_SUCH_ENTRY:
872       error = clib_error_return (0, "No such policer");
873       break;
874     }
875
876 done:
877   unformat_free (line_input);
878   vec_free (name);
879
880   return error;
881 }
882
883 VLIB_CLI_COMMAND (configure_policer_command, static) = {
884   .path = "configure policer",
885   .short_help = "configure policer [name <name> | index <index>] [type 1r2c | "
886                 "1r3c | 2r3c-2698 "
887                 "| 2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
888                 "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
889                 "[conform-action drop | transmit | mark-and-transmit <dscp>] "
890                 "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
891                 "[violate-action drop | transmit | mark-and-transmit <dscp>]",
892   .function = policer_add_command_fn,
893   .function_arg = 1
894 };
895
896 VLIB_CLI_COMMAND (policer_add_command, static) = {
897   .path = "policer add",
898   .short_help = "policer add name <name> [type 1r2c | 1r3c | 2r3c-2698 | "
899                 "2r3c-4115] [color-aware] [cir <cir>] [cb <cb>] [eir <eir>] "
900                 "[eb <eb>] [rate kbps | pps] [round closest | up | down] "
901                 "[conform-action drop | transmit | mark-and-transmit <dscp>] "
902                 "[exceed-action drop | transmit | mark-and-transmit <dscp>] "
903                 "[violate-action drop | transmit | mark-and-transmit <dscp>]",
904   .function = policer_add_command_fn,
905   .function_arg = 0
906 };
907
908 VLIB_CLI_COMMAND (policer_del_command, static) = {
909   .path = "policer del",
910   .short_help = "policer del [name <name> | index <index>]",
911   .function = policer_del_command_fn,
912 };
913
914 VLIB_CLI_COMMAND (policer_bind_command, static) = {
915   .path = "policer bind",
916   .short_help = "policer bind [unbind] [name <name> | index <index>] <worker>",
917   .function = policer_bind_command_fn,
918 };
919
920 VLIB_CLI_COMMAND (policer_input_command, static) = {
921   .path = "policer input",
922   .short_help =
923     "policer input [unapply] [name <name> | index <index>] <interface>",
924   .function = policer_input_command_fn,
925   .function_arg = VLIB_RX,
926 };
927
928 VLIB_CLI_COMMAND (policer_output_command, static) = {
929   .path = "policer output",
930   .short_help =
931     "policer output [unapply] [name <name> | index <index>] <interface>",
932   .function = policer_input_command_fn,
933   .function_arg = VLIB_TX,
934 };
935
936 VLIB_CLI_COMMAND (policer_reset_command, static) = {
937   .path = "policer reset",
938   .short_help = "policer reset [name <name> | index <index>]",
939   .function = policer_reset_command_fn
940 };
941
942 static clib_error_t *
943 show_policer_command_fn (vlib_main_t * vm,
944                          unformat_input_t * input, vlib_cli_command_t * cmd)
945 {
946   vnet_policer_main_t *pm = &vnet_policer_main;
947   unformat_input_t _line_input, *line_input = &_line_input;
948   policer_t *policer;
949   u32 policer_index = ~0;
950   u8 *name = 0;
951   uword *ci, *pi;
952   qos_pol_cfg_params_st *config;
953   clib_error_t *error = 0;
954
955   /* Get a line of input. */
956   if (!unformat_user (input, unformat_line_input, line_input))
957     {
958       pool_foreach (policer, pm->policers)
959         {
960           ci = hash_get_mem (pm->policer_config_by_name, policer->name);
961           config = pool_elt_at_index (pm->configs, ci[0]);
962
963           vlib_cli_output (vm, "Name \"%s\" %U ", policer->name,
964                            format_policer_config, config);
965           vlib_cli_output (vm, "%U", format_policer_instance, policer);
966           vlib_cli_output (vm, "-----------");
967         }
968       return 0;
969     }
970
971   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
972     {
973       if (unformat (line_input, "name %s", &name))
974         ;
975       else if (unformat (line_input, "index %u", &policer_index))
976         ;
977       else
978         {
979           error = clib_error_return (0, "unknown input `%U'",
980                                      format_unformat_error, line_input);
981           goto done;
982         }
983     }
984
985   if (~0 == policer_index && 0 != name)
986     {
987       pi = hash_get_mem (pm->policer_index_by_name, name);
988       if (pi != NULL)
989         policer_index = pi[0];
990     }
991
992   if (~0 == policer_index || pool_is_free_index (pm->policers, policer_index))
993     goto done;
994
995   policer = &pm->policers[policer_index];
996   ci = hash_get_mem (pm->policer_config_by_name, policer->name);
997   config = pool_elt_at_index (pm->configs, ci[0]);
998   vlib_cli_output (vm, "Name \"%s\" %U ", policer->name, format_policer_config,
999                    config);
1000   vlib_cli_output (vm, "%U", format_policer_instance, policer);
1001   vlib_cli_output (vm, "-----------");
1002
1003 done:
1004   unformat_free (line_input);
1005   vec_free (name);
1006
1007   return error;
1008 }
1009
1010
1011 VLIB_CLI_COMMAND (show_policer_command, static) = {
1012   .path = "show policer",
1013   .short_help = "show policer [name <name> | index <index>]",
1014   .function = show_policer_command_fn,
1015 };
1016
1017 static clib_error_t *
1018 show_policer_pools_command_fn (vlib_main_t * vm,
1019                                unformat_input_t * input,
1020                                vlib_cli_command_t * cmd)
1021 {
1022   vnet_policer_main_t *pm = &vnet_policer_main;
1023
1024   vlib_cli_output (vm, "pool sizes: configs=%d policers=%d",
1025                    pool_elts (pm->configs), pool_elts (pm->policers));
1026   return 0;
1027 }
1028 VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
1029     .path = "show policer pools",
1030     .short_help = "show policer pools",
1031     .function = show_policer_pools_command_fn,
1032 };
1033
1034 clib_error_t *
1035 policer_init (vlib_main_t * vm)
1036 {
1037   vnet_policer_main_t *pm = &vnet_policer_main;
1038
1039   pm->vlib_main = vm;
1040   pm->vnet_main = vnet_get_main ();
1041   pm->log_class = vlib_log_register_class ("policer", 0);
1042   pm->fq_index[VLIB_RX] =
1043     vlib_frame_queue_main_init (policer_input_node.index, 0);
1044   pm->fq_index[VLIB_TX] =
1045     vlib_frame_queue_main_init (policer_output_node.index, 0);
1046
1047   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
1048   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
1049
1050   vnet_classify_register_unformat_policer_next_index_fn
1051     (unformat_policer_classify_next_index);
1052   vnet_classify_register_unformat_opaque_index_fn
1053     (unformat_policer_classify_precolor);
1054
1055   return 0;
1056 }
1057
1058 VLIB_INIT_FUNCTION (policer_init);
1059
1060
1061
1062 /*
1063  * fd.io coding-style-patch-verification: ON
1064  *
1065  * Local Variables:
1066  * eval: (c-set-style "gnu")
1067  * End:
1068  */