LCOV - code coverage report
Current view: top level - plugins/nat/nat66 - nat66.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 133 164 81.1 %
Date: 2023-07-05 22:20:52 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /**
      16             :  * @file
      17             :  * @brief NAT66 implementation
      18             :  */
      19             : 
      20             : #include <nat/nat66/nat66.h>
      21             : #include <vpp/app/version.h>
      22             : #include <vnet/plugin/plugin.h>
      23             : #include <vnet/ip/reass/ip6_sv_reass.h>
      24             : 
      25             : nat66_main_t nat66_main;
      26             : 
      27             : /* Hook up input features */
      28       30799 : VNET_FEATURE_INIT (nat66_in2out, static) = {
      29             :   .arc_name = "ip6-unicast",
      30             :   .node_name = "nat66-in2out",
      31             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
      32             :   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
      33             : };
      34       30799 : VNET_FEATURE_INIT (nat66_out2in, static) = {
      35             :   .arc_name = "ip6-unicast",
      36             :   .node_name = "nat66-out2in",
      37             :   .runs_before = VNET_FEATURES ("ip6-lookup"),
      38             :   .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
      39             : };
      40             : 
      41             : clib_error_t *nat66_plugin_api_hookup (vlib_main_t * vm);
      42             : 
      43             : #define fail_if_enabled()                                                     \
      44             :   do                                                                          \
      45             :     {                                                                         \
      46             :       nat66_main_t *nm = &nat66_main;                                         \
      47             :       if (PREDICT_FALSE (nm->enabled))                                        \
      48             :         {                                                                     \
      49             :           nat66_elog_warn ("plugin enabled");                                 \
      50             :           return 1;                                                           \
      51             :         }                                                                     \
      52             :     }                                                                         \
      53             :   while (0)
      54             : 
      55             : #define fail_if_disabled()                                                    \
      56             :   do                                                                          \
      57             :     {                                                                         \
      58             :       nat66_main_t *nm = &nat66_main;                                         \
      59             :       if (PREDICT_FALSE (!nm->enabled))                                       \
      60             :         {                                                                     \
      61             :           nat66_elog_warn ("plugin disabled");                                \
      62             :           return 1;                                                           \
      63             :         }                                                                     \
      64             :     }                                                                         \
      65             :   while (0)
      66             : 
      67             : static clib_error_t *
      68         559 : nat66_init (vlib_main_t * vm)
      69             : {
      70         559 :   nat66_main_t *nm = &nat66_main;
      71             : 
      72         559 :   clib_memset (nm, 0, sizeof (*nm));
      73             : 
      74         559 :   nm->session_counters.name = "session counters";
      75         559 :   nm->in2out_packets.name = "in2out";
      76         559 :   nm->in2out_packets.stat_segment_name = "/nat64/in2out";
      77         559 :   nm->out2in_packets.name = "out2in";
      78         559 :   nm->out2in_packets.stat_segment_name = "/nat64/out2in";
      79             : 
      80         559 :   nm->nat_fib_src_hi = fib_source_allocate ("nat66-hi", FIB_SOURCE_PRIORITY_HI,
      81             :                                             FIB_SOURCE_BH_SIMPLE);
      82         559 :   return nat66_plugin_api_hookup (vm);
      83             : }
      84             : 
      85             : int
      86           2 : nat66_plugin_enable (u32 outside_vrf)
      87             : {
      88           2 :   nat66_main_t *nm = &nat66_main;
      89             : 
      90           2 :   u32 static_mapping_buckets = 1024;
      91           2 :   uword static_mapping_memory_size = 64 << 20;
      92             : 
      93           2 :   fail_if_enabled ();
      94             : 
      95           2 :   clib_bihash_init_24_8 (&nm->sm_l, "nat66-static-map-by-local",
      96             :                          static_mapping_buckets, static_mapping_memory_size);
      97           2 :   clib_bihash_init_24_8 (&nm->sm_e, "nat66-static-map-by-external",
      98             :                          static_mapping_buckets, static_mapping_memory_size);
      99             : 
     100           2 :   nm->outside_vrf_id = outside_vrf;
     101           4 :   nm->outside_fib_index = fib_table_find_or_create_and_lock (
     102           2 :     FIB_PROTOCOL_IP6, outside_vrf, nm->nat_fib_src_hi);
     103           2 :   nm->enabled = 1;
     104           2 :   return 0;
     105             : }
     106             : 
     107             : int
     108           2 : nat66_plugin_disable ()
     109             : {
     110           2 :   nat66_main_t *nm = &nat66_main;
     111             :   nat66_interface_t *i, *temp;
     112           2 :   int error = 0;
     113             : 
     114           2 :   temp = pool_dup (nm->interfaces);
     115           6 :   pool_foreach (i, temp)
     116             :     {
     117           4 :       if (nat66_interface_is_inside (i))
     118           3 :         error = nat66_interface_add_del (i->sw_if_index, 1, 0);
     119             : 
     120           4 :       if (nat66_interface_is_outside (i))
     121           1 :         error = nat66_interface_add_del (i->sw_if_index, 0, 0);
     122             : 
     123           4 :       if (error)
     124             :         {
     125           0 :           nat66_elog_warn ("error occurred while removing interface");
     126             :         }
     127             :     }
     128           2 :   pool_free (temp);
     129           2 :   pool_free (nm->interfaces);
     130             : 
     131           2 :   pool_free (nm->sm);
     132           2 :   clib_bihash_free_24_8 (&nm->sm_l);
     133           2 :   clib_bihash_free_24_8 (&nm->sm_e);
     134             : 
     135           2 :   nm->interfaces = 0;
     136           2 :   nm->sm = 0;
     137             : 
     138           2 :   vlib_clear_combined_counters (&nm->session_counters);
     139           2 :   vlib_clear_simple_counters (&nm->in2out_packets);
     140           2 :   vlib_clear_simple_counters (&nm->out2in_packets);
     141             : 
     142           2 :   nm->enabled = 0;
     143           2 :   return error;
     144             : }
     145             : 
     146             : static void
     147           4 : nat66_validate_counters (nat66_main_t * nm, u32 sw_if_index)
     148             : {
     149           4 :   vlib_validate_simple_counter (&nm->in2out_packets, sw_if_index);
     150           4 :   vlib_zero_simple_counter (&nm->in2out_packets, sw_if_index);
     151           4 :   vlib_validate_simple_counter (&nm->out2in_packets, sw_if_index);
     152           4 :   vlib_zero_simple_counter (&nm->out2in_packets, sw_if_index);
     153           4 : }
     154             : 
     155             : int
     156           8 : nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
     157             : {
     158           8 :   nat66_main_t *nm = &nat66_main;
     159           8 :   nat66_interface_t *interface = 0, *i;
     160             :   const char *feature_name;
     161             : 
     162           8 :   fail_if_disabled ();
     163             : 
     164          10 :   pool_foreach (i, nm->interfaces)
     165             :    {
     166           6 :     if (i->sw_if_index == sw_if_index)
     167             :       {
     168           4 :         interface = i;
     169           4 :         break;
     170             :       }
     171             :   }
     172             : 
     173           8 :   if (is_add)
     174             :     {
     175           4 :       if (interface)
     176           0 :         return VNET_API_ERROR_VALUE_EXIST;
     177             : 
     178           4 :       pool_get (nm->interfaces, interface);
     179           4 :       interface->sw_if_index = sw_if_index;
     180           4 :       interface->flags =
     181             :         is_inside ? NAT66_INTERFACE_FLAG_IS_INSIDE :
     182             :         NAT66_INTERFACE_FLAG_IS_OUTSIDE;
     183           4 :       nat66_validate_counters (nm, sw_if_index);
     184             :     }
     185             :   else
     186             :     {
     187           4 :       if (!interface)
     188           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     189             : 
     190           4 :       pool_put (nm->interfaces, interface);
     191             :     }
     192             : 
     193           8 :   feature_name = is_inside ? "nat66-in2out" : "nat66-out2in";
     194           8 :   int rv = ip6_sv_reass_enable_disable_with_refcnt (sw_if_index, is_add);
     195           8 :   if (rv)
     196           0 :     return rv;
     197           8 :   return vnet_feature_enable_disable ("ip6-unicast", feature_name,
     198             :                                       sw_if_index, is_add, 0, 0);
     199             : }
     200             : 
     201             : void
     202           0 : nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx)
     203             : {
     204           0 :   nat66_main_t *nm = &nat66_main;
     205           0 :   nat66_interface_t *i = 0;
     206             : 
     207           0 :   pool_foreach (i, nm->interfaces)
     208             :    {
     209           0 :     if (fn (i, ctx))
     210           0 :       break;
     211             :   }
     212           0 : }
     213             : 
     214             : nat66_static_mapping_t *
     215           8 : nat66_static_mapping_get (ip6_address_t * addr, u32 fib_index, u8 is_local)
     216             : {
     217           8 :   nat66_main_t *nm = &nat66_main;
     218           8 :   nat66_static_mapping_t *sm = 0;
     219             :   nat66_sm_key_t sm_key;
     220             :   clib_bihash_kv_24_8_t kv, value;
     221             : 
     222           8 :   sm_key.addr.as_u64[0] = addr->as_u64[0];
     223           8 :   sm_key.addr.as_u64[1] = addr->as_u64[1];
     224           8 :   sm_key.fib_index = fib_index;
     225           8 :   sm_key.rsvd = 0;
     226             : 
     227           8 :   kv.key[0] = sm_key.as_u64[0];
     228           8 :   kv.key[1] = sm_key.as_u64[1];
     229           8 :   kv.key[2] = sm_key.as_u64[2];
     230             : 
     231           8 :   if (!clib_bihash_search_24_8
     232             :       (is_local ? &nm->sm_l : &nm->sm_e, &kv, &value))
     233           8 :     sm = pool_elt_at_index (nm->sm, value.value);
     234             : 
     235           8 :   return sm;
     236             : }
     237             : 
     238             : int
     239           2 : nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
     240             :                               u32 vrf_id, u8 is_add)
     241             : {
     242           2 :   nat66_main_t *nm = &nat66_main;
     243           2 :   int rv = 0;
     244           2 :   nat66_static_mapping_t *sm = 0;
     245             :   nat66_sm_key_t sm_key;
     246             :   clib_bihash_kv_24_8_t kv, value;
     247           2 :   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, vrf_id);
     248             : 
     249           2 :   fail_if_disabled ();
     250             : 
     251           2 :   sm_key.addr.as_u64[0] = l_addr->as_u64[0];
     252           2 :   sm_key.addr.as_u64[1] = l_addr->as_u64[1];
     253           2 :   sm_key.fib_index = fib_index;
     254           2 :   sm_key.rsvd = 0;
     255           2 :   kv.key[0] = sm_key.as_u64[0];
     256           2 :   kv.key[1] = sm_key.as_u64[1];
     257           2 :   kv.key[2] = sm_key.as_u64[2];
     258             : 
     259           2 :   if (!clib_bihash_search_24_8 (&nm->sm_l, &kv, &value))
     260           0 :     sm = pool_elt_at_index (nm->sm, value.value);
     261             : 
     262           2 :   if (is_add)
     263             :     {
     264           2 :       if (sm)
     265           0 :         return VNET_API_ERROR_VALUE_EXIST;
     266             : 
     267           2 :       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
     268           2 :                                                      nm->nat_fib_src_hi);
     269           2 :       pool_get (nm->sm, sm);
     270           2 :       clib_memset (sm, 0, sizeof (*sm));
     271           2 :       sm->l_addr.as_u64[0] = l_addr->as_u64[0];
     272           2 :       sm->l_addr.as_u64[1] = l_addr->as_u64[1];
     273           2 :       sm->e_addr.as_u64[0] = e_addr->as_u64[0];
     274           2 :       sm->e_addr.as_u64[1] = e_addr->as_u64[1];
     275           2 :       sm->fib_index = fib_index;
     276             : 
     277           2 :       sm_key.fib_index = fib_index;
     278           2 :       kv.key[0] = sm_key.as_u64[0];
     279           2 :       kv.key[1] = sm_key.as_u64[1];
     280           2 :       kv.key[2] = sm_key.as_u64[2];
     281           2 :       kv.value = sm - nm->sm;
     282           2 :       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 1))
     283           0 :         nat66_elog_warn ("nat66-static-map-by-local add key failed");
     284           2 :       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
     285           2 :       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
     286           2 :       sm_key.fib_index = 0;
     287           2 :       kv.key[0] = sm_key.as_u64[0];
     288           2 :       kv.key[1] = sm_key.as_u64[1];
     289           2 :       kv.key[2] = sm_key.as_u64[2];
     290           2 :       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 1))
     291           0 :         nat66_elog_warn ("nat66-static-map-by-external add key failed");
     292             : 
     293           2 :       vlib_validate_combined_counter (&nm->session_counters, kv.value);
     294           2 :       vlib_zero_combined_counter (&nm->session_counters, kv.value);
     295             :     }
     296             :   else
     297             :     {
     298           0 :       if (!sm)
     299           0 :         return VNET_API_ERROR_NO_SUCH_ENTRY;
     300             : 
     301           0 :       kv.value = sm - nm->sm;
     302           0 :       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 0))
     303           0 :         nat66_elog_warn ("nat66-static-map-by-local delete key failed");
     304           0 :       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
     305           0 :       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
     306           0 :       sm_key.fib_index = 0;
     307           0 :       kv.key[0] = sm_key.as_u64[0];
     308           0 :       kv.key[1] = sm_key.as_u64[1];
     309           0 :       kv.key[2] = sm_key.as_u64[2];
     310           0 :       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 0))
     311           0 :         nat66_elog_warn ("nat66-static-map-by-external delete key failed");
     312           0 :       fib_table_unlock (sm->fib_index, FIB_PROTOCOL_IP6, nm->nat_fib_src_hi);
     313           0 :       pool_put (nm->sm, sm);
     314             :     }
     315             : 
     316           2 :   return rv;
     317             : }
     318             : 
     319             : void
     320           1 : nat66_static_mappings_walk (nat66_static_mapping_walk_fn_t fn, void *ctx)
     321             : {
     322           1 :   nat66_main_t *nm = &nat66_main;
     323           1 :   nat66_static_mapping_t *sm = 0;
     324             : 
     325           2 :   pool_foreach (sm, nm->sm)
     326             :    {
     327           1 :     if (fn (sm, ctx))
     328           0 :       break;
     329             :   }
     330           1 : }
     331             : 
     332             : VLIB_PLUGIN_REGISTER () =
     333             : {
     334             :  .version = VPP_BUILD_VER,
     335             :  .description = "NAT66",
     336             : };
     337             : 
     338        1119 : VLIB_INIT_FUNCTION (nat66_init);
     339             : 
     340             : /*
     341             :  * fd.io coding-style-patch-verification: ON
     342             :  *
     343             :  * Local Variables:
     344             :  * eval: (c-set-style "gnu")
     345             :  * End:
     346             :  */

Generated by: LCOV version 1.14