blob: e1cea21d7b6948ba8c86af39be40782f2d707471 [file] [log] [blame]
Damjan Marion22311502016-10-28 20:30:15 +02001/*
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>
Neale Rannsb069a692017-03-15 12:34:25 -040017#include <vnet/adj/adj.h>
Damjan Marion22311502016-10-28 20:30:15 +020018
19vnet_feature_main_t feature_main;
20
21static clib_error_t *
22vnet_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;
Damjan Marion8b3191e2016-11-09 19:54:20 +010038 if (areg->arc_index_ptr)
39 *areg->arc_index_ptr = arc_index;
Damjan Marion22311502016-10-28 20:30:15 +020040 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 {
Damjan Marion22311502016-10-28 20:30:15 +020046 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 {
Damjan Marion96b41f72016-11-10 18:01:42 +010065 vnet_feature_registration_t *next;
Damjan Marion22311502016-10-28 20:30:15 +020066 uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
67 if (p == 0)
Florin Coras3d2a9142017-08-16 21:23:44 -070068 {
69 /* Don't start vpp with broken features arcs */
70 clib_warning ("Unknown feature arc '%s'", freg->arc_name);
71 os_exit (1);
72 }
Damjan Marion22311502016-10-28 20:30:15 +020073
74 areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
75 arc_index = areg->feature_arc_index;
76
Damjan Marion96b41f72016-11-10 18:01:42 +010077 next = freg->next;
Damjan Marion13adc3d2018-04-09 20:59:53 +020078 freg->next_in_arc = fm->next_feature_by_arc[arc_index];
Damjan Marion96b41f72016-11-10 18:01:42 +010079 fm->next_feature_by_arc[arc_index] = freg;
Damjan Marion22311502016-10-28 20:30:15 +020080
81 /* next */
Damjan Marion96b41f72016-11-10 18:01:42 +010082 freg = next;
Damjan Marion22311502016-10-28 20:30:15 +020083 }
84
Damjan Marion96b41f72016-11-10 18:01:42 +010085 areg = fm->next_arc;
Damjan Marion22311502016-10-28 20:30:15 +020086 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 {
Florin Coras3d2a9142017-08-16 21:23:44 -0700101 clib_error_report (error);
102 os_exit (1);
Damjan Marion22311502016-10-28 20:30:15 +0200103 }
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));
Damjan Marion13adc3d2018-04-09 20:59:53 +0200113 freg = freg->next_in_arc;
Damjan Marion22311502016-10-28 20:30:15 +0200114 }
115
116 /* next */
117 areg = areg->next;
118 arc_index++;
119 }
120
121 return 0;
122}
123
124VLIB_INIT_FUNCTION (vnet_feature_init);
125
Damjan Marion87cd1192016-11-04 11:00:27 +0100126u8
127vnet_get_feature_arc_index (const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200128{
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
Pavel Kotucek7490a752016-11-15 09:19:11 +0100141vnet_feature_registration_t *
142vnet_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
Damjan Marion22311502016-10-28 20:30:15 +0200162u32
Damjan Marion87cd1192016-11-04 11:00:27 +0100163vnet_get_feature_index (u8 arc, const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200164{
165 vnet_feature_main_t *fm = &feature_main;
166 vnet_feature_registration_t *reg;
167 uword *p;
168
Damjan Marion21da6ce2016-11-28 18:21:59 +0100169 if (s == 0)
170 return ~0;
171
Damjan Marion22311502016-10-28 20:30:15 +0200172 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 *);
Damjan Marion8b3191e2016-11-09 19:54:20 +0100177 return reg->feature_index;
Damjan Marion22311502016-10-28 20:30:15 +0200178}
179
Damjan Marion96b41f72016-11-10 18:01:42 +0100180int
Damjan Marion8b3191e2016-11-09 19:54:20 +0100181vnet_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)
Damjan Marion22311502016-10-28 20:30:15 +0200185{
186 vnet_feature_main_t *fm = &feature_main;
187 vnet_feature_config_main_t *cm;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100188 i16 feature_count;
Matthew Smithc3267ed2018-05-15 15:51:30 -0500189 u32 ci;
Damjan Marion22311502016-10-28 20:30:15 +0200190
Damjan Marion05bb1dd2016-11-08 21:28:22 +0100191 if (arc_index == (u8) ~ 0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100192 return VNET_API_ERROR_INVALID_VALUE;
Damjan Marion22311502016-10-28 20:30:15 +0200193
Damjan Marion22311502016-10-28 20:30:15 +0200194 if (feature_index == ~0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100195 return VNET_API_ERROR_INVALID_VALUE_2;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100196
197 cm = &fm->feature_config_mains[arc_index];
198 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
Matthew Smithc3267ed2018-05-15 15:51:30 -0500199 ci = cm->config_index_by_sw_if_index[sw_if_index];
Damjan Marion22311502016-10-28 20:30:15 +0200200
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100201 vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
Damjan Marion21da6ce2016-11-28 18:21:59 +0100202 feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
203
204 if (!enable_disable && feature_count < 1)
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100205 return 0;
206
Damjan Marion22311502016-10-28 20:30:15 +0200207 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);
Matthew Smithc3267ed2018-05-15 15:51:30 -0500212 if (ci == ~0)
Klement Sekera3ecc2212018-03-27 10:34:43 +0200213 {
214 return 0;
215 }
Damjan Marion22311502016-10-28 20:30:15 +0200216 cm->config_index_by_sw_if_index[sw_if_index] = ci;
217
Damjan Marion21da6ce2016-11-28 18:21:59 +0100218 /* update feature count */
219 enable_disable = (enable_disable > 0);
220 feature_count += enable_disable ? 1 : -1;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100221 ASSERT (feature_count >= 0);
Damjan Marion22311502016-10-28 20:30:15 +0200222
Damjan Marion21da6ce2016-11-28 18:21:59 +0100223 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));
Neale Rannsb069a692017-03-15 12:34:25 -0400226 adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
Damjan Marion21da6ce2016-11-28 18:21:59 +0100227
228 fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
Damjan Marion96b41f72016-11-10 18:01:42 +0100229 return 0;
Damjan Marion22311502016-10-28 20:30:15 +0200230}
231
Damjan Marion8b3191e2016-11-09 19:54:20 +0100232int
233vnet_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
Dave Barach525c9d02018-05-26 10:48:55 -0400253static int
254feature_cmp (void *a1, void *a2)
255{
256 vnet_feature_registration_t *reg1 = a1;
257 vnet_feature_registration_t *reg2 = a2;
258
259 return (int) reg1->feature_index - reg2->feature_index;
260}
Damjan Marion22311502016-10-28 20:30:15 +0200261
262/** Display the set of available driver features.
263 Useful for verifying that expected features are present
264*/
265
266static clib_error_t *
267show_features_command_fn (vlib_main_t * vm,
268 unformat_input_t * input, vlib_cli_command_t * cmd)
269{
270 vnet_feature_main_t *fm = &feature_main;
271 vnet_feature_arc_registration_t *areg;
272 vnet_feature_registration_t *freg;
Dave Barach525c9d02018-05-26 10:48:55 -0400273 vnet_feature_registration_t *feature_regs = 0;
274 int verbose = 0;
275
276 if (unformat (input, "verbose"))
277 verbose = 1;
Damjan Marion22311502016-10-28 20:30:15 +0200278
279 vlib_cli_output (vm, "Available feature paths");
280
281 areg = fm->next_arc;
282 while (areg)
283 {
Dave Barach525c9d02018-05-26 10:48:55 -0400284 if (verbose)
285 vlib_cli_output (vm, "[%2d] %s:", areg->feature_arc_index,
286 areg->arc_name);
287 else
288 vlib_cli_output (vm, "%s:", areg->arc_name);
289
Damjan Marion96b41f72016-11-10 18:01:42 +0100290 freg = fm->next_feature_by_arc[areg->feature_arc_index];
291 while (freg)
292 {
Dave Barach525c9d02018-05-26 10:48:55 -0400293 vec_add1 (feature_regs, freg[0]);
Damjan Marion13adc3d2018-04-09 20:59:53 +0200294 freg = freg->next_in_arc;
Damjan Marion96b41f72016-11-10 18:01:42 +0100295 }
Damjan Marion22311502016-10-28 20:30:15 +0200296
Dave Barach525c9d02018-05-26 10:48:55 -0400297 vec_sort_with_function (feature_regs, feature_cmp);
Damjan Marion22311502016-10-28 20:30:15 +0200298
Dave Barach525c9d02018-05-26 10:48:55 -0400299 vec_foreach (freg, feature_regs)
300 {
301 if (verbose)
302 vlib_cli_output (vm, " [%2d]: %s\n", freg->feature_index,
303 freg->node_name);
304 else
305 vlib_cli_output (vm, " %s\n", freg->node_name);
306 }
307 vec_reset_length (feature_regs);
Damjan Marion22311502016-10-28 20:30:15 +0200308 /* next */
309 areg = areg->next;
310 }
Dave Barach525c9d02018-05-26 10:48:55 -0400311 vec_free (feature_regs);
Damjan Marion22311502016-10-28 20:30:15 +0200312
313 return 0;
314}
315
316/*?
317 * Display the set of available driver features
318 *
319 * @cliexpar
320 * Example:
Dave Barach525c9d02018-05-26 10:48:55 -0400321 * @cliexcmd{show features [verbose]}
Damjan Marion22311502016-10-28 20:30:15 +0200322 * @cliexend
323 * @endparblock
324?*/
325/* *INDENT-OFF* */
326VLIB_CLI_COMMAND (show_features_command, static) = {
327 .path = "show features",
328 .short_help = "show features",
329 .function = show_features_command_fn,
330};
331/* *INDENT-ON* */
332
333/** Display the set of driver features configured on a specific interface
334 * Called by "show interface" handler
335 */
336
337void
Dave Barach525c9d02018-05-26 10:48:55 -0400338vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose)
Damjan Marion22311502016-10-28 20:30:15 +0200339{
340 vnet_feature_main_t *fm = &feature_main;
341 u32 node_index, current_config_index;
342 u16 feature_arc;
343 vnet_feature_config_main_t *cm = fm->feature_config_mains;
344 vnet_feature_arc_registration_t *areg;
345 vnet_config_main_t *vcm;
346 vnet_config_t *cfg;
347 u32 cfg_index;
348 vnet_config_feature_t *feat;
349 vlib_node_t *n;
350 int i;
351
Dave Barach525c9d02018-05-26 10:48:55 -0400352 vlib_cli_output (vm, "Feature paths configured on %U...",
Damjan Marion22311502016-10-28 20:30:15 +0200353 format_vnet_sw_if_index_name,
354 vnet_get_main (), sw_if_index);
355
356 areg = fm->next_arc;
357 while (areg)
358 {
359 feature_arc = areg->feature_arc_index;
360 vcm = &(cm[feature_arc].config_main);
361
362 vlib_cli_output (vm, "\n%s:", areg->arc_name);
363 areg = areg->next;
364
365 if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
Damjan Marion87cd1192016-11-04 11:00:27 +0100366 vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
367 sw_if_index)
Damjan Marion22311502016-10-28 20:30:15 +0200368 {
369 vlib_cli_output (vm, " none configured");
370 continue;
371 }
372
373 current_config_index =
374 vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
375
376 if (current_config_index == ~0)
377 {
378 vlib_cli_output (vm, " none configured");
379 continue;
380 }
381
382 ASSERT (current_config_index
383 < vec_len (vcm->config_pool_index_by_user_index));
384
385 cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
386 cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
387
388 for (i = 0; i < vec_len (cfg->features); i++)
389 {
390 feat = cfg->features + i;
391 node_index = feat->node_index;
392 n = vlib_get_node (vm, node_index);
Dave Barach525c9d02018-05-26 10:48:55 -0400393 if (verbose)
394 vlib_cli_output (vm, " [%2d] %v", feat->feature_index, n->name);
395 else
396 vlib_cli_output (vm, " %v", n->name);
Damjan Marion22311502016-10-28 20:30:15 +0200397 }
398 }
399}
400
Pavel Kotucek7490a752016-11-15 09:19:11 +0100401static clib_error_t *
402set_interface_features_command_fn (vlib_main_t * vm,
403 unformat_input_t * input,
404 vlib_cli_command_t * cmd)
405{
406 vnet_main_t *vnm = vnet_get_main ();
407 unformat_input_t _line_input, *line_input = &_line_input;
408 clib_error_t *error = 0;
409
410 u8 *arc_name = 0;
411 u8 *feature_name = 0;
412 u32 sw_if_index = ~0;
413 u8 enable = 1;
414
415 /* Get a line of input. */
416 if (!unformat_user (input, unformat_line_input, line_input))
417 goto done;
418
419 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
420 {
421 if (unformat
422 (line_input, "%U %v", unformat_vnet_sw_interface, vnm, &sw_if_index,
423 &feature_name))
424 ;
425 else if (unformat (line_input, "arc %v", &arc_name))
426 ;
427 else if (unformat (line_input, "disable"))
428 enable = 0;
429 else
430 {
Dave Barach525c9d02018-05-26 10:48:55 -0400431 if (feature_name && arc_name)
432 break;
Pavel Kotucek7490a752016-11-15 09:19:11 +0100433 error = unformat_parse_error (line_input);
434 goto done;
435 }
436 }
437
438 if (sw_if_index == ~0)
439 {
440 error = clib_error_return (0, "Interface not specified...");
441 goto done;
442 }
443
444 vec_add1 (arc_name, 0);
445 vec_add1 (feature_name, 0);
446
447 vnet_feature_registration_t *reg;
448 reg =
449 vnet_get_feature_reg ((const char *) arc_name,
450 (const char *) feature_name);
451 if (reg == 0)
452 {
453 error = clib_error_return (0, "Unknown feature...");
454 goto done;
455 }
456 if (reg->enable_disable_cb)
457 error = reg->enable_disable_cb (sw_if_index, enable);
458 if (!error)
459 vnet_feature_enable_disable ((const char *) arc_name,
460 (const char *) feature_name, sw_if_index,
461 enable, 0, 0);
462
463done:
464 vec_free (feature_name);
465 vec_free (arc_name);
Billy McFall614c1312017-03-01 17:01:06 -0500466 unformat_free (line_input);
Pavel Kotucek7490a752016-11-15 09:19:11 +0100467 return error;
468}
469
470/*?
471 * Set feature for given interface
472 *
473 * @cliexpar
474 * Example:
475 * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast}
476 * @cliexend
477 * @endparblock
478?*/
479/* *INDENT-OFF* */
480VLIB_CLI_COMMAND (set_interface_feature_command, static) = {
481 .path = "set interface feature",
Pierre Pfister1bfd3722017-09-18 11:40:32 +0200482 .short_help = "set interface feature <intfc> <feature_name> arc <arc_name> "
483 "[disable]",
Pavel Kotucek7490a752016-11-15 09:19:11 +0100484 .function = set_interface_features_command_fn,
485};
486/* *INDENT-ON* */
487
Damjan Marion22311502016-10-28 20:30:15 +0200488/*
489 * fd.io coding-style-patch-verification: ON
490 *
491 * Local Variables:
492 * eval: (c-set-style "gnu")
493 * End:
494 */