714e20e8e725a0de6fa874c5a5fdb29cce90aca7
[vpp.git] / src / 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 #include <vnet/adj/adj.h>
18
19 vnet_feature_main_t feature_main;
20
21 static clib_error_t *
22 vnet_feature_init (vlib_main_t * vm)
23 {
24   vnet_feature_main_t *fm = &feature_main;
25   vnet_feature_registration_t *freg;
26   vnet_feature_arc_registration_t *areg;
27   u32 arc_index = 0;
28
29   fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
30   areg = fm->next_arc;
31
32   /* process feature arc registrations */
33   while (areg)
34     {
35       char *s;
36       int i = 0;
37       areg->feature_arc_index = arc_index;
38       if (areg->arc_index_ptr)
39         *areg->arc_index_ptr = arc_index;
40       hash_set_mem (fm->arc_index_by_name, areg->arc_name,
41                     pointer_to_uword (areg));
42
43       /* process start nodes */
44       while ((s = areg->start_nodes[i]))
45         {
46           i++;
47         }
48       areg->n_start_nodes = i;
49
50       /* next */
51       areg = areg->next;
52       arc_index++;
53     }
54
55   vec_validate (fm->next_feature_by_arc, arc_index - 1);
56   vec_validate (fm->feature_nodes, arc_index - 1);
57   vec_validate (fm->feature_config_mains, arc_index - 1);
58   vec_validate (fm->next_feature_by_name, arc_index - 1);
59   vec_validate (fm->sw_if_index_has_features, arc_index - 1);
60   vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
61
62   freg = fm->next_feature;
63   while (freg)
64     {
65       vnet_feature_registration_t *next;
66       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
67       if (p == 0)
68         {
69           /* Don't start vpp with broken features arcs */
70           clib_warning ("Unknown feature arc '%s'", freg->arc_name);
71           os_exit (1);
72         }
73
74       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
75       arc_index = areg->feature_arc_index;
76
77       next = freg->next;
78       freg->next_in_arc = fm->next_feature_by_arc[arc_index];
79       fm->next_feature_by_arc[arc_index] = freg;
80
81       /* next */
82       freg = next;
83     }
84
85   areg = fm->next_arc;
86   while (areg)
87     {
88       clib_error_t *error;
89       vnet_feature_config_main_t *cm;
90       vnet_config_main_t *vcm;
91
92       arc_index = areg->feature_arc_index;
93       cm = &fm->feature_config_mains[arc_index];
94       vcm = &cm->config_main;
95       if ((error = vnet_feature_arc_init (vm, vcm,
96                                           areg->start_nodes,
97                                           areg->n_start_nodes,
98                                           fm->next_feature_by_arc[arc_index],
99                                           &fm->feature_nodes[arc_index])))
100         {
101           clib_error_report (error);
102           os_exit (1);
103         }
104
105       fm->next_feature_by_name[arc_index] =
106         hash_create_string (0, sizeof (uword));
107       freg = fm->next_feature_by_arc[arc_index];
108
109       while (freg)
110         {
111           hash_set_mem (fm->next_feature_by_name[arc_index],
112                         freg->node_name, pointer_to_uword (freg));
113           freg = freg->next_in_arc;
114         }
115
116       /* next */
117       areg = areg->next;
118       arc_index++;
119     }
120
121   return 0;
122 }
123
124 VLIB_INIT_FUNCTION (vnet_feature_init);
125
126 u8
127 vnet_get_feature_arc_index (const char *s)
128 {
129   vnet_feature_main_t *fm = &feature_main;
130   vnet_feature_arc_registration_t *reg;
131   uword *p;
132
133   p = hash_get_mem (fm->arc_index_by_name, s);
134   if (p == 0)
135     return ~0;
136
137   reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
138   return reg->feature_arc_index;
139 }
140
141 vnet_feature_registration_t *
142 vnet_get_feature_reg (const char *arc_name, const char *node_name)
143 {
144   u8 arc_index;
145
146   arc_index = vnet_get_feature_arc_index (arc_name);
147   if (arc_index == (u8) ~ 0)
148     return 0;
149
150   vnet_feature_main_t *fm = &feature_main;
151   vnet_feature_registration_t *reg;
152   uword *p;
153
154   p = hash_get_mem (fm->next_feature_by_name[arc_index], node_name);
155   if (p == 0)
156     return 0;
157
158   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
159   return reg;
160 }
161
162 u32
163 vnet_get_feature_index (u8 arc, const char *s)
164 {
165   vnet_feature_main_t *fm = &feature_main;
166   vnet_feature_registration_t *reg;
167   uword *p;
168
169   if (s == 0)
170     return ~0;
171
172   p = hash_get_mem (fm->next_feature_by_name[arc], s);
173   if (p == 0)
174     return ~0;
175
176   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
177   return reg->feature_index;
178 }
179
180 int
181 vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
182                                         u32 sw_if_index, int enable_disable,
183                                         void *feature_config,
184                                         u32 n_feature_config_bytes)
185 {
186   vnet_feature_main_t *fm = &feature_main;
187   vnet_feature_config_main_t *cm;
188   i16 feature_count;
189   u32 ci;
190
191   if (arc_index == (u8) ~ 0)
192     return VNET_API_ERROR_INVALID_VALUE;
193
194   if (feature_index == ~0)
195     return VNET_API_ERROR_INVALID_VALUE_2;
196
197   cm = &fm->feature_config_mains[arc_index];
198   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
199   ci = cm->config_index_by_sw_if_index[sw_if_index];
200
201   vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
202   feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
203
204   if (!enable_disable && feature_count < 1)
205     return 0;
206
207   ci = (enable_disable
208         ? vnet_config_add_feature
209         : vnet_config_del_feature)
210     (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
211      n_feature_config_bytes);
212   if (ci == ~0)
213     {
214       return 0;
215     }
216   cm->config_index_by_sw_if_index[sw_if_index] = ci;
217
218   /* update feature count */
219   enable_disable = (enable_disable > 0);
220   feature_count += enable_disable ? 1 : -1;
221   ASSERT (feature_count >= 0);
222
223   fm->sw_if_index_has_features[arc_index] =
224     clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
225                      (feature_count > 0));
226   adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
227
228   fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
229   return 0;
230 }
231
232 int
233 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
234                              u32 sw_if_index, int enable_disable,
235                              void *feature_config, u32 n_feature_config_bytes)
236 {
237   u32 feature_index;
238   u8 arc_index;
239
240   arc_index = vnet_get_feature_arc_index (arc_name);
241
242   if (arc_index == (u8) ~ 0)
243     return VNET_API_ERROR_INVALID_VALUE;
244
245   feature_index = vnet_get_feature_index (arc_index, node_name);
246
247   return vnet_feature_enable_disable_with_index (arc_index, feature_index,
248                                                  sw_if_index, enable_disable,
249                                                  feature_config,
250                                                  n_feature_config_bytes);
251 }
252
253
254 /** Display the set of available driver features.
255     Useful for verifying that expected features are present
256 */
257
258 static clib_error_t *
259 show_features_command_fn (vlib_main_t * vm,
260                           unformat_input_t * input, vlib_cli_command_t * cmd)
261 {
262   vnet_feature_main_t *fm = &feature_main;
263   vnet_feature_arc_registration_t *areg;
264   vnet_feature_registration_t *freg;
265
266   vlib_cli_output (vm, "Available feature paths");
267
268   areg = fm->next_arc;
269   while (areg)
270     {
271       vlib_cli_output (vm, "%s:", areg->arc_name);
272       freg = fm->next_feature_by_arc[areg->feature_arc_index];
273       while (freg)
274         {
275           vlib_cli_output (vm, "  %s\n", freg->node_name);
276           freg = freg->next_in_arc;
277         }
278
279
280       /* next */
281       areg = areg->next;
282     }
283
284   return 0;
285 }
286
287 /*?
288  * Display the set of available driver features
289  *
290  * @cliexpar
291  * Example:
292  * @cliexcmd{show ip features}
293  * @cliexend
294  * @endparblock
295 ?*/
296 /* *INDENT-OFF* */
297 VLIB_CLI_COMMAND (show_features_command, static) = {
298   .path = "show features",
299   .short_help = "show features",
300   .function = show_features_command_fn,
301 };
302 /* *INDENT-ON* */
303
304 /** Display the set of driver features configured on a specific interface
305   * Called by "show interface" handler
306  */
307
308 void
309 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index)
310 {
311   vnet_feature_main_t *fm = &feature_main;
312   u32 node_index, current_config_index;
313   u16 feature_arc;
314   vnet_feature_config_main_t *cm = fm->feature_config_mains;
315   vnet_feature_arc_registration_t *areg;
316   vnet_config_main_t *vcm;
317   vnet_config_t *cfg;
318   u32 cfg_index;
319   vnet_config_feature_t *feat;
320   vlib_node_t *n;
321   int i;
322
323   vlib_cli_output (vm, "Driver feature paths configured on %U...",
324                    format_vnet_sw_if_index_name,
325                    vnet_get_main (), sw_if_index);
326
327   areg = fm->next_arc;
328   while (areg)
329     {
330       feature_arc = areg->feature_arc_index;
331       vcm = &(cm[feature_arc].config_main);
332
333       vlib_cli_output (vm, "\n%s:", areg->arc_name);
334       areg = areg->next;
335
336       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
337           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
338           sw_if_index)
339         {
340           vlib_cli_output (vm, "  none configured");
341           continue;
342         }
343
344       current_config_index =
345         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
346
347       if (current_config_index == ~0)
348         {
349           vlib_cli_output (vm, "  none configured");
350           continue;
351         }
352
353       ASSERT (current_config_index
354               < vec_len (vcm->config_pool_index_by_user_index));
355
356       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
357       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
358
359       for (i = 0; i < vec_len (cfg->features); i++)
360         {
361           feat = cfg->features + i;
362           node_index = feat->node_index;
363           n = vlib_get_node (vm, node_index);
364           vlib_cli_output (vm, "  %v", n->name);
365         }
366     }
367 }
368
369 static clib_error_t *
370 set_interface_features_command_fn (vlib_main_t * vm,
371                                    unformat_input_t * input,
372                                    vlib_cli_command_t * cmd)
373 {
374   vnet_main_t *vnm = vnet_get_main ();
375   unformat_input_t _line_input, *line_input = &_line_input;
376   clib_error_t *error = 0;
377
378   u8 *arc_name = 0;
379   u8 *feature_name = 0;
380   u32 sw_if_index = ~0;
381   u8 enable = 1;
382
383   /* Get a line of input. */
384   if (!unformat_user (input, unformat_line_input, line_input))
385     goto done;
386
387   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
388     {
389       if (unformat
390           (line_input, "%U %v", unformat_vnet_sw_interface, vnm, &sw_if_index,
391            &feature_name))
392         ;
393       else if (unformat (line_input, "arc %v", &arc_name))
394         ;
395       else if (unformat (line_input, "disable"))
396         enable = 0;
397       else
398         {
399           error = unformat_parse_error (line_input);
400           goto done;
401         }
402     }
403
404   if (sw_if_index == ~0)
405     {
406       error = clib_error_return (0, "Interface not specified...");
407       goto done;
408     }
409
410   vec_add1 (arc_name, 0);
411   vec_add1 (feature_name, 0);
412
413   vnet_feature_registration_t *reg;
414   reg =
415     vnet_get_feature_reg ((const char *) arc_name,
416                           (const char *) feature_name);
417   if (reg == 0)
418     {
419       error = clib_error_return (0, "Unknown feature...");
420       goto done;
421     }
422   if (reg->enable_disable_cb)
423     error = reg->enable_disable_cb (sw_if_index, enable);
424   if (!error)
425     vnet_feature_enable_disable ((const char *) arc_name,
426                                  (const char *) feature_name, sw_if_index,
427                                  enable, 0, 0);
428
429 done:
430   vec_free (feature_name);
431   vec_free (arc_name);
432   unformat_free (line_input);
433   return error;
434 }
435
436 /*?
437  * Set feature for given interface
438  *
439  * @cliexpar
440  * Example:
441  * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast}
442  * @cliexend
443  * @endparblock
444 ?*/
445 /* *INDENT-OFF* */
446 VLIB_CLI_COMMAND (set_interface_feature_command, static) = {
447   .path = "set interface feature",
448   .short_help = "set interface feature <intfc> <feature_name> arc <arc_name> "
449       "[disable]",
450   .function = set_interface_features_command_fn,
451 };
452 /* *INDENT-ON* */
453
454 /*
455  * fd.io coding-style-patch-verification: ON
456  *
457  * Local Variables:
458  * eval: (c-set-style "gnu")
459  * End:
460  */