QoS recording and marking
[vpp.git] / src / vnet / qos / qos_egress_map.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2018 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <vnet/qos/qos_egress_map.h>
19 #include <vnet/qos/qos_mark.h>
20
21 /**
22  * Pool from which to allocate table
23  */
24 qos_egress_map_t *qem_pool;
25
26 /**
27  * DB to map user table-IDs to internal table indicies.
28  */
29 uword *qem_db;
30
31 index_t
32 qos_egress_map_find (qos_egress_map_id_t mid)
33 {
34   uword *p = NULL;
35
36   p = hash_get (qem_db, mid);
37
38   if (NULL != p)
39     return p[0];
40
41   return (INDEX_INVALID);
42 }
43
44 qos_egress_map_t *
45 qos_egress_map_find_i (qos_egress_map_id_t mid)
46 {
47   index_t qemi;
48
49   qemi = qos_egress_map_find (mid);
50
51   if (INDEX_INVALID != qemi)
52     {
53       return (pool_elt_at_index (qem_pool, qemi));
54     }
55
56   return (NULL);
57 }
58
59 static qos_egress_map_t *
60 qos_egress_map_find_or_create (qos_egress_map_id_t mid)
61 {
62   qos_egress_map_t *qem;
63
64   /*
65    * Find the existing or create a new table
66    */
67   qem = qos_egress_map_find_i (mid);
68
69   if (NULL == qem)
70     {
71       index_t qemi;
72
73       pool_get_aligned (qem_pool, qem, CLIB_CACHE_LINE_BYTES);
74       qemi = qem - qem_pool;
75
76       memset (qem, 0, sizeof (*qem));
77       hash_set (qem_db, mid, qemi);
78     }
79
80   return (qem);
81 }
82
83 void
84 qos_egress_map_update (qos_egress_map_id_t mid,
85                        qos_source_t input_source, qos_bits_t * values)
86 {
87   qos_egress_map_t *qem;
88
89   qem = qos_egress_map_find_or_create (mid);
90
91   clib_memcpy (qem->qem_output[input_source],
92                values, sizeof (qem->qem_output[input_source]));
93 }
94
95 void
96 qos_egress_map_delete (qos_egress_map_id_t mid)
97 {
98   qos_egress_map_t *qem;
99
100   qem = qos_egress_map_find_i (mid);
101   hash_unset (qem_db, mid);
102
103   if (NULL != qem)
104     {
105       pool_put (qem_pool, qem);
106     }
107 }
108
109 static clib_error_t *
110 qos_egress_map_update_cli (vlib_main_t * vm,
111                            unformat_input_t * input, vlib_cli_command_t * cmd)
112 {
113   qos_egress_map_id_t map_id;
114   qos_egress_map_t *qem;
115   u8 add;
116
117   add = 1;
118   map_id = ~0;
119   qem = NULL;
120
121   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
122     {
123       if (unformat (input, "delete") || unformat (input, "del"))
124         add = 0;
125       else if (unformat (input, "id %d", &map_id))
126         qem = qos_egress_map_find_or_create (map_id);
127       else
128         {
129           int qs, qi, qo;
130
131           if (NULL == qem)
132             return clib_error_return (0, "map-id must be specified");
133
134           while (unformat
135                  (input, "[%U][%d]=%d", unformat_qos_source, &qs, &qi, &qo))
136             qem->qem_output[qs][qi] = qo;
137           break;
138         }
139     }
140
141   if (!add)
142     qos_egress_map_delete (map_id);
143
144   return (NULL);
145 }
146
147 /*?
148  * Update a Egress Qos Map table
149  *
150  * @cliexpar
151  * @cliexcmd{qos egress map id 0 [ip][4]=4}
152  ?*/
153 /* *INDENT-OFF* */
154 VLIB_CLI_COMMAND (qos_egress_map_update_command, static) = {
155   .path = "qos egress map",
156   .short_help = "qos egress map id %d [delete] {[SOURCE][INPUT]=OUTPUT}",
157   .function = qos_egress_map_update_cli,
158   .is_mp_safe = 1,
159 };
160 /* *INDENT-ON* */
161
162 u8 *
163 format_qos_egress_map (u8 * s, va_list * args)
164 {
165   qos_egress_map_t *qem = va_arg (*args, qos_egress_map_t *);
166   u32 indent = va_arg (*args, u32);
167   int qs;
168   u32 ii;
169
170   FOR_EACH_QOS_SOURCE (qs)
171   {
172     s = format (s, "%U%U:[",
173                 format_white_space, indent, format_qos_source, qs);
174
175     for (ii = 0; ii < ARRAY_LEN (qem->qem_output[qs]) - 1; ii++)
176       {
177         s = format (s, "%d,", qem->qem_output[qs][ii]);
178       }
179     s = format (s, "%d]\n", qem->qem_output[qs][ii]);
180   }
181
182   return (s);
183 }
184
185 static clib_error_t *
186 qos_egress_map_show (vlib_main_t * vm,
187                      unformat_input_t * input, vlib_cli_command_t * cmd)
188 {
189   qos_egress_map_id_t map_id;
190   qos_egress_map_t *qem;
191   clib_error_t *error;
192
193   map_id = ~0;
194   qem = NULL;
195   error = NULL;
196
197   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
198     {
199       if (unformat (input, "id %d", &map_id))
200         ;
201       else
202         {
203           error = unformat_parse_error (input);
204           goto done;
205         }
206     }
207
208   if (~0 == map_id)
209     {
210       index_t qemi;
211
212       /* *INDENT-OFF* */
213       hash_foreach(map_id, qemi, qem_db,
214       ({
215           vlib_cli_output (vm, " Map-ID:%d\n%U",
216                            map_id,
217                            format_qos_egress_map,
218                            pool_elt_at_index(qem_pool, qemi), 2);
219       }));
220       /* *INDENT-ON* */
221     }
222   else
223     {
224       qem = qos_egress_map_find_i (map_id);
225
226       if (NULL == qem)
227         {
228           error = clib_error_return (0, "No Map for ID %d", map_id);
229         }
230       else
231         {
232           vlib_cli_output (vm, " Map-ID:%d\n%U",
233                            map_id, format_qos_egress_map, qem, 2);
234         }
235     }
236
237 done:
238   return (error);
239 }
240
241 /*?
242  * Show Egress Qos Maps
243  *
244  * @cliexpar
245  * @cliexcmd{show qos egress map}
246  ?*/
247 /* *INDENT-OFF* */
248 VLIB_CLI_COMMAND (qos_egress_map_show_command, static) = {
249   .path = "show qos egress map",
250   .short_help = "show qos egress map id %d",
251   .function = qos_egress_map_show,
252   .is_mp_safe = 1,
253 };
254 /* *INDENT-ON* */
255
256 /*
257  * fd.io coding-style-patch-verification: ON
258  *
259  * Local Variables:
260  * eval: (c-set-style "gnu")
261  * End:
262  */