LCOV - code coverage report
Current view: top level - vnet - config.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 179 188 95.2 %
Date: 2023-10-26 01:39:38 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /*
       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:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       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.
      14             :  */
      15             : /*
      16             :  * config.c: feature configuration
      17             :  *
      18             :  * Copyright (c) 2008 Eliot Dresselhaus
      19             :  *
      20             :  * Permission is hereby granted, free of charge, to any person obtaining
      21             :  * a copy of this software and associated documentation files (the
      22             :  * "Software"), to deal in the Software without restriction, including
      23             :  * without limitation the rights to use, copy, modify, merge, publish,
      24             :  * distribute, sublicense, and/or sell copies of the Software, and to
      25             :  * permit persons to whom the Software is furnished to do so, subject to
      26             :  * the following conditions:
      27             :  *
      28             :  * The above copyright notice and this permission notice shall be
      29             :  * included in all copies or substantial portions of the Software.
      30             :  *
      31             :  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      32             :  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      33             :  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      34             :  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      35             :  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      36             :  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      37             :  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      38             :  */
      39             : 
      40             : #include <vnet/vnet.h>
      41             : 
      42             : static vnet_config_feature_t *
      43       87798 : duplicate_feature_vector (vnet_config_feature_t * feature_vector)
      44             : {
      45             :   vnet_config_feature_t *result, *f;
      46             : 
      47       87798 :   result = vec_dup (feature_vector);
      48      153215 :   vec_foreach (f, result) f->feature_config = vec_dup (f->feature_config);
      49             : 
      50       87798 :   return result;
      51             : }
      52             : 
      53             : static void
      54      100382 : free_feature_vector (vnet_config_feature_t * feature_vector)
      55             : {
      56             :   vnet_config_feature_t *f;
      57             : 
      58      169223 :   vec_foreach (f, feature_vector) vnet_config_feature_free (f);
      59      100382 :   vec_free (feature_vector);
      60      100382 : }
      61             : 
      62             : static u32
      63      215310 : add_next (vlib_main_t * vm,
      64             :           vnet_config_main_t * cm, u32 last_node_index, u32 this_node_index)
      65             : {
      66      215310 :   u32 i, ni = ~0;
      67             : 
      68      215310 :   if (last_node_index != ~0)
      69       71225 :     return vlib_node_add_next (vm, last_node_index, this_node_index);
      70             : 
      71      350453 :   for (i = 0; i < vec_len (cm->start_node_indices); i++)
      72             :     {
      73             :       u32 tmp;
      74      206368 :       tmp =
      75      206368 :         vlib_node_add_next (vm, cm->start_node_indices[i], this_node_index);
      76      206368 :       if (ni == ~0)
      77      144085 :         ni = tmp;
      78             :       /* Start nodes to first must agree on next indices. */
      79      206368 :       ASSERT (ni == tmp);
      80             :     }
      81             : 
      82      144085 :   return ni;
      83             : }
      84             : 
      85             : static vnet_config_t *
      86      144085 : find_config_with_features (vlib_main_t * vm,
      87             :                            vnet_config_main_t * cm,
      88             :                            vnet_config_feature_t * feature_vector,
      89             :                            u32 end_node_index)
      90             : {
      91      144085 :   u32 last_node_index = ~0;
      92             :   vnet_config_feature_t *f;
      93             :   u32 *config_string;
      94             :   uword *p;
      95             :   vnet_config_t *c;
      96             : 
      97      144085 :   config_string = cm->config_string_temp;
      98      144085 :   cm->config_string_temp = 0;
      99      144085 :   if (config_string)
     100       95932 :     vec_set_len (config_string, 0);
     101             : 
     102      236228 :   vec_foreach (f, feature_vector)
     103             :   {
     104             :     /* Connect node graph. */
     105       92143 :     f->next_index = add_next (vm, cm, last_node_index, f->node_index);
     106       92143 :     last_node_index = f->node_index;
     107             : 
     108             :     /* Store next index in config string. */
     109       92143 :     vec_add1 (config_string, f->next_index);
     110             : 
     111             :     /* Store feature config. */
     112       92143 :     vec_add (config_string, f->feature_config, vec_len (f->feature_config));
     113             :   }
     114             : 
     115             :   /* Terminate config string with next for end node. */
     116      144085 :   if (last_node_index == ~0 || last_node_index != end_node_index)
     117             :     {
     118      123167 :       u32 next_index = add_next (vm, cm, last_node_index, end_node_index);
     119      123167 :       vec_add1 (config_string, next_index);
     120             :     }
     121             : 
     122             :   /* Add the end node index to the config string so that it is part of
     123             :    * the key used to detect string sharing. If this is not included then
     124             :    * a modification of the end node would affect all the user of a shared
     125             :    * string. */
     126      144085 :   vec_add1 (config_string, end_node_index);
     127             : 
     128             :   /* See if config string is unique. */
     129      288170 :   p = hash_get_mem (cm->config_string_hash, config_string);
     130      144085 :   if (p)
     131             :     {
     132             :       /* Not unique.  Share existing config. */
     133      100382 :       cm->config_string_temp = config_string;        /* we'll use it again later. */
     134      100382 :       free_feature_vector (feature_vector);
     135      100382 :       c = pool_elt_at_index (cm->config_pool, p[0]);
     136             :     }
     137             :   else
     138             :     {
     139             :       u32 *d;
     140             : 
     141       43703 :       pool_get (cm->config_pool, c);
     142       43703 :       c->index = c - cm->config_pool;
     143       43703 :       c->features = feature_vector;
     144       43703 :       c->config_string_vector = config_string;
     145             : 
     146             :       /* Allocate copy of config string in heap.
     147             :          VLIB buffers will maintain pointers to heap as they read out
     148             :          configuration data. */
     149       43703 :       c->config_string_heap_index
     150       43703 :         = heap_alloc (cm->config_string_heap, vec_len (config_string) + 1,
     151             :                       c->config_string_heap_handle);
     152             : 
     153             :       /* First element in heap points back to pool index. */
     154       43703 :       d =
     155       43703 :         vec_elt_at_index (cm->config_string_heap,
     156             :                           c->config_string_heap_index);
     157       43703 :       d[0] = c->index;
     158       43703 :       clib_memcpy (d + 1, config_string, vec_bytes (config_string));
     159       87406 :       hash_set_mem (cm->config_string_hash, config_string, c->index);
     160             : 
     161       43703 :       c->reference_count = 0;        /* will be incremented by caller. */
     162             : 
     163       73213 :       vec_validate_init_empty (cm->end_node_indices_by_user_index,
     164             :                                c->config_string_heap_index + 1,
     165             :                                cm->default_end_node_index);
     166       43703 :       cm->end_node_indices_by_user_index[c->config_string_heap_index + 1]
     167       43703 :         = end_node_index;
     168             :     }
     169             : 
     170      144085 :   return c;
     171             : }
     172             : 
     173             : void
     174       16516 : vnet_config_init (vlib_main_t * vm,
     175             :                   vnet_config_main_t * cm,
     176             :                   char *start_node_names[],
     177             :                   int n_start_node_names,
     178             :                   char *feature_node_names[], int n_feature_node_names)
     179             : {
     180             :   vlib_node_t *n;
     181             :   u32 i;
     182             : 
     183       16516 :   clib_memset (cm, 0, sizeof (cm[0]));
     184             : 
     185       16516 :   cm->config_string_hash =
     186       16516 :     hash_create_vec (0,
     187             :                      STRUCT_SIZE_OF (vnet_config_t, config_string_vector[0]),
     188             :                      sizeof (uword));
     189             : 
     190       16516 :   ASSERT (n_feature_node_names >= 1);
     191             : 
     192       16516 :   vec_resize (cm->start_node_indices, n_start_node_names);
     193       38782 :   for (i = 0; i < n_start_node_names; i++)
     194             :     {
     195       22266 :       n = vlib_get_node_by_name (vm, (u8 *) start_node_names[i]);
     196             :       /* Given node name must exist. */
     197       22266 :       ASSERT (n != 0);
     198       22266 :       cm->start_node_indices[i] = n->index;
     199             :     }
     200             : 
     201       16516 :   vec_resize (cm->node_index_by_feature_index, n_feature_node_names);
     202      164674 :   for (i = 0; i < n_feature_node_names; i++)
     203             :     {
     204      148158 :       if (!feature_node_names[i])
     205        4698 :         cm->node_index_by_feature_index[i] = ~0;
     206             :       else
     207             :         {
     208      143460 :           n = vlib_get_node_by_name (vm, (u8 *) feature_node_names[i]);
     209             :           /* Given node may exist in plug-in library which is not present */
     210      143460 :           if (n)
     211             :             {
     212      140585 :               if (i + 1 == n_feature_node_names)
     213       16516 :                 cm->default_end_node_index = n->index;
     214      140585 :               cm->node_index_by_feature_index[i] = n->index;
     215             :             }
     216             :           else
     217        2875 :             cm->node_index_by_feature_index[i] = ~0;
     218             :         }
     219             :     }
     220       16516 : }
     221             : 
     222             : static void
     223      115062 : remove_reference (vnet_config_main_t * cm, vnet_config_t * c)
     224             : {
     225      115062 :   ASSERT (c->reference_count > 0);
     226      115062 :   c->reference_count -= 1;
     227      115062 :   if (c->reference_count == 0)
     228             :     {
     229       37549 :       hash_unset (cm->config_string_hash, c->config_string_vector);
     230       37549 :       vnet_config_free (cm, c);
     231       37549 :       pool_put (cm->config_pool, c);
     232             :     }
     233      115062 : }
     234             : 
     235             : static int
     236        4786 : feature_cmp (void *a1, void *a2)
     237             : {
     238        4786 :   vnet_config_feature_t *f1 = a1;
     239        4786 :   vnet_config_feature_t *f2 = a2;
     240             : 
     241        4786 :   return (int) f1->feature_index - f2->feature_index;
     242             : }
     243             : 
     244             : always_inline u32 *
     245      116837 : vnet_get_config_heap (vnet_config_main_t * cm, u32 ci)
     246             : {
     247      116837 :   return heap_elt_at_index (cm->config_string_heap, ci);
     248             : }
     249             : 
     250             : void
     251       24767 : vnet_config_del (vnet_config_main_t * cm, u32 config_id)
     252             : {
     253       24767 :   u32 *p = vnet_get_config_heap (cm, config_id);
     254       24767 :   vnet_config_t *old = pool_elt_at_index (cm->config_pool, p[-1]);
     255       24767 :   remove_reference (cm, old);
     256       24767 : }
     257             : 
     258             : u32
     259           0 : vnet_config_reset_end_node (vlib_main_t *vm, vnet_config_main_t *cm, u32 ci)
     260             : {
     261           0 :   cm->end_node_indices_by_user_index[ci] = cm->default_end_node_index;
     262             : 
     263             :   return (
     264           0 :     vnet_config_modify_end_node (vm, cm, ci, cm->default_end_node_index));
     265             : }
     266             : 
     267             : u32
     268        4547 : vnet_config_modify_end_node (vlib_main_t * vm,
     269             :                              vnet_config_main_t * cm,
     270             :                              u32 config_string_heap_index, u32 end_node_index)
     271             : {
     272             :   vnet_config_feature_t *new_features;
     273             :   vnet_config_t *old, *new;
     274             : 
     275        4547 :   if (end_node_index == ~0)     // feature node does not exist
     276           0 :     return ~0;
     277             : 
     278        4547 :   if (config_string_heap_index == ~0)
     279             :     {
     280        2024 :       old = 0;
     281        2024 :       new_features = 0;
     282             :     }
     283             :   else
     284             :     {
     285        2523 :       u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
     286        2523 :       old = pool_elt_at_index (cm->config_pool, p[-1]);
     287        2523 :       new_features = old->features;
     288        2523 :       if (new_features)
     289         196 :         new_features = duplicate_feature_vector (new_features);
     290             :     }
     291             : 
     292        4547 :   if (vec_len (new_features))
     293             :     {
     294             :       /* is the last feature the cuurent end node */
     295          26 :       u32 last = vec_len (new_features) - 1;
     296          26 :       if (new_features[last].node_index == cm->default_end_node_index)
     297             :         {
     298           0 :           vec_free (new_features->feature_config);
     299           0 :           vec_set_len (new_features, last);
     300             :         }
     301             :     }
     302             : 
     303        4547 :   if (old)
     304        2523 :     remove_reference (cm, old);
     305             : 
     306        4547 :   new = find_config_with_features (vm, cm, new_features, end_node_index);
     307        4547 :   new->reference_count += 1;
     308             : 
     309             :   /*
     310             :    * User gets pointer to config string first element
     311             :    * (which defines the pool index
     312             :    * this config string comes from).
     313             :    */
     314        4547 :   vec_validate (cm->config_pool_index_by_user_index,
     315             :                 new->config_string_heap_index + 1);
     316        4547 :   cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
     317        4547 :     = new - cm->config_pool;
     318        4547 :   return new->config_string_heap_index + 1;
     319             : }
     320             : 
     321             : u32
     322         972 : vnet_config_get_end_node (vlib_main_t *vm, vnet_config_main_t *cm,
     323             :                           u32 config_string_heap_index)
     324             : {
     325         972 :   if (config_string_heap_index >= vec_len (cm->end_node_indices_by_user_index))
     326           0 :     return cm->default_end_node_index;
     327         972 :   if (~0 == cm->end_node_indices_by_user_index[config_string_heap_index])
     328           0 :     return cm->default_end_node_index;
     329             : 
     330         972 :   return (cm->end_node_indices_by_user_index[config_string_heap_index]);
     331             : }
     332             : 
     333             : u32
     334       83132 : vnet_config_add_feature (vlib_main_t * vm,
     335             :                          vnet_config_main_t * cm,
     336             :                          u32 config_string_heap_index,
     337             :                          u32 feature_index,
     338             :                          void *feature_config, u32 n_feature_config_bytes)
     339             : {
     340             :   vnet_config_t *old, *new;
     341             :   vnet_config_feature_t *new_features, *f;
     342             :   u32 n_feature_config_u32s, end_node_index;
     343       83132 :   u32 node_index = vec_elt (cm->node_index_by_feature_index, feature_index);
     344             : 
     345       83132 :   if (node_index == ~0)         // feature node does not exist
     346           0 :     return ~0;
     347             : 
     348       83132 :   if (config_string_heap_index == ~0)
     349             :     {
     350       51766 :       old = 0;
     351       51766 :       new_features = 0;
     352       51766 :       end_node_index = cm->default_end_node_index;
     353             :     }
     354             :   else
     355             :     {
     356       31366 :       u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
     357       31366 :       old = pool_elt_at_index (cm->config_pool, p[-1]);
     358       31366 :       new_features = old->features;
     359       31366 :       end_node_index =
     360       31366 :         cm->end_node_indices_by_user_index[config_string_heap_index];
     361       31366 :       if (new_features)
     362       31196 :         new_features = duplicate_feature_vector (new_features);
     363             :     }
     364             : 
     365       83132 :   vec_add2 (new_features, f, 1);
     366       83132 :   f->feature_index = feature_index;
     367       83132 :   f->node_index = node_index;
     368             : 
     369       83132 :   if (n_feature_config_bytes)
     370             :     {
     371       24374 :       n_feature_config_u32s =
     372       24374 :         round_pow2 (n_feature_config_bytes,
     373       24374 :                     sizeof (f->feature_config[0])) /
     374             :         sizeof (f->feature_config[0]);
     375       24374 :       vec_validate (f->feature_config, n_feature_config_u32s - 1);
     376       24374 :       clib_memcpy_fast (f->feature_config, feature_config,
     377             :                         n_feature_config_bytes);
     378             :     }
     379             : 
     380             :   /* Sort (prioritize) features. */
     381       83132 :   if (vec_len (new_features) > 1)
     382        4308 :     vec_sort_with_function (new_features, feature_cmp);
     383             : 
     384       83132 :   if (old)
     385       31366 :     remove_reference (cm, old);
     386             : 
     387       83132 :   new = find_config_with_features (vm, cm, new_features, end_node_index);
     388       83132 :   new->reference_count += 1;
     389             : 
     390             :   /*
     391             :    * User gets pointer to config string first element
     392             :    * (which defines the pool index
     393             :    * this config string comes from).
     394             :    */
     395       83132 :   vec_validate (cm->config_pool_index_by_user_index,
     396             :                 new->config_string_heap_index + 1);
     397       83132 :   cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
     398       83132 :     = new - cm->config_pool;
     399       83132 :   return new->config_string_heap_index + 1;
     400             : }
     401             : 
     402             : u32
     403       58181 : vnet_config_del_feature (vlib_main_t * vm,
     404             :                          vnet_config_main_t * cm,
     405             :                          u32 config_string_heap_index,
     406             :                          u32 feature_index,
     407             :                          void *feature_config, u32 n_feature_config_bytes)
     408             : {
     409             :   vnet_config_t *old, *new;
     410             :   vnet_config_feature_t *new_features, *f;
     411             :   u32 n_feature_config_u32s;
     412             : 
     413             :   {
     414       58181 :     u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
     415             : 
     416       58181 :     old = pool_elt_at_index (cm->config_pool, p[-1]);
     417             :   }
     418             : 
     419       58181 :   n_feature_config_u32s =
     420       58181 :     round_pow2 (n_feature_config_bytes,
     421       58181 :                 sizeof (f->feature_config[0])) /
     422             :     sizeof (f->feature_config[0]);
     423             : 
     424             :   /* Find feature with same index and opaque data. */
     425       61077 :   vec_foreach (f, old->features)
     426             :   {
     427       59302 :     if (f->feature_index == feature_index
     428       56406 :         && vec_len (f->feature_config) == n_feature_config_u32s
     429       56406 :         && (n_feature_config_u32s == 0
     430       16209 :             || !memcmp (f->feature_config, feature_config,
     431             :                         n_feature_config_bytes)))
     432             :       break;
     433             :   }
     434             : 
     435             :   /* Feature not found. */
     436       58181 :   if (f >= vec_end (old->features))
     437        1775 :     return ~0;
     438             : 
     439       56406 :   new_features = duplicate_feature_vector (old->features);
     440       56406 :   f = new_features + (f - old->features);
     441       56406 :   vnet_config_feature_free (f);
     442       56406 :   vec_delete (new_features, 1, f - new_features);
     443             : 
     444             :   /* must remove old from config_pool now as it may be expanded and change
     445             :      memory location if the following function find_config_with_features()
     446             :      adds a new config because none of existing config's has matching features
     447             :      and so can be reused */
     448       56406 :   remove_reference (cm, old);
     449       56406 :   new = find_config_with_features (vm, cm, new_features,
     450       56406 :                                    cm->end_node_indices_by_user_index
     451       56406 :                                    [config_string_heap_index]);
     452       56406 :   new->reference_count += 1;
     453             : 
     454       56406 :   vec_validate (cm->config_pool_index_by_user_index,
     455             :                 new->config_string_heap_index + 1);
     456       56406 :   cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
     457       56406 :     = new - cm->config_pool;
     458       56406 :   return new->config_string_heap_index + 1;
     459             : }
     460             : 
     461             : /*
     462             :  * fd.io coding-style-patch-verification: ON
     463             :  *
     464             :  * Local Variables:
     465             :  * eval: (c-set-style "gnu")
     466             :  * End:
     467             :  */

Generated by: LCOV version 1.14