LCOV - code coverage report
Current view: top level - vnet/ip - ip_interface.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 99 102 97.1 %
Date: 2023-10-26 01:39:38 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 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             : #include <vnet/ip/ip.h>
      17             : 
      18             : /**
      19             :  * @file
      20             :  * @brief IP prefix management on interfaces
      21             :  */
      22             : 
      23             : u32
      24        8967 : ip_interface_address_find (ip_lookup_main_t * lm,
      25             :                            void *addr_fib, u32 address_length)
      26             : {
      27        8967 :   uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib);
      28             : 
      29        8967 :   if (p)
      30        4291 :     return (p[0]);
      31             : 
      32        4676 :   return (~0);
      33             : }
      34             : 
      35             : clib_error_t *
      36        4682 : ip_interface_address_add (ip_lookup_main_t * lm,
      37             :                           u32 sw_if_index,
      38             :                           void *addr_fib,
      39             :                           u32 address_length, u32 * result_if_address_index)
      40             : {
      41        4682 :   vnet_main_t *vnm = vnet_get_main ();
      42             :   ip_interface_address_t *a, *prev;
      43             :   u32 pi;                       /* previous index */
      44             :   u32 ai;
      45             :   u32 hi;                       /* head index */
      46             : 
      47             :   /* Verify given length. */
      48        4682 :   if ((address_length == 0) ||
      49        4682 :       (lm->is_ip6 && address_length > 128) ||
      50        4682 :       (!lm->is_ip6 && address_length > 32))
      51             :     {
      52           0 :       vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
      53           0 :       return clib_error_create
      54             :         ("%U wrong length for interface %U",
      55             :          lm->format_address_and_length, addr_fib,
      56             :          address_length, format_vnet_sw_if_index_name, vnm, sw_if_index);
      57             :     }
      58             : 
      59        4682 :   vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
      60             :                            sw_if_index, ~0);
      61             : 
      62        4682 :   pool_get_zero (lm->if_address_pool, a);
      63             : 
      64        4682 :   ai = a - lm->if_address_pool;
      65        4682 :   hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
      66             : 
      67        4682 :   prev = 0;
      68        4801 :   while (pi != (u32) ~ 0)
      69             :     {
      70         119 :       prev = pool_elt_at_index (lm->if_address_pool, pi);
      71         119 :       pi = prev->next_this_sw_interface;
      72             :     }
      73        4682 :   pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;
      74             : 
      75        4682 :   a->address_key = mhash_set (&lm->address_to_if_address_index,
      76             :                               addr_fib, ai, /* old_value */ 0);
      77        4682 :   a->address_length = address_length;
      78        4682 :   a->sw_if_index = sw_if_index;
      79        4682 :   a->flags = 0;
      80        4682 :   a->prev_this_sw_interface = pi;
      81        4682 :   a->next_this_sw_interface = ~0;
      82        4682 :   if (prev)
      83          76 :     prev->next_this_sw_interface = ai;
      84             : 
      85        4682 :   lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
      86        4682 :     (hi != ~0) ? hi : ai;
      87             : 
      88        4682 :   *result_if_address_index = ai;
      89             : 
      90        4682 :   return (NULL);
      91             : }
      92             : 
      93             : clib_error_t *
      94        4273 : ip_interface_address_del (ip_lookup_main_t * lm,
      95             :                           vnet_main_t * vnm,
      96             :                           u32 address_index, void *addr_fib,
      97             :                           u32 address_length, u32 sw_if_index)
      98             : {
      99             :   ip_interface_address_t *a, *prev, *next;
     100             : 
     101        4273 :   a = pool_elt_at_index (lm->if_address_pool, address_index);
     102             : 
     103        4273 :   if (a->sw_if_index != sw_if_index)
     104             :     {
     105           2 :       vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
     106           2 :       return clib_error_create ("%U not found for interface %U",
     107             :                                 lm->format_address_and_length,
     108             :                                 addr_fib, address_length,
     109             :                                 format_vnet_sw_if_index_name,
     110             :                                 vnet_get_main (), sw_if_index);
     111             :     }
     112             : 
     113        4271 :   if (a->prev_this_sw_interface != ~0)
     114             :     {
     115          10 :       prev = pool_elt_at_index (lm->if_address_pool,
     116             :                                 a->prev_this_sw_interface);
     117          10 :       prev->next_this_sw_interface = a->next_this_sw_interface;
     118             :     }
     119        4271 :   if (a->next_this_sw_interface != ~0)
     120             :     {
     121          66 :       next = pool_elt_at_index (lm->if_address_pool,
     122             :                                 a->next_this_sw_interface);
     123          66 :       next->prev_this_sw_interface = a->prev_this_sw_interface;
     124             : 
     125          66 :       if (a->prev_this_sw_interface == ~0)
     126          61 :         lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] =
     127          61 :           a->next_this_sw_interface;
     128             :     }
     129             : 
     130        4271 :   if ((a->next_this_sw_interface == ~0) && (a->prev_this_sw_interface == ~0))
     131        4200 :     lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] = ~0;
     132             : 
     133        4271 :   mhash_unset (&lm->address_to_if_address_index, addr_fib,
     134             :                /* old_value */ 0);
     135        4271 :   pool_put (lm->if_address_pool, a);
     136        4271 :   return NULL;
     137             : }
     138             : 
     139             : u8
     140          15 : ip_interface_has_address (u32 sw_if_index, ip46_address_t * ip, u8 is_ip4)
     141             : {
     142          15 :   ip_interface_address_t *ia = 0;
     143             : 
     144          15 :   if (is_ip4)
     145             :     {
     146          14 :       ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
     147             :       ip4_address_t *ip4;
     148             :       /* *INDENT-OFF* */
     149          14 :       foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
     150             :       ({
     151             :         ip4 = ip_interface_address_get_address (lm4, ia);
     152             :         if (ip4_address_compare (ip4, &ip->ip4) == 0)
     153             :           return 1;
     154             :       }));
     155             :       /* *INDENT-ON* */
     156             :     }
     157             :   else
     158             :     {
     159           1 :       ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
     160             :       ip6_address_t *ip6;
     161             :       /* *INDENT-OFF* */
     162           1 :       foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
     163             :       ({
     164             :         ip6 = ip_interface_address_get_address (lm6, ia);
     165             :         if (ip6_address_compare (ip6, &ip->ip6) == 0)
     166             :           return 1;
     167             :       }));
     168             :       /* *INDENT-ON* */
     169             :     }
     170           0 :   return 0;
     171             : }
     172             : 
     173             : void *
     174         228 : ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
     175             : {
     176         228 :   ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
     177         228 :   ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
     178         228 :   ip_interface_address_t *ia = 0;
     179             : 
     180         228 :   if (is_ip4)
     181             :     {
     182             :       /* *INDENT-OFF* */
     183         219 :       foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
     184             :       ({
     185             :         return ip_interface_address_get_address (lm4, ia);
     186             :       }));
     187             :       /* *INDENT-ON* */
     188             :     }
     189             :   else
     190             :     {
     191             :       /* *INDENT-OFF* */
     192           9 :       foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
     193             :       ({
     194             :         ip6_address_t *rv;
     195             :         rv = ip_interface_address_get_address (lm6, ia);
     196             :         /* Trying to use a link-local ip6 src address is a fool's errand */
     197             :         if (!ip6_address_is_link_local_unicast (rv))
     198             :           return rv;
     199             :       }));
     200             :       /* *INDENT-ON* */
     201             :     }
     202             : 
     203           1 :   return 0;
     204             : }
     205             : 
     206             : walk_rc_t
     207          50 : ip_interface_address_mark_one_interface (vnet_main_t *vnm,
     208             :                                          vnet_sw_interface_t *si, void *ctx)
     209             : {
     210          50 :   ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
     211          50 :   ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
     212          50 :   ip_interface_address_t *ia = 0;
     213             : 
     214             :   /* *INDENT-OFF* */
     215          94 :   foreach_ip_interface_address (lm4, ia, si->sw_if_index, 1 /* unnumbered */ ,
     216             :   ({
     217             :     ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
     218             :   }));
     219          94 :   foreach_ip_interface_address (lm6, ia, si->sw_if_index, 1 /* unnumbered */ ,
     220             :   ({
     221             :     ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
     222             :   }));
     223             :   /* *INDENT-ON* */
     224             : 
     225          50 :   return (WALK_CONTINUE);
     226             : }
     227             : 
     228             : void
     229          10 : ip_interface_address_mark (void)
     230             : {
     231          10 :   vnet_sw_interface_walk (vnet_get_main (),
     232             :                           ip_interface_address_mark_one_interface, NULL);
     233          10 : }
     234             : 
     235             : static walk_rc_t
     236          50 : ip_interface_address_sweep_one_interface (vnet_main_t * vnm,
     237             :                                           vnet_sw_interface_t * si, void *ctx)
     238             : {
     239          50 :   vlib_main_t *vm = vlib_get_main ();
     240          50 :   ip4_address_t *ip4_addrs = 0;
     241          50 :   ip6_address_t *ip6_addrs = 0;
     242          50 :   ip4_main_t *im4 = &ip4_main;
     243          50 :   ip6_main_t *im6 = &ip6_main;
     244             :   ip_interface_address_t *ia;
     245          50 :   u32 *ip6_masks = 0;
     246          50 :   u32 *ip4_masks = 0;
     247             :   int i;
     248             : 
     249             :   /* *INDENT-OFF* */
     250          99 :   foreach_ip_interface_address (&im4->lookup_main, ia, si->sw_if_index, 1,
     251             :   ({
     252             :     if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     253             :       {
     254             :         ip4_address_t * x = (ip4_address_t *)
     255             :           ip_interface_address_get_address (&im4->lookup_main, ia);
     256             :         vec_add1 (ip4_addrs, x[0]);
     257             :         vec_add1 (ip4_masks, ia->address_length);
     258             :       }
     259             :   }));
     260             : 
     261          99 :   foreach_ip_interface_address (&im6->lookup_main, ia, si->sw_if_index, 1,
     262             :   ({
     263             :     if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
     264             :       {
     265             :         ip6_address_t * x = (ip6_address_t *)
     266             :           ip_interface_address_get_address (&im6->lookup_main, ia);
     267             :         vec_add1 (ip6_addrs, x[0]);
     268             :         vec_add1 (ip6_masks, ia->address_length);
     269             :       }
     270             :   }));
     271             :   /* *INDENT-ON* */
     272             : 
     273          85 :   for (i = 0; i < vec_len (ip4_addrs); i++)
     274          35 :     ip4_add_del_interface_address (vm, si->sw_if_index, &ip4_addrs[i],
     275          35 :                                    ip4_masks[i], 1 /* is_del */ );
     276          85 :   for (i = 0; i < vec_len (ip6_addrs); i++)
     277          35 :     ip6_add_del_interface_address (vm, si->sw_if_index, &ip6_addrs[i],
     278          35 :                                    ip6_masks[i], 1 /* is_del */ );
     279             : 
     280          50 :   vec_free (ip4_addrs);
     281          50 :   vec_free (ip4_masks);
     282          50 :   vec_free (ip6_addrs);
     283          50 :   vec_free (ip6_masks);
     284             : 
     285          50 :   return (WALK_CONTINUE);
     286             : }
     287             : 
     288             : void
     289          10 : ip_interface_address_sweep (void)
     290             : {
     291          10 :   vnet_sw_interface_walk (vnet_get_main (),
     292             :                           ip_interface_address_sweep_one_interface, NULL);
     293          10 : }
     294             : 
     295             : /*
     296             :  * fd.io coding-style-patch-verification: ON
     297             :  *
     298             :  * Local Variables:
     299             :  * eval: (c-set-style "gnu")
     300             :  * End:
     301             :  */

Generated by: LCOV version 1.14