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

Generated by: LCOV version 1.14