blob: f0e9004c64da93e4ac591d0b636d3d28ebaef01b [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)
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
Damjan Marion96b41f72016-11-10 18:01:42 +010074 next = freg->next;
75 freg->next = fm->next_feature_by_arc[arc_index];
76 fm->next_feature_by_arc[arc_index] = freg;
Damjan Marion22311502016-10-28 20:30:15 +020077
78 /* next */
Damjan Marion96b41f72016-11-10 18:01:42 +010079 freg = next;
Damjan Marion22311502016-10-28 20:30:15 +020080 }
81
Damjan Marion96b41f72016-11-10 18:01:42 +010082 areg = fm->next_arc;
Damjan Marion22311502016-10-28 20:30:15 +020083 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
120VLIB_INIT_FUNCTION (vnet_feature_init);
121
Damjan Marion87cd1192016-11-04 11:00:27 +0100122u8
123vnet_get_feature_arc_index (const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200124{
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
Pavel Kotucek7490a752016-11-15 09:19:11 +0100137vnet_feature_registration_t *
138vnet_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
Damjan Marion22311502016-10-28 20:30:15 +0200158u32
Damjan Marion87cd1192016-11-04 11:00:27 +0100159vnet_get_feature_index (u8 arc, const char *s)
Damjan Marion22311502016-10-28 20:30:15 +0200160{
161 vnet_feature_main_t *fm = &feature_main;
162 vnet_feature_registration_t *reg;
163 uword *p;
164
Damjan Marion21da6ce2016-11-28 18:21:59 +0100165 if (s == 0)
166 return ~0;
167
Damjan Marion22311502016-10-28 20:30:15 +0200168 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 *);
Damjan Marion8b3191e2016-11-09 19:54:20 +0100173 return reg->feature_index;
Damjan Marion22311502016-10-28 20:30:15 +0200174}
175
Damjan Marion96b41f72016-11-10 18:01:42 +0100176int
Damjan Marion8b3191e2016-11-09 19:54:20 +0100177vnet_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)
Damjan Marion22311502016-10-28 20:30:15 +0200181{
182 vnet_feature_main_t *fm = &feature_main;
183 vnet_feature_config_main_t *cm;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100184 i16 feature_count;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100185 u32 ci;
Damjan Marion22311502016-10-28 20:30:15 +0200186
Damjan Marion05bb1dd2016-11-08 21:28:22 +0100187 if (arc_index == (u8) ~ 0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100188 return VNET_API_ERROR_INVALID_VALUE;
Damjan Marion22311502016-10-28 20:30:15 +0200189
Damjan Marion22311502016-10-28 20:30:15 +0200190 if (feature_index == ~0)
Damjan Marion96b41f72016-11-10 18:01:42 +0100191 return VNET_API_ERROR_INVALID_VALUE_2;
Damjan Marion8b3191e2016-11-09 19:54:20 +0100192
193 cm = &fm->feature_config_mains[arc_index];
194 vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
Damjan Marion22311502016-10-28 20:30:15 +0200195 ci = cm->config_index_by_sw_if_index[sw_if_index];
196
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100197 vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
Damjan Marion21da6ce2016-11-28 18:21:59 +0100198 feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
199
200 if (!enable_disable && feature_count < 1)
Pavel Kotucekf6e3dc42016-11-04 09:58:01 +0100201 return 0;
202
Damjan Marion22311502016-10-28 20:30:15 +0200203 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
Damjan Marion21da6ce2016-11-28 18:21:59 +0100210 /* update feature count */
211 enable_disable = (enable_disable > 0);
212 feature_count += enable_disable ? 1 : -1;
Damjan Marion21da6ce2016-11-28 18:21:59 +0100213 ASSERT (feature_count >= 0);
Damjan Marion22311502016-10-28 20:30:15 +0200214
Damjan Marion21da6ce2016-11-28 18:21:59 +0100215 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));
Neale Rannsb069a692017-03-15 12:34:25 -0400218 adj_feature_update (sw_if_index, arc_index, (feature_count > 0));
Damjan Marion21da6ce2016-11-28 18:21:59 +0100219
220 fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
Damjan Marion96b41f72016-11-10 18:01:42 +0100221 return 0;
Damjan Marion22311502016-10-28 20:30:15 +0200222}
223
Damjan Marion8b3191e2016-11-09 19:54:20 +0100224int
225vnet_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
Damjan Marion22311502016-10-28 20:30:15 +0200245
246/** Display the set of available driver features.
247 Useful for verifying that expected features are present
248*/
249
250static clib_error_t *
251show_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);
Damjan Marion96b41f72016-11-10 18:01:42 +0100264 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 }
Damjan Marion22311502016-10-28 20:30:15 +0200270
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* */
289VLIB_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
300void
301vnet_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 ||
Damjan Marion87cd1192016-11-04 11:00:27 +0100329 vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
330 sw_if_index)
Damjan Marion22311502016-10-28 20:30:15 +0200331 {
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
Pavel Kotucek7490a752016-11-15 09:19:11 +0100361static clib_error_t *
362set_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
421done:
422 vec_free (feature_name);
423 vec_free (arc_name);
Billy McFall614c1312017-03-01 17:01:06 -0500424 unformat_free (line_input);
Pavel Kotucek7490a752016-11-15 09:19:11 +0100425 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* */
438VLIB_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
Damjan Marion22311502016-10-28 20:30:15 +0200445/*
446 * fd.io coding-style-patch-verification: ON
447 *
448 * Local Variables:
449 * eval: (c-set-style "gnu")
450 * End:
451 */