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