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