feature: fix init issue when multiple arc are present
[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           i++;
44         }
45       areg->n_start_nodes = i;
46
47       /* next */
48       areg = areg->next;
49       arc_index++;
50     }
51
52   vec_validate (fm->next_feature_by_arc, arc_index - 1);
53   vec_validate (fm->feature_nodes, arc_index - 1);
54   vec_validate (fm->feature_config_mains, arc_index - 1);
55   vec_validate (fm->next_feature_by_name, arc_index - 1);
56   vec_validate (fm->sw_if_index_has_features, arc_index - 1);
57   vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
58
59   freg = fm->next_feature;
60   while (freg)
61     {
62       vnet_feature_registration_t *next;
63       uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
64       if (p == 0)
65         return clib_error_return (0, "Unknown feature arc '%s'",
66                                   freg->arc_name);
67
68       areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
69       arc_index = areg->feature_arc_index;
70
71       next = freg->next;
72       freg->next = fm->next_feature_by_arc[arc_index];
73       fm->next_feature_by_arc[arc_index] = freg;
74
75       /* next */
76       freg = next;
77     }
78
79   areg = fm->next_arc;
80   while (areg)
81     {
82       clib_error_t *error;
83       vnet_feature_config_main_t *cm;
84       vnet_config_main_t *vcm;
85
86       arc_index = areg->feature_arc_index;
87       cm = &fm->feature_config_mains[arc_index];
88       vcm = &cm->config_main;
89       if ((error = vnet_feature_arc_init (vm, vcm,
90                                           areg->start_nodes,
91                                           areg->n_start_nodes,
92                                           fm->next_feature_by_arc[arc_index],
93                                           &fm->feature_nodes[arc_index])))
94         {
95           return error;
96         }
97
98       fm->next_feature_by_name[arc_index] =
99         hash_create_string (0, sizeof (uword));
100       freg = fm->next_feature_by_arc[arc_index];
101
102       while (freg)
103         {
104           hash_set_mem (fm->next_feature_by_name[arc_index],
105                         freg->node_name, pointer_to_uword (freg));
106           freg = freg->next;
107         }
108
109       /* next */
110       areg = areg->next;
111       arc_index++;
112     }
113
114   fm->device_input_feature_arc_index =
115     vnet_get_feature_arc_index ("device-input");
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_u32;
168 }
169
170 int
171 vnet_feature_enable_disable (const char *arc_name, const char *node_name,
172                              u32 sw_if_index, int enable_disable,
173                              void *feature_config, u32 n_feature_config_bytes)
174 {
175   vnet_feature_main_t *fm = &feature_main;
176   vnet_feature_config_main_t *cm;
177   u32 feature_index, ci;
178   u8 arc_index;
179
180   arc_index = vnet_get_feature_arc_index (arc_name);
181
182   if (arc_index == (u8) ~ 0)
183     return VNET_API_ERROR_INVALID_VALUE;
184
185   cm = &fm->feature_config_mains[arc_index];
186   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
187   feature_index = vnet_get_feature_index (arc_index, node_name);
188   if (feature_index == ~0)
189     return VNET_API_ERROR_INVALID_VALUE_2;
190   ci = cm->config_index_by_sw_if_index[sw_if_index];
191
192   ci = (enable_disable
193         ? vnet_config_add_feature
194         : vnet_config_del_feature)
195     (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config,
196      n_feature_config_bytes);
197   cm->config_index_by_sw_if_index[sw_if_index] = ci;
198
199   vnet_config_update_feature_count (fm, arc_index, sw_if_index,
200                                     enable_disable);
201
202   return 0;
203 }
204
205
206 /** Display the set of available driver features.
207     Useful for verifying that expected features are present
208 */
209
210 static clib_error_t *
211 show_features_command_fn (vlib_main_t * vm,
212                           unformat_input_t * input, vlib_cli_command_t * cmd)
213 {
214   vnet_feature_main_t *fm = &feature_main;
215   vnet_feature_arc_registration_t *areg;
216   vnet_feature_registration_t *freg;
217
218   vlib_cli_output (vm, "Available feature paths");
219
220   areg = fm->next_arc;
221   while (areg)
222     {
223       vlib_cli_output (vm, "%s:", areg->arc_name);
224       freg = fm->next_feature_by_arc[areg->feature_arc_index];
225       while (freg)
226         {
227           vlib_cli_output (vm, "  %s\n", freg->node_name);
228           freg = freg->next;
229         }
230
231
232       /* next */
233       areg = areg->next;
234     }
235
236   return 0;
237 }
238
239 /*?
240  * Display the set of available driver features
241  *
242  * @cliexpar
243  * Example:
244  * @cliexcmd{show ip features}
245  * @cliexend
246  * @endparblock
247 ?*/
248 /* *INDENT-OFF* */
249 VLIB_CLI_COMMAND (show_features_command, static) = {
250   .path = "show features",
251   .short_help = "show features",
252   .function = show_features_command_fn,
253 };
254 /* *INDENT-ON* */
255
256 /** Display the set of driver features configured on a specific interface
257   * Called by "show interface" handler
258  */
259
260 void
261 vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index)
262 {
263   vnet_feature_main_t *fm = &feature_main;
264   u32 node_index, current_config_index;
265   u16 feature_arc;
266   vnet_feature_config_main_t *cm = fm->feature_config_mains;
267   vnet_feature_arc_registration_t *areg;
268   vnet_config_main_t *vcm;
269   vnet_config_t *cfg;
270   u32 cfg_index;
271   vnet_config_feature_t *feat;
272   vlib_node_t *n;
273   int i;
274
275   vlib_cli_output (vm, "Driver feature paths configured on %U...",
276                    format_vnet_sw_if_index_name,
277                    vnet_get_main (), sw_if_index);
278
279   areg = fm->next_arc;
280   while (areg)
281     {
282       feature_arc = areg->feature_arc_index;
283       vcm = &(cm[feature_arc].config_main);
284
285       vlib_cli_output (vm, "\n%s:", areg->arc_name);
286       areg = areg->next;
287
288       if (NULL == cm[feature_arc].config_index_by_sw_if_index ||
289           vec_len (cm[feature_arc].config_index_by_sw_if_index) <=
290           sw_if_index)
291         {
292           vlib_cli_output (vm, "  none configured");
293           continue;
294         }
295
296       current_config_index =
297         vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
298
299       if (current_config_index == ~0)
300         {
301           vlib_cli_output (vm, "  none configured");
302           continue;
303         }
304
305       ASSERT (current_config_index
306               < vec_len (vcm->config_pool_index_by_user_index));
307
308       cfg_index = vcm->config_pool_index_by_user_index[current_config_index];
309       cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
310
311       for (i = 0; i < vec_len (cfg->features); i++)
312         {
313           feat = cfg->features + i;
314           node_index = feat->node_index;
315           n = vlib_get_node (vm, node_index);
316           vlib_cli_output (vm, "  %v", n->name);
317         }
318     }
319 }
320
321 /*
322  * fd.io coding-style-patch-verification: ON
323  *
324  * Local Variables:
325  * eval: (c-set-style "gnu")
326  * End:
327  */