LCOV - code coverage report
Current view: top level - plugins/map - ip6_map.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 180 352 51.1 %
Date: 2023-07-05 22:20:52 Functions: 15 19 78.9 %

          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             : #include <vnet/ip/ip6_to_ip4.h>
      20             : #include <vnet/ip/reass/ip4_sv_reass.h>
      21             : 
      22             : enum ip6_map_next_e
      23             : {
      24             :   IP6_MAP_NEXT_IP4_LOOKUP,
      25             : #ifdef MAP_SKIP_IP6_LOOKUP
      26             :   IP6_MAP_NEXT_IP4_REWRITE,
      27             : #endif
      28             :   IP6_MAP_NEXT_IP4_REASS,
      29             :   IP6_MAP_NEXT_IP4_FRAGMENT,
      30             :   IP6_MAP_NEXT_IP6_ICMP_RELAY,
      31             :   IP6_MAP_NEXT_IP6_LOCAL,
      32             :   IP6_MAP_NEXT_DROP,
      33             :   IP6_MAP_NEXT_ICMP,
      34             :   IP6_MAP_N_NEXT,
      35             : };
      36             : 
      37             : enum ip6_map_ip6_reass_next_e
      38             : {
      39             :   IP6_MAP_IP6_REASS_NEXT_IP6_MAP,
      40             :   IP6_MAP_IP6_REASS_NEXT_DROP,
      41             :   IP6_MAP_IP6_REASS_N_NEXT,
      42             : };
      43             : 
      44             : enum ip6_map_post_ip4_reass_next_e
      45             : {
      46             :   IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP,
      47             :   IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT,
      48             :   IP6_MAP_POST_IP4_REASS_NEXT_DROP,
      49             :   IP6_MAP_POST_IP4_REASS_N_NEXT,
      50             : };
      51             : 
      52             : enum ip6_icmp_relay_next_e
      53             : {
      54             :   IP6_ICMP_RELAY_NEXT_IP4_LOOKUP,
      55             :   IP6_ICMP_RELAY_NEXT_DROP,
      56             :   IP6_ICMP_RELAY_N_NEXT,
      57             : };
      58             : 
      59             : vlib_node_registration_t ip6_map_post_ip4_reass_node;
      60             : vlib_node_registration_t ip6_map_ip6_reass_node;
      61             : static vlib_node_registration_t ip6_map_icmp_relay_node;
      62             : 
      63             : typedef struct
      64             : {
      65             :   u32 map_domain_index;
      66             :   u16 port;
      67             :   u8 cached;
      68             : } map_ip6_map_ip4_reass_trace_t;
      69             : 
      70             : u8 *
      71           0 : format_ip6_map_post_ip4_reass_trace (u8 * s, va_list * args)
      72             : {
      73           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      74           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      75           0 :   map_ip6_map_ip4_reass_trace_t *t =
      76             :     va_arg (*args, map_ip6_map_ip4_reass_trace_t *);
      77           0 :   return format (s, "MAP domain index: %d L4 port: %u Status: %s",
      78           0 :                  t->map_domain_index, clib_net_to_host_u16 (t->port),
      79           0 :                  t->cached ? "cached" : "forwarded");
      80             : }
      81             : 
      82             : typedef struct
      83             : {
      84             :   u16 offset;
      85             :   u16 frag_len;
      86             :   u8 out;
      87             : } map_ip6_map_ip6_reass_trace_t;
      88             : 
      89             : u8 *
      90           0 : format_ip6_map_ip6_reass_trace (u8 * s, va_list * args)
      91             : {
      92           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      93           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      94           0 :   map_ip6_map_ip6_reass_trace_t *t =
      95             :     va_arg (*args, map_ip6_map_ip6_reass_trace_t *);
      96           0 :   return format (s, "Offset: %d Fragment length: %d Status: %s", t->offset,
      97           0 :                  t->frag_len, t->out ? "out" : "in");
      98             : }
      99             : 
     100             : /*
     101             :  * ip6_map_sec_check
     102             :  */
     103             : static_always_inline bool
     104           9 : ip6_map_sec_check (map_domain_t * d, u16 port, ip4_header_t * ip4,
     105             :                    ip6_header_t * ip6)
     106             : {
     107           9 :   u16 sp4 = clib_net_to_host_u16 (port);
     108           9 :   u32 sa4 = clib_net_to_host_u32 (ip4->src_address.as_u32);
     109           9 :   u64 sal6 = map_get_pfx (d, sa4, sp4);
     110           9 :   u64 sar6 = map_get_sfx (d, sa4, sp4);
     111             : 
     112           9 :   if (PREDICT_FALSE
     113             :       (sal6 != clib_net_to_host_u64 (ip6->src_address.as_u64[0])
     114             :        || sar6 != clib_net_to_host_u64 (ip6->src_address.as_u64[1])))
     115           0 :     return (false);
     116           9 :   return (true);
     117             : }
     118             : 
     119             : static_always_inline void
     120           9 : ip6_map_security_check (map_domain_t * d, vlib_buffer_t * b0,
     121             :                         ip4_header_t * ip4, ip6_header_t * ip6, u32 * next,
     122             :                         u8 * error)
     123             : {
     124           9 :   map_main_t *mm = &map_main;
     125           9 :   if (d->ea_bits_len || d->rules)
     126             :     {
     127           9 :       if (d->psid_length > 0)
     128             :         {
     129           9 :           if (!ip4_is_fragment (ip4))
     130             :             {
     131           1 :               u16 port = ip4_get_port (ip4, 1);
     132           1 :               if (port)
     133             :                 {
     134           1 :                   if (mm->sec_check)
     135           1 :                     *error =
     136           1 :                       ip6_map_sec_check (d, port, ip4,
     137             :                                          ip6) ? MAP_ERROR_NONE :
     138             :                       MAP_ERROR_DECAP_SEC_CHECK;
     139             :                 }
     140             :               else
     141             :                 {
     142           0 :                   *error = MAP_ERROR_BAD_PROTOCOL;
     143             :                 }
     144             :             }
     145             :           else
     146             :             {
     147           8 :               if (mm->sec_check_frag)
     148             :                 {
     149           8 :                   vnet_buffer (b0)->ip.reass.next_index =
     150           8 :                     map_main.ip4_sv_reass_custom_next_index;
     151           8 :                   *next = IP6_MAP_NEXT_IP4_REASS;
     152             :                 }
     153             :             }
     154             :         }
     155             :     }
     156           9 : }
     157             : 
     158             : /*
     159             :  * ip6_map
     160             :  */
     161             : static uword
     162           5 : ip6_map (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
     163             : {
     164             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     165             :   vlib_node_runtime_t *error_node =
     166           5 :     vlib_node_get_runtime (vm, ip6_map_node.index);
     167           5 :   map_main_t *mm = &map_main;
     168           5 :   vlib_combined_counter_main_t *cm = mm->domain_counters;
     169           5 :   u32 thread_index = vm->thread_index;
     170             : 
     171           5 :   from = vlib_frame_vector_args (frame);
     172           5 :   n_left_from = frame->n_vectors;
     173           5 :   next_index = node->cached_next_index;
     174          10 :   while (n_left_from > 0)
     175             :     {
     176           5 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     177             : 
     178             :       /* Dual loop */
     179           7 :       while (n_left_from >= 4 && n_left_to_next >= 2)
     180             :         {
     181             :           u32 pi0, pi1;
     182             :           vlib_buffer_t *p0, *p1;
     183           2 :           u8 error0 = MAP_ERROR_NONE;
     184           2 :           u8 error1 = MAP_ERROR_NONE;
     185           2 :           map_domain_t *d0 = 0, *d1 = 0;
     186             :           ip4_header_t *ip40, *ip41;
     187             :           ip6_header_t *ip60, *ip61;
     188           2 :           u16 port0 = 0, port1 = 0;
     189           2 :           u32 map_domain_index0 = ~0, map_domain_index1 = ~0;
     190           2 :           u32 next0 = IP6_MAP_NEXT_IP4_LOOKUP;
     191           2 :           u32 next1 = IP6_MAP_NEXT_IP4_LOOKUP;
     192             : 
     193             :           /* Prefetch next iteration. */
     194             :           {
     195             :             vlib_buffer_t *p2, *p3;
     196             : 
     197           2 :             p2 = vlib_get_buffer (vm, from[2]);
     198           2 :             p3 = vlib_get_buffer (vm, from[3]);
     199             : 
     200           2 :             vlib_prefetch_buffer_header (p2, LOAD);
     201           2 :             vlib_prefetch_buffer_header (p3, LOAD);
     202             : 
     203             :             /* IPv6 + IPv4 header + 8 bytes of ULP */
     204           2 :             CLIB_PREFETCH (p2->data, 68, LOAD);
     205           2 :             CLIB_PREFETCH (p3->data, 68, LOAD);
     206             :           }
     207             : 
     208           2 :           pi0 = to_next[0] = from[0];
     209           2 :           pi1 = to_next[1] = from[1];
     210           2 :           from += 2;
     211           2 :           n_left_from -= 2;
     212           2 :           to_next += 2;
     213           2 :           n_left_to_next -= 2;
     214             : 
     215           2 :           p0 = vlib_get_buffer (vm, pi0);
     216           2 :           p1 = vlib_get_buffer (vm, pi1);
     217           2 :           ip60 = vlib_buffer_get_current (p0);
     218           2 :           ip61 = vlib_buffer_get_current (p1);
     219           2 :           vlib_buffer_advance (p0, sizeof (ip6_header_t));
     220           2 :           vlib_buffer_advance (p1, sizeof (ip6_header_t));
     221           2 :           ip40 = vlib_buffer_get_current (p0);
     222           2 :           ip41 = vlib_buffer_get_current (p1);
     223             : 
     224             :           /*
     225             :            * Encapsulated IPv4 packet
     226             :            *   - IPv4 fragmented -> Pass to virtual reassembly unless security check disabled
     227             :            *   - Lookup/Rewrite or Fragment node in case of packet > MTU
     228             :            * Fragmented IPv6 packet
     229             :            * ICMP IPv6 packet
     230             :            *   - Error -> Pass to ICMPv6/ICMPv4 relay
     231             :            *   - Info -> Pass to IPv6 local
     232             :            * Anything else -> drop
     233             :            */
     234           2 :           if (PREDICT_TRUE
     235             :               (ip60->protocol == IP_PROTOCOL_IP_IN_IP
     236             :                && clib_net_to_host_u16 (ip60->payload_length) > 20))
     237             :             {
     238           2 :               d0 =
     239           2 :                 ip4_map_get_domain ((ip4_address_t *) & ip40->
     240             :                                     src_address.as_u32, &map_domain_index0,
     241             :                                     &error0);
     242             :             }
     243           0 :           else if (ip60->protocol == IP_PROTOCOL_ICMP6 &&
     244           0 :                    clib_net_to_host_u16 (ip60->payload_length) >
     245             :                    sizeof (icmp46_header_t))
     246           0 :             {
     247           0 :               icmp46_header_t *icmp = (void *) (ip60 + 1);
     248           0 :               next0 = (icmp->type == ICMP6_echo_request
     249           0 :                        || icmp->type ==
     250           0 :                        ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
     251             :                 IP6_MAP_NEXT_IP6_ICMP_RELAY;
     252             :             }
     253           0 :           else if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
     254             :             {
     255           0 :               error0 = MAP_ERROR_FRAGMENTED;
     256             :             }
     257             :           else
     258             :             {
     259           0 :               error0 = MAP_ERROR_BAD_PROTOCOL;
     260             :             }
     261           2 :           if (PREDICT_TRUE
     262             :               (ip61->protocol == IP_PROTOCOL_IP_IN_IP
     263             :                && clib_net_to_host_u16 (ip61->payload_length) > 20))
     264             :             {
     265           2 :               d1 =
     266           2 :                 ip4_map_get_domain ((ip4_address_t *) & ip41->
     267             :                                     src_address.as_u32, &map_domain_index1,
     268             :                                     &error1);
     269             :             }
     270           0 :           else if (ip61->protocol == IP_PROTOCOL_ICMP6 &&
     271           0 :                    clib_net_to_host_u16 (ip61->payload_length) >
     272             :                    sizeof (icmp46_header_t))
     273           0 :             {
     274           0 :               icmp46_header_t *icmp = (void *) (ip61 + 1);
     275           0 :               next1 = (icmp->type == ICMP6_echo_request
     276           0 :                        || icmp->type ==
     277           0 :                        ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
     278             :                 IP6_MAP_NEXT_IP6_ICMP_RELAY;
     279             :             }
     280           0 :           else if (ip61->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
     281             :             {
     282           0 :               error1 = MAP_ERROR_FRAGMENTED;
     283             :             }
     284             :           else
     285             :             {
     286           0 :               error1 = MAP_ERROR_BAD_PROTOCOL;
     287             :             }
     288             : 
     289           2 :           if (d0)
     290             :             {
     291             :               /* MAP inbound security check */
     292           2 :               ip6_map_security_check (d0, p0, ip40, ip60, &next0, &error0);
     293             : 
     294           2 :               if (PREDICT_TRUE (error0 == MAP_ERROR_NONE &&
     295             :                                 next0 == IP6_MAP_NEXT_IP4_LOOKUP))
     296             :                 {
     297           0 :                   if (PREDICT_FALSE
     298             :                       (d0->mtu
     299             :                        && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
     300             :                     {
     301           0 :                       vnet_buffer (p0)->ip_frag.flags = 0;
     302           0 :                       vnet_buffer (p0)->ip_frag.next_index =
     303             :                         IP_FRAG_NEXT_IP4_LOOKUP;
     304           0 :                       vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
     305           0 :                       next0 = IP6_MAP_NEXT_IP4_FRAGMENT;
     306             :                     }
     307             :                   else
     308             :                     {
     309           0 :                       next0 =
     310           0 :                         ip6_map_ip4_lookup_bypass (p0,
     311             :                                                    ip40) ?
     312           0 :                         IP6_MAP_NEXT_IP4_REWRITE : next0;
     313             :                     }
     314           0 :                   vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     315             :                                                    thread_index,
     316             :                                                    map_domain_index0, 1,
     317           0 :                                                    clib_net_to_host_u16
     318           0 :                                                    (ip40->length));
     319             :                 }
     320             :             }
     321           2 :           if (d1)
     322             :             {
     323             :               /* MAP inbound security check */
     324           2 :               ip6_map_security_check (d1, p1, ip41, ip61, &next1, &error1);
     325             : 
     326           2 :               if (PREDICT_TRUE (error1 == MAP_ERROR_NONE &&
     327             :                                 next1 == IP6_MAP_NEXT_IP4_LOOKUP))
     328             :                 {
     329           0 :                   if (PREDICT_FALSE
     330             :                       (d1->mtu
     331             :                        && (clib_host_to_net_u16 (ip41->length) > d1->mtu)))
     332             :                     {
     333           0 :                       vnet_buffer (p1)->ip_frag.flags = 0;
     334           0 :                       vnet_buffer (p1)->ip_frag.next_index =
     335             :                         IP_FRAG_NEXT_IP4_LOOKUP;
     336           0 :                       vnet_buffer (p1)->ip_frag.mtu = d1->mtu;
     337           0 :                       next1 = IP6_MAP_NEXT_IP4_FRAGMENT;
     338             :                     }
     339             :                   else
     340             :                     {
     341           0 :                       next1 =
     342           0 :                         ip6_map_ip4_lookup_bypass (p1,
     343             :                                                    ip41) ?
     344           0 :                         IP6_MAP_NEXT_IP4_REWRITE : next1;
     345             :                     }
     346           0 :                   vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     347             :                                                    thread_index,
     348             :                                                    map_domain_index1, 1,
     349           0 :                                                    clib_net_to_host_u16
     350           0 :                                                    (ip41->length));
     351             :                 }
     352             :             }
     353             : 
     354           2 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     355             :             {
     356           2 :               map_add_trace (vm, node, p0, map_domain_index0, port0);
     357             :             }
     358             : 
     359           2 :           if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
     360             :             {
     361           2 :               map_add_trace (vm, node, p1, map_domain_index1, port1);
     362             :             }
     363             : 
     364           2 :           if (error0 == MAP_ERROR_DECAP_SEC_CHECK && mm->icmp6_enabled)
     365             :             {
     366             :               /* Set ICMP parameters */
     367           0 :               vlib_buffer_advance (p0, -sizeof (ip6_header_t));
     368           0 :               icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
     369             :                                            ICMP6_destination_unreachable_source_address_failed_policy,
     370             :                                            0);
     371           0 :               next0 = IP6_MAP_NEXT_ICMP;
     372             :             }
     373             :           else
     374             :             {
     375           2 :               next0 = (error0 == MAP_ERROR_NONE) ? next0 : IP6_MAP_NEXT_DROP;
     376             :             }
     377             : 
     378           2 :           if (error1 == MAP_ERROR_DECAP_SEC_CHECK && mm->icmp6_enabled)
     379             :             {
     380             :               /* Set ICMP parameters */
     381           0 :               vlib_buffer_advance (p1, -sizeof (ip6_header_t));
     382           0 :               icmp6_error_set_vnet_buffer (p1, ICMP6_destination_unreachable,
     383             :                                            ICMP6_destination_unreachable_source_address_failed_policy,
     384             :                                            0);
     385           0 :               next1 = IP6_MAP_NEXT_ICMP;
     386             :             }
     387             :           else
     388             :             {
     389           2 :               next1 = (error1 == MAP_ERROR_NONE) ? next1 : IP6_MAP_NEXT_DROP;
     390             :             }
     391             : 
     392             :           /* Reset packet */
     393           2 :           if (next0 == IP6_MAP_NEXT_IP6_LOCAL)
     394           0 :             vlib_buffer_advance (p0, -sizeof (ip6_header_t));
     395           2 :           if (next1 == IP6_MAP_NEXT_IP6_LOCAL)
     396           0 :             vlib_buffer_advance (p1, -sizeof (ip6_header_t));
     397             : 
     398           2 :           p0->error = error_node->errors[error0];
     399           2 :           p1->error = error_node->errors[error1];
     400           2 :           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
     401             :                                            n_left_to_next, pi0, pi1, next0,
     402             :                                            next1);
     403             :         }
     404             : 
     405             :       /* Single loop */
     406          12 :       while (n_left_from > 0 && n_left_to_next > 0)
     407             :         {
     408             :           u32 pi0;
     409             :           vlib_buffer_t *p0;
     410           7 :           u8 error0 = MAP_ERROR_NONE;
     411           7 :           map_domain_t *d0 = 0;
     412             :           ip4_header_t *ip40;
     413             :           ip6_header_t *ip60;
     414           7 :           i32 port0 = 0;
     415           7 :           u32 map_domain_index0 = ~0;
     416           7 :           u32 next0 = IP6_MAP_NEXT_IP4_LOOKUP;
     417             : 
     418           7 :           pi0 = to_next[0] = from[0];
     419           7 :           from += 1;
     420           7 :           n_left_from -= 1;
     421           7 :           to_next += 1;
     422           7 :           n_left_to_next -= 1;
     423             : 
     424           7 :           p0 = vlib_get_buffer (vm, pi0);
     425           7 :           ip60 = vlib_buffer_get_current (p0);
     426           7 :           vlib_buffer_advance (p0, sizeof (ip6_header_t));
     427           7 :           ip40 = vlib_buffer_get_current (p0);
     428             : 
     429             :           /*
     430             :            * Encapsulated IPv4 packet
     431             :            *   - IPv4 fragmented -> Pass to virtual reassembly unless security check disabled
     432             :            *   - Lookup/Rewrite or Fragment node in case of packet > MTU
     433             :            * Fragmented IPv6 packet
     434             :            * ICMP IPv6 packet
     435             :            *   - Error -> Pass to ICMPv6/ICMPv4 relay
     436             :            *   - Info -> Pass to IPv6 local
     437             :            * Anything else -> drop
     438             :            */
     439           7 :           if (PREDICT_TRUE
     440             :               (ip60->protocol == IP_PROTOCOL_IP_IN_IP
     441             :                && clib_net_to_host_u16 (ip60->payload_length) > 20))
     442             :             {
     443           5 :               d0 =
     444           5 :                 ip4_map_get_domain ((ip4_address_t *) & ip40->
     445             :                                     src_address.as_u32, &map_domain_index0,
     446             :                                     &error0);
     447             :             }
     448           2 :           else if (ip60->protocol == IP_PROTOCOL_ICMP6 &&
     449           0 :                    clib_net_to_host_u16 (ip60->payload_length) >
     450             :                    sizeof (icmp46_header_t))
     451           0 :             {
     452           0 :               icmp46_header_t *icmp = (void *) (ip60 + 1);
     453           0 :               next0 = (icmp->type == ICMP6_echo_request
     454           0 :                        || icmp->type ==
     455           0 :                        ICMP6_echo_reply) ? IP6_MAP_NEXT_IP6_LOCAL :
     456             :                 IP6_MAP_NEXT_IP6_ICMP_RELAY;
     457             :             }
     458           2 :           else if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION &&
     459           0 :                    (((ip6_frag_hdr_t *) (ip60 + 1))->next_hdr ==
     460             :                     IP_PROTOCOL_IP_IN_IP))
     461             :             {
     462           0 :               error0 = MAP_ERROR_FRAGMENTED;
     463             :             }
     464             :           else
     465             :             {
     466             :               /* XXX: Move get_domain to ip6_get_domain lookup on source */
     467             :               //error0 = MAP_ERROR_BAD_PROTOCOL;
     468           2 :               vlib_buffer_advance (p0, -sizeof (ip6_header_t));
     469           2 :               vnet_feature_next (&next0, p0);
     470             :             }
     471             : 
     472           7 :           if (d0)
     473             :             {
     474             :               /* MAP inbound security check */
     475           5 :               ip6_map_security_check (d0, p0, ip40, ip60, &next0, &error0);
     476             : 
     477           5 :               if (PREDICT_TRUE (error0 == MAP_ERROR_NONE &&
     478             :                                 next0 == IP6_MAP_NEXT_IP4_LOOKUP))
     479             :                 {
     480           1 :                   if (PREDICT_FALSE
     481             :                       (d0->mtu
     482             :                        && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
     483             :                     {
     484           0 :                       vnet_buffer (p0)->ip_frag.flags = 0;
     485           0 :                       vnet_buffer (p0)->ip_frag.next_index =
     486             :                         IP_FRAG_NEXT_IP4_LOOKUP;
     487           0 :                       vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
     488           0 :                       next0 = IP6_MAP_NEXT_IP4_FRAGMENT;
     489             :                     }
     490             :                   else
     491             :                     {
     492           1 :                       next0 =
     493           1 :                         ip6_map_ip4_lookup_bypass (p0,
     494             :                                                    ip40) ?
     495           1 :                         IP6_MAP_NEXT_IP4_REWRITE : next0;
     496             :                     }
     497           1 :                   vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     498             :                                                    thread_index,
     499             :                                                    map_domain_index0, 1,
     500           1 :                                                    clib_net_to_host_u16
     501           1 :                                                    (ip40->length));
     502             :                 }
     503             :             }
     504             : 
     505           7 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     506             :             {
     507           7 :               map_add_trace (vm, node, p0, map_domain_index0, port0);
     508             :             }
     509             : 
     510           7 :           if (mm->icmp6_enabled &&
     511           0 :               (error0 == MAP_ERROR_DECAP_SEC_CHECK
     512           0 :                || error0 == MAP_ERROR_NO_DOMAIN))
     513             :             {
     514             :               /* Set ICMP parameters */
     515           0 :               vlib_buffer_advance (p0, -sizeof (ip6_header_t));
     516           0 :               icmp6_error_set_vnet_buffer (p0, ICMP6_destination_unreachable,
     517             :                                            ICMP6_destination_unreachable_source_address_failed_policy,
     518             :                                            0);
     519           0 :               next0 = IP6_MAP_NEXT_ICMP;
     520             :             }
     521             :           else
     522             :             {
     523           7 :               next0 = (error0 == MAP_ERROR_NONE) ? next0 : IP6_MAP_NEXT_DROP;
     524             :             }
     525             : 
     526             :           /* Reset packet */
     527           7 :           if (next0 == IP6_MAP_NEXT_IP6_LOCAL)
     528           0 :             vlib_buffer_advance (p0, -sizeof (ip6_header_t));
     529             : 
     530           7 :           p0->error = error_node->errors[error0];
     531           7 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     532             :                                            n_left_to_next, pi0, next0);
     533             :         }
     534           5 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     535             :     }
     536             : 
     537           5 :   return frame->n_vectors;
     538             : }
     539             : 
     540             : 
     541             : void
     542           0 : map_ip6_drop_pi (u32 pi)
     543             : {
     544           0 :   vlib_main_t *vm = vlib_get_main ();
     545             :   vlib_node_runtime_t *n =
     546           0 :     vlib_node_get_runtime (vm, ip6_map_ip6_reass_node.index);
     547           0 :   vlib_set_next_frame_buffer (vm, n, IP6_MAP_IP6_REASS_NEXT_DROP, pi);
     548           0 : }
     549             : 
     550             : /*
     551             :  * ip6_map_post_ip4_reass
     552             :  */
     553             : static uword
     554           2 : ip6_map_post_ip4_reass (vlib_main_t * vm,
     555             :                         vlib_node_runtime_t * node, vlib_frame_t * frame)
     556             : {
     557             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     558             :   vlib_node_runtime_t *error_node =
     559           2 :     vlib_node_get_runtime (vm, ip6_map_post_ip4_reass_node.index);
     560           2 :   map_main_t *mm = &map_main;
     561           2 :   vlib_combined_counter_main_t *cm = mm->domain_counters;
     562           2 :   u32 thread_index = vm->thread_index;
     563             : 
     564           2 :   from = vlib_frame_vector_args (frame);
     565           2 :   n_left_from = frame->n_vectors;
     566           2 :   next_index = node->cached_next_index;
     567           4 :   while (n_left_from > 0)
     568             :     {
     569           2 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     570             : 
     571             :       /* Single loop */
     572          10 :       while (n_left_from > 0 && n_left_to_next > 0)
     573             :         {
     574             :           u32 pi0;
     575             :           vlib_buffer_t *p0;
     576           8 :           u8 error0 = MAP_ERROR_NONE;
     577             :           map_domain_t *d0;
     578             :           ip4_header_t *ip40;
     579             :           ip6_header_t *ip60;
     580           8 :           i32 port0 = 0;
     581           8 :           u32 map_domain_index0 = ~0;
     582           8 :           u32 next0 = IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP;
     583             : 
     584           8 :           pi0 = to_next[0] = from[0];
     585           8 :           from += 1;
     586           8 :           n_left_from -= 1;
     587           8 :           to_next += 1;
     588           8 :           n_left_to_next -= 1;
     589             : 
     590           8 :           p0 = vlib_get_buffer (vm, pi0);
     591           8 :           ip40 = vlib_buffer_get_current (p0);
     592           8 :           ip60 = ((ip6_header_t *) ip40) - 1;
     593             : 
     594             :           d0 =
     595           8 :             ip4_map_get_domain ((ip4_address_t *) & ip40->src_address.as_u32,
     596             :                                 &map_domain_index0, &error0);
     597             : 
     598           8 :           port0 = vnet_buffer (p0)->ip.reass.l4_src_port;
     599             : 
     600           8 :           if (PREDICT_TRUE (error0 == MAP_ERROR_NONE))
     601           8 :             error0 =
     602           8 :               ip6_map_sec_check (d0, port0, ip40,
     603             :                                  ip60) ? MAP_ERROR_NONE :
     604             :               MAP_ERROR_DECAP_SEC_CHECK;
     605             : 
     606           8 :           if (PREDICT_FALSE
     607             :               (error0 == MAP_ERROR_NONE &&
     608             :                d0->mtu && (clib_host_to_net_u16 (ip40->length) > d0->mtu)))
     609             :             {
     610           0 :               vnet_buffer (p0)->ip_frag.flags = 0;
     611           0 :               vnet_buffer (p0)->ip_frag.next_index = IP_FRAG_NEXT_IP4_LOOKUP;
     612           0 :               vnet_buffer (p0)->ip_frag.mtu = d0->mtu;
     613           0 :               next0 = IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT;
     614             :             }
     615             : 
     616           8 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     617             :             {
     618             :               map_ip6_map_ip4_reass_trace_t *tr =
     619           8 :                 vlib_add_trace (vm, node, p0, sizeof (*tr));
     620           8 :               tr->map_domain_index = map_domain_index0;
     621           8 :               tr->port = port0;
     622             :             }
     623             : 
     624           8 :           if (error0 == MAP_ERROR_NONE)
     625           8 :             vlib_increment_combined_counter (cm + MAP_DOMAIN_COUNTER_RX,
     626             :                                              thread_index,
     627             :                                              map_domain_index0, 1,
     628           8 :                                              clib_net_to_host_u16
     629           8 :                                              (ip40->length));
     630           8 :           next0 =
     631           8 :             (error0 ==
     632           8 :              MAP_ERROR_NONE) ? next0 : IP6_MAP_POST_IP4_REASS_NEXT_DROP;
     633           8 :           p0->error = error_node->errors[error0];
     634           8 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     635             :                                            n_left_to_next, pi0, next0);
     636             : 
     637             :         }
     638           2 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     639             :     }
     640           2 :   return frame->n_vectors;
     641             : }
     642             : 
     643             : /*
     644             :  * ip6_icmp_relay
     645             :  */
     646             : static uword
     647           0 : ip6_map_icmp_relay (vlib_main_t * vm,
     648             :                     vlib_node_runtime_t * node, vlib_frame_t * frame)
     649             : {
     650             :   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
     651             :   vlib_node_runtime_t *error_node =
     652           0 :     vlib_node_get_runtime (vm, ip6_map_icmp_relay_node.index);
     653           0 :   map_main_t *mm = &map_main;
     654           0 :   u32 thread_index = vm->thread_index;
     655             :   u16 *fragment_ids, *fid;
     656             : 
     657           0 :   from = vlib_frame_vector_args (frame);
     658           0 :   n_left_from = frame->n_vectors;
     659           0 :   next_index = node->cached_next_index;
     660             : 
     661             :   /* Get random fragment IDs for replies. */
     662           0 :   fid = fragment_ids =
     663           0 :     clib_random_buffer_get_data (&vm->random_buffer,
     664             :                                  n_left_from * sizeof (fragment_ids[0]));
     665             : 
     666           0 :   while (n_left_from > 0)
     667             :     {
     668           0 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     669             : 
     670             :       /* Single loop */
     671           0 :       while (n_left_from > 0 && n_left_to_next > 0)
     672             :         {
     673             :           u32 pi0;
     674             :           vlib_buffer_t *p0;
     675           0 :           u8 error0 = MAP_ERROR_NONE;
     676             :           ip6_header_t *ip60;
     677           0 :           u32 next0 = IP6_ICMP_RELAY_NEXT_IP4_LOOKUP;
     678             :           u32 mtu;
     679             : 
     680           0 :           pi0 = to_next[0] = from[0];
     681           0 :           from += 1;
     682           0 :           n_left_from -= 1;
     683           0 :           to_next += 1;
     684           0 :           n_left_to_next -= 1;
     685             : 
     686           0 :           p0 = vlib_get_buffer (vm, pi0);
     687           0 :           ip60 = vlib_buffer_get_current (p0);
     688           0 :           u16 tlen = clib_net_to_host_u16 (ip60->payload_length);
     689             : 
     690             :           /*
     691             :            * In:
     692             :            *  IPv6 header           (40)
     693             :            *  ICMPv6 header          (8)
     694             :            *  IPv6 header           (40)
     695             :            *  Original IPv4 header / packet
     696             :            * Out:
     697             :            *  New IPv4 header
     698             :            *  New ICMP header
     699             :            *  Original IPv4 header / packet
     700             :            */
     701             : 
     702             :           /* Need at least ICMP(8) + IPv6(40) + IPv4(20) + L4 header(8) */
     703           0 :           if (tlen < 76)
     704             :             {
     705           0 :               error0 = MAP_ERROR_ICMP_RELAY;
     706           0 :               goto error;
     707             :             }
     708             : 
     709           0 :           icmp46_header_t *icmp60 = (icmp46_header_t *) (ip60 + 1);
     710           0 :           ip6_header_t *inner_ip60 = (ip6_header_t *) (icmp60 + 2);
     711             : 
     712           0 :           if (inner_ip60->protocol != IP_PROTOCOL_IP_IN_IP)
     713             :             {
     714           0 :               error0 = MAP_ERROR_ICMP_RELAY;
     715           0 :               goto error;
     716             :             }
     717             : 
     718           0 :           ip4_header_t *inner_ip40 = (ip4_header_t *) (inner_ip60 + 1);
     719           0 :           vlib_buffer_advance (p0, 60); /* sizeof ( IPv6 + ICMP + IPv6 - IPv4 - ICMP ) */
     720           0 :           ip4_header_t *new_ip40 = vlib_buffer_get_current (p0);
     721           0 :           icmp46_header_t *new_icmp40 = (icmp46_header_t *) (new_ip40 + 1);
     722             : 
     723             :           /*
     724             :            * Relay according to RFC2473, section 8.3
     725             :            */
     726           0 :           switch (icmp60->type)
     727             :             {
     728           0 :             case ICMP6_destination_unreachable:
     729             :             case ICMP6_time_exceeded:
     730             :             case ICMP6_parameter_problem:
     731             :               /* Type 3 - destination unreachable, Code 1 - host unreachable */
     732           0 :               new_icmp40->type = ICMP4_destination_unreachable;
     733           0 :               new_icmp40->code =
     734             :                 ICMP4_destination_unreachable_destination_unreachable_host;
     735           0 :               break;
     736             : 
     737           0 :             case ICMP6_packet_too_big:
     738             :               /* Type 3 - destination unreachable, Code 4 - packet too big */
     739             :               /* Potential TODO: Adjust domain tunnel MTU based on the value received here */
     740           0 :               mtu = clib_net_to_host_u32 (*((u32 *) (icmp60 + 1)));
     741             : 
     742             :               /* Check DF flag */
     743           0 :               if (!
     744           0 :                   (inner_ip40->flags_and_fragment_offset &
     745           0 :                    clib_host_to_net_u16 (IP4_HEADER_FLAG_DONT_FRAGMENT)))
     746             :                 {
     747           0 :                   error0 = MAP_ERROR_ICMP_RELAY;
     748           0 :                   goto error;
     749             :                 }
     750             : 
     751           0 :               new_icmp40->type = ICMP4_destination_unreachable;
     752           0 :               new_icmp40->code =
     753             :                 ICMP4_destination_unreachable_fragmentation_needed_and_dont_fragment_set;
     754           0 :               *((u32 *) (new_icmp40 + 1)) =
     755           0 :                 clib_host_to_net_u32 (mtu < 1280 ? 1280 : mtu);
     756           0 :               break;
     757             : 
     758           0 :             default:
     759           0 :               error0 = MAP_ERROR_ICMP_RELAY;
     760           0 :               break;
     761             :             }
     762             : 
     763             :           /*
     764             :            * Ensure the total ICMP packet is no longer than 576 bytes (RFC1812)
     765             :            */
     766           0 :           new_ip40->ip_version_and_header_length = 0x45;
     767           0 :           new_ip40->tos = 0;
     768           0 :           u16 nlen = (tlen - 20) > 576 ? 576 : tlen - 20;
     769           0 :           new_ip40->length = clib_host_to_net_u16 (nlen);
     770           0 :           new_ip40->fragment_id = fid[0];
     771           0 :           fid++;
     772           0 :           new_ip40->ttl = 64;
     773           0 :           new_ip40->protocol = IP_PROTOCOL_ICMP;
     774           0 :           new_ip40->src_address = mm->icmp4_src_address;
     775           0 :           new_ip40->dst_address = inner_ip40->src_address;
     776           0 :           new_ip40->checksum = ip4_header_checksum (new_ip40);
     777             : 
     778           0 :           new_icmp40->checksum = 0;
     779           0 :           ip_csum_t sum = ip_incremental_checksum (0, new_icmp40, nlen - 20);
     780           0 :           new_icmp40->checksum = ~ip_csum_fold (sum);
     781             : 
     782           0 :           vlib_increment_simple_counter (&mm->icmp_relayed, thread_index, 0,
     783             :                                          1);
     784             : 
     785           0 :         error:
     786           0 :           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
     787             :             {
     788           0 :               map_trace_t *tr = vlib_add_trace (vm, node, p0, sizeof (*tr));
     789           0 :               tr->map_domain_index = 0;
     790           0 :               tr->port = 0;
     791             :             }
     792             : 
     793           0 :           next0 =
     794           0 :             (error0 == MAP_ERROR_NONE) ? next0 : IP6_ICMP_RELAY_NEXT_DROP;
     795           0 :           p0->error = error_node->errors[error0];
     796           0 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     797             :                                            n_left_to_next, pi0, next0);
     798             :         }
     799           0 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     800             :     }
     801             : 
     802           0 :   return frame->n_vectors;
     803             : 
     804             : }
     805             : 
     806             : /* *INDENT-OFF* */
     807       41439 : VNET_FEATURE_INIT (ip6_map_feature, static) =
     808             : {
     809             :   .arc_name = "ip6-unicast",
     810             :   .node_name = "ip6-map",
     811             :   .runs_before = VNET_FEATURES ("ip6-flow-classify"),
     812             :   .runs_after = VNET_FEATURES ("ip6-full-reassembly-feature"),
     813             : };
     814             : 
     815       77304 : VLIB_REGISTER_NODE(ip6_map_node) = {
     816             :   .function = ip6_map,
     817             :   .name = "ip6-map",
     818             :   .vector_size = sizeof(u32),
     819             :   .format_trace = format_map_trace,
     820             :   .type = VLIB_NODE_TYPE_INTERNAL,
     821             : 
     822             :   .n_errors = MAP_N_ERROR,
     823             :   .error_counters = map_error_counters,
     824             : 
     825             :   .n_next_nodes = IP6_MAP_N_NEXT,
     826             :   .next_nodes = {
     827             :     [IP6_MAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
     828             : #ifdef MAP_SKIP_IP6_LOOKUP
     829             :     [IP6_MAP_NEXT_IP4_REWRITE] = "ip4-load-balance",
     830             : #endif
     831             :     [IP6_MAP_NEXT_IP4_REASS] = "ip4-sv-reassembly-custom-next",
     832             :     [IP6_MAP_NEXT_IP4_FRAGMENT] = "ip4-frag",
     833             :     [IP6_MAP_NEXT_IP6_ICMP_RELAY] = "ip6-map-icmp-relay",
     834             :     [IP6_MAP_NEXT_IP6_LOCAL] = "ip6-local",
     835             :     [IP6_MAP_NEXT_DROP] = "error-drop",
     836             :     [IP6_MAP_NEXT_ICMP] = "ip6-icmp-error",
     837             :   },
     838             : };
     839             : /* *INDENT-ON* */
     840             : 
     841             : /* *INDENT-OFF* */
     842       77304 : VLIB_REGISTER_NODE(ip6_map_post_ip4_reass_node) = {
     843             :   .function = ip6_map_post_ip4_reass,
     844             :   .name = "ip6-map-post-ip4-reass",
     845             :   .vector_size = sizeof(u32),
     846             :   .format_trace = format_ip6_map_post_ip4_reass_trace,
     847             :   .type = VLIB_NODE_TYPE_INTERNAL,
     848             :   .n_errors = MAP_N_ERROR,
     849             :   .error_counters = map_error_counters,
     850             :   .n_next_nodes = IP6_MAP_POST_IP4_REASS_N_NEXT,
     851             :   .next_nodes = {
     852             :     [IP6_MAP_POST_IP4_REASS_NEXT_IP4_LOOKUP] = "ip4-lookup",
     853             :     [IP6_MAP_POST_IP4_REASS_NEXT_IP4_FRAGMENT] = "ip4-frag",
     854             :     [IP6_MAP_POST_IP4_REASS_NEXT_DROP] = "error-drop",
     855             :   },
     856             : };
     857             : /* *INDENT-ON* */
     858             : 
     859             : /* *INDENT-OFF* */
     860       77304 : VLIB_REGISTER_NODE(ip6_map_icmp_relay_node, static) = {
     861             :   .function = ip6_map_icmp_relay,
     862             :   .name = "ip6-map-icmp-relay",
     863             :   .vector_size = sizeof(u32),
     864             :   .format_trace = format_map_trace, //FIXME
     865             :   .type = VLIB_NODE_TYPE_INTERNAL,
     866             :   .n_errors = MAP_N_ERROR,
     867             :   .error_counters = map_error_counters,
     868             :   .n_next_nodes = IP6_ICMP_RELAY_N_NEXT,
     869             :   .next_nodes = {
     870             :     [IP6_ICMP_RELAY_NEXT_IP4_LOOKUP] = "ip4-lookup",
     871             :     [IP6_ICMP_RELAY_NEXT_DROP] = "error-drop",
     872             :   },
     873             : };
     874             : /* *INDENT-ON* */
     875             : 
     876             : clib_error_t *
     877         559 : ip6_map_init (vlib_main_t * vm)
     878             : {
     879         559 :   map_main.ip4_sv_reass_custom_next_index =
     880         559 :     ip4_sv_reass_custom_register_next_node
     881         559 :     (ip6_map_post_ip4_reass_node.index);
     882         559 :   return 0;
     883             : }
     884             : 
     885        1119 : VLIB_INIT_FUNCTION (ip6_map_init) =
     886             : {
     887             : .runs_after = VLIB_INITS ("map_init"),};
     888             : 
     889             : /*
     890             :  * fd.io coding-style-patch-verification: ON
     891             :  *
     892             :  * Local Variables:
     893             :  * eval: (c-set-style "gnu")
     894             :  * End:
     895             :  */

Generated by: LCOV version 1.14