LCOV - code coverage report
Current view: top level - plugins/map - ip6_map_t.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 278 304 91.4 %
Date: 2023-10-26 01:39:38 Functions: 18 18 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/ip4_to_ip6.h>
      18             : #include <vnet/ip/ip6_to_ip4.h>
      19             : #include <vnet/ip/ip_frag.h>
      20             : 
      21             : typedef enum
      22             : {
      23             :   IP6_MAPT_NEXT_MAPT_TCP_UDP,
      24             :   IP6_MAPT_NEXT_MAPT_ICMP,
      25             :   IP6_MAPT_NEXT_MAPT_FRAGMENTED,
      26             :   IP6_MAPT_NEXT_DROP,
      27             :   IP6_MAPT_NEXT_ICMP,
      28             :   IP6_MAPT_N_NEXT
      29             : } ip6_mapt_next_t;
      30             : 
      31             : typedef enum
      32             : {
      33             :   IP6_MAPT_ICMP_NEXT_IP4_LOOKUP,
      34             :   IP6_MAPT_ICMP_NEXT_IP4_REWRITE,
      35             :   IP6_MAPT_ICMP_NEXT_IP4_FRAG,
      36             :   IP6_MAPT_ICMP_NEXT_DROP,
      37             :   IP6_MAPT_ICMP_N_NEXT
      38             : } ip6_mapt_icmp_next_t;
      39             : 
      40             : typedef enum
      41             : {
      42             :   IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP,
      43             :   IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE,
      44             :   IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG,
      45             :   IP6_MAPT_TCP_UDP_NEXT_DROP,
      46             :   IP6_MAPT_TCP_UDP_N_NEXT
      47             : } ip6_mapt_tcp_udp_next_t;
      48             : 
      49             : typedef enum
      50             : {
      51             :   IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP,
      52             :   IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE,
      53             :   IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG,
      54             :   IP6_MAPT_FRAGMENTED_NEXT_DROP,
      55             :   IP6_MAPT_FRAGMENTED_N_NEXT
      56             : } ip6_mapt_fragmented_next_t;
      57             : 
      58             : typedef struct
      59             : {
      60             :   map_domain_t *d;
      61             :   u16 sender_port;
      62             : } icmp6_to_icmp_ctx_t;
      63             : 
      64             : static int
      65           4 : ip6_to_ip4_set_icmp_cb (ip6_header_t * ip6, ip4_header_t * ip4, void *arg)
      66             : {
      67           4 :   icmp6_to_icmp_ctx_t *ctx = arg;
      68             :   u32 ip4_sadr;
      69             : 
      70             :   // Security check
      71             :   // Note that this prevents an intermediate IPv6 router from answering
      72             :   // the request.
      73           4 :   ip4_sadr = map_get_ip4 (&ip6->src_address, ctx->d->ip6_src_len);
      74           4 :   if (ip6->src_address.as_u64[0] !=
      75           4 :       map_get_pfx_net (ctx->d, ip4_sadr, ctx->sender_port)
      76           4 :       || ip6->src_address.as_u64[1] != map_get_sfx_net (ctx->d, ip4_sadr,
      77           4 :                                                         ctx->sender_port))
      78           0 :     return -1;
      79             : 
      80           4 :   ip4->dst_address.as_u32 =
      81           4 :     ip6_map_t_embedded_address (ctx->d, &ip6->dst_address);
      82           4 :   ip4->src_address.as_u32 = ip4_sadr;
      83             : 
      84           4 :   return 0;
      85             : }
      86             : 
      87             : static int
      88           2 : ip6_to_ip4_set_inner_icmp_cb (ip6_header_t * ip6, ip4_header_t * ip4,
      89             :                               void *arg)
      90             : {
      91           2 :   icmp6_to_icmp_ctx_t *ctx = arg;
      92             :   u32 inner_ip4_dadr;
      93             : 
      94             :   //Security check of inner packet
      95           2 :   inner_ip4_dadr = map_get_ip4 (&ip6->dst_address, ctx->d->ip6_src_len);
      96           2 :   if (ip6->dst_address.as_u64[0] !=
      97           2 :       map_get_pfx_net (ctx->d, inner_ip4_dadr, ctx->sender_port)
      98           2 :       || ip6->dst_address.as_u64[1] != map_get_sfx_net (ctx->d,
      99             :                                                         inner_ip4_dadr,
     100           2 :                                                         ctx->sender_port))
     101           0 :     return -1;
     102             : 
     103           2 :   ip4->dst_address.as_u32 = inner_ip4_dadr;
     104           2 :   ip4->src_address.as_u32 =
     105           2 :     ip6_map_t_embedded_address (ctx->d, &ip6->src_address);
     106             : 
     107           2 :   return 0;
     108             : }
     109             : 
     110             : static uword
     111           4 : ip6_map_t_icmp (vlib_main_t * vm,
     112             :                 vlib_node_runtime_t * node, vlib_frame_t * frame)
     113             : {
     114             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     115             :   vlib_node_runtime_t *error_node =
     116           4 :     vlib_node_get_runtime (vm, ip6_map_t_icmp_node.index);
     117           4 :   from = vlib_frame_vector_args (frame);
     118           4 :   n_left_from = frame->n_vectors;
     119           4 :   next_index = node->cached_next_index;
     120           4 :   vlib_combined_counter_main_t *cm = map_main.domain_counters;
     121           4 :   u32 thread_index = vm->thread_index;
     122             : 
     123           8 :   while (n_left_from > 0)
     124             :     {
     125           4 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     126             : 
     127           8 :       while (n_left_from > 0 && n_left_to_next > 0)
     128             :         {
     129             :           u32 pi0;
     130             :           vlib_buffer_t *p0;
     131             :           u8 error0;
     132             :           ip6_mapt_icmp_next_t next0;
     133             :           map_domain_t *d0;
     134             :           u16 len0;
     135             :           icmp6_to_icmp_ctx_t ctx0;
     136             :           ip6_header_t *ip60;
     137             : 
     138           4 :           pi0 = to_next[0] = from[0];
     139           4 :           from += 1;
     140           4 :           n_left_from -= 1;
     141           4 :           to_next += 1;
     142           4 :           n_left_to_next -= 1;
     143           4 :           error0 = MAP_ERROR_NONE;
     144           4 :           next0 = IP6_MAPT_ICMP_NEXT_IP4_LOOKUP;
     145             : 
     146           4 :           p0 = vlib_get_buffer (vm, pi0);
     147           4 :           ip60 = vlib_buffer_get_current (p0);
     148           4 :           len0 = clib_net_to_host_u16 (ip60->payload_length);
     149           4 :           d0 =
     150           4 :             pool_elt_at_index (map_main.domains,
     151             :                                vnet_buffer (p0)->map_t.map_domain_index);
     152           4 :           ctx0.d = d0;
     153           4 :           ctx0.sender_port = 0;
     154           4 :           if (!ip6_get_port
     155           4 :               (vm, p0, ip60, p0->current_length, NULL, &ctx0.sender_port,
     156             :                NULL, NULL, NULL, NULL))
     157             :             {
     158             :               // In case of 1:1 mapping, we don't care about the port
     159           0 :               if (!(d0->ea_bits_len == 0 && d0->rules))
     160             :                 {
     161           0 :                   error0 = MAP_ERROR_ICMP;
     162           0 :                   goto err0;
     163             :                 }
     164             :             }
     165             : 
     166           4 :           if (icmp6_to_icmp (vm, p0, ip6_to_ip4_set_icmp_cb, &ctx0,
     167             :                              ip6_to_ip4_set_inner_icmp_cb, &ctx0))
     168             :             {
     169           0 :               error0 = MAP_ERROR_ICMP;
     170           0 :               goto err0;
     171             :             }
     172             : 
     173           4 :           if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     174             :             {
     175             :               // Send to fragmentation node if necessary
     176           0 :               vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     177           0 :               vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP4_LOOKUP;
     178           0 :               next0 = IP6_MAPT_ICMP_NEXT_IP4_FRAG;
     179             :             }
     180             :           else
     181             :             {
     182           8 :               next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
     183           4 :                 IP6_MAPT_ICMP_NEXT_IP4_REWRITE : next0;
     184             :             }
     185           4 :         err0:
     186           4 :           if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
     187             :             {
     188           4 :               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     189             :                                                thread_index,
     190           4 :                                                vnet_buffer (p0)->
     191             :                                                map_t.map_domain_index, 1,
     192             :                                                len0);
     193             :             }
     194             :           else
     195             :             {
     196           0 :               next0 = IP6_MAPT_ICMP_NEXT_DROP;
     197             :             }
     198             : 
     199           4 :           p0->error = error_node->errors[error0];
     200           4 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     201             :                                            to_next, n_left_to_next, pi0,
     202             :                                            next0);
     203             :         }
     204           4 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     205             :     }
     206           4 :   return frame->n_vectors;
     207             : }
     208             : 
     209             : /*
     210             :  * Translate IPv6 fragmented packet to IPv4.
     211             :  */
     212             : always_inline int
     213           1 : map_ip6_to_ip4_fragmented (vlib_main_t * vm, vlib_buffer_t * p)
     214             : {
     215             :   ip6_header_t *ip6;
     216             :   ip6_frag_hdr_t *frag;
     217             :   ip4_header_t *ip4;
     218             :   u16 frag_id;
     219             :   u8 frag_more;
     220             :   u16 frag_offset;
     221             :   u8 l4_protocol;
     222             :   u16 l4_offset;
     223             : 
     224           1 :   ip6 = vlib_buffer_get_current (p);
     225             : 
     226           1 :   if (ip6_parse
     227           1 :       (vm, p, ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
     228           0 :     return -1;
     229             : 
     230           1 :   frag = (ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_offset);
     231           1 :   ip4 = (ip4_header_t *) u8_ptr_add (ip6, l4_offset - sizeof (*ip4));
     232           1 :   vlib_buffer_advance (p, l4_offset - sizeof (*ip4));
     233             : 
     234           1 :   frag_id = frag_id_6to4 (frag->identification);
     235           1 :   frag_more = ip6_frag_hdr_more (frag);
     236           1 :   frag_offset = ip6_frag_hdr_offset (frag);
     237             : 
     238           1 :   ip4->dst_address.as_u32 = vnet_buffer (p)->map_t.v6.daddr;
     239           1 :   ip4->src_address.as_u32 = vnet_buffer (p)->map_t.v6.saddr;
     240             : 
     241           1 :   ip4->ip_version_and_header_length =
     242             :     IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
     243           1 :   ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
     244           1 :   ip4->length =
     245           1 :     u16_net_add (ip6->payload_length,
     246             :                  sizeof (*ip4) - l4_offset + sizeof (*ip6));
     247           1 :   ip4->fragment_id = frag_id;
     248           1 :   ip4->flags_and_fragment_offset =
     249           1 :     clib_host_to_net_u16 (frag_offset |
     250             :                           (frag_more ? IP4_HEADER_FLAG_MORE_FRAGMENTS : 0));
     251           1 :   ip4->ttl = ip6->hop_limit;
     252           1 :   ip4->protocol =
     253           1 :     (l4_protocol == IP_PROTOCOL_ICMP6) ? IP_PROTOCOL_ICMP : l4_protocol;
     254           1 :   ip4->checksum = ip4_header_checksum (ip4);
     255             : 
     256           1 :   return 0;
     257             : }
     258             : 
     259             : static uword
     260           1 : ip6_map_t_fragmented (vlib_main_t * vm,
     261             :                       vlib_node_runtime_t * node, vlib_frame_t * frame)
     262             : {
     263             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     264           1 :   from = vlib_frame_vector_args (frame);
     265           1 :   n_left_from = frame->n_vectors;
     266           1 :   next_index = node->cached_next_index;
     267             :   vlib_node_runtime_t *error_node =
     268           1 :     vlib_node_get_runtime (vm, ip6_map_t_fragmented_node.index);
     269             : 
     270           2 :   while (n_left_from > 0)
     271             :     {
     272           1 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     273             : 
     274           2 :       while (n_left_from > 0 && n_left_to_next > 0)
     275             :         {
     276             :           u32 pi0;
     277             :           vlib_buffer_t *p0;
     278             :           u32 next0;
     279             : 
     280           1 :           pi0 = to_next[0] = from[0];
     281           1 :           from += 1;
     282           1 :           n_left_from -= 1;
     283           1 :           to_next += 1;
     284           1 :           n_left_to_next -= 1;
     285           1 :           next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP;
     286           1 :           p0 = vlib_get_buffer (vm, pi0);
     287             : 
     288           1 :           if (map_ip6_to_ip4_fragmented (vm, p0))
     289             :             {
     290           0 :               p0->error = error_node->errors[MAP_ERROR_FRAGMENT_DROPPED];
     291           0 :               next0 = IP6_MAPT_FRAGMENTED_NEXT_DROP;
     292             :             }
     293             :           else
     294             :             {
     295           1 :               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     296             :                 {
     297             :                   // Send to fragmentation node if necessary
     298           0 :                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     299           0 :                   vnet_buffer (p0)->ip_frag.next_index =
     300             :                     IP_FRAG_NEXT_IP4_LOOKUP;
     301           0 :                   next0 = IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG;
     302             :                 }
     303             :               else
     304             :                 {
     305           2 :                   next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
     306           1 :                     IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE : next0;
     307             :                 }
     308             :             }
     309             : 
     310           1 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     311             :                                            to_next, n_left_to_next, pi0,
     312             :                                            next0);
     313             :         }
     314           1 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     315             :     }
     316           1 :   return frame->n_vectors;
     317             : }
     318             : 
     319             : /*
     320             :  * Translate IPv6 UDP/TCP packet to IPv4.
     321             :  * Returns 0 on success.
     322             :  * Returns a non-zero error code on error.
     323             :  */
     324             : always_inline int
     325           8 : map_ip6_to_ip4_tcp_udp (vlib_main_t * vm, vlib_buffer_t * p,
     326             :                         bool udp_checksum)
     327             : {
     328           8 :   map_main_t *mm = &map_main;
     329             :   ip6_header_t *ip6;
     330             :   u16 *checksum;
     331           8 :   ip_csum_t csum = 0;
     332             :   ip4_header_t *ip4;
     333             :   u16 fragment_id;
     334             :   u16 flags;
     335             :   u16 frag_offset;
     336             :   u8 l4_protocol;
     337             :   u16 l4_offset;
     338             :   ip6_address_t old_src, old_dst;
     339             : 
     340           8 :   ip6 = vlib_buffer_get_current (p);
     341             : 
     342           8 :   if (ip6_parse
     343           8 :       (vm, p, ip6, p->current_length, &l4_protocol, &l4_offset, &frag_offset))
     344           0 :     return -1;
     345             : 
     346           8 :   if (l4_protocol == IP_PROTOCOL_TCP)
     347             :     {
     348           5 :       tcp_header_t *tcp = (tcp_header_t *) u8_ptr_add (ip6, l4_offset);
     349           5 :       if (mm->tcp_mss > 0)
     350             :         {
     351           2 :           csum = tcp->checksum;
     352           2 :           map_mss_clamping (tcp, &csum, mm->tcp_mss);
     353           2 :           tcp->checksum = ip_csum_fold (csum);
     354             :         }
     355           5 :       checksum = &tcp->checksum;
     356             :     }
     357             :   else
     358             :     {
     359           3 :       udp_header_t *udp = (udp_header_t *) u8_ptr_add (ip6, l4_offset);
     360           3 :       checksum = &udp->checksum;
     361             :     }
     362             : 
     363           8 :   old_src.as_u64[0] = ip6->src_address.as_u64[0];
     364           8 :   old_src.as_u64[1] = ip6->src_address.as_u64[1];
     365           8 :   old_dst.as_u64[0] = ip6->dst_address.as_u64[0];
     366           8 :   old_dst.as_u64[1] = ip6->dst_address.as_u64[1];
     367             : 
     368           8 :   ip4 = (ip4_header_t *) u8_ptr_add (ip6, l4_offset - sizeof (*ip4));
     369             : 
     370           8 :   vlib_buffer_advance (p, l4_offset - sizeof (*ip4));
     371             : 
     372           8 :   if (PREDICT_FALSE (frag_offset))
     373             :     {
     374             :       // Only the first fragment
     375           1 :       ip6_frag_hdr_t *hdr = (ip6_frag_hdr_t *) u8_ptr_add (ip6, frag_offset);
     376           1 :       fragment_id = frag_id_6to4 (hdr->identification);
     377           1 :       flags = clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS);
     378             :     }
     379             :   else
     380             :     {
     381           7 :       fragment_id = 0;
     382           7 :       flags = 0;
     383             :     }
     384             : 
     385           8 :   ip4->dst_address.as_u32 = vnet_buffer (p)->map_t.v6.daddr;
     386           8 :   ip4->src_address.as_u32 = vnet_buffer (p)->map_t.v6.saddr;
     387             : 
     388             :   /*
     389             :    * Drop spoofed packets that from a known domain source.
     390             :    */
     391           8 :   u32 map_domain_index = -1;
     392           8 :   u8 error = 0;
     393             : 
     394           8 :   ip4_map_get_domain (&ip4->src_address, &map_domain_index, &error);
     395           8 :   if (error)
     396           1 :     return error;
     397             : 
     398           7 :   ip4->ip_version_and_header_length =
     399             :     IP4_VERSION_AND_HEADER_LENGTH_NO_OPTIONS;
     400           7 :   ip4->tos = ip6_translate_tos (ip6->ip_version_traffic_class_and_flow_label);
     401           7 :   ip4->length =
     402           7 :     u16_net_add (ip6->payload_length,
     403             :                  sizeof (*ip4) + sizeof (*ip6) - l4_offset);
     404           7 :   ip4->fragment_id = fragment_id;
     405           7 :   ip4->flags_and_fragment_offset = flags;
     406           7 :   ip4->ttl = ip6->hop_limit;
     407           7 :   ip4->protocol = l4_protocol;
     408           7 :   ip4->checksum = ip4_header_checksum (ip4);
     409             : 
     410             :   // UDP checksum is optional over IPv4
     411           7 :   if (!udp_checksum && l4_protocol == IP_PROTOCOL_UDP)
     412             :     {
     413           0 :       *checksum = 0;
     414             :     }
     415             :   else
     416             :     {
     417           7 :       csum = ip_csum_sub_even (*checksum, old_src.as_u64[0]);
     418           7 :       csum = ip_csum_sub_even (csum, old_src.as_u64[1]);
     419           7 :       csum = ip_csum_sub_even (csum, old_dst.as_u64[0]);
     420           7 :       csum = ip_csum_sub_even (csum, old_dst.as_u64[1]);
     421           7 :       csum = ip_csum_add_even (csum, ip4->dst_address.as_u32);
     422           7 :       csum = ip_csum_add_even (csum, ip4->src_address.as_u32);
     423           7 :       *checksum = ip_csum_fold (csum);
     424             :     }
     425             : 
     426           7 :   return 0;
     427             : }
     428             : 
     429             : static uword
     430           8 : ip6_map_t_tcp_udp (vlib_main_t * vm,
     431             :                    vlib_node_runtime_t * node, vlib_frame_t * frame)
     432             : {
     433             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     434             :   vlib_node_runtime_t *error_node =
     435           8 :     vlib_node_get_runtime (vm, ip6_map_t_tcp_udp_node.index);
     436             : 
     437           8 :   from = vlib_frame_vector_args (frame);
     438           8 :   n_left_from = frame->n_vectors;
     439           8 :   next_index = node->cached_next_index;
     440          16 :   while (n_left_from > 0)
     441             :     {
     442           8 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     443             : 
     444          16 :       while (n_left_from > 0 && n_left_to_next > 0)
     445             :         {
     446             :           u32 pi0;
     447             :           vlib_buffer_t *p0;
     448             :           ip6_mapt_tcp_udp_next_t next0;
     449             : 
     450           8 :           pi0 = to_next[0] = from[0];
     451           8 :           from += 1;
     452           8 :           n_left_from -= 1;
     453           8 :           to_next += 1;
     454           8 :           n_left_to_next -= 1;
     455           8 :           next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP;
     456             : 
     457           8 :           p0 = vlib_get_buffer (vm, pi0);
     458             : 
     459           8 :           if (map_ip6_to_ip4_tcp_udp (vm, p0, true))
     460             :             {
     461           1 :               p0->error = error_node->errors[MAP_ERROR_UNKNOWN];
     462           1 :               next0 = IP6_MAPT_TCP_UDP_NEXT_DROP;
     463             :             }
     464             :           else
     465             :             {
     466           7 :               if (vnet_buffer (p0)->map_t.mtu < p0->current_length)
     467             :                 {
     468             :                   // Send to fragmentation node if necessary
     469           0 :                   vnet_buffer (p0)->ip_frag.mtu = vnet_buffer (p0)->map_t.mtu;
     470           0 :                   vnet_buffer (p0)->ip_frag.next_index =
     471             :                     IP_FRAG_NEXT_IP4_LOOKUP;
     472           0 :                   next0 = IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG;
     473             :                 }
     474             :               else
     475             :                 {
     476          14 :                   next0 = ip6_map_ip4_lookup_bypass (p0, NULL) ?
     477           7 :                     IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE : next0;
     478             :                 }
     479             :             }
     480             : 
     481           8 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     482             :                                            to_next, n_left_to_next, pi0,
     483             :                                            next0);
     484             :         }
     485           8 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     486             :     }
     487           8 :   return frame->n_vectors;
     488             : }
     489             : 
     490             : static uword
     491          22 : ip6_map_t (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     492             : {
     493             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     494             :   vlib_node_runtime_t *error_node =
     495          22 :     vlib_node_get_runtime (vm, ip6_map_t_node.index);
     496          22 :   map_main_t *mm = &map_main;
     497          22 :   vlib_combined_counter_main_t *cm = map_main.domain_counters;
     498          22 :   u32 thread_index = vm->thread_index;
     499             : 
     500          22 :   from = vlib_frame_vector_args (frame);
     501          22 :   n_left_from = frame->n_vectors;
     502          22 :   next_index = node->cached_next_index;
     503          44 :   while (n_left_from > 0)
     504             :     {
     505          22 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     506             : 
     507          45 :       while (n_left_from > 0 && n_left_to_next > 0)
     508             :         {
     509             :           u32 pi0;
     510             :           vlib_buffer_t *p0;
     511             :           ip6_header_t *ip60;
     512             :           u8 error0;
     513             :           u32 l4_len0;
     514             :           i32 map_port0;
     515             :           map_domain_t *d0;
     516             :           ip6_frag_hdr_t *frag0;
     517          23 :           ip6_mapt_next_t next0 = 0;
     518             :           u32 saddr;
     519             : 
     520          23 :           pi0 = to_next[0] = from[0];
     521          23 :           from += 1;
     522          23 :           n_left_from -= 1;
     523          23 :           to_next += 1;
     524          23 :           n_left_to_next -= 1;
     525          23 :           error0 = MAP_ERROR_NONE;
     526          23 :           p0 = vlib_get_buffer (vm, pi0);
     527          23 :           u16 l4_src_port = vnet_buffer (p0)->ip.reass.l4_src_port;
     528             : 
     529          23 :           ip60 = vlib_buffer_get_current (p0);
     530             : 
     531             :           d0 =
     532          23 :             ip6_map_get_domain (&ip60->dst_address,
     533          23 :                                 &vnet_buffer (p0)->map_t.map_domain_index,
     534             :                                 &error0);
     535          23 :           if (!d0)
     536             :             {                   /* Guess it wasn't for us */
     537           1 :               vnet_feature_next (&next0, p0);
     538           1 :               goto exit;
     539             :             }
     540             : 
     541          22 :           saddr = map_get_ip4 (&ip60->src_address, d0->ip6_src_len);
     542          22 :           vnet_buffer (p0)->map_t.v6.saddr = saddr;
     543          44 :           vnet_buffer (p0)->map_t.v6.daddr =
     544          22 :             ip6_map_t_embedded_address (d0, &ip60->dst_address);
     545          22 :           vnet_buffer (p0)->map_t.mtu = d0->mtu ? d0->mtu : ~0;
     546             : 
     547          22 :           map_port0 = -1;
     548             : 
     549          22 :           if (PREDICT_FALSE (ip60->hop_limit == 1))
     550             :             {
     551           1 :               icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
     552             :                                            ICMP6_time_exceeded_ttl_exceeded_in_transit,
     553             :                                            0);
     554           1 :               p0->error = error_node->errors[MAP_ERROR_TIME_EXCEEDED];
     555           1 :               next0 = IP6_MAPT_NEXT_ICMP;
     556           1 :               goto trace;
     557             :             }
     558             : 
     559          21 :           if (PREDICT_FALSE
     560             :               (ip6_parse (vm, p0, ip60, p0->current_length,
     561             :                           &(vnet_buffer (p0)->map_t.v6.l4_protocol),
     562             :                           &(vnet_buffer (p0)->map_t.v6.l4_offset),
     563             :                           &(vnet_buffer (p0)->map_t.v6.frag_offset))))
     564             :             {
     565           0 :               error0 =
     566           0 :                 error0 == MAP_ERROR_NONE ? MAP_ERROR_MALFORMED : error0;
     567             :             }
     568             : 
     569          21 :           l4_len0 =
     570          21 :             (u32) clib_net_to_host_u16 (ip60->payload_length) +
     571          21 :             sizeof (*ip60) - vnet_buffer (p0)->map_t.v6.l4_offset;
     572          21 :           frag0 =
     573          21 :             (ip6_frag_hdr_t *) u8_ptr_add (ip60,
     574             :                                            vnet_buffer (p0)->map_t.v6.
     575             :                                            frag_offset);
     576             : 
     577          21 :           if (PREDICT_FALSE
     578             :               (vnet_buffer (p0)->map_t.v6.frag_offset
     579             :                && ip6_frag_hdr_offset (frag0)))
     580             :             {
     581           1 :               map_port0 = l4_src_port;
     582           1 :               next0 = IP6_MAPT_NEXT_MAPT_FRAGMENTED;
     583             :             }
     584             :           else
     585          20 :             if (PREDICT_TRUE
     586             :                 (vnet_buffer (p0)->map_t.v6.l4_protocol == IP_PROTOCOL_TCP))
     587             :             {
     588           7 :               error0 =
     589             :                 l4_len0 <
     590             :                 sizeof (tcp_header_t) ? MAP_ERROR_MALFORMED : error0;
     591           7 :               vnet_buffer (p0)->map_t.checksum_offset =
     592           7 :                 vnet_buffer (p0)->map_t.v6.l4_offset + 16;
     593           7 :               next0 = IP6_MAPT_NEXT_MAPT_TCP_UDP;
     594           7 :               map_port0 = l4_src_port;
     595             :             }
     596             :           else
     597          13 :             if (PREDICT_TRUE
     598             :                 (vnet_buffer (p0)->map_t.v6.l4_protocol == IP_PROTOCOL_UDP))
     599             :             {
     600           8 :               error0 =
     601             :                 l4_len0 <
     602             :                 sizeof (udp_header_t) ? MAP_ERROR_MALFORMED : error0;
     603           8 :               vnet_buffer (p0)->map_t.checksum_offset =
     604           8 :                 vnet_buffer (p0)->map_t.v6.l4_offset + 6;
     605           8 :               next0 = IP6_MAPT_NEXT_MAPT_TCP_UDP;
     606           8 :               map_port0 = l4_src_port;
     607             :             }
     608           5 :           else if (vnet_buffer (p0)->map_t.v6.l4_protocol ==
     609             :                    IP_PROTOCOL_ICMP6)
     610             :             {
     611           5 :               error0 =
     612             :                 l4_len0 <
     613             :                 sizeof (icmp46_header_t) ? MAP_ERROR_MALFORMED : error0;
     614           5 :               next0 = IP6_MAPT_NEXT_MAPT_ICMP;
     615           5 :               if (((icmp46_header_t *)
     616           5 :                    u8_ptr_add (ip60,
     617           5 :                                vnet_buffer (p0)->map_t.v6.l4_offset))->type ==
     618             :                   ICMP6_echo_reply
     619           4 :                   || ((icmp46_header_t *)
     620           4 :                       u8_ptr_add (ip60,
     621           4 :                                   vnet_buffer (p0)->map_t.v6.l4_offset))->
     622             :                   type == ICMP6_echo_request)
     623           3 :                 map_port0 = l4_src_port;
     624             :             }
     625             :           else
     626             :             {
     627             :               // TODO: In case of 1:1 mapping, it might be possible to
     628             :               // do something with those packets.
     629           0 :               error0 = MAP_ERROR_BAD_PROTOCOL;
     630             :             }
     631             : 
     632          40 :           if (PREDICT_FALSE (map_port0 != -1) &&
     633          19 :               (ip60->src_address.as_u64[0] !=
     634          19 :                map_get_pfx_net (d0, vnet_buffer (p0)->map_t.v6.saddr,
     635             :                                 map_port0)
     636          12 :                || ip60->src_address.as_u64[1] != map_get_sfx_net (d0,
     637          12 :                                                                   vnet_buffer
     638             :                                                                   (p0)->map_t.
     639             :                                                                   v6.saddr,
     640             :                                                                   map_port0)))
     641             :             {
     642             :               // Security check when map_port0 is not zero (non-first
     643             :               // fragment, UDP or TCP)
     644           8 :               error0 =
     645           8 :                 error0 == MAP_ERROR_NONE ? MAP_ERROR_SEC_CHECK : error0;
     646             :             }
     647             : 
     648          21 :           if (PREDICT_TRUE
     649             :               (error0 == MAP_ERROR_NONE && next0 != IP6_MAPT_NEXT_MAPT_ICMP))
     650             :             {
     651           9 :               vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     652             :                                                thread_index,
     653           9 :                                                vnet_buffer (p0)->map_t.
     654             :                                                map_domain_index, 1,
     655           9 :                                                clib_net_to_host_u16 (ip60->
     656             :                                                                      payload_length));
     657             :             }
     658             : 
     659          21 :           if (PREDICT_FALSE
     660             :               (error0 == MAP_ERROR_SEC_CHECK && mm->icmp6_enabled))
     661             :             {
     662           1 :               icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
     663             :                                            ICMP6_destination_unreachable_source_address_failed_policy,
     664             :                                            0);
     665           1 :               next0 = IP6_MAPT_NEXT_ICMP;
     666             :             }
     667             :           else
     668             :             {
     669          20 :               next0 = (error0 != MAP_ERROR_NONE) ? IP6_MAPT_NEXT_DROP : next0;
     670             :             }
     671             : 
     672          21 :           p0->error = error_node->errors[error0];
     673          22 :         trace:
     674          22 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     675             :             {
     676          22 :               map_add_trace (vm, node, p0,
     677          22 :                              vnet_buffer (p0)->map_t.map_domain_index,
     678             :                              map_port0);
     679             :             }
     680           0 :         exit:
     681          23 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     682             :                                            to_next, n_left_to_next, pi0,
     683             :                                            next0);
     684             :         }
     685          22 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     686             :     }
     687          22 :   return frame->n_vectors;
     688             : }
     689             : 
     690             : /* *INDENT-OFF* */
     691       87002 : VLIB_REGISTER_NODE(ip6_map_t_fragmented_node) = {
     692             :   .function = ip6_map_t_fragmented,
     693             :   .name = "ip6-map-t-fragmented",
     694             :   .vector_size = sizeof (u32),
     695             :   .format_trace = format_map_trace,
     696             :   .type = VLIB_NODE_TYPE_INTERNAL,
     697             : 
     698             :   .n_errors = MAP_N_ERROR,
     699             :   .error_counters = map_error_counters,
     700             : 
     701             :   .n_next_nodes = IP6_MAPT_FRAGMENTED_N_NEXT,
     702             :   .next_nodes =
     703             :   {
     704             :     [IP6_MAPT_FRAGMENTED_NEXT_IP4_LOOKUP] = "ip4-lookup",
     705             :     [IP6_MAPT_FRAGMENTED_NEXT_IP4_REWRITE] = "ip4-load-balance",
     706             :     [IP6_MAPT_FRAGMENTED_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     707             :     [IP6_MAPT_FRAGMENTED_NEXT_DROP] = "error-drop",
     708             :   },
     709             : };
     710             : /* *INDENT-ON* */
     711             : 
     712             : /* *INDENT-OFF* */
     713       87002 : VLIB_REGISTER_NODE(ip6_map_t_icmp_node) = {
     714             :   .function = ip6_map_t_icmp,
     715             :   .name = "ip6-map-t-icmp",
     716             :   .vector_size = sizeof (u32),
     717             :   .format_trace = format_map_trace,
     718             :   .type = VLIB_NODE_TYPE_INTERNAL,
     719             : 
     720             :   .n_errors = MAP_N_ERROR,
     721             :   .error_counters = map_error_counters,
     722             : 
     723             :   .n_next_nodes = IP6_MAPT_ICMP_N_NEXT,
     724             :   .next_nodes =
     725             :   {
     726             :     [IP6_MAPT_ICMP_NEXT_IP4_LOOKUP] = "ip4-lookup",
     727             :     [IP6_MAPT_ICMP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     728             :     [IP6_MAPT_ICMP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     729             :     [IP6_MAPT_ICMP_NEXT_DROP] = "error-drop",
     730             :   },
     731             : };
     732             : /* *INDENT-ON* */
     733             : 
     734             : /* *INDENT-OFF* */
     735       87002 : VLIB_REGISTER_NODE(ip6_map_t_tcp_udp_node) = {
     736             :   .function = ip6_map_t_tcp_udp,
     737             :   .name = "ip6-map-t-tcp-udp",
     738             :   .vector_size = sizeof (u32),
     739             :   .format_trace = format_map_trace,
     740             :   .type = VLIB_NODE_TYPE_INTERNAL,
     741             : 
     742             :   .n_errors = MAP_N_ERROR,
     743             :   .error_counters = map_error_counters,
     744             : 
     745             :   .n_next_nodes = IP6_MAPT_TCP_UDP_N_NEXT,
     746             :   .next_nodes =
     747             :   {
     748             :     [IP6_MAPT_TCP_UDP_NEXT_IP4_LOOKUP] = "ip4-lookup",
     749             :     [IP6_MAPT_TCP_UDP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     750             :     [IP6_MAPT_TCP_UDP_NEXT_IP4_FRAG] = IP4_FRAG_NODE_NAME,
     751             :     [IP6_MAPT_TCP_UDP_NEXT_DROP] = "error-drop",
     752             :   },
     753             : };
     754             : /* *INDENT-ON* */
     755             : 
     756             : /* *INDENT-OFF* */
     757       46657 : VNET_FEATURE_INIT (ip6_map_t_feature, static) = {
     758             :     .arc_name = "ip6-unicast",
     759             :     .node_name = "ip6-map-t",
     760             :     .runs_before = VNET_FEATURES ("ip6-flow-classify"),
     761             :     .runs_after = VNET_FEATURES ("ip6-sv-reassembly-feature"),
     762             : };
     763             : 
     764       87002 : VLIB_REGISTER_NODE(ip6_map_t_node) = {
     765             :   .function = ip6_map_t,
     766             :   .name = "ip6-map-t",
     767             :   .vector_size = sizeof(u32),
     768             :   .format_trace = format_map_trace,
     769             :   .type = VLIB_NODE_TYPE_INTERNAL,
     770             : 
     771             :   .n_errors = MAP_N_ERROR,
     772             :   .error_counters = map_error_counters,
     773             : 
     774             :   .n_next_nodes = IP6_MAPT_N_NEXT,
     775             :   .next_nodes =
     776             :   {
     777             :     [IP6_MAPT_NEXT_MAPT_TCP_UDP] = "ip6-map-t-tcp-udp",
     778             :     [IP6_MAPT_NEXT_MAPT_ICMP] = "ip6-map-t-icmp",
     779             :     [IP6_MAPT_NEXT_MAPT_FRAGMENTED] = "ip6-map-t-fragmented",
     780             :     [IP6_MAPT_NEXT_DROP] = "error-drop",
     781             :     [IP6_MAPT_NEXT_ICMP] = "ip6-icmp-error",
     782             :   },
     783             : };
     784             : /* *INDENT-ON* */
     785             : 
     786             : /*
     787             :  * fd.io coding-style-patch-verification: ON
     788             :  *
     789             :  * Local Variables:
     790             :  * eval: (c-set-style "gnu")
     791             :  * End:
     792             :  */

Generated by: LCOV version 1.14