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 <vppinfra/lb_hash_hash.h>
27 #include <vnet/hash/hash.h>
29 static_always_inline u16 *
30 locate_ethertype (ethernet_header_t *eth)
33 ethernet_vlan_header_t *vlan;
35 if (!ethernet_frame_is_tagged (clib_net_to_host_u16 (eth->type)))
37 ethertype_p = ð->type;
41 vlan = (void *) (eth + 1);
42 ethertype_p = &vlan->type;
43 if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
46 ethertype_p = &vlan->type;
53 hash_eth_l2 (void **p, u32 *hash, u32 n_packets)
55 u32 n_left_from = n_packets;
57 while (n_left_from >= 8)
59 ethernet_header_t *eth = *p;
60 u64 *dst = (u64 *) ð->dst_address[0];
61 u64 a = clib_mem_unaligned (dst, u64);
62 u32 *src = (u32 *) ð->src_address[2];
63 u32 b = clib_mem_unaligned (src, u32);
65 clib_prefetch_load (p[4]);
66 clib_prefetch_load (p[5]);
67 clib_prefetch_load (p[6]);
68 clib_prefetch_load (p[7]);
70 hash[0] = lb_hash_hash_2_tuples (a, b);
71 hash[1] = lb_hash_hash_2_tuples (a, b);
72 hash[2] = lb_hash_hash_2_tuples (a, b);
73 hash[3] = lb_hash_hash_2_tuples (a, b);
80 while (n_left_from > 0)
82 ethernet_header_t *eth = *p;
83 u64 *dst = (u64 *) ð->dst_address[0];
84 u64 a = clib_mem_unaligned (dst, u64);
85 u32 *src = (u32 *) ð->src_address[2];
86 u32 b = clib_mem_unaligned (src, u32);
88 hash[0] = lb_hash_hash_2_tuples (a, b);
96 static_always_inline u32
97 hash_eth_l23_inline (void **p)
99 ethernet_header_t *eth = *p;
102 u16 ethertype, *ethertype_p;
103 u32 *mac1, *mac2, *mac3;
106 ethertype_p = locate_ethertype (eth);
107 ethertype = clib_mem_unaligned (ethertype_p, u16);
109 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
110 (ethertype != htons (ETHERNET_TYPE_IP6)))
112 hash_eth_l2 (p, &hash, 1);
116 ip4 = (ip4_header_t *) (ethertype_p + 1);
117 ip_version = (ip4->ip_version_and_header_length >> 4);
119 if (ip_version == 0x4)
123 mac1 = (u32 *) ð->dst_address[0];
124 mac2 = (u32 *) ð->dst_address[4];
125 mac3 = (u32 *) ð->src_address[2];
127 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
128 clib_mem_unaligned (mac3, u32);
129 hash = lb_hash_hash_2_tuples (
130 clib_mem_unaligned (&ip4->address_pair, u64), a);
134 if (ip_version == 0x6)
137 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
139 mac1 = (u32 *) ð->dst_address[0];
140 mac2 = (u32 *) ð->dst_address[4];
141 mac3 = (u32 *) ð->src_address[2];
143 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
144 clib_mem_unaligned (mac3, u32);
145 hash = lb_hash_hash (
146 clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
147 clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
148 clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
149 clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
153 hash_eth_l2 (p, &hash, 1);
158 hash_eth_l23 (void **p, u32 *hash, u32 n_packets)
160 u32 n_left_from = n_packets;
162 while (n_left_from >= 8)
164 clib_prefetch_load (p[4]);
165 clib_prefetch_load (p[5]);
166 clib_prefetch_load (p[6]);
167 clib_prefetch_load (p[7]);
169 hash[0] = hash_eth_l23_inline (&p[0]);
170 hash[1] = hash_eth_l23_inline (&p[1]);
171 hash[2] = hash_eth_l23_inline (&p[2]);
172 hash[3] = hash_eth_l23_inline (&p[3]);
179 while (n_left_from > 0)
181 hash[0] = hash_eth_l23_inline (&p[0]);
189 static_always_inline u32
190 hash_eth_l34_inline (void **p)
192 ethernet_header_t *eth = *p;
196 u16 ethertype, *ethertype_p;
199 ethertype_p = locate_ethertype (eth);
200 ethertype = clib_mem_unaligned (ethertype_p, u16);
202 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
203 (ethertype != htons (ETHERNET_TYPE_IP6)))
205 hash_eth_l2 (p, &hash, 1);
209 ip4 = (ip4_header_t *) (ethertype_p + 1);
210 ip_version = (ip4->ip_version_and_header_length >> 4);
212 if (ip_version == 0x4)
215 tcp_header_t *tcp = (void *) (ip4 + 1);
217 is_tcp_udp = (ip4->protocol == IP_PROTOCOL_TCP) ||
218 (ip4->protocol == IP_PROTOCOL_UDP);
219 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
220 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
222 hash = lb_hash_hash_2_tuples (
223 clib_mem_unaligned (&ip4->address_pair, u64), a);
227 if (ip_version == 0x6)
231 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
232 tcp_header_t *tcp = (void *) (ip6 + 1);
235 if (PREDICT_TRUE ((ip6->protocol == IP_PROTOCOL_TCP) ||
236 (ip6->protocol == IP_PROTOCOL_UDP)))
239 tcp = (void *) (ip6 + 1);
241 else if (ip6->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
243 ip6_hop_by_hop_header_t *hbh = (ip6_hop_by_hop_header_t *) (ip6 + 1);
244 if ((hbh->protocol == IP_PROTOCOL_TCP) ||
245 (hbh->protocol == IP_PROTOCOL_UDP))
248 tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
251 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
252 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
254 hash = lb_hash_hash (
255 clib_mem_unaligned (&ip6->src_address.as_uword[0], uword),
256 clib_mem_unaligned (&ip6->src_address.as_uword[1], uword),
257 clib_mem_unaligned (&ip6->dst_address.as_uword[0], uword),
258 clib_mem_unaligned (&ip6->dst_address.as_uword[1], uword), a);
262 hash_eth_l2 (p, &hash, 1);
267 hash_eth_l34 (void **p, u32 *hash, u32 n_packets)
269 u32 n_left_from = n_packets;
271 while (n_left_from >= 8)
273 clib_prefetch_load (p[4]);
274 clib_prefetch_load (p[5]);
275 clib_prefetch_load (p[6]);
276 clib_prefetch_load (p[7]);
278 hash[0] = hash_eth_l34_inline (&p[0]);
279 hash[1] = hash_eth_l34_inline (&p[1]);
280 hash[2] = hash_eth_l34_inline (&p[2]);
281 hash[3] = hash_eth_l34_inline (&p[3]);
288 while (n_left_from > 0)
290 hash[0] = hash_eth_l34_inline (&p[0]);
298 VNET_REGISTER_HASH_FUNCTION (hash_eth_l2, static) = {
299 .name = "hash-eth-l2",
300 .description = "Hash ethernet L2 headers",
302 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l2,
305 VNET_REGISTER_HASH_FUNCTION (hash_eth_l23, static) = {
306 .name = "hash-eth-l23",
307 .description = "Hash ethernet L23 headers",
309 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l23,
312 VNET_REGISTER_HASH_FUNCTION (hash_eth_l34, static) = {
313 .name = "hash-eth-l34",
314 .description = "Hash ethernet L34 headers",
316 .function[VNET_HASH_FN_TYPE_ETHERNET] = hash_eth_l34,
320 * fd.io coding-style-patch-verification: ON
323 * eval: (c-set-style "gnu")