LCOV - code coverage report
Current view: top level - vnet/ipip - node.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 108 114 94.7 %
Date: 2023-10-26 01:39:38 Functions: 16 22 72.7 %

          Line data    Source code
       1             : /*
       2             :  * node.c: ipip packet processing
       3             :  *
       4             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       5             :  * Licensed under the Apache License, Version 2.0 (the "License");
       6             :  * you may not use this file except in compliance with the License.
       7             :  * You may obtain a copy of the License at:
       8             :  *
       9             :  *     http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  * Unless required by applicable law or aipiped to in writing, software
      12             :  * distributed under the License is distributed on an "AS IS" BASIS,
      13             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  * See the License for the specific language governing permissions and
      15             :  * limitations under the License.
      16             :  */
      17             : 
      18             : #include <vlib/vlib.h>
      19             : #include <vnet/ipip/ipip.h>
      20             : #include <vnet/ip/ip6_packet.h>
      21             : #include <vnet/mpls/mpls.h>
      22             : #include <vnet/tunnel/tunnel_dp.h>
      23             : #include <vppinfra/sparse_vec.h>
      24             : 
      25             : #define foreach_ipip_input_next                                               \
      26             :   _ (PUNT, "error-punt")                                                      \
      27             :   _ (DROP, "error-drop")                                                      \
      28             :   _ (IP4_INPUT, "ip4-input")                                                  \
      29             :   _ (IP6_INPUT, "ip6-input")                                                  \
      30             :   _ (MPLS_INPUT, "mpls-input")
      31             : 
      32             : typedef enum
      33             : {
      34             : #define _(s, n) IPIP_INPUT_NEXT_##s,
      35             :   foreach_ipip_input_next
      36             : #undef _
      37             :     IPIP_INPUT_N_NEXT,
      38             : } ipip_input_next_t;
      39             : 
      40             : typedef struct
      41             : {
      42             :   u32 tunnel_id;
      43             :   u32 length;
      44             :   ip46_address_t src;
      45             :   ip46_address_t dst;
      46             :   u8 is_ipv6;
      47             : } ipip_rx_trace_t;
      48             : 
      49             : static u8 *
      50        3193 : format_ipip_rx_trace (u8 * s, va_list * args)
      51             : {
      52        3193 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
      53        3193 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
      54        3193 :   ipip_rx_trace_t *t = va_arg (*args, ipip_rx_trace_t *);
      55             : 
      56        3193 :   s = format (s, "IPIP: tunnel %d len %d src %U dst %U", t->tunnel_id,
      57        3193 :               clib_net_to_host_u16 (t->length), format_ip46_address, &t->src,
      58             :               IP46_TYPE_ANY, format_ip46_address, &t->dst, IP46_TYPE_ANY);
      59        3193 :   return s;
      60             : }
      61             : 
      62             : always_inline uword
      63          99 : ipip_input (vlib_main_t * vm, vlib_node_runtime_t * node,
      64             :             vlib_frame_t * from_frame, bool is_ipv6)
      65             : {
      66          99 :   ipip_main_t *gm = &ipip_main;
      67             :   u32 n_left_from, next_index, *from, *to_next, n_left_to_next;
      68          99 :   u32 tunnel_sw_if_index = ~0;
      69          99 :   u32 thread_index = vm->thread_index;
      70             :   u32 len;
      71          99 :   vnet_interface_main_t *im = &gm->vnet_main->interface_main;
      72             : 
      73          99 :   from = vlib_frame_vector_args (from_frame);
      74          99 :   n_left_from = from_frame->n_vectors;
      75          99 :   next_index = node->cached_next_index;
      76         198 :   while (n_left_from > 0)
      77             :     {
      78          99 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
      79             : 
      80        6219 :       while (n_left_from > 0 && n_left_to_next > 0)
      81             :         {
      82             :           u32 bi0;
      83             :           vlib_buffer_t *b0;
      84             :           ip4_header_t *ip40;
      85             :           ip6_header_t *ip60;
      86        6120 :           u32 next0 = IPIP_INPUT_NEXT_DROP;
      87             :           u8 inner_protocol0;
      88             : 
      89        6120 :           bi0 = to_next[0] = from[0];
      90        6120 :           from += 1;
      91        6120 :           n_left_from -= 1;
      92        6120 :           to_next += 1;
      93        6120 :           n_left_to_next -= 1;
      94             : 
      95        6120 :           b0 = vlib_get_buffer (vm, bi0);
      96             : 
      97        6120 :           ipip_tunnel_key_t key0 = {
      98        6120 :             .fib_index = vnet_buffer (b0)->ip.fib_index,
      99             :             .mode = IPIP_MODE_P2P,
     100             :           };
     101             : 
     102        6120 :           if (is_ipv6)
     103             :             {
     104        2459 :               ip60 = vlib_buffer_get_current (b0);
     105             :               /* Check for outer fragmentation */
     106        2459 :               if (ip60->protocol == IP_PROTOCOL_IPV6_FRAGMENTATION)
     107             :                 {
     108           0 :                   next0 = IPIP_INPUT_NEXT_DROP;
     109           0 :                   b0->error = node->errors[IPIP_ERROR_FRAGMENTED_PACKET];
     110           0 :                   goto drop;
     111             :                 }
     112             : 
     113        2459 :               vlib_buffer_advance (b0, sizeof (*ip60));
     114        2459 :               ip_set (&key0.dst, &ip60->src_address, false);
     115        2459 :               ip_set (&key0.src, &ip60->dst_address, false);
     116        2459 :               inner_protocol0 = ip60->protocol;
     117        2459 :               key0.transport = IPIP_TRANSPORT_IP6;
     118             :             }
     119             :           else
     120             :             {
     121        3661 :               ip40 = vlib_buffer_get_current (b0);
     122             :               /* Check for outer fragmentation */
     123        3661 :               if (ip40->flags_and_fragment_offset &
     124        3661 :                   clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS))
     125             :                 {
     126           0 :                   next0 = IPIP_INPUT_NEXT_DROP;
     127           0 :                   b0->error = node->errors[IPIP_ERROR_FRAGMENTED_PACKET];
     128           0 :                   goto drop;
     129             :                 }
     130        3661 :               vlib_buffer_advance (b0, sizeof (*ip40));
     131        3661 :               ip_set (&key0.dst, &ip40->src_address, true);
     132        3661 :               ip_set (&key0.src, &ip40->dst_address, true);
     133        3661 :               inner_protocol0 = ip40->protocol;
     134        3661 :               key0.transport = IPIP_TRANSPORT_IP4;
     135             :             }
     136             : 
     137             :           /*
     138             :            * Find tunnel. First a lookup for P2P tunnels, then a lookup
     139             :            * for multipoint tunnels
     140             :            */
     141        6120 :           ipip_tunnel_t *t0 = ipip_tunnel_db_find (&key0);
     142        6120 :           if (!t0)
     143             :             {
     144         458 :               ip46_address_reset (&key0.dst);
     145         458 :               key0.mode = IPIP_MODE_6RD;
     146         458 :               t0 = ipip_tunnel_db_find (&key0);
     147         458 :               if (!t0)
     148             :                 {
     149         378 :                   next0 = IPIP_INPUT_NEXT_DROP;
     150         378 :                   b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
     151         378 :                   goto drop;
     152             :                 }
     153             :             }
     154        5742 :           tunnel_sw_if_index = t0->sw_if_index;
     155             : 
     156        5742 :           len = vlib_buffer_length_in_chain (vm, b0);
     157        5742 :           vnet_buffer (b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
     158             : 
     159        5742 :           if (inner_protocol0 == IP_PROTOCOL_IPV6)
     160             :             {
     161        2465 :               next0 = IPIP_INPUT_NEXT_IP6_INPUT;
     162             : 
     163        2465 :               if (is_ipv6)
     164        1881 :                 tunnel_decap_fixup_6o6 (t0->flags, (ip60 + 1), ip60);
     165             :               else
     166         584 :                 tunnel_decap_fixup_6o4 (t0->flags,
     167         584 :                                         (ip6_header_t *) (ip40 + 1), ip40);
     168             :             }
     169        3277 :           else if (inner_protocol0 == IP_PROTOCOL_IP_IN_IP)
     170             :             {
     171        3151 :               next0 = IPIP_INPUT_NEXT_IP4_INPUT;
     172             : 
     173        3151 :               if (is_ipv6)
     174         515 :                 tunnel_decap_fixup_4o6 (t0->flags,
     175         515 :                                         (ip4_header_t *) (ip60 + 1), ip60);
     176             :               else
     177        2636 :                 tunnel_decap_fixup_4o4 (t0->flags, ip40 + 1, ip40);
     178             :             }
     179         126 :           else if (inner_protocol0 == IP_PROTOCOL_MPLS_IN_IP)
     180             :             {
     181         126 :               next0 = IPIP_INPUT_NEXT_MPLS_INPUT;
     182             : 
     183         126 :               if (is_ipv6)
     184          63 :                 tunnel_decap_fixup_mplso6 (
     185          63 :                   t0->flags, (mpls_unicast_header_t *) (ip60 + 1), ip60);
     186             :               else
     187          63 :                 tunnel_decap_fixup_mplso4 (
     188          63 :                   t0->flags, (mpls_unicast_header_t *) ip40 + 1, ip40);
     189             :             }
     190             : 
     191        5742 :           if (!is_ipv6 && t0->mode == IPIP_MODE_6RD
     192          80 :               && t0->sixrd.security_check)
     193             :             {
     194          70 :               ip6_header_t *inner_ip60 = vlib_buffer_get_current (b0);
     195          70 :               if (sixrd_get_addr_net (t0, inner_ip60->src_address.as_u64[0])
     196          70 :                   != ip40->src_address.as_u32)
     197             :                 {
     198          10 :                   next0 = IPIP_INPUT_NEXT_DROP;
     199          10 :                   b0->error = node->errors[IPIP_ERROR_NO_TUNNEL];
     200          10 :                   goto drop;
     201             :                 }
     202             :             }
     203             : 
     204        5732 :           vlib_increment_combined_counter (im->combined_sw_if_counters +
     205             :                                            VNET_INTERFACE_COUNTER_RX,
     206             :                                            thread_index, tunnel_sw_if_index,
     207             :                                            1 /* packets */ ,
     208             :                                            len /* bytes */ );
     209             : 
     210        6120 :         drop:
     211        6120 :           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
     212             :             {
     213             :               ipip_rx_trace_t *tr =
     214        4788 :                 vlib_add_trace (vm, node, b0, sizeof (*tr));
     215        4788 :               tr->tunnel_id = tunnel_sw_if_index;
     216        4788 :               if (is_ipv6)
     217             :                 {
     218        1793 :                   tr->length = ip60->payload_length;
     219        1793 :                   tr->src.ip6.as_u64[0] = ip60->src_address.as_u64[0];
     220        1793 :                   tr->src.ip6.as_u64[1] = ip60->src_address.as_u64[1];
     221        1793 :                   tr->dst.ip6.as_u64[0] = ip60->dst_address.as_u64[0];
     222        1793 :                   tr->dst.ip6.as_u64[1] = ip60->dst_address.as_u64[1];
     223             :                 }
     224             :               else
     225             :                 {
     226        2995 :                   tr->length = ip40->length;
     227        2995 :                   tr->src.ip4.as_u32 = ip40->src_address.as_u32;
     228        2995 :                   tr->dst.ip4.as_u32 = ip40->dst_address.as_u32;
     229             :                 }
     230             :             }
     231             : 
     232        6120 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
     233             :                                            n_left_to_next, bi0, next0);
     234             :         }
     235             : 
     236          99 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     237             :     }
     238          99 :   vlib_node_increment_counter (vm,
     239          99 :                                !is_ipv6 ? ipip4_input_node.index :
     240             :                                ipip6_input_node.index, IPIP_ERROR_DECAP_PKTS,
     241          99 :                                from_frame->n_vectors);
     242          99 :   return from_frame->n_vectors;
     243             : }
     244             : 
     245        2362 : VLIB_NODE_FN (ipip4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     246             :                                  vlib_frame_t * from_frame)
     247             : {
     248          62 :   return ipip_input (vm, node, from_frame, /* is_ip6 */ false);
     249             : }
     250             : 
     251        2337 : VLIB_NODE_FN (ipip6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
     252             :                                  vlib_frame_t * from_frame)
     253             : {
     254          37 :   return ipip_input (vm, node, from_frame, /* is_ip6 */ true);
     255             : }
     256             : 
     257             : static char *ipip_error_strings[] = {
     258             : #define _(sym,string) string,
     259             :   foreach_ipip_error
     260             : #undef _
     261             : };
     262             : 
     263             : /* *INDENT-OFF* */
     264      183788 : VLIB_REGISTER_NODE(ipip4_input_node) = {
     265             :     .name = "ipip4-input",
     266             :     /* Takes a vector of packets. */
     267             :     .vector_size = sizeof(u32),
     268             :     .n_errors = IPIP_N_ERROR,
     269             :     .error_strings = ipip_error_strings,
     270             :     .n_next_nodes = IPIP_INPUT_N_NEXT,
     271             :     .next_nodes =
     272             :         {
     273             : #define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
     274             :             foreach_ipip_input_next
     275             : #undef _
     276             :         },
     277             :     .format_trace = format_ipip_rx_trace,
     278             : };
     279             : 
     280      183788 : VLIB_REGISTER_NODE(ipip6_input_node) = {
     281             :     .name = "ipip6-input",
     282             :     /* Takes a vector of packets. */
     283             :     .vector_size = sizeof(u32),
     284             :     .n_errors = IPIP_N_ERROR,
     285             :     .error_strings = ipip_error_strings,
     286             :     .n_next_nodes = IPIP_INPUT_N_NEXT,
     287             :     .next_nodes =
     288             :         {
     289             : #define _(s, n) [IPIP_INPUT_NEXT_##s] = n,
     290             :             foreach_ipip_input_next
     291             : #undef _
     292             :         },
     293             :     .format_trace = format_ipip_rx_trace,
     294             : };
     295             : 
     296             : /* *INDENT-ON* */
     297             : 
     298             : /*
     299             :  * fd.io coding-style-patch-verification: ON
     300             :  *
     301             :  * Local Variables:
     302             :  * eval: (c-set-style "gnu")
     303             :  * End:
     304             :  */

Generated by: LCOV version 1.14