LCOV - code coverage report
Current view: top level - plugins/nat/nat44-ei - nat44_ei.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 1216 1548 78.6 %
Date: 2023-10-26 01:39:38 Functions: 101 108 93.5 %

          Line data    Source code
       1             : /*
       2             :  * nat44_ei.c - nat44 endpoint dependent plugin
       3             :  *
       4             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or agreed to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
      13             :  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
      14             :  * License for the specific language governing permissions and limitations
      15             :  * under the License.
      16             :  */
      17             : 
      18             : #include <vnet/plugin/plugin.h>
      19             : #include <vpp/app/version.h>
      20             : 
      21             : #include <vnet/vnet.h>
      22             : #include <vnet/ip/ip.h>
      23             : #include <vnet/ip/ip4.h>
      24             : #include <vnet/ip/ip_table.h>
      25             : #include <vnet/ip/reass/ip4_sv_reass.h>
      26             : #include <vnet/fib/fib_table.h>
      27             : #include <vnet/fib/ip4_fib.h>
      28             : #include <vnet/plugin/plugin.h>
      29             : 
      30             : // nat lib
      31             : #include <nat/lib/log.h>
      32             : #include <nat/lib/nat_syslog.h>
      33             : #include <nat/lib/nat_inlines.h>
      34             : #include <nat/lib/ipfix_logging.h>
      35             : 
      36             : #include <nat/nat44-ei/nat44_ei_dpo.h>
      37             : #include <nat/nat44-ei/nat44_ei_inlines.h>
      38             : #include <nat/nat44-ei/nat44_ei.h>
      39             : 
      40             : nat44_ei_main_t nat44_ei_main;
      41             : 
      42             : extern vlib_node_registration_t nat44_ei_hairpinning_node;
      43             : extern vlib_node_registration_t
      44             :   nat44_ei_in2out_hairpinning_finish_ip4_lookup_node;
      45             : extern vlib_node_registration_t
      46             :   nat44_ei_in2out_hairpinning_finish_interface_output_node;
      47             : 
      48             : #define skip_if_disabled()                                                    \
      49             :   do                                                                          \
      50             :     {                                                                         \
      51             :       nat44_ei_main_t *nm = &nat44_ei_main;                                   \
      52             :       if (PREDICT_FALSE (!nm->enabled))                                       \
      53             :         return;                                                               \
      54             :     }                                                                         \
      55             :   while (0)
      56             : 
      57             : #define fail_if_enabled()                                                     \
      58             :   do                                                                          \
      59             :     {                                                                         \
      60             :       nat44_ei_main_t *nm = &nat44_ei_main;                                   \
      61             :       if (PREDICT_FALSE (nm->enabled))                                        \
      62             :         {                                                                     \
      63             :           nat44_ei_log_err ("plugin enabled");                                \
      64             :           return VNET_API_ERROR_FEATURE_ALREADY_ENABLED;                      \
      65             :         }                                                                     \
      66             :     }                                                                         \
      67             :   while (0)
      68             : 
      69             : #define fail_if_disabled()                                                    \
      70             :   do                                                                          \
      71             :     {                                                                         \
      72             :       nat44_ei_main_t *nm = &nat44_ei_main;                                   \
      73             :       if (PREDICT_FALSE (!nm->enabled))                                       \
      74             :         {                                                                     \
      75             :           nat44_ei_log_err ("plugin disabled");                               \
      76             :           return VNET_API_ERROR_FEATURE_ALREADY_DISABLED;                     \
      77             :         }                                                                     \
      78             :     }                                                                         \
      79             :   while (0)
      80             : 
      81             : /* Hook up input features */
      82       39169 : VNET_FEATURE_INIT (ip4_nat_classify, static) = {
      83             :   .arc_name = "ip4-unicast",
      84             :   .node_name = "nat44-ei-classify",
      85             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
      86             :                                "ip4-sv-reassembly-feature"),
      87             : };
      88       39169 : VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
      89             :   .arc_name = "ip4-unicast",
      90             :   .node_name = "nat44-ei-handoff-classify",
      91             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
      92             :                                "ip4-sv-reassembly-feature"),
      93             : };
      94       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_in2out, static) = {
      95             :   .arc_name = "ip4-unicast",
      96             :   .node_name = "nat44-ei-in2out",
      97             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
      98             :                                "ip4-sv-reassembly-feature"),
      99             : };
     100       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_out2in, static) = {
     101             :   .arc_name = "ip4-unicast",
     102             :   .node_name = "nat44-ei-out2in",
     103             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
     104             :                                "ip4-sv-reassembly-feature",
     105             :                                "ip4-dhcp-client-detect"),
     106             : };
     107       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_in2out_output, static) = {
     108             :   .arc_name = "ip4-output",
     109             :   .node_name = "nat44-ei-in2out-output",
     110             :   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
     111             :                                "ip4-sv-reassembly-output-feature"),
     112             : };
     113       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_hairpinning, static) = {
     114             :   .arc_name = "ip4-local",
     115             :   .node_name = "nat44-ei-hairpinning",
     116             :   .runs_before = VNET_FEATURES ("ip4-local-end-of-arc"),
     117             : };
     118       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_in2out_worker_handoff, static) = {
     119             :   .arc_name = "ip4-unicast",
     120             :   .node_name = "nat44-ei-in2out-worker-handoff",
     121             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
     122             : };
     123       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_out2in_worker_handoff, static) = {
     124             :   .arc_name = "ip4-unicast",
     125             :   .node_name = "nat44-ei-out2in-worker-handoff",
     126             :   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
     127             :                                "ip4-dhcp-client-detect"),
     128             : };
     129       39169 : VNET_FEATURE_INIT (ip4_nat44_ei_in2out_output_worker_handoff, static) = {
     130             :   .arc_name = "ip4-output",
     131             :   .node_name = "nat44-ei-in2out-output-worker-handoff",
     132             :   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa",
     133             :                                "ip4-sv-reassembly-output-feature"),
     134             : };
     135             : 
     136             : VLIB_PLUGIN_REGISTER () = {
     137             :   .version = VPP_BUILD_VER,
     138             :   .description = "IPv4 Endpoint-Independent NAT (NAT44 EI)",
     139             : };
     140             : 
     141             : #define foreach_nat44_ei_classify_error                                       \
     142             :   _ (NEXT_IN2OUT, "next in2out")                                              \
     143             :   _ (NEXT_OUT2IN, "next out2in")                                              \
     144             :   _ (FRAG_CACHED, "fragment cached")
     145             : 
     146             : typedef enum
     147             : {
     148             : #define _(sym, str) NAT44_EI_CLASSIFY_ERROR_##sym,
     149             :   foreach_nat44_ei_classify_error
     150             : #undef _
     151             :     NAT44_EI_CLASSIFY_N_ERROR,
     152             : } nat44_ei_classify_error_t;
     153             : 
     154             : static char *nat44_ei_classify_error_strings[] = {
     155             : #define _(sym, string) string,
     156             :   foreach_nat44_ei_classify_error
     157             : #undef _
     158             : };
     159             : 
     160             : typedef enum
     161             : {
     162             :   NAT44_EI_CLASSIFY_NEXT_IN2OUT,
     163             :   NAT44_EI_CLASSIFY_NEXT_OUT2IN,
     164             :   NAT44_EI_CLASSIFY_NEXT_DROP,
     165             :   NAT44_EI_CLASSIFY_N_NEXT,
     166             : } nat44_ei_classify_next_t;
     167             : 
     168             : typedef struct
     169             : {
     170             :   u8 next_in2out;
     171             :   u8 cached;
     172             : } nat44_ei_classify_trace_t;
     173             : 
     174             : void nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len,
     175             :                                    u32 sw_if_index, int is_add);
     176             : 
     177             : static void nat44_ei_worker_db_free (nat44_ei_main_per_thread_data_t *tnm);
     178             : 
     179             : static int nat44_ei_add_static_mapping_internal (
     180             :   ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port,
     181             :   nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags,
     182             :   ip4_address_t pool_addr, u8 *tag);
     183             : 
     184             : static int nat44_ei_del_static_mapping_internal (
     185             :   ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port,
     186             :   nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags);
     187             : 
     188             : always_inline bool
     189       31389 : nat44_ei_port_is_used (nat44_ei_address_t *a, u8 proto, u16 port)
     190             : {
     191       31389 :   return clib_bitmap_get (a->busy_port_bitmap[proto], port);
     192             : }
     193             : 
     194             : always_inline void
     195       10454 : nat44_ei_port_get (nat44_ei_address_t *a, u8 proto, u16 port)
     196             : {
     197       10454 :   ASSERT (!nat44_ei_port_is_used (a, proto, port));
     198       20908 :   a->busy_port_bitmap[proto] =
     199       10454 :     clib_bitmap_set (a->busy_port_bitmap[proto], port, 1);
     200       10454 : }
     201             : 
     202             : always_inline void
     203       10451 : nat44_ei_port_put (nat44_ei_address_t *a, u8 proto, u16 port)
     204             : {
     205       10451 :   ASSERT (nat44_ei_port_is_used (a, proto, port));
     206       20902 :   a->busy_port_bitmap[proto] =
     207       10451 :     clib_bitmap_set (a->busy_port_bitmap[proto], port, 0);
     208       10451 : }
     209             : 
     210             : static u8 *
     211           1 : format_nat44_ei_classify_trace (u8 *s, va_list *args)
     212             : {
     213           1 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     214           1 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     215           1 :   nat44_ei_classify_trace_t *t = va_arg (*args, nat44_ei_classify_trace_t *);
     216             :   char *next;
     217             : 
     218           1 :   if (t->cached)
     219           0 :     s = format (s, "nat44-ei-classify: fragment cached");
     220             :   else
     221             :     {
     222           1 :       next = t->next_in2out ? "nat44-ei-in2out" : "nat44-ei-out2in";
     223           1 :       s = format (s, "nat44-ei-classify: next %s", next);
     224             :     }
     225             : 
     226           1 :   return s;
     227             : }
     228             : 
     229             : static void nat44_ei_db_init (u32 translations, u32 translation_buckets,
     230             :                               u32 user_buckets);
     231             : 
     232             : static void nat44_ei_ip4_add_del_interface_address_cb (
     233             :   ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
     234             :   u32 address_length, u32 if_address_index, u32 is_delete);
     235             : 
     236             : static void nat44_ei_ip4_add_del_addr_only_sm_cb (
     237             :   ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address,
     238             :   u32 address_length, u32 if_address_index, u32 is_delete);
     239             : 
     240             : static void nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque,
     241             :                                          u32 sw_if_index, u32 new_fib_index,
     242             :                                          u32 old_fib_index);
     243             : 
     244             : void
     245         575 : nat44_ei_set_node_indexes (nat44_ei_main_t *nm, vlib_main_t *vm)
     246             : {
     247             :   vlib_node_t *node;
     248         575 :   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-out2in");
     249         575 :   nm->out2in_node_index = node->index;
     250         575 :   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-in2out");
     251         575 :   nm->in2out_node_index = node->index;
     252         575 :   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ei-in2out-output");
     253         575 :   nm->in2out_output_node_index = node->index;
     254         575 : }
     255             : 
     256             : int
     257          14 : nat44_ei_set_workers (uword *bitmap)
     258             : {
     259          14 :   nat44_ei_main_t *nm = &nat44_ei_main;
     260          14 :   int i, j = 0;
     261             : 
     262          14 :   if (nm->num_workers < 2)
     263           0 :     return VNET_API_ERROR_FEATURE_DISABLED;
     264             : 
     265          14 :   if (clib_bitmap_last_set (bitmap) >= nm->num_workers)
     266           0 :     return VNET_API_ERROR_INVALID_WORKER;
     267             : 
     268          14 :   vec_free (nm->workers);
     269          46 :   clib_bitmap_foreach (i, bitmap)
     270             :     {
     271          32 :       vec_add1 (nm->workers, i);
     272          32 :       nm->per_thread_data[nm->first_worker_index + i].snat_thread_index = j;
     273          32 :       nm->per_thread_data[nm->first_worker_index + i].thread_index = i;
     274          32 :       j++;
     275             :     }
     276             : 
     277          14 :   nm->port_per_thread = (0xffff - 1024) / _vec_len (nm->workers);
     278             : 
     279          14 :   return 0;
     280             : }
     281             : 
     282             : #define nat_validate_simple_counter(c, i)                                     \
     283             :   do                                                                          \
     284             :     {                                                                         \
     285             :       vlib_validate_simple_counter (&c, i);                                   \
     286             :       vlib_zero_simple_counter (&c, i);                                       \
     287             :     }                                                                         \
     288             :   while (0);
     289             : 
     290             : #define nat_init_simple_counter(c, n, sn)                                     \
     291             :   do                                                                          \
     292             :     {                                                                         \
     293             :       c.name = n;                                                             \
     294             :       c.stat_segment_name = sn;                                               \
     295             :       nat_validate_simple_counter (c, 0);                                     \
     296             :     }                                                                         \
     297             :   while (0);
     298             : 
     299             : static_always_inline void
     300         110 : nat_validate_interface_counters (nat44_ei_main_t *nm, u32 sw_if_index)
     301             : {
     302             : #define _(x)                                                                  \
     303             :   nat_validate_simple_counter (nm->counters.fastpath.in2out.x, sw_if_index);  \
     304             :   nat_validate_simple_counter (nm->counters.fastpath.out2in.x, sw_if_index);  \
     305             :   nat_validate_simple_counter (nm->counters.slowpath.in2out.x, sw_if_index);  \
     306             :   nat_validate_simple_counter (nm->counters.slowpath.out2in.x, sw_if_index);
     307         110 :   foreach_nat_counter;
     308             : #undef _
     309         110 :   nat_validate_simple_counter (nm->counters.hairpinning, sw_if_index);
     310         110 : }
     311             : 
     312             : static void
     313         337 : nat44_ei_add_del_addr_to_fib_foreach_out_if (ip4_address_t *addr, u8 is_add)
     314             : {
     315         337 :   nat44_ei_main_t *nm = &nat44_ei_main;
     316             :   nat44_ei_interface_t *i;
     317             : 
     318         884 :   pool_foreach (i, nm->interfaces)
     319             :     {
     320         547 :       if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
     321             :         {
     322         268 :           nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
     323             :         }
     324             :     }
     325         342 :   pool_foreach (i, nm->output_feature_interfaces)
     326             :     {
     327           5 :       if (nat44_ei_interface_is_outside (i) && !nm->out2in_dpo)
     328             :         {
     329           5 :           nat44_ei_add_del_addr_to_fib (addr, 32, i->sw_if_index, is_add);
     330             :         }
     331             :     }
     332         337 : }
     333             : 
     334             : static_always_inline void
     335         110 : nat44_ei_add_del_addr_to_fib_foreach_addr (u32 sw_if_index, u8 is_add)
     336             : {
     337         110 :   nat44_ei_main_t *nm = &nat44_ei_main;
     338             :   nat44_ei_address_t *ap;
     339             : 
     340         158 :   vec_foreach (ap, nm->addresses)
     341             :     {
     342          48 :       nat44_ei_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, is_add);
     343             :     }
     344         110 : }
     345             : 
     346             : static_always_inline void
     347         110 : nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (u32 sw_if_index, u8 is_add)
     348             : {
     349         110 :   nat44_ei_main_t *nm = &nat44_ei_main;
     350             :   nat44_ei_static_mapping_t *m;
     351             : 
     352         129 :   pool_foreach (m, nm->static_mappings)
     353             :     {
     354          19 :       if (is_sm_addr_only (m->flags) &&
     355          10 :           !(m->local_addr.as_u32 == m->external_addr.as_u32))
     356             :         {
     357           9 :           nat44_ei_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index,
     358             :                                         is_add);
     359             :         }
     360             :     }
     361         110 : }
     362             : 
     363             : static int
     364         144 : nat44_ei_is_address_used_in_static_mapping (ip4_address_t addr)
     365             : {
     366         144 :   nat44_ei_main_t *nm = &nat44_ei_main;
     367             :   nat44_ei_static_mapping_t *m;
     368         145 :   pool_foreach (m, nm->static_mappings)
     369             :     {
     370           1 :       if (is_sm_addr_only (m->flags) || is_sm_identity_nat (m->flags))
     371             :         {
     372           1 :           continue;
     373             :         }
     374           0 :       if (m->external_addr.as_u32 == addr.as_u32)
     375             :         {
     376           0 :           return 1;
     377             :         }
     378             :     }
     379         144 :   return 0;
     380             : }
     381             : 
     382             : clib_error_t *
     383         575 : nat44_ei_init (vlib_main_t *vm)
     384             : {
     385         575 :   nat44_ei_main_t *nm = &nat44_ei_main;
     386         575 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
     387             :   vlib_thread_registration_t *tr;
     388         575 :   ip4_add_del_interface_address_callback_t cbi = { 0 };
     389         575 :   ip4_table_bind_callback_t cbt = { 0 };
     390         575 :   u32 i, num_threads = 0;
     391         575 :   uword *p, *bitmap = 0;
     392             : 
     393         575 :   clib_memset (nm, 0, sizeof (*nm));
     394             : 
     395             :   // required
     396         575 :   nm->vnet_main = vnet_get_main ();
     397             :   // convenience
     398         575 :   nm->ip4_main = &ip4_main;
     399         575 :   nm->api_main = vlibapi_get_main ();
     400         575 :   nm->ip4_lookup_main = &ip4_main.lookup_main;
     401             : 
     402             :   // handoff stuff
     403         575 :   nm->fq_out2in_index = ~0;
     404         575 :   nm->fq_in2out_index = ~0;
     405         575 :   nm->fq_in2out_output_index = ~0;
     406             : 
     407         575 :   nm->log_level = NAT_LOG_ERROR;
     408             : 
     409         575 :   nat44_ei_set_node_indexes (nm, vm);
     410         575 :   nm->log_class = vlib_log_register_class ("nat44-ei", 0);
     411             : 
     412         575 :   nat_init_simple_counter (nm->total_users, "total-users",
     413             :                            "/nat44-ei/total-users");
     414         575 :   nat_init_simple_counter (nm->total_sessions, "total-sessions",
     415             :                            "/nat44-ei/total-sessions");
     416         575 :   nat_init_simple_counter (nm->user_limit_reached, "user-limit-reached",
     417             :                            "/nat44-ei/user-limit-reached");
     418             : 
     419             : #define _(x)                                                                  \
     420             :   nat_init_simple_counter (nm->counters.fastpath.in2out.x, #x,                \
     421             :                            "/nat44-ei/in2out/fastpath/" #x);                  \
     422             :   nat_init_simple_counter (nm->counters.fastpath.out2in.x, #x,                \
     423             :                            "/nat44-ei/out2in/fastpath/" #x);                  \
     424             :   nat_init_simple_counter (nm->counters.slowpath.in2out.x, #x,                \
     425             :                            "/nat44-ei/in2out/slowpath/" #x);                  \
     426             :   nat_init_simple_counter (nm->counters.slowpath.out2in.x, #x,                \
     427             :                            "/nat44-ei/out2in/slowpath/" #x);
     428         575 :   foreach_nat_counter;
     429             : #undef _
     430         575 :   nat_init_simple_counter (nm->counters.hairpinning, "hairpinning",
     431             :                            "/nat44-ei/hairpinning");
     432             : 
     433         575 :   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
     434         575 :   if (p)
     435             :     {
     436         575 :       tr = (vlib_thread_registration_t *) p[0];
     437         575 :       if (tr)
     438             :         {
     439         575 :           nm->num_workers = tr->count;
     440         575 :           nm->first_worker_index = tr->first_index;
     441             :         }
     442             :     }
     443         575 :   num_threads = tm->n_vlib_mains - 1;
     444         575 :   nm->port_per_thread = 0xffff - 1024;
     445         575 :   vec_validate (nm->per_thread_data, num_threads);
     446             : 
     447             :   /* Use all available workers by default */
     448         575 :   if (nm->num_workers > 1)
     449             :     {
     450          46 :       for (i = 0; i < nm->num_workers; i++)
     451          32 :         bitmap = clib_bitmap_set (bitmap, i, 1);
     452          14 :       nat44_ei_set_workers (bitmap);
     453          14 :       clib_bitmap_free (bitmap);
     454             :     }
     455             :   else
     456             :     {
     457         561 :       nm->per_thread_data[0].snat_thread_index = 0;
     458             :     }
     459             : 
     460             :   /* callbacks to call when interface address changes. */
     461         575 :   cbi.function = nat44_ei_ip4_add_del_interface_address_cb;
     462         575 :   vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cbi);
     463         575 :   cbi.function = nat44_ei_ip4_add_del_addr_only_sm_cb;
     464         575 :   vec_add1 (nm->ip4_main->add_del_interface_address_callbacks, cbi);
     465             : 
     466             :   /* callbacks to call when interface to table biding changes */
     467         575 :   cbt.function = nat44_ei_update_outside_fib;
     468         575 :   vec_add1 (nm->ip4_main->table_bind_callbacks, cbt);
     469             : 
     470         575 :   nm->fib_src_low = fib_source_allocate (
     471             :     "nat44-ei-low", FIB_SOURCE_PRIORITY_LOW, FIB_SOURCE_BH_SIMPLE);
     472         575 :   nm->fib_src_hi = fib_source_allocate ("nat44-ei-hi", FIB_SOURCE_PRIORITY_HI,
     473             :                                         FIB_SOURCE_BH_SIMPLE);
     474             : 
     475             :   // used only by out2in-dpo feature
     476         575 :   nat_dpo_module_init ();
     477         575 :   nat_ha_init (vm, nm->num_workers, num_threads);
     478             : 
     479         575 :   nm->hairpinning_fq_index =
     480         575 :     vlib_frame_queue_main_init (nat44_ei_hairpinning_node.index, 0);
     481         575 :   nm->in2out_hairpinning_finish_ip4_lookup_node_fq_index =
     482         575 :     vlib_frame_queue_main_init (
     483             :       nat44_ei_in2out_hairpinning_finish_ip4_lookup_node.index, 0);
     484         575 :   nm->in2out_hairpinning_finish_interface_output_node_fq_index =
     485         575 :     vlib_frame_queue_main_init (
     486             :       nat44_ei_in2out_hairpinning_finish_interface_output_node.index, 0);
     487         575 :   return nat44_ei_api_hookup (vm);
     488             : }
     489             : 
     490        1151 : VLIB_INIT_FUNCTION (nat44_ei_init);
     491             : 
     492             : int
     493          58 : nat44_ei_plugin_enable (nat44_ei_config_t c)
     494             : {
     495          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
     496             : 
     497          58 :   fail_if_enabled ();
     498             : 
     499          58 :   if (!c.users)
     500           0 :     c.users = 1024;
     501             : 
     502          58 :   if (!c.sessions)
     503           0 :     c.sessions = 10 * 1024;
     504             : 
     505          58 :   if (!c.user_sessions)
     506          58 :     c.user_sessions = c.sessions;
     507             : 
     508          58 :   nm->rconfig = c;
     509             : 
     510          58 :   if (!nm->frame_queue_nelts)
     511           2 :     nm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
     512             : 
     513          58 :   nm->translations = c.sessions;
     514          58 :   nm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
     515          58 :   nm->user_buckets = nat_calc_bihash_buckets (c.users);
     516             : 
     517          58 :   nm->pat = (!c.static_mapping_only ||
     518           0 :              (c.static_mapping_only && c.connection_tracking));
     519             : 
     520          58 :   nm->static_mapping_only = c.static_mapping_only;
     521          58 :   nm->static_mapping_connection_tracking = c.connection_tracking;
     522          58 :   nm->out2in_dpo = c.out2in_dpo;
     523          58 :   nm->forwarding_enabled = 0;
     524          58 :   nm->mss_clamping = 0;
     525             : 
     526          58 :   nm->max_users_per_thread = c.users;
     527          58 :   nm->max_translations_per_thread = c.sessions;
     528          58 :   nm->max_translations_per_user = c.user_sessions;
     529             : 
     530          58 :   nm->inside_vrf_id = c.inside_vrf;
     531         116 :   nm->inside_fib_index = fib_table_find_or_create_and_lock (
     532          58 :     FIB_PROTOCOL_IP4, c.inside_vrf, nm->fib_src_hi);
     533             : 
     534          58 :   nm->outside_vrf_id = c.outside_vrf;
     535         116 :   nm->outside_fib_index = fib_table_find_or_create_and_lock (
     536          58 :     FIB_PROTOCOL_IP4, c.outside_vrf, nm->fib_src_hi);
     537             : 
     538          58 :   nat_reset_timeouts (&nm->timeouts);
     539          58 :   nat44_ei_db_init (nm->translations, nm->translation_buckets,
     540             :                     nm->user_buckets);
     541          58 :   nat44_ei_set_alloc_default ();
     542             : 
     543          58 :   vlib_zero_simple_counter (&nm->total_users, 0);
     544          58 :   vlib_zero_simple_counter (&nm->total_sessions, 0);
     545          58 :   vlib_zero_simple_counter (&nm->user_limit_reached, 0);
     546             : 
     547          58 :   if (nm->num_workers > 1)
     548             :     {
     549           2 :       if (nm->fq_in2out_index == ~0)
     550             :         {
     551           1 :           nm->fq_in2out_index = vlib_frame_queue_main_init (
     552             :             nm->in2out_node_index, nm->frame_queue_nelts);
     553             :         }
     554           2 :       if (nm->fq_out2in_index == ~0)
     555             :         {
     556           1 :           nm->fq_out2in_index = vlib_frame_queue_main_init (
     557             :             nm->out2in_node_index, nm->frame_queue_nelts);
     558             :         }
     559           2 :       if (nm->fq_in2out_output_index == ~0)
     560             :         {
     561           1 :           nm->fq_in2out_output_index = vlib_frame_queue_main_init (
     562             :             nm->in2out_output_node_index, nm->frame_queue_nelts);
     563             :         }
     564             :     }
     565             : 
     566          58 :   nat_ha_enable ();
     567          58 :   nm->enabled = 1;
     568             : 
     569          58 :   return 0;
     570             : }
     571             : 
     572             : static_always_inline nat44_ei_outside_fib_t *
     573         110 : nat44_ei_get_outside_fib (nat44_ei_outside_fib_t *outside_fibs, u32 fib_index)
     574             : {
     575             :   nat44_ei_outside_fib_t *f;
     576         111 :   vec_foreach (f, outside_fibs)
     577             :     {
     578          58 :       if (f->fib_index == fib_index)
     579             :         {
     580          57 :           return f;
     581             :         }
     582             :     }
     583          53 :   return 0;
     584             : }
     585             : 
     586             : static_always_inline nat44_ei_interface_t *
     587         349 : nat44_ei_get_interface (nat44_ei_interface_t *interfaces, u32 sw_if_index)
     588             : {
     589             :   nat44_ei_interface_t *i;
     590         421 :   pool_foreach (i, interfaces)
     591             :     {
     592         188 :       if (i->sw_if_index == sw_if_index)
     593             :         {
     594         116 :           return i;
     595             :         }
     596             :     }
     597         233 :   return 0;
     598             : }
     599             : 
     600             : static_always_inline int
     601         110 : nat44_ei_hairpinning_enable (u8 is_enable)
     602             : {
     603         110 :   nat44_ei_main_t *nm = &nat44_ei_main;
     604         110 :   u32 sw_if_index = 0; // local0
     605             : 
     606         110 :   if (is_enable)
     607             :     {
     608          55 :       nm->hairpin_reg += 1;
     609          55 :       if (1 == nm->hairpin_reg)
     610             :         {
     611          48 :           return vnet_feature_enable_disable (
     612             :             "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0);
     613             :         }
     614             :     }
     615             :   else
     616             :     {
     617          55 :       if (0 == nm->hairpin_reg)
     618           0 :         return 1;
     619             : 
     620          55 :       nm->hairpin_reg -= 1;
     621          55 :       if (0 == nm->hairpin_reg)
     622             :         {
     623          48 :           return vnet_feature_enable_disable (
     624             :             "ip4-local", "nat44-ei-hairpinning", sw_if_index, is_enable, 0, 0);
     625             :         }
     626             :     }
     627             : 
     628          14 :   return 0;
     629             : }
     630             : 
     631             : int
     632         106 : nat44_ei_add_interface (u32 sw_if_index, u8 is_inside)
     633             : {
     634             :   const char *feature_name, *del_feature_name;
     635         106 :   nat44_ei_main_t *nm = &nat44_ei_main;
     636             : 
     637             :   nat44_ei_outside_fib_t *outside_fib;
     638             :   nat44_ei_interface_t *i;
     639             :   u32 fib_index;
     640             :   int rv;
     641             : 
     642         106 :   fail_if_disabled ();
     643             : 
     644         106 :   if (nm->out2in_dpo && !is_inside)
     645             :     {
     646           0 :       nat44_ei_log_err ("error unsupported");
     647           0 :       return VNET_API_ERROR_UNSUPPORTED;
     648             :     }
     649             : 
     650         106 :   if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
     651             :     {
     652           0 :       nat44_ei_log_err ("error interface already configured");
     653           0 :       return VNET_API_ERROR_VALUE_EXIST;
     654             :     }
     655             : 
     656         106 :   i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
     657         106 :   if (i)
     658             :     {
     659           2 :       if ((nat44_ei_interface_is_inside (i) && is_inside) ||
     660           2 :           (nat44_ei_interface_is_outside (i) && !is_inside))
     661             :         {
     662           0 :           return 0;
     663             :         }
     664           1 :       if (nm->num_workers > 1)
     665             :         {
     666           0 :           del_feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
     667             :                                           "nat44-ei-out2in-worker-handoff";
     668           0 :           feature_name = "nat44-ei-handoff-classify";
     669             :         }
     670             :       else
     671             :         {
     672           1 :           del_feature_name =
     673             :             !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
     674             : 
     675           1 :           feature_name = "nat44-ei-classify";
     676             :         }
     677             : 
     678           1 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
     679           1 :       if (rv)
     680             :         {
     681           0 :           return rv;
     682             :         }
     683           1 :       rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
     684             :                                         sw_if_index, 0, 0, 0);
     685           1 :       if (rv)
     686             :         {
     687           0 :           return rv;
     688             :         }
     689           1 :       rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
     690             :                                         sw_if_index, 1, 0, 0);
     691           1 :       if (rv)
     692             :         {
     693           0 :           return rv;
     694             :         }
     695           1 :       if (!is_inside)
     696             :         {
     697           0 :           rv = nat44_ei_hairpinning_enable (0);
     698           0 :           if (rv)
     699             :             {
     700           0 :               return rv;
     701             :             }
     702             :         }
     703             :     }
     704             :   else
     705             :     {
     706         105 :       if (nm->num_workers > 1)
     707             :         {
     708           4 :           feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
     709             :                                      "nat44-ei-out2in-worker-handoff";
     710             :         }
     711             :       else
     712             :         {
     713         101 :           feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
     714             :         }
     715         105 :       nat_validate_interface_counters (nm, sw_if_index);
     716             : 
     717         105 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
     718         105 :       if (rv)
     719             :         {
     720           0 :           return rv;
     721             :         }
     722         105 :       rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
     723             :                                         sw_if_index, 1, 0, 0);
     724         105 :       if (rv)
     725             :         {
     726           0 :           return rv;
     727             :         }
     728         105 :       if (is_inside && !nm->out2in_dpo)
     729             :         {
     730          55 :           rv = nat44_ei_hairpinning_enable (1);
     731          55 :           if (rv)
     732             :             {
     733           0 :               return rv;
     734             :             }
     735             :         }
     736             : 
     737         105 :       pool_get (nm->interfaces, i);
     738         105 :       i->sw_if_index = sw_if_index;
     739         105 :       i->flags = 0;
     740             :     }
     741             : 
     742             :   fib_index =
     743         106 :     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
     744             : 
     745         106 :   if (!is_inside)
     746             :     {
     747          50 :       i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
     748             : 
     749          50 :       outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
     750          50 :       if (outside_fib)
     751             :         {
     752           0 :           outside_fib->refcount++;
     753             :         }
     754             :       else
     755             :         {
     756          50 :           vec_add2 (nm->outside_fibs, outside_fib, 1);
     757          50 :           outside_fib->fib_index = fib_index;
     758          50 :           outside_fib->refcount = 1;
     759             :         }
     760             : 
     761          50 :       nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1);
     762          50 :       nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1);
     763             :     }
     764             :   else
     765             :     {
     766          56 :       i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
     767             :     }
     768             : 
     769         106 :   return 0;
     770             : }
     771             : 
     772             : int
     773         106 : nat44_ei_del_interface (u32 sw_if_index, u8 is_inside)
     774             : {
     775             :   const char *feature_name, *del_feature_name;
     776         106 :   nat44_ei_main_t *nm = &nat44_ei_main;
     777             : 
     778             :   nat44_ei_outside_fib_t *outside_fib;
     779             :   nat44_ei_interface_t *i;
     780             :   u32 fib_index;
     781             :   int rv;
     782             : 
     783         106 :   fail_if_disabled ();
     784             : 
     785         106 :   if (nm->out2in_dpo && !is_inside)
     786             :     {
     787           0 :       nat44_ei_log_err ("error unsupported");
     788           0 :       return VNET_API_ERROR_UNSUPPORTED;
     789             :     }
     790             : 
     791         106 :   i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
     792         106 :   if (i == 0)
     793             :     {
     794           0 :       nat44_ei_log_err ("error interface couldn't be found");
     795           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
     796             :     }
     797             : 
     798         106 :   if (nat44_ei_interface_is_inside (i) && nat44_ei_interface_is_outside (i))
     799             :     {
     800           1 :       if (nm->num_workers > 1)
     801             :         {
     802           0 :           del_feature_name = "nat44-ei-handoff-classify";
     803           0 :           feature_name = !is_inside ? "nat44-ei-in2out-worker-handoff" :
     804             :                                       "nat44-ei-out2in-worker-handoff";
     805             :         }
     806             :       else
     807             :         {
     808           1 :           del_feature_name = "nat44-ei-classify";
     809           1 :           feature_name = !is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
     810             :         }
     811             : 
     812           1 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
     813           1 :       if (rv)
     814             :         {
     815           0 :           return rv;
     816             :         }
     817           1 :       rv = vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
     818             :                                         sw_if_index, 0, 0, 0);
     819           1 :       if (rv)
     820             :         {
     821           0 :           return rv;
     822             :         }
     823           1 :       rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
     824             :                                         sw_if_index, 1, 0, 0);
     825           1 :       if (rv)
     826             :         {
     827           0 :           return rv;
     828             :         }
     829           1 :       if (is_inside)
     830             :         {
     831           1 :           i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
     832             :         }
     833             :       else
     834             :         {
     835           0 :           rv = nat44_ei_hairpinning_enable (1);
     836           0 :           if (rv)
     837             :             {
     838           0 :               return rv;
     839             :             }
     840           0 :           i->flags &= ~NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
     841             :         }
     842             :     }
     843             :   else
     844             :     {
     845         105 :       if (nm->num_workers > 1)
     846             :         {
     847           4 :           feature_name = is_inside ? "nat44-ei-in2out-worker-handoff" :
     848             :                                      "nat44-ei-out2in-worker-handoff";
     849             :         }
     850             :       else
     851             :         {
     852         101 :           feature_name = is_inside ? "nat44-ei-in2out" : "nat44-ei-out2in";
     853             :         }
     854             : 
     855         105 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
     856         105 :       if (rv)
     857             :         {
     858           0 :           return rv;
     859             :         }
     860         105 :       rv = vnet_feature_enable_disable ("ip4-unicast", feature_name,
     861             :                                         sw_if_index, 0, 0, 0);
     862         105 :       if (rv)
     863             :         {
     864           0 :           return rv;
     865             :         }
     866         105 :       if (is_inside)
     867             :         {
     868          55 :           rv = nat44_ei_hairpinning_enable (0);
     869          55 :           if (rv)
     870             :             {
     871           0 :               return rv;
     872             :             }
     873             :         }
     874             : 
     875             :       // remove interface
     876         105 :       pool_put (nm->interfaces, i);
     877             :     }
     878             : 
     879         106 :   if (!is_inside)
     880             :     {
     881             :       fib_index =
     882          50 :         fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
     883          50 :       outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
     884          50 :       if (outside_fib)
     885             :         {
     886          50 :           outside_fib->refcount--;
     887          50 :           if (!outside_fib->refcount)
     888             :             {
     889          48 :               vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
     890             :             }
     891             :         }
     892             : 
     893          50 :       nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 0);
     894          50 :       nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0);
     895             :     }
     896             : 
     897         106 :   return 0;
     898             : }
     899             : 
     900             : int
     901           5 : nat44_ei_add_output_interface (u32 sw_if_index)
     902             : {
     903           5 :   nat44_ei_main_t *nm = &nat44_ei_main;
     904             : 
     905             :   nat44_ei_outside_fib_t *outside_fib;
     906             :   nat44_ei_interface_t *i;
     907             :   u32 fib_index;
     908             :   int rv;
     909             : 
     910           5 :   fail_if_disabled ();
     911             : 
     912           5 :   if (nat44_ei_get_interface (nm->interfaces, sw_if_index))
     913             :     {
     914           0 :       nat44_ei_log_err ("error interface already configured");
     915           0 :       return VNET_API_ERROR_VALUE_EXIST;
     916             :     }
     917             : 
     918           5 :   if (nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index))
     919             :     {
     920           0 :       nat44_ei_log_err ("error interface already configured");
     921           0 :       return VNET_API_ERROR_VALUE_EXIST;
     922             :     }
     923             : 
     924           5 :   if (nm->num_workers > 1)
     925             :     {
     926           0 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
     927           0 :       if (rv)
     928             :         {
     929           0 :           return rv;
     930             :         }
     931           0 :       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
     932           0 :       if (rv)
     933             :         {
     934           0 :           return rv;
     935             :         }
     936           0 :       rv = vnet_feature_enable_disable (
     937             :         "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 1, 0, 0);
     938           0 :       if (rv)
     939             :         {
     940           0 :           return rv;
     941             :         }
     942           0 :       rv = vnet_feature_enable_disable (
     943             :         "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 1,
     944             :         0, 0);
     945           0 :       if (rv)
     946             :         {
     947           0 :           return rv;
     948             :         }
     949             :     }
     950             :   else
     951             :     {
     952           5 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
     953           5 :       if (rv)
     954             :         {
     955           0 :           return rv;
     956             :         }
     957           5 :       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
     958           5 :       if (rv)
     959             :         {
     960           0 :           return rv;
     961             :         }
     962           5 :       rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
     963             :                                         sw_if_index, 1, 0, 0);
     964           5 :       if (rv)
     965             :         {
     966           0 :           return rv;
     967             :         }
     968           5 :       rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
     969             :                                         sw_if_index, 1, 0, 0);
     970           5 :       if (rv)
     971             :         {
     972           0 :           return rv;
     973             :         }
     974             :     }
     975             : 
     976           5 :   nat_validate_interface_counters (nm, sw_if_index);
     977             : 
     978           5 :   pool_get (nm->output_feature_interfaces, i);
     979           5 :   i->sw_if_index = sw_if_index;
     980           5 :   i->flags = 0;
     981           5 :   i->flags |= NAT44_EI_INTERFACE_FLAG_IS_INSIDE;
     982           5 :   i->flags |= NAT44_EI_INTERFACE_FLAG_IS_OUTSIDE;
     983             : 
     984             :   fib_index =
     985           5 :     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
     986           5 :   outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
     987           5 :   if (outside_fib)
     988             :     {
     989           2 :       outside_fib->refcount++;
     990             :     }
     991             :   else
     992             :     {
     993           3 :       vec_add2 (nm->outside_fibs, outside_fib, 1);
     994           3 :       outside_fib->fib_index = fib_index;
     995           3 :       outside_fib->refcount = 1;
     996             :     }
     997             : 
     998           5 :   nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 1);
     999           5 :   nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 1);
    1000             : 
    1001           5 :   return 0;
    1002             : }
    1003             : 
    1004             : int
    1005           5 : nat44_ei_del_output_interface (u32 sw_if_index)
    1006             : {
    1007           5 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1008             : 
    1009             :   nat44_ei_outside_fib_t *outside_fib;
    1010             :   nat44_ei_interface_t *i;
    1011             :   u32 fib_index;
    1012             :   int rv;
    1013             : 
    1014           5 :   fail_if_disabled ();
    1015             : 
    1016           5 :   i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index);
    1017           5 :   if (!i)
    1018             :     {
    1019           0 :       nat44_ei_log_err ("error interface couldn't be found");
    1020           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
    1021             :     }
    1022             : 
    1023           5 :   if (nm->num_workers > 1)
    1024             :     {
    1025           0 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
    1026           0 :       if (rv)
    1027             :         {
    1028           0 :           return rv;
    1029             :         }
    1030           0 :       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
    1031           0 :       if (rv)
    1032             :         {
    1033           0 :           return rv;
    1034             :         }
    1035           0 :       rv = vnet_feature_enable_disable (
    1036             :         "ip4-unicast", "nat44-ei-out2in-worker-handoff", sw_if_index, 0, 0, 0);
    1037           0 :       if (rv)
    1038             :         {
    1039           0 :           return rv;
    1040             :         }
    1041           0 :       rv = vnet_feature_enable_disable (
    1042             :         "ip4-output", "nat44-ei-in2out-output-worker-handoff", sw_if_index, 0,
    1043             :         0, 0);
    1044           0 :       if (rv)
    1045             :         {
    1046           0 :           return rv;
    1047             :         }
    1048             :     }
    1049             :   else
    1050             :     {
    1051           5 :       rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
    1052           5 :       if (rv)
    1053             :         {
    1054           0 :           return rv;
    1055             :         }
    1056           5 :       rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
    1057           5 :       if (rv)
    1058             :         {
    1059           0 :           return rv;
    1060             :         }
    1061           5 :       rv = vnet_feature_enable_disable ("ip4-unicast", "nat44-ei-out2in",
    1062             :                                         sw_if_index, 0, 0, 0);
    1063           5 :       if (rv)
    1064             :         {
    1065           0 :           return rv;
    1066             :         }
    1067           5 :       rv = vnet_feature_enable_disable ("ip4-output", "nat44-ei-in2out-output",
    1068             :                                         sw_if_index, 0, 0, 0);
    1069           5 :       if (rv)
    1070             :         {
    1071           0 :           return rv;
    1072             :         }
    1073             :     }
    1074             : 
    1075           5 :   pool_put (nm->output_feature_interfaces, i);
    1076             : 
    1077             :   fib_index =
    1078           5 :     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
    1079           5 :   outside_fib = nat44_ei_get_outside_fib (nm->outside_fibs, fib_index);
    1080           5 :   if (outside_fib)
    1081             :     {
    1082           5 :       outside_fib->refcount--;
    1083           5 :       if (!outside_fib->refcount)
    1084             :         {
    1085           4 :           vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
    1086             :         }
    1087             :     }
    1088             : 
    1089           5 :   nat44_ei_add_del_addr_to_fib_foreach_addr (sw_if_index, 0);
    1090           5 :   nat44_ei_add_del_addr_to_fib_foreach_addr_only_sm (sw_if_index, 0);
    1091             : 
    1092           5 :   return 0;
    1093             : }
    1094             : 
    1095             : int
    1096           0 : nat44_ei_add_del_output_interface (u32 sw_if_index, int is_del)
    1097             : {
    1098           0 :   if (is_del)
    1099             :     {
    1100           0 :       return nat44_ei_del_output_interface (sw_if_index);
    1101             :     }
    1102             :   else
    1103             :     {
    1104           0 :       return nat44_ei_add_output_interface (sw_if_index);
    1105             :     }
    1106             : }
    1107             : 
    1108             : int
    1109          58 : nat44_ei_del_addresses ()
    1110             : {
    1111          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1112             :   nat44_ei_address_t *a, *vec;
    1113          58 :   int error = 0;
    1114             : 
    1115          58 :   vec = vec_dup (nm->addresses);
    1116         198 :   vec_foreach (a, vec)
    1117             :     {
    1118         140 :       error = nat44_ei_del_address (a->addr, 0);
    1119             : 
    1120         140 :       if (error)
    1121             :         {
    1122           0 :           nat44_ei_log_err ("error occurred while removing adderess");
    1123             :         }
    1124             :     }
    1125          58 :   vec_free (vec);
    1126          58 :   vec_free (nm->addresses);
    1127          58 :   nm->addresses = 0;
    1128             : 
    1129          58 :   vec_free (nm->auto_add_sw_if_indices);
    1130          58 :   nm->auto_add_sw_if_indices = 0;
    1131          58 :   return error;
    1132             : }
    1133             : 
    1134             : int
    1135          58 : nat44_ei_del_interfaces ()
    1136             : {
    1137          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1138             :   nat44_ei_interface_t *i, *pool;
    1139          58 :   int error = 0;
    1140             : 
    1141          58 :   pool = pool_dup (nm->interfaces);
    1142         160 :   pool_foreach (i, pool)
    1143             :     {
    1144         102 :       if (nat44_ei_interface_is_inside (i))
    1145             :         {
    1146          54 :           error = nat44_ei_del_interface (i->sw_if_index, 1);
    1147             :         }
    1148         102 :       if (nat44_ei_interface_is_outside (i))
    1149             :         {
    1150          49 :           error = nat44_ei_del_interface (i->sw_if_index, 0);
    1151             :         }
    1152             : 
    1153         102 :       if (error)
    1154             :         {
    1155           0 :           nat44_ei_log_err ("error occurred while removing interface");
    1156             :         }
    1157             :     }
    1158          58 :   pool_free (pool);
    1159          58 :   pool_free (nm->interfaces);
    1160          58 :   nm->interfaces = 0;
    1161          58 :   return error;
    1162             : }
    1163             : 
    1164             : int
    1165          58 : nat44_ei_del_output_interfaces ()
    1166             : {
    1167          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1168             :   nat44_ei_interface_t *i, *pool;
    1169          58 :   int error = 0;
    1170             : 
    1171          58 :   pool = pool_dup (nm->output_feature_interfaces);
    1172          62 :   pool_foreach (i, pool)
    1173             :     {
    1174           4 :       error = nat44_ei_del_output_interface (i->sw_if_index);
    1175           4 :       if (error)
    1176             :         {
    1177           0 :           nat44_ei_log_err ("error occurred while removing output interface");
    1178             :         }
    1179             :     }
    1180          58 :   pool_free (pool);
    1181          58 :   pool_free (nm->output_feature_interfaces);
    1182          58 :   nm->output_feature_interfaces = 0;
    1183          58 :   return error;
    1184             : }
    1185             : 
    1186             : static clib_error_t *
    1187       11798 : nat44_ei_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
    1188             : {
    1189       11798 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1190             :   nat44_ei_interface_t *i;
    1191       11798 :   int error = 0;
    1192             : 
    1193       11798 :   if (is_add)
    1194        7547 :     return 0;
    1195             : 
    1196        4251 :   if (!nm->enabled)
    1197        4243 :     return 0;
    1198             : 
    1199           8 :   i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
    1200           8 :   if (i)
    1201             :     {
    1202           3 :       bool is_inside = nat44_ei_interface_is_inside (i);
    1203           3 :       bool is_outside = nat44_ei_interface_is_outside (i);
    1204             : 
    1205           3 :       if (is_inside)
    1206             :         {
    1207           2 :           error |= nat44_ei_del_interface (sw_if_index, 1);
    1208             :         }
    1209           3 :       if (is_outside)
    1210             :         {
    1211           1 :           error |= nat44_ei_del_interface (sw_if_index, 0);
    1212             :         }
    1213             : 
    1214           3 :       if (error)
    1215             :         {
    1216           0 :           nat44_ei_log_err ("error occurred while removing interface");
    1217             :         }
    1218             :     }
    1219             : 
    1220           8 :   i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index);
    1221           8 :   if (i)
    1222             :     {
    1223           1 :       error = nat44_ei_del_output_interface (sw_if_index);
    1224           1 :       if (error)
    1225             :         {
    1226           0 :           nat44_ei_log_err ("error occurred while removing output interface");
    1227             :         }
    1228             :     }
    1229             : 
    1230           8 :   return 0;
    1231             : }
    1232             : 
    1233        1151 : VNET_SW_INTERFACE_ADD_DEL_FUNCTION (nat44_ei_sw_interface_add_del);
    1234             : 
    1235             : int
    1236          58 : nat44_ei_del_static_mappings ()
    1237             : {
    1238          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1239             :   nat44_ei_static_mapping_t *m, *pool;
    1240          58 :   int error = 0;
    1241             : 
    1242          58 :   pool = pool_dup (nm->static_mappings);
    1243          91 :   pool_foreach (m, pool)
    1244             :     {
    1245          33 :       error = nat44_ei_del_static_mapping_internal (
    1246          33 :         m->local_addr, m->external_addr, m->local_port, m->external_port,
    1247             :         m->proto, m->vrf_id, ~0, m->flags);
    1248          33 :       if (error)
    1249             :         {
    1250           0 :           nat44_ei_log_err ("error occurred while removing mapping");
    1251             :         }
    1252             :     }
    1253          58 :   pool_free (pool);
    1254          58 :   pool_free (nm->static_mappings);
    1255          58 :   nm->static_mappings = 0;
    1256             : 
    1257          58 :   vec_free (nm->to_resolve);
    1258          58 :   nm->to_resolve = 0;
    1259             : 
    1260          58 :   clib_bihash_free_8_8 (&nm->static_mapping_by_local);
    1261          58 :   clib_bihash_free_8_8 (&nm->static_mapping_by_external);
    1262             : 
    1263          58 :   return error;
    1264             : }
    1265             : 
    1266             : int
    1267          58 : nat44_ei_plugin_disable ()
    1268             : {
    1269          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1270             :   nat44_ei_main_per_thread_data_t *tnm;
    1271          58 :   int rc, error = 0;
    1272             : 
    1273          58 :   fail_if_disabled ();
    1274             : 
    1275          58 :   nat_ha_disable ();
    1276             : 
    1277          58 :   rc = nat44_ei_del_static_mappings ();
    1278          58 :   if (rc)
    1279           0 :     error = VNET_API_ERROR_BUG;
    1280             : 
    1281          58 :   rc = nat44_ei_del_addresses ();
    1282          58 :   if (rc)
    1283           0 :     error = VNET_API_ERROR_BUG;
    1284             : 
    1285          58 :   rc = nat44_ei_del_interfaces ();
    1286          58 :   if (rc)
    1287           0 :     error = VNET_API_ERROR_BUG;
    1288             : 
    1289          58 :   rc = nat44_ei_del_output_interfaces ();
    1290          58 :   if (rc)
    1291           0 :     error = VNET_API_ERROR_BUG;
    1292             : 
    1293          58 :   if (nm->pat)
    1294             :     {
    1295          58 :       clib_bihash_free_8_8 (&nm->in2out);
    1296          58 :       clib_bihash_free_8_8 (&nm->out2in);
    1297             : 
    1298         120 :       vec_foreach (tnm, nm->per_thread_data)
    1299             :         {
    1300          62 :           nat44_ei_worker_db_free (tnm);
    1301             :         }
    1302             :     }
    1303             : 
    1304          58 :   clib_memset (&nm->rconfig, 0, sizeof (nm->rconfig));
    1305             : 
    1306          58 :   nm->forwarding_enabled = 0;
    1307          58 :   nm->enabled = 0;
    1308             : 
    1309          58 :   return error;
    1310             : }
    1311             : 
    1312             : int
    1313           2 : nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
    1314             :                                        u32 thread_index, ip4_address_t addr,
    1315             :                                        u16 port, nat_protocol_t protocol)
    1316             : {
    1317           2 :   nat44_ei_address_t *a = 0;
    1318             :   u32 address_index;
    1319           2 :   u16 port_host_byte_order = clib_net_to_host_u16 (port);
    1320             : 
    1321           2 :   for (address_index = 0; address_index < vec_len (addresses); address_index++)
    1322             :     {
    1323           2 :       if (addresses[address_index].addr.as_u32 != addr.as_u32)
    1324           0 :         continue;
    1325             : 
    1326           2 :       a = addresses + address_index;
    1327           2 :       if (nat44_ei_port_is_used (a, protocol, port_host_byte_order))
    1328           0 :         return VNET_API_ERROR_INSTANCE_IN_USE;
    1329             : 
    1330           2 :       nat44_ei_port_get (a, protocol, port_host_byte_order);
    1331           2 :       a->busy_ports_per_thread[protocol][thread_index]++;
    1332           2 :       a->busy_ports[protocol]++;
    1333           2 :       return 0;
    1334             :     }
    1335             : 
    1336           0 :   return VNET_API_ERROR_NO_SUCH_ENTRY;
    1337             : }
    1338             : 
    1339             : void
    1340           0 : nat44_ei_add_del_address_dpo (ip4_address_t addr, u8 is_add)
    1341             : {
    1342           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1343           0 :   dpo_id_t dpo_v4 = DPO_INVALID;
    1344           0 :   fib_prefix_t pfx = {
    1345             :     .fp_proto = FIB_PROTOCOL_IP4,
    1346             :     .fp_len = 32,
    1347           0 :     .fp_addr.ip4.as_u32 = addr.as_u32,
    1348             :   };
    1349             : 
    1350           0 :   if (is_add)
    1351             :     {
    1352           0 :       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
    1353           0 :       fib_table_entry_special_dpo_add (0, &pfx, nm->fib_src_hi,
    1354             :                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
    1355           0 :       dpo_reset (&dpo_v4);
    1356             :     }
    1357             :   else
    1358             :     {
    1359           0 :       fib_table_entry_special_remove (0, &pfx, nm->fib_src_hi);
    1360             :     }
    1361           0 : }
    1362             : 
    1363             : void
    1364       10435 : nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
    1365             :                                         u32 thread_index, ip4_address_t *addr,
    1366             :                                         u16 port, nat_protocol_t protocol)
    1367             : {
    1368             :   nat44_ei_address_t *a;
    1369             :   u32 address_index;
    1370       10435 :   u16 port_host_byte_order = clib_net_to_host_u16 (port);
    1371             : 
    1372       12861 :   for (address_index = 0; address_index < vec_len (addresses); address_index++)
    1373             :     {
    1374       12861 :       if (addresses[address_index].addr.as_u32 == addr->as_u32)
    1375       10435 :         break;
    1376             :     }
    1377             : 
    1378       10435 :   ASSERT (address_index < vec_len (addresses));
    1379             : 
    1380       10435 :   a = addresses + address_index;
    1381       10435 :   nat44_ei_port_put (a, protocol, port_host_byte_order);
    1382       10435 :   a->busy_ports[protocol]--;
    1383       10435 :   a->busy_ports_per_thread[protocol][thread_index]--;
    1384       10435 : }
    1385             : 
    1386             : void
    1387          57 : nat44_ei_free_session_data_v2 (nat44_ei_main_t *nm, nat44_ei_session_t *s,
    1388             :                                u32 thread_index, u8 is_ha)
    1389             : {
    1390             :   clib_bihash_kv_8_8_t kv;
    1391             : 
    1392             :   /* session lookup tables */
    1393          57 :   init_nat_i2o_k (&kv, s);
    1394          57 :   if (clib_bihash_add_del_8_8 (&nm->in2out, &kv, 0))
    1395           0 :     nat_elog_warn (nm, "in2out key del failed");
    1396          57 :   init_nat_o2i_k (&kv, s);
    1397          57 :   if (clib_bihash_add_del_8_8 (&nm->out2in, &kv, 0))
    1398           0 :     nat_elog_warn (nm, "out2in key del failed");
    1399             : 
    1400          57 :   if (!is_ha)
    1401          56 :     nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
    1402          56 :                              &s->in2out.addr, s->in2out.port, &s->out2in.addr,
    1403          56 :                              s->out2in.port, s->nat_proto);
    1404             : 
    1405          57 :   if (nat44_ei_is_unk_proto_session (s))
    1406          49 :     return;
    1407             : 
    1408          57 :   if (!is_ha)
    1409             :     {
    1410             :       /* log NAT event */
    1411          56 :       nat_ipfix_logging_nat44_ses_delete (
    1412             :         thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
    1413          56 :         nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
    1414             :         s->in2out.fib_index);
    1415             : 
    1416          56 :       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
    1417          56 :                    s->ext_host_port, s->nat_proto, s->out2in.fib_index,
    1418             :                    thread_index);
    1419             :     }
    1420             : 
    1421          57 :   if (nat44_ei_is_session_static (s))
    1422          49 :     return;
    1423             : 
    1424           8 :   nat44_ei_free_outside_address_and_port (nm->addresses, thread_index,
    1425           8 :                                           &s->out2in.addr, s->out2in.port,
    1426             :                                           s->nat_proto);
    1427             : }
    1428             : 
    1429             : nat44_ei_user_t *
    1430       10487 : nat44_ei_user_get_or_create (nat44_ei_main_t *nm, ip4_address_t *addr,
    1431             :                              u32 fib_index, u32 thread_index)
    1432             : {
    1433       10487 :   nat44_ei_user_t *u = 0;
    1434             :   nat44_ei_user_key_t user_key;
    1435             :   clib_bihash_kv_8_8_t kv, value;
    1436       10487 :   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
    1437             :   dlist_elt_t *per_user_list_head_elt;
    1438             : 
    1439       10487 :   user_key.addr.as_u32 = addr->as_u32;
    1440       10487 :   user_key.fib_index = fib_index;
    1441       10487 :   kv.key = user_key.as_u64;
    1442             : 
    1443             :   /* Ever heard of the "user" = src ip4 address before? */
    1444       10487 :   if (clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    1445             :     {
    1446       10396 :       if (pool_elts (tnm->users) >= nm->max_users_per_thread)
    1447             :         {
    1448           0 :           vlib_increment_simple_counter (&nm->user_limit_reached, thread_index,
    1449             :                                          0, 1);
    1450           0 :           nat_elog_warn (nm, "maximum user limit reached");
    1451           0 :           return NULL;
    1452             :         }
    1453             :       /* no, make a new one */
    1454       10396 :       pool_get (tnm->users, u);
    1455       10396 :       clib_memset (u, 0, sizeof (*u));
    1456             : 
    1457       10396 :       u->addr.as_u32 = addr->as_u32;
    1458       10396 :       u->fib_index = fib_index;
    1459             : 
    1460       10396 :       pool_get (tnm->list_pool, per_user_list_head_elt);
    1461             : 
    1462       10396 :       u->sessions_per_user_list_head_index =
    1463       10396 :         per_user_list_head_elt - tnm->list_pool;
    1464             : 
    1465       10396 :       clib_dlist_init (tnm->list_pool, u->sessions_per_user_list_head_index);
    1466             : 
    1467       10396 :       kv.value = u - tnm->users;
    1468             : 
    1469             :       /* add user */
    1470       10396 :       if (clib_bihash_add_del_8_8 (&tnm->user_hash, &kv, 1))
    1471             :         {
    1472           0 :           nat_elog_warn (nm, "user_hash key add failed");
    1473           0 :           nat44_ei_delete_user_with_no_session (nm, u, thread_index);
    1474           0 :           return NULL;
    1475             :         }
    1476             : 
    1477       10396 :       vlib_set_simple_counter (&nm->total_users, thread_index, 0,
    1478       10396 :                                pool_elts (tnm->users));
    1479             :     }
    1480             :   else
    1481             :     {
    1482          91 :       u = pool_elt_at_index (tnm->users, value.value);
    1483             :     }
    1484             : 
    1485       10487 :   return u;
    1486             : }
    1487             : 
    1488             : nat44_ei_session_t *
    1489       10487 : nat44_ei_session_alloc_or_recycle (nat44_ei_main_t *nm, nat44_ei_user_t *u,
    1490             :                                    u32 thread_index, f64 now)
    1491             : {
    1492             :   nat44_ei_session_t *s;
    1493       10487 :   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
    1494             :   u32 oldest_per_user_translation_list_index, session_index;
    1495             :   dlist_elt_t *oldest_per_user_translation_list_elt;
    1496             :   dlist_elt_t *per_user_translation_list_elt;
    1497             : 
    1498             :   /* Over quota? Recycle the least recently used translation */
    1499       10487 :   if ((u->nsessions + u->nstaticsessions) >= nm->max_translations_per_user)
    1500             :     {
    1501           0 :       oldest_per_user_translation_list_index = clib_dlist_remove_head (
    1502             :         tnm->list_pool, u->sessions_per_user_list_head_index);
    1503             : 
    1504           0 :       ASSERT (oldest_per_user_translation_list_index != ~0);
    1505             : 
    1506             :       /* Add it back to the end of the LRU list */
    1507           0 :       clib_dlist_addtail (tnm->list_pool, u->sessions_per_user_list_head_index,
    1508             :                           oldest_per_user_translation_list_index);
    1509             :       /* Get the list element */
    1510           0 :       oldest_per_user_translation_list_elt = pool_elt_at_index (
    1511             :         tnm->list_pool, oldest_per_user_translation_list_index);
    1512             : 
    1513             :       /* Get the session index from the list element */
    1514           0 :       session_index = oldest_per_user_translation_list_elt->value;
    1515             : 
    1516             :       /* Get the session */
    1517           0 :       s = pool_elt_at_index (tnm->sessions, session_index);
    1518             : 
    1519           0 :       nat44_ei_free_session_data_v2 (nm, s, thread_index, 0);
    1520           0 :       if (nat44_ei_is_session_static (s))
    1521           0 :         u->nstaticsessions--;
    1522             :       else
    1523           0 :         u->nsessions--;
    1524           0 :       s->flags = 0;
    1525           0 :       s->total_bytes = 0;
    1526           0 :       s->total_pkts = 0;
    1527           0 :       s->state = 0;
    1528           0 :       s->ext_host_addr.as_u32 = 0;
    1529           0 :       s->ext_host_port = 0;
    1530           0 :       s->ext_host_nat_addr.as_u32 = 0;
    1531           0 :       s->ext_host_nat_port = 0;
    1532             :     }
    1533             :   else
    1534             :     {
    1535       10487 :       pool_get (tnm->sessions, s);
    1536       10487 :       clib_memset (s, 0, sizeof (*s));
    1537             : 
    1538             :       /* Create list elts */
    1539       10487 :       pool_get (tnm->list_pool, per_user_translation_list_elt);
    1540       10487 :       clib_dlist_init (tnm->list_pool,
    1541       10487 :                        per_user_translation_list_elt - tnm->list_pool);
    1542             : 
    1543       10487 :       per_user_translation_list_elt->value = s - tnm->sessions;
    1544       10487 :       s->per_user_index = per_user_translation_list_elt - tnm->list_pool;
    1545       10487 :       s->per_user_list_head_index = u->sessions_per_user_list_head_index;
    1546             : 
    1547       10487 :       clib_dlist_addtail (tnm->list_pool, s->per_user_list_head_index,
    1548       10487 :                           per_user_translation_list_elt - tnm->list_pool);
    1549             : 
    1550       10487 :       s->user_index = u - tnm->users;
    1551       10487 :       vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
    1552       10487 :                                pool_elts (tnm->sessions));
    1553             :     }
    1554             : 
    1555       10487 :   s->ha_last_refreshed = now;
    1556             : 
    1557       10487 :   return s;
    1558             : }
    1559             : 
    1560             : void
    1561       10427 : nat44_ei_free_session_data (nat44_ei_main_t *nm, nat44_ei_session_t *s,
    1562             :                             u32 thread_index, u8 is_ha)
    1563             : {
    1564             :   clib_bihash_kv_8_8_t kv;
    1565             : 
    1566       10427 :   init_nat_i2o_k (&kv, s);
    1567       10427 :   if (clib_bihash_add_del_8_8 (&nm->in2out, &kv, 0))
    1568           0 :     nat_elog_warn (nm, "in2out key del failed");
    1569             : 
    1570       10427 :   init_nat_o2i_k (&kv, s);
    1571       10427 :   if (clib_bihash_add_del_8_8 (&nm->out2in, &kv, 0))
    1572           0 :     nat_elog_warn (nm, "out2in key del failed");
    1573             : 
    1574       10427 :   if (!is_ha)
    1575             :     {
    1576       10427 :       nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
    1577       10427 :                                &s->in2out.addr, s->in2out.port,
    1578       10427 :                                &s->out2in.addr, s->out2in.port, s->nat_proto);
    1579             : 
    1580       10427 :       nat_ipfix_logging_nat44_ses_delete (
    1581             :         thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
    1582       10427 :         nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
    1583             :         s->in2out.fib_index);
    1584             : 
    1585       10427 :       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
    1586       10427 :                    s->ext_host_port, s->nat_proto, s->out2in.fib_index,
    1587             :                    thread_index);
    1588             :     }
    1589             : 
    1590       10427 :   if (nat44_ei_is_session_static (s))
    1591           0 :     return;
    1592             : 
    1593       10427 :   nat44_ei_free_outside_address_and_port (nm->addresses, thread_index,
    1594       10427 :                                           &s->out2in.addr, s->out2in.port,
    1595             :                                           s->nat_proto);
    1596             : }
    1597             : 
    1598             : static_always_inline void
    1599           0 : nat44_ei_user_del_sessions (nat44_ei_user_t *u, u32 thread_index)
    1600             : {
    1601             :   dlist_elt_t *elt;
    1602             :   nat44_ei_session_t *s;
    1603             : 
    1604           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1605           0 :   nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
    1606             : 
    1607             :   // get head
    1608           0 :   elt =
    1609           0 :     pool_elt_at_index (tnm->list_pool, u->sessions_per_user_list_head_index);
    1610             :   // get first element
    1611           0 :   elt = pool_elt_at_index (tnm->list_pool, elt->next);
    1612             : 
    1613           0 :   while (elt->value != ~0)
    1614             :     {
    1615           0 :       s = pool_elt_at_index (tnm->sessions, elt->value);
    1616           0 :       elt = pool_elt_at_index (tnm->list_pool, elt->next);
    1617             : 
    1618           0 :       nat44_ei_free_session_data (nm, s, thread_index, 0);
    1619           0 :       nat44_ei_delete_session (nm, s, thread_index);
    1620             :     }
    1621           0 : }
    1622             : 
    1623             : int
    1624           0 : nat44_ei_user_del (ip4_address_t *addr, u32 fib_index)
    1625             : {
    1626           0 :   int rv = 1;
    1627             : 
    1628           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1629             :   nat44_ei_main_per_thread_data_t *tnm;
    1630             : 
    1631             :   nat44_ei_user_key_t user_key;
    1632             :   clib_bihash_kv_8_8_t kv, value;
    1633             : 
    1634           0 :   user_key.addr.as_u32 = addr->as_u32;
    1635           0 :   user_key.fib_index = fib_index;
    1636           0 :   kv.key = user_key.as_u64;
    1637             : 
    1638           0 :   if (nm->num_workers > 1)
    1639             :     {
    1640           0 :       vec_foreach (tnm, nm->per_thread_data)
    1641             :         {
    1642           0 :           if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    1643             :             {
    1644           0 :               nat44_ei_user_del_sessions (
    1645           0 :                 pool_elt_at_index (tnm->users, value.value),
    1646             :                 tnm->thread_index);
    1647           0 :               rv = 0;
    1648           0 :               break;
    1649             :             }
    1650             :         }
    1651             :     }
    1652             :   else
    1653             :     {
    1654           0 :       tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
    1655           0 :       if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    1656             :         {
    1657           0 :           nat44_ei_user_del_sessions (
    1658           0 :             pool_elt_at_index (tnm->users, value.value), tnm->thread_index);
    1659           0 :           rv = 0;
    1660             :         }
    1661             :     }
    1662           0 :   return rv;
    1663             : }
    1664             : 
    1665             : void
    1666          38 : nat44_ei_static_mapping_del_sessions (nat44_ei_main_t *nm,
    1667             :                                       nat44_ei_main_per_thread_data_t *tnm,
    1668             :                                       nat44_ei_user_key_t u_key, int addr_only,
    1669             :                                       ip4_address_t e_addr, u16 e_port)
    1670             : {
    1671             :   clib_bihash_kv_8_8_t kv, value;
    1672          38 :   kv.key = u_key.as_u64;
    1673             :   u64 user_index;
    1674             :   dlist_elt_t *head, *elt;
    1675             :   nat44_ei_user_t *u;
    1676             :   nat44_ei_session_t *s;
    1677             :   u32 elt_index, head_index, ses_index;
    1678             : 
    1679          38 :   if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    1680             :     {
    1681          25 :       user_index = value.value;
    1682          25 :       u = pool_elt_at_index (tnm->users, user_index);
    1683          25 :       if (u->nstaticsessions)
    1684             :         {
    1685          25 :           head_index = u->sessions_per_user_list_head_index;
    1686          25 :           head = pool_elt_at_index (tnm->list_pool, head_index);
    1687          25 :           elt_index = head->next;
    1688          25 :           elt = pool_elt_at_index (tnm->list_pool, elt_index);
    1689          25 :           ses_index = elt->value;
    1690          61 :           while (ses_index != ~0)
    1691             :             {
    1692          49 :               s = pool_elt_at_index (tnm->sessions, ses_index);
    1693          49 :               elt = pool_elt_at_index (tnm->list_pool, elt->next);
    1694          49 :               ses_index = elt->value;
    1695             : 
    1696          49 :               if (!addr_only)
    1697             :                 {
    1698          13 :                   if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
    1699          13 :                       (s->out2in.port != e_port))
    1700           0 :                     continue;
    1701             :                 }
    1702             : 
    1703          49 :               if (!nat44_ei_is_session_static (s))
    1704           0 :                 continue;
    1705             : 
    1706          49 :               nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data,
    1707             :                                              0);
    1708          49 :               nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
    1709             : 
    1710          49 :               if (!addr_only)
    1711          13 :                 break;
    1712             :             }
    1713             :         }
    1714             :     }
    1715          38 : }
    1716             : 
    1717             : u32
    1718          17 : nat44_ei_get_in2out_worker_index (ip4_header_t *ip0, u32 rx_fib_index0,
    1719             :                                   u8 is_output)
    1720             : {
    1721          17 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1722          17 :   u32 next_worker_index = 0;
    1723             :   u32 hash;
    1724             : 
    1725          17 :   next_worker_index = nm->first_worker_index;
    1726          17 :   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
    1727          17 :          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
    1728             : 
    1729          17 :   if (PREDICT_TRUE (is_pow2 (_vec_len (nm->workers))))
    1730          17 :     next_worker_index += nm->workers[hash & (_vec_len (nm->workers) - 1)];
    1731             :   else
    1732           0 :     next_worker_index += nm->workers[hash % _vec_len (nm->workers)];
    1733             : 
    1734          17 :   return next_worker_index;
    1735             : }
    1736             : 
    1737             : u32
    1738          32 : nat44_ei_get_thread_idx_by_port (u16 e_port)
    1739             : {
    1740          32 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1741          32 :   u32 thread_idx = nm->num_workers;
    1742          32 :   if (nm->num_workers > 1)
    1743             :     {
    1744           4 :       thread_idx = nm->first_worker_index +
    1745           2 :                    nm->workers[(e_port - 1024) / nm->port_per_thread %
    1746           2 :                                _vec_len (nm->workers)];
    1747             :     }
    1748          32 :   return thread_idx;
    1749             : }
    1750             : 
    1751             : u32
    1752           0 : nat44_ei_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip0,
    1753             :                                   u32 rx_fib_index0, u8 is_output)
    1754             : {
    1755           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1756             :   udp_header_t *udp;
    1757             :   u16 port;
    1758             :   clib_bihash_kv_8_8_t kv, value;
    1759             :   nat44_ei_static_mapping_t *m;
    1760             :   u32 proto;
    1761           0 :   u32 next_worker_index = 0;
    1762             : 
    1763             :   /* first try static mappings without port */
    1764           0 :   if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
    1765             :     {
    1766           0 :       init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
    1767           0 :       if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
    1768             :                                    &value))
    1769             :         {
    1770           0 :           m = pool_elt_at_index (nm->static_mappings, value.value);
    1771           0 :           return m->workers[0];
    1772             :         }
    1773             :     }
    1774             : 
    1775           0 :   proto = ip_proto_to_nat_proto (ip0->protocol);
    1776           0 :   udp = ip4_next_header (ip0);
    1777           0 :   port = vnet_buffer (b)->ip.reass.l4_dst_port;
    1778             : 
    1779             :   /* unknown protocol */
    1780           0 :   if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
    1781             :     {
    1782             :       /* use current thread */
    1783           0 :       return vlib_get_thread_index ();
    1784             :     }
    1785             : 
    1786           0 :   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
    1787             :     {
    1788           0 :       icmp46_header_t *icmp = (icmp46_header_t *) udp;
    1789           0 :       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
    1790           0 :       if (!icmp_type_is_error_message (
    1791           0 :             vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
    1792           0 :         port = vnet_buffer (b)->ip.reass.l4_src_port;
    1793             :       else
    1794             :         {
    1795             :           /* if error message, then it's not fragmented and we can access it */
    1796           0 :           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
    1797           0 :           proto = ip_proto_to_nat_proto (inner_ip->protocol);
    1798           0 :           void *l4_header = ip4_next_header (inner_ip);
    1799           0 :           switch (proto)
    1800             :             {
    1801           0 :             case NAT_PROTOCOL_ICMP:
    1802           0 :               icmp = (icmp46_header_t *) l4_header;
    1803           0 :               echo = (icmp_echo_header_t *) (icmp + 1);
    1804           0 :               port = echo->identifier;
    1805           0 :               break;
    1806           0 :             case NAT_PROTOCOL_UDP:
    1807             :             case NAT_PROTOCOL_TCP:
    1808           0 :               port = ((tcp_udp_header_t *) l4_header)->src_port;
    1809           0 :               break;
    1810           0 :             default:
    1811           0 :               return vlib_get_thread_index ();
    1812             :             }
    1813           0 :         }
    1814             :     }
    1815             : 
    1816             :   /* try static mappings with port */
    1817           0 :   if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
    1818             :     {
    1819           0 :       init_nat_k (&kv, ip0->dst_address, port, rx_fib_index0, proto);
    1820           0 :       if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
    1821             :                                    &value))
    1822             :         {
    1823           0 :           m = pool_elt_at_index (nm->static_mappings, value.value);
    1824           0 :           return m->workers[0];
    1825             :         }
    1826             :     }
    1827             : 
    1828             :   /* worker by outside port */
    1829             :   next_worker_index =
    1830           0 :     nat44_ei_get_thread_idx_by_port (clib_net_to_host_u16 (port));
    1831           0 :   return next_worker_index;
    1832             : }
    1833             : 
    1834             : static int
    1835       10439 : nat44_ei_alloc_default_cb (nat44_ei_address_t *addresses, u32 fib_index,
    1836             :                            u32 thread_index, nat_protocol_t proto,
    1837             :                            ip4_address_t s_addr, ip4_address_t *addr,
    1838             :                            u16 *port, u16 port_per_thread,
    1839             :                            u32 snat_thread_index)
    1840             : {
    1841       10439 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1842       10439 :   nat44_ei_address_t *a, *ga = 0;
    1843             :   u32 portnum;
    1844             :   int i;
    1845             : 
    1846       10439 :   if (vec_len (addresses) > 0)
    1847             :     {
    1848       10432 :       int s_addr_offset = s_addr.as_u32 % vec_len (addresses);
    1849             : 
    1850       25739 :       for (i = s_addr_offset; i < vec_len (addresses); ++i)
    1851             :         {
    1852       15319 :           a = addresses + i;
    1853             : 
    1854       15319 :           if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
    1855             :             {
    1856       15319 :               if (a->fib_index == fib_index)
    1857             :                 {
    1858             :                   while (1)
    1859             :                     {
    1860          24 :                       portnum = (port_per_thread * snat_thread_index) +
    1861          24 :                                 nat_random_port (&nm->random_seed, 0,
    1862          12 :                                                  port_per_thread - 1) +
    1863             :                                 1024;
    1864          12 :                       if (nat44_ei_port_is_used (a, proto, portnum))
    1865           0 :                         continue;
    1866          12 :                       nat44_ei_port_get (a, proto, portnum);
    1867          12 :                       a->busy_ports_per_thread[proto][thread_index]++;
    1868          12 :                       a->busy_ports[proto]++;
    1869          12 :                       *addr = a->addr;
    1870          12 :                       *port = clib_host_to_net_u16 (portnum);
    1871          12 :                       return 0;
    1872             :                     }
    1873             :                 }
    1874       15307 :               else if (a->fib_index == ~0)
    1875             :                 {
    1876       15295 :                   ga = a;
    1877             :                 }
    1878             :             }
    1879             :         }
    1880             : 
    1881       15345 :       for (i = 0; i < s_addr_offset; ++i)
    1882             :         {
    1883        4925 :           a = addresses + i;
    1884        4925 :           if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
    1885             :             {
    1886        4925 :               if (a->fib_index == fib_index)
    1887             :                 {
    1888             :                   while (1)
    1889             :                     {
    1890           0 :                       portnum = (port_per_thread * snat_thread_index) +
    1891           0 :                                 nat_random_port (&nm->random_seed, 0,
    1892           0 :                                                  port_per_thread - 1) +
    1893             :                                 1024;
    1894           0 :                       if (nat44_ei_port_is_used (a, proto, portnum))
    1895           0 :                         continue;
    1896           0 :                       nat44_ei_port_get (a, proto, portnum);
    1897           0 :                       a->busy_ports_per_thread[proto][thread_index]++;
    1898           0 :                       a->busy_ports[proto]++;
    1899           0 :                       *addr = a->addr;
    1900           0 :                       *port = clib_host_to_net_u16 (portnum);
    1901           0 :                       return 0;
    1902             :                     }
    1903             :                 }
    1904        4925 :               else if (a->fib_index == ~0)
    1905             :                 {
    1906        4925 :                   ga = a;
    1907             :                 }
    1908             :             }
    1909             :         }
    1910             : 
    1911       10420 :       if (ga)
    1912             :         {
    1913       10420 :           a = ga;
    1914       10420 :           if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
    1915             :             {
    1916       10420 :               if (a->fib_index == ~0)
    1917             :                 {
    1918             :                   while (1)
    1919             :                     {
    1920       20900 :                       portnum = (port_per_thread * snat_thread_index) +
    1921       20900 :                                 nat_random_port (&nm->random_seed, 0,
    1922       10450 :                                                  port_per_thread - 1) +
    1923             :                                 1024;
    1924       10450 :                       if (nat44_ei_port_is_used (a, proto, portnum))
    1925          30 :                         continue;
    1926       10420 :                       nat44_ei_port_get (a, proto, portnum);
    1927       10420 :                       a->busy_ports_per_thread[proto][thread_index]++;
    1928       10420 :                       a->busy_ports[proto]++;
    1929       10420 :                       *addr = a->addr;
    1930       10420 :                       *port = clib_host_to_net_u16 (portnum);
    1931       10420 :                       return 0;
    1932             :                     }
    1933             :                 }
    1934             :             }
    1935             :         }
    1936             :     }
    1937             : 
    1938             :   /* Totally out of translations to use... */
    1939           7 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
    1940           7 :   return 1;
    1941             : }
    1942             : 
    1943             : static int
    1944           5 : nat44_ei_alloc_range_cb (nat44_ei_address_t *addresses, u32 fib_index,
    1945             :                          u32 thread_index, nat_protocol_t proto,
    1946             :                          ip4_address_t s_addr, ip4_address_t *addr, u16 *port,
    1947             :                          u16 port_per_thread, u32 snat_thread_index)
    1948             : {
    1949           5 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1950           5 :   nat44_ei_address_t *a = addresses;
    1951             :   u16 portnum, ports;
    1952             : 
    1953           5 :   ports = nm->end_port - nm->start_port + 1;
    1954             : 
    1955           5 :   if (!vec_len (addresses))
    1956           0 :     goto exhausted;
    1957             : 
    1958           5 :   if (a->busy_ports[proto] < ports)
    1959             :     {
    1960             :       while (1)
    1961             :         {
    1962           0 :           portnum =
    1963           3 :             nat_random_port (&nm->random_seed, nm->start_port, nm->end_port);
    1964           3 :           if (nat44_ei_port_is_used (a, proto, portnum))
    1965           0 :             continue;
    1966           3 :           nat44_ei_port_get (a, proto, portnum);
    1967           3 :           a->busy_ports[proto]++;
    1968           3 :           *addr = a->addr;
    1969           3 :           *port = clib_host_to_net_u16 (portnum);
    1970           3 :           return 0;
    1971             :         }
    1972             :     }
    1973             : 
    1974           2 : exhausted:
    1975             :   /* Totally out of translations to use... */
    1976           2 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
    1977           2 :   return 1;
    1978             : }
    1979             : 
    1980             : static int
    1981           1 : nat44_ei_alloc_mape_cb (nat44_ei_address_t *addresses, u32 fib_index,
    1982             :                         u32 thread_index, nat_protocol_t proto,
    1983             :                         ip4_address_t s_addr, ip4_address_t *addr, u16 *port,
    1984             :                         u16 port_per_thread, u32 snat_thread_index)
    1985             : {
    1986           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    1987           1 :   nat44_ei_address_t *a = addresses;
    1988             :   u16 m, ports, portnum, A, j;
    1989           1 :   m = 16 - (nm->psid_offset + nm->psid_length);
    1990           1 :   ports = (1 << (16 - nm->psid_length)) - (1 << m);
    1991             : 
    1992           1 :   if (!vec_len (addresses))
    1993           0 :     goto exhausted;
    1994             : 
    1995           1 :   if (a->busy_ports[proto] < ports)
    1996             :     {
    1997             :       while (1)
    1998             :         {
    1999           0 :           A =
    2000           1 :             nat_random_port (&nm->random_seed, 1, pow2_mask (nm->psid_offset));
    2001           1 :           j = nat_random_port (&nm->random_seed, 0, pow2_mask (m));
    2002           1 :           portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m));
    2003           1 :           if (nat44_ei_port_is_used (a, proto, portnum))
    2004           0 :             continue;
    2005           1 :           nat44_ei_port_get (a, proto, portnum);
    2006           1 :           a->busy_ports[proto]++;
    2007           1 :           *addr = a->addr;
    2008           1 :           *port = clib_host_to_net_u16 (portnum);
    2009           1 :           return 0;
    2010             :         }
    2011             :     }
    2012             : 
    2013           0 : exhausted:
    2014             :   /* Totally out of translations to use... */
    2015           0 :   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
    2016           0 :   return 1;
    2017             : }
    2018             : 
    2019             : void
    2020          58 : nat44_ei_set_alloc_default ()
    2021             : {
    2022          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2023             : 
    2024          58 :   nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
    2025          58 :   nm->alloc_addr_and_port = nat44_ei_alloc_default_cb;
    2026          58 : }
    2027             : 
    2028             : void
    2029           1 : nat44_ei_set_alloc_range (u16 start_port, u16 end_port)
    2030             : {
    2031           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2032             : 
    2033           1 :   nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_RANGE;
    2034           1 :   nm->alloc_addr_and_port = nat44_ei_alloc_range_cb;
    2035           1 :   nm->start_port = start_port;
    2036           1 :   nm->end_port = end_port;
    2037           1 : }
    2038             : 
    2039             : void
    2040           1 : nat44_ei_set_alloc_mape (u16 psid, u16 psid_offset, u16 psid_length)
    2041             : {
    2042           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2043             : 
    2044           1 :   nm->addr_and_port_alloc_alg = NAT44_EI_ADDR_AND_PORT_ALLOC_ALG_MAPE;
    2045           1 :   nm->alloc_addr_and_port = nat44_ei_alloc_mape_cb;
    2046           1 :   nm->psid = psid;
    2047           1 :   nm->psid_offset = psid_offset;
    2048           1 :   nm->psid_length = psid_length;
    2049           1 : }
    2050             : 
    2051             : void
    2052       10484 : nat44_ei_delete_session (nat44_ei_main_t *nm, nat44_ei_session_t *ses,
    2053             :                          u32 thread_index)
    2054             : {
    2055       10484 :   nat44_ei_main_per_thread_data_t *tnm =
    2056       10484 :     vec_elt_at_index (nm->per_thread_data, thread_index);
    2057             :   clib_bihash_kv_8_8_t kv, value;
    2058             :   nat44_ei_user_t *u;
    2059       10484 :   const nat44_ei_user_key_t u_key = { .addr = ses->in2out.addr,
    2060       10484 :                                       .fib_index = ses->in2out.fib_index };
    2061       10484 :   const u8 u_static = nat44_ei_is_session_static (ses);
    2062             : 
    2063       10484 :   clib_dlist_remove (tnm->list_pool, ses->per_user_index);
    2064       10484 :   pool_put_index (tnm->list_pool, ses->per_user_index);
    2065             : 
    2066       10484 :   pool_put (tnm->sessions, ses);
    2067       10484 :   vlib_set_simple_counter (&nm->total_sessions, thread_index, 0,
    2068       10484 :                            pool_elts (tnm->sessions));
    2069             : 
    2070       10484 :   kv.key = u_key.as_u64;
    2071       10484 :   if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    2072             :     {
    2073       10484 :       u = pool_elt_at_index (tnm->users, value.value);
    2074       10484 :       if (u_static)
    2075          49 :         u->nstaticsessions--;
    2076             :       else
    2077       10435 :         u->nsessions--;
    2078             : 
    2079       10484 :       nat44_ei_delete_user_with_no_session (nm, u, thread_index);
    2080             :     }
    2081       10484 : }
    2082             : 
    2083             : int
    2084           4 : nat44_ei_del_session (nat44_ei_main_t *nm, ip4_address_t *addr, u16 port,
    2085             :                       nat_protocol_t proto, u32 vrf_id, int is_in)
    2086             : {
    2087             :   nat44_ei_main_per_thread_data_t *tnm;
    2088             :   clib_bihash_kv_8_8_t kv, value;
    2089             :   u32 fib_index;
    2090             :   nat44_ei_session_t *s;
    2091             :   clib_bihash_8_8_t *t;
    2092             : 
    2093           4 :   fail_if_disabled ();
    2094             : 
    2095           4 :   fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
    2096           4 :   init_nat_k (&kv, *addr, port, fib_index, proto);
    2097           4 :   t = is_in ? &nm->in2out : &nm->out2in;
    2098           4 :   if (!clib_bihash_search_8_8 (t, &kv, &value))
    2099             :     {
    2100             :       // this is called from API/CLI, so the world is stopped here
    2101             :       // it's safe to manipulate arbitrary per-thread data
    2102           4 :       u32 thread_index = nat_value_get_thread_index (&value);
    2103           4 :       tnm = vec_elt_at_index (nm->per_thread_data, thread_index);
    2104           4 :       u32 session_index = nat_value_get_session_index (&value);
    2105           4 :       if (pool_is_free_index (tnm->sessions, session_index))
    2106           0 :         return VNET_API_ERROR_UNSPECIFIED;
    2107             : 
    2108           4 :       s = pool_elt_at_index (tnm->sessions, session_index);
    2109           4 :       nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data, 0);
    2110           4 :       nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
    2111           4 :       return 0;
    2112             :     }
    2113             : 
    2114           0 :   return VNET_API_ERROR_NO_SUCH_ENTRY;
    2115             : }
    2116             : 
    2117             : void
    2118         330 : nat44_ei_add_del_addr_to_fib (ip4_address_t *addr, u8 p_len, u32 sw_if_index,
    2119             :                               int is_add)
    2120             : {
    2121         330 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2122         330 :   fib_prefix_t prefix = {
    2123             :     .fp_len = p_len,
    2124             :     .fp_proto = FIB_PROTOCOL_IP4,
    2125             :     .fp_addr = {
    2126         330 :                 .ip4.as_u32 = addr->as_u32,
    2127             :                 },
    2128             :   };
    2129         330 :   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
    2130             : 
    2131         330 :   if (is_add)
    2132             :     {
    2133         165 :       fib_table_entry_update_one_path (fib_index, &prefix, nm->fib_src_low,
    2134             :                                        (FIB_ENTRY_FLAG_CONNECTED |
    2135             :                                         FIB_ENTRY_FLAG_LOCAL |
    2136             :                                         FIB_ENTRY_FLAG_EXCLUSIVE),
    2137             :                                        DPO_PROTO_IP4, NULL, sw_if_index, ~0, 1,
    2138             :                                        NULL, FIB_ROUTE_PATH_FLAG_NONE);
    2139             :     }
    2140             :   else
    2141             :     {
    2142         165 :       fib_table_entry_delete (fib_index, &prefix, nm->fib_src_low);
    2143             :     }
    2144         330 : }
    2145             : 
    2146             : int
    2147          16 : nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
    2148             : {
    2149          16 :   u32 ti = nat44_ei_get_thread_idx_by_port (port);
    2150          16 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2151          16 :   nat44_ei_address_t *a = 0;
    2152             :   int i;
    2153             : 
    2154          16 :   for (i = 0; i < vec_len (nm->addresses); i++)
    2155             :     {
    2156          16 :       a = nm->addresses + i;
    2157             : 
    2158          16 :       if (a->addr.as_u32 != addr.as_u32)
    2159           0 :         continue;
    2160             : 
    2161          16 :       if (nat44_ei_port_is_used (a, proto, port))
    2162           0 :         continue;
    2163             : 
    2164          16 :       nat44_ei_port_get (a, proto, port);
    2165          16 :       if (port > 1024)
    2166             :         {
    2167          16 :           a->busy_ports[proto]++;
    2168          16 :           a->busy_ports_per_thread[proto][ti]++;
    2169             :         }
    2170          16 :       return 0;
    2171             :     }
    2172             : 
    2173           0 :   return 1;
    2174             : }
    2175             : 
    2176             : int
    2177          16 : nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
    2178             : {
    2179          16 :   u32 ti = nat44_ei_get_thread_idx_by_port (port);
    2180          16 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2181          16 :   nat44_ei_address_t *a = 0;
    2182             :   int i;
    2183             : 
    2184          16 :   for (i = 0; i < vec_len (nm->addresses); i++)
    2185             :     {
    2186          16 :       a = nm->addresses + i;
    2187             : 
    2188          16 :       if (a->addr.as_u32 != addr.as_u32)
    2189           0 :         continue;
    2190             : 
    2191          16 :       nat44_ei_port_put (a, proto, port);
    2192          16 :       if (port > 1024)
    2193             :         {
    2194          16 :           a->busy_ports[proto]--;
    2195          16 :           a->busy_ports_per_thread[proto][ti]--;
    2196             :         }
    2197          16 :       return 0;
    2198             :     }
    2199             : 
    2200           0 :   return 1;
    2201             : }
    2202             : 
    2203             : void
    2204           2 : nat44_ei_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
    2205             :                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
    2206             :                              u32 flags, ip4_address_t pool_addr, u8 *tag)
    2207             : {
    2208             :   nat44_ei_static_map_resolve_t *rp;
    2209           2 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2210             : 
    2211           2 :   vec_add2 (nm->to_resolve, rp, 1);
    2212           2 :   rp->l_addr.as_u32 = l_addr.as_u32;
    2213           2 :   rp->l_port = l_port;
    2214           2 :   rp->e_port = e_port;
    2215           2 :   rp->sw_if_index = sw_if_index;
    2216           2 :   rp->vrf_id = vrf_id;
    2217           2 :   rp->proto = proto;
    2218           2 :   rp->flags = flags;
    2219           2 :   rp->pool_addr = pool_addr;
    2220           2 :   rp->tag = vec_dup (tag);
    2221           2 : }
    2222             : 
    2223             : int
    2224           3 : nat44_ei_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
    2225             :                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
    2226             :                              u32 flags, int *out)
    2227             : {
    2228             :   nat44_ei_static_map_resolve_t *rp;
    2229           3 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2230             :   int i;
    2231             : 
    2232           3 :   for (i = 0; i < vec_len (nm->to_resolve); i++)
    2233             :     {
    2234           1 :       rp = nm->to_resolve + i;
    2235             : 
    2236           1 :       if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id)
    2237             :         {
    2238           1 :           if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags))
    2239             :             {
    2240           0 :               if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
    2241             :                 {
    2242           0 :                   if (rp->e_port != e_port || rp->proto != proto)
    2243             :                     {
    2244           0 :                       continue;
    2245             :                     }
    2246             :                 }
    2247             :             }
    2248           1 :           else if (rp->l_addr.as_u32 == l_addr.as_u32)
    2249             :             {
    2250           1 :               if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
    2251             :                 {
    2252           0 :                   if (rp->l_port != l_port || rp->e_port != e_port ||
    2253           0 :                       rp->proto != proto)
    2254             :                     {
    2255           0 :                       continue;
    2256             :                     }
    2257             :                 }
    2258             :             }
    2259             :           else
    2260             :             {
    2261           0 :               continue;
    2262             :             }
    2263           1 :           if (out)
    2264             :             {
    2265           1 :               *out = i;
    2266             :             }
    2267           1 :           return 0;
    2268             :         }
    2269             :     }
    2270           2 :   return 1;
    2271             : }
    2272             : 
    2273             : int
    2274           1 : nat44_ei_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
    2275             :                              nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
    2276             :                              u32 flags)
    2277             : {
    2278           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2279             :   int i;
    2280           1 :   if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
    2281             :                                     sw_if_index, flags, &i))
    2282             :     {
    2283           1 :       vec_del1 (nm->to_resolve, i);
    2284           1 :       return 0;
    2285             :     }
    2286           0 :   return 1;
    2287             : }
    2288             : 
    2289             : void
    2290          38 : delete_matching_dynamic_sessions (const nat44_ei_static_mapping_t *m,
    2291             :                                   u32 worker_index)
    2292             : {
    2293          38 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2294             :   clib_bihash_kv_8_8_t kv, value;
    2295             :   nat44_ei_session_t *s;
    2296             :   nat44_ei_user_key_t u_key;
    2297             :   nat44_ei_user_t *u;
    2298             :   nat44_ei_main_per_thread_data_t *tnm;
    2299             :   dlist_elt_t *head, *elt;
    2300             :   u32 elt_index, head_index;
    2301             :   u32 ses_index;
    2302             :   u64 user_index;
    2303             : 
    2304          38 :   if (nm->static_mapping_only)
    2305           0 :     return;
    2306             : 
    2307          38 :   tnm = vec_elt_at_index (nm->per_thread_data, worker_index);
    2308             : 
    2309          38 :   u_key.addr = m->local_addr;
    2310          38 :   u_key.fib_index = m->fib_index;
    2311          38 :   kv.key = u_key.as_u64;
    2312          38 :   if (!clib_bihash_search_8_8 (&tnm->user_hash, &kv, &value))
    2313             :     {
    2314           1 :       user_index = value.value;
    2315           1 :       u = pool_elt_at_index (tnm->users, user_index);
    2316           1 :       if (u->nsessions)
    2317             :         {
    2318           1 :           head_index = u->sessions_per_user_list_head_index;
    2319           1 :           head = pool_elt_at_index (tnm->list_pool, head_index);
    2320           1 :           elt_index = head->next;
    2321           1 :           elt = pool_elt_at_index (tnm->list_pool, elt_index);
    2322           1 :           ses_index = elt->value;
    2323           4 :           while (ses_index != ~0)
    2324             :             {
    2325           3 :               s = pool_elt_at_index (tnm->sessions, ses_index);
    2326           3 :               elt = pool_elt_at_index (tnm->list_pool, elt->next);
    2327           3 :               ses_index = elt->value;
    2328             : 
    2329           3 :               if (nat44_ei_is_session_static (s))
    2330           0 :                 continue;
    2331             : 
    2332           3 :               if (!is_sm_addr_only (m->flags) &&
    2333           0 :                   s->in2out.port != m->local_port)
    2334           0 :                 continue;
    2335             : 
    2336           3 :               nat44_ei_free_session_data_v2 (nm, s, tnm - nm->per_thread_data,
    2337             :                                              0);
    2338           3 :               nat44_ei_delete_session (nm, s, tnm - nm->per_thread_data);
    2339             : 
    2340           3 :               if (!is_sm_addr_only (m->flags))
    2341           0 :                 break;
    2342             :             }
    2343             :         }
    2344             :     }
    2345             : }
    2346             : 
    2347             : int
    2348          38 : nat44_ei_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
    2349             :                              u16 l_port, u16 e_port, nat_protocol_t proto,
    2350             :                              u32 vrf_id, u32 sw_if_index, u32 flags,
    2351             :                              ip4_address_t pool_addr, u8 *tag)
    2352             : 
    2353             : {
    2354          38 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2355             : 
    2356          38 :   if (is_sm_switch_address (flags))
    2357             :     {
    2358           2 :       if (!nat44_ei_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
    2359             :                                         sw_if_index, flags, 0))
    2360             :         {
    2361           0 :           return VNET_API_ERROR_VALUE_EXIST;
    2362             :         }
    2363             : 
    2364           2 :       nat44_ei_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
    2365             :                                    sw_if_index, flags, pool_addr, tag);
    2366             : 
    2367             :       ip4_address_t *first_int_addr =
    2368           2 :         ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
    2369           2 :       if (!first_int_addr)
    2370             :         {
    2371             :           // dhcp resolution required
    2372           2 :           return 0;
    2373             :         }
    2374             : 
    2375           0 :       e_addr.as_u32 = first_int_addr->as_u32;
    2376             :     }
    2377             : 
    2378          36 :   return nat44_ei_add_static_mapping_internal (l_addr, e_addr, l_port, e_port,
    2379             :                                                proto, vrf_id, sw_if_index,
    2380             :                                                flags, pool_addr, tag);
    2381             : }
    2382             : 
    2383             : int
    2384           3 : nat44_ei_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
    2385             :                              u16 l_port, u16 e_port, nat_protocol_t proto,
    2386             :                              u32 vrf_id, u32 sw_if_index, u32 flags)
    2387             : {
    2388           3 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2389             : 
    2390           3 :   if (is_sm_switch_address (flags))
    2391             :     {
    2392             : 
    2393           1 :       if (nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
    2394             :                                        sw_if_index, flags))
    2395             :         {
    2396           0 :           return VNET_API_ERROR_NO_SUCH_ENTRY;
    2397             :         }
    2398             : 
    2399             :       ip4_address_t *first_int_addr =
    2400           1 :         ip4_interface_first_address (nm->ip4_main, sw_if_index, 0);
    2401           1 :       if (!first_int_addr)
    2402             :         {
    2403             :           // dhcp resolution required
    2404           0 :           return 0;
    2405             :         }
    2406             : 
    2407           1 :       e_addr.as_u32 = first_int_addr->as_u32;
    2408             :     }
    2409             : 
    2410           3 :   return nat44_ei_del_static_mapping_internal (
    2411             :     l_addr, e_addr, l_port, e_port, proto, vrf_id, sw_if_index, flags);
    2412             : }
    2413             : 
    2414             : static int
    2415          39 : nat44_ei_add_static_mapping_internal (ip4_address_t l_addr,
    2416             :                                       ip4_address_t e_addr, u16 l_port,
    2417             :                                       u16 e_port, nat_protocol_t proto,
    2418             :                                       u32 vrf_id, u32 sw_if_index, u32 flags,
    2419             :                                       ip4_address_t pool_addr, u8 *tag)
    2420             : {
    2421          39 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2422             :   clib_bihash_kv_8_8_t kv, value;
    2423             :   nat44_ei_lb_addr_port_t *local;
    2424             :   nat44_ei_static_mapping_t *m;
    2425          39 :   u32 fib_index = ~0;
    2426             :   u32 worker_index;
    2427             : 
    2428          39 :   fail_if_disabled ();
    2429             : 
    2430          39 :   if (is_sm_addr_only (flags))
    2431             :     {
    2432          23 :       e_port = l_port = proto = 0;
    2433             :     }
    2434             : 
    2435          39 :   if (is_sm_identity_nat (flags))
    2436             :     {
    2437           3 :       l_port = e_port;
    2438           3 :       l_addr.as_u32 = e_addr.as_u32;
    2439             :     }
    2440             : 
    2441             :   // fib index 0
    2442          39 :   init_nat_k (&kv, e_addr, e_port, 0, proto);
    2443             : 
    2444          39 :   if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
    2445             :     {
    2446           1 :       m = pool_elt_at_index (nm->static_mappings, value.value);
    2447           1 :       if (!is_sm_identity_nat (m->flags))
    2448             :         {
    2449           0 :           return VNET_API_ERROR_VALUE_EXIST;
    2450             :         }
    2451             : 
    2452             :       // case:
    2453             :       // adding local identity nat record for different vrf table
    2454           2 :       pool_foreach (local, m->locals)
    2455             :         {
    2456           1 :           if (local->vrf_id == vrf_id)
    2457             :             {
    2458           0 :               return VNET_API_ERROR_VALUE_EXIST;
    2459             :             }
    2460             :         }
    2461             : 
    2462           1 :       pool_get (m->locals, local);
    2463             : 
    2464           1 :       local->vrf_id = vrf_id;
    2465           2 :       local->fib_index = fib_table_find_or_create_and_lock (
    2466           1 :         FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
    2467             : 
    2468           1 :       init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
    2469           1 :                    m->proto, 0, m - nm->static_mappings);
    2470           1 :       clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
    2471             : 
    2472           1 :       return 0;
    2473             :     }
    2474             : 
    2475          38 :   if (vrf_id != ~0)
    2476             :     {
    2477          38 :       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
    2478          38 :                                                      nm->fib_src_low);
    2479             :     }
    2480             :   else
    2481             :     {
    2482             :       // fallback to default vrf
    2483           0 :       vrf_id = nm->inside_vrf_id;
    2484           0 :       fib_index = nm->inside_fib_index;
    2485           0 :       fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
    2486             :     }
    2487             : 
    2488          38 :   if (!is_sm_identity_nat (flags))
    2489             :     {
    2490          36 :       init_nat_k (&kv, l_addr, l_port, fib_index, proto);
    2491          36 :       if (!clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
    2492             :         {
    2493           0 :           return VNET_API_ERROR_VALUE_EXIST;
    2494             :         }
    2495             :     }
    2496             : 
    2497          38 :   if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
    2498             :     {
    2499          16 :       if (nat44_ei_reserve_port (e_addr, e_port, proto))
    2500             :         {
    2501             :           // remove resolve record
    2502           0 :           if ((is_sm_switch_address (flags)) && !is_sm_identity_nat (flags))
    2503             :             {
    2504           0 :               nat44_ei_del_resolve_record (l_addr, l_port, e_port, proto,
    2505             :                                            vrf_id, sw_if_index, flags);
    2506             :             }
    2507           0 :           return VNET_API_ERROR_NO_SUCH_ENTRY;
    2508             :         }
    2509             :     }
    2510             : 
    2511          38 :   pool_get (nm->static_mappings, m);
    2512          38 :   clib_memset (m, 0, sizeof (*m));
    2513             : 
    2514          38 :   m->flags = flags;
    2515          38 :   m->local_addr = l_addr;
    2516          38 :   m->external_addr = e_addr;
    2517             : 
    2518          38 :   m->tag = vec_dup (tag);
    2519             : 
    2520          38 :   if (!is_sm_addr_only (flags))
    2521             :     {
    2522          16 :       m->local_port = l_port;
    2523          16 :       m->external_port = e_port;
    2524          16 :       m->proto = proto;
    2525             :     }
    2526             : 
    2527          38 :   if (is_sm_identity_nat (flags))
    2528             :     {
    2529           2 :       pool_get (m->locals, local);
    2530             : 
    2531           2 :       local->vrf_id = vrf_id;
    2532           2 :       local->fib_index = fib_index;
    2533             :     }
    2534             :   else
    2535             :     {
    2536          36 :       m->vrf_id = vrf_id;
    2537          36 :       m->fib_index = fib_index;
    2538             :     }
    2539             : 
    2540          38 :   init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
    2541          38 :                m - nm->static_mappings);
    2542          38 :   clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 1);
    2543             : 
    2544          38 :   init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
    2545          38 :                m - nm->static_mappings);
    2546          38 :   clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 1);
    2547             : 
    2548          38 :   if (nm->num_workers > 1)
    2549             :     {
    2550             :       // store worker index for this record
    2551           3 :       ip4_header_t ip = {
    2552           3 :         .src_address = m->local_addr,
    2553             :       };
    2554           3 :       worker_index = nat44_ei_get_in2out_worker_index (&ip, m->fib_index, 0);
    2555           3 :       vec_add1 (m->workers, worker_index);
    2556             :     }
    2557             :   else
    2558             :     {
    2559          35 :       worker_index = nm->num_workers;
    2560             :     }
    2561          38 :   delete_matching_dynamic_sessions (m, worker_index);
    2562             : 
    2563          38 :   if (is_sm_addr_only (flags))
    2564             :     {
    2565          22 :       nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 1);
    2566             :     }
    2567             : 
    2568          38 :   return 0;
    2569             : }
    2570             : 
    2571             : static int
    2572          38 : nat44_ei_del_static_mapping_internal (ip4_address_t l_addr,
    2573             :                                       ip4_address_t e_addr, u16 l_port,
    2574             :                                       u16 e_port, nat_protocol_t proto,
    2575             :                                       u32 vrf_id, u32 sw_if_index, u32 flags)
    2576             : {
    2577             :   nat44_ei_main_per_thread_data_t *tnm;
    2578          38 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2579             :   clib_bihash_kv_8_8_t kv, value;
    2580             :   nat44_ei_lb_addr_port_t *local;
    2581             :   nat44_ei_static_mapping_t *m;
    2582          38 :   u32 fib_index = ~0;
    2583             :   nat44_ei_user_key_t u_key;
    2584             : 
    2585          38 :   fail_if_disabled ();
    2586             : 
    2587          38 :   if (is_sm_addr_only (flags))
    2588             :     {
    2589          22 :       e_port = l_port = proto = 0;
    2590             :     }
    2591             : 
    2592          38 :   if (is_sm_identity_nat (flags))
    2593             :     {
    2594           2 :       l_port = e_port;
    2595           2 :       l_addr.as_u32 = e_addr.as_u32;
    2596             :     }
    2597             : 
    2598             :   // fib index 0
    2599          38 :   init_nat_k (&kv, e_addr, e_port, 0, proto);
    2600             : 
    2601          38 :   if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
    2602             :     {
    2603           0 :       if (is_sm_switch_address (flags))
    2604             :         {
    2605           0 :           return 0;
    2606             :         }
    2607           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
    2608             :     }
    2609             : 
    2610          38 :   m = pool_elt_at_index (nm->static_mappings, value.value);
    2611             : 
    2612          38 :   if (is_sm_identity_nat (flags))
    2613             :     {
    2614           2 :       u8 found = 0;
    2615             : 
    2616           2 :       if (vrf_id == ~0)
    2617             :         {
    2618           0 :           vrf_id = nm->inside_vrf_id;
    2619             :         }
    2620             : 
    2621           5 :       pool_foreach (local, m->locals)
    2622             :         {
    2623           3 :           if (local->vrf_id == vrf_id)
    2624             :             {
    2625           2 :               local = pool_elt_at_index (m->locals, local - m->locals);
    2626           2 :               fib_index = local->fib_index;
    2627           2 :               pool_put (m->locals, local);
    2628           2 :               found = 1;
    2629             :             }
    2630             :         }
    2631           2 :       if (!found)
    2632             :         {
    2633           0 :           return VNET_API_ERROR_NO_SUCH_ENTRY;
    2634             :         }
    2635             :     }
    2636             :   else
    2637             :     {
    2638          36 :       fib_index = m->fib_index;
    2639             :     }
    2640             : 
    2641          38 :   if (!(is_sm_addr_only (flags) || nm->static_mapping_only))
    2642             :     {
    2643          16 :       if (nat44_ei_free_port (e_addr, e_port, proto))
    2644             :         {
    2645           0 :           return VNET_API_ERROR_INVALID_VALUE;
    2646             :         }
    2647             :     }
    2648             : 
    2649          38 :   init_nat_k (&kv, l_addr, l_port, fib_index, proto);
    2650          38 :   clib_bihash_add_del_8_8 (&nm->static_mapping_by_local, &kv, 0);
    2651             : 
    2652          38 :   if (!nm->static_mapping_only || nm->static_mapping_connection_tracking)
    2653             :     {
    2654             :       // delete sessions for static mapping
    2655          38 :       if (nm->num_workers > 1)
    2656           3 :         tnm = vec_elt_at_index (nm->per_thread_data, m->workers[0]);
    2657             :       else
    2658          35 :         tnm = vec_elt_at_index (nm->per_thread_data, nm->num_workers);
    2659             : 
    2660          38 :       u_key.addr = m->local_addr;
    2661          38 :       u_key.fib_index = fib_index;
    2662          38 :       kv.key = u_key.as_u64;
    2663          38 :       nat44_ei_static_mapping_del_sessions (
    2664          38 :         nm, tnm, u_key, is_sm_addr_only (flags), e_addr, e_port);
    2665             :     }
    2666             : 
    2667          38 :   fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
    2668             : 
    2669          38 :   if (!pool_elts (m->locals))
    2670             :     {
    2671             :       // this is last record remove all required stuff
    2672             :       // fib_index 0
    2673          37 :       init_nat_k (&kv, e_addr, e_port, 0, proto);
    2674          37 :       clib_bihash_add_del_8_8 (&nm->static_mapping_by_external, &kv, 0);
    2675             : 
    2676          37 :       vec_free (m->tag);
    2677          37 :       vec_free (m->workers);
    2678          37 :       pool_put (nm->static_mappings, m);
    2679             : 
    2680          37 :       if (is_sm_addr_only (flags) && !is_sm_identity_nat (flags))
    2681             :         {
    2682          21 :           nat44_ei_add_del_addr_to_fib_foreach_out_if (&e_addr, 0);
    2683             :         }
    2684             :     }
    2685             : 
    2686          38 :   return 0;
    2687             : }
    2688             : 
    2689             : int
    2690       21013 : nat44_ei_static_mapping_match (ip4_address_t match_addr, u16 match_port,
    2691             :                                u32 match_fib_index,
    2692             :                                nat_protocol_t match_protocol,
    2693             :                                ip4_address_t *mapping_addr, u16 *mapping_port,
    2694             :                                u32 *mapping_fib_index, u8 by_external,
    2695             :                                u8 *is_addr_only, u8 *is_identity_nat)
    2696             : {
    2697       21013 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2698             :   clib_bihash_kv_8_8_t kv, value;
    2699             :   nat44_ei_static_mapping_t *m;
    2700             :   u16 port;
    2701             : 
    2702       21013 :   if (by_external)
    2703             :     {
    2704       10536 :       init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
    2705       10536 :       if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
    2706             :                                   &value))
    2707             :         {
    2708             :           /* Try address only mapping */
    2709       10520 :           init_nat_k (&kv, match_addr, 0, 0, 0);
    2710       10520 :           if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv,
    2711             :                                       &value))
    2712       10478 :             return 1;
    2713             :         }
    2714          58 :       m = pool_elt_at_index (nm->static_mappings, value.value);
    2715             : 
    2716          58 :       *mapping_fib_index = m->fib_index;
    2717          58 :       *mapping_addr = m->local_addr;
    2718          58 :       port = m->local_port;
    2719             :     }
    2720             :   else
    2721             :     {
    2722       10477 :       init_nat_k (&kv, match_addr, match_port, match_fib_index,
    2723             :                   match_protocol);
    2724       10477 :       if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv, &value))
    2725             :         {
    2726             :           /* Try address only mapping */
    2727       10471 :           init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
    2728       10471 :           if (clib_bihash_search_8_8 (&nm->static_mapping_by_local, &kv,
    2729             :                                       &value))
    2730       10445 :             return 1;
    2731             :         }
    2732          32 :       m = pool_elt_at_index (nm->static_mappings, value.value);
    2733             : 
    2734          32 :       *mapping_fib_index = nm->outside_fib_index;
    2735          32 :       *mapping_addr = m->external_addr;
    2736          32 :       port = m->external_port;
    2737             :     }
    2738             : 
    2739             :   /* Address only mapping doesn't change port */
    2740          90 :   if (is_sm_addr_only (m->flags))
    2741          68 :     *mapping_port = match_port;
    2742             :   else
    2743          22 :     *mapping_port = port;
    2744             : 
    2745          90 :   if (PREDICT_FALSE (is_addr_only != 0))
    2746           6 :     *is_addr_only = is_sm_addr_only (m->flags);
    2747             : 
    2748          90 :   if (PREDICT_FALSE (is_identity_nat != 0))
    2749          50 :     *is_identity_nat = is_sm_identity_nat (m->flags);
    2750             : 
    2751          90 :   return 0;
    2752             : }
    2753             : 
    2754             : static void
    2755          63 : nat44_ei_worker_db_free (nat44_ei_main_per_thread_data_t *tnm)
    2756             : {
    2757          63 :   pool_free (tnm->list_pool);
    2758          63 :   pool_free (tnm->lru_pool);
    2759          63 :   pool_free (tnm->sessions);
    2760          63 :   pool_free (tnm->users);
    2761             : 
    2762          63 :   clib_bihash_free_8_8 (&tnm->user_hash);
    2763          63 : }
    2764             : 
    2765             : u8 *
    2766       20963 : format_nat44_ei_key (u8 *s, va_list *args)
    2767             : {
    2768       20963 :   u64 key = va_arg (*args, u64);
    2769             : 
    2770             :   ip4_address_t addr;
    2771             :   u16 port;
    2772             :   nat_protocol_t protocol;
    2773             :   u32 fib_index;
    2774             : 
    2775       20963 :   split_nat_key (key, &addr, &port, &fib_index, &protocol);
    2776             : 
    2777       20963 :   s = format (s, "%U proto %U port %d fib %d", format_ip4_address, &addr,
    2778       20963 :               format_nat_protocol, protocol, clib_net_to_host_u16 (port),
    2779             :               fib_index);
    2780       20963 :   return s;
    2781             : }
    2782             : 
    2783             : u8 *
    2784       10384 : format_nat44_ei_user_kvp (u8 *s, va_list *args)
    2785             : {
    2786       10384 :   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
    2787             :   nat44_ei_user_key_t k;
    2788             : 
    2789       10384 :   k.as_u64 = v->key;
    2790             : 
    2791       10384 :   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
    2792             :               k.fib_index, v->value);
    2793             : 
    2794       10384 :   return s;
    2795             : }
    2796             : 
    2797             : u8 *
    2798       20902 : format_nat44_ei_session_kvp (u8 *s, va_list *args)
    2799             : {
    2800       20902 :   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
    2801             : 
    2802       20902 :   s = format (s, "%U thread-index %llu session-index %llu",
    2803             :               format_nat44_ei_key, v->key, nat_value_get_thread_index (v),
    2804             :               nat_value_get_session_index (v));
    2805             : 
    2806       20902 :   return s;
    2807             : }
    2808             : 
    2809             : u8 *
    2810          61 : format_nat44_ei_static_mapping_kvp (u8 *s, va_list *args)
    2811             : {
    2812          61 :   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
    2813             : 
    2814          61 :   s = format (s, "%U static-mapping-index %llu", format_nat44_ei_key, v->key,
    2815             :               v->value);
    2816             : 
    2817          61 :   return s;
    2818             : }
    2819             : 
    2820             : static void
    2821          63 : nat44_ei_worker_db_init (nat44_ei_main_per_thread_data_t *tnm,
    2822             :                          u32 translations, u32 translation_buckets,
    2823             :                          u32 user_buckets)
    2824             : {
    2825             :   dlist_elt_t *head;
    2826             : 
    2827          63 :   pool_alloc (tnm->list_pool, translations);
    2828          63 :   pool_alloc (tnm->lru_pool, translations);
    2829          63 :   pool_alloc (tnm->sessions, translations);
    2830             : 
    2831          63 :   clib_bihash_init_8_8 (&tnm->user_hash, "users", user_buckets, 0);
    2832             : 
    2833          63 :   clib_bihash_set_kvp_format_fn_8_8 (&tnm->user_hash,
    2834             :                                      format_nat44_ei_user_kvp);
    2835             : 
    2836          63 :   pool_get (tnm->lru_pool, head);
    2837          63 :   tnm->tcp_trans_lru_head_index = head - tnm->lru_pool;
    2838          63 :   clib_dlist_init (tnm->lru_pool, tnm->tcp_trans_lru_head_index);
    2839             : 
    2840          63 :   pool_get (tnm->lru_pool, head);
    2841          63 :   tnm->tcp_estab_lru_head_index = head - tnm->lru_pool;
    2842          63 :   clib_dlist_init (tnm->lru_pool, tnm->tcp_estab_lru_head_index);
    2843             : 
    2844          63 :   pool_get (tnm->lru_pool, head);
    2845          63 :   tnm->udp_lru_head_index = head - tnm->lru_pool;
    2846          63 :   clib_dlist_init (tnm->lru_pool, tnm->udp_lru_head_index);
    2847             : 
    2848          63 :   pool_get (tnm->lru_pool, head);
    2849          63 :   tnm->icmp_lru_head_index = head - tnm->lru_pool;
    2850          63 :   clib_dlist_init (tnm->lru_pool, tnm->icmp_lru_head_index);
    2851             : 
    2852          63 :   pool_get (tnm->lru_pool, head);
    2853          63 :   tnm->unk_proto_lru_head_index = head - tnm->lru_pool;
    2854          63 :   clib_dlist_init (tnm->lru_pool, tnm->unk_proto_lru_head_index);
    2855          63 : }
    2856             : 
    2857             : static void
    2858          58 : nat44_ei_db_init (u32 translations, u32 translation_buckets, u32 user_buckets)
    2859             : {
    2860          58 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2861             :   nat44_ei_main_per_thread_data_t *tnm;
    2862             : 
    2863          58 :   u32 static_mapping_buckets = 1024;
    2864          58 :   u32 static_mapping_memory_size = 64 << 20;
    2865             : 
    2866          58 :   clib_bihash_init_8_8 (&nm->static_mapping_by_local,
    2867             :                         "static_mapping_by_local", static_mapping_buckets,
    2868             :                         static_mapping_memory_size);
    2869          58 :   clib_bihash_init_8_8 (&nm->static_mapping_by_external,
    2870             :                         "static_mapping_by_external", static_mapping_buckets,
    2871             :                         static_mapping_memory_size);
    2872          58 :   clib_bihash_set_kvp_format_fn_8_8 (&nm->static_mapping_by_local,
    2873             :                                      format_nat44_ei_static_mapping_kvp);
    2874          58 :   clib_bihash_set_kvp_format_fn_8_8 (&nm->static_mapping_by_external,
    2875             :                                      format_nat44_ei_static_mapping_kvp);
    2876             : 
    2877          58 :   if (nm->pat)
    2878             :     {
    2879          58 :       clib_bihash_init_8_8 (&nm->in2out, "in2out", translation_buckets, 0);
    2880          58 :       clib_bihash_init_8_8 (&nm->out2in, "out2in", translation_buckets, 0);
    2881          58 :       clib_bihash_set_kvp_format_fn_8_8 (&nm->in2out,
    2882             :                                          format_nat44_ei_session_kvp);
    2883          58 :       clib_bihash_set_kvp_format_fn_8_8 (&nm->out2in,
    2884             :                                          format_nat44_ei_session_kvp);
    2885         120 :       vec_foreach (tnm, nm->per_thread_data)
    2886             :         {
    2887          62 :           nat44_ei_worker_db_init (tnm, translations, translation_buckets,
    2888             :                                    user_buckets);
    2889             :         }
    2890             :     }
    2891          58 : }
    2892             : 
    2893             : void
    2894           1 : nat44_ei_sessions_clear ()
    2895             : {
    2896           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2897             :   nat44_ei_main_per_thread_data_t *tnm;
    2898             : 
    2899           1 :   if (nm->pat)
    2900             :     {
    2901           1 :       clib_bihash_free_8_8 (&nm->in2out);
    2902           1 :       clib_bihash_free_8_8 (&nm->out2in);
    2903           1 :       clib_bihash_init_8_8 (&nm->in2out, "in2out", nm->translation_buckets, 0);
    2904           1 :       clib_bihash_init_8_8 (&nm->out2in, "out2in", nm->translation_buckets, 0);
    2905           1 :       clib_bihash_set_kvp_format_fn_8_8 (&nm->in2out,
    2906             :                                          format_nat44_ei_session_kvp);
    2907           1 :       clib_bihash_set_kvp_format_fn_8_8 (&nm->out2in,
    2908             :                                          format_nat44_ei_session_kvp);
    2909           2 :       vec_foreach (tnm, nm->per_thread_data)
    2910             :         {
    2911           1 :           nat44_ei_worker_db_free (tnm);
    2912           1 :           nat44_ei_worker_db_init (tnm, nm->translations,
    2913             :                                    nm->translation_buckets, nm->user_buckets);
    2914             :         }
    2915             :     }
    2916             : 
    2917           1 :   vlib_zero_simple_counter (&nm->total_users, 0);
    2918           1 :   vlib_zero_simple_counter (&nm->total_sessions, 0);
    2919           1 :   vlib_zero_simple_counter (&nm->user_limit_reached, 0);
    2920           1 : }
    2921             : 
    2922             : static void
    2923         946 : nat44_ei_update_outside_fib (ip4_main_t *im, uword opaque, u32 sw_if_index,
    2924             :                              u32 new_fib_index, u32 old_fib_index)
    2925             : {
    2926         946 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2927             :   nat44_ei_outside_fib_t *outside_fib;
    2928             :   nat44_ei_interface_t *i;
    2929         946 :   u8 is_add = 1;
    2930         946 :   u8 match = 0;
    2931             : 
    2932         954 :   if (!nm->enabled || (new_fib_index == old_fib_index) ||
    2933           8 :       (!vec_len (nm->outside_fibs)))
    2934             :     {
    2935         944 :       return;
    2936             :     }
    2937             : 
    2938          11 :   pool_foreach (i, nm->interfaces)
    2939             :     {
    2940           9 :       if (i->sw_if_index == sw_if_index)
    2941             :         {
    2942           4 :           if (!(nat44_ei_interface_is_outside (i)))
    2943           2 :             return;
    2944           2 :           match = 1;
    2945             :         }
    2946             :     }
    2947             : 
    2948           2 :   pool_foreach (i, nm->output_feature_interfaces)
    2949             :     {
    2950           0 :       if (i->sw_if_index == sw_if_index)
    2951             :         {
    2952           0 :           if (!(nat44_ei_interface_is_outside (i)))
    2953           0 :             return;
    2954           0 :           match = 1;
    2955             :         }
    2956             :     }
    2957             : 
    2958           2 :   if (!match)
    2959           0 :     return;
    2960             : 
    2961           2 :   vec_foreach (outside_fib, nm->outside_fibs)
    2962             :     {
    2963           2 :       if (outside_fib->fib_index == old_fib_index)
    2964             :         {
    2965           2 :           outside_fib->refcount--;
    2966           2 :           if (!outside_fib->refcount)
    2967           2 :             vec_del1 (nm->outside_fibs, outside_fib - nm->outside_fibs);
    2968           2 :           break;
    2969             :         }
    2970             :     }
    2971             : 
    2972           3 :   vec_foreach (outside_fib, nm->outside_fibs)
    2973             :     {
    2974           2 :       if (outside_fib->fib_index == new_fib_index)
    2975             :         {
    2976           1 :           outside_fib->refcount++;
    2977           1 :           is_add = 0;
    2978           1 :           break;
    2979             :         }
    2980             :     }
    2981             : 
    2982           2 :   if (is_add)
    2983             :     {
    2984           1 :       vec_add2 (nm->outside_fibs, outside_fib, 1);
    2985           1 :       outside_fib->refcount = 1;
    2986           1 :       outside_fib->fib_index = new_fib_index;
    2987             :     }
    2988             : }
    2989             : 
    2990             : int
    2991         147 : nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id)
    2992             : {
    2993         147 :   nat44_ei_main_t *nm = &nat44_ei_main;
    2994         147 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
    2995             :   nat44_ei_address_t *ap;
    2996             : 
    2997         147 :   fail_if_disabled ();
    2998             : 
    2999             :   /* Check if address already exists */
    3000        5001 :   vec_foreach (ap, nm->addresses)
    3001             :     {
    3002        4854 :       if (ap->addr.as_u32 == addr->as_u32)
    3003             :         {
    3004           0 :           nat44_ei_log_err ("address exist");
    3005           0 :           return VNET_API_ERROR_VALUE_EXIST;
    3006             :         }
    3007             :     }
    3008             : 
    3009         147 :   vec_add2 (nm->addresses, ap, 1);
    3010             : 
    3011         147 :   ap->fib_index = ~0;
    3012         147 :   ap->addr = *addr;
    3013             : 
    3014         147 :   if (vrf_id != ~0)
    3015             :     {
    3016           5 :       ap->fib_index = fib_table_find_or_create_and_lock (
    3017           5 :         FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
    3018             :     }
    3019             : 
    3020             :   nat_protocol_t proto;
    3021         735 :   for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
    3022             :     {
    3023         588 :       ap->busy_port_bitmap[proto] = 0;
    3024         588 :       ap->busy_ports[proto] = 0;
    3025         588 :       ap->busy_ports_per_thread[proto] = 0;
    3026        1192 :       vec_validate_init_empty (ap->busy_ports_per_thread[proto],
    3027             :                                tm->n_vlib_mains - 1, 0);
    3028             :     }
    3029             : 
    3030         147 :     nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1);
    3031             : 
    3032         147 :   return 0;
    3033             : }
    3034             : 
    3035             : int
    3036         147 : nat44_ei_del_address (ip4_address_t addr, u8 delete_sm)
    3037             : {
    3038         147 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3039         147 :   nat44_ei_address_t *a = 0;
    3040             :   nat44_ei_session_t *ses;
    3041         147 :   u32 *ses_to_be_removed = 0, *ses_index;
    3042             :   nat44_ei_main_per_thread_data_t *tnm;
    3043             :   nat44_ei_static_mapping_t *m;
    3044             :   int j;
    3045             : 
    3046         147 :   fail_if_disabled ();
    3047             : 
    3048             :   /* Find SNAT address */
    3049        2548 :   for (j = 0; j < vec_len (nm->addresses); j++)
    3050             :     {
    3051        2548 :       if (nm->addresses[j].addr.as_u32 == addr.as_u32)
    3052             :         {
    3053         147 :           a = nm->addresses + j;
    3054         147 :           break;
    3055             :         }
    3056             :     }
    3057         147 :   if (!a)
    3058             :     {
    3059           0 :       nat44_ei_log_err ("no such address");
    3060           0 :       return VNET_API_ERROR_NO_SUCH_ENTRY;
    3061             :     }
    3062             : 
    3063         147 :   if (delete_sm)
    3064             :     {
    3065           5 :       pool_foreach (m, nm->static_mappings)
    3066             :         {
    3067           2 :           if (m->external_addr.as_u32 == addr.as_u32)
    3068           2 :             nat44_ei_del_static_mapping_internal (
    3069           2 :               m->local_addr, m->external_addr, m->local_port, m->external_port,
    3070             :               m->proto, m->vrf_id, ~0, m->flags);
    3071             :         }
    3072             :     }
    3073             :   else
    3074             :     {
    3075             :       /* Check if address is used in some static mapping */
    3076         144 :       if (nat44_ei_is_address_used_in_static_mapping (addr))
    3077             :         {
    3078           0 :           nat44_ei_log_err ("address used in static mapping");
    3079           0 :           return VNET_API_ERROR_UNSPECIFIED;
    3080             :         }
    3081             :     }
    3082             : 
    3083             :   /* Delete sessions using address */
    3084         147 :   if (a->busy_ports[NAT_PROTOCOL_TCP] || a->busy_ports[NAT_PROTOCOL_UDP] ||
    3085          15 :       a->busy_ports[NAT_PROTOCOL_ICMP])
    3086             :     {
    3087         268 :       vec_foreach (tnm, nm->per_thread_data)
    3088             :         {
    3089       15493 :           pool_foreach (ses, tnm->sessions)
    3090             :             {
    3091       15357 :               if (ses->out2in.addr.as_u32 == addr.as_u32)
    3092             :                 {
    3093       10427 :                   nat44_ei_free_session_data (nm, ses,
    3094       10427 :                                               tnm - nm->per_thread_data, 0);
    3095       10427 :                   vec_add1 (ses_to_be_removed, ses - tnm->sessions);
    3096             :                 }
    3097             :             }
    3098       10563 :           vec_foreach (ses_index, ses_to_be_removed)
    3099             :             {
    3100       10427 :               ses = pool_elt_at_index (tnm->sessions, ses_index[0]);
    3101       10427 :               nat44_ei_delete_session (nm, ses, tnm - nm->per_thread_data);
    3102             :             }
    3103         136 :           vec_free (ses_to_be_removed);
    3104             :         }
    3105             :     }
    3106             : 
    3107         147 :   nat44_ei_add_del_addr_to_fib_foreach_out_if (&addr, 0);
    3108             : 
    3109         147 :   if (a->fib_index != ~0)
    3110             :     {
    3111           5 :       fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
    3112             :     }
    3113             : 
    3114             :   nat_protocol_t proto;
    3115         735 :   for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
    3116             :     {
    3117         588 :       vec_free (a->busy_ports_per_thread[proto]);
    3118             :     }
    3119             : 
    3120         147 :   vec_del1 (nm->addresses, j);
    3121         147 :   return 0;
    3122             : }
    3123             : 
    3124             : int
    3125           4 : nat44_ei_add_interface_address (u32 sw_if_index)
    3126             : {
    3127           4 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3128           4 :   ip4_main_t *ip4_main = nm->ip4_main;
    3129             :   ip4_address_t *first_int_addr;
    3130           4 :   u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
    3131             :   int i;
    3132             : 
    3133           4 :   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
    3134             :     {
    3135           0 :       if (auto_add_sw_if_indices[i] == sw_if_index)
    3136             :         {
    3137           0 :           return VNET_API_ERROR_VALUE_EXIST;
    3138             :         }
    3139             :     }
    3140             : 
    3141             :   /* add to the auto-address list */
    3142           4 :   vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
    3143             : 
    3144             :   // if the address is already bound - or static - add it now
    3145           4 :   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
    3146           4 :   if (first_int_addr)
    3147             :     {
    3148           1 :       (void) nat44_ei_add_address (first_int_addr, ~0);
    3149             :     }
    3150             : 
    3151           4 :   return 0;
    3152             : }
    3153             : 
    3154             : int
    3155           0 : nat44_ei_del_interface_address (u32 sw_if_index)
    3156             : {
    3157           0 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3158           0 :   ip4_main_t *ip4_main = nm->ip4_main;
    3159             :   ip4_address_t *first_int_addr;
    3160             :   nat44_ei_static_map_resolve_t *rp;
    3161           0 :   u32 *indices_to_delete = 0;
    3162             :   int i, j;
    3163           0 :   u32 *auto_add_sw_if_indices = nm->auto_add_sw_if_indices;
    3164             : 
    3165           0 :   fail_if_disabled ();
    3166             : 
    3167           0 :   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
    3168             : 
    3169           0 :   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
    3170             :     {
    3171           0 :       if (auto_add_sw_if_indices[i] == sw_if_index)
    3172             :         {
    3173             :           first_int_addr =
    3174           0 :             ip4_interface_first_address (ip4_main, sw_if_index, 0);
    3175           0 :           if (first_int_addr)
    3176             :             {
    3177           0 :               (void) nat44_ei_del_address (first_int_addr[0], 1);
    3178             :             }
    3179             :           else
    3180             :             {
    3181           0 :               for (j = 0; j < vec_len (nm->to_resolve); j++)
    3182             :                 {
    3183           0 :                   rp = nm->to_resolve + j;
    3184           0 :                   if (rp->sw_if_index == sw_if_index)
    3185             :                     {
    3186           0 :                       vec_add1 (indices_to_delete, j);
    3187             :                     }
    3188             :                 }
    3189           0 :               if (vec_len (indices_to_delete))
    3190             :                 {
    3191           0 :                   for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
    3192             :                     {
    3193           0 :                       vec_del1 (nm->to_resolve, j);
    3194             :                     }
    3195           0 :                   vec_free (indices_to_delete);
    3196             :                 }
    3197             :             }
    3198             : 
    3199           0 :           vec_del1 (nm->auto_add_sw_if_indices, i);
    3200           0 :           return 0;
    3201             :         }
    3202             :     }
    3203           0 :   return VNET_API_ERROR_NO_SUCH_ENTRY;
    3204             : }
    3205             : 
    3206             : static_always_inline int
    3207          23 : is_sw_if_index_reg_for_auto_resolve (u32 *sw_if_indices, u32 sw_if_index)
    3208             : {
    3209             :   u32 *i;
    3210          23 :   vec_foreach (i, sw_if_indices)
    3211             :     {
    3212           7 :       if (*i == sw_if_index)
    3213             :         {
    3214           7 :           return 1;
    3215             :         }
    3216             :     }
    3217          16 :   return 0;
    3218             : }
    3219             : 
    3220             : static void
    3221        4838 : nat44_ei_ip4_add_del_interface_address_cb (ip4_main_t *im, uword opaque,
    3222             :                                            u32 sw_if_index,
    3223             :                                            ip4_address_t *address,
    3224             :                                            u32 address_length,
    3225             :                                            u32 if_address_index, u32 is_delete)
    3226             : {
    3227        4838 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3228             :   nat44_ei_static_map_resolve_t *rp;
    3229        4838 :   nat44_ei_address_t *addresses = nm->addresses;
    3230             :   int rv, i;
    3231             : 
    3232        4838 :   if (!nm->enabled)
    3233             :     {
    3234        4815 :       return;
    3235             :     }
    3236             : 
    3237          23 :   if (!is_sw_if_index_reg_for_auto_resolve (nm->auto_add_sw_if_indices,
    3238             :                                             sw_if_index))
    3239             :     {
    3240          16 :       return;
    3241             :     }
    3242             : 
    3243           7 :   if (!is_delete)
    3244             :     {
    3245             :       /* Don't trip over lease renewal, static config */
    3246           4 :       for (i = 0; i < vec_len (addresses); i++)
    3247             :         {
    3248           0 :           if (addresses[i].addr.as_u32 == address->as_u32)
    3249             :             {
    3250           0 :               return;
    3251             :             }
    3252             :         }
    3253             : 
    3254           4 :       (void) nat44_ei_add_address (address, ~0);
    3255             : 
    3256             :       /* Scan static map resolution vector */
    3257           7 :       for (i = 0; i < vec_len (nm->to_resolve); i++)
    3258             :         {
    3259           3 :           rp = nm->to_resolve + i;
    3260           3 :           if (is_sm_addr_only (rp->flags))
    3261             :             {
    3262           2 :               continue;
    3263             :             }
    3264             :           /* On this interface? */
    3265           1 :           if (rp->sw_if_index == sw_if_index)
    3266             :             {
    3267           1 :               rv = nat44_ei_add_static_mapping_internal (
    3268           1 :                 rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
    3269             :                 rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag);
    3270           1 :               if (rv)
    3271             :                 {
    3272           0 :                   nat_elog_notice_X1 (
    3273             :                     nm, "add_static_mapping_internal returned %d", "i4", rv);
    3274             :                 }
    3275             :             }
    3276             :         }
    3277             :     }
    3278             :   else
    3279             :     {
    3280             :       // remove all static mapping records
    3281           3 :       (void) nat44_ei_del_address (address[0], 1);
    3282             :     }
    3283             : }
    3284             : 
    3285             : int
    3286           1 : nat44_ei_set_frame_queue_nelts (u32 frame_queue_nelts)
    3287             : {
    3288           1 :   fail_if_enabled ();
    3289           1 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3290           1 :   nm->frame_queue_nelts = frame_queue_nelts;
    3291           1 :   return 0;
    3292             : }
    3293             : 
    3294             : static void
    3295        4838 : nat44_ei_ip4_add_del_addr_only_sm_cb (ip4_main_t *im, uword opaque,
    3296             :                                       u32 sw_if_index, ip4_address_t *address,
    3297             :                                       u32 address_length, u32 if_address_index,
    3298             :                                       u32 is_delete)
    3299             : {
    3300        4838 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3301             :   nat44_ei_static_map_resolve_t *rp;
    3302             :   nat44_ei_static_mapping_t *m;
    3303             :   clib_bihash_kv_8_8_t kv, value;
    3304        4838 :   int i, rv = 0, match = 0;
    3305             : 
    3306        4838 :   if (!nm->enabled)
    3307             :     {
    3308        4836 :       return;
    3309             :     }
    3310             : 
    3311          25 :   for (i = 0; i < vec_len (nm->to_resolve); i++)
    3312             :     {
    3313           5 :       rp = nm->to_resolve + i;
    3314             : 
    3315           5 :       if (is_sm_addr_only (rp->flags) && rp->sw_if_index == sw_if_index)
    3316             :         {
    3317           3 :           match = 1;
    3318           3 :           break;
    3319             :         }
    3320             :     }
    3321             : 
    3322          23 :   if (!match)
    3323             :     {
    3324          20 :       return;
    3325             :     }
    3326             : 
    3327           3 :   init_nat_k (&kv, *address, is_sm_addr_only (rp->flags) ? 0 : rp->e_port,
    3328             :               nm->outside_fib_index,
    3329           3 :               is_sm_addr_only (rp->flags) ? 0 : rp->proto);
    3330           3 :   if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
    3331           3 :     m = 0;
    3332             :   else
    3333           0 :     m = pool_elt_at_index (nm->static_mappings, value.value);
    3334             : 
    3335           3 :   if (is_delete)
    3336             :     {
    3337           1 :       if (!m)
    3338           1 :         return;
    3339           0 :       rv = nat44_ei_del_static_mapping_internal (
    3340           0 :         rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id,
    3341             :         ~0, rp->flags);
    3342           0 :       if (rv)
    3343             :         {
    3344           0 :           nat_elog_notice_X1 (nm, "nat44_ei_del_static_mapping returned %d",
    3345             :                               "i4", rv);
    3346             :         }
    3347             :     }
    3348             :   else
    3349             :     {
    3350           2 :       if (m)
    3351           0 :         return;
    3352           2 :       rv = nat44_ei_add_static_mapping_internal (
    3353           2 :         rp->l_addr, address[0], rp->l_port, rp->e_port, rp->proto, rp->vrf_id,
    3354             :         ~0, rp->flags, rp->pool_addr, rp->tag);
    3355             : 
    3356           2 :       if (rv)
    3357             :         {
    3358           0 :           nat_elog_notice_X1 (nm, "nat44_ei_add_static_mapping returned %d",
    3359             :                               "i4", rv);
    3360             :         }
    3361             :     }
    3362             : }
    3363             : 
    3364             : static_always_inline uword
    3365           2 : nat44_ei_classify_inline_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
    3366             :                              vlib_frame_t *frame)
    3367             : {
    3368             :   u32 n_left_from, *from, *to_next;
    3369             :   nat44_ei_classify_next_t next_index;
    3370           2 :   nat44_ei_main_t *nm = &nat44_ei_main;
    3371             :   nat44_ei_static_mapping_t *m;
    3372           2 :   u32 next_in2out = 0, next_out2in = 0;
    3373             : 
    3374           2 :   from = vlib_frame_vector_args (frame);
    3375           2 :   n_left_from = frame->n_vectors;
    3376           2 :   next_index = node->cached_next_index;
    3377             : 
    3378           4 :   while (n_left_from > 0)
    3379             :     {
    3380             :       u32 n_left_to_next;
    3381             : 
    3382           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    3383             : 
    3384           4 :       while (n_left_from > 0 && n_left_to_next > 0)
    3385             :         {
    3386             :           u32 bi0;
    3387             :           vlib_buffer_t *b0;
    3388           2 :           u32 next0 = NAT44_EI_CLASSIFY_NEXT_IN2OUT;
    3389             :           ip4_header_t *ip0;
    3390             :           nat44_ei_address_t *ap;
    3391             :           clib_bihash_kv_8_8_t kv0, value0;
    3392             : 
    3393             :           /* speculatively enqueue b0 to the current next frame */
    3394           2 :           bi0 = from[0];
    3395           2 :           to_next[0] = bi0;
    3396           2 :           from += 1;
    3397           2 :           to_next += 1;
    3398           2 :           n_left_from -= 1;
    3399           2 :           n_left_to_next -= 1;
    3400             : 
    3401           2 :           b0 = vlib_get_buffer (vm, bi0);
    3402           2 :           ip0 = vlib_buffer_get_current (b0);
    3403             : 
    3404           3 :           vec_foreach (ap, nm->addresses)
    3405             :             {
    3406           2 :               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
    3407             :                 {
    3408           1 :                   next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
    3409           1 :                   goto enqueue0;
    3410             :                 }
    3411             :             }
    3412             : 
    3413           1 :           if (PREDICT_FALSE (pool_elts (nm->static_mappings)))
    3414             :             {
    3415           0 :               init_nat_k (&kv0, ip0->dst_address, 0, 0, 0);
    3416             :               /* try to classify the fragment based on IP header alone */
    3417           0 :               if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external,
    3418             :                                            &kv0, &value0))
    3419             :                 {
    3420           0 :                   m = pool_elt_at_index (nm->static_mappings, value0.value);
    3421           0 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
    3422           0 :                     next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
    3423           0 :                   goto enqueue0;
    3424             :                 }
    3425           0 :               init_nat_k (&kv0, ip0->dst_address,
    3426           0 :                           vnet_buffer (b0)->ip.reass.l4_dst_port, 0,
    3427           0 :                           ip_proto_to_nat_proto (ip0->protocol));
    3428           0 :               if (!clib_bihash_search_8_8 (&nm->static_mapping_by_external,
    3429             :                                            &kv0, &value0))
    3430             :                 {
    3431           0 :                   m = pool_elt_at_index (nm->static_mappings, value0.value);
    3432           0 :                   if (m->local_addr.as_u32 != m->external_addr.as_u32)
    3433           0 :                     next0 = NAT44_EI_CLASSIFY_NEXT_OUT2IN;
    3434             :                 }
    3435             :             }
    3436             : 
    3437           1 :         enqueue0:
    3438           2 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
    3439             :                              (b0->flags & VLIB_BUFFER_IS_TRACED)))
    3440             :             {
    3441             :               nat44_ei_classify_trace_t *t =
    3442           2 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
    3443           2 :               t->cached = 0;
    3444           2 :               t->next_in2out = next0 == NAT44_EI_CLASSIFY_NEXT_IN2OUT ? 1 : 0;
    3445             :             }
    3446             : 
    3447           2 :           next_in2out += next0 == NAT44_EI_CLASSIFY_NEXT_IN2OUT;
    3448           2 :           next_out2in += next0 == NAT44_EI_CLASSIFY_NEXT_OUT2IN;
    3449             : 
    3450             :           /* verify speculative enqueue, maybe switch current next frame */
    3451           2 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
    3452             :                                            n_left_to_next, bi0, next0);
    3453             :         }
    3454             : 
    3455           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    3456             :     }
    3457             : 
    3458           2 :   vlib_node_increment_counter (
    3459             :     vm, node->node_index, NAT44_EI_CLASSIFY_ERROR_NEXT_IN2OUT, next_in2out);
    3460           2 :   vlib_node_increment_counter (
    3461             :     vm, node->node_index, NAT44_EI_CLASSIFY_ERROR_NEXT_OUT2IN, next_out2in);
    3462           2 :   return frame->n_vectors;
    3463             : }
    3464             : 
    3465         577 : VLIB_NODE_FN (nat44_ei_classify_node)
    3466             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
    3467             : {
    3468           2 :   return nat44_ei_classify_inline_fn (vm, node, frame);
    3469             : }
    3470             : 
    3471       72026 : VLIB_REGISTER_NODE (nat44_ei_classify_node) = {
    3472             :   .name = "nat44-ei-classify",
    3473             :   .vector_size = sizeof (u32),
    3474             :   .format_trace = format_nat44_ei_classify_trace,
    3475             :   .type = VLIB_NODE_TYPE_INTERNAL,
    3476             :   .n_errors = ARRAY_LEN(nat44_ei_classify_error_strings),
    3477             :   .error_strings = nat44_ei_classify_error_strings,
    3478             :   .n_next_nodes = NAT44_EI_CLASSIFY_N_NEXT,
    3479             :   .next_nodes = {
    3480             :     [NAT44_EI_CLASSIFY_NEXT_IN2OUT] = "nat44-ei-in2out",
    3481             :     [NAT44_EI_CLASSIFY_NEXT_OUT2IN] = "nat44-ei-out2in",
    3482             :     [NAT44_EI_CLASSIFY_NEXT_DROP] = "error-drop",
    3483             :   },
    3484             : };
    3485             : 
    3486         575 : VLIB_NODE_FN (nat44_ei_handoff_classify_node)
    3487             : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
    3488             : {
    3489           0 :   return nat44_ei_classify_inline_fn (vm, node, frame);
    3490             : }
    3491             : 
    3492       72026 : VLIB_REGISTER_NODE (nat44_ei_handoff_classify_node) = {
    3493             :   .name = "nat44-ei-handoff-classify",
    3494             :   .vector_size = sizeof (u32),
    3495             :   .format_trace = format_nat44_ei_classify_trace,
    3496             :   .type = VLIB_NODE_TYPE_INTERNAL,
    3497             :   .n_errors = ARRAY_LEN(nat44_ei_classify_error_strings),
    3498             :   .error_strings = nat44_ei_classify_error_strings,
    3499             :   .n_next_nodes = NAT44_EI_CLASSIFY_N_NEXT,
    3500             :   .next_nodes = {
    3501             :     [NAT44_EI_CLASSIFY_NEXT_IN2OUT] = "nat44-ei-in2out-worker-handoff",
    3502             :     [NAT44_EI_CLASSIFY_NEXT_OUT2IN] = "nat44-ei-out2in-worker-handoff",
    3503             :     [NAT44_EI_CLASSIFY_NEXT_DROP] = "error-drop",
    3504             :   },
    3505             : };
    3506             : 
    3507             : /*
    3508             :  * fd.io coding-style-patch-verification: ON
    3509             :  *
    3510             :  * Local Variables:
    3511             :  * eval: (c-set-style "gnu")
    3512             :  * End:
    3513             :  */

Generated by: LCOV version 1.14