LCOV - code coverage report
Current view: top level - plugins/map - ip4_map_t.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 274 304 90.1 %
Date: 2023-10-26 01:39:38 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             : #include "map.h"
      16             : 
      17             : #include <vnet/ip/ip_frag.h>
      18             : #include <vnet/ip/ip4_to_ip6.h>
      19             : 
      20             : typedef enum
      21             : {
      22             :   IP4_MAPT_NEXT_MAPT_TCP_UDP,
      23             :   IP4_MAPT_NEXT_MAPT_ICMP,
      24             :   IP4_MAPT_NEXT_MAPT_FRAGMENTED,
      25             :   IP4_MAPT_NEXT_ICMP_ERROR,
      26             :   IP4_MAPT_NEXT_DROP,
      27             :   IP4_MAPT_N_NEXT
      28             : } ip4_mapt_next_t;
      29             : 
      30             : typedef enum
      31             : {
      32             :   IP4_MAPT_ICMP_NEXT_IP6_LOOKUP,
      33             :   IP4_MAPT_ICMP_NEXT_IP6_REWRITE,
      34             :   IP4_MAPT_ICMP_NEXT_IP6_FRAG,
      35             :   IP4_MAPT_ICMP_NEXT_DROP,
      36             :   IP4_MAPT_ICMP_N_NEXT
      37             : } ip4_mapt_icmp_next_t;
      38             : 
      39             : typedef enum
      40             : {
      41             :   IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP,
      42             :   IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE,
      43             :   IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG,
      44             :   IP4_MAPT_TCP_UDP_NEXT_DROP,
      45             :   IP4_MAPT_TCP_UDP_N_NEXT
      46             : } ip4_mapt_tcp_udp_next_t;
      47             : 
      48             : typedef enum
      49             : {
      50             :   IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP,
      51             :   IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE,
      52             :   IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG,
      53             :   IP4_MAPT_FRAGMENTED_NEXT_DROP,
      54             :   IP4_MAPT_FRAGMENTED_N_NEXT
      55             : } ip4_mapt_fragmented_next_t;
      56             : 
      57             : //This is used to pass information within the buffer data.
      58             : //Buffer structure being too small to contain big structures like this.
      59             : /* *INDENT-OFF* */
      60             : typedef CLIB_PACKED (struct {
      61             :   ip6_address_t daddr;
      62             :   ip6_address_t saddr;
      63             :   //IPv6 header + Fragmentation header will be here
      64             :   //sizeof(ip6) + sizeof(ip_frag) - sizeof(ip4)
      65             :   u8 unused[28];
      66             : }) ip4_mapt_pseudo_header_t;
      67             : /* *INDENT-ON* */
      68             : 
      69             : typedef struct
      70             : {
      71             :   map_domain_t *d;
      72             :   u16 recv_port;
      73             : } icmp_to_icmp6_ctx_t;
      74             : 
      75             : static int
      76           5 : ip4_to_ip6_set_icmp_cb (vlib_buffer_t * b, ip4_header_t * ip4,
      77             :                         ip6_header_t * ip6, void *arg)
      78             : {
      79           5 :   icmp_to_icmp6_ctx_t *ctx = arg;
      80             : 
      81           5 :   ip4_map_t_embedded_address (ctx->d, &ip6->src_address, &ip4->src_address);
      82           5 :   ip6->dst_address.as_u64[0] =
      83           5 :     map_get_pfx_net (ctx->d, ip4->dst_address.as_u32, ctx->recv_port);
      84           5 :   ip6->dst_address.as_u64[1] =
      85           5 :     map_get_sfx_net (ctx->d, ip4->dst_address.as_u32, ctx->recv_port);
      86             : 
      87           5 :   return 0;
      88             : }
      89             : 
      90             : static int
      91           1 : ip4_to_ip6_set_inner_icmp_cb (vlib_buffer_t * b, ip4_header_t * ip4,
      92             :                               ip6_header_t * ip6, void *arg)
      93             : {
      94           1 :   icmp_to_icmp6_ctx_t *ctx = arg;
      95             :   ip4_address_t old_src, old_dst;
      96             : 
      97           1 :   old_src.as_u32 = ip4->src_address.as_u32;
      98           1 :   old_dst.as_u32 = ip4->dst_address.as_u32;
      99             : 
     100             :   //Note that the source address is within the domain
     101             :   //while the destination address is the one outside the domain
     102           1 :   ip4_map_t_embedded_address (ctx->d, &ip6->dst_address, &old_dst);
     103           1 :   ip6->src_address.as_u64[0] =
     104           1 :     map_get_pfx_net (ctx->d, old_src.as_u32, ctx->recv_port);
     105           1 :   ip6->src_address.as_u64[1] =
     106           1 :     map_get_sfx_net (ctx->d, old_src.as_u32, ctx->recv_port);
     107             : 
     108           1 :   return 0;
     109             : }
     110             : 
     111             : static uword
     112           5 : ip4_map_t_icmp (vlib_main_t * vm,
     113             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     114             : {
     115             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     116             :   vlib_node_runtime_t *error_node =
     117           5 :     vlib_node_get_runtime (vm, ip4_map_t_icmp_node.index);
     118           5 :   from = vlib_frame_vector_args (frame);
     119           5 :   n_left_from = frame->n_vectors;
     120           5 :   next_index = node->cached_next_index;
     121           5 :   vlib_combined_counter_main_t *cm = map_main.domain_counters;
     122           5 :   u32 thread_index = vm->thread_index;
     123             : 
     124          10 :   while (n_left_from > 0)
     125             :     {
     126           5 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     127             : 
     128          10 :       while (n_left_from > 0 && n_left_to_next > 0)
     129             :         {
     130             :           u32 pi0;
     131             :           vlib_buffer_t *p0;
     132             :           ip4_mapt_icmp_next_t next0;
     133             :           u8 error0;
     134             :           map_domain_t *d0;
     135             :           u16 len0;
     136             :           icmp_to_icmp6_ctx_t ctx0;
     137             :           ip4_header_t *ip40;
     138             : 
     139           5 :           next0 = IP4_MAPT_ICMP_NEXT_IP6_LOOKUP;
     140           5 :           pi0 = to_next[0] = from[0];
     141           5 :           from += 1;
     142           5 :           n_left_from -= 1;
     143           5 :           to_next += 1;
     144           5 :           n_left_to_next -= 1;
     145           5 :           error0 = MAP_ERROR_NONE;
     146             : 
     147           5 :           p0 = vlib_get_buffer (vm, pi0);
     148           5 :           vlib_buffer_advance (p0, sizeof (ip4_mapt_pseudo_header_t));  //The pseudo-header is not used
     149             :           len0 =
     150           5 :             clib_net_to_host_u16 (((ip4_header_t *)
     151           5 :                                    vlib_buffer_get_current (p0))->length);
     152           5 :           d0 =
     153           5 :             pool_elt_at_index (map_main.domains,
     154             :                                vnet_buffer (p0)->map_t.map_domain_index);
     155             : 
     156           5 :           ip40 = vlib_buffer_get_current (p0);
     157           5 :           ctx0.recv_port = ip4_get_port (ip40, 0);
     158           5 :           ctx0.d = d0;
     159           5 :           if (ctx0.recv_port == 0)
     160             :             {
     161             :               // In case of 1:1 mapping, we don't care about the port
     162           0 :               if (!(d0->ea_bits_len == 0 && d0->rules))
     163             :                 {
     164           0 :                   error0 = MAP_ERROR_ICMP;
     165           0 :                   goto err0;
     166             :                 }
     167             :             }
     168             : 
     169           5 :           if (icmp_to_icmp6
     170             :               (p0, ip4_to_ip6_set_icmp_cb, &ctx0,
     171             :                ip4_to_ip6_set_inner_icmp_cb, &ctx0))
     172             :             {
     173           0 :               error0 = MAP_ERROR_ICMP;
     174           0 :               goto err0;
     175             :             }
     176             : 
     177           5 :           if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     178             :             {
     179           1 :               vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     180           1 :               vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP6_LOOKUP;
     181           1 :               next0 = IP4_MAPT_ICMP_NEXT_IP6_FRAG;
     182             :             }
     183             :           else
     184             :             {
     185           8 :               next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
     186           4 :                 IP4_MAPT_ICMP_NEXT_IP6_REWRITE : next0;
     187             :             }
     188           5 :         err0:
     189           5 :           if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
     190             :             {
     191           5 :               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
     192             :                                                thread_index,
     193           5 :                                                vnet_buffer (p0)->
     194             :                                                map_t.map_domain_index, 1,
     195             :                                                len0);
     196             :             }
     197             :           else
     198             :             {
     199           0 :               next0 = IP4_MAPT_ICMP_NEXT_DROP;
     200             :             }
     201           5 :           p0->error = error_node->errors[error0];
     202           5 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     203             :                                            to_next, n_left_to_next, pi0,
     204             :                                            next0);
     205             :         }
     206           5 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     207             :     }
     208           5 :   return frame->n_vectors;
     209             : }
     210             : 
     211             : /*
     212             :  * Translate fragmented IPv4 UDP/TCP packet to IPv6.
     213             :  */
     214             : always_inline int
     215           2 : map_ip4_to_ip6_fragmented (vlib_buffer_t * p,
     216             :                            ip4_mapt_pseudo_header_t * pheader)
     217             : {
     218             :   ip4_header_t *ip4;
     219             :   ip6_header_t *ip6;
     220             :   ip6_frag_hdr_t *frag;
     221             : 
     222           2 :   ip4 = vlib_buffer_get_current (p);
     223           2 :   frag = (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
     224           2 :   ip6 =
     225             :     (ip6_header_t *) u8_ptr_add (ip4,
     226             :                                  sizeof (*ip4) - sizeof (*frag) -
     227             :                                  sizeof (*ip6));
     228           2 :   vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
     229             : 
     230             :   //We know that the protocol was one of ICMP, TCP or UDP
     231             :   //because the first fragment was found and cached
     232           2 :   frag->next_hdr =
     233           2 :     (ip4->protocol == IP_PROTOCOL_ICMP) ? IP_PROTOCOL_ICMP6 : ip4->protocol;
     234           2 :   frag->identification = frag_id_4to6 (ip4->fragment_id);
     235           2 :   frag->rsv = 0;
     236           2 :   frag->fragment_offset_and_more =
     237           2 :     ip6_frag_hdr_offset_and_more (ip4_get_fragment_offset (ip4),
     238             :                                   clib_net_to_host_u16
     239             :                                   (ip4->flags_and_fragment_offset) &
     240             :                                   IP4_HEADER_FLAG_MORE_FRAGMENTS);
     241             : 
     242           2 :   ip6->ip_version_traffic_class_and_flow_label =
     243           2 :     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
     244           2 :   ip6->payload_length =
     245           2 :     clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
     246           2 :                           sizeof (*ip4) + sizeof (*frag));
     247           2 :   ip6->hop_limit = ip4->ttl;
     248           2 :   ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
     249             : 
     250           2 :   ip6->dst_address.as_u64[0] = pheader->daddr.as_u64[0];
     251           2 :   ip6->dst_address.as_u64[1] = pheader->daddr.as_u64[1];
     252           2 :   ip6->src_address.as_u64[0] = pheader->saddr.as_u64[0];
     253           2 :   ip6->src_address.as_u64[1] = pheader->saddr.as_u64[1];
     254             : 
     255           2 :   return 0;
     256             : }
     257             : 
     258             : static uword
     259           2 : ip4_map_t_fragmented (vlib_main_t * vm,
     260             :                       vlib_node_runtime_t * node, vlib_frame_t * frame)
     261             : {
     262             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     263           2 :   from = vlib_frame_vector_args (frame);
     264           2 :   n_left_from = frame->n_vectors;
     265           2 :   next_index = node->cached_next_index;
     266             :   vlib_node_runtime_t *error_node =
     267           2 :     vlib_node_get_runtime (vm, ip4_map_t_fragmented_node.index);
     268             : 
     269           4 :   while (n_left_from > 0)
     270             :     {
     271           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     272             : 
     273           4 :       while (n_left_from > 0 && n_left_to_next > 0)
     274             :         {
     275             :           u32 pi0;
     276             :           vlib_buffer_t *p0;
     277             :           ip4_mapt_pseudo_header_t *pheader0;
     278             :           ip4_mapt_fragmented_next_t next0;
     279             : 
     280           2 :           next0 = IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP;
     281           2 :           pi0 = to_next[0] = from[0];
     282           2 :           from += 1;
     283           2 :           n_left_from -= 1;
     284           2 :           to_next += 1;
     285           2 :           n_left_to_next -= 1;
     286             : 
     287           2 :           p0 = vlib_get_buffer (vm, pi0);
     288             : 
     289             :           //Accessing pseudo header
     290           2 :           pheader0 = vlib_buffer_get_current (p0);
     291           2 :           vlib_buffer_advance (p0, sizeof (*pheader0));
     292             : 
     293           2 :           if (map_ip4_to_ip6_fragmented (p0, pheader0))
     294             :             {
     295           0 :               p0->error = error_node->errors[MAP_ERROR_FRAGMENT_DROPPED];
     296           0 :               next0 = IP4_MAPT_FRAGMENTED_NEXT_DROP;
     297             :             }
     298             :           else
     299             :             {
     300           2 :               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     301             :                 {
     302           0 :                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     303           0 :                   vnet_buffer (p0)->ip_frag.next_index =
     304             :                     IP_FRAG_NEXT_IP6_LOOKUP;
     305           0 :                   next0 = IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG;
     306             :                 }
     307             :               else
     308             :                 {
     309           4 :                   next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
     310           2 :                     IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE : next0;
     311             :                 }
     312             :             }
     313             : 
     314           2 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     315             :                                            to_next, n_left_to_next, pi0,
     316             :                                            next0);
     317             :         }
     318           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     319             :     }
     320           2 :   return frame->n_vectors;
     321             : }
     322             : 
     323             : /*
     324             :  * Translate IPv4 UDP/TCP packet to IPv6.
     325             :  */
     326             : always_inline int
     327           7 : map_ip4_to_ip6_tcp_udp (vlib_buffer_t * p, ip4_mapt_pseudo_header_t * pheader)
     328             : {
     329           7 :   map_main_t *mm = &map_main;
     330             :   ip4_header_t *ip4;
     331             :   ip6_header_t *ip6;
     332             :   ip_csum_t csum;
     333             :   u16 *checksum;
     334             :   ip6_frag_hdr_t *frag;
     335             :   u32 frag_id;
     336             :   ip4_address_t old_src, old_dst;
     337             : 
     338           7 :   ip4 = vlib_buffer_get_current (p);
     339             : 
     340           7 :   if (ip4->protocol == IP_PROTOCOL_UDP)
     341             :     {
     342           3 :       udp_header_t *udp = ip4_next_header (ip4);
     343           3 :       checksum = &udp->checksum;
     344             : 
     345             :       /*
     346             :        * UDP checksum is optional over IPv4 but mandatory for IPv6 We
     347             :        * do not check udp->length sanity but use our safe computed
     348             :        * value instead
     349             :        */
     350           3 :       if (PREDICT_FALSE (!*checksum))
     351             :         {
     352           0 :           u16 udp_len = clib_host_to_net_u16 (ip4->length) - sizeof (*ip4);
     353           0 :           csum = ip_incremental_checksum (0, udp, udp_len);
     354           0 :           csum = ip_csum_with_carry (csum, clib_host_to_net_u16 (udp_len));
     355           0 :           csum =
     356           0 :             ip_csum_with_carry (csum, clib_host_to_net_u16 (IP_PROTOCOL_UDP));
     357           0 :           csum = ip_csum_with_carry (csum, *((u64 *) (&ip4->src_address)));
     358           0 :           *checksum = ~ip_csum_fold (csum);
     359             :         }
     360             :     }
     361             :   else
     362             :     {
     363           4 :       tcp_header_t *tcp = ip4_next_header (ip4);
     364           4 :       if (mm->tcp_mss > 0)
     365             :         {
     366           2 :           csum = tcp->checksum;
     367           2 :           map_mss_clamping (tcp, &csum, mm->tcp_mss);
     368           2 :           tcp->checksum = ip_csum_fold (csum);
     369             :         }
     370           4 :       checksum = &tcp->checksum;
     371             :     }
     372             : 
     373           7 :   old_src.as_u32 = ip4->src_address.as_u32;
     374           7 :   old_dst.as_u32 = ip4->dst_address.as_u32;
     375             : 
     376             :   /* Deal with fragmented packets */
     377           7 :   if (PREDICT_FALSE (ip4->flags_and_fragment_offset &
     378             :                      clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS)))
     379             :     {
     380           1 :       ip6 =
     381             :         (ip6_header_t *) u8_ptr_add (ip4,
     382             :                                      sizeof (*ip4) - sizeof (*ip6) -
     383             :                                      sizeof (*frag));
     384           1 :       frag =
     385             :         (ip6_frag_hdr_t *) u8_ptr_add (ip4, sizeof (*ip4) - sizeof (*frag));
     386           1 :       frag_id = frag_id_4to6 (ip4->fragment_id);
     387           1 :       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) - sizeof (*frag));
     388             :     }
     389             :   else
     390             :     {
     391           6 :       ip6 = (ip6_header_t *) (((u8 *) ip4) + sizeof (*ip4) - sizeof (*ip6));
     392           6 :       vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
     393           6 :       frag = NULL;
     394             :     }
     395             : 
     396           7 :   ip6->ip_version_traffic_class_and_flow_label =
     397           7 :     clib_host_to_net_u32 ((6 << 28) + (ip4->tos << 20));
     398           7 :   ip6->payload_length = u16_net_add (ip4->length, -sizeof (*ip4));
     399           7 :   ip6->hop_limit = ip4->ttl;
     400           7 :   ip6->protocol = ip4->protocol;
     401           7 :   if (PREDICT_FALSE (frag != NULL))
     402             :     {
     403           1 :       frag->next_hdr = ip6->protocol;
     404           1 :       frag->identification = frag_id;
     405           1 :       frag->rsv = 0;
     406           1 :       frag->fragment_offset_and_more = ip6_frag_hdr_offset_and_more (0, 1);
     407           1 :       ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
     408           1 :       ip6->payload_length = u16_net_add (ip6->payload_length, sizeof (*frag));
     409             :     }
     410             : 
     411           7 :   ip6->dst_address.as_u64[0] = pheader->daddr.as_u64[0];
     412           7 :   ip6->dst_address.as_u64[1] = pheader->daddr.as_u64[1];
     413           7 :   ip6->src_address.as_u64[0] = pheader->saddr.as_u64[0];
     414           7 :   ip6->src_address.as_u64[1] = pheader->saddr.as_u64[1];
     415             : 
     416           7 :   csum = ip_csum_sub_even (*checksum, old_src.as_u32);
     417           7 :   csum = ip_csum_sub_even (csum, old_dst.as_u32);
     418           7 :   csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
     419           7 :   csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
     420           7 :   csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
     421           7 :   csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
     422           7 :   *checksum = ip_csum_fold (csum);
     423             : 
     424           7 :   return 0;
     425             : }
     426             : 
     427             : static uword
     428           7 : ip4_map_t_tcp_udp (vlib_main_t * vm,
     429             :                    vlib_node_runtime_t * node, vlib_frame_t * frame)
     430             : {
     431             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     432           7 :   from = vlib_frame_vector_args (frame);
     433           7 :   n_left_from = frame->n_vectors;
     434           7 :   next_index = node->cached_next_index;
     435             :   vlib_node_runtime_t *error_node =
     436           7 :     vlib_node_get_runtime (vm, ip4_map_t_tcp_udp_node.index);
     437             : 
     438             : 
     439          14 :   while (n_left_from > 0)
     440             :     {
     441           7 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     442             : 
     443          14 :       while (n_left_from > 0 && n_left_to_next > 0)
     444             :         {
     445             :           u32 pi0;
     446             :           vlib_buffer_t *p0;
     447             :           ip4_mapt_pseudo_header_t *pheader0;
     448             :           ip4_mapt_tcp_udp_next_t next0;
     449             : 
     450           7 :           pi0 = to_next[0] = from[0];
     451           7 :           from += 1;
     452           7 :           n_left_from -= 1;
     453           7 :           to_next += 1;
     454           7 :           n_left_to_next -= 1;
     455             : 
     456           7 :           next0 = IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP;
     457           7 :           p0 = vlib_get_buffer (vm, pi0);
     458             : 
     459             :           //Accessing pseudo header
     460           7 :           pheader0 = vlib_buffer_get_current (p0);
     461           7 :           vlib_buffer_advance (p0, sizeof (*pheader0));
     462             : 
     463           7 :           if (map_ip4_to_ip6_tcp_udp (p0, pheader0))
     464             :             {
     465           0 :               p0->error = error_node->errors[MAP_ERROR_UNKNOWN];
     466           0 :               next0 = IP4_MAPT_TCP_UDP_NEXT_DROP;
     467             :             }
     468             :           else
     469             :             {
     470           7 :               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     471             :                 {
     472             :                   //Send to fragmentation node if necessary
     473           1 :                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     474           1 :                   vnet_buffer (p0)->ip_frag.next_index =
     475             :                     IP_FRAG_NEXT_IP6_LOOKUP;
     476           1 :                   next0 = IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG;
     477             :                 }
     478             :               else
     479             :                 {
     480          12 :                   next0 = ip4_map_ip6_lookup_bypass (p0, NULL) ?
     481           6 :                     IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE : next0;
     482             :                 }
     483             :             }
     484           7 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     485             :                                            to_next, n_left_to_next, pi0,
     486             :                                            next0);
     487             :         }
     488           7 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     489             :     }
     490             : 
     491           7 :   return frame->n_vectors;
     492             : }
     493             : 
     494             : static_always_inline void
     495          15 : ip4_map_t_classify (vlib_buffer_t * p0, map_domain_t * d0,
     496             :                     ip4_header_t * ip40, u16 ip4_len0, i32 * dst_port0,
     497             :                     u8 * error0, ip4_mapt_next_t * next0, u16 l4_dst_port)
     498             : {
     499          15 :   if (PREDICT_FALSE (ip4_get_fragment_offset (ip40)))
     500             :     {
     501           2 :       *next0 = IP4_MAPT_NEXT_MAPT_FRAGMENTED;
     502           2 :       if (d0->ea_bits_len == 0 && d0->rules)
     503             :         {
     504           0 :           *dst_port0 = 0;
     505             :         }
     506             :       else
     507             :         {
     508           2 :           *dst_port0 = l4_dst_port;
     509           2 :           *error0 = (*dst_port0 == -1) ? MAP_ERROR_FRAGMENT_MEMORY : *error0;
     510             :         }
     511             :     }
     512          13 :   else if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_TCP))
     513             :     {
     514           4 :       vnet_buffer (p0)->map_t.checksum_offset = 36;
     515           4 :       *next0 = IP4_MAPT_NEXT_MAPT_TCP_UDP;
     516           4 :       *error0 = ip4_len0 < 40 ? MAP_ERROR_MALFORMED : *error0;
     517           4 :       *dst_port0 = l4_dst_port;
     518             :     }
     519           9 :   else if (PREDICT_TRUE (ip40->protocol == IP_PROTOCOL_UDP))
     520             :     {
     521           4 :       vnet_buffer (p0)->map_t.checksum_offset = 26;
     522           4 :       *next0 = IP4_MAPT_NEXT_MAPT_TCP_UDP;
     523           4 :       *error0 = ip4_len0 < 28 ? MAP_ERROR_MALFORMED : *error0;
     524           4 :       *dst_port0 = l4_dst_port;
     525             :     }
     526           5 :   else if (ip40->protocol == IP_PROTOCOL_ICMP)
     527             :     {
     528           5 :       *next0 = IP4_MAPT_NEXT_MAPT_ICMP;
     529           5 :       if (d0->ea_bits_len == 0 && d0->rules)
     530           0 :         *dst_port0 = 0;
     531           5 :       else if (((icmp46_header_t *) u8_ptr_add (ip40, sizeof (*ip40)))->type
     532             :                == ICMP4_echo_reply
     533           4 :                || ((icmp46_header_t *)
     534             :                    u8_ptr_add (ip40,
     535           4 :                                sizeof (*ip40)))->type == ICMP4_echo_request)
     536           4 :         *dst_port0 = l4_dst_port;
     537             :     }
     538             :   else
     539             :     {
     540           0 :       *error0 = MAP_ERROR_BAD_PROTOCOL;
     541             :     }
     542          15 : }
     543             : 
     544             : static uword
     545          15 : ip4_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     546             : {
     547             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     548             :   vlib_node_runtime_t *error_node =
     549          15 :     vlib_node_get_runtime (vm, ip4_map_t_node.index);
     550          15 :   from = vlib_frame_vector_args (frame);
     551          15 :   n_left_from = frame->n_vectors;
     552          15 :   next_index = node->cached_next_index;
     553          15 :   vlib_combined_counter_main_t *cm = map_main.domain_counters;
     554          15 :   u32 thread_index = vm->thread_index;
     555             : 
     556          30 :   while (n_left_from > 0)
     557             :     {
     558          15 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     559             : 
     560          32 :       while (n_left_from > 0 && n_left_to_next > 0)
     561             :         {
     562             :           u32 pi0;
     563             :           vlib_buffer_t *p0;
     564             :           ip4_header_t *ip40;
     565             :           map_domain_t *d0;
     566          17 :           ip4_mapt_next_t next0 = 0;
     567             :           u16 ip4_len0;
     568             :           u8 error0;
     569             :           i32 dst_port0;
     570             :           ip4_mapt_pseudo_header_t *pheader0;
     571             : 
     572          17 :           pi0 = to_next[0] = from[0];
     573          17 :           from += 1;
     574          17 :           n_left_from -= 1;
     575          17 :           to_next += 1;
     576          17 :           n_left_to_next -= 1;
     577          17 :           error0 = MAP_ERROR_NONE;
     578             : 
     579          17 :           p0 = vlib_get_buffer (vm, pi0);
     580             : 
     581          17 :           u16 l4_dst_port = vnet_buffer (p0)->ip.reass.l4_dst_port;
     582             : 
     583          17 :           ip40 = vlib_buffer_get_current (p0);
     584          17 :           ip4_len0 = clib_host_to_net_u16 (ip40->length);
     585          17 :           if (PREDICT_FALSE (p0->current_length < ip4_len0 ||
     586             :                              ip40->ip_version_and_header_length != 0x45))
     587             :             {
     588           0 :               error0 = MAP_ERROR_UNKNOWN;
     589             :             }
     590             : 
     591          17 :           d0 = ip4_map_get_domain (&ip40->dst_address,
     592          17 :                                    &vnet_buffer (p0)->map_t.map_domain_index,
     593             :                                    &error0);
     594             : 
     595          17 :           if (!d0)
     596             :             {                   /* Guess it wasn't for us */
     597           1 :               vnet_feature_next (&next0, p0);
     598           1 :               goto exit;
     599             :             }
     600             : 
     601          16 :           dst_port0 = -1;
     602             : 
     603          16 :           if (PREDICT_FALSE (ip40->ttl == 1))
     604             :             {
     605           1 :               icmp4_error_set_vnet_buffer (p0, ICMP4_time_exceeded,
     606             :                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
     607             :                                            0);
     608           1 :               p0->error = error_node->errors[MAP_ERROR_TIME_EXCEEDED];
     609           1 :               next0 = IP4_MAPT_NEXT_ICMP_ERROR;
     610           1 :               goto trace;
     611             :             }
     612             : 
     613          15 :           bool df0 =
     614          30 :             ip40->flags_and_fragment_offset &
     615          15 :             clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT);
     616             : 
     617          15 :           vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
     618             : 
     619          15 :           if (PREDICT_FALSE
     620             :               (df0 && !map_main.frag_ignore_df
     621             :                &&
     622             :                ((ip4_len0 +
     623             :                  (sizeof (ip6_header_t) - sizeof (ip4_header_t))) >
     624             :                 vnet_buffer (p0)->map_t.mtu)))
     625             :             {
     626           0 :               icmp4_error_set_vnet_buffer (p0, ICMP4_destination_unreachable,
     627             :                                            ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set,
     628           0 :                                            vnet_buffer (p0)->map_t.mtu -
     629             :                                            (sizeof (ip6_header_t) -
     630             :                                             sizeof (ip4_header_t)));
     631           0 :               p0->error = error_node->errors[MAP_ERROR_DF_SET];
     632           0 :               next0 = IP4_MAPT_NEXT_ICMP_ERROR;
     633           0 :               goto trace;
     634             :             }
     635             : 
     636          15 :           ip4_map_t_classify (p0, d0, ip40, ip4_len0, &dst_port0, &error0,
     637             :                               &next0, l4_dst_port);
     638             : 
     639             :           /* Verify that port is not among the well-known ports */
     640          15 :           if ((d0->psid_length > 0 && d0->psid_offset > 0)
     641          15 :               && (clib_net_to_host_u16 (dst_port0) <
     642          15 :                   (0x1 << (16 - d0->psid_offset))))
     643             :             {
     644           1 :               error0 = MAP_ERROR_SEC_CHECK;
     645             :             }
     646             : 
     647             :           //Add MAP-T pseudo header in front of the packet
     648          15 :           vlib_buffer_advance (p0, -sizeof (*pheader0));
     649          15 :           pheader0 = vlib_buffer_get_current (p0);
     650             : 
     651             :           //Save addresses within the packet
     652          15 :           ip4_map_t_embedded_address (d0, &pheader0->saddr,
     653          15 :                                       &ip40->src_address);
     654          15 :           pheader0->daddr.as_u64[0] =
     655          15 :             map_get_pfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
     656          15 :           pheader0->daddr.as_u64[1] =
     657          15 :             map_get_sfx_net (d0, ip40->dst_address.as_u32, (u16) dst_port0);
     658             : 
     659          15 :           if (PREDICT_TRUE
     660             :               (error0 == MAP_ERROR_NONE && next0 != IP4_MAPT_NEXT_MAPT_ICMP))
     661             :             {
     662           9 :               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_TX,
     663             :                                                thread_index,
     664           9 :                                                vnet_buffer (p0)->
     665             :                                                map_t.map_domain_index, 1,
     666           9 :                                                clib_net_to_host_u16
     667           9 :                                                (ip40->length));
     668             :             }
     669             : 
     670          15 :           next0 = (error0 != MAP_ERROR_NONE) ? IP4_MAPT_NEXT_DROP : next0;
     671          15 :           p0->error = error_node->errors[error0];
     672          16 :         trace:
     673          16 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     674             :             {
     675          16 :               map_add_trace (vm, node, p0, d0 - map_main.domains, dst_port0);
     676             :             }
     677           0 :         exit:
     678          17 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     679             :                                            to_next, n_left_to_next, pi0,
     680             :                                            next0);
     681             :         }
     682          15 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     683             :     }
     684          15 :   return frame->n_vectors;
     685             : }
     686             : 
     687             : /* *INDENT-OFF* */
     688       46657 : VNET_FEATURE_INIT (ip4_map_t_feature, static) = {
     689             :     .arc_name = "ip4-unicast",
     690             :     .node_name = "ip4-map-t",
     691             :     .runs_before = VNET_FEATURES ("ip4-flow-classify"),
     692             :     .runs_after = VNET_FEATURES ("ip4-sv-reassembly-feature"),
     693             : };
     694             : 
     695       87002 : VLIB_REGISTER_NODE(ip4_map_t_fragmented_node) = {
     696             :   .function = ip4_map_t_fragmented,
     697             :   .name = "ip4-map-t-fragmented",
     698             :   .vector_size = sizeof(u32),
     699             :   .format_trace = format_map_trace,
     700             :   .type = VLIB_NODE_TYPE_INTERNAL,
     701             : 
     702             :   .n_errors = MAP_N_ERROR,
     703             :   .error_counters = map_error_counters,
     704             : 
     705             :   .n_next_nodes = IP4_MAPT_FRAGMENTED_N_NEXT,
     706             :   .next_nodes = {
     707             :       [IP4_MAPT_FRAGMENTED_NEXT_IP6_LOOKUP] = "ip6-lookup",
     708             :       [IP4_MAPT_FRAGMENTED_NEXT_IP6_REWRITE] = "ip6-load-balance",
     709             :       [IP4_MAPT_FRAGMENTED_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
     710             :       [IP4_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
     711             :   },
     712             : };
     713             : /* *INDENT-ON* */
     714             : 
     715             : /* *INDENT-OFF* */
     716       87002 : VLIB_REGISTER_NODE(ip4_map_t_icmp_node) = {
     717             :   .function = ip4_map_t_icmp,
     718             :   .name = "ip4-map-t-icmp",
     719             :   .vector_size = sizeof(u32),
     720             :   .format_trace = format_map_trace,
     721             :   .type = VLIB_NODE_TYPE_INTERNAL,
     722             : 
     723             :   .n_errors = MAP_N_ERROR,
     724             :   .error_counters = map_error_counters,
     725             : 
     726             :   .n_next_nodes = IP4_MAPT_ICMP_N_NEXT,
     727             :   .next_nodes = {
     728             :       [IP4_MAPT_ICMP_NEXT_IP6_LOOKUP] = "ip6-lookup",
     729             :       [IP4_MAPT_ICMP_NEXT_IP6_REWRITE] = "ip6-load-balance",
     730             :       [IP4_MAPT_ICMP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
     731             :       [IP4_MAPT_ICMP_NEXT_DROP] = "error-drop",
     732             :   },
     733             : };
     734             : /* *INDENT-ON* */
     735             : 
     736             : /* *INDENT-OFF* */
     737       87002 : VLIB_REGISTER_NODE(ip4_map_t_tcp_udp_node) = {
     738             :   .function = ip4_map_t_tcp_udp,
     739             :   .name = "ip4-map-t-tcp-udp",
     740             :   .vector_size = sizeof(u32),
     741             :   .format_trace = format_map_trace,
     742             :   .type = VLIB_NODE_TYPE_INTERNAL,
     743             : 
     744             :   .n_errors = MAP_N_ERROR,
     745             :   .error_counters = map_error_counters,
     746             : 
     747             :   .n_next_nodes = IP4_MAPT_TCP_UDP_N_NEXT,
     748             :   .next_nodes = {
     749             :       [IP4_MAPT_TCP_UDP_NEXT_IP6_LOOKUP] = "ip6-lookup",
     750             :       [IP4_MAPT_TCP_UDP_NEXT_IP6_REWRITE] = "ip6-load-balance",
     751             :       [IP4_MAPT_TCP_UDP_NEXT_IP6_FRAG] = IP6_FRAG_NODE_NAME,
     752             :       [IP4_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
     753             :   },
     754             : };
     755             : /* *INDENT-ON* */
     756             : 
     757             : /* *INDENT-OFF* */
     758       87002 : VLIB_REGISTER_NODE(ip4_map_t_node) = {
     759             :   .function = ip4_map_t,
     760             :   .name = "ip4-map-t",
     761             :   .vector_size = sizeof(u32),
     762             :   .format_trace = format_map_trace,
     763             :   .type = VLIB_NODE_TYPE_INTERNAL,
     764             : 
     765             :   .n_errors = MAP_N_ERROR,
     766             :   .error_counters = map_error_counters,
     767             : 
     768             :   .n_next_nodes = IP4_MAPT_N_NEXT,
     769             :   .next_nodes = {
     770             :       [IP4_MAPT_NEXT_MAPT_TCP_UDP] = "ip4-map-t-tcp-udp",
     771             :       [IP4_MAPT_NEXT_MAPT_ICMP] = "ip4-map-t-icmp",
     772             :       [IP4_MAPT_NEXT_MAPT_FRAGMENTED] = "ip4-map-t-fragmented",
     773             :       [IP4_MAPT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     774             :       [IP4_MAPT_NEXT_DROP] = "error-drop",
     775             :   },
     776             : };
     777             : /* *INDENT-ON* */
     778             : 
     779             : /*
     780             :  * fd.io coding-style-patch-verification: ON
     781             :  *
     782             :  * Local Variables:
     783             :  * eval: (c-set-style "gnu")
     784             :  * End:
     785             :  */

Generated by: LCOV version 1.14