summaryrefslogtreecommitdiffstats
path: root/vnet/vnet/ip/ip_feature_registration.c
diff options
context:
space:
mode:
Diffstat (limited to 'vnet/vnet/ip/ip_feature_registration.c')
-rw-r--r--vnet/vnet/ip/ip_feature_registration.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/vnet/vnet/ip/ip_feature_registration.c b/vnet/vnet/ip/ip_feature_registration.c
new file mode 100644
index 00000000000..02699c4f087
--- /dev/null
+++ b/vnet/vnet/ip/ip_feature_registration.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+
+static int comma_split (u8 *s, u8 **a, u8 **b)
+{
+ *a = s;
+
+ while (*s && *s != ',')
+ s++;
+
+ if (*s == ',')
+ *s = 0;
+ else
+ return 1;
+
+ *b = (u8 *) (s+1);
+ return 0;
+}
+
+clib_error_t *
+ip_feature_init_cast (vlib_main_t * vm,
+ ip_config_main_t * cm,
+ vnet_config_main_t * vcm,
+ char **feature_start_nodes,
+ int num_feature_start_nodes,
+ vnet_cast_t cast,
+ int is_ip4)
+{
+ uword * index_by_name;
+ uword * reg_by_index;
+ u8 ** node_names = 0;
+ u8 * node_name;
+ char ** these_constraints;
+ char * this_constraint_c;
+ u8 ** constraints = 0;
+ u8 * constraint_tuple;
+ u8 * this_constraint;
+ u8 ** orig, ** closure;
+ uword * p;
+ int i, j, k;
+ u8 * a_name, * b_name;
+ int a_index, b_index;
+ int n_features;
+ u32 * result = 0;
+ vnet_ip_feature_registration_t * this_reg, * first_reg;
+ char ** feature_nodes = 0;
+ hash_pair_t * hp;
+ u8 ** keys_to_delete = 0;
+ ip4_main_t * im4 = &ip4_main;
+ ip6_main_t * im6 = &ip6_main;
+
+ index_by_name = hash_create_string (0, sizeof (uword));
+ reg_by_index = hash_create (0, sizeof (uword));
+
+ if (cast == VNET_UNICAST)
+ {
+ if (is_ip4)
+ first_reg = im4->next_uc_feature;
+ else
+ first_reg = im6->next_uc_feature;
+ }
+ else
+ {
+ if (is_ip4)
+ first_reg = im4->next_mc_feature;
+ else
+ first_reg = im6->next_mc_feature;
+ }
+
+ this_reg = first_reg;
+
+ /* pass 1, collect feature node names, construct a before b pairs */
+ while (this_reg)
+ {
+ node_name = format (0, "%s%c", this_reg->node_name, 0);
+ hash_set (reg_by_index, vec_len(node_names), (uword) this_reg);
+
+ hash_set_mem (index_by_name, node_name, vec_len(node_names));
+
+ vec_add1 (node_names, node_name);
+
+ these_constraints = this_reg->runs_before;
+
+ while (these_constraints [0])
+ {
+ this_constraint_c = these_constraints[0];
+
+ constraint_tuple = format (0, "%s,%s%c", node_name,
+ this_constraint_c, 0);
+ vec_add1 (constraints, constraint_tuple);
+ these_constraints++;
+ }
+ this_reg = this_reg->next;
+ }
+
+ n_features = vec_len (node_names);
+ orig = clib_ptclosure_alloc (n_features);
+
+ for (i = 0; i < vec_len (constraints); i++)
+ {
+ this_constraint = constraints[i];
+
+ if (comma_split (this_constraint, &a_name, &b_name))
+ return clib_error_return (0, "comma_split failed!");
+
+ p = hash_get_mem (index_by_name, a_name);
+ if (p == 0)
+ return clib_error_return (0, "feature node '%s' not found", a_name);
+ a_index = p[0];
+
+ p = hash_get_mem (index_by_name, b_name);
+ if (p == 0)
+ return clib_error_return (0, "feature node '%s' not found", b_name);
+ b_index = p[0];
+
+ /* add a before b to the original set of constraints */
+ orig[a_index][b_index] = 1;
+ vec_free (this_constraint);
+ }
+
+ /* Compute the positive transitive closure of the original constraints */
+ closure = clib_ptclosure (orig);
+
+ /* Compute a partial order across feature nodes, if one exists. */
+ again:
+ for (i = 0; i < n_features; i++)
+ {
+ for (j = 0; j < n_features; j++)
+ {
+ if (closure[i][j])
+ goto item_constrained;
+ }
+ /* Item i can be output */
+ vec_add1 (result, i);
+ {
+ for (k = 0; k < n_features; k++)
+ closure [k][i] = 0;
+ /*
+ * Add a "Magic" a before a constraint.
+ * This means we'll never output it again
+ */
+ closure [i][i] = 1;
+ goto again;
+ }
+ item_constrained:
+ ;
+ }
+
+ /* see if we got a partial order... */
+ if (vec_len (result) != n_features)
+ return clib_error_return (0, "ip4_feature_init_cast (cast=%d), no PO!");
+
+ /*
+ * We win.
+ * Bind the index variables, and output the feature node name vector
+ * using the partial order we just computed. Result is in stack
+ * order, because the entry with the fewest constraints (e.g. none)
+ * is output first, etc.
+ */
+
+ for (i = n_features-1; i >= 0; i--)
+ {
+ p = hash_get (reg_by_index, result[i]);
+ ASSERT (p != 0);
+ this_reg = (vnet_ip_feature_registration_t *)p[0];
+ *this_reg->feature_index = n_features - (i+1);
+ vec_add1 (feature_nodes, this_reg->node_name);
+ }
+
+ /* Set up the config infrastructure */
+ vnet_config_init (vm, vcm,
+ feature_start_nodes,
+ num_feature_start_nodes,
+ feature_nodes,
+ vec_len(feature_nodes));
+
+ /* Finally, clean up all the shit we allocated */
+ hash_foreach_pair (hp, index_by_name,
+ ({
+ vec_add1 (keys_to_delete, (u8 *)hp->key);
+ }));
+ hash_free (index_by_name);
+ for (i = 0; i < vec_len(keys_to_delete); i++)
+ vec_free (keys_to_delete[i]);
+ vec_free (keys_to_delete);
+ hash_free (reg_by_index);
+ vec_free (result);
+ clib_ptclosure_free (orig);
+ clib_ptclosure_free (closure);
+ return 0;
+}
+