LCOV - code coverage report
Current view: top level - plugins/nat/nat64 - nat64_out2in.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 233 338 68.9 %
Date: 2023-10-26 01:39:38 Functions: 18 26 69.2 %

          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 <nat/nat64/nat64.h>
      17             : #include <vnet/ip/ip4_to_ip6.h>
      18             : #include <vnet/fib/ip4_fib.h>
      19             : #include <vnet/udp/udp_local.h>
      20             : 
      21             : typedef struct
      22             : {
      23             :   u32 sw_if_index;
      24             :   u32 next_index;
      25             : } nat64_out2in_trace_t;
      26             : 
      27             : static u8 *
      28          23 : format_nat64_out2in_trace (u8 * s, va_list * args)
      29             : {
      30          23 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      31          23 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      32          23 :   nat64_out2in_trace_t *t = va_arg (*args, nat64_out2in_trace_t *);
      33             : 
      34             :   s =
      35          23 :     format (s, "NAT64-out2in: sw_if_index %d, next index %d", t->sw_if_index,
      36             :             t->next_index);
      37             : 
      38          23 :   return s;
      39             : }
      40             : 
      41             : #define foreach_nat64_out2in_error                       \
      42             : _(UNSUPPORTED_PROTOCOL, "unsupported protocol")          \
      43             : _(NO_TRANSLATION, "no translation")                      \
      44             : _(UNKNOWN, "unknown")
      45             : 
      46             : typedef enum
      47             : {
      48             : #define _(sym,str) NAT64_OUT2IN_ERROR_##sym,
      49             :   foreach_nat64_out2in_error
      50             : #undef _
      51             :     NAT64_OUT2IN_N_ERROR,
      52             : } nat64_out2in_error_t;
      53             : 
      54             : static char *nat64_out2in_error_strings[] = {
      55             : #define _(sym,string) string,
      56             :   foreach_nat64_out2in_error
      57             : #undef _
      58             : };
      59             : 
      60             : typedef enum
      61             : {
      62             :   NAT64_OUT2IN_NEXT_IP6_LOOKUP,
      63             :   NAT64_OUT2IN_NEXT_IP4_LOOKUP,
      64             :   NAT64_OUT2IN_NEXT_DROP,
      65             :   NAT64_OUT2IN_N_NEXT,
      66             : } nat64_out2in_next_t;
      67             : 
      68             : typedef struct nat64_out2in_set_ctx_t_
      69             : {
      70             :   vlib_buffer_t *b;
      71             :   vlib_main_t *vm;
      72             :   u32 thread_index;
      73             : } nat64_out2in_set_ctx_t;
      74             : 
      75             : static int
      76          28 : nat64_out2in_tcp_udp (vlib_main_t * vm, vlib_buffer_t * b,
      77             :                       nat64_out2in_set_ctx_t * ctx)
      78             : {
      79             :   ip4_header_t *ip4;
      80             :   ip6_header_t *ip6;
      81             :   ip_csum_t csum;
      82          28 :   u16 *checksum = NULL;
      83             :   ip6_frag_hdr_t *frag;
      84             :   u32 frag_id;
      85             :   ip4_address_t old_src, old_dst;
      86             : 
      87          28 :   nat64_main_t *nm = &nat64_main;
      88             :   nat64_db_bib_entry_t *bibe;
      89             :   nat64_db_st_entry_t *ste;
      90             :   ip46_address_t saddr;
      91             :   ip46_address_t daddr;
      92             :   ip6_address_t ip6_saddr;
      93          28 :   u8 proto = vnet_buffer (b)->ip.reass.ip_proto;
      94          28 :   u16 dport = vnet_buffer (b)->ip.reass.l4_dst_port;
      95          28 :   u16 sport = vnet_buffer (b)->ip.reass.l4_src_port;
      96             :   u32 sw_if_index, fib_index;
      97          28 :   nat64_db_t *db = &nm->db[ctx->thread_index];
      98             : 
      99          28 :   ip4 = vlib_buffer_get_current (b);
     100             : 
     101          28 :   udp_header_t *udp = ip4_next_header (ip4);
     102          28 :   tcp_header_t *tcp = ip4_next_header (ip4);
     103          28 :   if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
     104             :     {
     105          24 :       if (ip4->protocol == IP_PROTOCOL_UDP)
     106             :         {
     107           7 :           checksum = &udp->checksum;
     108             :           //UDP checksum is optional over IPv4 but mandatory for IPv6
     109             :           //We do not check udp->length sanity but use our safe computed value instead
     110           7 :           if (PREDICT_FALSE (!*checksum))
     111             :             {
     112           0 :               u16 udp_len =
     113           0 :                 clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
     114           0 :               csum = ip_incremental_checksum (0, udp, udp_len);
     115             :               csum =
     116           0 :                 ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
     117             :               csum =
     118           0 :                 ip_csum_with_carry (csum,
     119           0 :                                     clib_host_to_net_u16 (IP_PROTOCOL_UDP));
     120             :               csum =
     121           0 :                 ip_csum_with_carry (csum, *((u64 *) (&ip4->src_address)));
     122           0 :               *checksum = ~ip_csum_fold (csum);
     123             :             }
     124             :         }
     125             :       else
     126             :         {
     127          17 :           checksum = &tcp->checksum;
     128             :         }
     129             :     }
     130             : 
     131          28 :   old_src.as_u32 = ip4->src_address.as_u32;
     132          28 :   old_dst.as_u32 = ip4->dst_address.as_u32;
     133             : 
     134             :   // Deal with fragmented packets
     135          28 :   u16 frag_offset = ip4_get_fragment_offset (ip4);
     136          28 :   if (PREDICT_FALSE (ip4_get_fragment_more (ip4) || frag_offset))
     137             :     {
     138           6 :       ip6 =
     139             :         (ip6_header_t *) u8_ptr_add (ip4,
     140             :                                      sizeof (*ip4) - sizeof (*ip6) -
     141             :                                      sizeof (*frag));
     142           6 :       frag =
     143             :         (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
     144           6 :       frag_id = frag_id_4to6 (ip4->fragment_id);
     145           6 :       vlib_buffer_advance (b, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
     146             :     }
     147             :   else
     148             :     {
     149          22 :       ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
     150          22 :       vlib_buffer_advance (b, sizeof (*ip4) - sizeof (*ip6));
     151          22 :       frag = NULL;
     152             :     }
     153             : 
     154          28 :   ip6->ip_version_traffic_class_and_flow_label =
     155          28 :     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
     156          28 :   ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
     157          28 :   ip6->hop_limit = ip4->ttl;
     158          28 :   ip6->protocol = ip4->protocol;
     159             : 
     160          28 :   sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
     161          28 :   fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
     162             : 
     163          28 :   clib_memset (&saddr, 0, sizeof (saddr));
     164          28 :   saddr.ip4.as_u32 = ip4->src_address.as_u32;
     165          28 :   clib_memset (&daddr, 0, sizeof (daddr));
     166          28 :   daddr.ip4.as_u32 = ip4->dst_address.as_u32;
     167             : 
     168             :   ste =
     169          28 :     nat64_db_st_entry_find (db, &daddr, &saddr, dport, sport, proto,
     170             :                             fib_index, 0);
     171          28 :   if (ste)
     172             :     {
     173          28 :       bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
     174          28 :       if (!bibe)
     175           0 :         return -1;
     176             :     }
     177             :   else
     178             :     {
     179           0 :       bibe = nat64_db_bib_entry_find (db, &daddr, dport, proto, fib_index, 0);
     180             : 
     181           0 :       if (!bibe)
     182           0 :         return -1;
     183             : 
     184           0 :       nat64_compose_ip6 (&ip6_saddr, &old_src, bibe->fib_index);
     185             :       ste =
     186           0 :         nat64_db_st_entry_create (ctx->thread_index, db, bibe, &ip6_saddr,
     187             :                                   &saddr.ip4, sport);
     188             : 
     189           0 :       if (!ste)
     190           0 :         return -1;
     191             : 
     192           0 :       vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
     193           0 :                                db->st.st_entries_num);
     194             :     }
     195             : 
     196          28 :   ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
     197          28 :   ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
     198             : 
     199          28 :   ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
     200          28 :   ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
     201             : 
     202          28 :   vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
     203             : 
     204          28 :   nat64_session_reset_timeout (ste, ctx->vm);
     205             : 
     206          28 :   if (PREDICT_FALSE (frag != NULL))
     207             :     {
     208           6 :       frag->next_hdr = ip6->protocol;
     209           6 :       frag->identification = frag_id;
     210           6 :       frag->rsv = 0;
     211           6 :       frag->fragment_offset_and_more =
     212           6 :         ip6_frag_hdr_offset_and_more (frag_offset, 1);
     213           6 :       ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
     214           6 :       ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
     215             :     }
     216             : 
     217          28 :   if (!vnet_buffer (b)->ip.reass.is_non_first_fragment)
     218             :     {
     219          24 :       udp->dst_port = bibe->in_port;
     220             : 
     221          24 :       if (proto == IP_PROTOCOL_TCP)
     222             :         {
     223          17 :           nat64_tcp_session_set_state (ste, tcp, 0);
     224             :         }
     225             : 
     226          24 :       csum = ip_csum_sub_even (*checksum, dport);
     227          24 :       csum = ip_csum_add_even (csum, udp->dst_port);
     228          24 :       csum = ip_csum_sub_even (csum, old_src.as_u32);
     229          24 :       csum = ip_csum_sub_even (csum, old_dst.as_u32);
     230          24 :       csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
     231          24 :       csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
     232          24 :       csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
     233          24 :       csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
     234          24 :       *checksum = ip_csum_fold (csum);
     235             :     }
     236             : 
     237          28 :   return 0;
     238             : }
     239             : 
     240             : static int
     241          10 : nat64_out2in_icmp_set_cb (vlib_buffer_t * b, ip4_header_t * ip4,
     242             :                           ip6_header_t * ip6, void *arg)
     243             : {
     244          10 :   nat64_main_t *nm = &nat64_main;
     245          10 :   nat64_out2in_set_ctx_t *ctx = arg;
     246             :   nat64_db_bib_entry_t *bibe;
     247             :   nat64_db_st_entry_t *ste;
     248             :   ip46_address_t saddr, daddr;
     249             :   ip6_address_t ip6_saddr;
     250             :   u32 sw_if_index, fib_index;
     251          10 :   icmp46_header_t *icmp = ip4_next_header (ip4);
     252          10 :   nat64_db_t *db = &nm->db[ctx->thread_index];
     253             : 
     254          10 :   sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
     255          10 :   fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
     256             : 
     257          10 :   clib_memset (&saddr, 0, sizeof (saddr));
     258          10 :   saddr.ip4.as_u32 = ip4->src_address.as_u32;
     259          10 :   clib_memset (&daddr, 0, sizeof (daddr));
     260          10 :   daddr.ip4.as_u32 = ip4->dst_address.as_u32;
     261             : 
     262          10 :   if (icmp->type == ICMP6_echo_request || icmp->type == ICMP6_echo_reply)
     263           7 :     {
     264           7 :       u16 out_id = ((u16 *) (icmp))[2];
     265             :       ste =
     266           7 :         nat64_db_st_entry_find (db, &daddr, &saddr, out_id, 0,
     267             :                                 IP_PROTOCOL_ICMP, fib_index, 0);
     268             : 
     269           7 :       if (ste)
     270             :         {
     271             :           bibe =
     272           7 :             nat64_db_bib_entry_by_index (db, IP_PROTOCOL_ICMP,
     273             :                                          ste->bibe_index);
     274           7 :           if (!bibe)
     275           0 :             return -1;
     276             :         }
     277             :       else
     278             :         {
     279             :           bibe =
     280           0 :             nat64_db_bib_entry_find (db, &daddr, out_id,
     281             :                                      IP_PROTOCOL_ICMP, fib_index, 0);
     282           0 :           if (!bibe)
     283           0 :             return -1;
     284             : 
     285           0 :           nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
     286             :           ste =
     287           0 :             nat64_db_st_entry_create (ctx->thread_index, db,
     288             :                                       bibe, &ip6_saddr, &saddr.ip4, 0);
     289             : 
     290           0 :           if (!ste)
     291           0 :             return -1;
     292             : 
     293           0 :           vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
     294           0 :                                    db->st.st_entries_num);
     295             :         }
     296             : 
     297           7 :       nat64_session_reset_timeout (ste, ctx->vm);
     298             : 
     299           7 :       ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
     300           7 :       ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
     301             : 
     302           7 :       ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
     303           7 :       ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
     304           7 :       ((u16 *) (icmp))[2] = bibe->in_port;
     305             : 
     306           7 :       vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
     307             :     }
     308             :   else
     309             :     {
     310           3 :       ip6_header_t *inner_ip6 = (ip6_header_t *) u8_ptr_add (icmp, 8);
     311             : 
     312           3 :       nat64_compose_ip6 (&ip6->src_address, &ip4->src_address,
     313           3 :                          vnet_buffer (ctx->b)->sw_if_index[VLIB_TX]);
     314           3 :       ip6->dst_address.as_u64[0] = inner_ip6->src_address.as_u64[0];
     315           3 :       ip6->dst_address.as_u64[1] = inner_ip6->src_address.as_u64[1];
     316             :     }
     317             : 
     318          10 :   return 0;
     319             : }
     320             : 
     321             : static int
     322           3 : nat64_out2in_inner_icmp_set_cb (vlib_buffer_t * b, ip4_header_t * ip4,
     323             :                                 ip6_header_t * ip6, void *arg)
     324             : {
     325           3 :   nat64_main_t *nm = &nat64_main;
     326           3 :   nat64_out2in_set_ctx_t *ctx = arg;
     327             :   nat64_db_bib_entry_t *bibe;
     328             :   nat64_db_st_entry_t *ste;
     329             :   ip46_address_t saddr, daddr;
     330             :   u32 sw_if_index, fib_index;
     331           3 :   u8 proto = ip4->protocol;
     332           3 :   nat64_db_t *db = &nm->db[ctx->thread_index];
     333             : 
     334           3 :   sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
     335             :   fib_index =
     336           3 :     fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP6, sw_if_index);
     337             : 
     338           3 :   clib_memset (&saddr, 0, sizeof (saddr));
     339           3 :   saddr.ip4.as_u32 = ip4->src_address.as_u32;
     340           3 :   clib_memset (&daddr, 0, sizeof (daddr));
     341           3 :   daddr.ip4.as_u32 = ip4->dst_address.as_u32;
     342             : 
     343           3 :   if (proto == IP_PROTOCOL_ICMP6)
     344             :     {
     345           1 :       icmp46_header_t *icmp = ip4_next_header (ip4);
     346           1 :       u16 out_id = ((u16 *) (icmp))[2];
     347           1 :       proto = IP_PROTOCOL_ICMP;
     348             : 
     349           1 :       if (!
     350           1 :           (icmp->type == ICMP6_echo_request
     351           0 :            || icmp->type == ICMP6_echo_reply))
     352           0 :         return -1;
     353             : 
     354             :       ste =
     355           1 :         nat64_db_st_entry_find (db, &saddr, &daddr, out_id, 0, proto,
     356             :                                 fib_index, 0);
     357           1 :       if (!ste)
     358           0 :         return -1;
     359             : 
     360           1 :       bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
     361           1 :       if (!bibe)
     362           0 :         return -1;
     363             : 
     364           1 :       ip6->dst_address.as_u64[0] = ste->in_r_addr.as_u64[0];
     365           1 :       ip6->dst_address.as_u64[1] = ste->in_r_addr.as_u64[1];
     366           1 :       ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
     367           1 :       ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
     368           1 :       ((u16 *) (icmp))[2] = bibe->in_port;
     369             : 
     370           1 :       vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
     371             :     }
     372             :   else
     373             :     {
     374           2 :       udp_header_t *udp = ip4_next_header (ip4);
     375           2 :       tcp_header_t *tcp = ip4_next_header (ip4);
     376           2 :       u16 dport = udp->dst_port;
     377           2 :       u16 sport = udp->src_port;
     378             :       u16 *checksum;
     379             :       ip_csum_t csum;
     380             : 
     381             :       ste =
     382           2 :         nat64_db_st_entry_find (db, &saddr, &daddr, sport, dport, proto,
     383             :                                 fib_index, 0);
     384           2 :       if (!ste)
     385           0 :         return -1;
     386             : 
     387           2 :       bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
     388           2 :       if (!bibe)
     389           0 :         return -1;
     390             : 
     391           2 :       nat64_compose_ip6 (&ip6->dst_address, &daddr.ip4, bibe->fib_index);
     392           2 :       ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
     393           2 :       ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
     394           2 :       udp->src_port = bibe->in_port;
     395             : 
     396           2 :       if (proto == IP_PROTOCOL_UDP)
     397           1 :         checksum = &udp->checksum;
     398             :       else
     399           1 :         checksum = &tcp->checksum;
     400           2 :       if (*checksum)
     401             :         {
     402           1 :           csum = ip_csum_sub_even (*checksum, sport);
     403           1 :           csum = ip_csum_add_even (csum, udp->src_port);
     404           1 :           *checksum = ip_csum_fold (csum);
     405             :         }
     406             : 
     407           2 :       vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
     408             :     }
     409             : 
     410           3 :   return 0;
     411             : }
     412             : 
     413             : static int
     414           1 : nat64_out2in_unk_proto (vlib_main_t * vm, vlib_buffer_t * p,
     415             :                         nat64_out2in_set_ctx_t * ctx)
     416             : {
     417           1 :   ip4_header_t *ip4 = vlib_buffer_get_current (p);
     418             :   ip6_header_t *ip6;
     419             :   ip6_frag_hdr_t *frag;
     420             :   u32 frag_id;
     421             : 
     422           1 :   nat64_main_t *nm = &nat64_main;
     423             :   nat64_db_bib_entry_t *bibe;
     424             :   nat64_db_st_entry_t *ste;
     425             :   ip46_address_t saddr, daddr;
     426             :   ip6_address_t ip6_saddr;
     427             :   u32 sw_if_index, fib_index;
     428           1 :   u8 proto = ip4->protocol;
     429           1 :   nat64_db_t *db = &nm->db[ctx->thread_index];
     430             : 
     431             :   // Deal with fragmented packets
     432           1 :   u16 frag_offset = ip4_get_fragment_offset (ip4);
     433           1 :   if (PREDICT_FALSE (ip4_get_fragment_more (ip4) || frag_offset))
     434             :     {
     435           0 :       ip6 =
     436             :         (ip6_header_t *) u8_ptr_add (ip4,
     437             :                                      sizeof (*ip4) - sizeof (*ip6) -
     438             :                                      sizeof (*frag));
     439           0 :       frag =
     440             :         (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
     441           0 :       frag_id = frag_id_4to6 (ip4->fragment_id);
     442           0 :       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
     443             :     }
     444             :   else
     445             :     {
     446           1 :       ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
     447           1 :       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
     448           1 :       frag = NULL;
     449             :     }
     450             : 
     451           1 :   ip6->ip_version_traffic_class_and_flow_label =
     452           1 :     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
     453           1 :   ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
     454           1 :   ip6->hop_limit = ip4->ttl;
     455           1 :   ip6->protocol = ip4->protocol;
     456             : 
     457           1 :   if (PREDICT_FALSE (frag != NULL))
     458             :     {
     459           0 :       frag->next_hdr = ip6->protocol;
     460           0 :       frag->identification = frag_id;
     461           0 :       frag->rsv = 0;
     462           0 :       frag->fragment_offset_and_more =
     463           0 :         ip6_frag_hdr_offset_and_more (frag_offset, 1);
     464           0 :       ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
     465           0 :       ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
     466             :     }
     467             : 
     468           1 :   sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
     469           1 :   fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
     470             : 
     471           1 :   clib_memset (&saddr, 0, sizeof (saddr));
     472           1 :   saddr.ip4.as_u32 = ip4->src_address.as_u32;
     473           1 :   clib_memset (&daddr, 0, sizeof (daddr));
     474           1 :   daddr.ip4.as_u32 = ip4->dst_address.as_u32;
     475             : 
     476             :   ste =
     477           1 :     nat64_db_st_entry_find (db, &daddr, &saddr, 0, 0, proto, fib_index, 0);
     478           1 :   if (ste)
     479             :     {
     480           1 :       bibe = nat64_db_bib_entry_by_index (db, proto, ste->bibe_index);
     481           1 :       if (!bibe)
     482           0 :         return -1;
     483             :     }
     484             :   else
     485             :     {
     486           0 :       bibe = nat64_db_bib_entry_find (db, &daddr, 0, proto, fib_index, 0);
     487             : 
     488           0 :       if (!bibe)
     489           0 :         return -1;
     490             : 
     491           0 :       nat64_compose_ip6 (&ip6_saddr, &ip4->src_address, bibe->fib_index);
     492           0 :       ste = nat64_db_st_entry_create (ctx->thread_index, db,
     493             :                                       bibe, &ip6_saddr, &saddr.ip4, 0);
     494             : 
     495           0 :       if (!ste)
     496           0 :         return -1;
     497             : 
     498           0 :       vlib_set_simple_counter (&nm->total_sessions, ctx->thread_index, 0,
     499           0 :                                db->st.st_entries_num);
     500             :     }
     501             : 
     502           1 :   nat64_session_reset_timeout (ste, ctx->vm);
     503             : 
     504           1 :   ip6->src_address.as_u64[0] = ste->in_r_addr.as_u64[0];
     505           1 :   ip6->src_address.as_u64[1] = ste->in_r_addr.as_u64[1];
     506             : 
     507           1 :   ip6->dst_address.as_u64[0] = bibe->in_addr.as_u64[0];
     508           1 :   ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
     509             : 
     510           1 :   vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
     511             : 
     512           1 :   return 0;
     513             : }
     514             : 
     515        2312 : VLIB_NODE_FN (nat64_out2in_node) (vlib_main_t * vm,
     516             :                                   vlib_node_runtime_t * node,
     517             :                                   vlib_frame_t * frame)
     518             : {
     519             :   u32 n_left_from, *from, *to_next;
     520             :   nat64_out2in_next_t next_index;
     521          12 :   nat64_main_t *nm = &nat64_main;
     522          12 :   u32 thread_index = vm->thread_index;
     523             : 
     524          12 :   from = vlib_frame_vector_args (frame);
     525          12 :   n_left_from = frame->n_vectors;
     526          12 :   next_index = node->cached_next_index;
     527          24 :   while (n_left_from > 0)
     528             :     {
     529             :       u32 n_left_to_next;
     530             : 
     531          12 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     532             : 
     533          51 :       while (n_left_from > 0 && n_left_to_next > 0)
     534             :         {
     535             :           u32 bi0;
     536             :           vlib_buffer_t *b0;
     537             :           u32 next0;
     538             :           ip4_header_t *ip40;
     539             :           u32 proto0;
     540             :           nat64_out2in_set_ctx_t ctx0;
     541             :           udp_header_t *udp0;
     542             :           u32 sw_if_index0;
     543             : 
     544             :           /* speculatively enqueue b0 to the current next frame */
     545          39 :           bi0 = from[0];
     546          39 :           to_next[0] = bi0;
     547          39 :           from += 1;
     548          39 :           to_next += 1;
     549          39 :           n_left_from -= 1;
     550          39 :           n_left_to_next -= 1;
     551             : 
     552          39 :           b0 = vlib_get_buffer (vm, bi0);
     553          39 :           ip40 = vlib_buffer_get_current (b0);
     554             : 
     555          39 :           ctx0.b = b0;
     556          39 :           ctx0.vm = vm;
     557          39 :           ctx0.thread_index = thread_index;
     558             : 
     559          39 :           next0 = NAT64_OUT2IN_NEXT_IP6_LOOKUP;
     560             : 
     561          39 :           proto0 = ip_proto_to_nat_proto (ip40->protocol);
     562          39 :           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     563          39 :           if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
     564             :             {
     565           1 :               if (nat64_out2in_unk_proto (vm, b0, &ctx0))
     566             :                 {
     567           0 :                   next0 = NAT64_OUT2IN_NEXT_DROP;
     568           0 :                   b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
     569             :                 }
     570           1 :               vlib_increment_simple_counter (&nm->counters.out2in.other,
     571             :                                              thread_index, sw_if_index0, 1);
     572           1 :               goto trace0;
     573             :             }
     574             : 
     575          38 :           if (proto0 == NAT_PROTOCOL_ICMP)
     576             :             {
     577          10 :               vlib_increment_simple_counter (&nm->counters.out2in.icmp,
     578             :                                              thread_index, sw_if_index0, 1);
     579          10 :               if (icmp_to_icmp6
     580             :                   (b0, nat64_out2in_icmp_set_cb, &ctx0,
     581             :                    nat64_out2in_inner_icmp_set_cb, &ctx0))
     582             :                 {
     583           0 :                   next0 = NAT64_OUT2IN_NEXT_DROP;
     584           0 :                   b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
     585           0 :                   goto trace0;
     586             :                 }
     587             :             }
     588             :           else
     589             :             {
     590          28 :               if (proto0 == NAT_PROTOCOL_TCP)
     591          21 :                 vlib_increment_simple_counter (&nm->counters.out2in.tcp,
     592             :                                                thread_index, sw_if_index0, 1);
     593             :               else
     594           7 :                 vlib_increment_simple_counter (&nm->counters.out2in.udp,
     595             :                                                thread_index, sw_if_index0, 1);
     596             : 
     597          28 :               if (nat64_out2in_tcp_udp (vm, b0, &ctx0))
     598             :                 {
     599           0 :                   udp0 = ip4_next_header (ip40);
     600             :                   /*
     601             :                    * Send DHCP packets to the ipv4 stack, or we won't
     602             :                    * be able to use dhcp client on the outside interface
     603             :                    */
     604           0 :                   if ((proto0 == NAT_PROTOCOL_UDP)
     605           0 :                       && (udp0->dst_port ==
     606           0 :                           clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client)))
     607             :                     {
     608           0 :                       next0 = NAT64_OUT2IN_NEXT_IP4_LOOKUP;
     609           0 :                       goto trace0;
     610             :                     }
     611           0 :                   next0 = NAT64_OUT2IN_NEXT_DROP;
     612           0 :                   b0->error = node->errors[NAT64_OUT2IN_ERROR_NO_TRANSLATION];
     613           0 :                   goto trace0;
     614             :                 }
     615             :             }
     616             : 
     617          28 :         trace0:
     618          39 :           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
     619             :                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
     620             :             {
     621             :               nat64_out2in_trace_t *t =
     622          39 :                 vlib_add_trace (vm, node, b0, sizeof (*t));
     623          39 :               t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
     624          39 :               t->next_index = next0;
     625             :             }
     626             : 
     627          39 :           if (next0 == NAT64_OUT2IN_NEXT_DROP)
     628             :             {
     629           0 :               vlib_increment_simple_counter (&nm->counters.out2in.drops,
     630             :                                              thread_index, sw_if_index0, 1);
     631             :             }
     632             : 
     633             :           /* verify speculative enqueue, maybe switch current next frame */
     634          39 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     635             :                                            n_left_to_next, bi0, next0);
     636             :         }
     637          12 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     638             :     }
     639          12 :   return frame->n_vectors;
     640             : }
     641             : 
     642             : /* *INDENT-OFF* */
     643       67994 : VLIB_REGISTER_NODE (nat64_out2in_node) = {
     644             :   .name = "nat64-out2in",
     645             :   .vector_size = sizeof (u32),
     646             :   .format_trace = format_nat64_out2in_trace,
     647             :   .type = VLIB_NODE_TYPE_INTERNAL,
     648             :   .n_errors = ARRAY_LEN (nat64_out2in_error_strings),
     649             :   .error_strings = nat64_out2in_error_strings,
     650             :   .n_next_nodes = NAT64_OUT2IN_N_NEXT,
     651             :   /* edit / add dispositions here */
     652             :   .next_nodes = {
     653             :     [NAT64_OUT2IN_NEXT_DROP] = "error-drop",
     654             :     [NAT64_OUT2IN_NEXT_IP6_LOOKUP] = "ip6-lookup",
     655             :     [NAT64_OUT2IN_NEXT_IP4_LOOKUP] = "ip4-lookup",
     656             :   },
     657             : };
     658             : /* *INDENT-ON* */
     659             : 
     660             : typedef struct nat64_out2in_frag_set_ctx_t_
     661             : {
     662             :   vlib_main_t *vm;
     663             :   vlib_buffer_t *b;
     664             :   u32 sess_index;
     665             :   u32 thread_index;
     666             :   u8 proto;
     667             :   u8 first_frag;
     668             : } nat64_out2in_frag_set_ctx_t;
     669             : 
     670             : #define foreach_nat64_out2in_handoff_error                       \
     671             : _(CONGESTION_DROP, "congestion drop")                            \
     672             : _(SAME_WORKER, "same worker")                                    \
     673             : _(DO_HANDOFF, "do handoff")
     674             : 
     675             : typedef enum
     676             : {
     677             : #define _(sym,str) NAT64_OUT2IN_HANDOFF_ERROR_##sym,
     678             :   foreach_nat64_out2in_handoff_error
     679             : #undef _
     680             :     NAT64_OUT2IN_HANDOFF_N_ERROR,
     681             : } nat64_out2in_handoff_error_t;
     682             : 
     683             : static char *nat64_out2in_handoff_error_strings[] = {
     684             : #define _(sym,string) string,
     685             :   foreach_nat64_out2in_handoff_error
     686             : #undef _
     687             : };
     688             : 
     689             : typedef struct
     690             : {
     691             :   u32 next_worker_index;
     692             : } nat64_out2in_handoff_trace_t;
     693             : 
     694             : static u8 *
     695           0 : format_nat64_out2in_handoff_trace (u8 * s, va_list * args)
     696             : {
     697           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
     698           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
     699           0 :   nat64_out2in_handoff_trace_t *t =
     700             :     va_arg (*args, nat64_out2in_handoff_trace_t *);
     701             : 
     702             :   s =
     703           0 :     format (s, "NAT64-OUT2IN-HANDOFF: next-worker %d", t->next_worker_index);
     704             : 
     705           0 :   return s;
     706             : }
     707             : 
     708        2300 : VLIB_NODE_FN (nat64_out2in_handoff_node) (vlib_main_t * vm,
     709             :                                           vlib_node_runtime_t * node,
     710             :                                           vlib_frame_t * frame)
     711             : {
     712           0 :   nat64_main_t *nm = &nat64_main;
     713             :   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
     714             :   u32 n_enq, n_left_from, *from;
     715             :   u16 thread_indices[VLIB_FRAME_SIZE], *ti;
     716             :   u32 fq_index;
     717           0 :   u32 thread_index = vm->thread_index;
     718           0 :   u32 do_handoff = 0, same_worker = 0;
     719             : 
     720           0 :   from = vlib_frame_vector_args (frame);
     721           0 :   n_left_from = frame->n_vectors;
     722           0 :   vlib_get_buffers (vm, from, bufs, n_left_from);
     723             : 
     724           0 :   b = bufs;
     725           0 :   ti = thread_indices;
     726             : 
     727           0 :   fq_index = nm->fq_out2in_index;
     728             : 
     729           0 :   while (n_left_from > 0)
     730             :     {
     731             :       ip4_header_t *ip0;
     732             : 
     733           0 :       ip0 = vlib_buffer_get_current (b[0]);
     734           0 :       ti[0] = nat64_get_worker_out2in (b[0], ip0);
     735             : 
     736           0 :       if (ti[0] != thread_index)
     737           0 :         do_handoff++;
     738             :       else
     739           0 :         same_worker++;
     740             : 
     741           0 :       if (PREDICT_FALSE
     742             :           ((node->flags & VLIB_NODE_FLAG_TRACE)
     743             :            && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
     744             :         {
     745             :           nat64_out2in_handoff_trace_t *t =
     746           0 :             vlib_add_trace (vm, node, b[0], sizeof (*t));
     747           0 :           t->next_worker_index = ti[0];
     748             :         }
     749             : 
     750           0 :       n_left_from -= 1;
     751           0 :       ti += 1;
     752           0 :       b += 1;
     753             :     }
     754             : 
     755           0 :   n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
     756           0 :                                          thread_indices, frame->n_vectors, 1);
     757             : 
     758           0 :   if (n_enq < frame->n_vectors)
     759           0 :     vlib_node_increment_counter (vm, node->node_index,
     760             :                                  NAT64_OUT2IN_HANDOFF_ERROR_CONGESTION_DROP,
     761           0 :                                  frame->n_vectors - n_enq);
     762           0 :   vlib_node_increment_counter (vm, node->node_index,
     763             :                                NAT64_OUT2IN_HANDOFF_ERROR_SAME_WORKER,
     764             :                                same_worker);
     765           0 :   vlib_node_increment_counter (vm, node->node_index,
     766             :                                NAT64_OUT2IN_HANDOFF_ERROR_DO_HANDOFF,
     767             :                                do_handoff);
     768             : 
     769           0 :   return frame->n_vectors;
     770             : }
     771             : 
     772             : /* *INDENT-OFF* */
     773       67994 : VLIB_REGISTER_NODE (nat64_out2in_handoff_node) = {
     774             :   .name = "nat64-out2in-handoff",
     775             :   .vector_size = sizeof (u32),
     776             :   .format_trace = format_nat64_out2in_handoff_trace,
     777             :   .type = VLIB_NODE_TYPE_INTERNAL,
     778             :   .n_errors = ARRAY_LEN(nat64_out2in_handoff_error_strings),
     779             :   .error_strings = nat64_out2in_handoff_error_strings,
     780             : 
     781             :   .n_next_nodes = 1,
     782             : 
     783             :   .next_nodes = {
     784             :     [0] = "error-drop",
     785             :   },
     786             : };
     787             : /* *INDENT-ON* */
     788             : 
     789             : /*
     790             :  * fd.io coding-style-patch-verification: ON
     791             :  *
     792             :  * Local Variables:
     793             :  * eval: (c-set-style "gnu")
     794             :  * End:
     795             :  */

Generated by: LCOV version 1.14