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;
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_UNICAST)
73 first_reg = im4->next_uc_feature;
75 first_reg = im6->next_uc_feature;
80 first_reg = im4->next_mc_feature;
82 first_reg = im6->next_mc_feature;
87 /* pass 1, collect feature node names, construct a before b pairs */
90 node_name = format (0, "%s%c", this_reg->node_name, 0);
91 hash_set (reg_by_index, vec_len(node_names), (uword) this_reg);
93 hash_set_mem (index_by_name, node_name, vec_len(node_names));
95 vec_add1 (node_names, node_name);
97 these_constraints = this_reg->runs_before;
99 while (these_constraints [0])
101 this_constraint_c = these_constraints[0];
103 constraint_tuple = format (0, "%s,%s%c", node_name,
104 this_constraint_c, 0);
105 vec_add1 (constraints, constraint_tuple);
108 this_reg = this_reg->next;
111 n_features = vec_len (node_names);
112 orig = clib_ptclosure_alloc (n_features);
114 for (i = 0; i < vec_len (constraints); i++)
116 this_constraint = constraints[i];
118 if (comma_split (this_constraint, &a_name, &b_name))
119 return clib_error_return (0, "comma_split failed!");
121 p = hash_get_mem (index_by_name, a_name);
123 * Note: the next two errors mean that the xxx_FEATURE_INIT macros are
124 * b0rked. As in: if you code "A depends on B," and you forget
125 * to define a FEATURE_INIT macro for B, you lose.
126 * Nonexistent graph nodes are tolerated.
129 return clib_error_return (0, "feature node '%s' not found", a_name);
132 p = hash_get_mem (index_by_name, b_name);
134 return clib_error_return (0, "feature node '%s' not found", b_name);
137 /* add a before b to the original set of constraints */
138 orig[a_index][b_index] = 1;
139 vec_free (this_constraint);
142 /* Compute the positive transitive closure of the original constraints */
143 closure = clib_ptclosure (orig);
145 /* Compute a partial order across feature nodes, if one exists. */
147 for (i = 0; i < n_features; i++)
149 for (j = 0; j < n_features; j++)
152 goto item_constrained;
154 /* Item i can be output */
155 vec_add1 (result, i);
157 for (k = 0; k < n_features; k++)
160 * Add a "Magic" a before a constraint.
161 * This means we'll never output it again
170 /* see if we got a partial order... */
171 if (vec_len (result) != n_features)
172 return clib_error_return
173 (0, "ip%s_feature_init_cast (cast=%d), no partial order!",
174 is_ip4 ? "4" : "6", cast);
178 * Bind the index variables, and output the feature node name vector
179 * using the partial order we just computed. Result is in stack
180 * order, because the entry with the fewest constraints (e.g. none)
181 * is output first, etc.
184 for (i = n_features-1; i >= 0; i--)
186 p = hash_get (reg_by_index, result[i]);
188 this_reg = (vnet_ip_feature_registration_t *)p[0];
189 *this_reg->feature_index = n_features - (i+1);
190 vec_add1 (feature_nodes, this_reg->node_name);
193 /* Set up the config infrastructure */
194 vnet_config_init (vm, vcm,
196 num_feature_start_nodes,
198 vec_len(feature_nodes));
200 /* Save a copy for show command */
202 im4->feature_nodes[cast] = feature_nodes;
204 im6->feature_nodes[cast] = feature_nodes;
206 /* Finally, clean up all the shit we allocated */
207 hash_foreach_pair (hp, index_by_name,
209 vec_add1 (keys_to_delete, (u8 *)hp->key);
211 hash_free (index_by_name);
212 for (i = 0; i < vec_len(keys_to_delete); i++)
213 vec_free (keys_to_delete[i]);
214 vec_free (keys_to_delete);
215 hash_free (reg_by_index);
217 clib_ptclosure_free (orig);
218 clib_ptclosure_free (closure);
222 #define foreach_af_cast \
223 _(4, VNET_UNICAST, "ip4 unicast") \
224 _(4, VNET_MULTICAST, "ip4 multicast") \
225 _(6, VNET_UNICAST, "ip6 unicast") \
226 _(6, VNET_MULTICAST, "ip6 multicast")
228 static clib_error_t *
229 show_ip_features_command_fn (vlib_main_t * vm,
230 unformat_input_t * input,
231 vlib_cli_command_t * cmd)
233 ip4_main_t * im4 = &ip4_main;
234 ip6_main_t * im6 = &ip6_main;
238 vlib_cli_output (vm, "Available IP feature nodes");
242 features = im##a->feature_nodes[c]; \
243 vlib_cli_output (vm, "%s:", s); \
244 for (i = 0; i < vec_len(features); i++) \
245 vlib_cli_output (vm, " %s\n", features[i]); \
253 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
254 .path = "show ip features",
255 .short_help = "show ip features",
256 .function = show_ip_features_command_fn,
259 static clib_error_t *
260 show_ip_interface_features_command_fn (vlib_main_t * vm,
261 unformat_input_t * input,
262 vlib_cli_command_t * cmd)
264 vnet_main_t * vnm = vnet_get_main();
265 ip4_main_t * im4 = &ip4_main;
266 ip_lookup_main_t * lm4 = &im4->lookup_main;
267 ip6_main_t * im6 = &ip6_main;
268 ip_lookup_main_t * lm6 = &im6->lookup_main;
270 ip_lookup_main_t * lm;
271 ip_config_main_t * cm;
272 vnet_config_main_t * vcm;
275 vnet_config_feature_t * feat;
279 u32 current_config_index;
283 if (! unformat (input, "%U", unformat_vnet_sw_interface,
285 return clib_error_return (0, "Interface not specified...");
287 vlib_cli_output (vm, "IP feature paths configured on %U...",
288 format_vnet_sw_if_index_name, vnm, sw_if_index);
291 for (af = 0; af < 2; af++)
298 for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
300 cm = lm->rx_config_mains + cast;
301 vcm = &cm->config_main;
303 vlib_cli_output (vm, "\nipv%s %scast:",
304 (af == 0) ? "4" : "6",
305 cast == VNET_UNICAST ?
308 current_config_index = vec_elt (cm->config_index_by_sw_if_index,
311 ASSERT(current_config_index
312 < vec_len (vcm->config_pool_index_by_user_index));
315 vcm->config_pool_index_by_user_index[current_config_index];
316 cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
318 for (i = 0; i < vec_len(cfg->features); i++)
320 feat = cfg->features + i;
321 node_index = feat->node_index;
322 n = vlib_get_node (vm, node_index);
323 vlib_cli_output (vm, " %v", n->name);
331 VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
332 .path = "show ip interface features",
333 .short_help = "show ip interface features <intfc>",
334 .function = show_ip_interface_features_command_fn,