span: add feature (rx only) (VPP-185)
[vpp.git] / vnet / 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
18 vnet_feature_main_t feature_main;
19
20 static clib_error_t *
21 vnet_feature_init (vlib_main_t * vm)
22 {
23   vnet_feature_main_t *fm = &feature_main;
24   vnet_feature_registration_t *freg;
25   vnet_feature_arc_registration_t *areg;
26   u32 arc_index = 0;
27
28   fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
29   areg = fm->next_arc;
30
31   /* process feature arc registrations */
32   while (areg)
33     {
34       char *s;
35       int i = 0;
36       areg->feature_arc_index = arc_index;
37       if (areg->arc_index_ptr)
38         *areg->arc_index_ptr = arc_index;
39       hash_set_mem (fm->arc_index_by_name, areg->arc_name,
40                     pointer_to_uword (areg));
41
42       /* process start nodes */
43       while ((s = areg->start_nodes[i]))
44         {
45           i++;
46         }
47       areg->n_start_nodes = i;
48
49       /* next */
50       areg = areg->next;
51       arc_index++;
52     }
53
54   vec_validate (fm->next_feature_by_arc, arc_index - 1);
55   vec_validate (fm->feature_nodes, arc_index - 1);
56   vec_validate (fm->feature_config_mains, arc_index - 1);
57   vec_validate (fm->next_feature_by_name, arc_index - 1);
58   vec_validate (fm->sw_if_index_has_features, arc_index - 1);
59   vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
60
61   freg = fm->next_feature;
62   while (freg)
63     {
64       vnet_feature_registration_t *next;
65       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
66       if (p == 0)
67         return clib_error_return (0, "Unknown feature arc '%s'",
68                                   freg->arc_name);
69
70       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
71       arc_index = areg->feature_arc_index;
72
73       next = freg->next;
74       freg->next = fm->next_feature_by_arc[arc_index];
75       fm->next_feature_by_arc[arc_index] = freg;
76
77       /* next */
78       freg = next;
79     }
80
81   areg = fm->next_arc;
82   while (areg)
83     {
84       clib_error_t *error;
85       vnet_feature_config_main_t *cm;
86       vnet_config_main_t *vcm;
87
88       arc_index = areg->feature_arc_index;
89       cm = &fm->feature_config_mains[arc_index];
90       vcm = &cm->config_main;
91       if ((error = vnet_feature_arc_init (vm, vcm,
92                                           areg->start_nodes,
93                                           areg->n_start_nodes,
94                                           fm->next_feature_by_arc[arc_index],
95                                           &fm->feature_nodes[arc_index])))
96         {
97           return error;
98         }
99
100       fm->next_feature_by_name[arc_index] =
101         hash_create_string (0, sizeof (uword));
102       freg = fm->next_feature_by_arc[arc_index];
103
104       while (freg)
105         {
106           hash_set_mem (fm->next_feature_by_name[arc_index],
107                         freg->node_name, pointer_to_uword (freg));
108           freg = freg->next;
109         }
110
111       /* next */
112       areg = areg->next;
113       arc_index++;
114     }
115
116   return 0;
117 }
118
119 VLIB_INIT_FUNCTION (vnet_feature_init);
120
121 void
122 vnet_config_update_feature_count (vnet_feature_main_t * fm, u8 arc,
123                                   u32 sw_if_index, int is_add)
124 {
125   uword bit_value;
126
127   vec_validate (fm->feature_count_by_sw_if_index[arc], sw_if_index);
128
129   fm->feature_count_by_sw_if_index[arc][sw_if_index] += is_add ? 1 : -1;
130
131   ASSERT (fm->feature_count_by_sw_if_index[arc][sw_if_index] >= 0);
132
133   bit_value = fm->feature_count_by_sw_if_index[arc][sw_if_index] > 0;
134
135   fm->sw_if_index_has_features[arc] =
136     clib_bitmap_set (fm->sw_if_index_has_features[arc], sw_if_index,
137                      bit_value);
138 }
139
140 u8
141 vnet_get_feature_arc_index (const char *s)
142 {
143   vnet_feature_main_t *fm = &feature_main;
144   vnet_feature_arc_registration_t *reg;
145   uword *p;
146
147   p = hash_get_mem (fm->arc_index_by_name, s);
148   if (p == 0)
149     return ~0;
150
151   reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
152   return reg->feature_arc_index;
153 }
154
155 u32
156 vnet_get_feature_index (u8 arc, const char *s)
157 {
158   vnet_feature_main_t *fm = &feature_main;
159   vnet_feature_registration_t *reg;
160   uword *p;
161
162   p = hash_get_mem (fm->next_feature_by_name[arc], s);
163   if (p == 0)
164     return ~0;
165
166   reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
167   return reg->feature_index;
168 }
169
170 int
171 vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
172                                         u32 sw_if_index, int enable_disable,
173                                         void *feature_config,
174                                         u32 n_feature_config_bytes)
175 {
176   vnet_feature_main_t *fm = &feature_main;
177   vnet_feature_config_main_t *cm;
178   u32 ci;
179
180   if (arc_index == (u8) ~ 0)
181     return VNET_API_ERROR_INVALID_VALUE;
182
183   if (feature_index == ~0)
184     return VNET_API_ERROR_INVALID_VALUE_2;
185
186   cm = &fm->feature_config_mains[arc_index];
187   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
188   ci = cm->config_index_by_sw_if_index[sw_if_index];
189
190   vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
191   if (!enable_disable
192       && fm->feature_count_by_sw_if_index[arc_index][sw_if_index] < 1)
193     return 0;
194
195   ci = (enable_disable
196         ? vnet_config_add_feature
197         : vnet_config_del_feature)
198     (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
199      n_feature_config_bytes);
200   cm->config_index_by_sw_if_index[sw_if_index] = ci;
201
202   vnet_config_update_feature_count (fm, arc_index, sw_if_index,
203                                     enable_disable);
204
205   return 0;
206 }
207
208 int
209 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
210                              u32 sw_if_index, int enable_disable,
211                              void *feature_config, u32 n_feature_config_bytes)
212 {
213   u32 feature_index;
214   u8 arc_index;
215
216   arc_index = vnet_get_feature_arc_index (arc_name);
217
218   if (arc_index == (u8) ~ 0)
219     return VNET_API_ERROR_INVALID_VALUE;
220
221   feature_index = vnet_get_feature_index (arc_index, node_name);
222
223   return vnet_feature_enable_disable_with_index (arc_index, feature_index,
224                                                  sw_if_index, enable_disable,
225                                                  feature_config,
226                                                  n_feature_config_bytes);
227 }
228
229
230 /** Display the set of available driver features.
231     Useful for verifying that expected features are present
232 */
233
234 static clib_error_t *
235 show_features_command_fn (vlib_main_t * vm,
236                           unformat_input_t * input, vlib_cli_command_t * cmd)
237 {
238   vnet_feature_main_t *fm = &feature_main;
239   vnet_feature_arc_registration_t *areg;
240   vnet_feature_registration_t *freg;
241
242   vlib_cli_output (vm, "Available feature paths");
243
244   areg = fm->next_arc;
245   while (areg)
246     {
247       vlib_cli_output (vm, "%s:", areg->arc_name);
248       freg = fm->next_feature_by_arc[areg->feature_arc_index];
249       while (freg)
250         {
251           vlib_cli_output (vm, "  %s\n", freg->node_name);
252           freg = freg->next;
253         }
254
255
256       /* next */
257       areg = areg->next;
258     }
259
260   return 0;
261 }
262
263 /*?
264  * Display the set of available driver features
265  *
266  * @cliexpar
267  * Example:
268  * @cliexcmd{show ip features}
269  * @cliexend
270  * @endparblock
271 ?*/
272 /* *INDENT-OFF* */
273 VLIB_CLI_COMMAND (show_features_command, static) = {
274   .path = "show features",
275   .short_help = "show features",
276   .function = show_features_command_fn,
277 };
278 /* *INDENT-ON* */
279
280 /** Display the set of driver features configured on a specific interface
281   * Called by "show interface" handler
282  */
283
284 void
285 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index)
286 {
287   vnet_feature_main_t *fm = &feature_main;
288   u32 node_index, current_config_index;
289   u16 feature_arc;
290   vnet_feature_config_main_t *cm = fm->feature_config_mains;
291   vnet_feature_arc_registration_t *areg;
292   vnet_config_main_t *vcm;
293   vnet_config_t *cfg;
294   u32 cfg_index;
295   vnet_config_feature_t *feat;
296   vlib_node_t *n;
297   int i;
298
299   vlib_cli_output (vm, "Driver feature paths configured on %U...",
300                    format_vnet_sw_if_index_name,
301                    vnet_get_main (), sw_if_index);
302
303   areg = fm->next_arc;
304   while (areg)
305     {
306       feature_arc = areg->feature_arc_index;
307       vcm = &(cm[feature_arc].config_main);
308
309       vlib_cli_output (vm, "\n%s:", areg->arc_name);
310       areg = areg->next;
311
312       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
313           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
314           sw_if_index)
315         {
316           vlib_cli_output (vm, "  none configured");
317           continue;
318         }
319
320       current_config_index =
321         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
322
323       if (current_config_index == ~0)
324         {
325           vlib_cli_output (vm, "  none configured");
326           continue;
327         }
328
329       ASSERT (current_config_index
330               < vec_len (vcm->config_pool_index_by_user_index));
331
332       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
333       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
334
335       for (i = 0; i < vec_len (cfg->features); i++)
336         {
337           feat = cfg->features + i;
338           node_index = feat->node_index;
339           n = vlib_get_node (vm, node_index);
340           vlib_cli_output (vm, "  %v", n->name);
341         }
342     }
343 }
344
345 /*
346  * fd.io coding-style-patch-verification: ON
347  *
348  * Local Variables:
349  * eval: (c-set-style "gnu")
350  * End:
351  */