LCOV - code coverage report
Current view: top level - vnet/teib - teib.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 134 140 95.7 %
Date: 2023-10-26 01:39:38 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /*
       2             :  * teib.h: Tunnel Endpoint Information Base
       3             :  *
       4             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : 
      19             : #include <vnet/teib/teib.h>
      20             : #include <vnet/fib/fib_table.h>
      21             : #include <vnet/adj/adj_midchain.h>
      22             : #include <vnet/ip/ip6_ll_table.h>
      23             : 
      24             : typedef struct teib_key_t_
      25             : {
      26             :   ip_address_t tk_peer;
      27             :   u8 __pad[3];
      28             :   u32 tk_sw_if_index;
      29             : } __clib_packed teib_key_t;
      30             : 
      31             : STATIC_ASSERT_SIZEOF (teib_key_t, 24);
      32             : 
      33             : struct teib_entry_t_
      34             : {
      35             :   teib_key_t *te_key;
      36             :   fib_prefix_t te_nh;
      37             :   u32 te_nh_fib_index;
      38             : };
      39             : 
      40             : typedef struct teib_db_t_
      41             : {
      42             :   u32 td_n_entries[N_AF];
      43             :   uword *td_db;
      44             : } teib_db_t;
      45             : 
      46             : static teib_db_t teib_db;
      47             : static teib_entry_t *teib_pool;
      48             : static teib_vft_t *teib_vfts;
      49             : static vlib_log_class_t teib_logger;
      50             : 
      51             : #define TEIB_NOTIFY(_te, _fn) {                  \
      52             :   teib_vft_t *_vft;                              \
      53             :   vec_foreach(_vft, teib_vfts) {                 \
      54             :     if (_vft->_fn) {                             \
      55             :       _vft->_fn(_te);                            \
      56             :     }                                            \
      57             :   }                                              \
      58             : }
      59             : 
      60             : #define TEIB_DBG(...)                           \
      61             :     vlib_log_debug (teib_logger, __VA_ARGS__);
      62             : 
      63             : #define TEIB_INFO(...)                          \
      64             :     vlib_log_notice (teib_logger, __VA_ARGS__);
      65             : 
      66             : #define TEIB_TE_DBG(_te, _fmt, _args...)                      \
      67             :   vlib_log_debug (teib_logger, "[%U]: " _fmt, format_teib_entry, _te - teib_pool, ##_args)
      68             : #define TEIB_TE_INFO(_te, _fmt, _args...)                      \
      69             :   vlib_log_notice (teib_logger, "[%U]: " _fmt, format_teib_entry, _te - teib_pool, ##_args)
      70             : 
      71             : u32
      72        1349 : teib_entry_get_sw_if_index (const teib_entry_t * te)
      73             : {
      74        1349 :   return (te->te_key->tk_sw_if_index);
      75             : }
      76             : 
      77             : static ip_address_family_t
      78          12 : teib_entry_get_af (const teib_entry_t * te)
      79             : {
      80          12 :   return (ip_addr_version (&te->te_key->tk_peer));
      81             : }
      82             : 
      83             : u32
      84         791 : teib_entry_get_fib_index (const teib_entry_t * te)
      85             : {
      86         791 :   return (te->te_nh_fib_index);
      87             : }
      88             : 
      89             : const ip_address_t *
      90         961 : teib_entry_get_peer (const teib_entry_t * te)
      91             : {
      92         961 :   return (&te->te_key->tk_peer);
      93             : }
      94             : 
      95             : const fib_prefix_t *
      96         947 : teib_entry_get_nh (const teib_entry_t * te)
      97             : {
      98         947 :   return (&te->te_nh);
      99             : }
     100             : 
     101             : void
     102         126 : teib_entry_adj_stack (const teib_entry_t * te, adj_index_t ai)
     103             : {
     104         126 :   adj_midchain_delegate_stack (ai, te->te_nh_fib_index, &te->te_nh);
     105         126 : }
     106             : 
     107             : teib_entry_t *
     108        1017 : teib_entry_get (index_t tei)
     109             : {
     110        1017 :   return pool_elt_at_index (teib_pool, tei);
     111             : }
     112             : 
     113             : teib_entry_t *
     114         277 : teib_entry_find (u32 sw_if_index, const ip_address_t * peer)
     115             : {
     116         277 :   teib_key_t nk = {
     117             :     .tk_peer = *peer,
     118             :     .tk_sw_if_index = sw_if_index,
     119             :   };
     120             :   uword *p;
     121             : 
     122         277 :   p = hash_get_mem (teib_db.td_db, &nk);
     123             : 
     124         277 :   if (NULL != p)
     125         142 :     return teib_entry_get (p[0]);
     126             : 
     127         135 :   return (NULL);
     128             : }
     129             : 
     130             : teib_entry_t *
     131          75 : teib_entry_find_46 (u32 sw_if_index,
     132             :                     fib_protocol_t fproto, const ip46_address_t * peer)
     133             : {
     134             :   ip_address_t ip;
     135             : 
     136          75 :   ip_address_from_46 (peer, fproto, &ip);
     137             : 
     138          75 :   return (teib_entry_find (sw_if_index, &ip));
     139             : }
     140             : 
     141             : static void
     142          97 : teib_adj_fib_add (const ip_address_t *ip, u32 sw_if_index, u32 peer_fib_index)
     143             : {
     144         126 :   if (AF_IP6 == ip_addr_version (ip) &&
     145          29 :       ip6_address_is_link_local_unicast (&ip_addr_v6 (ip)))
     146           1 :     {
     147           1 :       ip6_ll_prefix_t pfx = {
     148             :         .ilp_addr = ip_addr_v6 (ip),
     149             :         .ilp_sw_if_index = sw_if_index,
     150             :       };
     151           1 :       ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
     152             :     }
     153             :   else
     154             :     {
     155             :       fib_prefix_t pfx;
     156             : 
     157          96 :       ip_address_to_fib_prefix (ip, &pfx);
     158          96 :       fib_table_entry_path_add (
     159             :         peer_fib_index, &pfx, FIB_SOURCE_ADJ, FIB_ENTRY_FLAG_ATTACHED,
     160          96 :         fib_proto_to_dpo (pfx.fp_proto), &pfx.fp_addr, sw_if_index, ~0, 1,
     161             :         NULL, FIB_ROUTE_PATH_FLAG_NONE);
     162             : 
     163          96 :       if (0 == teib_db.td_n_entries[ip_addr_version (ip)]++)
     164           8 :         fib_table_lock (peer_fib_index, pfx.fp_proto, FIB_SOURCE_ADJ);
     165             :     }
     166          97 : }
     167             : 
     168             : static void
     169          97 : teib_adj_fib_remove (ip_address_t *ip, u32 sw_if_index, u32 peer_fib_index)
     170             : {
     171         126 :   if (AF_IP6 == ip_addr_version (ip) &&
     172          29 :       ip6_address_is_link_local_unicast (&ip_addr_v6 (ip)))
     173           1 :     {
     174           1 :       ip6_ll_prefix_t pfx = {
     175             :         .ilp_addr = ip_addr_v6 (ip),
     176             :         .ilp_sw_if_index = sw_if_index,
     177             :       };
     178           1 :       ip6_ll_table_entry_delete (&pfx);
     179             :     }
     180             :   else
     181             :     {
     182             :       fib_prefix_t pfx;
     183             : 
     184          96 :       ip_address_to_fib_prefix (ip, &pfx);
     185          96 :       fib_table_entry_path_remove (
     186          96 :         peer_fib_index, &pfx, FIB_SOURCE_ADJ, fib_proto_to_dpo (pfx.fp_proto),
     187             :         &pfx.fp_addr, sw_if_index, ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
     188             : 
     189          96 :       if (0 == --teib_db.td_n_entries[ip_addr_version (ip)])
     190           8 :         fib_table_unlock (peer_fib_index, pfx.fp_proto, FIB_SOURCE_ADJ);
     191             :     }
     192          97 : }
     193             : 
     194             : int
     195          85 : teib_entry_add (u32 sw_if_index,
     196             :                 const ip_address_t * peer,
     197             :                 u32 nh_table_id, const ip_address_t * nh)
     198             : {
     199             :   fib_protocol_t nh_proto;
     200             :   teib_entry_t *te;
     201             :   u32 nh_fib_index, peer_fib_index;
     202             :   index_t tei;
     203             : 
     204          85 :   nh_proto = (AF_IP4 == ip_addr_version (nh) ?
     205          85 :               FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
     206             : 
     207          85 :   peer_fib_index = fib_table_get_index_for_sw_if_index (
     208          85 :     ip_address_family_to_fib_proto (peer->version), sw_if_index);
     209          85 :   nh_fib_index = fib_table_find (nh_proto, nh_table_id);
     210             : 
     211          85 :   if (~0 == nh_fib_index)
     212             :     {
     213           0 :       return (VNET_API_ERROR_NO_SUCH_FIB);
     214             :     }
     215             : 
     216          85 :   te = teib_entry_find (sw_if_index, peer);
     217             : 
     218          85 :   if (NULL == te)
     219             :     {
     220          85 :       teib_key_t nk = {
     221             :         .tk_peer = *peer,
     222             :         .tk_sw_if_index = sw_if_index,
     223             :       };
     224             :       teib_entry_t *te;
     225             : 
     226          85 :       pool_get_zero (teib_pool, te);
     227             : 
     228          85 :       tei = te - teib_pool;
     229          85 :       te->te_key = clib_mem_alloc (sizeof (*te->te_key));
     230          85 :       clib_memcpy (te->te_key, &nk, sizeof (*te->te_key));
     231             : 
     232          85 :       ip_address_to_fib_prefix (nh, &te->te_nh);
     233          85 :       te->te_nh_fib_index = nh_fib_index;
     234             : 
     235         170 :       hash_set_mem (teib_db.td_db, te->te_key, tei);
     236             : 
     237             :       /* we how have a /32 in the overlay, add an adj-fib */
     238          85 :       teib_adj_fib_add (&te->te_key->tk_peer, sw_if_index, peer_fib_index);
     239             : 
     240         340 :       TEIB_NOTIFY (te, nv_added);
     241          85 :       TEIB_TE_INFO (te, "created");
     242             :     }
     243             :   else
     244             :     {
     245           0 :       TEIB_TE_INFO (te, "exists");
     246           0 :       return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
     247             :     }
     248          85 :   return 0;
     249             : }
     250             : 
     251             : int
     252          85 : teib_entry_del (u32 sw_if_index, const ip_address_t * peer)
     253             : {
     254             :   teib_entry_t *te;
     255             : 
     256          85 :   te = teib_entry_find (sw_if_index, peer);
     257             : 
     258          85 :   if (te != NULL)
     259             :     {
     260          85 :       TEIB_TE_INFO (te, "removed");
     261             : 
     262             :       u32 peer_fib_index;
     263             : 
     264          85 :       peer_fib_index = fib_table_get_index_for_sw_if_index (
     265          85 :         ip_address_family_to_fib_proto (peer->version), sw_if_index);
     266             : 
     267          85 :       teib_adj_fib_remove (&te->te_key->tk_peer, sw_if_index, peer_fib_index);
     268             : 
     269         170 :       hash_unset_mem (teib_db.td_db, te->te_key);
     270             : 
     271         340 :       TEIB_NOTIFY (te, nv_deleted);
     272             : 
     273          85 :       clib_mem_free (te->te_key);
     274          85 :       pool_put (teib_pool, te);
     275             :     }
     276             :   else
     277             :     {
     278           0 :       TEIB_INFO ("no such entry: %U, %U", format_vnet_sw_if_index_name,
     279             :                  vnet_get_main (), sw_if_index, format_ip_address, peer);
     280           0 :       return (VNET_API_ERROR_NO_SUCH_ENTRY);
     281             :     }
     282          85 :   return 0;
     283             : }
     284             : 
     285             : u8 *
     286         182 : format_teib_entry (u8 * s, va_list * args)
     287             : {
     288         182 :   index_t tei = va_arg (*args, index_t);
     289         182 :   vnet_main_t *vnm = vnet_get_main ();
     290             :   teib_entry_t *te;
     291             : 
     292         182 :   te = teib_entry_get (tei);
     293             : 
     294         182 :   s = format (s, "[%d] ", tei);
     295         182 :   s = format (s, "%U:", format_vnet_sw_if_index_name,
     296         182 :               vnm, te->te_key->tk_sw_if_index);
     297         182 :   s = format (s, "%U", format_ip_address,
     298         182 :               &te->te_key->tk_peer, IP46_TYPE_ANY);
     299         182 :   s = format (s, " via [%d]:%U",
     300         182 :               fib_table_get_table_id (te->te_nh_fib_index, te->te_nh.fp_proto),
     301             :               format_fib_prefix, &te->te_nh);
     302             : 
     303         182 :   return (s);
     304             : }
     305             : 
     306             : void
     307         102 : teib_walk (teib_walk_cb_t fn, void *ctx)
     308             : {
     309             :   index_t tei;
     310             : 
     311             :   /* *INDENT-OFF* */
     312         723 :   pool_foreach_index (tei, teib_pool)
     313             :    {
     314         621 :     fn(tei, ctx);
     315             :   }
     316             :   /* *INDENT-ON* */
     317         102 : }
     318             : 
     319             : void
     320          18 : teib_walk_itf (u32 sw_if_index, teib_walk_cb_t fn, void *ctx)
     321             : {
     322             :   index_t tei;
     323             : 
     324             :   /* *INDENT-OFF* */
     325          36 :   pool_foreach_index (tei, teib_pool)
     326             :    {
     327          18 :     if (sw_if_index == teib_entry_get_sw_if_index(teib_entry_get(tei)))
     328           0 :       fn(tei, ctx);
     329             :   }
     330             :   /* *INDENT-ON* */
     331          18 : }
     332             : 
     333             : static void
     334        1723 : teib_walk_itf_proto (u32 sw_if_index,
     335             :                      ip_address_family_t af, teib_walk_cb_t fn, void *ctx)
     336             : {
     337             :   index_t tei;
     338             : 
     339             :   /* *INDENT-OFF* */
     340        1753 :   pool_foreach_index (tei, teib_pool)
     341             :    {
     342          42 :     if (sw_if_index == teib_entry_get_sw_if_index(teib_entry_get(tei)) &&
     343          12 :         af == teib_entry_get_af(teib_entry_get(tei)))
     344          12 :       fn(tei, ctx);
     345             :   }
     346             :   /* *INDENT-ON* */
     347        1723 : }
     348             : 
     349             : typedef struct teib_table_bind_ctx_t_
     350             : {
     351             :   u32 new_peer_fib_index;
     352             :   u32 old_peer_fib_index;
     353             : } teib_table_bind_ctx_t;
     354             : 
     355             : static walk_rc_t
     356          12 : teib_walk_table_bind (index_t tei, void *arg)
     357             : {
     358          12 :   teib_table_bind_ctx_t *ctx = arg;
     359             :   teib_entry_t *te;
     360             : 
     361          12 :   te = teib_entry_get (tei);
     362             : 
     363          12 :   TEIB_TE_INFO (te, "bind: %d -> %d", ctx->old_peer_fib_index,
     364             :                 ctx->new_peer_fib_index);
     365             : 
     366          12 :   teib_adj_fib_remove (&te->te_key->tk_peer, te->te_key->tk_sw_if_index,
     367             :                        ctx->old_peer_fib_index);
     368          12 :   teib_adj_fib_add (&te->te_key->tk_peer, te->te_key->tk_sw_if_index,
     369             :                     ctx->new_peer_fib_index);
     370             : 
     371          12 :   return (WALK_CONTINUE);
     372             : }
     373             : 
     374             : static void
     375         946 : teib_table_bind_v4 (ip4_main_t * im,
     376             :                     uword opaque,
     377             :                     u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
     378             : {
     379         946 :   teib_table_bind_ctx_t ctx = {
     380             :     .old_peer_fib_index = old_fib_index,
     381             :     .new_peer_fib_index = new_fib_index,
     382             :   };
     383             : 
     384         946 :   teib_walk_itf_proto (sw_if_index, AF_IP4, teib_walk_table_bind, &ctx);
     385         946 : }
     386             : 
     387             : static void
     388         777 : teib_table_bind_v6 (ip6_main_t * im,
     389             :                     uword opaque,
     390             :                     u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
     391             : {
     392         777 :   teib_table_bind_ctx_t ctx = {
     393             :     .old_peer_fib_index = old_fib_index,
     394             :     .new_peer_fib_index = new_fib_index,
     395             :   };
     396             : 
     397         777 :   teib_walk_itf_proto (sw_if_index, AF_IP6, teib_walk_table_bind, &ctx);
     398         777 : }
     399             : 
     400             : void
     401        1725 : teib_register (const teib_vft_t * vft)
     402             : {
     403        1725 :   vec_add1 (teib_vfts, *vft);
     404        1725 : }
     405             : 
     406             : static clib_error_t *
     407         575 : teib_init (vlib_main_t * vm)
     408             : {
     409         575 :   teib_db.td_db = hash_create_mem (0, sizeof (teib_key_t), sizeof (u32));
     410             : 
     411         575 :   ip4_table_bind_callback_t cb4 = {
     412             :     .function = teib_table_bind_v4,
     413             :   };
     414         575 :   vec_add1 (ip4_main.table_bind_callbacks, cb4);
     415             : 
     416         575 :   ip6_table_bind_callback_t cb6 = {
     417             :     .function = teib_table_bind_v6,
     418             :   };
     419         575 :   vec_add1 (ip6_main.table_bind_callbacks, cb6);
     420             : 
     421         575 :   teib_logger = vlib_log_register_class ("teib", "teib");
     422             : 
     423         575 :   return (NULL);
     424             : }
     425             : 
     426       95039 : VLIB_INIT_FUNCTION (teib_init);
     427             : 
     428             : /*
     429             :  * fd.io coding-style-patch-verification: ON
     430             :  *
     431             :  * Local Variables:
     432             :  * eval: (c-set-style "gnu")
     433             :  * End:
     434             :  */

Generated by: LCOV version 1.14