tcp: avoid fr segments less than mss if possible
[vpp.git] / src / vnet / config.c
index 9beda4a..c05da66 100644 (file)
@@ -85,7 +85,8 @@ add_next (vlib_main_t * vm,
 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;
@@ -96,7 +97,7 @@ find_config_with_features (vlib_main_t * vm,
   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)
   {
@@ -112,12 +113,18 @@ find_config_with_features (vlib_main_t * vm,
   }
 
   /* 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)
@@ -152,6 +159,12 @@ find_config_with_features (vlib_main_t * vm,
       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;
@@ -197,7 +210,7 @@ vnet_config_init (vlib_main_t * vm,
          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
@@ -234,6 +247,89 @@ vnet_get_config_heap (vnet_config_main_t * cm, u32 ci)
   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,
@@ -243,7 +339,7 @@ vnet_config_add_feature (vlib_main_t * vm,
 {
   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
@@ -253,12 +349,15 @@ vnet_config_add_feature (vlib_main_t * vm,
     {
       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);
     }
@@ -267,11 +366,16 @@ vnet_config_add_feature (vlib_main_t * vm,
   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)
@@ -280,7 +384,7 @@ vnet_config_add_feature (vlib_main_t * vm,
   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;
 
   /*
@@ -342,7 +446,9 @@ vnet_config_del_feature (vlib_main_t * vm,
      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,