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

Generated by: LCOV version 1.14