2 * Copyright (c) 2015 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vnet/vnet.h>
17 #include <vnet/ip/ip.h>
19 static int comma_split (u8 *s, u8 **a, u8 **b)
23 while (*s && *s != ',')
36 ip_feature_init_cast (vlib_main_t * vm,
37 ip_config_main_t * cm,
38 vnet_config_main_t * vcm,
39 char **feature_start_nodes,
40 int num_feature_start_nodes,
44 uword * index_by_name;
48 char ** these_constraints;
49 char * this_constraint_c;
50 u8 ** constraints = 0;
51 u8 * constraint_tuple;
53 u8 ** orig, ** closure;
56 u8 * a_name, * b_name;
60 vnet_ip_feature_registration_t * this_reg, * first_reg = 0;
61 char ** feature_nodes = 0;
63 u8 ** keys_to_delete = 0;
64 ip4_main_t * im4 = &ip4_main;
65 ip6_main_t * im6 = &ip6_main;
67 index_by_name = hash_create_string (0, sizeof (uword));
68 reg_by_index = hash_create (0, sizeof (uword));
70 if (cast == VNET_IP_RX_UNICAST_FEAT)
73 first_reg = im4->next_uc_feature;
75 first_reg = im6->next_uc_feature;
77 else if (cast == VNET_IP_RX_MULTICAST_FEAT)
80 first_reg = im4->next_mc_feature;
82 first_reg = im6->next_mc_feature;
84 else if (cast == VNET_IP_TX_FEAT)
87 first_reg = im4->next_tx_feature;
89 first_reg = im6->next_tx_feature;
95 /* pass 1, collect feature node names, construct a before b pairs */
98 node_name = format (0, "%s%c", this_reg->node_name, 0);
99 hash_set (reg_by_index, vec_len(node_names), (uword) this_reg);
101 hash_set_mem (index_by_name, node_name, vec_len(node_names));
103 vec_add1 (node_names, node_name);
105 these_constraints = this_reg->runs_before;
106 while (these_constraints && these_constraints [0])
108 this_constraint_c = these_constraints[0];
110 constraint_tuple = format (0, "%s,%s%c", node_name,
111 this_constraint_c, 0);
112 vec_add1 (constraints, constraint_tuple);
116 these_constraints = this_reg->runs_after;
117 while (these_constraints && these_constraints [0])
119 this_constraint_c = these_constraints[0];
121 constraint_tuple = format (0, "%s,%s%c",
124 vec_add1 (constraints, constraint_tuple);
128 this_reg = this_reg->next;
131 n_features = vec_len (node_names);
132 orig = clib_ptclosure_alloc (n_features);
134 for (i = 0; i < vec_len (constraints); i++)
136 this_constraint = constraints[i];
138 if (comma_split (this_constraint, &a_name, &b_name))
139 return clib_error_return (0, "comma_split failed!");
141 p = hash_get_mem (index_by_name, a_name);
143 * Note: the next two errors mean that the xxx_FEATURE_INIT macros are
144 * b0rked. As in: if you code "A depends on B," and you forget
145 * to define a FEATURE_INIT macro for B, you lose.
146 * Nonexistent graph nodes are tolerated.
149 return clib_error_return (0, "feature node '%s' not found", a_name);
152 p = hash_get_mem (index_by_name, b_name);
154 return clib_error_return (0, "feature node '%s' not found", b_name);
157 /* add a before b to the original set of constraints */
158 orig[a_index][b_index] = 1;
159 vec_free (this_constraint);
162 /* Compute the positive transitive closure of the original constraints */
163 closure = clib_ptclosure (orig);
165 /* Compute a partial order across feature nodes, if one exists. */
167 for (i = 0; i < n_features; i++)
169 for (j = 0; j < n_features; j++)
172 goto item_constrained;
174 /* Item i can be output */
175 vec_add1 (result, i);
177 for (k = 0; k < n_features; k++)
180 * Add a "Magic" a before a constraint.
181 * This means we'll never output it again
190 /* see if we got a partial order... */
191 if (vec_len (result) != n_features)
192 return clib_error_return
193 (0, "ip%s_feature_init_cast (cast=%d), no partial order!",
194 is_ip4 ? "4" : "6", cast);
198 * Bind the index variables, and output the feature node name vector
199 * using the partial order we just computed. Result is in stack
200 * order, because the entry with the fewest constraints (e.g. none)
201 * is output first, etc.
204 for (i = n_features-1; i >= 0; i--)
206 p = hash_get (reg_by_index, result[i]);
208 this_reg = (vnet_ip_feature_registration_t *)p[0];
209 *this_reg->feature_index = n_features - (i+1);
210 vec_add1 (feature_nodes, this_reg->node_name);
213 /* Set up the config infrastructure */
214 vnet_config_init (vm, vcm,
216 num_feature_start_nodes,
218 vec_len(feature_nodes));
220 /* Save a copy for show command */
222 im4->feature_nodes[cast] = feature_nodes;
224 im6->feature_nodes[cast] = feature_nodes;
226 /* Finally, clean up all the shit we allocated */
227 hash_foreach_pair (hp, index_by_name,
229 vec_add1 (keys_to_delete, (u8 *)hp->key);
231 hash_free (index_by_name);
232 for (i = 0; i < vec_len(keys_to_delete); i++)
233 vec_free (keys_to_delete[i]);
234 vec_free (keys_to_delete);
235 hash_free (reg_by_index);
237 clib_ptclosure_free (orig);
238 clib_ptclosure_free (closure);
242 #define foreach_af_cast \
243 _(4, VNET_IP_RX_UNICAST_FEAT, "ip4 unicast") \
244 _(4, VNET_IP_RX_MULTICAST_FEAT, "ip4 multicast") \
245 _(4, VNET_IP_TX_FEAT, "ip4 output") \
246 _(6, VNET_IP_RX_UNICAST_FEAT, "ip6 unicast") \
247 _(6, VNET_IP_RX_MULTICAST_FEAT, "ip6 multicast") \
248 _(6, VNET_IP_TX_FEAT, "ip6 output")
250 static clib_error_t *
251 show_ip_features_command_fn (vlib_main_t * vm,
252 unformat_input_t * input,
253 vlib_cli_command_t * cmd)
255 ip4_main_t * im4 = &ip4_main;
256 ip6_main_t * im6 = &ip6_main;
260 vlib_cli_output (vm, "Available IP feature nodes");
264 features = im##a->feature_nodes[c]; \
265 vlib_cli_output (vm, "%s:", s); \
266 for (i = 0; i < vec_len(features); i++) \
267 vlib_cli_output (vm, " %s\n", features[i]); \
275 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
276 .path = "show ip features",
277 .short_help = "show ip features",
278 .function = show_ip_features_command_fn,
281 static clib_error_t *
282 show_ip_interface_features_command_fn (vlib_main_t * vm,
283 unformat_input_t * input,
284 vlib_cli_command_t * cmd)
286 vnet_main_t * vnm = vnet_get_main();
287 ip4_main_t * im4 = &ip4_main;
288 ip_lookup_main_t * lm4 = &im4->lookup_main;
289 ip6_main_t * im6 = &ip6_main;
290 ip_lookup_main_t * lm6 = &im6->lookup_main;
292 ip_lookup_main_t * lm;
293 ip_config_main_t * cm;
294 vnet_config_main_t * vcm;
297 vnet_config_feature_t * feat;
301 u32 current_config_index;
305 if (! unformat (input, "%U", unformat_vnet_sw_interface,
307 return clib_error_return (0, "Interface not specified...");
309 vlib_cli_output (vm, "IP feature paths configured on %U...",
310 format_vnet_sw_if_index_name, vnm, sw_if_index);
313 for (af = 0; af < 2; af++)
320 for (cast = VNET_IP_RX_UNICAST_FEAT; cast < VNET_N_IP_FEAT; cast++)
322 cm = lm->feature_config_mains + cast;
323 vcm = &cm->config_main;
325 vlib_cli_output (vm, "\nipv%s %scast:",
326 (af == 0) ? "4" : "6",
327 cast == VNET_IP_RX_UNICAST_FEAT ?
330 current_config_index = vec_elt (cm->config_index_by_sw_if_index,
333 ASSERT(current_config_index
334 < vec_len (vcm->config_pool_index_by_user_index));
337 vcm->config_pool_index_by_user_index[current_config_index];
338 cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
340 for (i = 0; i < vec_len(cfg->features); i++)
342 feat = cfg->features + i;
343 node_index = feat->node_index;
344 n = vlib_get_node (vm, node_index);
345 vlib_cli_output (vm, " %v", n->name);
353 VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
354 .path = "show ip interface features",
355 .short_help = "show ip interface features <intfc>",
356 .function = show_ip_interface_features_command_fn,