Add ip6-local feature arc
[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 = 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;
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   cm->config_index_by_sw_if_index[sw_if_index] = ci;
213
214   /* update feature count */
215   enable_disable = (enable_disable > 0);
216   feature_count += enable_disable ? 1 : -1;
217   ASSERT (feature_count >= 0);
218
219   fm->sw_if_index_has_features[arc_index] =
220     clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
221                      (feature_count > 0));
222   adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
223
224   fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
225   return 0;
226 }
227
228 int
229 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
230                              u32 sw_if_index, int enable_disable,
231                              void *feature_config, u32 n_feature_config_bytes)
232 {
233   u32 feature_index;
234   u8 arc_index;
235
236   arc_index = vnet_get_feature_arc_index (arc_name);
237
238   if (arc_index == (u8) ~ 0)
239     return VNET_API_ERROR_INVALID_VALUE;
240
241   feature_index = vnet_get_feature_index (arc_index, node_name);
242
243   return vnet_feature_enable_disable_with_index (arc_index, feature_index,
244                                                  sw_if_index, enable_disable,
245                                                  feature_config,
246                                                  n_feature_config_bytes);
247 }
248
249
250 /** Display the set of available driver features.
251     Useful for verifying that expected features are present
252 */
253
254 static clib_error_t *
255 show_features_command_fn (vlib_main_t * vm,
256                           unformat_input_t * input, vlib_cli_command_t * cmd)
257 {
258   vnet_feature_main_t *fm = &feature_main;
259   vnet_feature_arc_registration_t *areg;
260   vnet_feature_registration_t *freg;
261
262   vlib_cli_output (vm, "Available feature paths");
263
264   areg = fm->next_arc;
265   while (areg)
266     {
267       vlib_cli_output (vm, "%s:", areg->arc_name);
268       freg = fm->next_feature_by_arc[areg->feature_arc_index];
269       while (freg)
270         {
271           vlib_cli_output (vm, "  %s\n", freg->node_name);
272           freg = freg->next;
273         }
274
275
276       /* next */
277       areg = areg->next;
278     }
279
280   return 0;
281 }
282
283 /*?
284  * Display the set of available driver features
285  *
286  * @cliexpar
287  * Example:
288  * @cliexcmd{show ip features}
289  * @cliexend
290  * @endparblock
291 ?*/
292 /* *INDENT-OFF* */
293 VLIB_CLI_COMMAND (show_features_command, static) = {
294   .path = "show features",
295   .short_help = "show features",
296   .function = show_features_command_fn,
297 };
298 /* *INDENT-ON* */
299
300 /** Display the set of driver features configured on a specific interface
301   * Called by "show interface" handler
302  */
303
304 void
305 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index)
306 {
307   vnet_feature_main_t *fm = &feature_main;
308   u32 node_index, current_config_index;
309   u16 feature_arc;
310   vnet_feature_config_main_t *cm = fm->feature_config_mains;
311   vnet_feature_arc_registration_t *areg;
312   vnet_config_main_t *vcm;
313   vnet_config_t *cfg;
314   u32 cfg_index;
315   vnet_config_feature_t *feat;
316   vlib_node_t *n;
317   int i;
318
319   vlib_cli_output (vm, "Driver feature paths configured on %U...",
320                    format_vnet_sw_if_index_name,
321                    vnet_get_main (), sw_if_index);
322
323   areg = fm->next_arc;
324   while (areg)
325     {
326       feature_arc = areg->feature_arc_index;
327       vcm = &(cm[feature_arc].config_main);
328
329       vlib_cli_output (vm, "\n%s:", areg->arc_name);
330       areg = areg->next;
331
332       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
333           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
334           sw_if_index)
335         {
336           vlib_cli_output (vm, "  none configured");
337           continue;
338         }
339
340       current_config_index =
341         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
342
343       if (current_config_index == ~0)
344         {
345           vlib_cli_output (vm, "  none configured");
346           continue;
347         }
348
349       ASSERT (current_config_index
350               < vec_len (vcm->config_pool_index_by_user_index));
351
352       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
353       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
354
355       for (i = 0; i < vec_len (cfg->features); i++)
356         {
357           feat = cfg->features + i;
358           node_index = feat->node_index;
359           n = vlib_get_node (vm, node_index);
360           vlib_cli_output (vm, "  %v", n->name);
361         }
362     }
363 }
364
365 static clib_error_t *
366 set_interface_features_command_fn (vlib_main_t * vm,
367                                    unformat_input_t * input,
368                                    vlib_cli_command_t * cmd)
369 {
370   vnet_main_t *vnm = vnet_get_main ();
371   unformat_input_t _line_input, *line_input = &_line_input;
372   clib_error_t *error = 0;
373
374   u8 *arc_name = 0;
375   u8 *feature_name = 0;
376   u32 sw_if_index = ~0;
377   u8 enable = 1;
378
379   /* Get a line of input. */
380   if (!unformat_user (input, unformat_line_input, line_input))
381     goto done;
382
383   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
384     {
385       if (unformat
386           (line_input, "%U %v", unformat_vnet_sw_interface, vnm, &sw_if_index,
387            &feature_name))
388         ;
389       else if (unformat (line_input, "arc %v", &arc_name))
390         ;
391       else if (unformat (line_input, "disable"))
392         enable = 0;
393       else
394         {
395           error = unformat_parse_error (line_input);
396           goto done;
397         }
398     }
399
400   if (sw_if_index == ~0)
401     {
402       error = clib_error_return (0, "Interface not specified...");
403       goto done;
404     }
405
406   vec_add1 (arc_name, 0);
407   vec_add1 (feature_name, 0);
408
409   vnet_feature_registration_t *reg;
410   reg =
411     vnet_get_feature_reg ((const char *) arc_name,
412                           (const char *) feature_name);
413   if (reg == 0)
414     {
415       error = clib_error_return (0, "Unknown feature...");
416       goto done;
417     }
418   if (reg->enable_disable_cb)
419     error = reg->enable_disable_cb (sw_if_index, enable);
420   if (!error)
421     vnet_feature_enable_disable ((const char *) arc_name,
422                                  (const char *) feature_name, sw_if_index,
423                                  enable, 0, 0);
424
425 done:
426   vec_free (feature_name);
427   vec_free (arc_name);
428   unformat_free (line_input);
429   return error;
430 }
431
432 /*?
433  * Set feature for given interface
434  *
435  * @cliexpar
436  * Example:
437  * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast}
438  * @cliexend
439  * @endparblock
440 ?*/
441 /* *INDENT-OFF* */
442 VLIB_CLI_COMMAND (set_interface_feature_command, static) = {
443   .path = "set interface feature",
444   .short_help = "set interface feature <intfc> <feature_name> arc <arc_name> "
445       "[disable]",
446   .function = set_interface_features_command_fn,
447 };
448 /* *INDENT-ON* */
449
450 /*
451  * fd.io coding-style-patch-verification: ON
452  *
453  * Local Variables:
454  * eval: (c-set-style "gnu")
455  * End:
456  */