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 = ð->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 *) ð->dst_address[0];
62 0 : u64 a = clib_mem_unaligned (dst, u64);
63 0 : u32 *src = (u32 *) ð->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 *) ð->dst_address[0];
85 0 : u64 a = clib_mem_unaligned (dst, u64);
86 0 : u32 *src = (u32 *) ð->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 *) ð->dst_address[0];
125 0 : mac2 = (u32 *) ð->dst_address[4];
126 0 : mac3 = (u32 *) ð->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 *) ð->dst_address[0];
141 0 : mac2 = (u32 *) ð->dst_address[4];
142 0 : mac3 = (u32 *) ð->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 : */
|