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