static vnet_config_t *
find_config_with_features (vlib_main_t * vm,
vnet_config_main_t * cm,
- vnet_config_feature_t * feature_vector)
+ vnet_config_feature_t * feature_vector,
+ u32 end_node_index)
{
u32 last_node_index = ~0;
vnet_config_feature_t *f;
config_string = cm->config_string_temp;
cm->config_string_temp = 0;
if (config_string)
- _vec_len (config_string) = 0;
+ vec_set_len (config_string, 0);
vec_foreach (f, feature_vector)
{
}
/* Terminate config string with next for end node. */
- if (last_node_index == ~0 || last_node_index != cm->end_node_index)
+ if (last_node_index == ~0 || last_node_index != end_node_index)
{
- u32 next_index = add_next (vm, cm, last_node_index, cm->end_node_index);
+ u32 next_index = add_next (vm, cm, last_node_index, end_node_index);
vec_add1 (config_string, next_index);
}
+ /* Add the end node index to the config string so that it is part of
+ * the key used to detect string sharing. If this is not included then
+ * a modification of the end node would affect all the user of a shared
+ * string. */
+ vec_add1 (config_string, end_node_index);
+
/* See if config string is unique. */
p = hash_get_mem (cm->config_string_hash, config_string);
if (p)
hash_set_mem (cm->config_string_hash, config_string, c->index);
c->reference_count = 0; /* will be incremented by caller. */
+
+ vec_validate_init_empty (cm->end_node_indices_by_user_index,
+ c->config_string_heap_index + 1,
+ cm->default_end_node_index);
+ cm->end_node_indices_by_user_index[c->config_string_heap_index + 1]
+ = end_node_index;
}
return c;
vlib_node_t *n;
u32 i;
- memset (cm, 0, sizeof (cm[0]));
+ clib_memset (cm, 0, sizeof (cm[0]));
cm->config_string_hash =
hash_create_vec (0,
if (n)
{
if (i + 1 == n_feature_node_names)
- cm->end_node_index = n->index;
+ cm->default_end_node_index = n->index;
cm->node_index_by_feature_index[i] = n->index;
}
else
return heap_elt_at_index (cm->config_string_heap, ci);
}
+void
+vnet_config_del (vnet_config_main_t * cm, u32 config_id)
+{
+ u32 *p = vnet_get_config_heap (cm, config_id);
+ vnet_config_t *old = pool_elt_at_index (cm->config_pool, p[-1]);
+ remove_reference (cm, old);
+}
+
+u32
+vnet_config_reset_end_node (vlib_main_t *vm, vnet_config_main_t *cm, u32 ci)
+{
+ cm->end_node_indices_by_user_index[ci] = cm->default_end_node_index;
+
+ return (
+ vnet_config_modify_end_node (vm, cm, ci, cm->default_end_node_index));
+}
+
+u32
+vnet_config_modify_end_node (vlib_main_t * vm,
+ vnet_config_main_t * cm,
+ u32 config_string_heap_index, u32 end_node_index)
+{
+ vnet_config_feature_t *new_features;
+ vnet_config_t *old, *new;
+
+ if (end_node_index == ~0) // feature node does not exist
+ return ~0;
+
+ if (config_string_heap_index == ~0)
+ {
+ old = 0;
+ new_features = 0;
+ }
+ else
+ {
+ u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
+ old = pool_elt_at_index (cm->config_pool, p[-1]);
+ new_features = old->features;
+ if (new_features)
+ new_features = duplicate_feature_vector (new_features);
+ }
+
+ if (vec_len (new_features))
+ {
+ /* is the last feature the cuurent end node */
+ u32 last = vec_len (new_features) - 1;
+ if (new_features[last].node_index == cm->default_end_node_index)
+ {
+ vec_free (new_features->feature_config);
+ vec_set_len (new_features, last);
+ }
+ }
+
+ if (old)
+ remove_reference (cm, old);
+
+ new = find_config_with_features (vm, cm, new_features, end_node_index);
+ new->reference_count += 1;
+
+ /*
+ * User gets pointer to config string first element
+ * (which defines the pool index
+ * this config string comes from).
+ */
+ vec_validate (cm->config_pool_index_by_user_index,
+ new->config_string_heap_index + 1);
+ cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
+ = new - cm->config_pool;
+ return new->config_string_heap_index + 1;
+}
+
+u32
+vnet_config_get_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
+ u32 config_string_heap_index)
+{
+ if (config_string_heap_index >= vec_len (cm->end_node_indices_by_user_index))
+ return cm->default_end_node_index;
+ if (~0 == cm->end_node_indices_by_user_index[config_string_heap_index])
+ return cm->default_end_node_index;
+
+ return (cm->end_node_indices_by_user_index[config_string_heap_index]);
+}
+
u32
vnet_config_add_feature (vlib_main_t * vm,
vnet_config_main_t * cm,
{
vnet_config_t *old, *new;
vnet_config_feature_t *new_features, *f;
- u32 n_feature_config_u32s;
+ u32 n_feature_config_u32s, end_node_index;
u32 node_index = vec_elt (cm->node_index_by_feature_index, feature_index);
if (node_index == ~0) // feature node does not exist
- return config_string_heap_index; // return original config index
+ return ~0;
if (config_string_heap_index == ~0)
{
old = 0;
new_features = 0;
+ end_node_index = cm->default_end_node_index;
}
else
{
u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
old = pool_elt_at_index (cm->config_pool, p[-1]);
new_features = old->features;
+ end_node_index =
+ cm->end_node_indices_by_user_index[config_string_heap_index];
if (new_features)
new_features = duplicate_feature_vector (new_features);
}
f->feature_index = feature_index;
f->node_index = node_index;
- n_feature_config_u32s =
- round_pow2 (n_feature_config_bytes,
- sizeof (f->feature_config[0])) /
- sizeof (f->feature_config[0]);
- vec_add (f->feature_config, feature_config, n_feature_config_u32s);
+ if (n_feature_config_bytes)
+ {
+ n_feature_config_u32s =
+ round_pow2 (n_feature_config_bytes,
+ sizeof (f->feature_config[0])) /
+ sizeof (f->feature_config[0]);
+ vec_validate (f->feature_config, n_feature_config_u32s - 1);
+ clib_memcpy_fast (f->feature_config, feature_config,
+ n_feature_config_bytes);
+ }
/* Sort (prioritize) features. */
if (vec_len (new_features) > 1)
if (old)
remove_reference (cm, old);
- new = find_config_with_features (vm, cm, new_features);
+ new = find_config_with_features (vm, cm, new_features, end_node_index);
new->reference_count += 1;
/*
/* Feature not found. */
if (f >= vec_end (old->features))
- return config_string_heap_index; // return original config index
+ return ~0;
new_features = duplicate_feature_vector (old->features);
f = new_features + (f - old->features);
adds a new config because none of existing config's has matching features
and so can be reused */
remove_reference (cm, old);
- new = find_config_with_features (vm, cm, new_features);
+ new = find_config_with_features (vm, cm, new_features,
+ cm->end_node_indices_by_user_index
+ [config_string_heap_index]);
new->reference_count += 1;
vec_validate (cm->config_pool_index_by_user_index,