5a7b7711661d2606160180ba46738e3f7f25ec9e
[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 <vnet/policer/policer.h>
17 #include <vnet/classify/vnet_classify.h>
18
19 clib_error_t *
20 policer_add_del (vlib_main_t * vm,
21                  u8 * name,
22                  sse2_qos_pol_cfg_params_st * cfg,
23                  u32 * policer_index, u8 is_add)
24 {
25   vnet_policer_main_t *pm = &vnet_policer_main;
26   policer_read_response_type_st test_policer;
27   policer_read_response_type_st *policer;
28   uword *p;
29   u32 pi;
30   int rv;
31
32   p = hash_get_mem (pm->policer_config_by_name, name);
33
34   if (is_add == 0)
35     {
36       /* free policer config and template */
37       if (p == 0)
38         {
39           vec_free (name);
40           return clib_error_return (0, "No such policer configuration");
41         }
42       pool_put_index (pm->configs, p[0]);
43       pool_put_index (pm->policer_templates, p[0]);
44       hash_unset_mem (pm->policer_config_by_name, name);
45
46       /* free policer */
47       p = hash_get_mem (pm->policer_index_by_name, name);
48       if (p == 0)
49         {
50           vec_free (name);
51           return clib_error_return (0, "No such policer");
52         }
53       pool_put_index (pm->policers, p[0]);
54       hash_unset_mem (pm->policer_index_by_name, name);
55
56       vec_free (name);
57       return 0;
58     }
59
60   if (p != 0)
61     {
62       vec_free (name);
63       return clib_error_return (0, "Policer already exists");
64     }
65
66   /* Vet the configuration before adding it to the table */
67   rv = sse2_pol_logical_2_physical (cfg, &test_policer);
68
69   if (rv == 0)
70     {
71       policer_read_response_type_st *pp;
72       sse2_qos_pol_cfg_params_st *cp;
73
74       pool_get (pm->configs, cp);
75       pool_get (pm->policer_templates, pp);
76
77       ASSERT (cp - pm->configs == pp - pm->policer_templates);
78
79       clib_memcpy (cp, cfg, sizeof (*cp));
80       clib_memcpy (pp, &test_policer, sizeof (*pp));
81
82       hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs);
83       pool_get_aligned (pm->policers, policer, CLIB_CACHE_LINE_BYTES);
84       policer[0] = pp[0];
85       pi = policer - pm->policers;
86       hash_set_mem (pm->policer_index_by_name, name, pi);
87       *policer_index = pi;
88     }
89   else
90     {
91       vec_free (name);
92       return clib_error_return (0, "Config failed sanity check");
93     }
94
95   return 0;
96 }
97
98 u8 *
99 format_policer_instance (u8 * s, va_list * va)
100 {
101   policer_read_response_type_st *i
102     = va_arg (*va, policer_read_response_type_st *);
103
104   s = format (s, "policer at %llx: %s rate, %s color-aware\n",
105               i, i->single_rate ? "single" : "dual",
106               i->color_aware ? "is" : "not");
107   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
108               i->cir_tokens_per_period, i->pir_tokens_per_period, i->scale);
109   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
110               i->current_limit,
111               i->current_bucket, i->extended_limit, i->extended_bucket);
112   s = format (s, "last update %llu\n", i->last_update_time);
113   return s;
114 }
115
116 static u8 *
117 format_policer_round_type (u8 * s, va_list * va)
118 {
119   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
120
121   if (c->rnd_type == SSE2_QOS_ROUND_TO_CLOSEST)
122     s = format (s, "closest");
123   else if (c->rnd_type == SSE2_QOS_ROUND_TO_UP)
124     s = format (s, "up");
125   else if (c->rnd_type == SSE2_QOS_ROUND_TO_DOWN)
126     s = format (s, "down");
127   else
128     s = format (s, "ILLEGAL");
129   return s;
130 }
131
132
133 static u8 *
134 format_policer_rate_type (u8 * s, va_list * va)
135 {
136   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
137
138   if (c->rate_type == SSE2_QOS_RATE_KBPS)
139     s = format (s, "kbps");
140   else if (c->rate_type == SSE2_QOS_RATE_PPS)
141     s = format (s, "pps");
142   else
143     s = format (s, "ILLEGAL");
144   return s;
145 }
146
147 static u8 *
148 format_policer_type (u8 * s, va_list * va)
149 {
150   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
151
152   if (c->rfc == SSE2_QOS_POLICER_TYPE_1R2C)
153     s = format (s, "1r2c");
154
155   else if (c->rfc == SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697)
156     s = format (s, "1r3c");
157
158   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698)
159     s = format (s, "2r3c-2698");
160
161   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115)
162     s = format (s, "2r3c-4115");
163
164   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
165     s = format (s, "2r3c-mef5cf1");
166   else
167     s = format (s, "ILLEGAL");
168   return s;
169 }
170
171 static u8 *
172 format_dscp (u8 * s, va_list * va)
173 {
174   u32 i = va_arg (*va, u32);
175   char *t = 0;
176
177   switch (i)
178     {
179 #define _(v,f,str) case VNET_DSCP_##f: t = str; break;
180       foreach_vnet_dscp
181 #undef _
182     default:
183       return format (s, "ILLEGAL");
184     }
185   s = format (s, "%s", t);
186   return s;
187 }
188
189 static u8 *
190 format_policer_action_type (u8 * s, va_list * va)
191 {
192   sse2_qos_pol_action_params_st *a
193     = va_arg (*va, sse2_qos_pol_action_params_st *);
194
195   if (a->action_type == SSE2_QOS_ACTION_DROP)
196     s = format (s, "drop");
197   else if (a->action_type == SSE2_QOS_ACTION_TRANSMIT)
198     s = format (s, "transmit");
199   else if (a->action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT)
200     s = format (s, "mark-and-transmit %U", format_dscp, a->dscp);
201   else
202     s = format (s, "ILLEGAL");
203   return s;
204 }
205
206 u8 *
207 format_policer_config (u8 * s, va_list * va)
208 {
209   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
210
211   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
212               format_policer_type, c,
213               c->rb.kbps.cir_kbps,
214               c->rb.kbps.eir_kbps, c->rb.kbps.cb_bytes, c->rb.kbps.eb_bytes);
215   s = format (s, "rate type %U, round type %U\n",
216               format_policer_rate_type, c, format_policer_round_type, c);
217   s = format (s, "conform action %U, exceed action %U, violate action %U\n",
218               format_policer_action_type, &c->conform_action,
219               format_policer_action_type, &c->exceed_action,
220               format_policer_action_type, &c->violate_action);
221   return s;
222 }
223
224 static uword
225 unformat_policer_type (unformat_input_t * input, va_list * va)
226 {
227   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
228
229   if (!unformat (input, "type"))
230     return 0;
231
232   if (unformat (input, "1r2c"))
233     c->rfc = SSE2_QOS_POLICER_TYPE_1R2C;
234   else if (unformat (input, "1r3c"))
235     c->rfc = SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697;
236   else if (unformat (input, "2r3c-2698"))
237     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698;
238   else if (unformat (input, "2r3c-4115"))
239     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115;
240   else if (unformat (input, "2r3c-mef5cf1"))
241     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
242   else
243     return 0;
244   return 1;
245 }
246
247 static uword
248 unformat_policer_round_type (unformat_input_t * input, va_list * va)
249 {
250   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
251
252   if (!unformat (input, "round"))
253     return 0;
254
255   if (unformat (input, "closest"))
256     c->rnd_type = SSE2_QOS_ROUND_TO_CLOSEST;
257   else if (unformat (input, "up"))
258     c->rnd_type = SSE2_QOS_ROUND_TO_UP;
259   else if (unformat (input, "down"))
260     c->rnd_type = SSE2_QOS_ROUND_TO_DOWN;
261   else
262     return 0;
263   return 1;
264 }
265
266 static uword
267 unformat_policer_rate_type (unformat_input_t * input, va_list * va)
268 {
269   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
270
271   if (!unformat (input, "rate"))
272     return 0;
273
274   if (unformat (input, "kbps"))
275     c->rate_type = SSE2_QOS_RATE_KBPS;
276   else if (unformat (input, "pps"))
277     c->rate_type = SSE2_QOS_RATE_PPS;
278   else
279     return 0;
280   return 1;
281 }
282
283 static uword
284 unformat_policer_cir (unformat_input_t * input, va_list * va)
285 {
286   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
287
288   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
289     return 1;
290   return 0;
291 }
292
293 static uword
294 unformat_policer_eir (unformat_input_t * input, va_list * va)
295 {
296   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
297
298   if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps))
299     return 1;
300   return 0;
301 }
302
303 static uword
304 unformat_policer_cb (unformat_input_t * input, va_list * va)
305 {
306   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
307
308   if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes))
309     return 1;
310   return 0;
311 }
312
313 static uword
314 unformat_policer_eb (unformat_input_t * input, va_list * va)
315 {
316   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
317
318   if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes))
319     return 1;
320   return 0;
321 }
322
323 static uword
324 unformat_dscp (unformat_input_t * input, va_list * va)
325 {
326   u8 *r = va_arg (*va, u8 *);
327
328   if (0);
329 #define _(v,f,str) else if (unformat (input, str)) *r = VNET_DSCP_##f;
330   foreach_vnet_dscp
331 #undef _
332     else
333     return 0;
334   return 1;
335 }
336
337 static uword
338 unformat_policer_action_type (unformat_input_t * input, va_list * va)
339 {
340   sse2_qos_pol_action_params_st *a
341     = va_arg (*va, sse2_qos_pol_action_params_st *);
342
343   if (unformat (input, "drop"))
344     a->action_type = SSE2_QOS_ACTION_DROP;
345   else if (unformat (input, "transmit"))
346     a->action_type = SSE2_QOS_ACTION_TRANSMIT;
347   else if (unformat (input, "mark-and-transmit %U", unformat_dscp, &a->dscp))
348     a->action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT;
349   else
350     return 0;
351   return 1;
352 }
353
354 static uword
355 unformat_policer_action (unformat_input_t * input, va_list * va)
356 {
357   sse2_qos_pol_cfg_params_st *c = va_arg (*va, sse2_qos_pol_cfg_params_st *);
358
359   if (unformat (input, "conform-action %U", unformat_policer_action_type,
360                 &c->conform_action))
361     return 1;
362   else if (unformat (input, "exceed-action %U", unformat_policer_action_type,
363                      &c->exceed_action))
364     return 1;
365   else if (unformat (input, "violate-action %U", unformat_policer_action_type,
366                      &c->violate_action))
367     return 1;
368   return 0;
369 }
370
371 static uword
372 unformat_policer_classify_next_index (unformat_input_t * input, va_list * va)
373 {
374   u32 *r = va_arg (*va, u32 *);
375   vnet_policer_main_t *pm = &vnet_policer_main;
376   uword *p;
377   u8 *match_name = 0;
378
379   if (unformat (input, "%s", &match_name))
380     ;
381   else
382     return 0;
383
384   p = hash_get_mem (pm->policer_index_by_name, match_name);
385
386   if (p == 0)
387     return 0;
388
389   *r = p[0];
390
391   return 1;
392 }
393
394 static uword
395 unformat_policer_classify_precolor (unformat_input_t * input, va_list * va)
396 {
397   u32 *r = va_arg (*va, u32 *);
398
399   if (unformat (input, "conform-color"))
400     *r = POLICE_CONFORM;
401   else if (unformat (input, "exceed-color"))
402     *r = POLICE_EXCEED;
403   else
404     return 0;
405
406   return 1;
407 }
408
409 #define foreach_config_param                    \
410 _(eb)                                           \
411 _(cb)                                           \
412 _(eir)                                          \
413 _(cir)                                          \
414 _(rate_type)                                    \
415 _(round_type)                                   \
416 _(type)                                         \
417 _(action)
418
419 static clib_error_t *
420 configure_policer_command_fn (vlib_main_t * vm,
421                               unformat_input_t * input,
422                               vlib_cli_command_t * cmd)
423 {
424   sse2_qos_pol_cfg_params_st c;
425   unformat_input_t _line_input, *line_input = &_line_input;
426   u8 is_add = 1;
427   u8 *name = 0;
428   u32 pi;
429   clib_error_t *error = NULL;
430
431   /* Get a line of input. */
432   if (!unformat_user (input, unformat_line_input, line_input))
433     return 0;
434
435   memset (&c, 0, sizeof (c));
436
437   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
438     {
439       if (unformat (line_input, "del"))
440         is_add = 0;
441       else if (unformat (line_input, "name %s", &name))
442         ;
443       else if (unformat (line_input, "color-aware"))
444         c.color_aware = 1;
445
446 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
447       foreach_config_param
448 #undef _
449         else
450         {
451           error = clib_error_return (0, "unknown input `%U'",
452                                      format_unformat_error, line_input);
453           goto done;
454         }
455     }
456
457   error = policer_add_del (vm, name, &c, &pi, is_add);
458
459 done:
460   unformat_free (line_input);
461
462   return error;
463 }
464
465 /* *INDENT-OFF* */
466 VLIB_CLI_COMMAND (configure_policer_command, static) = {
467     .path = "configure policer",
468     .short_help = "configure policer name <name> <params> ",
469     .function = configure_policer_command_fn,
470 };
471 /* *INDENT-ON* */
472
473 static clib_error_t *
474 show_policer_command_fn (vlib_main_t * vm,
475                          unformat_input_t * input, vlib_cli_command_t * cmd)
476 {
477   vnet_policer_main_t *pm = &vnet_policer_main;
478   hash_pair_t *p;
479   u32 pool_index;
480   u8 *match_name = 0;
481   u8 *name;
482   sse2_qos_pol_cfg_params_st *config;
483   policer_read_response_type_st *templ;
484
485   (void) unformat (input, "name %s", &match_name);
486
487   /* *INDENT-OFF* */
488   hash_foreach_pair (p, pm->policer_config_by_name,
489   ({
490     name = (u8 *) p->key;
491     if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
492       {
493         pool_index = p->value[0];
494         config = pool_elt_at_index (pm->configs, pool_index);
495         templ = pool_elt_at_index (pm->policer_templates, pool_index);
496         vlib_cli_output (vm, "Name \"%s\" %U ",
497                          name, format_policer_config, config);
498         vlib_cli_output (vm, "Template %U",
499                          format_policer_instance, templ);
500         vlib_cli_output (vm, "-----------");
501       }
502   }));
503   /* *INDENT-ON* */
504   return 0;
505 }
506
507
508 /* *INDENT-OFF* */
509 VLIB_CLI_COMMAND (show_policer_command, static) = {
510     .path = "show policer",
511     .short_help = "show policer [name]",
512     .function = show_policer_command_fn,
513 };
514 /* *INDENT-ON* */
515
516 static clib_error_t *
517 show_policer_pools_command_fn (vlib_main_t * vm,
518                                unformat_input_t * input,
519                                vlib_cli_command_t * cmd)
520 {
521   vnet_policer_main_t *pm = &vnet_policer_main;
522
523   vlib_cli_output (vm, "pool sizes: configs=%d templates=%d policers=%d",
524                    pool_elts (pm->configs),
525                    pool_elts (pm->policer_templates),
526                    pool_elts (pm->policers));
527   return 0;
528 }
529 /* *INDENT-OFF* */
530 VLIB_CLI_COMMAND (show_policer_pools_command, static) = {
531     .path = "show policer pools",
532     .short_help = "show policer pools",
533     .function = show_policer_pools_command_fn,
534 };
535 /* *INDENT-ON* */
536
537 clib_error_t *
538 policer_init (vlib_main_t * vm)
539 {
540   vnet_policer_main_t *pm = &vnet_policer_main;
541   void vnet_policer_node_funcs_reference (void);
542
543   vnet_policer_node_funcs_reference ();
544
545   pm->vlib_main = vm;
546   pm->vnet_main = vnet_get_main ();
547
548   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
549   pm->policer_index_by_name = hash_create_string (0, sizeof (uword));
550
551   vnet_classify_register_unformat_policer_next_index_fn
552     (unformat_policer_classify_next_index);
553   vnet_classify_register_unformat_opaque_index_fn
554     (unformat_policer_classify_precolor);
555
556   return 0;
557 }
558
559 VLIB_INIT_FUNCTION (policer_init);
560
561
562
563 /*
564  * fd.io coding-style-patch-verification: ON
565  *
566  * Local Variables:
567  * eval: (c-set-style "gnu")
568  * End:
569  */