1f46285aa212fb3ad3f65d5163d10431126647b1
[vpp.git] / vnet / vnet / feature / feature.c
1 /*
2  * Copyright (c) 2016 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
16 #include <vnet/feature/feature.h>
17
18 vnet_feature_main_t feature_main;
19
20 static clib_error_t *
21 vnet_feature_init (vlib_main_t * vm)
22 {
23   vnet_feature_main_t *fm = &feature_main;
24   vnet_feature_registration_t *freg;
25   vnet_feature_arc_registration_t *areg;
26   u32 arc_index = 0;
27
28   fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
29   areg = fm->next_arc;
30
31   /* process feature arc registrations */
32   while (areg)
33     {
34       char *s;
35       int i = 0;
36       areg->feature_arc_index = arc_index;
37       if (areg->arc_index_ptr)
38         *areg->arc_index_ptr = arc_index;
39       hash_set_mem (fm->arc_index_by_name, areg->arc_name,
40                     pointer_to_uword (areg));
41
42       /* process start nodes */
43       while ((s = areg->start_nodes[i]))
44         {
45           i++;
46         }
47       areg->n_start_nodes = i;
48
49       /* next */
50       areg = areg->next;
51       arc_index++;
52     }
53
54   vec_validate (fm->next_feature_by_arc, arc_index - 1);
55   vec_validate (fm->feature_nodes, arc_index - 1);
56   vec_validate (fm->feature_config_mains, arc_index - 1);
57   vec_validate (fm->next_feature_by_name, arc_index - 1);
58   vec_validate (fm->sw_if_index_has_features, arc_index - 1);
59   vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
60
61   freg = fm->next_feature;
62   while (freg)
63     {
64       vnet_feature_registration_t *next;
65       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
66       if (p == 0)
67         return clib_error_return (0, "Unknown feature arc '%s'",
68                                   freg->arc_name);
69
70       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
71       arc_index = areg->feature_arc_index;
72
73       next = freg->next;
74       freg->next = fm->next_feature_by_arc[arc_index];
75       fm->next_feature_by_arc[arc_index] = freg;
76
77       /* next */
78       freg = next;
79     }
80
81   areg = fm->next_arc;
82   while (areg)
83     {
84       clib_error_t *error;
85       vnet_feature_config_main_t *cm;
86       vnet_config_main_t *vcm;
87
88       arc_index = areg->feature_arc_index;
89       cm = &fm->feature_config_mains[arc_index];
90       vcm = &cm->config_main;
91       if ((error = vnet_feature_arc_init (vm, vcm,
92                                           areg->start_nodes,
93                                           areg->n_start_nodes,
94                                           fm->next_feature_by_arc[arc_index],
95                                           &fm->feature_nodes[arc_index])))
96         {
97           return error;
98         }
99
100       fm->next_feature_by_name[arc_index] =
101         hash_create_string (0, sizeof (uword));
102       freg = fm->next_feature_by_arc[arc_index];
103
104       while (freg)
105         {
106           hash_set_mem (fm->next_feature_by_name[arc_index],
107                         freg->node_name, pointer_to_uword (freg));
108           freg = freg->next;
109         }
110
111       /* next */
112       areg = areg->next;
113       arc_index++;
114     }
115
116   return 0;
117 }
118
119 VLIB_INIT_FUNCTION (vnet_feature_init);
120
121 void
122 vnet_config_update_feature_count (vnet_feature_main_t * fm, u8 arc,
123                                   u32 sw_if_index, int is_add)
124 {
125   uword bit_value;
126
127   vec_validate (fm->feature_count_by_sw_if_index[arc], sw_if_index);
128
129   fm->feature_count_by_sw_if_index[arc][sw_if_index] += is_add ? 1 : -1;
130
131   ASSERT (fm->feature_count_by_sw_if_index[arc][sw_if_index] >= 0);
132
133   bit_value = fm->feature_count_by_sw_if_index[arc][sw_if_index] > 0;
134
135   fm->sw_if_index_has_features[arc] =
136     clib_bitmap_set (fm->sw_if_index_has_features[arc], sw_if_index,
137                      bit_value);
138 }
139
140 u8
141 vnet_get_feature_arc_index (const char *s)
142 {
143   vnet_feature_main_t *fm = &feature_main;
144   vnet_feature_arc_registration_t *reg;
145   uword *p;
146
147   p = hash_get_mem (fm->arc_index_by_name, s);
148   if (p == 0)
149     return ~0;
150
151   reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
152   return reg->feature_arc_index;
153 }
154
155 u32
156 vnet_get_feature_index (u8 arc, const char *s)
157 {
158   vnet_feature_main_t *fm = &feature_main;
159   vnet_feature_registration_t *reg;
160   uword *p;
161
162   p = hash_get_mem (fm->next_feature_by_name[arc], s);
163   if (p == 0)
164     return ~0;
165
166   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
167   return reg->feature_index;
168 }
169
170 int
171 vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
172                                         u32 sw_if_index, int enable_disable,
173                                         void *feature_config,
174                                         u32 n_feature_config_bytes)
175 {
176   vnet_feature_main_t *fm = &feature_main;
177   vnet_feature_config_main_t *cm;
178   u32 ci;
179
180   if (arc_index == (u8) ~ 0)
181     return VNET_API_ERROR_INVALID_VALUE;
182
183   if (feature_index == ~0)
184     return VNET_API_ERROR_INVALID_VALUE_2;
185
186   cm = &fm->feature_config_mains[arc_index];
187   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
188   ci = cm->config_index_by_sw_if_index[sw_if_index];
189
190   ci = (enable_disable
191         ? vnet_config_add_feature
192         : vnet_config_del_feature)
193     (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
194      n_feature_config_bytes);
195   cm->config_index_by_sw_if_index[sw_if_index] = ci;
196
197   vnet_config_update_feature_count (fm, arc_index, sw_if_index,
198                                     enable_disable);
199
200   return 0;
201 }
202
203 int
204 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
205                              u32 sw_if_index, int enable_disable,
206                              void *feature_config, u32 n_feature_config_bytes)
207 {
208   u32 feature_index;
209   u8 arc_index;
210
211   arc_index = vnet_get_feature_arc_index (arc_name);
212
213   if (arc_index == (u8) ~ 0)
214     return VNET_API_ERROR_INVALID_VALUE;
215
216   feature_index = vnet_get_feature_index (arc_index, node_name);
217
218   return vnet_feature_enable_disable_with_index (arc_index, feature_index,
219                                                  sw_if_index, enable_disable,
220                                                  feature_config,
221                                                  n_feature_config_bytes);
222 }
223
224
225 /** Display the set of available driver features.
226     Useful for verifying that expected features are present
227 */
228
229 static clib_error_t *
230 show_features_command_fn (vlib_main_t * vm,
231                           unformat_input_t * input, vlib_cli_command_t * cmd)
232 {
233   vnet_feature_main_t *fm = &feature_main;
234   vnet_feature_arc_registration_t *areg;
235   vnet_feature_registration_t *freg;
236
237   vlib_cli_output (vm, "Available feature paths");
238
239   areg = fm->next_arc;
240   while (areg)
241     {
242       vlib_cli_output (vm, "%s:", areg->arc_name);
243       freg = fm->next_feature_by_arc[areg->feature_arc_index];
244       while (freg)
245         {
246           vlib_cli_output (vm, "  %s\n", freg->node_name);
247           freg = freg->next;
248         }
249
250
251       /* next */
252       areg = areg->next;
253     }
254
255   return 0;
256 }
257
258 /*?
259  * Display the set of available driver features
260  *
261  * @cliexpar
262  * Example:
263  * @cliexcmd{show ip features}
264  * @cliexend
265  * @endparblock
266 ?*/
267 /* *INDENT-OFF* */
268 VLIB_CLI_COMMAND (show_features_command, static) = {
269   .path = "show features",
270   .short_help = "show features",
271   .function = show_features_command_fn,
272 };
273 /* *INDENT-ON* */
274
275 /** Display the set of driver features configured on a specific interface
276   * Called by "show interface" handler
277  */
278
279 void
280 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index)
281 {
282   vnet_feature_main_t *fm = &feature_main;
283   u32 node_index, current_config_index;
284   u16 feature_arc;
285   vnet_feature_config_main_t *cm = fm->feature_config_mains;
286   vnet_feature_arc_registration_t *areg;
287   vnet_config_main_t *vcm;
288   vnet_config_t *cfg;
289   u32 cfg_index;
290   vnet_config_feature_t *feat;
291   vlib_node_t *n;
292   int i;
293
294   vlib_cli_output (vm, "Driver feature paths configured on %U...",
295                    format_vnet_sw_if_index_name,
296                    vnet_get_main (), sw_if_index);
297
298   areg = fm->next_arc;
299   while (areg)
300     {
301       feature_arc = areg->feature_arc_index;
302       vcm = &(cm[feature_arc].config_main);
303
304       vlib_cli_output (vm, "\n%s:", areg->arc_name);
305       areg = areg->next;
306
307       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
308           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
309           sw_if_index)
310         {
311           vlib_cli_output (vm, "  none configured");
312           continue;
313         }
314
315       current_config_index =
316         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
317
318       if (current_config_index == ~0)
319         {
320           vlib_cli_output (vm, "  none configured");
321           continue;
322         }
323
324       ASSERT (current_config_index
325               < vec_len (vcm->config_pool_index_by_user_index));
326
327       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
328       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
329
330       for (i = 0; i < vec_len (cfg->features); i++)
331         {
332           feat = cfg->features + i;
333           node_index = feat->node_index;
334           n = vlib_get_node (vm, node_index);
335           vlib_cli_output (vm, "  %v", n->name);
336         }
337     }
338 }
339
340 /*
341  * fd.io coding-style-patch-verification: ON
342  *
343  * Local Variables:
344  * eval: (c-set-style "gnu")
345  * End:
346  */