Return 0 if no tap interfaces are ready
[vpp.git] / vnet / 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
18 clib_error_t *
19 policer_add_del (vlib_main_t *vm,
20                  u8 * name, sse2_qos_pol_cfg_params_st * cfg,
21                  u8 is_add)
22 {
23   vnet_policer_main_t *pm = &vnet_policer_main;
24   policer_read_response_type_st test_policer;
25   uword * p;
26   int rv;
27
28   if (is_add == 0)
29     {
30       p = hash_get_mem (pm->policer_config_by_name, name);
31       if (p == 0)
32         {
33           vec_free(name);
34           return clib_error_return (0, "No such policer configuration");
35         }
36       hash_unset_mem (pm->policer_config_by_name, name);
37       vec_free(name);
38       return 0;
39     }
40
41   /* Vet the configuration before adding it to the table */
42   rv = sse2_pol_logical_2_physical (cfg, &test_policer);
43
44   if (rv == 0)
45     {
46       policer_read_response_type_st *pp;
47       sse2_qos_pol_cfg_params_st *cp;
48
49       pool_get (pm->configs, cp);
50       pool_get (pm->policer_templates, pp);
51
52       ASSERT (cp - pm->configs == pp - pm->policer_templates);
53
54       clib_memcpy (cp, cfg, sizeof (*cp));
55       clib_memcpy (pp, &test_policer, sizeof (*pp));
56
57       hash_set_mem (pm->policer_config_by_name, name, cp - pm->configs);
58     }
59   else
60     {
61       vec_free (name);
62       return clib_error_return (0, "Config failed sanity check");
63     }
64
65   return 0;
66 }
67
68 u8 * format_policer_instance (u8 * s, va_list * va)
69 {
70   policer_read_response_type_st * i 
71     = va_arg (*va, policer_read_response_type_st *);
72
73   s = format (s, "policer at %llx: %s rate, %s color-aware\n", 
74               i, i->single_rate ? "single" : "dual",
75               i->color_aware ? "is" : "not");
76   s = format (s, "cir %u tok/period, pir %u tok/period, scale %u\n",
77               i->cir_tokens_per_period, i->pir_tokens_per_period, 
78               i->scale);
79   s = format (s, "cur lim %u, cur bkt %u, ext lim %u, ext bkt %u\n",
80               i->current_limit,
81               i->current_bucket,
82               i->extended_limit,
83               i->extended_bucket);
84   s = format (s, "last update %llu\n", i->last_update_time);
85   return s;
86 }              
87
88 static u8 * format_policer_round_type (u8 * s, va_list * va)
89 {
90   sse2_qos_pol_cfg_params_st * c 
91     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
92
93   if (c->rnd_type == SSE2_QOS_ROUND_TO_CLOSEST)
94     s = format(s, "closest");
95   else if (c->rnd_type == SSE2_QOS_ROUND_TO_UP)
96     s = format (s, "up");
97   else if (c->rnd_type == SSE2_QOS_ROUND_TO_DOWN)
98     s = format (s, "down");
99   else
100     s = format (s, "ILLEGAL");
101   return s;
102 }
103
104
105 static u8 * format_policer_rate_type (u8 * s, va_list * va)
106 {
107   sse2_qos_pol_cfg_params_st * c 
108     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
109
110   if (c->rate_type == SSE2_QOS_RATE_KBPS)
111     s = format (s, "kbps");
112   else if (c->rate_type == SSE2_QOS_RATE_PPS)
113     s = format(s, "pps");
114   else
115     s = format (s, "ILLEGAL");
116   return s;
117 }
118
119 static u8 * format_policer_type (u8 * s, va_list * va)
120 {
121   sse2_qos_pol_cfg_params_st * c 
122     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
123   
124   if (c->rfc == SSE2_QOS_POLICER_TYPE_1R2C)
125     s = format (s, "1r2c");
126       
127   else if (c->rfc == SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697)
128     s = format (s, "1r3c");
129
130   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698)
131     s = format (s, "2r3c-2698");
132
133   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115)
134     s = format (s, "2r3c-4115");
135
136   else if (c->rfc == SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1)
137     s = format (s, "2r3c-mef5cf1");
138   else
139     s = format (s, "ILLEGAL");
140   return s;
141 }
142
143 u8 * format_policer_config (u8 * s, va_list * va)
144 {
145   sse2_qos_pol_cfg_params_st * c 
146     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
147
148   s = format (s, "type %U cir %u eir %u cb %u eb %u\n",
149               format_policer_type, c, 
150               c->rb.kbps.cir_kbps,
151               c->rb.kbps.eir_kbps,
152               c->rb.kbps.cb_bytes,
153               c->rb.kbps.eb_bytes);
154   s = format (s, "rate type %U, round type %U\n",
155               format_policer_rate_type, c,
156               format_policer_round_type, c);
157   return s;
158 }
159
160 static uword
161 unformat_policer_type (unformat_input_t * input, va_list * va)
162 {
163   sse2_qos_pol_cfg_params_st * c 
164     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
165
166   if (!unformat (input, "type"))
167     return 0;
168
169   if (unformat (input, "1r2c"))
170     c->rfc = SSE2_QOS_POLICER_TYPE_1R2C;
171   else if (unformat (input, "1r3c"))
172     c->rfc = SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697;
173   else if (unformat (input, "2r3c-2698"))
174     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698;
175   else if (unformat (input, "2r3c-4115"))
176     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115;
177   else if (unformat (input, "2r3c-mef5cf1"))
178     c->rfc = SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1;
179   else
180     return 0;
181   return 1;
182 }
183
184 static uword
185 unformat_policer_round_type (unformat_input_t * input, va_list * va)
186 {
187   sse2_qos_pol_cfg_params_st * c 
188     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
189
190   if (!unformat(input, "round"))
191     return 0;
192
193   if (unformat(input, "closest"))
194     c->rnd_type = SSE2_QOS_ROUND_TO_CLOSEST;
195   else if (unformat (input, "up"))
196     c->rnd_type = SSE2_QOS_ROUND_TO_UP;
197   else if (unformat (input, "down"))
198     c->rnd_type = SSE2_QOS_ROUND_TO_DOWN;
199   else
200     return 0;
201   return 1;
202 }
203
204 static uword
205 unformat_policer_rate_type (unformat_input_t * input, va_list * va)
206 {
207   sse2_qos_pol_cfg_params_st * c 
208     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
209
210   if (!unformat(input, "rate"))
211     return 0;
212
213   if (unformat (input, "kbps"))
214     c->rate_type = SSE2_QOS_RATE_KBPS;
215   else if (unformat(input, "pps"))
216     c->rate_type = SSE2_QOS_RATE_PPS;
217   else
218     return 0;
219   return 1;
220 }
221
222 static uword
223 unformat_policer_cir (unformat_input_t * input, va_list * va)
224 {
225   sse2_qos_pol_cfg_params_st * c 
226     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
227
228   if (unformat (input, "cir %u", &c->rb.kbps.cir_kbps))
229     return 1;
230   return 0;
231 }
232
233 static uword
234 unformat_policer_eir (unformat_input_t * input, va_list * va)
235 {
236   sse2_qos_pol_cfg_params_st * c 
237     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
238
239   if (unformat (input, "eir %u", &c->rb.kbps.eir_kbps))
240     return 1;
241   return 0;
242 }
243
244 static uword
245 unformat_policer_cb (unformat_input_t * input, va_list * va)
246 {
247   sse2_qos_pol_cfg_params_st * c 
248     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
249
250   if (unformat (input, "cb %u", &c->rb.kbps.cb_bytes))
251     return 1;
252   return 0;
253 }
254
255 static uword
256 unformat_policer_eb (unformat_input_t * input, va_list * va)
257 {
258   sse2_qos_pol_cfg_params_st * c 
259     = va_arg (*va, sse2_qos_pol_cfg_params_st *);
260
261   if (unformat (input, "eb %u", &c->rb.kbps.eb_bytes))
262     return 1;
263   return 0;
264 }
265
266
267 #define foreach_config_param                    \
268 _(eb)                                           \
269 _(cb)                                           \
270 _(eir)                                          \
271 _(cir)                                          \
272 _(rate_type)                                    \
273 _(round_type)                                   \
274 _(type)
275
276 static clib_error_t *
277 configure_policer_command_fn (vlib_main_t * vm,
278                               unformat_input_t * input,
279                               vlib_cli_command_t * cmd)
280 {
281   sse2_qos_pol_cfg_params_st c;
282   unformat_input_t _line_input, * line_input = &_line_input;
283   u8 is_add = 1;
284   u8 * name = 0;
285
286   /* Get a line of input. */
287   if (! unformat_user (input, unformat_line_input, line_input))
288     return 0;
289
290   memset (&c, 0, sizeof (c));
291
292   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) 
293     {
294       if (unformat (line_input, "del"))
295         is_add = 0;
296       else if (unformat(line_input, "name %s", &name))
297         ;
298
299 #define _(a) else if (unformat (line_input, "%U", unformat_policer_##a, &c)) ;
300       foreach_config_param
301 #undef _
302
303       else
304         return clib_error_return (0, "unknown input `%U'",
305                                   format_unformat_error, line_input);
306     }
307
308   unformat_free (line_input);
309
310   return policer_add_del(vm, name, &c, is_add);
311 }
312
313 VLIB_CLI_COMMAND (configure_policer_command, static) = {
314     .path = "configure policer",
315     .short_help = "configure policer name <name> <params> ",
316     .function = configure_policer_command_fn,
317 };
318
319
320 static clib_error_t *
321 show_policer_command_fn (vlib_main_t * vm,
322                               unformat_input_t * input,
323                               vlib_cli_command_t * cmd)
324 {
325   vnet_policer_main_t *pm = &vnet_policer_main;
326   hash_pair_t * p;
327   u32 pool_index;
328   u8 * match_name = 0;
329   u8 * name;
330   sse2_qos_pol_cfg_params_st *config;
331   policer_read_response_type_st *templ;
332
333   (void) unformat (input, "name %s", &match_name);
334
335   hash_foreach_pair (p, pm->policer_config_by_name,
336   ({
337     name = (u8 *) p->key;
338     if (match_name == 0 || !strcmp((char *) name, (char *) match_name))
339       {
340         pool_index = p->value[0];
341         config = pool_elt_at_index (pm->configs, pool_index);
342         templ = pool_elt_at_index (pm->policer_templates, pool_index);
343         vlib_cli_output (vm, "Name \"%s\" %U ", 
344                          name, format_policer_config, config);
345         vlib_cli_output (vm, "Template %U", 
346                          format_policer_instance, templ);
347         vlib_cli_output (vm, "-----------");
348       }
349   }));
350   return 0;
351 }
352
353
354 VLIB_CLI_COMMAND (show_policer_command, static) = {
355     .path = "show policer",
356     .short_help = "show policer [name]",
357     .function = show_policer_command_fn,
358 };
359
360 clib_error_t *policer_init (vlib_main_t * vm)
361 {
362   vnet_policer_main_t * pm = &vnet_policer_main;
363   void vnet_policer_node_funcs_reference(void);
364
365   vnet_policer_node_funcs_reference();
366   
367   pm->vlib_main = vm;
368   pm->vnet_main = vnet_get_main();
369
370   pm->policer_config_by_name = hash_create_string (0, sizeof (uword));
371   return 0;
372 }
373
374 VLIB_INIT_FUNCTION(policer_init);
375
376