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 return clib_error_return (0, "feature node '%s' not found", a_name);
126 p = hash_get_mem (index_by_name, b_name);
128 return clib_error_return (0, "feature node '%s' not found", b_name);
131 /* add a before b to the original set of constraints */
132 orig[a_index][b_index] = 1;
133 vec_free (this_constraint);
136 /* Compute the positive transitive closure of the original constraints */
137 closure = clib_ptclosure (orig);
139 /* Compute a partial order across feature nodes, if one exists. */
141 for (i = 0; i < n_features; i++)
143 for (j = 0; j < n_features; j++)
146 goto item_constrained;
148 /* Item i can be output */
149 vec_add1 (result, i);
151 for (k = 0; k < n_features; k++)
154 * Add a "Magic" a before a constraint.
155 * This means we'll never output it again
164 /* see if we got a partial order... */
165 if (vec_len (result) != n_features)
166 return clib_error_return
167 (0, "ip%s_feature_init_cast (cast=%d), no partial order!",
168 is_ip4 ? "4" : "6", cast);
172 * Bind the index variables, and output the feature node name vector
173 * using the partial order we just computed. Result is in stack
174 * order, because the entry with the fewest constraints (e.g. none)
175 * is output first, etc.
178 for (i = n_features-1; i >= 0; i--)
180 p = hash_get (reg_by_index, result[i]);
182 this_reg = (vnet_ip_feature_registration_t *)p[0];
183 *this_reg->feature_index = n_features - (i+1);
184 vec_add1 (feature_nodes, this_reg->node_name);
187 /* Set up the config infrastructure */
188 vnet_config_init (vm, vcm,
190 num_feature_start_nodes,
192 vec_len(feature_nodes));
194 /* Save a copy for show command */
196 im4->feature_nodes[cast] = feature_nodes;
198 im6->feature_nodes[cast] = feature_nodes;
200 /* Finally, clean up all the shit we allocated */
201 hash_foreach_pair (hp, index_by_name,
203 vec_add1 (keys_to_delete, (u8 *)hp->key);
205 hash_free (index_by_name);
206 for (i = 0; i < vec_len(keys_to_delete); i++)
207 vec_free (keys_to_delete[i]);
208 vec_free (keys_to_delete);
209 hash_free (reg_by_index);
211 clib_ptclosure_free (orig);
212 clib_ptclosure_free (closure);
216 #define foreach_af_cast \
217 _(4, VNET_UNICAST, "ip4 unicast") \
218 _(4, VNET_MULTICAST, "ip4 multicast") \
219 _(6, VNET_UNICAST, "ip6 unicast") \
220 _(6, VNET_MULTICAST, "ip6 multicast")
222 static clib_error_t *
223 show_ip_features_command_fn (vlib_main_t * vm,
224 unformat_input_t * input,
225 vlib_cli_command_t * cmd)
227 ip4_main_t * im4 = &ip4_main;
228 ip6_main_t * im6 = &ip6_main;
232 vlib_cli_output (vm, "Available IP feature nodes");
236 features = im##a->feature_nodes[c]; \
237 vlib_cli_output (vm, "%s:", s); \
238 for (i = 0; i < vec_len(features); i++) \
239 vlib_cli_output (vm, " %s\n", features[i]); \
247 VLIB_CLI_COMMAND (show_ip_features_command, static) = {
248 .path = "show ip features",
249 .short_help = "show ip features",
250 .function = show_ip_features_command_fn,
253 static clib_error_t *
254 show_ip_interface_features_command_fn (vlib_main_t * vm,
255 unformat_input_t * input,
256 vlib_cli_command_t * cmd)
258 vnet_main_t * vnm = vnet_get_main();
259 ip4_main_t * im4 = &ip4_main;
260 ip_lookup_main_t * lm4 = &im4->lookup_main;
261 ip6_main_t * im6 = &ip6_main;
262 ip_lookup_main_t * lm6 = &im6->lookup_main;
264 ip_lookup_main_t * lm;
265 ip_config_main_t * cm;
266 vnet_config_main_t * vcm;
269 vnet_config_feature_t * feat;
273 u32 current_config_index;
277 if (! unformat (input, "%U", unformat_vnet_sw_interface,
279 return clib_error_return (0, "Interface not specified...");
281 vlib_cli_output (vm, "IP feature paths configured on %U...",
282 format_vnet_sw_if_index_name, vnm, sw_if_index);
285 for (af = 0; af < 2; af++)
292 for (cast = VNET_UNICAST; cast < VNET_N_CAST; cast++)
294 cm = lm->rx_config_mains + cast;
295 vcm = &cm->config_main;
297 vlib_cli_output (vm, "\nipv%s %scast:",
298 (af == 0) ? "4" : "6",
299 cast == VNET_UNICAST ?
302 current_config_index = vec_elt (cm->config_index_by_sw_if_index,
305 ASSERT(current_config_index
306 < vec_len (vcm->config_pool_index_by_user_index));
309 vcm->config_pool_index_by_user_index[current_config_index];
310 cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
312 for (i = 0; i < vec_len(cfg->features); i++)
314 feat = cfg->features + i;
315 node_index = feat->node_index;
316 n = vlib_get_node (vm, node_index);
317 vlib_cli_output (vm, " %v", n->name);
325 VLIB_CLI_COMMAND (show_ip_interface_features_command, static) = {
326 .path = "show ip interface features",
327 .short_help = "show ip interface features <intfc>",
328 .function = show_ip_interface_features_command_fn,