2 * SPDX-License-Identifier: Apache-2.0
3 * Copyright(c) 2021 Cisco Systems, Inc.
7 #include <vnet/ethernet/ethernet.h>
8 #include <vnet/ip/ip4_packet.h>
9 #include <vnet/ip/ip6_packet.h>
10 #include <vnet/hash/hash.h>
11 #include <vppinfra/crc32.h>
13 #ifdef clib_crc32c_uses_intrinsics
15 static const u8 l4_mask_bits[256] = {
16 [IP_PROTOCOL_ICMP] = 16, [IP_PROTOCOL_IGMP] = 8,
17 [IP_PROTOCOL_TCP] = 32, [IP_PROTOCOL_UDP] = 32,
18 [IP_PROTOCOL_IPSEC_ESP] = 32, [IP_PROTOCOL_IPSEC_AH] = 32,
19 [IP_PROTOCOL_ICMP6] = 16,
22 static_always_inline u32
23 compute_ip6_key (ip6_header_t *ip)
27 /* dst + src ip as u64 */
28 hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 8));
29 hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 16));
30 hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 24));
31 hash = clib_crc32c_u64 (hash, *(u64u *) ((u8 *) ip + 32));
33 l4hdr = *(u32 *) ip6_next_header (ip) & pow2_mask (l4_mask_bits[pr]);
34 /* protocol + l4 hdr */
35 return clib_crc32c_u64 (hash, ((u64) pr << 32) | l4hdr);
38 static_always_inline u32
39 compute_ip4_key (ip4_header_t *ip)
43 /* dst + src ip as u64 */
44 hash = clib_crc32c_u64 (0, *(u64 *) ((u8 *) ip + 12));
46 l4hdr = *(u32 *) ip4_next_header (ip) & pow2_mask (l4_mask_bits[pr]);
47 /* protocol + l4 hdr */
48 return clib_crc32c_u64 (hash, ((u64) pr << 32) | l4hdr);
50 static_always_inline u32
51 compute_ip_key (void *p)
53 if ((((u8 *) p)[0] & 0xf0) == 0x40)
54 return compute_ip4_key (p);
55 else if ((((u8 *) p)[0] & 0xf0) == 0x60)
56 return compute_ip6_key (p);
61 vnet_crc32c_5tuple_ip_func (void **p, u32 *hash, u32 n_packets)
63 u32 n_left_from = n_packets;
65 while (n_left_from >= 8)
67 clib_prefetch_load (p[4]);
68 clib_prefetch_load (p[5]);
69 clib_prefetch_load (p[6]);
70 clib_prefetch_load (p[7]);
72 hash[0] = compute_ip_key (p[0]);
73 hash[1] = compute_ip_key (p[1]);
74 hash[2] = compute_ip_key (p[2]);
75 hash[3] = compute_ip_key (p[3]);
82 while (n_left_from > 0)
84 hash[0] = compute_ip_key (p[0]);
92 static_always_inline u32
93 compute_ethernet_key (void *p)
95 u16 ethertype = 0, l2hdr_sz = 0;
97 ethernet_header_t *eh = (ethernet_header_t *) p;
98 ethertype = clib_net_to_host_u16 (eh->type);
99 l2hdr_sz = sizeof (ethernet_header_t);
101 if (ethernet_frame_is_tagged (ethertype))
103 ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
105 ethertype = clib_net_to_host_u16 (vlan->type);
106 l2hdr_sz += sizeof (*vlan);
107 while (ethernet_frame_is_tagged (ethertype))
110 ethertype = clib_net_to_host_u16 (vlan->type);
111 l2hdr_sz += sizeof (*vlan);
115 if (ethertype == ETHERNET_TYPE_IP4)
117 ip4_header_t *ip4 = (ip4_header_t *) (p + l2hdr_sz);
118 return compute_ip4_key (ip4);
120 else if (ethertype == ETHERNET_TYPE_IP6)
122 ip6_header_t *ip6 = (ip6_header_t *) (p + l2hdr_sz);
123 return compute_ip6_key (ip6);
129 vnet_crc32c_5tuple_ethernet_func (void **p, u32 *hash, u32 n_packets)
131 u32 n_left_from = n_packets;
133 while (n_left_from >= 8)
135 clib_prefetch_load (p[4]);
136 clib_prefetch_load (p[5]);
137 clib_prefetch_load (p[6]);
138 clib_prefetch_load (p[7]);
140 hash[0] = compute_ethernet_key (p[0]);
141 hash[1] = compute_ethernet_key (p[1]);
142 hash[2] = compute_ethernet_key (p[2]);
143 hash[3] = compute_ethernet_key (p[3]);
150 while (n_left_from > 0)
152 hash[0] = compute_ethernet_key (p[0]);
160 VNET_REGISTER_HASH_FUNCTION (crc32c_5tuple, static) = {
161 .name = "crc32c-5tuple",
162 .description = "IPv4/IPv6 header and TCP/UDP ports",
164 .function[VNET_HASH_FN_TYPE_ETHERNET] = vnet_crc32c_5tuple_ethernet_func,
165 .function[VNET_HASH_FN_TYPE_IP] = vnet_crc32c_5tuple_ip_func,