LCOV - code coverage report
Current view: top level - vnet/udp - udp_inlines.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 135 139 97.1 %
Date: 2023-07-05 22:20:52 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #ifndef SRC_VNET_UDP_UDP_INLINES_H_
      17             : #define SRC_VNET_UDP_UDP_INLINES_H_
      18             : 
      19             : #include <vnet/vnet.h>
      20             : #include <vnet/ip/ip4.h>
      21             : #include <vnet/ip/ip6.h>
      22             : #include <vnet/udp/udp_packet.h>
      23             : #include <vnet/interface_output.h>
      24             : #include <vnet/ip/ip4_inlines.h>
      25             : #include <vnet/ip/ip6_inlines.h>
      26             : #include <vnet/udp/udp_encap.h>
      27             : 
      28             : always_inline void *
      29       58172 : vlib_buffer_push_udp (vlib_buffer_t * b, u16 sp, u16 dp, u8 offload_csum)
      30             : {
      31             :   udp_header_t *uh;
      32       58172 :   u16 udp_len = sizeof (udp_header_t) + b->current_length;
      33       58172 :   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
      34           0 :     udp_len += b->total_length_not_including_first_buffer;
      35             : 
      36       58172 :   uh = vlib_buffer_push_uninit (b, sizeof (udp_header_t));
      37       58172 :   uh->src_port = sp;
      38       58172 :   uh->dst_port = dp;
      39       58172 :   uh->checksum = 0;
      40       58172 :   uh->length = clib_host_to_net_u16 (udp_len);
      41       58172 :   if (offload_csum)
      42       58172 :     vnet_buffer_offload_flags_set (b, VNET_BUFFER_OFFLOAD_F_UDP_CKSUM);
      43       58172 :   vnet_buffer (b)->l4_hdr_offset = (u8 *) uh - b->data;
      44       58172 :   b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID;
      45       58172 :   return uh;
      46             : }
      47             : 
      48             : /*
      49             :  * Encode udp source port entropy value per
      50             :  * https://datatracker.ietf.org/doc/html/rfc7510#section-3
      51             :  */
      52             : always_inline u16
      53         268 : ip_udp_sport_entropy (vlib_buffer_t *b0)
      54             : {
      55         268 :   u16 port = clib_host_to_net_u16 (0x03 << 14);
      56         268 :   port |= vnet_buffer (b0)->ip.flow_hash & 0xffff;
      57         268 :   return port;
      58             : }
      59             : 
      60             : always_inline u32
      61         268 : ip_udp_compute_flow_hash (vlib_buffer_t *b0, u8 is_ip4)
      62             : {
      63             :   ip4_header_t *ip4;
      64             :   ip6_header_t *ip6;
      65             : 
      66         268 :   if (is_ip4)
      67             :     {
      68         134 :       ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
      69         134 :       return ip4_compute_flow_hash (ip4, IP_FLOW_HASH_DEFAULT);
      70             :     }
      71             :   else
      72             :     {
      73         134 :       ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
      74         134 :       return ip6_compute_flow_hash (ip6, IP_FLOW_HASH_DEFAULT);
      75             :     }
      76             : }
      77             : 
      78             : always_inline void
      79          29 : ip_udp_fixup_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 is_ip4,
      80             :                   u8 sport_entropy)
      81             : {
      82             :   u16 new_l0;
      83             :   udp_header_t *udp0;
      84             : 
      85          29 :   if (is_ip4)
      86             :     {
      87             :       ip4_header_t *ip0;
      88             :       ip_csum_t sum0;
      89          17 :       u16 old_l0 = 0;
      90             : 
      91          17 :       ip0 = vlib_buffer_get_current (b0);
      92             : 
      93             :       /* fix the <bleep>ing outer-IP checksum */
      94          17 :       sum0 = ip0->checksum;
      95             :       /* old_l0 always 0, see the rewrite setup */
      96          17 :       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
      97             : 
      98          17 :       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
      99             :                              length /* changed member */ );
     100          17 :       ip0->checksum = ip_csum_fold (sum0);
     101          17 :       ip0->length = new_l0;
     102             : 
     103             :       /* Fix UDP length */
     104          17 :       udp0 = (udp_header_t *) (ip0 + 1);
     105          17 :       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
     106          17 :                                      - sizeof (*ip0));
     107          17 :       udp0->length = new_l0;
     108             : 
     109          17 :       if (sport_entropy)
     110           6 :         udp0->src_port = ip_udp_sport_entropy (b0);
     111             :     }
     112             :   else
     113             :     {
     114             :       ip6_header_t *ip0;
     115             :       int bogus0;
     116             : 
     117          12 :       ip0 = vlib_buffer_get_current (b0);
     118             : 
     119          12 :       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
     120          12 :                                      - sizeof (*ip0));
     121          12 :       ip0->payload_length = new_l0;
     122             : 
     123             :       /* Fix UDP length */
     124          12 :       udp0 = (udp_header_t *) (ip0 + 1);
     125          12 :       udp0->length = new_l0;
     126             : 
     127          12 :       if (sport_entropy)
     128           6 :         udp0->src_port = ip_udp_sport_entropy (b0);
     129             : 
     130          12 :       udp0->checksum =
     131          12 :         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
     132          12 :       ASSERT (bogus0 == 0);
     133             : 
     134          12 :       if (udp0->checksum == 0)
     135           0 :         udp0->checksum = 0xffff;
     136             :     }
     137          29 : }
     138             : 
     139             : always_inline void
     140          28 : ip_udp_encap_one (vlib_main_t *vm, vlib_buffer_t *b0, u8 *ec0, word ec_len,
     141             :                   ip_address_family_t encap_family,
     142             :                   ip_address_family_t payload_family,
     143             :                   udp_encap_fixup_flags_t flags)
     144             : {
     145          28 :   u8 sport_entropy = (flags & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
     146             : 
     147          28 :   if (payload_family < N_AF)
     148             :     {
     149          28 :       vnet_calc_checksums_inline (vm, b0, payload_family == AF_IP4,
     150             :                                   payload_family == AF_IP6);
     151             : 
     152             :       /* Сalculate flow hash to be used for entropy */
     153          28 :       if (sport_entropy && 0 == vnet_buffer (b0)->ip.flow_hash)
     154          12 :         vnet_buffer (b0)->ip.flow_hash =
     155          12 :           ip_udp_compute_flow_hash (b0, payload_family == AF_IP4);
     156             :     }
     157             : 
     158          28 :   vlib_buffer_advance (b0, -ec_len);
     159             : 
     160          28 :   if (encap_family == AF_IP4)
     161             :     {
     162             :       ip4_header_t *ip0;
     163             : 
     164          16 :       ip0 = vlib_buffer_get_current (b0);
     165             : 
     166             :       /* Apply the encap string. */
     167          16 :       clib_memcpy_fast (ip0, ec0, ec_len);
     168          16 :       ip_udp_fixup_one (vm, b0, 1, sport_entropy);
     169             :     }
     170             :   else
     171             :     {
     172             :       ip6_header_t *ip0;
     173             : 
     174          12 :       ip0 = vlib_buffer_get_current (b0);
     175             : 
     176             :       /* Apply the encap string. */
     177          12 :       clib_memcpy_fast (ip0, ec0, ec_len);
     178          12 :       ip_udp_fixup_one (vm, b0, 0, sport_entropy);
     179             :     }
     180          28 : }
     181             : 
     182             : always_inline void
     183         288 : ip_udp_encap_two (vlib_main_t *vm, vlib_buffer_t *b0, vlib_buffer_t *b1,
     184             :                   u8 *ec0, u8 *ec1, word ec_len,
     185             :                   ip_address_family_t encap_family,
     186             :                   ip_address_family_t payload_family,
     187             :                   udp_encap_fixup_flags_t flags0,
     188             :                   udp_encap_fixup_flags_t flags1)
     189             : {
     190             :   u16 new_l0, new_l1;
     191             :   udp_header_t *udp0, *udp1;
     192         288 :   int payload_ip4 = (payload_family == AF_IP4);
     193         288 :   int sport_entropy0 = (flags0 & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
     194         288 :   int sport_entropy1 = (flags1 & UDP_ENCAP_FIXUP_UDP_SRC_PORT_ENTROPY) != 0;
     195             : 
     196         288 :   if (payload_family < N_AF)
     197             :     {
     198         288 :       vnet_calc_checksums_inline (vm, b0, payload_ip4, !payload_ip4);
     199         288 :       vnet_calc_checksums_inline (vm, b1, payload_ip4, !payload_ip4);
     200             : 
     201             :       /* Сalculate flow hash to be used for entropy */
     202         288 :       if (sport_entropy0 && 0 == vnet_buffer (b0)->ip.flow_hash)
     203         128 :         vnet_buffer (b0)->ip.flow_hash =
     204         128 :           ip_udp_compute_flow_hash (b0, payload_ip4);
     205         288 :       if (sport_entropy1 && 0 == vnet_buffer (b1)->ip.flow_hash)
     206         128 :         vnet_buffer (b1)->ip.flow_hash =
     207         128 :           ip_udp_compute_flow_hash (b1, payload_ip4);
     208             :     }
     209             : 
     210         288 :   vlib_buffer_advance (b0, -ec_len);
     211         288 :   vlib_buffer_advance (b1, -ec_len);
     212             : 
     213         288 :   if (encap_family == AF_IP4)
     214             :     {
     215             :       ip4_header_t *ip0, *ip1;
     216             :       ip_csum_t sum0, sum1;
     217         160 :       u16 old_l0 = 0, old_l1 = 0;
     218             : 
     219         160 :       ip0 = vlib_buffer_get_current (b0);
     220         160 :       ip1 = vlib_buffer_get_current (b1);
     221             : 
     222             :       /* Apply the encap string */
     223         160 :       clib_memcpy_fast (ip0, ec0, ec_len);
     224         160 :       clib_memcpy_fast (ip1, ec1, ec_len);
     225             : 
     226             :       /* fix the <bleep>ing outer-IP checksum */
     227         160 :       sum0 = ip0->checksum;
     228         160 :       sum1 = ip1->checksum;
     229             : 
     230             :       /* old_l0 always 0, see the rewrite setup */
     231         160 :       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
     232         160 :       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
     233             : 
     234         160 :       sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
     235             :                              length /* changed member */ );
     236         160 :       sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
     237             :                              length /* changed member */ );
     238             : 
     239         160 :       ip0->checksum = ip_csum_fold (sum0);
     240         160 :       ip1->checksum = ip_csum_fold (sum1);
     241             : 
     242         160 :       ip0->length = new_l0;
     243         160 :       ip1->length = new_l1;
     244             : 
     245             :       /* Fix UDP length */
     246         160 :       udp0 = (udp_header_t *) (ip0 + 1);
     247         160 :       udp1 = (udp_header_t *) (ip1 + 1);
     248             : 
     249             :       new_l0 =
     250         160 :         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
     251             :                               sizeof (*ip0));
     252             :       new_l1 =
     253         160 :         clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1) -
     254             :                               sizeof (*ip1));
     255         160 :       udp0->length = new_l0;
     256         160 :       udp1->length = new_l1;
     257             : 
     258         160 :       if (sport_entropy0)
     259          64 :         udp0->src_port = ip_udp_sport_entropy (b0);
     260         160 :       if (sport_entropy1)
     261          64 :         udp1->src_port = ip_udp_sport_entropy (b1);
     262             :     }
     263             :   else
     264             :     {
     265             :       ip6_header_t *ip0, *ip1;
     266             :       int bogus0, bogus1;
     267             : 
     268         128 :       ip0 = vlib_buffer_get_current (b0);
     269         128 :       ip1 = vlib_buffer_get_current (b1);
     270             : 
     271             :       /* Apply the encap string. */
     272         128 :       clib_memcpy_fast (ip0, ec0, ec_len);
     273         128 :       clib_memcpy_fast (ip1, ec1, ec_len);
     274             : 
     275         128 :       new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
     276         128 :                                      - sizeof (*ip0));
     277         128 :       new_l1 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1)
     278         128 :                                      - sizeof (*ip1));
     279         128 :       ip0->payload_length = new_l0;
     280         128 :       ip1->payload_length = new_l1;
     281             : 
     282             :       /* Fix UDP length */
     283         128 :       udp0 = (udp_header_t *) (ip0 + 1);
     284         128 :       udp1 = (udp_header_t *) (ip1 + 1);
     285             : 
     286         128 :       udp0->length = new_l0;
     287         128 :       udp1->length = new_l1;
     288             : 
     289         128 :       if (sport_entropy0)
     290          64 :         udp0->src_port = ip_udp_sport_entropy (b0);
     291         128 :       if (sport_entropy1)
     292          64 :         udp1->src_port = ip_udp_sport_entropy (b1);
     293             : 
     294         128 :       udp0->checksum =
     295         128 :         ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
     296         128 :       udp1->checksum =
     297         128 :         ip6_tcp_udp_icmp_compute_checksum (vm, b1, ip1, &bogus1);
     298         128 :       ASSERT (bogus0 == 0);
     299         128 :       ASSERT (bogus1 == 0);
     300             : 
     301         128 :       if (udp0->checksum == 0)
     302           0 :         udp0->checksum = 0xffff;
     303         128 :       if (udp1->checksum == 0)
     304           0 :         udp1->checksum = 0xffff;
     305             :     }
     306         288 : }
     307             : 
     308             : #endif /* SRC_VNET_UDP_UDP_INLINES_H_ */
     309             : 
     310             : /*
     311             :  * fd.io coding-style-patch-verification: ON
     312             :  *
     313             :  * Local Variables:
     314             :  * eval: (c-set-style "gnu")
     315             :  * End:
     316             :  */

Generated by: LCOV version 1.14