LCOV - code coverage report
Current view: top level - plugins/cnat - cnat_src_policy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 57 73 78.1 %
Date: 2023-07-05 22:20:52 Functions: 7 8 87.5 %

          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 <cnat/cnat_src_policy.h>
      17             : #include <cnat/cnat_inline.h>
      18             : 
      19             : #include <cnat/cnat_session.h>
      20             : #include <cnat/cnat_translation.h>
      21             : 
      22             : cnat_src_policy_main_t cnat_src_policy_main;
      23             : 
      24             : void
      25           0 : cnat_register_vip_src_policy (cnat_vip_source_policy_t fp)
      26             : {
      27           0 :   cnat_src_policy_main.vip_policy = fp;
      28           0 : }
      29             : 
      30             : cnat_source_policy_errors_t
      31         348 : cnat_vip_default_source_policy (vlib_main_t * vm,
      32             :                                 vlib_buffer_t * b,
      33             :                                 cnat_session_t * session,
      34             :                                 u32 * rsession_flags,
      35             :                                 const cnat_translation_t * ct,
      36             :                                 cnat_node_ctx_t * ctx)
      37             : {
      38             :   ip_protocol_t iproto;
      39             :   udp_header_t *udp0;
      40             :   ip4_header_t *ip4;
      41             :   ip6_header_t *ip6;
      42             : 
      43         348 :   if (AF_IP4 == ctx->af)
      44             :     {
      45         174 :       ip4 = vlib_buffer_get_current (b);
      46         174 :       iproto = ip4->protocol;
      47         174 :       udp0 = (udp_header_t *) (ip4 + 1);
      48             :     }
      49             :   else
      50             :     {
      51         174 :       ip6 = vlib_buffer_get_current (b);
      52         174 :       iproto = ip6->protocol;
      53         174 :       udp0 = (udp_header_t *) (ip6 + 1);
      54             :     }
      55             : 
      56         348 :   int rv = 0;
      57         348 :   if (!session->value.cs_port[VLIB_RX])
      58             :     {
      59             :       u16 sport;
      60         348 :       sport = udp0->src_port;
      61             :       /* Allocate a port only if asked and if we actually sNATed */
      62         348 :       if ((ct->flags & CNAT_TRANSLATION_FLAG_ALLOCATE_PORT)
      63           0 :           && (*rsession_flags & CNAT_SESSION_FLAG_HAS_SNAT))
      64             :         {
      65           0 :           sport = 0;            /* force allocation */
      66           0 :           session->value.flags |= CNAT_SESSION_FLAG_ALLOC_PORT;
      67           0 :           rv = cnat_allocate_port (&sport, iproto);
      68           0 :           if (rv)
      69           0 :             return CNAT_SOURCE_ERROR_EXHAUSTED_PORTS;
      70             :         }
      71             : 
      72         348 :       session->value.cs_port[VLIB_RX] = sport;
      73             :     }
      74         348 :   return 0;
      75             : }
      76             : 
      77             : always_inline cnat_src_port_allocator_t *
      78          40 : cnat_get_src_port_allocator (ip_protocol_t iproto)
      79             : {
      80          40 :   cnat_src_policy_main_t *cspm = &cnat_src_policy_main;
      81          40 :   switch (iproto)
      82             :     {
      83          16 :     case IP_PROTOCOL_TCP:
      84          16 :       return &cspm->src_ports[CNAT_SPORT_PROTO_TCP];
      85          16 :     case IP_PROTOCOL_UDP:
      86          16 :       return &cspm->src_ports[CNAT_SPORT_PROTO_UDP];
      87           2 :     case IP_PROTOCOL_ICMP:
      88           2 :       return &cspm->src_ports[CNAT_SPORT_PROTO_ICMP];
      89           6 :     case IP_PROTOCOL_ICMP6:
      90           6 :       return &cspm->src_ports[CNAT_SPORT_PROTO_ICMP6];
      91           0 :     default:
      92           0 :       return 0;
      93             :     }
      94             : }
      95             : 
      96             : void
      97          20 : cnat_free_port (u16 port, ip_protocol_t iproto)
      98             : {
      99             :   cnat_src_port_allocator_t *ca;
     100          20 :   ca = cnat_get_src_port_allocator (iproto);
     101          20 :   if (!ca)
     102           0 :     return;
     103          20 :   clib_spinlock_lock (&ca->lock);
     104          20 :   clib_bitmap_set_no_check (ca->bmap, port, 0);
     105          20 :   clib_spinlock_unlock (&ca->lock);
     106             : }
     107             : 
     108             : int
     109          20 : cnat_allocate_port (u16 * port, ip_protocol_t iproto)
     110             : {
     111          20 :   *port = clib_net_to_host_u16 (*port);
     112          20 :   if (*port == 0)
     113          20 :     *port = MIN_SRC_PORT;
     114             :   cnat_src_port_allocator_t *ca;
     115          20 :   ca = cnat_get_src_port_allocator (iproto);
     116          20 :   if (!ca)
     117           0 :     return -1;
     118          20 :   clib_spinlock_lock (&ca->lock);
     119          20 :   if (clib_bitmap_get_no_check (ca->bmap, *port))
     120             :     {
     121          16 :       *port = clib_bitmap_next_clear (ca->bmap, *port);
     122          16 :       if (PREDICT_FALSE (*port >= UINT16_MAX))
     123           0 :         *port = clib_bitmap_next_clear (ca->bmap, MIN_SRC_PORT);
     124          16 :       if (PREDICT_FALSE (*port >= UINT16_MAX))
     125             :         {
     126           0 :           clib_spinlock_unlock (&ca->lock);
     127           0 :           return -1;
     128             :         }
     129             :     }
     130          20 :   clib_bitmap_set_no_check (ca->bmap, *port, 1);
     131          20 :   *port = clib_host_to_net_u16 (*port);
     132          20 :   clib_spinlock_unlock (&ca->lock);
     133          20 :   return 0;
     134             : }
     135             : 
     136             : static clib_error_t *
     137         559 : cnat_src_policy_init (vlib_main_t * vm)
     138             : {
     139         559 :   cnat_src_policy_main_t *cspm = &cnat_src_policy_main;
     140         559 :   cspm->vip_policy = cnat_vip_default_source_policy;
     141         559 :   cspm->default_policy = cnat_vip_default_source_policy;
     142             : 
     143         559 :   vec_validate (cspm->src_ports, CNAT_N_SPORT_PROTO);
     144        2795 :   for (int i = 0; i < CNAT_N_SPORT_PROTO; i++)
     145             :     {
     146        2236 :       clib_spinlock_init (&cspm->src_ports[i].lock);
     147        2236 :       clib_bitmap_validate (cspm->src_ports[i].bmap, UINT16_MAX);
     148             :     }
     149             :   /* Inject cleanup callback */
     150         559 :   cnat_free_port_cb = cnat_free_port;
     151         559 :   return (NULL);
     152             : }
     153             : 
     154        4479 : VLIB_INIT_FUNCTION (cnat_src_policy_init);
     155             : 
     156             : /*
     157             :  * fd.io coding-style-patch-verification: ON
     158             :  *
     159             :  * Local Variables:
     160             :  * eval: (c-set-style "gnu")
     161             :  * End:
     162             :  */

Generated by: LCOV version 1.14