LCOV - code coverage report
Current view: top level - plugins/cnat - cnat_snat_policy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 136 280 48.6 %
Date: 2023-07-05 22:20:52 Functions: 23 33 69.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/ip/ip.h>
      17             : #include <cnat/cnat_snat_policy.h>
      18             : #include <cnat/cnat_translation.h>
      19             : 
      20             : cnat_snat_policy_main_t cnat_snat_policy_main;
      21             : 
      22             : uword
      23           0 : unformat_cnat_snat_interface_map_type (unformat_input_t *input, va_list *args)
      24             : {
      25           0 :   u8 *a = va_arg (*args, u8 *);
      26           0 :   if (unformat (input, "include-v4"))
      27           0 :     *a = CNAT_SNAT_IF_MAP_INCLUDE_V4;
      28           0 :   else if (unformat (input, "include-v6"))
      29           0 :     *a = CNAT_SNAT_IF_MAP_INCLUDE_V6;
      30           0 :   else if (unformat (input, "k8s"))
      31           0 :     *a = CNAT_SNAT_IF_MAP_INCLUDE_POD;
      32             :   else
      33           0 :     return 0;
      34           0 :   return 1;
      35             : }
      36             : 
      37             : u8 *
      38           0 : format_cnat_snat_interface_map_type (u8 *s, va_list *args)
      39             : {
      40           0 :   cnat_snat_interface_map_type_t mtype = va_arg (*args, int);
      41           0 :   switch (mtype)
      42             :     {
      43           0 :     case CNAT_SNAT_IF_MAP_INCLUDE_V4:
      44           0 :       s = format (s, "Included v4");
      45           0 :       break;
      46           0 :     case CNAT_SNAT_IF_MAP_INCLUDE_V6:
      47           0 :       s = format (s, "Included v6");
      48           0 :       break;
      49           0 :     case CNAT_SNAT_IF_MAP_INCLUDE_POD:
      50           0 :       s = format (s, "k8s pod");
      51           0 :       break;
      52           0 :     default:
      53           0 :       s = format (s, "(unknown)");
      54           0 :       break;
      55             :     }
      56           0 :   return (s);
      57             : }
      58             : 
      59             : u8 *
      60           0 : format_cnat_snat_prefix (u8 *s, va_list *args)
      61             : {
      62           0 :   clib_bihash_kv_24_8_t *kv = va_arg (*args, clib_bihash_kv_24_8_t *);
      63           0 :   CLIB_UNUSED (int verbose) = va_arg (*args, int);
      64           0 :   u32 af = kv->key[2] >> 32;
      65           0 :   u32 len = kv->key[2] & 0xffffffff;
      66           0 :   if (AF_IP4 == af)
      67           0 :     s = format (s, "%U/%d", format_ip4_address, &kv->key[0], len);
      68             :   else
      69           0 :     s = format (s, "%U/%d", format_ip6_address, &kv->key[0], len);
      70           0 :   return (s);
      71             : }
      72             : 
      73             : static void
      74           8 : cnat_compute_prefix_lengths_in_search_order (
      75             :   cnat_snat_exclude_pfx_table_t *table, ip_address_family_t af)
      76             : {
      77             :   int i;
      78           8 :   vec_reset_length (table->meta[af].prefix_lengths_in_search_order);
      79             :   /* Note: bitmap reversed so this is in fact a longest prefix match */
      80          12 :   clib_bitmap_foreach (i, table->meta[af].non_empty_dst_address_length_bitmap)
      81             :     {
      82           4 :       int dst_address_length = 128 - i;
      83           4 :       vec_add1 (table->meta[af].prefix_lengths_in_search_order,
      84             :                 dst_address_length);
      85             :     }
      86           8 : }
      87             : 
      88             : int
      89          24 : cnat_snat_policy_add_del_if (u32 sw_if_index, u8 is_add,
      90             :                              cnat_snat_interface_map_type_t table)
      91             : {
      92          24 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
      93             : 
      94          24 :   if (table >= ARRAY_LEN (cpm->interface_maps))
      95           0 :     return VNET_API_ERROR_INVALID_VALUE;
      96             : 
      97          24 :   clib_bitmap_t **map = &cpm->interface_maps[table];
      98             : 
      99          24 :   *map = clib_bitmap_set (*map, sw_if_index, is_add);
     100          24 :   return 0;
     101             : }
     102             : 
     103             : static clib_error_t *
     104           0 : cnat_snat_policy_add_del_if_command_fn (vlib_main_t *vm,
     105             :                                         unformat_input_t *input,
     106             :                                         vlib_cli_command_t *cmd)
     107             : {
     108           0 :   vnet_main_t *vnm = vnet_get_main ();
     109           0 :   int is_add = 1;
     110           0 :   u32 sw_if_index = ~0;
     111           0 :   u32 table = 0;
     112             :   int rv;
     113             : 
     114           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     115             :     {
     116           0 :       if (unformat (input, "del"))
     117           0 :         is_add = 0;
     118           0 :       else if (unformat (input, "table %U",
     119             :                          unformat_cnat_snat_interface_map_type, &table))
     120             :         ;
     121           0 :       else if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
     122             :                          &sw_if_index))
     123             :         ;
     124             :       else
     125           0 :         return clib_error_return (0, "unknown input '%U'",
     126             :                                   format_unformat_error, input);
     127             :     }
     128             : 
     129           0 :   if (sw_if_index == ~0)
     130           0 :     return clib_error_return (0, "Interface not specified");
     131             : 
     132           0 :   rv = cnat_snat_policy_add_del_if (sw_if_index, is_add, table);
     133             : 
     134           0 :   if (rv)
     135           0 :     return clib_error_return (0, "Error %d", rv);
     136             : 
     137           0 :   return NULL;
     138             : }
     139             : 
     140      245447 : VLIB_CLI_COMMAND (cnat_snat_policy_add_del_if_command, static) = {
     141             :   .path = "set cnat snat-policy if",
     142             :   .short_help = "set cnat snat-policy if [del]"
     143             :                 "[table [include-v4 include-v6 k8s]] [interface]",
     144             :   .function = cnat_snat_policy_add_del_if_command_fn,
     145             : };
     146             : 
     147             : int
     148           4 : cnat_snat_policy_add_pfx (ip_prefix_t *pfx)
     149             : {
     150             :   /* All packets destined to this prefix won't be source-NAT-ed */
     151           4 :   cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
     152             :   clib_bihash_kv_24_8_t kv;
     153             :   ip6_address_t *mask;
     154           4 :   u64 af = ip_prefix_version (pfx);
     155             :   ;
     156             : 
     157           4 :   mask = &table->ip_masks[pfx->len];
     158           4 :   if (AF_IP4 == af)
     159             :     {
     160           2 :       kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
     161           2 :       kv.key[1] = 0;
     162             :     }
     163             :   else
     164             :     {
     165           2 :       kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
     166           2 :       kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
     167             :     }
     168           4 :   kv.key[2] = ((u64) af << 32) | pfx->len;
     169           4 :   clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 1 /* is_add */);
     170             : 
     171           4 :   table->meta[af].dst_address_length_refcounts[pfx->len]++;
     172           8 :   table->meta[af].non_empty_dst_address_length_bitmap = clib_bitmap_set (
     173           4 :     table->meta[af].non_empty_dst_address_length_bitmap, 128 - pfx->len, 1);
     174           4 :   cnat_compute_prefix_lengths_in_search_order (table, af);
     175           4 :   return 0;
     176             : }
     177             : 
     178             : int
     179           4 : cnat_snat_policy_del_pfx (ip_prefix_t *pfx)
     180             : {
     181           4 :   cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
     182             :   clib_bihash_kv_24_8_t kv, val;
     183             :   ip6_address_t *mask;
     184           4 :   u64 af = ip_prefix_version (pfx);
     185             :   ;
     186             : 
     187           4 :   mask = &table->ip_masks[pfx->len];
     188           4 :   if (AF_IP4 == af)
     189             :     {
     190           2 :       kv.key[0] = (u64) ip_prefix_v4 (pfx).as_u32 & mask->as_u64[0];
     191           2 :       kv.key[1] = 0;
     192             :     }
     193             :   else
     194             :     {
     195           2 :       kv.key[0] = ip_prefix_v6 (pfx).as_u64[0] & mask->as_u64[0];
     196           2 :       kv.key[1] = ip_prefix_v6 (pfx).as_u64[1] & mask->as_u64[1];
     197             :     }
     198           4 :   kv.key[2] = ((u64) af << 32) | pfx->len;
     199             : 
     200           4 :   if (clib_bihash_search_24_8 (&table->ip_hash, &kv, &val))
     201             :     {
     202           0 :       return 1;
     203             :     }
     204           4 :   clib_bihash_add_del_24_8 (&table->ip_hash, &kv, 0 /* is_add */);
     205             :   /* refcount accounting */
     206           4 :   ASSERT (table->meta[af].dst_address_length_refcounts[pfx->len] > 0);
     207           4 :   if (--table->meta[af].dst_address_length_refcounts[pfx->len] == 0)
     208             :     {
     209           4 :       table->meta[af].non_empty_dst_address_length_bitmap =
     210           4 :         clib_bitmap_set (table->meta[af].non_empty_dst_address_length_bitmap,
     211           4 :                          128 - pfx->len, 0);
     212           4 :       cnat_compute_prefix_lengths_in_search_order (table, af);
     213             :     }
     214           4 :   return 0;
     215             : }
     216             : 
     217             : int
     218         140 : cnat_search_snat_prefix (ip46_address_t *addr, ip_address_family_t af)
     219             : {
     220             :   /* Returns 0 if addr matches any of the listed prefixes */
     221         140 :   cnat_snat_exclude_pfx_table_t *table = &cnat_snat_policy_main.excluded_pfx;
     222             :   clib_bihash_kv_24_8_t kv, val;
     223             :   int i, n_p, rv;
     224         140 :   n_p = vec_len (table->meta[af].prefix_lengths_in_search_order);
     225         140 :   if (AF_IP4 == af)
     226             :     {
     227          35 :       kv.key[0] = addr->ip4.as_u32;
     228          35 :       kv.key[1] = 0;
     229             :     }
     230             :   else
     231             :     {
     232         105 :       kv.key[0] = addr->as_u64[0];
     233         105 :       kv.key[1] = addr->as_u64[1];
     234             :     }
     235             : 
     236             :   /*
     237             :    * start search from a mask length same length or shorter.
     238             :    * we don't want matches longer than the mask passed
     239             :    */
     240         140 :   i = 0;
     241         140 :   for (; i < n_p; i++)
     242             :     {
     243         120 :       int dst_address_length =
     244         120 :         table->meta[af].prefix_lengths_in_search_order[i];
     245         120 :       ip6_address_t *mask = &table->ip_masks[dst_address_length];
     246             : 
     247         120 :       ASSERT (dst_address_length >= 0 && dst_address_length <= 128);
     248             :       /* As lengths are decreasing, masks are increasingly specific. */
     249         120 :       kv.key[0] &= mask->as_u64[0];
     250         120 :       kv.key[1] &= mask->as_u64[1];
     251         120 :       kv.key[2] = ((u64) af << 32) | dst_address_length;
     252         120 :       rv = clib_bihash_search_inline_2_24_8 (&table->ip_hash, &kv, &val);
     253         120 :       if (rv == 0)
     254         120 :         return 0;
     255             :     }
     256          20 :   return -1;
     257             : }
     258             : 
     259             : static_always_inline int
     260         140 : cnat_snat_policy_interface_enabled (u32 sw_if_index, ip_address_family_t af)
     261             : {
     262         140 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     263         140 :   return clib_bitmap_get (cpm->interface_maps[af], sw_if_index);
     264             : }
     265             : 
     266             : int
     267           0 : cnat_snat_policy_none (vlib_buffer_t *b, cnat_session_t *session)
     268             : {
     269             :   /* srcNAT everything by default */
     270           0 :   return 1;
     271             : }
     272             : 
     273             : int
     274         140 : cnat_snat_policy_if_pfx (vlib_buffer_t *b, cnat_session_t *session)
     275             : {
     276         140 :   ip46_address_t *dst_addr = &session->key.cs_ip[VLIB_TX];
     277         140 :   u32 in_if = vnet_buffer (b)->sw_if_index[VLIB_RX];
     278         140 :   ip_address_family_t af = session->key.cs_af;
     279             : 
     280             :   /* source nat for outgoing connections */
     281         140 :   if (cnat_snat_policy_interface_enabled (in_if, af))
     282         140 :     if (cnat_search_snat_prefix (dst_addr, af))
     283             :       /* Destination is not in the prefixes that don't require snat */
     284          20 :       return 1;
     285         120 :   return 0;
     286             : }
     287             : 
     288             : int
     289           0 : cnat_snat_policy_k8s (vlib_buffer_t *b, cnat_session_t *session)
     290             : {
     291           0 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     292           0 :   ip_address_family_t af = session->key.cs_af;
     293             : 
     294           0 :   ip46_address_t *src_addr = &session->key.cs_ip[VLIB_RX];
     295           0 :   ip46_address_t *dst_addr = &session->key.cs_ip[VLIB_TX];
     296           0 :   u32 in_if = vnet_buffer (b)->sw_if_index[VLIB_RX];
     297           0 :   u32 out_if = vnet_buffer (b)->sw_if_index[VLIB_TX];
     298             : 
     299             :   /* source nat for outgoing connections */
     300           0 :   if (cnat_snat_policy_interface_enabled (in_if, af))
     301           0 :     if (cnat_search_snat_prefix (dst_addr, af))
     302             :       /* Destination is not in the prefixes that don't require snat */
     303           0 :       return 1;
     304             : 
     305             :   /* source nat for translations that come from the outside:
     306             :      src not not a pod interface, dst not a pod interface */
     307           0 :   if (!clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
     308           0 :                         in_if) &&
     309           0 :       !clib_bitmap_get (cpm->interface_maps[CNAT_SNAT_IF_MAP_INCLUDE_POD],
     310             :                         out_if))
     311             :     {
     312           0 :       if (AF_IP6 == af &&
     313           0 :           ip6_address_is_equal (&src_addr->ip6,
     314           0 :                                 &ip_addr_v6 (&cpm->snat_ip6.ce_ip)))
     315           0 :         return 0;
     316           0 :       if (AF_IP4 == af &&
     317           0 :           ip4_address_is_equal (&src_addr->ip4,
     318           0 :                                 &ip_addr_v4 (&cpm->snat_ip4.ce_ip)))
     319           0 :         return 0;
     320           0 :       return 1;
     321             :     }
     322             : 
     323             :   /* handle the case where a container is connecting to itself via a service */
     324           0 :   if (ip46_address_is_equal (src_addr, dst_addr))
     325           0 :     return 1;
     326             : 
     327           0 :   return 0;
     328             : }
     329             : 
     330             : void
     331           6 : cnat_set_snat (ip4_address_t *ip4, ip6_address_t *ip6, u32 sw_if_index)
     332             : {
     333           6 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     334             : 
     335           6 :   cnat_lazy_init ();
     336             : 
     337           6 :   cnat_translation_unwatch_addr (INDEX_INVALID, CNAT_RESOLV_ADDR_SNAT);
     338             : 
     339           6 :   ip_address_set (&cpm->snat_ip4.ce_ip, ip4, AF_IP4);
     340           6 :   ip_address_set (&cpm->snat_ip6.ce_ip, ip6, AF_IP6);
     341           6 :   cpm->snat_ip4.ce_sw_if_index = sw_if_index;
     342           6 :   cpm->snat_ip6.ce_sw_if_index = sw_if_index;
     343             : 
     344           6 :   cnat_resolve_ep (&cpm->snat_ip4);
     345           6 :   cnat_resolve_ep (&cpm->snat_ip6);
     346           6 :   cnat_translation_watch_addr (INDEX_INVALID, 0, &cpm->snat_ip4,
     347             :                                CNAT_RESOLV_ADDR_SNAT);
     348           6 :   cnat_translation_watch_addr (INDEX_INVALID, 0, &cpm->snat_ip6,
     349             :                                CNAT_RESOLV_ADDR_SNAT);
     350           6 : }
     351             : 
     352             : static clib_error_t *
     353           0 : cnat_set_snat_cli (vlib_main_t *vm, unformat_input_t *input,
     354             :                    vlib_cli_command_t *cmd)
     355             : {
     356           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     357           0 :   vnet_main_t *vnm = vnet_get_main ();
     358           0 :   ip4_address_t ip4 = { { 0 } };
     359           0 :   ip6_address_t ip6 = { { 0 } };
     360           0 :   clib_error_t *e = 0;
     361           0 :   u32 sw_if_index = INDEX_INVALID;
     362             : 
     363           0 :   cnat_lazy_init ();
     364             : 
     365             :   /* Get a line of input. */
     366           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     367           0 :     return 0;
     368             : 
     369           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     370             :     {
     371           0 :       if (unformat_user (line_input, unformat_ip4_address, &ip4))
     372             :         ;
     373           0 :       else if (unformat_user (line_input, unformat_ip6_address, &ip6))
     374             :         ;
     375           0 :       else if (unformat_user (line_input, unformat_vnet_sw_interface, vnm,
     376             :                               &sw_if_index))
     377             :         ;
     378             :       else
     379             :         {
     380           0 :           e = clib_error_return (0, "unknown input '%U'",
     381             :                                  format_unformat_error, input);
     382           0 :           goto done;
     383             :         }
     384             :     }
     385             : 
     386           0 :   cnat_set_snat (&ip4, &ip6, sw_if_index);
     387             : 
     388           0 : done:
     389           0 :   unformat_free (line_input);
     390             : 
     391           0 :   return (e);
     392             : }
     393             : 
     394      245447 : VLIB_CLI_COMMAND (cnat_set_snat_command, static) = {
     395             :   .path = "set cnat snat-policy addr",
     396             :   .short_help =
     397             :     "set cnat snat-policy addr [<ip4-address>][<ip6-address>][sw_if_index]",
     398             :   .function = cnat_set_snat_cli,
     399             : };
     400             : 
     401             : static clib_error_t *
     402           0 : cnat_snat_policy_add_del_pfx_command_fn (vlib_main_t *vm,
     403             :                                          unformat_input_t *input,
     404             :                                          vlib_cli_command_t *cmd)
     405             : {
     406             :   ip_prefix_t pfx;
     407           0 :   u8 is_add = 1;
     408             :   int rv;
     409             : 
     410           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     411             :     {
     412           0 :       if (unformat (input, "%U", unformat_ip_prefix, &pfx))
     413             :         ;
     414           0 :       else if (unformat (input, "del"))
     415           0 :         is_add = 0;
     416             :       else
     417           0 :         return (clib_error_return (0, "unknown input '%U'",
     418             :                                    format_unformat_error, input));
     419             :     }
     420             : 
     421           0 :   if (is_add)
     422           0 :     rv = cnat_snat_policy_add_pfx (&pfx);
     423             :   else
     424           0 :     rv = cnat_snat_policy_del_pfx (&pfx);
     425             : 
     426           0 :   if (rv)
     427           0 :     return (clib_error_return (0, "error %d", rv, input));
     428             : 
     429           0 :   return (NULL);
     430             : }
     431             : 
     432      245447 : VLIB_CLI_COMMAND (cnat_snat_policy_add_del_pfx_command, static) = {
     433             :   .path = "set cnat snat-policy prefix",
     434             :   .short_help = "set cnat snat-policy prefix [del] [prefix]",
     435             :   .function = cnat_snat_policy_add_del_pfx_command_fn,
     436             : };
     437             : 
     438             : static clib_error_t *
     439           0 : cnat_show_snat (vlib_main_t *vm, unformat_input_t *input,
     440             :                 vlib_cli_command_t *cmd)
     441             : {
     442           0 :   cnat_snat_exclude_pfx_table_t *excluded_pfx =
     443             :     &cnat_snat_policy_main.excluded_pfx;
     444           0 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     445           0 :   vnet_main_t *vnm = vnet_get_main ();
     446             :   u32 sw_if_index;
     447             : 
     448           0 :   vlib_cli_output (vm, "Source NAT\n  ip4: %U\n  ip6: %U\n\n",
     449             :                    format_cnat_endpoint, &cpm->snat_ip4, format_cnat_endpoint,
     450             :                    &cpm->snat_ip6);
     451           0 :   vlib_cli_output (vm, "Excluded prefixes:\n  %U\n", format_bihash_24_8,
     452             :                    &excluded_pfx->ip_hash, 1);
     453             : 
     454           0 :   for (int i = 0; i < CNAT_N_SNAT_IF_MAP; i++)
     455             :     {
     456           0 :       vlib_cli_output (vm, "\n%U interfaces:\n",
     457             :                        format_cnat_snat_interface_map_type, i);
     458           0 :       clib_bitmap_foreach (sw_if_index, cpm->interface_maps[i])
     459           0 :         vlib_cli_output (vm, "  %U\n", format_vnet_sw_if_index_name, vnm,
     460             :                          sw_if_index);
     461             :     }
     462             : 
     463           0 :   return (NULL);
     464             : }
     465             : 
     466      245447 : VLIB_CLI_COMMAND (cnat_show_snat_command, static) = {
     467             :   .path = "show cnat snat-policy",
     468             :   .short_help = "show cnat snat-policy",
     469             :   .function = cnat_show_snat,
     470             : };
     471             : 
     472             : int
     473           4 : cnat_set_snat_policy (cnat_snat_policy_type_t policy)
     474             : {
     475           4 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     476           4 :   switch (policy)
     477             :     {
     478           0 :     case CNAT_SNAT_POLICY_NONE:
     479           0 :       cpm->snat_policy = cnat_snat_policy_none;
     480           0 :       break;
     481           4 :     case CNAT_SNAT_POLICY_IF_PFX:
     482           4 :       cpm->snat_policy = cnat_snat_policy_if_pfx;
     483           4 :       break;
     484           0 :     case CNAT_SNAT_POLICY_K8S:
     485           0 :       cpm->snat_policy = cnat_snat_policy_k8s;
     486           0 :       break;
     487           0 :     default:
     488           0 :       return 1;
     489             :     }
     490           4 :   return 0;
     491             : }
     492             : 
     493             : static clib_error_t *
     494           0 : cnat_snat_policy_set_cmd_fn (vlib_main_t *vm, unformat_input_t *input,
     495             :                              vlib_cli_command_t *cmd)
     496             : {
     497           0 :   cnat_snat_policy_type_t policy = CNAT_SNAT_POLICY_NONE;
     498           0 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     499             :     {
     500           0 :       if (unformat (input, "none"))
     501             :         ;
     502           0 :       else if (unformat (input, "if-pfx"))
     503           0 :         policy = CNAT_SNAT_POLICY_IF_PFX;
     504           0 :       else if (unformat (input, "k8s"))
     505           0 :         policy = CNAT_SNAT_POLICY_K8S;
     506             :       else
     507           0 :         return clib_error_return (0, "unknown input '%U'",
     508             :                                   format_unformat_error, input);
     509             :     }
     510             : 
     511           0 :   cnat_set_snat_policy (policy);
     512           0 :   return NULL;
     513             : }
     514             : 
     515      245447 : VLIB_CLI_COMMAND (cnat_snat_policy_set_cmd, static) = {
     516             :   .path = "set cnat snat-policy",
     517             :   .short_help = "set cnat snat-policy [none][if-pfx][k8s]",
     518             :   .function = cnat_snat_policy_set_cmd_fn,
     519             : };
     520             : 
     521             : static void
     522           8 : cnat_if_addr_add_del_snat_cb (addr_resolution_t *ar, ip_address_t *address,
     523             :                               u8 is_del)
     524             : {
     525           8 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     526             :   cnat_endpoint_t *ep;
     527             : 
     528           8 :   ep = AF_IP4 == ar->af ? &cpm->snat_ip4 : &cpm->snat_ip6;
     529             : 
     530           8 :   if (!is_del && ep->ce_flags & CNAT_EP_FLAG_RESOLVED)
     531           2 :     return;
     532             : 
     533           6 :   if (is_del)
     534             :     {
     535           4 :       ep->ce_flags &= ~CNAT_EP_FLAG_RESOLVED;
     536             :       /* Are there remaining addresses ? */
     537           4 :       if (0 == cnat_resolve_addr (ar->sw_if_index, ar->af, address))
     538           2 :         is_del = 0;
     539             :     }
     540             : 
     541           6 :   if (!is_del)
     542             :     {
     543           4 :       ip_address_copy (&ep->ce_ip, address);
     544           4 :       ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
     545             :     }
     546             : }
     547             : 
     548             : static clib_error_t *
     549         559 : cnat_snat_init (vlib_main_t *vm)
     550             : {
     551         559 :   cnat_snat_policy_main_t *cpm = &cnat_snat_policy_main;
     552         559 :   cnat_main_t *cm = &cnat_main;
     553         559 :   cnat_snat_exclude_pfx_table_t *excluded_pfx = &cpm->excluded_pfx;
     554             : 
     555             :   int i;
     556       72670 :   for (i = 0; i < ARRAY_LEN (excluded_pfx->ip_masks); i++)
     557             :     {
     558             :       u32 j, i0, i1;
     559             : 
     560       72111 :       i0 = i / 32;
     561       72111 :       i1 = i % 32;
     562             : 
     563      181675 :       for (j = 0; j < i0; j++)
     564      109564 :         excluded_pfx->ip_masks[i].as_u32[j] = ~0;
     565             : 
     566       72111 :       if (i1)
     567       69316 :         excluded_pfx->ip_masks[i].as_u32[i0] =
     568       69316 :           clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
     569             :     }
     570         559 :   clib_bihash_init_24_8 (&excluded_pfx->ip_hash, "snat prefixes",
     571             :                          cm->snat_hash_buckets, cm->snat_hash_memory);
     572         559 :   clib_bihash_set_kvp_format_fn_24_8 (&excluded_pfx->ip_hash,
     573             :                                       format_cnat_snat_prefix);
     574             : 
     575        2236 :   for (int i = 0; i < CNAT_N_SNAT_IF_MAP; i++)
     576        1677 :     clib_bitmap_validate (cpm->interface_maps[i], cm->snat_if_map_length);
     577             : 
     578         559 :   cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_SNAT,
     579             :                                          cnat_if_addr_add_del_snat_cb);
     580             : 
     581         559 :   cpm->snat_policy = cnat_snat_policy_none;
     582             : 
     583         559 :   return (NULL);
     584             : }
     585             : 
     586        3919 : VLIB_INIT_FUNCTION (cnat_snat_init);
     587             : 
     588             : /*
     589             :  * fd.io coding-style-patch-verification: ON
     590             :  *
     591             :  * Local Variables:
     592             :  * eval: (c-set-style "gnu")
     593             :  * End:
     594             :  */

Generated by: LCOV version 1.14