LCOV - code coverage report
Current view: top level - plugins/cnat - cnat_translation.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 268 332 80.7 %
Date: 2023-10-26 01:39:38 Functions: 32 35 91.4 %

          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/fib/fib_source.h>
      17             : #include <vnet/fib/fib_table.h>
      18             : #include <vnet/fib/fib_entry_track.h>
      19             : #include <vnet/dpo/load_balance.h>
      20             : #include <vnet/dpo/drop_dpo.h>
      21             : 
      22             : #include <cnat/cnat_translation.h>
      23             : #include <cnat/cnat_maglev.h>
      24             : #include <cnat/cnat_session.h>
      25             : #include <cnat/cnat_client.h>
      26             : 
      27             : cnat_translation_t *cnat_translation_pool;
      28             : clib_bihash_8_8_t cnat_translation_db;
      29             : addr_resolution_t *tr_resolutions;
      30             : cnat_if_addr_add_cb_t *cnat_if_addr_add_cbs;
      31             : 
      32             : static fib_node_type_t cnat_translation_fib_node_type;
      33             : 
      34             : vlib_combined_counter_main_t cnat_translation_counters = {
      35             :   .name = "cnat-translation",
      36             :   .stat_segment_name = "/net/cnat-translation",
      37             : };
      38             : 
      39             : void
      40          86 : cnat_translation_watch_addr (index_t cti, u64 opaque, cnat_endpoint_t * ep,
      41             :                              cnat_addr_resol_type_t type)
      42             : {
      43             :   addr_resolution_t *ar;
      44             : 
      45          86 :   if (INDEX_INVALID == ep->ce_sw_if_index)
      46          74 :     return;
      47             : 
      48          12 :   pool_get (tr_resolutions, ar);
      49          12 :   ar->af = ep->ce_ip.version;
      50          12 :   ar->sw_if_index = ep->ce_sw_if_index;
      51          12 :   ar->type = type;
      52          12 :   ar->opaque = opaque;
      53          12 :   ar->cti = cti;
      54             : }
      55             : 
      56             : static void
      57          26 : cnat_resolve_ep_tuple (cnat_endpoint_tuple_t * path)
      58             : {
      59          26 :   cnat_resolve_ep (&path->src_ep);
      60          26 :   cnat_resolve_ep (&path->dst_ep);
      61          26 : }
      62             : 
      63             : void
      64          44 : cnat_translation_unwatch_addr (u32 cti, cnat_addr_resol_type_t type)
      65             : {
      66             :   /* Delete tr resolution entries matching translation index */
      67             :   addr_resolution_t *ar;
      68          44 :   index_t *indexes = 0, *ari;
      69          56 :   pool_foreach (ar, tr_resolutions)
      70             :     {
      71          12 :       if ((cti == INDEX_INVALID || ar->cti == cti) &&
      72          12 :           (ar->type == type || CNAT_RESOLV_ADDR_ANY == type))
      73          12 :         vec_add1 (indexes, ar - tr_resolutions);
      74             :     }
      75          56 :   vec_foreach (ari, indexes) pool_put_index (tr_resolutions, *ari);
      76             : 
      77          44 :   vec_free (indexes);
      78          44 : }
      79             : 
      80             : static void
      81          22 : cnat_tracker_release (cnat_ep_trk_t * trk)
      82             : {
      83             :   /* We only track fully resolved endpoints */
      84          22 :   if (!(trk->ct_flags & CNAT_TRK_ACTIVE))
      85           0 :     return;
      86          22 :   fib_entry_untrack (trk->ct_fei, trk->ct_sibling);
      87             : }
      88             : 
      89             : static void
      90          50 : cnat_tracker_track (index_t cti, cnat_ep_trk_t * trk)
      91             : {
      92             :   fib_prefix_t pfx;
      93             :   /* We only track fully resolved endpoints */
      94          50 :   if (trk->ct_ep[VLIB_TX].ce_flags & CNAT_EP_FLAG_RESOLVED &&
      95          38 :       trk->ct_ep[VLIB_RX].ce_flags & CNAT_EP_FLAG_RESOLVED)
      96          34 :     trk->ct_flags |= CNAT_TRK_ACTIVE;
      97             :   else
      98             :     {
      99          16 :       trk->ct_flags &= ~CNAT_TRK_ACTIVE;
     100          16 :       return;
     101             :     }
     102             : 
     103          34 :   ip_address_to_fib_prefix (&trk->ct_ep[VLIB_TX].ce_ip, &pfx);
     104          34 :   trk->ct_fei = fib_entry_track (CNAT_FIB_TABLE,
     105             :                                  &pfx,
     106             :                                  cnat_translation_fib_node_type,
     107             :                                  cti, &trk->ct_sibling);
     108             : 
     109          34 :   fib_entry_contribute_forwarding (trk->ct_fei,
     110          34 :                                    fib_forw_chain_type_from_fib_proto
     111          34 :                                    (pfx.fp_proto), &trk->ct_dpo);
     112             : }
     113             : 
     114             : u8 *
     115         131 : format_cnat_lb_type (u8 *s, va_list *args)
     116             : {
     117         131 :   cnat_lb_type_t lb_type = va_arg (*args, int);
     118         131 :   if (CNAT_LB_DEFAULT == lb_type)
     119         131 :     s = format (s, "default");
     120           0 :   else if (CNAT_LB_MAGLEV == lb_type)
     121           0 :     s = format (s, "maglev");
     122             :   else
     123           0 :     s = format (s, "unknown");
     124         131 :   return (s);
     125             : }
     126             : 
     127             : uword
     128           0 : unformat_cnat_lb_type (unformat_input_t *input, va_list *args)
     129             : {
     130           0 :   cnat_lb_type_t *a = va_arg (*args, cnat_lb_type_t *);
     131           0 :   if (unformat (input, "default"))
     132           0 :     *a = CNAT_LB_DEFAULT;
     133           0 :   else if (unformat (input, "maglev"))
     134           0 :     *a = CNAT_LB_MAGLEV;
     135             :   else
     136           0 :     return 0;
     137           0 :   return 1;
     138             : }
     139             : 
     140             : /**
     141             :  * Add a translation to the bihash
     142             :  *
     143             :  * @param cci the ID of the parent client (invalid if vip not resolved)
     144             :  * @param vip the translation endpoint
     145             :  * @param proto the translation proto
     146             :  * @param cti the translation index to be used as value
     147             :  */
     148             : static void
     149          22 : cnat_add_translation_to_db (index_t cci, cnat_endpoint_t * vip,
     150             :                             ip_protocol_t proto, index_t cti)
     151             : {
     152             :   clib_bihash_kv_8_8_t bkey;
     153             :   u64 key;
     154          22 :   if (INDEX_INVALID == cci)
     155             :     {
     156           4 :       key = proto << 8 | 0x80 | vip->ce_ip.version;
     157           4 :       key = key << 16 | vip->ce_port;
     158           4 :       key = key << 32 | (u32) vip->ce_sw_if_index;
     159             :     }
     160             :   else
     161             :     {
     162          18 :       key = proto << 8;
     163          18 :       key = key << 16 | vip->ce_port;
     164          18 :       key = key << 32 | (u32) cci;
     165             :     }
     166             : 
     167          22 :   bkey.key = key;
     168          22 :   bkey.value = cti;
     169             : 
     170          22 :   clib_bihash_add_del_8_8 (&cnat_translation_db, &bkey, 1);
     171          22 : }
     172             : 
     173             : /**
     174             :  * Remove a translation from the bihash
     175             :  *
     176             :  * @param cci the ID of the parent client
     177             :  * @param vip the translation endpoint
     178             :  * @param proto the translation proto
     179             :  */
     180             : static void
     181          22 : cnat_remove_translation_from_db (index_t cci, cnat_endpoint_t * vip,
     182             :                                  ip_protocol_t proto)
     183             : {
     184             :   clib_bihash_kv_8_8_t bkey;
     185             :   u64 key;
     186          22 :   if (INDEX_INVALID == cci)
     187             :     {
     188           4 :       key = proto << 8 | 0x80 | vip->ce_ip.version;
     189           4 :       key = key << 16 | vip->ce_port;
     190           4 :       key = key << 32 | (u32) vip->ce_sw_if_index;
     191             :     }
     192             :   else
     193             :     {
     194          18 :       key = proto << 8;
     195          18 :       key = key << 16 | vip->ce_port;
     196          18 :       key = key << 32 | (u32) cci;
     197             :     }
     198             : 
     199          22 :   bkey.key = key;
     200             : 
     201          22 :   clib_bihash_add_del_8_8 (&cnat_translation_db, &bkey, 0);
     202          22 : }
     203             : 
     204             : 
     205             : 
     206             : static void
     207          58 : cnat_translation_stack (cnat_translation_t * ct)
     208             : {
     209             :   fib_protocol_t fproto;
     210             :   cnat_ep_trk_t *trk;
     211             :   dpo_proto_t dproto;
     212          58 :   u32 ep_idx = 0;
     213             :   index_t lbi;
     214             : 
     215          58 :   fproto = ip_address_family_to_fib_proto (ct->ct_vip.ce_ip.version);
     216          58 :   dproto = fib_proto_to_dpo (fproto);
     217             : 
     218          58 :   vec_reset_length (ct->ct_active_paths);
     219             : 
     220         156 :   vec_foreach (trk, ct->ct_paths)
     221          98 :     if (trk->ct_flags & CNAT_TRK_ACTIVE)
     222          62 :       vec_add1 (ct->ct_active_paths, *trk);
     223             : 
     224          58 :   flow_hash_config_t fhc = IP_FLOW_HASH_DEFAULT;
     225          58 :   if (ct->fhc != 0)
     226          58 :     fhc = ct->fhc;
     227          58 :   lbi = load_balance_create (vec_len (ct->ct_active_paths),
     228          58 :                              fib_proto_to_dpo (fproto), fhc);
     229             : 
     230          58 :   ep_idx = 0;
     231         120 :   vec_foreach (trk, ct->ct_active_paths)
     232          62 :     load_balance_set_bucket (lbi, ep_idx++, &trk->ct_dpo);
     233             : 
     234          58 :   if (ep_idx > 0 && CNAT_LB_MAGLEV == ct->lb_type)
     235           0 :     cnat_translation_init_maglev (ct);
     236             : 
     237          58 :   dpo_set (&ct->ct_lb, DPO_LOAD_BALANCE, dproto, lbi);
     238          58 :   dpo_stack (cnat_client_dpo, dproto, &ct->ct_lb, &ct->ct_lb);
     239          58 :   ct->flags |= CNAT_TR_FLAG_STACKED;
     240          58 : }
     241             : 
     242             : int
     243          16 : cnat_translation_delete (u32 id)
     244             : {
     245             :   cnat_translation_t *ct;
     246             :   cnat_ep_trk_t *trk;
     247             : 
     248          16 :   if (pool_is_free_index (cnat_translation_pool, id))
     249           0 :     return (VNET_API_ERROR_NO_SUCH_ENTRY);
     250             : 
     251          16 :   ct = pool_elt_at_index (cnat_translation_pool, id);
     252             : 
     253          16 :   dpo_reset (&ct->ct_lb);
     254             : 
     255          32 :   vec_foreach (trk, ct->ct_active_paths)
     256          16 :     cnat_tracker_release (trk);
     257             : 
     258          16 :   cnat_remove_translation_from_db (ct->ct_cci, &ct->ct_vip, ct->ct_proto);
     259          16 :   cnat_client_translation_deleted (ct->ct_cci);
     260          16 :   cnat_translation_unwatch_addr (id, CNAT_RESOLV_ADDR_ANY);
     261          16 :   pool_put (cnat_translation_pool, ct);
     262             : 
     263          16 :   return (0);
     264             : }
     265             : 
     266             : u32
     267          22 : cnat_translation_update (cnat_endpoint_t *vip, ip_protocol_t proto,
     268             :                          cnat_endpoint_tuple_t *paths, u8 flags,
     269             :                          cnat_lb_type_t lb_type, flow_hash_config_t fhc)
     270             : {
     271             :   cnat_endpoint_tuple_t *path;
     272             :   const cnat_client_t *cc;
     273             :   cnat_translation_t *ct;
     274             :   cnat_ep_trk_t *trk;
     275             :   index_t cci;
     276             : 
     277          22 :   cnat_lazy_init ();
     278          22 :   if (cnat_resolve_ep (vip))
     279             :     {
     280             :       /* vip only contains a sw_if_index for now */
     281           2 :       ct = cnat_find_translation (vip->ce_sw_if_index, vip->ce_port, proto);
     282           2 :       cci = INDEX_INVALID;
     283             :     }
     284             :   else
     285             :     {
     286             :       /* do we know of this ep's vip */
     287          20 :       cci = cnat_client_add (&vip->ce_ip, flags);
     288          20 :       cc = cnat_client_get (cci);
     289             : 
     290          20 :       ct = cnat_find_translation (cc->parent_cci, vip->ce_port, proto);
     291             :     }
     292             : 
     293          22 :   if (NULL == ct)
     294             :     {
     295          16 :       pool_get_zero (cnat_translation_pool, ct);
     296             : 
     297          16 :       clib_memcpy (&ct->ct_vip, vip, sizeof (*vip));
     298          16 :       ct->ct_proto = proto;
     299          16 :       ct->ct_cci = cci;
     300          16 :       ct->index = ct - cnat_translation_pool;
     301          16 :       ct->lb_type = lb_type;
     302          16 :       ct->fhc = fhc;
     303             : 
     304          16 :       cnat_add_translation_to_db (cci, vip, proto, ct->index);
     305          16 :       cnat_client_translation_added (cci);
     306             : 
     307          16 :       vlib_validate_combined_counter (&cnat_translation_counters, ct->index);
     308          16 :       vlib_zero_combined_counter (&cnat_translation_counters, ct->index);
     309             :     }
     310          22 :   ct->flags = flags;
     311             : 
     312          22 :   cnat_translation_unwatch_addr (ct->index, CNAT_RESOLV_ADDR_ANY);
     313          22 :   cnat_translation_watch_addr (ct->index, 0, vip,
     314             :                                CNAT_RESOLV_ADDR_TRANSLATION);
     315             : 
     316          28 :   vec_foreach (trk, ct->ct_paths)
     317             :   {
     318           6 :     cnat_tracker_release (trk);
     319             :   }
     320             : 
     321          22 :   vec_reset_length (ct->ct_paths);
     322          22 :   ct->flags &= ~CNAT_TR_FLAG_STACKED;
     323             : 
     324          22 :   u64 path_idx = 0;
     325          48 :   vec_foreach (path, paths)
     326             :   {
     327          26 :     cnat_resolve_ep_tuple (path);
     328          26 :     cnat_translation_watch_addr (ct->index,
     329             :                                  path_idx << 32 | VLIB_RX, &path->src_ep,
     330             :                                  CNAT_RESOLV_ADDR_BACKEND);
     331          26 :     cnat_translation_watch_addr (ct->index,
     332          26 :                                  path_idx << 32 | VLIB_TX, &path->dst_ep,
     333             :                                  CNAT_RESOLV_ADDR_BACKEND);
     334          26 :     path_idx++;
     335             : 
     336          26 :     vec_add2 (ct->ct_paths, trk, 1);
     337             : 
     338          26 :     clib_memcpy (&trk->ct_ep[VLIB_TX], &path->dst_ep,
     339             :                  sizeof (trk->ct_ep[VLIB_TX]));
     340          26 :     clib_memcpy (&trk->ct_ep[VLIB_RX], &path->src_ep,
     341             :                  sizeof (trk->ct_ep[VLIB_RX]));
     342          26 :     trk->ct_flags = path->ep_flags;
     343             : 
     344          26 :     cnat_tracker_track (ct->index, trk);
     345             :   }
     346             : 
     347          22 :   cnat_translation_stack (ct);
     348             : 
     349          22 :   return (ct->index);
     350             : }
     351             : 
     352             : void
     353          20 : cnat_translation_walk (cnat_translation_walk_cb_t cb, void *ctx)
     354             : {
     355             :   u32 api;
     356             : 
     357          24 :   pool_foreach_index (api, cnat_translation_pool)
     358             :    {
     359           4 :     if (!cb(api, ctx))
     360           0 :       break;
     361             :   }
     362          20 : }
     363             : 
     364             : static u8 *
     365         158 : format_cnat_ep_trk (u8 * s, va_list * args)
     366             : {
     367         158 :   cnat_ep_trk_t *ck = va_arg (*args, cnat_ep_trk_t *);
     368         158 :   u32 indent = va_arg (*args, u32);
     369             : 
     370         158 :   s = format (s, "%U->%U", format_cnat_endpoint, &ck->ct_ep[VLIB_RX],
     371             :               format_cnat_endpoint, &ck->ct_ep[VLIB_TX]);
     372         158 :   s = format (s, "\n%Ufib-entry:%d", format_white_space, indent, ck->ct_fei);
     373         158 :   s = format (s, "\n%U%U",
     374             :               format_white_space, indent, format_dpo_id, &ck->ct_dpo, 6);
     375             : 
     376         158 :   return (s);
     377             : }
     378             : 
     379             : u8 *
     380         131 : format_cnat_translation (u8 * s, va_list * args)
     381             : {
     382         131 :   cnat_translation_t *ct = va_arg (*args, cnat_translation_t *);
     383         131 :   cnat_main_t *cm = &cnat_main;
     384             :   cnat_ep_trk_t *ck;
     385             : 
     386         131 :   s = format (s, "[%d] ", ct->index);
     387         131 :   s = format (s, "%U %U ", format_cnat_endpoint, &ct->ct_vip,
     388         131 :               format_ip_protocol, ct->ct_proto);
     389         131 :   s = format (s, "lb:%U ", format_cnat_lb_type, ct->lb_type);
     390             : 
     391         131 :   if ((ct->fhc == 0) || (ct->fhc == IP_FLOW_HASH_DEFAULT))
     392         104 :     s = format (s, "fhc:0x%x(default)", IP_FLOW_HASH_DEFAULT);
     393             :   else
     394          27 :     s = format (s, "fhc:0x%x", ct->fhc);
     395             : 
     396         289 :   vec_foreach (ck, ct->ct_paths)
     397         158 :     s = format (s, "\n%U", format_cnat_ep_trk, ck, 2);
     398             : 
     399             :   /* If printing a trace, the LB object might be deleted */
     400         131 :   if (!pool_is_free_index (load_balance_pool, ct->ct_lb.dpoi_index))
     401             :     {
     402         128 :       s = format (s, "\n via:");
     403         128 :       s = format (s, "\n%U%U",
     404             :                   format_white_space, 2, format_dpo_id, &ct->ct_lb, 2);
     405             :     }
     406             : 
     407         131 :   u32 bid = 0;
     408         131 :   if (CNAT_LB_MAGLEV == ct->lb_type)
     409             :     {
     410           0 :       s = format (s, "\nmaglev backends map");
     411           0 :       uword *bitmap = NULL;
     412           0 :       clib_bitmap_alloc (bitmap, cm->maglev_len);
     413           0 :       vec_foreach (ck, ct->ct_paths)
     414             :         {
     415           0 :           clib_bitmap_zero (bitmap);
     416           0 :           for (u32 i = 0; i < vec_len (ct->lb_maglev); i++)
     417           0 :             if (ct->lb_maglev[i] == bid)
     418           0 :               clib_bitmap_set (bitmap, i, 1);
     419           0 :           s = format (s, "\n  backend#%d: %U", bid, format_bitmap_hex, bitmap);
     420             : 
     421           0 :           bid++;
     422             :         }
     423           0 :       clib_bitmap_free (bitmap);
     424             :     }
     425             : 
     426         131 :   return (s);
     427             : }
     428             : 
     429             : static clib_error_t *
     430           3 : cnat_translation_show (vlib_main_t * vm,
     431             :                        unformat_input_t * input, vlib_cli_command_t * cmd)
     432             : {
     433             :   index_t cti;
     434             :   cnat_translation_t *ct;
     435             : 
     436           3 :   cti = INDEX_INVALID;
     437             : 
     438           3 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     439             :     {
     440           0 :       if (unformat (input, "%d", &cti))
     441             :         ;
     442             :       else
     443           0 :         return (clib_error_return (0, "unknown input '%U'",
     444             :                                    format_unformat_error, input));
     445             :     }
     446             : 
     447           3 :   if (INDEX_INVALID == cti)
     448             :     {
     449          11 :       pool_foreach_index (cti, cnat_translation_pool)
     450             :        {
     451           8 :         ct = pool_elt_at_index (cnat_translation_pool, cti);
     452           8 :         vlib_cli_output(vm, "%U", format_cnat_translation, ct);
     453             :       }
     454             :     }
     455             :   else
     456             :     {
     457           0 :       vlib_cli_output (vm, "Invalid policy ID:%d", cti);
     458             :     }
     459             : 
     460           3 :   return (NULL);
     461             : }
     462             : 
     463             : int
     464          15 : cnat_translation_purge (void)
     465             : {
     466             :   /* purge all the translations */
     467          15 :   index_t tri, *trp, *trs = NULL;
     468             : 
     469          17 :   pool_foreach_index (tri, cnat_translation_pool)
     470             :    {
     471           2 :     vec_add1(trs, tri);
     472             :   }
     473             : 
     474          17 :   vec_foreach (trp, trs) cnat_translation_delete (*trp);
     475             : 
     476          15 :   ASSERT (0 == pool_elts (cnat_translation_pool));
     477             : 
     478          15 :   vec_free (trs);
     479             : 
     480          15 :   return (0);
     481             : }
     482             : 
     483      257065 : VLIB_CLI_COMMAND (cnat_translation_show_cmd_node, static) = {
     484             :   .path = "show cnat translation",
     485             :   .function = cnat_translation_show,
     486             :   .short_help = "show cnat translation <VIP>",
     487             :   .is_mp_safe = 1,
     488             : };
     489             : 
     490             : static fib_node_t *
     491          12 : cnat_translation_get_node (fib_node_index_t index)
     492             : {
     493          12 :   cnat_translation_t *ct = cnat_translation_get (index);
     494          12 :   return (&(ct->ct_node));
     495             : }
     496             : 
     497             : static cnat_translation_t *
     498          12 : cnat_translation_get_from_node (fib_node_t * node)
     499             : {
     500          12 :   return ((cnat_translation_t *) (((char *) node) -
     501             :                                   STRUCT_OFFSET_OF (cnat_translation_t,
     502             :                                                     ct_node)));
     503             : }
     504             : 
     505             : static void
     506           0 : cnat_translation_last_lock_gone (fib_node_t * node)
     507             : {
     508           0 :  /**/}
     509             : 
     510             : /*
     511             :  * A back walk has reached this ABF policy
     512             :  */
     513             : static fib_node_back_walk_rc_t
     514          12 : cnat_translation_back_walk_notify (fib_node_t * node,
     515             :                                    fib_node_back_walk_ctx_t * ctx)
     516             : {
     517             :   /*
     518             :    * re-stack the fmask on the n-eos of the via
     519             :    */
     520          12 :   cnat_translation_t *ct = cnat_translation_get_from_node (node);
     521             : 
     522             :   /* If we have more than FIB_PATH_LIST_POPULAR paths
     523             :    * we might get called during path tracking
     524             :    * (cnat_tracker_track) */
     525          12 :   if (!(ct->flags & CNAT_TR_FLAG_STACKED))
     526           0 :     return (FIB_NODE_BACK_WALK_CONTINUE);
     527             : 
     528          12 :   cnat_translation_stack (ct);
     529             : 
     530          12 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     531             : }
     532             : 
     533             : /*
     534             :  * The translation's graph node virtual function table
     535             :  */
     536             : static const fib_node_vft_t cnat_translation_vft = {
     537             :   .fnv_get = cnat_translation_get_node,
     538             :   .fnv_last_lock = cnat_translation_last_lock_gone,
     539             :   .fnv_back_walk = cnat_translation_back_walk_notify,
     540             : };
     541             : 
     542             : static clib_error_t *
     543           0 : cnat_translation_cli_add_del (vlib_main_t * vm,
     544             :                               unformat_input_t * input,
     545             :                               vlib_cli_command_t * cmd)
     546             : {
     547           0 :   u32 del_index = INDEX_INVALID;
     548           0 :   ip_protocol_t proto = IP_PROTOCOL_TCP;
     549             :   cnat_endpoint_t vip;
     550           0 :   u8 flags = CNAT_FLAG_EXCLUSIVE;
     551           0 :   cnat_endpoint_tuple_t tmp, *paths = NULL, *path;
     552           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     553           0 :   clib_error_t *e = 0;
     554             :   cnat_lb_type_t lb_type;
     555             : 
     556             :   /* Get a line of input. */
     557           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     558           0 :     return 0;
     559             : 
     560           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     561             :     {
     562           0 :       if (unformat (line_input, "add"))
     563           0 :         del_index = INDEX_INVALID;
     564           0 :       else if (unformat (line_input, "del %d", &del_index))
     565             :         ;
     566             :       else
     567           0 :         if (unformat (line_input, "proto %U", unformat_ip_protocol, &proto))
     568             :         ;
     569           0 :       else if (unformat (line_input, "vip %U", unformat_cnat_ep, &vip))
     570           0 :         flags = CNAT_FLAG_EXCLUSIVE;
     571           0 :       else if (unformat (line_input, "real %U", unformat_cnat_ep, &vip))
     572           0 :         flags = 0;
     573           0 :       else if (unformat (line_input, "to %U", unformat_cnat_ep_tuple, &tmp))
     574             :         {
     575           0 :           vec_add2 (paths, path, 1);
     576           0 :           clib_memcpy (path, &tmp, sizeof (cnat_endpoint_tuple_t));
     577             :         }
     578           0 :       else if (unformat (line_input, "%U", unformat_cnat_lb_type, &lb_type))
     579             :         ;
     580             :       else
     581             :         {
     582           0 :           e = clib_error_return (0, "unknown input '%U'",
     583             :                                  format_unformat_error, line_input);
     584           0 :           goto done;
     585             :         }
     586             :     }
     587             : 
     588           0 :   flow_hash_config_t fhc = 0;
     589           0 :   if (INDEX_INVALID == del_index)
     590           0 :     cnat_translation_update (&vip, proto, paths, flags, lb_type, fhc);
     591             :   else
     592           0 :     cnat_translation_delete (del_index);
     593             : 
     594           0 : done:
     595           0 :   vec_free (paths);
     596           0 :   unformat_free (line_input);
     597           0 :   return (e);
     598             : }
     599             : 
     600      257065 : VLIB_CLI_COMMAND (cnat_translation_cli_add_del_command, static) =
     601             : {
     602             :   .path = "cnat translation",
     603             :   .short_help = "cnat translation [add|del] proto [TCP|UDP] [vip|real] [ip|sw_if_index [v6]] [port] [to [ip|sw_if_index [v6]] [port]->[ip|sw_if_index [v6]] [port]]",
     604             :   .function = cnat_translation_cli_add_del,
     605             : };
     606             : 
     607             : static void
     608           8 : cnat_if_addr_add_del_translation_cb (addr_resolution_t * ar,
     609             :                                      ip_address_t * address, u8 is_del)
     610             : {
     611             :   cnat_translation_t *ct;
     612           8 :   ct = cnat_translation_get (ar->cti);
     613           8 :   if (!is_del && ct->ct_vip.ce_flags & CNAT_EP_FLAG_RESOLVED)
     614           2 :     return;
     615             : 
     616           6 :   cnat_remove_translation_from_db (ct->ct_cci, &ct->ct_vip, ct->ct_proto);
     617             : 
     618           6 :   if (is_del)
     619             :     {
     620           4 :       ct->ct_vip.ce_flags &= ~CNAT_EP_FLAG_RESOLVED;
     621           4 :       ct->ct_cci = INDEX_INVALID;
     622           4 :       cnat_client_translation_deleted (ct->ct_cci);
     623             :       /* Are there remaining addresses ? */
     624           4 :       if (0 == cnat_resolve_addr (ar->sw_if_index, ar->af, address))
     625           2 :         is_del = 0;
     626             :     }
     627             : 
     628           6 :   if (!is_del)
     629             :     {
     630           4 :       ct->ct_cci = cnat_client_add (address, ct->flags);
     631           4 :       cnat_client_translation_added (ct->ct_cci);
     632           4 :       ip_address_copy (&ct->ct_vip.ce_ip, address);
     633           4 :       ct->ct_vip.ce_flags |= CNAT_EP_FLAG_RESOLVED;
     634             :     }
     635             : 
     636           6 :   cnat_add_translation_to_db (ct->ct_cci, &ct->ct_vip, ct->ct_proto,
     637             :                               ct->index);
     638             : }
     639             : 
     640             : static void
     641          32 : cnat_if_addr_add_del_backend_cb (addr_resolution_t * ar,
     642             :                                  ip_address_t * address, u8 is_del)
     643             : {
     644             :   cnat_translation_t *ct;
     645             :   cnat_ep_trk_t *trk;
     646             :   cnat_endpoint_t *ep;
     647             : 
     648          32 :   u8 direction = ar->opaque & 0xf;
     649          32 :   u32 path_idx = ar->opaque >> 32;
     650             : 
     651          32 :   ct = cnat_translation_get (ar->cti);
     652             : 
     653          32 :   trk = &ct->ct_paths[path_idx];
     654          32 :   ep = &trk->ct_ep[direction];
     655             : 
     656          32 :   if (!is_del && ep->ce_flags & CNAT_EP_FLAG_RESOLVED)
     657           8 :     return;
     658             : 
     659          24 :   ASSERT (ep->ce_sw_if_index == ar->sw_if_index);
     660             : 
     661          24 :   if (is_del)
     662             :     {
     663          16 :       ep->ce_flags &= ~CNAT_EP_FLAG_RESOLVED;
     664             :       /* Are there remaining addresses ? */
     665          16 :       if (0 == cnat_resolve_addr (ar->sw_if_index, ar->af, address))
     666           8 :         is_del = 0;
     667             :     }
     668             : 
     669          24 :   if (!is_del)
     670             :     {
     671          16 :       ip_address_copy (&ep->ce_ip, address);
     672          16 :       ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
     673             :     }
     674             : 
     675          24 :   ct->flags &= ~CNAT_TR_FLAG_STACKED;
     676          24 :   cnat_tracker_track (ar->cti, trk);
     677             : 
     678          24 :   cnat_translation_stack (ct);
     679          24 :   ct->flags |= CNAT_TR_FLAG_STACKED;
     680             : }
     681             : 
     682             : static void
     683        8953 : cnat_if_addr_add_del_callback (u32 sw_if_index, ip_address_t * address,
     684             :                                u8 is_del)
     685             : {
     686             :   addr_resolution_t *ar;
     687        9129 :   pool_foreach (ar, tr_resolutions)
     688             :     {
     689         176 :       if (ar->sw_if_index != sw_if_index)
     690         120 :         continue;
     691          56 :       if (ar->af != ip_addr_version (address))
     692           8 :         continue;
     693          48 :       cnat_if_addr_add_cbs[ar->type](ar, address, is_del);
     694             :     }
     695        8953 : }
     696             : 
     697             : static void
     698        4115 : cnat_ip6_if_addr_add_del_callback (struct ip6_main_t *im,
     699             :                                    uword opaque, u32 sw_if_index,
     700             :                                    ip6_address_t * address,
     701             :                                    u32 address_length, u32 if_address_index,
     702             :                                    u32 is_del)
     703             : {
     704             :   ip_address_t addr;
     705        4115 :   ip_address_set (&addr, address, AF_IP6);
     706        4115 :   cnat_if_addr_add_del_callback (sw_if_index, &addr, is_del);
     707        4115 : }
     708             : 
     709             : static void
     710        4838 : cnat_ip4_if_addr_add_del_callback (struct ip4_main_t *im,
     711             :                                    uword opaque, u32 sw_if_index,
     712             :                                    ip4_address_t * address,
     713             :                                    u32 address_length, u32 if_address_index,
     714             :                                    u32 is_del)
     715             : {
     716             :   ip_address_t addr;
     717        4838 :   ip_address_set (&addr, address, AF_IP4);
     718        4838 :   cnat_if_addr_add_del_callback (sw_if_index, &addr, is_del);
     719        4838 : }
     720             : 
     721             : void
     722        1725 : cnat_translation_register_addr_add_cb (cnat_addr_resol_type_t typ,
     723             :                                        cnat_if_addr_add_cb_t fn)
     724             : {
     725        1725 :   vec_validate (cnat_if_addr_add_cbs, CNAT_ADDR_N_RESOLUTIONS);
     726        1725 :   cnat_if_addr_add_cbs[typ] = fn;
     727        1725 : }
     728             : 
     729             : static clib_error_t *
     730         575 : cnat_translation_init (vlib_main_t * vm)
     731             : {
     732         575 :   ip4_main_t *i4m = &ip4_main;
     733         575 :   ip6_main_t *i6m = &ip6_main;
     734         575 :   cnat_main_t *cm = &cnat_main;
     735         575 :   cnat_translation_fib_node_type =
     736         575 :     fib_node_register_new_type ("cnat-translation", &cnat_translation_vft);
     737             : 
     738         575 :   clib_bihash_init_8_8 (&cnat_translation_db, "CNat translation DB",
     739             :                         cm->translation_hash_buckets,
     740             :                         cm->translation_hash_memory);
     741             : 
     742         575 :   ip4_add_del_interface_address_callback_t cb4 = { 0 };
     743         575 :   cb4.function = cnat_ip4_if_addr_add_del_callback;
     744         575 :   vec_add1 (i4m->add_del_interface_address_callbacks, cb4);
     745             : 
     746         575 :   ip6_add_del_interface_address_callback_t cb6 = { 0 };
     747         575 :   cb6.function = cnat_ip6_if_addr_add_del_callback;
     748         575 :   vec_add1 (i6m->add_del_interface_address_callbacks, cb6);
     749             : 
     750         575 :   cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_BACKEND,
     751             :                                          cnat_if_addr_add_del_backend_cb);
     752         575 :   cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_TRANSLATION,
     753             :                                          cnat_if_addr_add_del_translation_cb);
     754             : 
     755         575 :   return (NULL);
     756             : }
     757             : 
     758        2879 : VLIB_INIT_FUNCTION (cnat_translation_init);
     759             : 
     760             : /*
     761             :  * fd.io coding-style-patch-verification: ON
     762             :  *
     763             :  * Local Variables:
     764             :  * eval: (c-set-style "gnu")
     765             :  * End:
     766             :  */

Generated by: LCOV version 1.14