blob: 2cdbcff88c89d96e77584088b431929e673b4b76 [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;
Dave Barach2dd192b2018-11-19 09:31:48 -050027 vnet_feature_constraint_registration_t *creg;
Damjan Marion22311502016-10-28 20:30:15 +020028 u32 arc_index = 0;
29
30 fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
31 areg = fm->next_arc;
32
33 /* process feature arc registrations */
34 while (areg)
35 {
36 char *s;
37 int i = 0;
38 areg->feature_arc_index = arc_index;
Damjan Marion8b3191e2016-11-09 19:54:20 +010039 if (areg->arc_index_ptr)
40 *areg->arc_index_ptr = arc_index;
Damjan Marion22311502016-10-28 20:30:15 +020041 hash_set_mem (fm->arc_index_by_name, areg->arc_name,
42 pointer_to_uword (areg));
43
44 /* process start nodes */
45 while ((s = areg->start_nodes[i]))
46 {
Damjan Marion22311502016-10-28 20:30:15 +020047 i++;
48 }
49 areg->n_start_nodes = i;
50
51 /* next */
52 areg = areg->next;
53 arc_index++;
54 }
55
56 vec_validate (fm->next_feature_by_arc, arc_index - 1);
57 vec_validate (fm->feature_nodes, arc_index - 1);
58 vec_validate (fm->feature_config_mains, arc_index - 1);
59 vec_validate (fm->next_feature_by_name, arc_index - 1);
60 vec_validate (fm->sw_if_index_has_features, arc_index - 1);
61 vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
Dave Barach2dd192b2018-11-19 09:31:48 -050062 vec_validate (fm->next_constraint_by_arc, arc_index - 1);
Damjan Marion22311502016-10-28 20:30:15 +020063
64 freg = fm->next_feature;
65 while (freg)
66 {
Damjan Marion96b41f72016-11-10 18:01:42 +010067 vnet_feature_registration_t *next;
Damjan Marion22311502016-10-28 20:30:15 +020068 uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
69 if (p == 0)
Florin Coras3d2a9142017-08-16 21:23:44 -070070 {
71 /* Don't start vpp with broken features arcs */
72 clib_warning ("Unknown feature arc '%s'", freg->arc_name);
73 os_exit (1);
74 }
Damjan Marion22311502016-10-28 20:30:15 +020075
76 areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
77 arc_index = areg->feature_arc_index;
78
Damjan Marion96b41f72016-11-10 18:01:42 +010079 next = freg->next;
Damjan Marion13adc3d2018-04-09 20:59:53 +020080 freg->next_in_arc = fm->next_feature_by_arc[arc_index];
Damjan Marion96b41f72016-11-10 18:01:42 +010081 fm->next_feature_by_arc[arc_index] = freg;
Damjan Marion22311502016-10-28 20:30:15 +020082
83 /* next */
Damjan Marion96b41f72016-11-10 18:01:42 +010084 freg = next;
Damjan Marion22311502016-10-28 20:30:15 +020085 }
86
Dave Barach2dd192b2018-11-19 09:31:48 -050087 /* Move bulk constraints to the constraint by arc lists */
88 creg = fm->next_constraint;
89 while (creg)
90 {
91 vnet_feature_constraint_registration_t *next;
92 uword *p = hash_get_mem (fm->arc_index_by_name, creg->arc_name);
93 if (p == 0)
94 {
95 /* Don't start vpp with broken features arcs */
96 clib_warning ("Unknown feature arc '%s'", creg->arc_name);
97 os_exit (1);
98 }
99
100 areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
101 arc_index = areg->feature_arc_index;
102
103 next = creg->next;
104 creg->next_in_arc = fm->next_constraint_by_arc[arc_index];
105 fm->next_constraint_by_arc[arc_index] = creg;
106
107 /* next */
108 creg = next;
109 }
110
111
Damjan Marion96b41f72016-11-10 18:01:42 +0100112 areg = fm->next_arc;
Damjan Marion22311502016-10-28 20:30:15 +0200113 while (areg)
114 {
115 clib_error_t *error;
116 vnet_feature_config_main_t *cm;
117 vnet_config_main_t *vcm;
118
119 arc_index = areg->feature_arc_index;
120 cm = &fm->feature_config_mains[arc_index];
121 vcm = &cm->config_main;
Dave Barach2dd192b2018-11-19 09:31:48 -0500122 if ((error = vnet_feature_arc_init
123 (vm, vcm, areg->start_nodes, areg->n_start_nodes,
124 fm->next_feature_by_arc[arc_index],
125 fm->next_constraint_by_arc[arc_index],
126 &fm->feature_nodes[arc_index])))
Damjan Marion22311502016-10-28 20:30:15 +0200127 {
Florin Coras3d2a9142017-08-16 21:23:44 -0700128 clib_error_report (error);
129 os_exit (1);
Damjan Marion22311502016-10-28 20:30:15 +0200130 }
131
132 fm->next_feature_by_name[arc_index] =
133 hash_create_string (0, sizeof (uword));
134 freg = fm->next_feature_by_arc[arc_index];
135
136 while (freg)
137 {
138 hash_set_mem (fm->next_feature_by_name[arc_index],
139 freg->node_name, pointer_to_uword (freg));
Damjan Marion13adc3d2018-04-09 20:59:53 +0200140 freg = freg->next_in_arc;
Damjan Marion22311502016-10-28 20:30:15 +0200141 }
142
143 /* next */
144 areg = areg->next;
145 arc_index++;
146 }
147
148 return 0;
149}
150
151VLIB_INIT_FUNCTION (vnet_feature_init);
152
Damjan Marion87cd1192016-11-04 11:00:27 +0100153u8
154vnet_get_feature_arc_index (const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200155{
156 vnet_feature_main_t *fm = &feature_main;
157 vnet_feature_arc_registration_t *reg;
158 uword *p;
159
160 p = hash_get_mem (fm->arc_index_by_name, s);
161 if (p == 0)
162 return ~0;
163
164 reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
165 return reg->feature_arc_index;
166}
167
Pavel Kotucek7490a752016-11-15 09:19:11 +0100168vnet_feature_registration_t *
169vnet_get_feature_reg (const char *arc_name, const char *node_name)
170{
171 u8 arc_index;
172
173 arc_index = vnet_get_feature_arc_index (arc_name);
174 if (arc_index == (u8) ~ 0)
175 return 0;
176
177 vnet_feature_main_t *fm = &feature_main;
178 vnet_feature_registration_t *reg;
179 uword *p;
180
181 p = hash_get_mem (fm->next_feature_by_name[arc_index], node_name);
182 if (p == 0)
183 return 0;
184
185 reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
186 return reg;
187}
188
Damjan Marion22311502016-10-28 20:30:15 +0200189u32
Damjan Marion87cd1192016-11-04 11:00:27 +0100190vnet_get_feature_index (u8 arc, const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200191{
192 vnet_feature_main_t *fm = &feature_main;
193 vnet_feature_registration_t *reg;
194 uword *p;
195
Damjan Marion21da6ce2016-11-28 18:21:59 +0100196 if (s == 0)
197 return ~0;
198
Damjan Marion22311502016-10-28 20:30:15 +0200199 p = hash_get_mem (fm->next_feature_by_name[arc], s);
200 if (p == 0)
201 return ~0;
202
203 reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
Damjan Marion8b3191e2016-11-09 19:54:20 +0100204 return reg->feature_index;
Damjan Marion22311502016-10-28 20:30:15 +0200205}
206
Damjan Marion96b41f72016-11-10 18:01:42 +0100207int
Damjan Marion8b3191e2016-11-09 19:54:20 +0100208vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
209 u32 sw_if_index, int enable_disable,
210 void *feature_config,
211 u32 n_feature_config_bytes)
Damjan Marion22311502016-10-28 20:30:15 +0200212{
213 vnet_feature_main_t *fm = &feature_main;
214 vnet_feature_config_main_t *cm;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100215 i16 feature_count;
Matthew Smithc3267ed2018-05-15 15:51:30 -0500216 u32 ci;
Damjan Marion22311502016-10-28 20:30:15 +0200217
Damjan Marion05bb1dd2016-11-08 21:28:22 +0100218 if (arc_index == (u8) ~ 0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100219 return VNET_API_ERROR_INVALID_VALUE;
Damjan Marion22311502016-10-28 20:30:15 +0200220
Damjan Marion22311502016-10-28 20:30:15 +0200221 if (feature_index == ~0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100222 return VNET_API_ERROR_INVALID_VALUE_2;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100223
224 cm = &fm->feature_config_mains[arc_index];
225 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
Matthew Smithc3267ed2018-05-15 15:51:30 -0500226 ci = cm->config_index_by_sw_if_index[sw_if_index];
Damjan Marion22311502016-10-28 20:30:15 +0200227
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100228 vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
Damjan Marion21da6ce2016-11-28 18:21:59 +0100229 feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
230
231 if (!enable_disable && feature_count < 1)
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100232 return 0;
233
Damjan Marion22311502016-10-28 20:30:15 +0200234 ci = (enable_disable
235 ? vnet_config_add_feature
236 : vnet_config_del_feature)
237 (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
238 n_feature_config_bytes);
Matthew Smithc3267ed2018-05-15 15:51:30 -0500239 if (ci == ~0)
Klement Sekera3ecc2212018-03-27 10:34:43 +0200240 {
241 return 0;
242 }
Damjan Marion22311502016-10-28 20:30:15 +0200243 cm->config_index_by_sw_if_index[sw_if_index] = ci;
244
Damjan Marion21da6ce2016-11-28 18:21:59 +0100245 /* update feature count */
246 enable_disable = (enable_disable > 0);
247 feature_count += enable_disable ? 1 : -1;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100248 ASSERT (feature_count >= 0);
Damjan Marion22311502016-10-28 20:30:15 +0200249
Damjan Marion21da6ce2016-11-28 18:21:59 +0100250 fm->sw_if_index_has_features[arc_index] =
251 clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index,
252 (feature_count > 0));
Neale Rannsb069a692017-03-15 12:34:25 -0400253 adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
Damjan Marion21da6ce2016-11-28 18:21:59 +0100254
255 fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
Damjan Marion96b41f72016-11-10 18:01:42 +0100256 return 0;
Damjan Marion22311502016-10-28 20:30:15 +0200257}
258
Damjan Marion8b3191e2016-11-09 19:54:20 +0100259int
260vnet_feature_enable_disable (const char *arc_name, const char *node_name,
261 u32 sw_if_index, int enable_disable,
262 void *feature_config, u32 n_feature_config_bytes)
263{
264 u32 feature_index;
265 u8 arc_index;
266
267 arc_index = vnet_get_feature_arc_index (arc_name);
268
269 if (arc_index == (u8) ~ 0)
270 return VNET_API_ERROR_INVALID_VALUE;
271
272 feature_index = vnet_get_feature_index (arc_index, node_name);
273
274 return vnet_feature_enable_disable_with_index (arc_index, feature_index,
275 sw_if_index, enable_disable,
276 feature_config,
277 n_feature_config_bytes);
278}
279
Dave Barach525c9d02018-05-26 10:48:55 -0400280static int
281feature_cmp (void *a1, void *a2)
282{
283 vnet_feature_registration_t *reg1 = a1;
284 vnet_feature_registration_t *reg2 = a2;
285
286 return (int) reg1->feature_index - reg2->feature_index;
287}
Damjan Marion22311502016-10-28 20:30:15 +0200288
289/** Display the set of available driver features.
290 Useful for verifying that expected features are present
291*/
292
293static clib_error_t *
294show_features_command_fn (vlib_main_t * vm,
295 unformat_input_t * input, vlib_cli_command_t * cmd)
296{
297 vnet_feature_main_t *fm = &feature_main;
298 vnet_feature_arc_registration_t *areg;
299 vnet_feature_registration_t *freg;
Dave Barach525c9d02018-05-26 10:48:55 -0400300 vnet_feature_registration_t *feature_regs = 0;
301 int verbose = 0;
302
303 if (unformat (input, "verbose"))
304 verbose = 1;
Damjan Marion22311502016-10-28 20:30:15 +0200305
306 vlib_cli_output (vm, "Available feature paths");
307
308 areg = fm->next_arc;
309 while (areg)
310 {
Dave Barach525c9d02018-05-26 10:48:55 -0400311 if (verbose)
312 vlib_cli_output (vm, "[%2d] %s:", areg->feature_arc_index,
313 areg->arc_name);
314 else
315 vlib_cli_output (vm, "%s:", areg->arc_name);
316
Damjan Marion96b41f72016-11-10 18:01:42 +0100317 freg = fm->next_feature_by_arc[areg->feature_arc_index];
318 while (freg)
319 {
Dave Barach525c9d02018-05-26 10:48:55 -0400320 vec_add1 (feature_regs, freg[0]);
Damjan Marion13adc3d2018-04-09 20:59:53 +0200321 freg = freg->next_in_arc;
Damjan Marion96b41f72016-11-10 18:01:42 +0100322 }
Damjan Marion22311502016-10-28 20:30:15 +0200323
Dave Barach525c9d02018-05-26 10:48:55 -0400324 vec_sort_with_function (feature_regs, feature_cmp);
Damjan Marion22311502016-10-28 20:30:15 +0200325
Dave Barach525c9d02018-05-26 10:48:55 -0400326 vec_foreach (freg, feature_regs)
327 {
328 if (verbose)
329 vlib_cli_output (vm, " [%2d]: %s\n", freg->feature_index,
330 freg->node_name);
331 else
332 vlib_cli_output (vm, " %s\n", freg->node_name);
333 }
334 vec_reset_length (feature_regs);
Damjan Marion22311502016-10-28 20:30:15 +0200335 /* next */
336 areg = areg->next;
337 }
Dave Barach525c9d02018-05-26 10:48:55 -0400338 vec_free (feature_regs);
Damjan Marion22311502016-10-28 20:30:15 +0200339
340 return 0;
341}
342
343/*?
344 * Display the set of available driver features
345 *
346 * @cliexpar
347 * Example:
Dave Barach525c9d02018-05-26 10:48:55 -0400348 * @cliexcmd{show features [verbose]}
Damjan Marion22311502016-10-28 20:30:15 +0200349 * @cliexend
350 * @endparblock
351?*/
352/* *INDENT-OFF* */
353VLIB_CLI_COMMAND (show_features_command, static) = {
354 .path = "show features",
355 .short_help = "show features",
356 .function = show_features_command_fn,
357};
358/* *INDENT-ON* */
359
360/** Display the set of driver features configured on a specific interface
361 * Called by "show interface" handler
362 */
363
364void
Dave Barach525c9d02018-05-26 10:48:55 -0400365vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose)
Damjan Marion22311502016-10-28 20:30:15 +0200366{
367 vnet_feature_main_t *fm = &feature_main;
368 u32 node_index, current_config_index;
369 u16 feature_arc;
370 vnet_feature_config_main_t *cm = fm->feature_config_mains;
371 vnet_feature_arc_registration_t *areg;
372 vnet_config_main_t *vcm;
373 vnet_config_t *cfg;
374 u32 cfg_index;
375 vnet_config_feature_t *feat;
376 vlib_node_t *n;
377 int i;
378
Dave Barach525c9d02018-05-26 10:48:55 -0400379 vlib_cli_output (vm, "Feature paths configured on %U...",
Damjan Marion22311502016-10-28 20:30:15 +0200380 format_vnet_sw_if_index_name,
381 vnet_get_main (), sw_if_index);
382
383 areg = fm->next_arc;
384 while (areg)
385 {
386 feature_arc = areg->feature_arc_index;
387 vcm = &(cm[feature_arc].config_main);
388
389 vlib_cli_output (vm, "\n%s:", areg->arc_name);
390 areg = areg->next;
391
392 if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
Damjan Marion87cd1192016-11-04 11:00:27 +0100393 vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
394 sw_if_index)
Damjan Marion22311502016-10-28 20:30:15 +0200395 {
396 vlib_cli_output (vm, " none configured");
397 continue;
398 }
399
400 current_config_index =
401 vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
402
403 if (current_config_index == ~0)
404 {
405 vlib_cli_output (vm, " none configured");
406 continue;
407 }
408
409 ASSERT (current_config_index
410 < vec_len (vcm->config_pool_index_by_user_index));
411
412 cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
413 cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
414
415 for (i = 0; i < vec_len (cfg->features); i++)
416 {
417 feat = cfg->features + i;
418 node_index = feat->node_index;
419 n = vlib_get_node (vm, node_index);
Dave Barach525c9d02018-05-26 10:48:55 -0400420 if (verbose)
421 vlib_cli_output (vm, " [%2d] %v", feat->feature_index, n->name);
422 else
423 vlib_cli_output (vm, " %v", n->name);
Damjan Marion22311502016-10-28 20:30:15 +0200424 }
425 }
426}
427
Pavel Kotucek7490a752016-11-15 09:19:11 +0100428static clib_error_t *
429set_interface_features_command_fn (vlib_main_t * vm,
430 unformat_input_t * input,
431 vlib_cli_command_t * cmd)
432{
433 vnet_main_t *vnm = vnet_get_main ();
434 unformat_input_t _line_input, *line_input = &_line_input;
435 clib_error_t *error = 0;
436
437 u8 *arc_name = 0;
438 u8 *feature_name = 0;
439 u32 sw_if_index = ~0;
440 u8 enable = 1;
441
442 /* Get a line of input. */
443 if (!unformat_user (input, unformat_line_input, line_input))
Paul Vinciguerra3b4a6a12018-10-02 19:02:16 -0700444 return 0;
Pavel Kotucek7490a752016-11-15 09:19:11 +0100445
446 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
447 {
448 if (unformat
449 (line_input, "%U %v", unformat_vnet_sw_interface, vnm, &sw_if_index,
450 &feature_name))
451 ;
452 else if (unformat (line_input, "arc %v", &arc_name))
453 ;
454 else if (unformat (line_input, "disable"))
455 enable = 0;
456 else
457 {
Dave Barach525c9d02018-05-26 10:48:55 -0400458 if (feature_name && arc_name)
459 break;
Pavel Kotucek7490a752016-11-15 09:19:11 +0100460 error = unformat_parse_error (line_input);
461 goto done;
462 }
463 }
464
465 if (sw_if_index == ~0)
466 {
467 error = clib_error_return (0, "Interface not specified...");
468 goto done;
469 }
470
471 vec_add1 (arc_name, 0);
472 vec_add1 (feature_name, 0);
473
474 vnet_feature_registration_t *reg;
475 reg =
476 vnet_get_feature_reg ((const char *) arc_name,
477 (const char *) feature_name);
478 if (reg == 0)
479 {
480 error = clib_error_return (0, "Unknown feature...");
481 goto done;
482 }
483 if (reg->enable_disable_cb)
484 error = reg->enable_disable_cb (sw_if_index, enable);
485 if (!error)
486 vnet_feature_enable_disable ((const char *) arc_name,
487 (const char *) feature_name, sw_if_index,
488 enable, 0, 0);
489
490done:
491 vec_free (feature_name);
492 vec_free (arc_name);
Billy McFall614c1312017-03-01 17:01:06 -0500493 unformat_free (line_input);
Pavel Kotucek7490a752016-11-15 09:19:11 +0100494 return error;
495}
496
497/*?
498 * Set feature for given interface
499 *
500 * @cliexpar
501 * Example:
502 * @cliexcmd{set interface feature GigabitEthernet2/0/0 ip4_flow_classify arc ip4_unicast}
503 * @cliexend
504 * @endparblock
505?*/
506/* *INDENT-OFF* */
507VLIB_CLI_COMMAND (set_interface_feature_command, static) = {
508 .path = "set interface feature",
Pierre Pfister1bfd3722017-09-18 11:40:32 +0200509 .short_help = "set interface feature <intfc> <feature_name> arc <arc_name> "
510 "[disable]",
Pavel Kotucek7490a752016-11-15 09:19:11 +0100511 .function = set_interface_features_command_fn,
512};
513/* *INDENT-ON* */
514
Damjan Marion22311502016-10-28 20:30:15 +0200515/*
516 * fd.io coding-style-patch-verification: ON
517 *
518 * Local Variables:
519 * eval: (c-set-style "gnu")
520 * End:
521 */