blob: ad4047e62b3dc399a676e7012a8cd4511fc70f42 [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;
78 freg->next = fm->next_feature_by_arc[arc_index];
79 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));
113 freg = freg->next;
114 }
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;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100189 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);
Damjan Marion22311502016-10-28 20:30:15 +0200199 ci = cm->config_index_by_sw_if_index[sw_if_index];
200
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);
212 cm->config_index_by_sw_if_index[sw_if_index] = ci;
213
Damjan Marion21da6ce2016-11-28 18:21:59 +0100214 /* update feature count */
215 enable_disable = (enable_disable > 0);
216 feature_count += enable_disable ? 1 : -1;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100217 ASSERT (feature_count >= 0);
Damjan Marion22311502016-10-28 20:30:15 +0200218
Damjan Marion21da6ce2016-11-28 18:21:59 +0100219 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));
Neale Rannsb069a692017-03-15 12:34:25 -0400222 adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
Damjan Marion21da6ce2016-11-28 18:21:59 +0100223
224 fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
Damjan Marion96b41f72016-11-10 18:01:42 +0100225 return 0;
Damjan Marion22311502016-10-28 20:30:15 +0200226}
227
Damjan Marion8b3191e2016-11-09 19:54:20 +0100228int
229vnet_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
Damjan Marion22311502016-10-28 20:30:15 +0200249
250/** Display the set of available driver features.
251 Useful for verifying that expected features are present
252*/
253
254static clib_error_t *
255show_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);
Damjan Marion96b41f72016-11-10 18:01:42 +0100268 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 }
Damjan Marion22311502016-10-28 20:30:15 +0200274
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* */
293VLIB_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
304void
305vnet_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 ||
Damjan Marion87cd1192016-11-04 11:00:27 +0100333 vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
334 sw_if_index)
Damjan Marion22311502016-10-28 20:30:15 +0200335 {
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
Pavel Kotucek7490a752016-11-15 09:19:11 +0100365static clib_error_t *
366set_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
425done:
426 vec_free (feature_name);
427 vec_free (arc_name);
Billy McFall614c1312017-03-01 17:01:06 -0500428 unformat_free (line_input);
Pavel Kotucek7490a752016-11-15 09:19:11 +0100429 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* */
442VLIB_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 .function = set_interface_features_command_fn,
446};
447/* *INDENT-ON* */
448
Damjan Marion22311502016-10-28 20:30:15 +0200449/*
450 * fd.io coding-style-patch-verification: ON
451 *
452 * Local Variables:
453 * eval: (c-set-style "gnu")
454 * End:
455 */