09dd9cc965f16ec876716f2f2cd2a0ca7a432fcb
[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
18
19 vnet_feature_main_t feature_main;
20
21 typedef struct vnet_feature_upd_registration_t_
22 {
23   vnet_feature_update_cb_t cb;
24   void *data;
25 } vnet_feature_upd_registration_t;
26
27 static vnet_feature_upd_registration_t *regs;
28
29 void
30 vnet_feature_register (vnet_feature_update_cb_t cb, void *data)
31 {
32   vnet_feature_upd_registration_t *reg;
33
34   vec_add2 (regs, reg, 1);
35
36   reg->cb = cb;
37   reg->data = data;
38 }
39
40 static void
41 vent_feature_reg_invoke (u32 sw_if_index, u8 arc_index, u8 is_enable)
42 {
43   vnet_feature_upd_registration_t *reg;
44
45   vec_foreach (reg, regs)
46     reg->cb (sw_if_index, arc_index, is_enable, reg->data);
47 }
48
49
50 static clib_error_t *
51 vnet_feature_init (vlib_main_t * vm)
52 {
53   vnet_feature_main_t *fm = &feature_main;
54   vnet_feature_registration_t *freg;
55   vnet_feature_arc_registration_t *areg;
56   vnet_feature_constraint_registration_t *creg;
57   u32 arc_index = 0;
58
59   fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
60   areg = fm->next_arc;
61
62   /* process feature arc registrations */
63   while (areg)
64     {
65       char *s;
66       int i = 0;
67       areg->feature_arc_index = arc_index;
68       if (areg->arc_index_ptr)
69         *areg->arc_index_ptr = arc_index;
70       hash_set_mem (fm->arc_index_by_name, areg->arc_name,
71                     pointer_to_uword (areg));
72
73       /* process start nodes */
74       while ((s = areg->start_nodes[i]))
75         {
76           i++;
77         }
78       areg->n_start_nodes = i;
79
80       /* next */
81       areg = areg->next;
82       arc_index++;
83     }
84
85   vec_validate (fm->next_feature_by_arc, arc_index - 1);
86   vec_validate (fm->feature_nodes, arc_index - 1);
87   vec_validate (fm->feature_config_mains, arc_index - 1);
88   vec_validate (fm->next_feature_by_name, arc_index - 1);
89   vec_validate (fm->sw_if_index_has_features, arc_index - 1);
90   vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
91   vec_validate (fm->next_constraint_by_arc, arc_index - 1);
92
93   freg = fm->next_feature;
94   while (freg)
95     {
96       vnet_feature_registration_t *next;
97       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
98       if (p == 0)
99         {
100           /* Don't start vpp with broken features arcs */
101           clib_warning ("Unknown feature arc '%s'", freg->arc_name);
102           os_exit (1);
103         }
104
105       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
106       arc_index = areg->feature_arc_index;
107
108       next = freg->next;
109       freg->next_in_arc = fm->next_feature_by_arc[arc_index];
110       fm->next_feature_by_arc[arc_index] = freg;
111
112       /* next */
113       freg = next;
114     }
115
116   /* Move bulk constraints to the constraint by arc lists */
117   creg = fm->next_constraint;
118   while (creg)
119     {
120       vnet_feature_constraint_registration_t *next;
121       uword *p = hash_get_mem (fm->arc_index_by_name, creg->arc_name);
122       if (p == 0)
123         {
124           /* Don't start vpp with broken features arcs */
125           clib_warning ("Unknown feature arc '%s'", creg->arc_name);
126           os_exit (1);
127         }
128
129       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
130       arc_index = areg->feature_arc_index;
131
132       next = creg->next;
133       creg->next_in_arc = fm->next_constraint_by_arc[arc_index];
134       fm->next_constraint_by_arc[arc_index] = creg;
135
136       /* next */
137       creg = next;
138     }
139
140
141   areg = fm->next_arc;
142   while (areg)
143     {
144       clib_error_t *error;
145       vnet_feature_config_main_t *cm;
146       vnet_config_main_t *vcm;
147       char **features_in_order, *last_feature;
148
149       arc_index = areg->feature_arc_index;
150       cm = &fm->feature_config_mains[arc_index];
151       vcm = &cm->config_main;
152       if ((error = vnet_feature_arc_init
153            (vm, vcm, areg->start_nodes, areg->n_start_nodes,
154             areg->last_in_arc,
155             fm->next_feature_by_arc[arc_index],
156             fm->next_constraint_by_arc[arc_index],
157             &fm->feature_nodes[arc_index])))
158         {
159           clib_error_report (error);
160           os_exit (1);
161         }
162
163       features_in_order = fm->feature_nodes[arc_index];
164
165       /* If specified, verify that the last node in the arc is actually last */
166       if (areg->last_in_arc && vec_len (features_in_order) > 0)
167         {
168           last_feature = features_in_order[vec_len (features_in_order) - 1];
169           if (strncmp (areg->last_in_arc, last_feature,
170                        strlen (areg->last_in_arc)))
171             clib_warning
172               ("WARNING: %s arc: last node is %s, but expected %s!",
173                areg->arc_name, last_feature, areg->last_in_arc);
174         }
175
176       fm->next_feature_by_name[arc_index] =
177         hash_create_string (0, sizeof (uword));
178       freg = fm->next_feature_by_arc[arc_index];
179
180       while (freg)
181         {
182           hash_set_mem (fm->next_feature_by_name[arc_index],
183                         freg->node_name, pointer_to_uword (freg));
184           freg = freg->next_in_arc;
185         }
186
187       /* next */
188       areg = areg->next;
189       arc_index++;
190     }
191
192   return 0;
193 }
194
195 VLIB_INIT_FUNCTION (vnet_feature_init);
196
197 u8
198 vnet_get_feature_arc_index (const char *s)
199 {
200   vnet_feature_main_t *fm = &feature_main;
201   vnet_feature_arc_registration_t *reg;
202   uword *p;
203
204   p = hash_get_mem (fm->arc_index_by_name, s);
205   if (p == 0)
206     return ~0;
207
208   reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
209   return reg->feature_arc_index;
210 }
211
212 vnet_feature_registration_t *
213 vnet_get_feature_reg (const char *arc_name, const char *node_name)
214 {
215   u8 arc_index;
216
217   arc_index = vnet_get_feature_arc_index (arc_name);
218   if (arc_index == (u8) ~ 0)
219     return 0;
220
221   vnet_feature_main_t *fm = &feature_main;
222   vnet_feature_registration_t *reg;
223   uword *p;
224
225   p = hash_get_mem (fm->next_feature_by_name[arc_index], node_name);
226   if (p == 0)
227     return 0;
228
229   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
230   return reg;
231 }
232
233 u32
234 vnet_get_feature_index (u8 arc, const char *s)
235 {
236   vnet_feature_main_t *fm = &feature_main;
237   vnet_feature_registration_t *reg;
238   uword *p;
239
240   if (s == 0)
241     return ~0;
242
243   p = hash_get_mem (fm->next_feature_by_name[arc], s);
244   if (p == 0)
245     return ~0;
246
247   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
248   return reg->feature_index;
249 }
250
251 int
252 vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
253                                         u32 sw_if_index, int enable_disable,
254                                         void *feature_config,
255                                         u32 n_feature_config_bytes)
256 {
257   vnet_feature_main_t *fm = &feature_main;
258   vnet_feature_config_main_t *cm;
259   i16 feature_count;
260   u32 ci;
261
262   if (arc_index == (u8) ~ 0)
263     return VNET_API_ERROR_INVALID_VALUE;
264
265   if (feature_index == ~0)
266     return VNET_API_ERROR_INVALID_VALUE_2;
267
268   cm = &fm->feature_config_mains[arc_index];
269   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
270   ci = cm->config_index_by_sw_if_index[sw_if_index];
271
272   vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
273   feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
274
275   if (!enable_disable && feature_count < 1)
276     return 0;
277
278   ci = (enable_disable
279         ? vnet_config_add_feature
280         : vnet_config_del_feature)
281     (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
282      n_feature_config_bytes);
283   if (ci == ~0)
284     {
285       return 0;
286     }
287   cm->config_index_by_sw_if_index[sw_if_index] = ci;
288
289   /* update feature count */
290   enable_disable = (enable_disable > 0);
291   feature_count += enable_disable ? 1 : -1;
292   ASSERT (feature_count >= 0);
293
294   fm->sw_if_index_has_features[arc_index] =
295     clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
296                      (feature_count > 0));
297   vent_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0));
298
299   fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
300   return 0;
301 }
302
303 int
304 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
305                              u32 sw_if_index, int enable_disable,
306                              void *feature_config, u32 n_feature_config_bytes)
307 {
308   u32 feature_index;
309   u8 arc_index;
310
311   arc_index = vnet_get_feature_arc_index (arc_name);
312
313   if (arc_index == (u8) ~ 0)
314     return VNET_API_ERROR_INVALID_VALUE;
315
316   feature_index = vnet_get_feature_index (arc_index, node_name);
317
318   return vnet_feature_enable_disable_with_index (arc_index, feature_index,
319                                                  sw_if_index, enable_disable,
320                                                  feature_config,
321                                                  n_feature_config_bytes);
322 }
323
324 u32
325 vnet_feature_modify_end_node (u8 arc_index,
326                               u32 sw_if_index, u32 end_node_index)
327 {
328   vnet_feature_main_t *fm = &feature_main;
329   vnet_feature_config_main_t *cm;
330   u32 ci;
331
332   if (arc_index == (u8) ~ 0)
333     return VNET_API_ERROR_INVALID_VALUE;
334
335   if (end_node_index == ~0)
336     return VNET_API_ERROR_INVALID_VALUE_2;
337
338   cm = &fm->feature_config_mains[arc_index];
339   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
340   ci = cm->config_index_by_sw_if_index[sw_if_index];
341
342   ci = vnet_config_modify_end_node (vlib_get_main (), &cm->config_main,
343                                     ci, end_node_index);
344
345   if (ci != ~0)
346     cm->config_index_by_sw_if_index[sw_if_index] = ci;
347
348   return ci;
349 }
350
351 static int
352 feature_cmp (void *a1, void *a2)
353 {
354   vnet_feature_registration_t *reg1 = a1;
355   vnet_feature_registration_t *reg2 = a2;
356
357   return (int) reg1->feature_index - reg2->feature_index;
358 }
359
360 /** Display the set of available driver features.
361     Useful for verifying that expected features are present
362 */
363
364 static clib_error_t *
365 show_features_command_fn (vlib_main_t * vm,
366                           unformat_input_t * input, vlib_cli_command_t * cmd)
367 {
368   vnet_feature_main_t *fm = &feature_main;
369   vnet_feature_arc_registration_t *areg;
370   vnet_feature_registration_t *freg;
371   vnet_feature_registration_t *feature_regs = 0;
372   int verbose = 0;
373
374   if (unformat (input, "verbose"))
375     verbose = 1;
376
377   vlib_cli_output (vm, "Available feature paths");
378
379   areg = fm->next_arc;
380   while (areg)
381     {
382       if (verbose)
383         vlib_cli_output (vm, "[%2d] %s:", areg->feature_arc_index,
384                          areg->arc_name);
385       else
386         vlib_cli_output (vm, "%s:", areg->arc_name);
387
388       freg = fm->next_feature_by_arc[areg->feature_arc_index];
389       while (freg)
390         {
391           vec_add1 (feature_regs, freg[0]);
392           freg = freg->next_in_arc;
393         }
394
395       vec_sort_with_function (feature_regs, feature_cmp);
396
397       vec_foreach (freg, feature_regs)
398       {
399         if (verbose)
400           vlib_cli_output (vm, "  [%2d]: %s\n", freg->feature_index,
401                            freg->node_name);
402         else
403           vlib_cli_output (vm, "  %s\n", freg->node_name);
404       }
405       vec_reset_length (feature_regs);
406       /* next */
407       areg = areg->next;
408     }
409   vec_free (feature_regs);
410
411   return 0;
412 }
413
414 /*?
415  * Display the set of available driver features
416  *
417  * @cliexpar
418  * Example:
419  * @cliexcmd{show features [verbose]}
420  * @cliexend
421  * @endparblock
422 ?*/
423 /* *INDENT-OFF* */
424 VLIB_CLI_COMMAND (show_features_command, static) = {
425   .path = "show features",
426   .short_help = "show features [verbose]",
427   .function = show_features_command_fn,
428 };
429 /* *INDENT-ON* */
430
431 /** Display the set of driver features configured on a specific interface
432   * Called by "show interface" handler
433  */
434
435 void
436 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose)
437 {
438   vnet_feature_main_t *fm = &feature_main;
439   u32 node_index, current_config_index;
440   u16 feature_arc;
441   vnet_feature_config_main_t *cm = fm->feature_config_mains;
442   vnet_feature_arc_registration_t *areg;
443   vnet_config_main_t *vcm;
444   vnet_config_t *cfg;
445   u32 cfg_index;
446   vnet_config_feature_t *feat;
447   vlib_node_t *n;
448   int i;
449
450   vlib_cli_output (vm, "Feature paths configured on %U...",
451                    format_vnet_sw_if_index_name,
452                    vnet_get_main (), sw_if_index);
453
454   areg = fm->next_arc;
455   while (areg)
456     {
457       feature_arc = areg->feature_arc_index;
458       vcm = &(cm[feature_arc].config_main);
459
460       vlib_cli_output (vm, "\n%s:", areg->arc_name);
461       areg = areg->next;
462
463       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
464           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
465           sw_if_index)
466         {
467           vlib_cli_output (vm, "  none configured");
468           continue;
469         }
470
471       current_config_index =
472         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
473
474       if (current_config_index == ~0)
475         {
476           vlib_cli_output (vm, "  none configured");
477           continue;
478         }
479
480       ASSERT (current_config_index
481               < vec_len (vcm->config_pool_index_by_user_index));
482
483       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
484       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
485
486       for (i = 0; i < vec_len (cfg->features); i++)
487         {
488           feat = cfg->features + i;
489           node_index = feat->node_index;
490           n = vlib_get_node (vm, node_index);
491           if (verbose)
492             vlib_cli_output (vm, "  [%2d] %v", feat->feature_index, n->name);
493           else
494             vlib_cli_output (vm, "  %v", n->name);
495         }
496       if (verbose)
497         {
498           n =
499             vlib_get_node (vm,
500                            vcm->end_node_indices_by_user_index
501                            [current_config_index]);
502           vlib_cli_output (vm, "  [end] %v", n->name);
503         }
504     }
505 }
506
507 static clib_error_t *
508 set_interface_features_command_fn (vlib_main_t * vm,
509                                    unformat_input_t * input,
510                                    vlib_cli_command_t * cmd)
511 {
512   vnet_main_t *vnm = vnet_get_main ();
513   unformat_input_t _line_input, *line_input = &_line_input;
514   clib_error_t *error = 0;
515
516   u8 *arc_name = 0;
517   u8 *feature_name = 0;
518   u32 sw_if_index = ~0;
519   u8 enable = 1;
520
521   /* Get a line of input. */
522   if (!unformat_user (input, unformat_line_input, line_input))
523     return 0;
524
525   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
526     {
527       if (unformat
528           (line_input, "%U %s arc %s", unformat_vnet_sw_interface, vnm,
529            &sw_if_index, &feature_name, &arc_name))
530         ;
531       else if (unformat (line_input, "disable"))
532         enable = 0;
533       else
534         {
535           error = unformat_parse_error (line_input);
536           goto done;
537         }
538     }
539   if (!feature_name || !arc_name)
540     {
541       error = clib_error_return (0, "Both feature name and arc required...");
542       goto done;
543     }
544
545   if (sw_if_index == ~0)
546     {
547       error = clib_error_return (0, "Interface not specified...");
548       goto done;
549     }
550
551   vec_add1 (arc_name, 0);
552   vec_add1 (feature_name, 0);
553
554   u8 arc_index;
555
556   arc_index = vnet_get_feature_arc_index ((const char *) arc_name);
557
558   if (arc_index == (u8) ~ 0)
559     {
560       error =
561         clib_error_return (0, "Unknown arc name (%s)... ",
562                            (const char *) arc_name);
563       goto done;
564     }
565
566   vnet_feature_registration_t *reg;
567   reg =
568     vnet_get_feature_reg ((const char *) arc_name,
569                           (const char *) feature_name);
570   if (reg == 0)
571     {
572       error =
573         clib_error_return (0,
574                            "Feature (%s) not registered to arc (%s)... See 'show features verbose' for valid feature/arc combinations. ",
575                            feature_name, arc_name);
576       goto done;
577     }
578   if (reg->enable_disable_cb)
579     error = reg->enable_disable_cb (sw_if_index, enable);
580   if (!error)
581     vnet_feature_enable_disable ((const char *) arc_name,
582                                  (const char *) feature_name, sw_if_index,
583                                  enable, 0, 0);
584
585 done:
586   vec_free (feature_name);
587   vec_free (arc_name);
588   unformat_free (line_input);
589   return error;
590 }
591
592 /*?
593  * Set feature for given interface
594  *
595  * @cliexpar
596  * Example:
597  * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast}
598  * @cliexend
599  * @endparblock
600 ?*/
601 /* *INDENT-OFF* */
602 VLIB_CLI_COMMAND (set_interface_feature_command, static) = {
603   .path = "set interface feature",
604   .short_help = "set interface feature <intfc> <feature_name> arc <arc_name> "
605       "[disable]",
606   .function = set_interface_features_command_fn,
607 };
608 /* *INDENT-ON* */
609
610 /*
611  * fd.io coding-style-patch-verification: ON
612  *
613  * Local Variables:
614  * eval: (c-set-style "gnu")
615  * End:
616  */