LCOV - code coverage report
Current view: top level - vnet/hash - hash_eth.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 33 160 20.6 %
Date: 2023-07-05 22:20:52 Functions: 6 9 66.7 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2021 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #define _GNU_SOURCE
      19             : #include <stdint.h>
      20             : #include <vlib/vlib.h>
      21             : #include <vlib/unix/unix.h>
      22             : #include <vnet/ethernet/ethernet.h>
      23             : #include <vnet/ip/ip4_packet.h>
      24             : #include <vnet/ip/ip6_packet.h>
      25             : #include <vnet/ip/ip6_hop_by_hop_packet.h>
      26             : #include <vnet/tcp/tcp_packet.h>
      27             : #include <vppinfra/lb_hash_hash.h>
      28             : #include <vnet/hash/hash.h>
      29             : 
      30             : static_always_inline u16 *
      31           2 : locate_ethertype (ethernet_header_t *eth)
      32             : {
      33             :   u16 *ethertype_p;
      34             :   ethernet_vlan_header_t *vlan;
      35             : 
      36           2 :   if (!ethernet_frame_is_tagged (clib_net_to_host_u16 (eth->type)))
      37             :     {
      38           2 :       ethertype_p = &eth->type;
      39             :     }
      40             :   else
      41             :     {
      42           0 :       vlan = (void *) (eth + 1);
      43           0 :       ethertype_p = &vlan->type;
      44           0 :       if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
      45             :         {
      46           0 :           vlan++;
      47           0 :           ethertype_p = &vlan->type;
      48             :         }
      49             :     }
      50           2 :   return ethertype_p;
      51             : }
      52             : 
      53             : static void
      54           0 : hash_eth_l2 (void **p, u32 *hash, u32 n_packets)
      55             : {
      56           0 :   u32 n_left_from = n_packets;
      57             : 
      58           0 :   while (n_left_from >= 8)
      59             :     {
      60           0 :       ethernet_header_t *eth = *p;
      61           0 :       u64 *dst = (u64 *) &eth->dst_address[0];
      62           0 :       u64 a = clib_mem_unaligned (dst, u64);
      63           0 :       u32 *src = (u32 *) &eth->src_address[2];
      64           0 :       u32 b = clib_mem_unaligned (src, u32);
      65             : 
      66           0 :       clib_prefetch_load (p[4]);
      67           0 :       clib_prefetch_load (p[5]);
      68           0 :       clib_prefetch_load (p[6]);
      69           0 :       clib_prefetch_load (p[7]);
      70             : 
      71           0 :       hash[0] = lb_hash_hash_2_tuples (a, b);
      72           0 :       hash[1] = lb_hash_hash_2_tuples (a, b);
      73           0 :       hash[2] = lb_hash_hash_2_tuples (a, b);
      74           0 :       hash[3] = lb_hash_hash_2_tuples (a, b);
      75             : 
      76           0 :       hash += 4;
      77           0 :       n_left_from -= 4;
      78           0 :       p += 4;
      79             :     }
      80             : 
      81           0 :   while (n_left_from > 0)
      82             :     {
      83           0 :       ethernet_header_t *eth = *p;
      84           0 :       u64 *dst = (u64 *) &eth->dst_address[0];
      85           0 :       u64 a = clib_mem_unaligned (dst, u64);
      86           0 :       u32 *src = (u32 *) &eth->src_address[2];
      87           0 :       u32 b = clib_mem_unaligned (src, u32);
      88             : 
      89           0 :       hash[0] = lb_hash_hash_2_tuples (a, b);
      90             : 
      91           0 :       hash += 1;
      92           0 :       n_left_from -= 1;
      93           0 :       p += 1;
      94             :     }
      95           0 : }
      96             : 
      97             : static_always_inline u32
      98           0 : hash_eth_l23_inline (void **p)
      99             : {
     100           0 :   ethernet_header_t *eth = *p;
     101             :   u8 ip_version;
     102             :   ip4_header_t *ip4;
     103             :   u16 ethertype, *ethertype_p;
     104             :   u32 *mac1, *mac2, *mac3;
     105             :   u32 hash;
     106             : 
     107           0 :   ethertype_p = locate_ethertype (eth);
     108           0 :   ethertype = clib_mem_unaligned (ethertype_p, u16);
     109             : 
     110           0 :   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
     111           0 :       (ethertype != htons (ETHERNET_TYPE_IP6)))
     112             :     {
     113           0 :       hash_eth_l2 (p, &hash, 1);
     114           0 :       return hash;
     115             :     }
     116             : 
     117           0 :   ip4 = (ip4_header_t *) (ethertype_p + 1);
     118           0 :   ip_version = (ip4->ip_version_and_header_length >> 4);
     119             : 
     120           0 :   if (ip_version == 0x4)
     121             :     {
     122             :       u32 a;
     123             : 
     124           0 :       mac1 = (u32 *) &eth->dst_address[0];
     125           0 :       mac2 = (u32 *) &eth->dst_address[4];
     126           0 :       mac3 = (u32 *) &eth->src_address[2];
     127             : 
     128           0 :       a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
     129           0 :           clib_mem_unaligned (mac3, u32);
     130           0 :       hash = lb_hash_hash_2_tuples (
     131           0 :         clib_mem_unaligned (&ip4->address_pair, u64), a);
     132           0 :       return hash;
     133             :     }
     134             : 
     135           0 :   if (ip_version == 0x6)
     136             :     {
     137             :       u64 a;
     138           0 :       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
     139             : 
     140           0 :       mac1 = (u32 *) &eth->dst_address[0];
     141           0 :       mac2 = (u32 *) &eth->dst_address[4];
     142           0 :       mac3 = (u32 *) &eth->src_address[2];
     143             : 
     144           0 :       a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
     145           0 :           clib_mem_unaligned (mac3, u32);
     146           0 :       hash = lb_hash_hash (
     147           0 :         clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
     148           0 :         clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
     149           0 :         clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
     150           0 :         clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
     151           0 :       return hash;
     152             :     }
     153             : 
     154           0 :   hash_eth_l2 (p, &hash, 1);
     155           0 :   return hash;
     156             : }
     157             : 
     158             : static void
     159           0 : hash_eth_l23 (void **p, u32 *hash, u32 n_packets)
     160             : {
     161           0 :   u32 n_left_from = n_packets;
     162             : 
     163           0 :   while (n_left_from >= 8)
     164             :     {
     165           0 :       clib_prefetch_load (p[4]);
     166           0 :       clib_prefetch_load (p[5]);
     167           0 :       clib_prefetch_load (p[6]);
     168           0 :       clib_prefetch_load (p[7]);
     169             : 
     170           0 :       hash[0] = hash_eth_l23_inline (&p[0]);
     171           0 :       hash[1] = hash_eth_l23_inline (&p[1]);
     172           0 :       hash[2] = hash_eth_l23_inline (&p[2]);
     173           0 :       hash[3] = hash_eth_l23_inline (&p[3]);
     174             : 
     175           0 :       hash += 4;
     176           0 :       n_left_from -= 4;
     177           0 :       p += 4;
     178             :     }
     179             : 
     180           0 :   while (n_left_from > 0)
     181             :     {
     182           0 :       hash[0] = hash_eth_l23_inline (&p[0]);
     183             : 
     184           0 :       hash += 1;
     185           0 :       n_left_from -= 1;
     186           0 :       p += 1;
     187             :     }
     188           0 : }
     189             : 
     190             : static_always_inline u32
     191           2 : hash_eth_l34_inline (void **p)
     192             : {
     193           2 :   ethernet_header_t *eth = *p;
     194             :   u8 ip_version;
     195             :   uword is_tcp_udp;
     196             :   ip4_header_t *ip4;
     197             :   u16 ethertype, *ethertype_p;
     198             :   u32 hash;
     199             : 
     200           2 :   ethertype_p = locate_ethertype (eth);
     201           2 :   ethertype = clib_mem_unaligned (ethertype_p, u16);
     202             : 
     203           2 :   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
     204           0 :       (ethertype != htons (ETHERNET_TYPE_IP6)))
     205             :     {
     206           0 :       hash_eth_l2 (p, &hash, 1);
     207           0 :       return hash;
     208             :     }
     209             : 
     210           2 :   ip4 = (ip4_header_t *) (ethertype_p + 1);
     211           2 :   ip_version = (ip4->ip_version_and_header_length >> 4);
     212             : 
     213           2 :   if (ip_version == 0x4)
     214             :     {
     215             :       u32 a, t1, t2;
     216           2 :       tcp_header_t *tcp = (void *) (ip4 + 1);
     217             : 
     218           4 :       is_tcp_udp = (ip4->protocol == IP_PROTOCOL_TCP) ||
     219           2 :                    (ip4->protocol == IP_PROTOCOL_UDP);
     220           2 :       t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
     221           2 :       t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
     222           2 :       a = t1 ^ t2;
     223           4 :       hash = lb_hash_hash_2_tuples (
     224           2 :         clib_mem_unaligned (&ip4->address_pair, u64), a);
     225           2 :       return hash;
     226             :     }
     227             : 
     228           0 :   if (ip_version == 0x6)
     229             :     {
     230             :       u64 a;
     231             :       u32 t1, t2;
     232           0 :       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
     233           0 :       tcp_header_t *tcp = (void *) (ip6 + 1);
     234             : 
     235           0 :       is_tcp_udp = 0;
     236           0 :       if (PREDICT_TRUE ((ip6->protocol == IP_PROTOCOL_TCP) ||
     237             :                         (ip6->protocol == IP_PROTOCOL_UDP)))
     238             :         {
     239           0 :           is_tcp_udp = 1;
     240           0 :           tcp = (void *) (ip6 + 1);
     241             :         }
     242           0 :       else if (ip6->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
     243             :         {
     244           0 :           ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip6 + 1);
     245           0 :           if ((hbh->protocol == IP_PROTOCOL_TCP) ||
     246           0 :               (hbh->protocol == IP_PROTOCOL_UDP))
     247             :             {
     248           0 :               is_tcp_udp = 1;
     249           0 :               tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
     250             :             }
     251             :         }
     252           0 :       t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
     253           0 :       t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
     254           0 :       a = t1 ^ t2;
     255           0 :       hash = lb_hash_hash (
     256           0 :         clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
     257           0 :         clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
     258           0 :         clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
     259           0 :         clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
     260           0 :       return hash;
     261             :     }
     262             : 
     263           0 :   hash_eth_l2 (p, &hash, 1);
     264           0 :   return hash;
     265             : }
     266             : 
     267             : static void
     268           1 : hash_eth_l34 (void **p, u32 *hash, u32 n_packets)
     269             : {
     270           1 :   u32 n_left_from = n_packets;
     271             : 
     272           1 :   while (n_left_from >= 8)
     273             :     {
     274           0 :       clib_prefetch_load (p[4]);
     275           0 :       clib_prefetch_load (p[5]);
     276           0 :       clib_prefetch_load (p[6]);
     277           0 :       clib_prefetch_load (p[7]);
     278             : 
     279           0 :       hash[0] = hash_eth_l34_inline (&p[0]);
     280           0 :       hash[1] = hash_eth_l34_inline (&p[1]);
     281           0 :       hash[2] = hash_eth_l34_inline (&p[2]);
     282           0 :       hash[3] = hash_eth_l34_inline (&p[3]);
     283             : 
     284           0 :       hash += 4;
     285           0 :       n_left_from -= 4;
     286           0 :       p += 4;
     287             :     }
     288             : 
     289           3 :   while (n_left_from > 0)
     290             :     {
     291           2 :       hash[0] = hash_eth_l34_inline (&p[0]);
     292             : 
     293           2 :       hash += 1;
     294           2 :       n_left_from -= 1;
     295           2 :       p += 1;
     296             :     }
     297           1 : }
     298             : 
     299         559 : VNET_REGISTER_HASH_FUNCTION (hash_eth_l2, static) = {
     300             :   .name = "hash-eth-l2",
     301             :   .description = "Hash ethernet L2 headers",
     302             :   .priority = 50,
     303             :   .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l2,
     304             : };
     305             : 
     306         559 : VNET_REGISTER_HASH_FUNCTION (hash_eth_l23, static) = {
     307             :   .name = "hash-eth-l23",
     308             :   .description = "Hash ethernet L23 headers",
     309             :   .priority = 50,
     310             :   .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l23,
     311             : };
     312             : 
     313         559 : VNET_REGISTER_HASH_FUNCTION (hash_eth_l34, static) = {
     314             :   .name = "hash-eth-l34",
     315             :   .description = "Hash ethernet L34 headers",
     316             :   .priority = 50,
     317             :   .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l34,
     318             : };
     319             : 
     320             : /*
     321             :  * fd.io coding-style-patch-verification: ON
     322             :  *
     323             :  * Local Variables:
     324             :  * eval: (c-set-style "gnu")
     325             :  * End:
     326             :  */

Generated by: LCOV version 1.14