LCOV - code coverage report
Current view: top level - plugins/nat/nat64 - nat64.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 453 755 60.0 %
Date: 2023-07-05 22:20:52 Functions: 44 55 80.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vppinfra/crc32.h>
      17             : #include <vnet/fib/ip4_fib.h>
      18             : 
      19             : #include <vnet/ip/reass/ip4_sv_reass.h>
      20             : #include <vnet/ip/reass/ip6_sv_reass.h>
      21             : #include <vnet/plugin/plugin.h>
      22             : #include <vpp/app/version.h>
      23             : 
      24             : #include <nat/lib/ipfix_logging.h>
      25             : #include <nat/nat64/nat64.h>
      26             : 
      27             : nat64_main_t nat64_main;
      28             : 
      29             : /* *INDENT-OFF* */
      30             : /* Hook up input features */
      31       31919 : VNET_FEATURE_INIT (nat64_in2out, static) = {
      32             :   .arc_name = "ip6-unicast",
      33             :   .node_name = "nat64-in2out",
      34             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
      35             :   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
      36             : };
      37       31919 : VNET_FEATURE_INIT (nat64_out2in, static) = {
      38             :   .arc_name = "ip4-unicast",
      39             :   .node_name = "nat64-out2in",
      40             :   .runs_before = VNET_FEATURES ("ip4-lookup"),
      41             :   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
      42             : };
      43       31919 : VNET_FEATURE_INIT (nat64_in2out_handoff, static) = {
      44             :   .arc_name = "ip6-unicast",
      45             :   .node_name = "nat64-in2out-handoff",
      46             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
      47             :   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
      48             : };
      49       31919 : VNET_FEATURE_INIT (nat64_out2in_handoff, static) = {
      50             :   .arc_name = "ip4-unicast",
      51             :   .node_name = "nat64-out2in-handoff",
      52             :   .runs_before = VNET_FEATURES ("ip4-lookup"),
      53             :   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
      54             : };
      55             : VLIB_PLUGIN_REGISTER () = {
      56             :     .version = VPP_BUILD_VER,
      57             :     .description = "NAT64",
      58             : };
      59             : static u8 well_known_prefix[] = {
      60             :   0x00, 0x64, 0xff, 0x9b,
      61             :   0x00, 0x00, 0x00, 0x00,
      62             :   0x00, 0x00, 0x00, 0x00,
      63             :   0x00, 0x00, 0x00, 0x00
      64             : };
      65             : /* *INDENT-ON* */
      66             : 
      67             : #define nat_elog_str(_str)                      \
      68             : do                                              \
      69             :   {                                             \
      70             :     ELOG_TYPE_DECLARE (e) =                     \
      71             :       {                                         \
      72             :         .format = "nat-msg " _str,              \
      73             :         .format_args = "",                      \
      74             :       };                                        \
      75             :     ELOG_DATA (&vlib_global_main.elog_main, e); \
      76             :   } while (0);
      77             : 
      78             : static void
      79        4699 : nat64_ip4_add_del_interface_address_cb (ip4_main_t * im, uword opaque,
      80             :                                         u32 sw_if_index,
      81             :                                         ip4_address_t * address,
      82             :                                         u32 address_length,
      83             :                                         u32 if_address_index, u32 is_delete)
      84             : {
      85        4699 :   nat64_main_t *nm = &nat64_main;
      86             :   int i, j;
      87             : 
      88        4699 :   if (plugin_enabled () == 0)
      89        4697 :     return;
      90             : 
      91           2 :   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
      92             :     {
      93           2 :       if (sw_if_index == nm->auto_add_sw_if_indices[i])
      94             :         {
      95           2 :           if (!is_delete)
      96             :             {
      97             :               /* Don't trip over lease renewal, static config */
      98           1 :               for (j = 0; j < vec_len (nm->addr_pool); j++)
      99           0 :                 if (nm->addr_pool[j].addr.as_u32 == address->as_u32)
     100           0 :                   return;
     101             : 
     102           1 :               (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
     103             :                                               address, ~0, 1);
     104           1 :               return;
     105             :             }
     106             :           else
     107             :             {
     108           1 :               (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
     109             :                                               address, ~0, 0);
     110           1 :               return;
     111             :             }
     112             :         }
     113             :     }
     114             : }
     115             : 
     116             : u32
     117           0 : nat64_get_worker_in2out (ip6_address_t * addr)
     118             : {
     119           0 :   nat64_main_t *nm = &nat64_main;
     120           0 :   u32 next_worker_index = nm->first_worker_index;
     121             :   u32 hash;
     122             : 
     123             : #ifdef clib_crc32c_uses_intrinsics
     124           0 :   hash = clib_crc32c ((u8 *) addr->as_u32, 16);
     125             : #else
     126             :   u64 tmp = addr->as_u64[0] ^ addr->as_u64[1];
     127             :   hash = clib_xxhash (tmp);
     128             : #endif
     129             : 
     130           0 :   if (PREDICT_TRUE (is_pow2 (_vec_len (nm->workers))))
     131           0 :     next_worker_index += nm->workers[hash & (_vec_len (nm->workers) - 1)];
     132             :   else
     133           0 :     next_worker_index += nm->workers[hash % _vec_len (nm->workers)];
     134             : 
     135           0 :   return next_worker_index;
     136             : }
     137             : 
     138             : static u32
     139           0 : get_thread_idx_by_port (u16 e_port)
     140             : {
     141           0 :   nat64_main_t *nm = &nat64_main;
     142           0 :   u32 thread_idx = nm->num_workers;
     143           0 :   if (nm->num_workers > 1)
     144             :     {
     145           0 :       thread_idx = nm->first_worker_index +
     146           0 :                    nm->workers[(e_port - 1024) / nm->port_per_thread %
     147           0 :                                _vec_len (nm->workers)];
     148             :     }
     149           0 :   return thread_idx;
     150             : }
     151             : 
     152             : u32
     153           0 : nat64_get_worker_out2in (vlib_buffer_t * b, ip4_header_t * ip)
     154             : {
     155           0 :   nat64_main_t *nm = &nat64_main;
     156             :   udp_header_t *udp;
     157             :   u16 port;
     158             :   u32 proto;
     159             : 
     160           0 :   proto = ip_proto_to_nat_proto (ip->protocol);
     161           0 :   udp = ip4_next_header (ip);
     162           0 :   port = udp->dst_port;
     163             : 
     164             :   /* unknown protocol */
     165           0 :   if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
     166             :     {
     167             :       nat64_db_t *db;
     168             :       ip46_address_t daddr;
     169             :       nat64_db_bib_entry_t *bibe;
     170             : 
     171           0 :       clib_memset (&daddr, 0, sizeof (daddr));
     172           0 :       daddr.ip4.as_u32 = ip->dst_address.as_u32;
     173             : 
     174             :       /* *INDENT-OFF* */
     175           0 :       vec_foreach (db, nm->db)
     176             :         {
     177           0 :           bibe = nat64_db_bib_entry_find (db, &daddr, 0, ip->protocol, 0, 0);
     178           0 :           if (bibe)
     179           0 :             return (u32) (db - nm->db);
     180             :         }
     181             :       /* *INDENT-ON* */
     182           0 :       return vlib_get_thread_index ();
     183             :     }
     184             : 
     185             :   /* ICMP */
     186           0 :   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
     187             :     {
     188           0 :       icmp46_header_t *icmp = (icmp46_header_t *) udp;
     189           0 :       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
     190           0 :       if (!icmp_type_is_error_message
     191           0 :           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
     192           0 :         port = vnet_buffer (b)->ip.reass.l4_src_port;
     193             :       else
     194             :         {
     195             :           /* if error message, then it's not fragmented and we can access it */
     196           0 :           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
     197           0 :           proto = ip_proto_to_nat_proto (inner_ip->protocol);
     198           0 :           void *l4_header = ip4_next_header (inner_ip);
     199           0 :           switch (proto)
     200             :             {
     201           0 :             case NAT_PROTOCOL_ICMP:
     202           0 :               icmp = (icmp46_header_t *) l4_header;
     203           0 :               echo = (icmp_echo_header_t *) (icmp + 1);
     204           0 :               port = echo->identifier;
     205           0 :               break;
     206           0 :             case NAT_PROTOCOL_UDP:
     207             :             case NAT_PROTOCOL_TCP:
     208           0 :               port = ((tcp_udp_header_t *) l4_header)->src_port;
     209           0 :               break;
     210           0 :             default:
     211           0 :               return vlib_get_thread_index ();
     212             :             }
     213           0 :         }
     214             :     }
     215             : 
     216             :   /* worker by outside port  (TCP/UDP) */
     217           0 :   port = clib_net_to_host_u16 (port);
     218           0 :   if (port > 1024)
     219           0 :     return get_thread_idx_by_port (port);
     220             : 
     221           0 :   return vlib_get_thread_index ();
     222             : }
     223             : 
     224             : clib_error_t *
     225         559 : nat64_init (vlib_main_t * vm)
     226             : {
     227         559 :   nat64_main_t *nm = &nat64_main;
     228         559 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     229             :   ip4_add_del_interface_address_callback_t cb4;
     230             :   vlib_node_t *node;
     231             : 
     232         559 :   clib_memset (nm, 0, sizeof (*nm));
     233             : 
     234         559 :   nm->ip4_main = &ip4_main;
     235         559 :   nm->log_class = vlib_log_register_class ("nat64", 0);
     236             : 
     237         559 :   nm->port_per_thread = 0xffff - 1024;
     238             : 
     239         559 :   nm->fq_in2out_index = ~0;
     240         559 :   nm->fq_out2in_index = ~0;
     241             : 
     242         559 :   node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
     243         559 :   nm->error_node_index = node->index;
     244         559 :   node = vlib_get_node_by_name (vm, (u8 *) "nat64-in2out");
     245         559 :   nm->in2out_node_index = node->index;
     246         559 :   node = vlib_get_node_by_name (vm, (u8 *) "nat64-in2out-slowpath");
     247         559 :   nm->in2out_slowpath_node_index = node->index;
     248         559 :   node = vlib_get_node_by_name (vm, (u8 *) "nat64-out2in");
     249         559 :   nm->out2in_node_index = node->index;
     250             : 
     251         559 :   node = vlib_get_node_by_name (vm, (u8 *) "nat64-expire-worker-walk");
     252         559 :   nm->expire_worker_walk_node_index = node->index;
     253             : 
     254         559 :   nm->fib_src_hi = fib_source_allocate ("nat64-hi",
     255             :                                         FIB_SOURCE_PRIORITY_HI,
     256             :                                         FIB_SOURCE_BH_SIMPLE);
     257         559 :   nm->fib_src_low = fib_source_allocate ("nat64-low",
     258             :                                          FIB_SOURCE_PRIORITY_LOW,
     259             :                                          FIB_SOURCE_BH_SIMPLE);
     260             : 
     261             :   // set protocol timeouts to defaults
     262         559 :   nat64_reset_timeouts ();
     263             : 
     264             :   /* Set up the interface address add/del callback */
     265         559 :   cb4.function = nat64_ip4_add_del_interface_address_cb;
     266         559 :   cb4.function_opaque = 0;
     267         559 :   vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cb4);
     268             : 
     269             :   /* Init counters */
     270         559 :   nm->total_bibs.name = "total-bibs";
     271         559 :   nm->total_bibs.stat_segment_name = "/nat64/total-bibs";
     272         559 :   vlib_validate_simple_counter (&nm->total_bibs, 0);
     273         559 :   vlib_zero_simple_counter (&nm->total_bibs, 0);
     274         559 :   nm->total_sessions.name = "total-sessions";
     275         559 :   nm->total_sessions.stat_segment_name = "/nat64/total-sessions";
     276         559 :   vlib_validate_simple_counter (&nm->total_sessions, 0);
     277         559 :   vlib_zero_simple_counter (&nm->total_sessions, 0);
     278             : 
     279         559 :   uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers");
     280         559 :   if (p)
     281             :     {
     282             :       vlib_thread_registration_t *tr;
     283         559 :       tr = (vlib_thread_registration_t *) p[0];
     284         559 :       if (tr)
     285             :         {
     286         559 :           nm->num_workers = tr->count;
     287         559 :           nm->first_worker_index = tr->first_index;
     288             :         }
     289             :     }
     290             : 
     291         559 :   if (nm->num_workers > 1)
     292             :     {
     293             :       int i;
     294          14 :       uword *bitmap = 0;
     295             : 
     296          46 :       for (i = 0; i < nm->num_workers; i++)
     297          32 :         bitmap = clib_bitmap_set (bitmap, i, 1);
     298             : 
     299             :       /* *INDENT-OFF* */
     300          46 :       clib_bitmap_foreach (i, bitmap)
     301             :          {
     302          32 :           vec_add1(nm->workers, i);
     303             :         }
     304             :       /* *INDENT-ON* */
     305             : 
     306          14 :       clib_bitmap_free (bitmap);
     307             : 
     308          14 :       nm->port_per_thread = (0xffff - 1024) / _vec_len (nm->workers);
     309             :     }
     310             : 
     311             :   /* Init IPFIX logging */
     312         559 :   nat_ipfix_logging_init (vm);
     313             : 
     314             : #define _(x)                                                     \
     315             :   nm->counters.in2out.x.name = #x;                               \
     316             :   nm->counters.in2out.x.stat_segment_name = "/nat64/in2out/" #x; \
     317             :   nm->counters.out2in.x.name = #x;                               \
     318             :   nm->counters.out2in.x.stat_segment_name = "/nat64/out2in/" #x;
     319         559 :   foreach_nat_counter;
     320             : #undef _
     321         559 :   return nat64_api_hookup (vm);
     322             : }
     323             : 
     324        1119 : VLIB_INIT_FUNCTION (nat64_init);
     325             : 
     326             : static void nat64_free_out_addr_and_port (struct nat64_db_s *db,
     327             :                                           ip4_address_t * addr, u16 port,
     328             :                                           u8 protocol);
     329             : 
     330             : int
     331          20 : nat64_init_hash (nat64_config_t c)
     332             : {
     333          20 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     334          20 :   nat64_main_t *nm = &nat64_main;
     335             :   nat64_db_t *db;
     336          20 :   int rv = 0;
     337             : 
     338          20 :   vec_validate (nm->db, tm->n_vlib_mains - 1);
     339             : 
     340             :   /* *INDENT-OFF* */
     341          40 :   vec_foreach (db, nm->db)
     342             :     {
     343          20 :       if (nat64_db_init (db, c, nat64_free_out_addr_and_port))
     344             :         {
     345           0 :           nat64_log_err ("NAT64 DB init failed");
     346           0 :           rv = 1;
     347             :         }
     348             :     }
     349             :   /* *INDENT-ON* */
     350             : 
     351          20 :   return rv;
     352             : }
     353             : 
     354             : int
     355          20 : nat64_free_hash ()
     356             : {
     357          20 :   nat64_main_t *nm = &nat64_main;
     358             :   nat64_db_t *db;
     359          20 :   int rv = 0;
     360             : 
     361             :   /* *INDENT-OFF* */
     362          40 :   vec_foreach (db, nm->db)
     363             :     {
     364          20 :       if (nat64_db_free (db))
     365             :         {
     366           0 :           nat64_log_err ("NAT64 DB free failed");
     367           0 :           rv = 1;
     368             :         }
     369             :     }
     370             :   /* *INDENT-ON* */
     371             : 
     372          20 :   vec_free (nm->db);
     373             : 
     374          20 :   return rv;
     375             : }
     376             : 
     377             : int
     378          32 : nat64_add_del_pool_addr (u32 thread_index,
     379             :                          ip4_address_t * addr, u32 vrf_id, u8 is_add)
     380             : {
     381          32 :   nat64_main_t *nm = &nat64_main;
     382          32 :   nat64_address_t *a = 0;
     383             :   nat64_interface_t *interface;
     384             :   int i;
     385             :   nat64_db_t *db;
     386          32 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     387             : 
     388             :   /* Check if address already exists */
     389          89 :   for (i = 0; i < vec_len (nm->addr_pool); i++)
     390             :     {
     391          61 :       if (nm->addr_pool[i].addr.as_u32 == addr->as_u32)
     392             :         {
     393           4 :           a = nm->addr_pool + i;
     394           4 :           break;
     395             :         }
     396             :     }
     397             : 
     398          32 :   if (is_add)
     399             :     {
     400          28 :       if (a)
     401           0 :         return VNET_API_ERROR_VALUE_EXIST;
     402             : 
     403          28 :       vec_add2 (nm->addr_pool, a, 1);
     404          28 :       a->addr = *addr;
     405          28 :       a->fib_index = ~0;
     406          28 :       if (vrf_id != ~0)
     407           2 :         a->fib_index =
     408           2 :           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
     409           2 :                                              nm->fib_src_hi);
     410             : #define _(N, id, n, s) \
     411             :       clib_memset (a->busy_##n##_port_refcounts, 0, sizeof(a->busy_##n##_port_refcounts)); \
     412             :       a->busy_##n##_ports = 0; \
     413             :       vec_validate_init_empty (a->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
     414         124 :       foreach_nat_protocol
     415             : #undef _
     416             :     }
     417             :   else
     418             :     {
     419           4 :       if (!a)
     420           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     421             : 
     422           4 :       if (a->fib_index != ~0)
     423           0 :         fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6, nm->fib_src_hi);
     424             :       /* Delete sessions using address */
     425             :       /* *INDENT-OFF* */
     426           8 :       vec_foreach (db, nm->db)
     427             :         {
     428           4 :           nat64_db_free_out_addr (thread_index, db, &a->addr);
     429           4 :           vlib_set_simple_counter (&nm->total_bibs, db - nm->db, 0,
     430           4 :                                    db->bib.bib_entries_num);
     431           4 :           vlib_set_simple_counter (&nm->total_sessions, db - nm->db, 0,
     432           4 :                                    db->st.st_entries_num);
     433             :         }
     434             :       /* *INDENT-ON* */
     435           4 :       vec_del1 (nm->addr_pool, i);
     436             :     }
     437             : 
     438             :   /* Add/del external address to FIB */
     439             :   /* *INDENT-OFF* */
     440          36 :   pool_foreach (interface, nm->interfaces)
     441             :    {
     442           8 :     if (nat64_interface_is_inside(interface))
     443           4 :       continue;
     444             : 
     445           4 :     nat64_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add);
     446           4 :     break;
     447             :   }
     448             :   /* *INDENT-ON* */
     449             : 
     450          32 :   return 0;
     451             : }
     452             : 
     453             : void
     454          24 : nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx)
     455             : {
     456          24 :   nat64_main_t *nm = &nat64_main;
     457          24 :   nat64_address_t *a = 0;
     458             : 
     459             :   /* *INDENT-OFF* */
     460          50 :   vec_foreach (a, nm->addr_pool)
     461             :     {
     462          26 :       if (fn (a, ctx))
     463           0 :         break;
     464             :     };
     465             :   /* *INDENT-ON* */
     466          24 : }
     467             : 
     468             : int
     469           1 : nat64_add_interface_address (u32 sw_if_index, int is_add)
     470             : {
     471           1 :   nat64_main_t *nm = &nat64_main;
     472           1 :   ip4_main_t *ip4_main = nm->ip4_main;
     473             :   ip4_address_t *first_int_addr;
     474             :   int i;
     475             : 
     476           1 :   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
     477             : 
     478           1 :   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
     479             :     {
     480           0 :       if (nm->auto_add_sw_if_indices[i] == sw_if_index)
     481             :         {
     482           0 :           if (is_add)
     483           0 :             return VNET_API_ERROR_VALUE_EXIST;
     484             :           else
     485             :             {
     486             :               /* if have address remove it */
     487           0 :               if (first_int_addr)
     488           0 :                 (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
     489             :                                                 first_int_addr, ~0, 0);
     490           0 :               vec_del1 (nm->auto_add_sw_if_indices, i);
     491           0 :               return 0;
     492             :             }
     493             :         }
     494             :     }
     495             : 
     496           1 :   if (!is_add)
     497           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     498             : 
     499             :   /* add to the auto-address list */
     500           1 :   vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
     501             : 
     502             :   /* If the address is already bound - or static - add it now */
     503           1 :   if (first_int_addr)
     504           0 :     (void) nat64_add_del_pool_addr (vlib_get_thread_index (),
     505             :                                     first_int_addr, ~0, 1);
     506             : 
     507           1 :   return 0;
     508             : }
     509             : 
     510             : static void
     511          32 : nat64_validate_counters (nat64_main_t * nm, u32 sw_if_index)
     512             : {
     513             : #define _(x)                                                          \
     514             :   vlib_validate_simple_counter (&nm->counters.in2out.x, sw_if_index); \
     515             :   vlib_zero_simple_counter (&nm->counters.in2out.x, sw_if_index);     \
     516             :   vlib_validate_simple_counter (&nm->counters.out2in.x, sw_if_index); \
     517             :   vlib_zero_simple_counter (&nm->counters.out2in.x, sw_if_index);
     518          32 :   foreach_nat_counter;
     519             : #undef _
     520          32 : }
     521             : 
     522             : void
     523          28 : nat64_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
     524             :                            int is_add)
     525             : {
     526          28 :   nat64_main_t *nm = &nat64_main;
     527          28 :   fib_prefix_t prefix = {
     528             :     .fp_len = p_len,
     529             :     .fp_proto = FIB_PROTOCOL_IP4,
     530             :     .fp_addr = {
     531          28 :                 .ip4.as_u32 = addr->as_u32,
     532             :                 },
     533             :   };
     534          28 :   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
     535             : 
     536          28 :   if (is_add)
     537          26 :     fib_table_entry_update_one_path (fib_index,
     538             :                                      &prefix,
     539          26 :                                      nm->fib_src_low,
     540             :                                      (FIB_ENTRY_FLAG_CONNECTED |
     541             :                                       FIB_ENTRY_FLAG_LOCAL |
     542             :                                       FIB_ENTRY_FLAG_EXCLUSIVE),
     543             :                                      DPO_PROTO_IP4,
     544             :                                      NULL,
     545             :                                      sw_if_index,
     546             :                                      ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
     547             :   else
     548           2 :     fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
     549          28 : }
     550             : 
     551             : int
     552          65 : nat64_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
     553             : {
     554          65 :   vlib_main_t *vm = vlib_get_main ();
     555          65 :   nat64_main_t *nm = &nat64_main;
     556          65 :   nat64_interface_t *interface = 0, *i;
     557             :   nat64_address_t *ap;
     558             :   const char *feature_name, *arc_name;
     559             : 
     560             :   // TODO: is enabled ? we can't signal if it is not
     561             : 
     562             :   /* Check if interface already exists */
     563             :   /* *INDENT-OFF* */
     564          83 :   pool_foreach (i, nm->interfaces)
     565             :    {
     566          51 :     if (i->sw_if_index == sw_if_index)
     567             :       {
     568          33 :         interface = i;
     569          33 :         break;
     570             :       }
     571             :   }
     572             :   /* *INDENT-ON* */
     573             : 
     574          65 :   if (is_add)
     575             :     {
     576          33 :       if (interface)
     577           1 :         goto set_flags;
     578             : 
     579          32 :       pool_get (nm->interfaces, interface);
     580          32 :       interface->sw_if_index = sw_if_index;
     581          32 :       interface->flags = 0;
     582          32 :       nat64_validate_counters (nm, sw_if_index);
     583          33 :     set_flags:
     584          33 :       if (is_inside)
     585          18 :         interface->flags |= NAT64_INTERFACE_FLAG_IS_INSIDE;
     586             :       else
     587          15 :         interface->flags |= NAT64_INTERFACE_FLAG_IS_OUTSIDE;
     588             : 
     589          33 :       nm->total_enabled_count++;
     590          33 :       vlib_process_signal_event (vm,
     591          33 :                                  nm->expire_walk_node_index,
     592             :                                  NAT64_CLEANER_RESCHEDULE, 0);
     593             : 
     594             :     }
     595             :   else
     596             :     {
     597          32 :       if (!interface)
     598           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     599             : 
     600          32 :       if ((nat64_interface_is_inside (interface)
     601          18 :            && nat64_interface_is_outside (interface)))
     602           1 :         interface->flags &=
     603             :           is_inside ? ~NAT64_INTERFACE_FLAG_IS_INSIDE :
     604             :           ~NAT64_INTERFACE_FLAG_IS_OUTSIDE;
     605             :       else
     606          31 :         pool_put (nm->interfaces, interface);
     607             : 
     608          32 :       nm->total_enabled_count--;
     609             :     }
     610             : 
     611          65 :   if (!is_inside)
     612             :     {
     613             :       /* *INDENT-OFF* */
     614          39 :       vec_foreach (ap, nm->addr_pool)
     615          24 :         nat64_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add);
     616             :       /* *INDENT-ON* */
     617             :     }
     618             : 
     619          65 :   if (nm->num_workers > 1)
     620             :     {
     621           0 :       feature_name =
     622             :         is_inside ? "nat64-in2out-handoff" : "nat64-out2in-handoff";
     623           0 :       if (nm->fq_in2out_index == ~0)
     624           0 :         nm->fq_in2out_index =
     625           0 :           vlib_frame_queue_main_init (nat64_in2out_node.index, 0);
     626           0 :       if (nm->fq_out2in_index == ~0)
     627           0 :         nm->fq_out2in_index =
     628           0 :           vlib_frame_queue_main_init (nat64_out2in_node.index, 0);
     629             :     }
     630             :   else
     631          65 :     feature_name = is_inside ? "nat64-in2out" : "nat64-out2in";
     632             : 
     633          65 :   arc_name = is_inside ? "ip6-unicast" : "ip4-unicast";
     634             : 
     635          65 :   if (is_inside)
     636             :     {
     637          50 :       int rv = ip6_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
     638          50 :       if (rv)
     639           0 :         return rv;
     640             :     }
     641             :   else
     642             :     {
     643          15 :       int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
     644          15 :       if (rv)
     645           0 :         return rv;
     646             :     }
     647             : 
     648          65 :   return vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
     649             :                                       is_add, 0, 0);
     650             : }
     651             : 
     652             : void
     653          22 : nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx)
     654             : {
     655          22 :   nat64_main_t *nm = &nat64_main;
     656          22 :   nat64_interface_t *i = 0;
     657             : 
     658             :   /* *INDENT-OFF* */
     659          54 :   pool_foreach (i, nm->interfaces)
     660             :    {
     661          32 :     if (fn (i, ctx))
     662           0 :       break;
     663             :   }
     664             :   /* *INDENT-ON* */
     665          22 : }
     666             : 
     667             : // TODO: plugin independent
     668             : static_always_inline u16
     669          27 : nat64_random_port (u16 min, u16 max)
     670             : {
     671          27 :   nat64_main_t *nm = &nat64_main;
     672             :   u32 rwide;
     673             :   u16 r;
     674             : 
     675          27 :   rwide = random_u32 (&nm->random_seed);
     676          27 :   r = rwide & 0xFFFF;
     677          27 :   if (r >= min && r <= max)
     678          27 :     return r;
     679             : 
     680           0 :   return min + (rwide % (max - min + 1));
     681             : }
     682             : 
     683             : static_always_inline int
     684          27 : nat64_alloc_addr_and_port_default (nat64_address_t * addresses,
     685             :                                    u32 fib_index,
     686             :                                    u32 thread_index,
     687             :                                    nat_protocol_t proto,
     688             :                                    ip4_address_t * addr,
     689             :                                    u16 * port,
     690             :                                    u16 port_per_thread, u32 nat_thread_index)
     691             : {
     692             :   int i;
     693          27 :   nat64_address_t *a, *ga = 0;
     694             :   u32 portnum;
     695             : 
     696          57 :   for (i = 0; i < vec_len (addresses); i++)
     697             :     {
     698          36 :       a = addresses + i;
     699          36 :       switch (proto)
     700             :         {
     701             : #define _(N, j, n, s) \
     702             :         case NAT_PROTOCOL_##N: \
     703             :           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
     704             :             { \
     705             :               if (a->fib_index == fib_index) \
     706             :                 { \
     707             :                   while (1) \
     708             :                     { \
     709             :                       portnum = (port_per_thread * \
     710             :                         nat_thread_index) + \
     711             :                         nat64_random_port(0, port_per_thread - 1) + 1024; \
     712             :                       if (a->busy_##n##_port_refcounts[portnum]) \
     713             :                         continue; \
     714             :                       --a->busy_##n##_port_refcounts[portnum]; \
     715             :                       a->busy_##n##_ports_per_thread[thread_index]++; \
     716             :                       a->busy_##n##_ports++; \
     717             :                       *addr = a->addr; \
     718             :                       *port = clib_host_to_net_u16(portnum); \
     719             :                       return 0; \
     720             :                     } \
     721             :                 } \
     722             :               else if (a->fib_index == ~0) \
     723             :                 { \
     724             :                   ga = a; \
     725             :                 } \
     726             :             } \
     727             :           break;
     728          36 :           foreach_nat_protocol
     729             : #undef _
     730           0 :         default:
     731           0 :           return 1;
     732             :         }
     733             : 
     734             :     }
     735             : 
     736          21 :   if (ga)
     737             :     {
     738          21 :       a = ga;
     739          21 :       switch (proto)
     740             :         {
     741             : #define _(N, j, n, s) \
     742             :         case NAT_PROTOCOL_##N: \
     743             :           while (1) \
     744             :             { \
     745             :               portnum = (port_per_thread * \
     746             :                 nat_thread_index) + \
     747             :                 nat64_random_port(0, port_per_thread - 1) + 1024; \
     748             :               if (a->busy_##n##_port_refcounts[portnum]) \
     749             :                 continue; \
     750             :               ++a->busy_##n##_port_refcounts[portnum]; \
     751             :               a->busy_##n##_ports_per_thread[thread_index]++; \
     752             :               a->busy_##n##_ports++; \
     753             :               *addr = a->addr; \
     754             :               *port = clib_host_to_net_u16(portnum); \
     755             :               return 0; \
     756             :             }
     757             :           break;
     758          21 :           foreach_nat_protocol
     759             : #undef _
     760           0 :         default:
     761           0 :           return 1;
     762             :         }
     763           0 :     }
     764             : 
     765             :   /* Totally out of translations to use... */
     766           0 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
     767           0 :   return 1;
     768             : }
     769             : 
     770             : int
     771          27 : nat64_alloc_out_addr_and_port (u32 fib_index, nat_protocol_t proto,
     772             :                                ip4_address_t * addr, u16 * port,
     773             :                                u32 thread_index)
     774             : {
     775          27 :   nat64_main_t *nm = &nat64_main;
     776          27 :   u32 worker_index = 0;
     777             :   int rv;
     778             : 
     779          27 :   if (nm->num_workers > 1)
     780           0 :     worker_index = thread_index - nm->first_worker_index;
     781             : 
     782          27 :   rv = nat64_alloc_addr_and_port_default (nm->addr_pool, fib_index,
     783             :                                           thread_index,
     784             :                                           proto, addr, port,
     785          27 :                                           nm->port_per_thread, worker_index);
     786             : 
     787          27 :   return rv;
     788             : }
     789             : 
     790             : static void
     791           3 : nat64_free_out_addr_and_port (struct nat64_db_s *db, ip4_address_t * addr,
     792             :                               u16 port, u8 protocol)
     793             : {
     794           3 :   nat64_main_t *nm = &nat64_main;
     795           3 :   u32 thread_index = db - nm->db;
     796           3 :   nat_protocol_t proto = ip_proto_to_nat_proto (protocol);
     797           3 :   u16 port_host_byte_order = clib_net_to_host_u16 (port);
     798             :   nat64_address_t *a;
     799             :   int i;
     800             : 
     801           3 :   for (i = 0; i < vec_len (nm->addr_pool); i++)
     802             :     {
     803           2 :       a = nm->addr_pool + i;
     804           2 :       if (addr->as_u32 != a->addr.as_u32)
     805           0 :         continue;
     806           2 :       switch (proto)
     807             :         {
     808             : #define _(N, j, n, s) \
     809             :         case NAT_PROTOCOL_##N: \
     810             :           ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
     811             :           --a->busy_##n##_port_refcounts[port_host_byte_order]; \
     812             :           a->busy_##n##_ports--; \
     813             :           a->busy_##n##_ports_per_thread[thread_index]--; \
     814             :           break;
     815           2 :           foreach_nat_protocol
     816             : #undef _
     817           0 :         default:
     818           0 :           nat_elog_str ("unknown protocol");
     819           0 :           return;
     820             :         }
     821           2 :       break;
     822             :     }
     823             : }
     824             : 
     825             : /**
     826             :  * @brief Add/delete static BIB entry in worker thread.
     827             :  */
     828             : static uword
     829           0 : nat64_static_bib_worker_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
     830             :                             vlib_frame_t * f)
     831             : {
     832           0 :   nat64_main_t *nm = &nat64_main;
     833           0 :   u32 thread_index = vm->thread_index;
     834           0 :   nat64_db_t *db = &nm->db[thread_index];
     835             :   nat64_static_bib_to_update_t *static_bib;
     836             :   nat64_db_bib_entry_t *bibe;
     837             :   ip46_address_t addr;
     838             : 
     839             :   /* *INDENT-OFF* */
     840           0 :   pool_foreach (static_bib, nm->static_bibs)
     841             :    {
     842           0 :     if ((static_bib->thread_index != thread_index) || (static_bib->done))
     843           0 :       continue;
     844             : 
     845           0 :     if (static_bib->is_add)
     846             :       {
     847           0 :           (void) nat64_db_bib_entry_create (thread_index, db,
     848             :                                             &static_bib->in_addr,
     849             :                                             &static_bib->out_addr,
     850           0 :                                             static_bib->in_port,
     851           0 :                                             static_bib->out_port,
     852             :                                             static_bib->fib_index,
     853           0 :                                             static_bib->proto, 1);
     854           0 :           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
     855           0 :                                    db->bib.bib_entries_num);
     856             :       }
     857             :     else
     858             :       {
     859           0 :         addr.as_u64[0] = static_bib->in_addr.as_u64[0];
     860           0 :         addr.as_u64[1] = static_bib->in_addr.as_u64[1];
     861           0 :         bibe = nat64_db_bib_entry_find (db, &addr, static_bib->in_port,
     862           0 :                                         static_bib->proto,
     863             :                                         static_bib->fib_index, 1);
     864           0 :         if (bibe)
     865             :           {
     866           0 :             nat64_db_bib_entry_free (thread_index, db, bibe);
     867           0 :             vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
     868           0 :                                      db->bib.bib_entries_num);
     869           0 :             vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
     870           0 :                                      db->st.st_entries_num);
     871             :           }
     872             :       }
     873             : 
     874           0 :       static_bib->done = 1;
     875             :   }
     876             :   /* *INDENT-ON* */
     877             : 
     878           0 :   return 0;
     879             : }
     880             : 
     881             : static vlib_node_registration_t nat64_static_bib_worker_node;
     882             : 
     883             : /* *INDENT-OFF* */
     884       58824 : VLIB_REGISTER_NODE (nat64_static_bib_worker_node, static) = {
     885             :     .function = nat64_static_bib_worker_fn,
     886             :     .type = VLIB_NODE_TYPE_INPUT,
     887             :     .state = VLIB_NODE_STATE_INTERRUPT,
     888             :     .name = "nat64-static-bib-worker",
     889             : };
     890             : /* *INDENT-ON* */
     891             : 
     892             : int
     893          11 : nat64_add_del_static_bib_entry (ip6_address_t * in_addr,
     894             :                                 ip4_address_t * out_addr, u16 in_port,
     895             :                                 u16 out_port, u8 proto, u32 vrf_id, u8 is_add)
     896             : {
     897          11 :   nat64_main_t *nm = &nat64_main;
     898             :   nat64_db_bib_entry_t *bibe;
     899          11 :   u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
     900          11 :                                                      nm->fib_src_hi);
     901          11 :   nat_protocol_t p = ip_proto_to_nat_proto (proto);
     902             :   ip46_address_t addr;
     903             :   int i;
     904             :   nat64_address_t *a;
     905          11 :   u32 thread_index = 0;
     906             :   nat64_db_t *db;
     907             :   nat64_static_bib_to_update_t *static_bib;
     908             :   vlib_main_t *worker_vm;
     909          11 :   u32 *to_be_free = 0, *index;
     910             : 
     911          11 :   if (nm->num_workers > 1)
     912             :     {
     913           0 :       thread_index = nat64_get_worker_in2out (in_addr);
     914           0 :       db = &nm->db[thread_index];
     915             :     }
     916             :   else
     917          11 :     db = &nm->db[nm->num_workers];
     918             : 
     919          11 :   addr.as_u64[0] = in_addr->as_u64[0];
     920          11 :   addr.as_u64[1] = in_addr->as_u64[1];
     921             :   bibe =
     922          11 :     nat64_db_bib_entry_find (db, &addr, clib_host_to_net_u16 (in_port),
     923             :                              proto, fib_index, 1);
     924             : 
     925          11 :   if (is_add)
     926             :     {
     927          10 :       if (bibe)
     928           0 :         return VNET_API_ERROR_VALUE_EXIST;
     929             : 
     930             :       /* outside port must be assigned to same thread as internall address */
     931          10 :       if ((out_port > 1024) && (nm->num_workers > 1))
     932             :         {
     933           0 :           if (thread_index != get_thread_idx_by_port (out_port))
     934           0 :             return VNET_API_ERROR_INVALID_VALUE_2;
     935             :         }
     936             : 
     937          20 :       for (i = 0; i < vec_len (nm->addr_pool); i++)
     938             :         {
     939          19 :           a = nm->addr_pool + i;
     940          19 :           if (out_addr->as_u32 != a->addr.as_u32)
     941          10 :             continue;
     942           9 :           switch (p)
     943             :             {
     944             : #define _(N, j, n, s) \
     945             :             case NAT_PROTOCOL_##N: \
     946             :               if (a->busy_##n##_port_refcounts[out_port]) \
     947             :                 return VNET_API_ERROR_INVALID_VALUE; \
     948             :               ++a->busy_##n##_port_refcounts[out_port]; \
     949             :               if (out_port > 1024) \
     950             :                 { \
     951             :                   a->busy_##n##_ports++; \
     952             :                   a->busy_##n##_ports_per_thread[thread_index]++; \
     953             :                 } \
     954             :               break;
     955           9 :               foreach_nat_protocol
     956             : #undef _
     957           0 :             default:
     958           0 :               clib_memset (&addr, 0, sizeof (addr));
     959           0 :               addr.ip4.as_u32 = out_addr->as_u32;
     960           0 :               if (nat64_db_bib_entry_find (db, &addr, 0, proto, fib_index, 0))
     961           0 :                 return VNET_API_ERROR_INVALID_VALUE;
     962             :             }
     963           9 :           break;
     964             :         }
     965          10 :       if (!nm->num_workers)
     966             :         {
     967             :           bibe =
     968          10 :             nat64_db_bib_entry_create (thread_index, db, in_addr, out_addr,
     969          10 :                                        clib_host_to_net_u16 (in_port),
     970          10 :                                        clib_host_to_net_u16 (out_port),
     971             :                                        fib_index, proto, 1);
     972          10 :           if (!bibe)
     973           0 :             return VNET_API_ERROR_UNSPECIFIED;
     974             : 
     975          10 :           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
     976          10 :                                    db->bib.bib_entries_num);
     977             :         }
     978             :     }
     979             :   else
     980             :     {
     981           1 :       if (!bibe)
     982           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     983             : 
     984           1 :       if (!nm->num_workers)
     985             :         {
     986           1 :           nat64_db_bib_entry_free (thread_index, db, bibe);
     987           1 :           vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
     988           1 :                                    db->bib.bib_entries_num);
     989             :         }
     990             :     }
     991             : 
     992          11 :   if (nm->num_workers)
     993             :     {
     994             :       /* *INDENT-OFF* */
     995           0 :       pool_foreach (static_bib, nm->static_bibs)
     996             :        {
     997           0 :         if (static_bib->done)
     998           0 :           vec_add1 (to_be_free, static_bib - nm->static_bibs);
     999             :       }
    1000           0 :       vec_foreach (index, to_be_free)
    1001           0 :         pool_put_index (nm->static_bibs, index[0]);
    1002             :       /* *INDENT-ON* */
    1003           0 :       vec_free (to_be_free);
    1004           0 :       pool_get (nm->static_bibs, static_bib);
    1005           0 :       static_bib->in_addr.as_u64[0] = in_addr->as_u64[0];
    1006           0 :       static_bib->in_addr.as_u64[1] = in_addr->as_u64[1];
    1007           0 :       static_bib->in_port = clib_host_to_net_u16 (in_port);
    1008           0 :       static_bib->out_addr.as_u32 = out_addr->as_u32;
    1009           0 :       static_bib->out_port = clib_host_to_net_u16 (out_port);
    1010           0 :       static_bib->fib_index = fib_index;
    1011           0 :       static_bib->proto = proto;
    1012           0 :       static_bib->is_add = is_add;
    1013           0 :       static_bib->thread_index = thread_index;
    1014           0 :       static_bib->done = 0;
    1015           0 :       worker_vm = vlib_get_main_by_index (thread_index);
    1016           0 :       if (worker_vm)
    1017           0 :         vlib_node_set_interrupt_pending (worker_vm,
    1018             :                                          nat64_static_bib_worker_node.index);
    1019             :       else
    1020           0 :         return VNET_API_ERROR_UNSPECIFIED;
    1021             :     }
    1022             : 
    1023          11 :   return 0;
    1024             : }
    1025             : 
    1026             : int
    1027           0 : nat64_set_udp_timeout (u32 timeout)
    1028             : {
    1029           0 :   nat64_main_t *nm = &nat64_main;
    1030             : 
    1031           0 :   if (timeout == 0)
    1032           0 :     nm->udp_timeout = NAT_UDP_TIMEOUT;
    1033             :   else
    1034           0 :     nm->udp_timeout = timeout;
    1035             : 
    1036           0 :   return 0;
    1037             : }
    1038             : 
    1039             : u32
    1040           0 : nat64_get_udp_timeout (void)
    1041             : {
    1042           0 :   nat64_main_t *nm = &nat64_main;
    1043             : 
    1044           0 :   return nm->udp_timeout;
    1045             : }
    1046             : 
    1047             : int
    1048           0 : nat64_set_icmp_timeout (u32 timeout)
    1049             : {
    1050           0 :   nat64_main_t *nm = &nat64_main;
    1051             : 
    1052           0 :   if (timeout == 0)
    1053           0 :     nm->icmp_timeout = NAT_ICMP_TIMEOUT;
    1054             :   else
    1055           0 :     nm->icmp_timeout = timeout;
    1056             : 
    1057           0 :   return 0;
    1058             : }
    1059             : 
    1060             : void
    1061         579 : nat64_reset_timeouts ()
    1062             : {
    1063         579 :   nat64_main_t *nm = &nat64_main;
    1064             : 
    1065         579 :   nm->udp_timeout = NAT_UDP_TIMEOUT;
    1066         579 :   nm->icmp_timeout = NAT_ICMP_TIMEOUT;
    1067         579 :   nm->tcp_est_timeout = NAT_TCP_ESTABLISHED_TIMEOUT;
    1068         579 :   nm->tcp_trans_timeout = NAT_TCP_TRANSITORY_TIMEOUT;
    1069         579 : }
    1070             : 
    1071             : u32
    1072           0 : nat64_get_icmp_timeout (void)
    1073             : {
    1074           0 :   nat64_main_t *nm = &nat64_main;
    1075             : 
    1076           0 :   return nm->icmp_timeout;
    1077             : }
    1078             : 
    1079             : int
    1080           0 : nat64_set_tcp_timeouts (u32 trans, u32 est)
    1081             : {
    1082           0 :   nat64_main_t *nm = &nat64_main;
    1083             : 
    1084           0 :   if (trans == 0)
    1085           0 :     nm->tcp_trans_timeout = NAT_TCP_TRANSITORY_TIMEOUT;
    1086             :   else
    1087           0 :     nm->tcp_trans_timeout = trans;
    1088             : 
    1089           0 :   if (est == 0)
    1090           0 :     nm->tcp_est_timeout = NAT_TCP_ESTABLISHED_TIMEOUT;
    1091             :   else
    1092           0 :     nm->tcp_est_timeout = est;
    1093             : 
    1094           0 :   return 0;
    1095             : }
    1096             : 
    1097             : u32
    1098           0 : nat64_get_tcp_trans_timeout (void)
    1099             : {
    1100           0 :   nat64_main_t *nm = &nat64_main;
    1101             : 
    1102           0 :   return nm->tcp_trans_timeout;
    1103             : }
    1104             : 
    1105             : u32
    1106           0 : nat64_get_tcp_est_timeout (void)
    1107             : {
    1108           0 :   nat64_main_t *nm = &nat64_main;
    1109             : 
    1110           0 :   return nm->tcp_est_timeout;
    1111             : }
    1112             : 
    1113             : void
    1114          84 : nat64_session_reset_timeout (nat64_db_st_entry_t * ste, vlib_main_t * vm)
    1115             : {
    1116          84 :   nat64_main_t *nm = &nat64_main;
    1117          84 :   u32 now = (u32) vlib_time_now (vm);
    1118             : 
    1119          84 :   switch (ip_proto_to_nat_proto (ste->proto))
    1120             :     {
    1121          15 :     case NAT_PROTOCOL_ICMP:
    1122          15 :       ste->expire = now + nm->icmp_timeout;
    1123          15 :       return;
    1124          48 :     case NAT_PROTOCOL_TCP:
    1125             :       {
    1126          48 :         switch (ste->tcp_state)
    1127             :           {
    1128          34 :           case NAT64_TCP_STATE_V4_INIT:
    1129             :           case NAT64_TCP_STATE_V6_INIT:
    1130             :           case NAT64_TCP_STATE_V4_FIN_RCV:
    1131             :           case NAT64_TCP_STATE_V6_FIN_RCV:
    1132             :           case NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV:
    1133             :           case NAT64_TCP_STATE_TRANS:
    1134          34 :             ste->expire = now + nm->tcp_trans_timeout;
    1135          34 :             return;
    1136          11 :           case NAT64_TCP_STATE_ESTABLISHED:
    1137          11 :             ste->expire = now + nm->tcp_est_timeout;
    1138          11 :             return;
    1139           3 :           default:
    1140           3 :             return;
    1141             :           }
    1142             :       }
    1143          17 :     case NAT_PROTOCOL_UDP:
    1144          17 :       ste->expire = now + nm->udp_timeout;
    1145          17 :       return;
    1146           4 :     default:
    1147           4 :       ste->expire = now + nm->udp_timeout;
    1148           4 :       return;
    1149             :     }
    1150             : }
    1151             : 
    1152             : void
    1153          38 : nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, tcp_header_t * tcp,
    1154             :                              u8 is_ip6)
    1155             : {
    1156          38 :   switch (ste->tcp_state)
    1157             :     {
    1158          17 :     case NAT64_TCP_STATE_CLOSED:
    1159             :       {
    1160          17 :         if (tcp->flags & TCP_FLAG_SYN)
    1161             :           {
    1162          17 :             if (is_ip6)
    1163          17 :               ste->tcp_state = NAT64_TCP_STATE_V6_INIT;
    1164             :             else
    1165           0 :               ste->tcp_state = NAT64_TCP_STATE_V4_INIT;
    1166             :           }
    1167          17 :         return;
    1168             :       }
    1169           0 :     case NAT64_TCP_STATE_V4_INIT:
    1170             :       {
    1171           0 :         if (is_ip6 && (tcp->flags & TCP_FLAG_SYN))
    1172           0 :           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
    1173           0 :         return;
    1174             :       }
    1175          12 :     case NAT64_TCP_STATE_V6_INIT:
    1176             :       {
    1177          12 :         if (!is_ip6 && (tcp->flags & TCP_FLAG_SYN))
    1178           9 :           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
    1179          12 :         return;
    1180             :       }
    1181           9 :     case NAT64_TCP_STATE_ESTABLISHED:
    1182             :       {
    1183           9 :         if (tcp->flags & TCP_FLAG_FIN)
    1184             :           {
    1185           0 :             if (is_ip6)
    1186           0 :               ste->tcp_state = NAT64_TCP_STATE_V6_FIN_RCV;
    1187             :             else
    1188           0 :               ste->tcp_state = NAT64_TCP_STATE_V4_FIN_RCV;
    1189             :           }
    1190           9 :         else if (tcp->flags & TCP_FLAG_RST)
    1191             :           {
    1192           0 :             ste->tcp_state = NAT64_TCP_STATE_TRANS;
    1193             :           }
    1194           9 :         return;
    1195             :       }
    1196           0 :     case NAT64_TCP_STATE_V4_FIN_RCV:
    1197             :       {
    1198           0 :         if (is_ip6 && (tcp->flags & TCP_FLAG_FIN))
    1199           0 :           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
    1200           0 :         return;
    1201             :       }
    1202           0 :     case NAT64_TCP_STATE_V6_FIN_RCV:
    1203             :       {
    1204           0 :         if (!is_ip6 && (tcp->flags & TCP_FLAG_FIN))
    1205           0 :           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
    1206           0 :         return;
    1207             :       }
    1208           0 :     case NAT64_TCP_STATE_TRANS:
    1209             :       {
    1210           0 :         if (!(tcp->flags & TCP_FLAG_RST))
    1211           0 :           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
    1212           0 :         return;
    1213             :       }
    1214           0 :     default:
    1215           0 :       return;
    1216             :     }
    1217             : }
    1218             : 
    1219             : int
    1220           2 : nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, u8 is_add)
    1221             : {
    1222           2 :   nat64_main_t *nm = &nat64_main;
    1223           2 :   nat64_prefix_t *p = 0;
    1224             :   int i;
    1225             : 
    1226             :   /* Verify prefix length */
    1227           2 :   if (plen != 32 && plen != 40 && plen != 48 && plen != 56 && plen != 64
    1228           0 :       && plen != 96)
    1229           0 :     return VNET_API_ERROR_INVALID_VALUE;
    1230             : 
    1231             :   /* Check if tenant already have prefix */
    1232           3 :   for (i = 0; i < vec_len (nm->pref64); i++)
    1233             :     {
    1234           1 :       if (nm->pref64[i].vrf_id == vrf_id)
    1235             :         {
    1236           0 :           p = nm->pref64 + i;
    1237           0 :           break;
    1238             :         }
    1239             :     }
    1240             : 
    1241           2 :   if (is_add)
    1242             :     {
    1243           2 :       if (!p)
    1244             :         {
    1245           2 :           vec_add2 (nm->pref64, p, 1);
    1246           4 :           p->fib_index =
    1247           2 :             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
    1248           2 :                                                nm->fib_src_hi);
    1249           2 :           p->vrf_id = vrf_id;
    1250             :         }
    1251             : 
    1252           2 :       p->prefix.as_u64[0] = prefix->as_u64[0];
    1253           2 :       p->prefix.as_u64[1] = prefix->as_u64[1];
    1254           2 :       p->plen = plen;
    1255             :     }
    1256             :   else
    1257             :     {
    1258           0 :       if (!p)
    1259           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
    1260             : 
    1261             :       // TODO: missing fib_table_unlock ?
    1262             : 
    1263           0 :       vec_del1 (nm->pref64, i);
    1264             :     }
    1265             : 
    1266           2 :   return 0;
    1267             : }
    1268             : 
    1269             : void
    1270          22 : nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx)
    1271             : {
    1272          22 :   nat64_main_t *nm = &nat64_main;
    1273          22 :   nat64_prefix_t *p = 0;
    1274             : 
    1275             :   /* *INDENT-OFF* */
    1276          27 :   vec_foreach (p, nm->pref64)
    1277             :     {
    1278           5 :       if (fn (p, ctx))
    1279           0 :         break;
    1280             :     };
    1281             :   /* *INDENT-ON* */
    1282          22 : }
    1283             : 
    1284             : void
    1285          20 : nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
    1286             : {
    1287          20 :   nat64_main_t *nm = &nat64_main;
    1288          20 :   nat64_prefix_t *p, *gp = 0, *prefix = 0;
    1289             : 
    1290             :   /* *INDENT-OFF* */
    1291          20 :   vec_foreach (p, nm->pref64)
    1292             :     {
    1293           0 :       if (p->fib_index == fib_index)
    1294             :         {
    1295           0 :           prefix = p;
    1296           0 :           break;
    1297             :         }
    1298             : 
    1299           0 :       if (p->fib_index == 0)
    1300           0 :         gp = p;
    1301             :     };
    1302             :   /* *INDENT-ON* */
    1303             : 
    1304          20 :   if (!prefix)
    1305          20 :     prefix = gp;
    1306             : 
    1307          20 :   if (prefix)
    1308             :     {
    1309           0 :       clib_memcpy_fast (ip6, &p->prefix, sizeof (ip6_address_t));
    1310           0 :       switch (p->plen)
    1311             :         {
    1312           0 :         case 32:
    1313           0 :           ip6->as_u32[1] = ip4->as_u32;
    1314           0 :           break;
    1315           0 :         case 40:
    1316           0 :           ip6->as_u8[5] = ip4->as_u8[0];
    1317           0 :           ip6->as_u8[6] = ip4->as_u8[1];
    1318           0 :           ip6->as_u8[7] = ip4->as_u8[2];
    1319           0 :           ip6->as_u8[9] = ip4->as_u8[3];
    1320           0 :           break;
    1321           0 :         case 48:
    1322           0 :           ip6->as_u8[6] = ip4->as_u8[0];
    1323           0 :           ip6->as_u8[7] = ip4->as_u8[1];
    1324           0 :           ip6->as_u8[9] = ip4->as_u8[2];
    1325           0 :           ip6->as_u8[10] = ip4->as_u8[3];
    1326           0 :           break;
    1327           0 :         case 56:
    1328           0 :           ip6->as_u8[7] = ip4->as_u8[0];
    1329           0 :           ip6->as_u8[9] = ip4->as_u8[1];
    1330           0 :           ip6->as_u8[10] = ip4->as_u8[2];
    1331           0 :           ip6->as_u8[11] = ip4->as_u8[3];
    1332           0 :           break;
    1333           0 :         case 64:
    1334           0 :           ip6->as_u8[9] = ip4->as_u8[0];
    1335           0 :           ip6->as_u8[10] = ip4->as_u8[1];
    1336           0 :           ip6->as_u8[11] = ip4->as_u8[2];
    1337           0 :           ip6->as_u8[12] = ip4->as_u8[3];
    1338           0 :           break;
    1339           0 :         case 96:
    1340           0 :           ip6->as_u32[3] = ip4->as_u32;
    1341           0 :           break;
    1342           0 :         default:
    1343           0 :           nat_elog_str ("invalid prefix length");
    1344           0 :           break;
    1345             :         }
    1346             :     }
    1347             :   else
    1348             :     {
    1349          20 :       clib_memcpy_fast (ip6, well_known_prefix, sizeof (ip6_address_t));
    1350          20 :       ip6->as_u32[3] = ip4->as_u32;
    1351             :     }
    1352          20 : }
    1353             : 
    1354             : void
    1355          42 : nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
    1356             : {
    1357          42 :   nat64_main_t *nm = &nat64_main;
    1358          42 :   nat64_prefix_t *p, *gp = 0;
    1359          42 :   u8 plen = 0;
    1360             : 
    1361             :   /* *INDENT-OFF* */
    1362          45 :   vec_foreach (p, nm->pref64)
    1363             :     {
    1364           9 :       if (p->fib_index == fib_index)
    1365             :         {
    1366           6 :           plen = p->plen;
    1367           6 :           break;
    1368             :         }
    1369             : 
    1370           3 :       if (p->vrf_id == 0)
    1371           3 :         gp = p;
    1372             :     };
    1373             :   /* *INDENT-ON* */
    1374             : 
    1375          42 :   if (!plen)
    1376             :     {
    1377          36 :       if (gp)
    1378           0 :         plen = gp->plen;
    1379             :       else
    1380          36 :         plen = 96;
    1381             :     }
    1382             : 
    1383          42 :   switch (plen)
    1384             :     {
    1385           3 :     case 32:
    1386           3 :       ip4->as_u32 = ip6->as_u32[1];
    1387           3 :       break;
    1388           0 :     case 40:
    1389           0 :       ip4->as_u8[0] = ip6->as_u8[5];
    1390           0 :       ip4->as_u8[1] = ip6->as_u8[6];
    1391           0 :       ip4->as_u8[2] = ip6->as_u8[7];
    1392           0 :       ip4->as_u8[3] = ip6->as_u8[9];
    1393           0 :       break;
    1394           0 :     case 48:
    1395           0 :       ip4->as_u8[0] = ip6->as_u8[6];
    1396           0 :       ip4->as_u8[1] = ip6->as_u8[7];
    1397           0 :       ip4->as_u8[2] = ip6->as_u8[9];
    1398           0 :       ip4->as_u8[3] = ip6->as_u8[10];
    1399           0 :       break;
    1400           3 :     case 56:
    1401           3 :       ip4->as_u8[0] = ip6->as_u8[7];
    1402           3 :       ip4->as_u8[1] = ip6->as_u8[9];
    1403           3 :       ip4->as_u8[2] = ip6->as_u8[10];
    1404           3 :       ip4->as_u8[3] = ip6->as_u8[11];
    1405           3 :       break;
    1406           0 :     case 64:
    1407           0 :       ip4->as_u8[0] = ip6->as_u8[9];
    1408           0 :       ip4->as_u8[1] = ip6->as_u8[10];
    1409           0 :       ip4->as_u8[2] = ip6->as_u8[11];
    1410           0 :       ip4->as_u8[3] = ip6->as_u8[12];
    1411           0 :       break;
    1412          36 :     case 96:
    1413          36 :       ip4->as_u32 = ip6->as_u32[3];
    1414          36 :       break;
    1415           0 :     default:
    1416           0 :       nat_elog_str ("invalid prefix length");
    1417           0 :       break;
    1418             :     }
    1419          42 : }
    1420             : 
    1421             : /**
    1422             :  * @brief Per worker process checking expire time for NAT64 sessions.
    1423             :  */
    1424             : static uword
    1425          34 : nat64_expire_worker_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
    1426             :                              vlib_frame_t * f)
    1427             : {
    1428          34 :   nat64_main_t *nm = &nat64_main;
    1429          34 :   u32 thread_index = vm->thread_index;
    1430             :   nat64_db_t *db;
    1431             :   u32 now;
    1432             : 
    1433             :   // TODO: barier sync on plugin enabled
    1434          34 :   if (plugin_enabled () == 0)
    1435           0 :     return 0;
    1436             : 
    1437          34 :   db = &nm->db[thread_index];
    1438          34 :   now = (u32) vlib_time_now (vm);
    1439             : 
    1440          34 :   nad64_db_st_free_expired (thread_index, db, now);
    1441          34 :   vlib_set_simple_counter (&nm->total_bibs, thread_index, 0,
    1442          34 :                            db->bib.bib_entries_num);
    1443          34 :   vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
    1444          34 :                            db->st.st_entries_num);
    1445          34 :   return 0;
    1446             : }
    1447             : 
    1448             : /* *INDENT-OFF* */
    1449       58824 : VLIB_REGISTER_NODE (nat64_expire_worker_walk_node, static) = {
    1450             :     .function = nat64_expire_worker_walk_fn,
    1451             :     .type = VLIB_NODE_TYPE_INPUT,
    1452             :     .state = VLIB_NODE_STATE_INTERRUPT,
    1453             :     .name = "nat64-expire-worker-walk",
    1454             : };
    1455             : /* *INDENT-ON* */
    1456             : 
    1457             : /**
    1458             :  * @brief Centralized process to drive per worker expire walk.
    1459             :  */
    1460             : static uword
    1461           1 : nat64_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
    1462             :                       vlib_frame_t * f)
    1463             : {
    1464           1 :   nat64_main_t *nm = &nat64_main;
    1465           1 :   vlib_main_t **worker_vms = 0, *worker_vm;
    1466             :   int i;
    1467           1 :   uword event_type, *event_data = 0;
    1468             : 
    1469           1 :   if (vlib_get_n_threads () == 0)
    1470           0 :     vec_add1 (worker_vms, vm);
    1471             :   else
    1472             :     {
    1473           2 :       for (i = 0; i < vlib_get_n_threads (); i++)
    1474             :         {
    1475           1 :           worker_vm = vlib_get_main_by_index (i);
    1476           1 :           if (worker_vm)
    1477           1 :             vec_add1 (worker_vms, worker_vm);
    1478             :         }
    1479             :     }
    1480             : 
    1481             :   while (1)
    1482             :     {
    1483          35 :       if (nm->total_enabled_count)
    1484             :         {
    1485          34 :           vlib_process_wait_for_event_or_clock (vm, 10.0);
    1486          33 :           event_type = vlib_process_get_events (vm, &event_data);
    1487             :         }
    1488             :       else
    1489             :         {
    1490           1 :           vlib_process_wait_for_event (vm);
    1491           1 :           event_type = vlib_process_get_events (vm, &event_data);
    1492             :         }
    1493             : 
    1494          34 :       switch (event_type)
    1495             :         {
    1496           1 :         case ~0:
    1497           1 :           break;
    1498          33 :         case NAT64_CLEANER_RESCHEDULE:
    1499          33 :           break;
    1500           0 :         default:
    1501           0 :           nat64_log_err ("unknown event %u", event_type);
    1502           0 :           break;
    1503             :         }
    1504             : 
    1505          68 :       for (i = 0; i < vec_len (worker_vms); i++)
    1506             :         {
    1507          34 :           worker_vm = worker_vms[i];
    1508          34 :           vlib_node_set_interrupt_pending (worker_vm,
    1509             :                                            nm->expire_worker_walk_node_index);
    1510             :         }
    1511             :     }
    1512             : 
    1513             :   return 0;
    1514             : }
    1515             : 
    1516             : void
    1517          20 : nat64_create_expire_walk_process ()
    1518             : {
    1519          20 :   nat64_main_t *nm = &nat64_main;
    1520             : 
    1521          20 :   if (nm->expire_walk_node_index)
    1522          19 :     return;
    1523           1 :   nm->expire_walk_node_index = vlib_process_create (vlib_get_main (),
    1524             :                                                     "nat64-expire-walk",
    1525             :                                                     nat64_expire_walk_fn,
    1526             :                                                     16 /* stack_bytes */ );
    1527             : }
    1528             : 
    1529             : int
    1530          20 : nat64_plugin_enable (nat64_config_t c)
    1531             : {
    1532          20 :   nat64_main_t *nm = &nat64_main;
    1533             : 
    1534          20 :   if (plugin_enabled () == 1)
    1535             :     {
    1536           0 :       nat64_log_err ("plugin already enabled!");
    1537           0 :       return 1;
    1538             :     }
    1539             : 
    1540          20 :   if (!c.bib_buckets)
    1541           0 :     c.bib_buckets = 1024;
    1542             : 
    1543          20 :   if (!c.bib_memory_size)
    1544          20 :     c.bib_memory_size = 128 << 20;
    1545             : 
    1546          20 :   if (!c.st_buckets)
    1547           0 :     c.st_buckets = 2048;
    1548             : 
    1549          20 :   if (!c.st_memory_size)
    1550          20 :     c.st_memory_size = 256 << 20;
    1551             : 
    1552          20 :   nm->config = c;
    1553             : 
    1554          20 :   if (nat64_init_hash (c))
    1555             :     {
    1556           0 :       nat64_log_err ("initializing hashes failed!");
    1557           0 :       return 1;
    1558             :     }
    1559             : 
    1560          20 :   nat64_create_expire_walk_process ();
    1561             : 
    1562          20 :   nm->enabled = 1;
    1563          20 :   return 0;
    1564             : }
    1565             : 
    1566             : int
    1567          20 : nat64_plugin_disable ()
    1568             : {
    1569          20 :   nat64_main_t *nm = &nat64_main;
    1570          20 :   vnet_main_t *vnm = vnet_get_main ();
    1571          20 :   int rv = 0;
    1572             : 
    1573             :   nat64_address_t *a;
    1574          20 :   nat64_interface_t *i, *interfaces = 0;
    1575             : 
    1576          20 :   if (plugin_enabled () == 0)
    1577             :     {
    1578           0 :       nat64_log_err ("plugin already disabled!");
    1579           0 :       return 1;
    1580             :     }
    1581          20 :   nm->enabled = 0;
    1582             : 
    1583             :   /* *INDENT-OFF* */
    1584          50 :   pool_foreach (i, nm->interfaces)
    1585             :    {
    1586          30 :     vec_add1 (interfaces, *i);
    1587             :   }
    1588             :   /* *INDENT-ON* */
    1589          50 :   vec_foreach (i, interfaces)
    1590             :   {
    1591          30 :     rv = nat64_interface_add_del (i->sw_if_index, i->flags, 0);
    1592          30 :     if (rv)
    1593             :       {
    1594           0 :         nat64_log_err ("%U %s interface del failed",
    1595             :                        format_vnet_sw_if_index_name, vnm, i->sw_if_index,
    1596             :                        i->flags & NAT64_INTERFACE_FLAG_IS_INSIDE ?
    1597             :                        "inside" : "outside");
    1598             :       }
    1599             :   }
    1600          20 :   vec_free (interfaces);
    1601          20 :   pool_free (nm->interfaces);
    1602             : 
    1603          20 :   nat64_reset_timeouts ();
    1604             : 
    1605          20 :   if (nat64_free_hash ())
    1606             :     {
    1607           0 :       rv = 1;
    1608           0 :       nat64_log_err ("freeing hashes failed!");
    1609             :     }
    1610             : 
    1611             :   // TODO: based on nat64_add_del_prefix fib_table_unlock is not called
    1612          20 :   vec_free (nm->pref64);
    1613             : 
    1614          20 :   if (vec_len (nm->addr_pool))
    1615             :     {
    1616          36 :       vec_foreach (a, nm->addr_pool)
    1617             :       {
    1618          24 :         if (a->fib_index != ~0)
    1619           2 :           fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6, nm->fib_src_hi);
    1620             :       }
    1621          12 :       vec_free (nm->addr_pool);
    1622             :     }
    1623          20 :   return rv;
    1624             : }
    1625             : 
    1626             : uword
    1627          40 : unformat_nat_protocol (unformat_input_t * input, va_list * args)
    1628             : {
    1629          40 :   u32 *r = va_arg (*args, u32 *);
    1630             : 
    1631             :   if (0);
    1632             : #define _(N, i, n, s) else if (unformat (input, s)) *r = NAT_PROTOCOL_##N;
    1633          40 :   foreach_nat_protocol
    1634             : #undef _
    1635             :     else
    1636          40 :     return 0;
    1637           0 :   return 1;
    1638             : }
    1639             : 
    1640             : u8 *
    1641          60 : format_nat_protocol (u8 * s, va_list * args)
    1642             : {
    1643          60 :   u32 i = va_arg (*args, u32);
    1644          60 :   u8 *t = 0;
    1645             : 
    1646          60 :   switch (i)
    1647             :     {
    1648             : #define _(N, j, n, str) case NAT_PROTOCOL_##N: t = (u8 *) str; break;
    1649          60 :       foreach_nat_protocol
    1650             : #undef _
    1651           0 :     default:
    1652           0 :       s = format (s, "unknown");
    1653           0 :       return s;
    1654             :     }
    1655          60 :   s = format (s, "%s", t);
    1656          60 :   return s;
    1657             : }
    1658             : 
    1659             : /*
    1660             :  * fd.io coding-style-patch-verification: ON
    1661             :  *
    1662             :  * Local Variables:
    1663             :  * eval: (c-set-style "gnu")
    1664             :  * End:
    1665             :  */

Generated by: LCOV version 1.14