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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
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>
30 static_always_inline u16 *
31 locate_ethertype (ethernet_header_t *eth)
34 ethernet_vlan_header_t *vlan;
36 if (!ethernet_frame_is_tagged (clib_net_to_host_u16 (eth->type)))
38 ethertype_p = ð->type;
42 vlan = (void *) (eth + 1);
43 ethertype_p = &vlan->type;
44 if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
47 ethertype_p = &vlan->type;
54 hash_eth_l2 (void **p, u32 *hash, u32 n_packets)
56 u32 n_left_from = n_packets;
58 while (n_left_from >= 8)
60 ethernet_header_t *eth = *p;
61 u64 *dst = (u64 *) ð->dst_address[0];
62 u64 a = clib_mem_unaligned (dst, u64);
63 u32 *src = (u32 *) ð->src_address[2];
64 u32 b = clib_mem_unaligned (src, u32);
66 clib_prefetch_load (p[4]);
67 clib_prefetch_load (p[5]);
68 clib_prefetch_load (p[6]);
69 clib_prefetch_load (p[7]);
71 hash[0] = lb_hash_hash_2_tuples (a, b);
72 hash[1] = lb_hash_hash_2_tuples (a, b);
73 hash[2] = lb_hash_hash_2_tuples (a, b);
74 hash[3] = lb_hash_hash_2_tuples (a, b);
81 while (n_left_from > 0)
83 ethernet_header_t *eth = *p;
84 u64 *dst = (u64 *) ð->dst_address[0];
85 u64 a = clib_mem_unaligned (dst, u64);
86 u32 *src = (u32 *) ð->src_address[2];
87 u32 b = clib_mem_unaligned (src, u32);
89 hash[0] = lb_hash_hash_2_tuples (a, b);
97 static_always_inline u32
98 hash_eth_l23_inline (void **p)
100 ethernet_header_t *eth = *p;
103 u16 ethertype, *ethertype_p;
104 u32 *mac1, *mac2, *mac3;
107 ethertype_p = locate_ethertype (eth);
108 ethertype = clib_mem_unaligned (ethertype_p, u16);
110 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
111 (ethertype != htons (ETHERNET_TYPE_IP6)))
113 hash_eth_l2 (p, &hash, 1);
117 ip4 = (ip4_header_t *) (ethertype_p + 1);
118 ip_version = (ip4->ip_version_and_header_length >> 4);
120 if (ip_version == 0x4)
124 mac1 = (u32 *) ð->dst_address[0];
125 mac2 = (u32 *) ð->dst_address[4];
126 mac3 = (u32 *) ð->src_address[2];
128 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
129 clib_mem_unaligned (mac3, u32);
130 hash = lb_hash_hash_2_tuples (
131 clib_mem_unaligned (&ip4->address_pair, u64), a);
135 if (ip_version == 0x6)
138 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
140 mac1 = (u32 *) ð->dst_address[0];
141 mac2 = (u32 *) ð->dst_address[4];
142 mac3 = (u32 *) ð->src_address[2];
144 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
145 clib_mem_unaligned (mac3, u32);
146 hash = lb_hash_hash (
147 clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
148 clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
149 clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
150 clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
154 hash_eth_l2 (p, &hash, 1);
159 hash_eth_l23 (void **p, u32 *hash, u32 n_packets)
161 u32 n_left_from = n_packets;
163 while (n_left_from >= 8)
165 clib_prefetch_load (p[4]);
166 clib_prefetch_load (p[5]);
167 clib_prefetch_load (p[6]);
168 clib_prefetch_load (p[7]);
170 hash[0] = hash_eth_l23_inline (&p[0]);
171 hash[1] = hash_eth_l23_inline (&p[1]);
172 hash[2] = hash_eth_l23_inline (&p[2]);
173 hash[3] = hash_eth_l23_inline (&p[3]);
180 while (n_left_from > 0)
182 hash[0] = hash_eth_l23_inline (&p[0]);
190 static_always_inline u32
191 hash_eth_l34_inline (void **p)
193 ethernet_header_t *eth = *p;
197 u16 ethertype, *ethertype_p;
200 ethertype_p = locate_ethertype (eth);
201 ethertype = clib_mem_unaligned (ethertype_p, u16);
203 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
204 (ethertype != htons (ETHERNET_TYPE_IP6)))
206 hash_eth_l2 (p, &hash, 1);
210 ip4 = (ip4_header_t *) (ethertype_p + 1);
211 ip_version = (ip4->ip_version_and_header_length >> 4);
213 if (ip_version == 0x4)
216 tcp_header_t *tcp = (void *) (ip4 + 1);
218 is_tcp_udp = (ip4->protocol == IP_PROTOCOL_TCP) ||
219 (ip4->protocol == IP_PROTOCOL_UDP);
220 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
221 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
223 hash = lb_hash_hash_2_tuples (
224 clib_mem_unaligned (&ip4->address_pair, u64), a);
228 if (ip_version == 0x6)
232 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
233 tcp_header_t *tcp = (void *) (ip6 + 1);
236 if (PREDICT_TRUE ((ip6->protocol == IP_PROTOCOL_TCP) ||
237 (ip6->protocol == IP_PROTOCOL_UDP)))
240 tcp = (void *) (ip6 + 1);
242 else if (ip6->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
244 ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip6 + 1);
245 if ((hbh->protocol == IP_PROTOCOL_TCP) ||
246 (hbh->protocol == IP_PROTOCOL_UDP))
249 tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
252 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
253 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
255 hash = lb_hash_hash (
256 clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
257 clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
258 clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
259 clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
263 hash_eth_l2 (p, &hash, 1);
268 hash_eth_l34 (void **p, u32 *hash, u32 n_packets)
270 u32 n_left_from = n_packets;
272 while (n_left_from >= 8)
274 clib_prefetch_load (p[4]);
275 clib_prefetch_load (p[5]);
276 clib_prefetch_load (p[6]);
277 clib_prefetch_load (p[7]);
279 hash[0] = hash_eth_l34_inline (&p[0]);
280 hash[1] = hash_eth_l34_inline (&p[1]);
281 hash[2] = hash_eth_l34_inline (&p[2]);
282 hash[3] = hash_eth_l34_inline (&p[3]);
289 while (n_left_from > 0)
291 hash[0] = hash_eth_l34_inline (&p[0]);
299 VNET_REGISTER_HASH_FUNCTION (hash_eth_l2, static) = {
300 .name = "hash-eth-l2",
301 .description = "Hash ethernet L2 headers",
303 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l2,
306 VNET_REGISTER_HASH_FUNCTION (hash_eth_l23, static) = {
307 .name = "hash-eth-l23",
308 .description = "Hash ethernet L23 headers",
310 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l23,
313 VNET_REGISTER_HASH_FUNCTION (hash_eth_l34, static) = {
314 .name = "hash-eth-l34",
315 .description = "Hash ethernet L34 headers",
317 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l34,
321 * fd.io coding-style-patch-verification: ON
324 * eval: (c-set-style "gnu")