tcp: Do not include the tcp_packet.h file in the ip4_packet.h
[vpp.git] / src / vnet / hash / hash_eth.c
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 locate_ethertype (ethernet_header_t *eth)
32 {
33   u16 *ethertype_p;
34   ethernet_vlan_header_t *vlan;
35
36   if (!ethernet_frame_is_tagged (clib_net_to_host_u16 (eth->type)))
37     {
38       ethertype_p = &eth->type;
39     }
40   else
41     {
42       vlan = (void *) (eth + 1);
43       ethertype_p = &vlan->type;
44       if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
45         {
46           vlan++;
47           ethertype_p = &vlan->type;
48         }
49     }
50   return ethertype_p;
51 }
52
53 static void
54 hash_eth_l2 (void **p, u32 *hash, u32 n_packets)
55 {
56   u32 n_left_from = n_packets;
57
58   while (n_left_from >= 8)
59     {
60       ethernet_header_t *eth = *p;
61       u64 *dst = (u64 *) &eth->dst_address[0];
62       u64 a = clib_mem_unaligned (dst, u64);
63       u32 *src = (u32 *) &eth->src_address[2];
64       u32 b = clib_mem_unaligned (src, u32);
65
66       clib_prefetch_load (p[4]);
67       clib_prefetch_load (p[5]);
68       clib_prefetch_load (p[6]);
69       clib_prefetch_load (p[7]);
70
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);
75
76       hash += 4;
77       n_left_from -= 4;
78       p += 4;
79     }
80
81   while (n_left_from > 0)
82     {
83       ethernet_header_t *eth = *p;
84       u64 *dst = (u64 *) &eth->dst_address[0];
85       u64 a = clib_mem_unaligned (dst, u64);
86       u32 *src = (u32 *) &eth->src_address[2];
87       u32 b = clib_mem_unaligned (src, u32);
88
89       hash[0] = lb_hash_hash_2_tuples (a, b);
90
91       hash += 1;
92       n_left_from -= 1;
93       p += 1;
94     }
95 }
96
97 static_always_inline u32
98 hash_eth_l23_inline (void **p)
99 {
100   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   ethertype_p = locate_ethertype (eth);
108   ethertype = clib_mem_unaligned (ethertype_p, u16);
109
110   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
111       (ethertype != htons (ETHERNET_TYPE_IP6)))
112     {
113       hash_eth_l2 (p, &hash, 1);
114       return hash;
115     }
116
117   ip4 = (ip4_header_t *) (ethertype_p + 1);
118   ip_version = (ip4->ip_version_and_header_length >> 4);
119
120   if (ip_version == 0x4)
121     {
122       u32 a;
123
124       mac1 = (u32 *) &eth->dst_address[0];
125       mac2 = (u32 *) &eth->dst_address[4];
126       mac3 = (u32 *) &eth->src_address[2];
127
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);
132       return hash;
133     }
134
135   if (ip_version == 0x6)
136     {
137       u64 a;
138       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
139
140       mac1 = (u32 *) &eth->dst_address[0];
141       mac2 = (u32 *) &eth->dst_address[4];
142       mac3 = (u32 *) &eth->src_address[2];
143
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);
151       return hash;
152     }
153
154   hash_eth_l2 (p, &hash, 1);
155   return hash;
156 }
157
158 static void
159 hash_eth_l23 (void **p, u32 *hash, u32 n_packets)
160 {
161   u32 n_left_from = n_packets;
162
163   while (n_left_from >= 8)
164     {
165       clib_prefetch_load (p[4]);
166       clib_prefetch_load (p[5]);
167       clib_prefetch_load (p[6]);
168       clib_prefetch_load (p[7]);
169
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]);
174
175       hash += 4;
176       n_left_from -= 4;
177       p += 4;
178     }
179
180   while (n_left_from > 0)
181     {
182       hash[0] = hash_eth_l23_inline (&p[0]);
183
184       hash += 1;
185       n_left_from -= 1;
186       p += 1;
187     }
188 }
189
190 static_always_inline u32
191 hash_eth_l34_inline (void **p)
192 {
193   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   ethertype_p = locate_ethertype (eth);
201   ethertype = clib_mem_unaligned (ethertype_p, u16);
202
203   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
204       (ethertype != htons (ETHERNET_TYPE_IP6)))
205     {
206       hash_eth_l2 (p, &hash, 1);
207       return hash;
208     }
209
210   ip4 = (ip4_header_t *) (ethertype_p + 1);
211   ip_version = (ip4->ip_version_and_header_length >> 4);
212
213   if (ip_version == 0x4)
214     {
215       u32 a, t1, t2;
216       tcp_header_t *tcp = (void *) (ip4 + 1);
217
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;
222       a = t1 ^ t2;
223       hash = lb_hash_hash_2_tuples (
224         clib_mem_unaligned (&ip4->address_pair, u64), a);
225       return hash;
226     }
227
228   if (ip_version == 0x6)
229     {
230       u64 a;
231       u32 t1, t2;
232       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
233       tcp_header_t *tcp = (void *) (ip6 + 1);
234
235       is_tcp_udp = 0;
236       if (PREDICT_TRUE ((ip6->protocol == IP_PROTOCOL_TCP) ||
237                         (ip6->protocol == IP_PROTOCOL_UDP)))
238         {
239           is_tcp_udp = 1;
240           tcp = (void *) (ip6 + 1);
241         }
242       else if (ip6->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
243         {
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))
247             {
248               is_tcp_udp = 1;
249               tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
250             }
251         }
252       t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
253       t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
254       a = t1 ^ t2;
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);
260       return hash;
261     }
262
263   hash_eth_l2 (p, &hash, 1);
264   return hash;
265 }
266
267 static void
268 hash_eth_l34 (void **p, u32 *hash, u32 n_packets)
269 {
270   u32 n_left_from = n_packets;
271
272   while (n_left_from >= 8)
273     {
274       clib_prefetch_load (p[4]);
275       clib_prefetch_load (p[5]);
276       clib_prefetch_load (p[6]);
277       clib_prefetch_load (p[7]);
278
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]);
283
284       hash += 4;
285       n_left_from -= 4;
286       p += 4;
287     }
288
289   while (n_left_from > 0)
290     {
291       hash[0] = hash_eth_l34_inline (&p[0]);
292
293       hash += 1;
294       n_left_from -= 1;
295       p += 1;
296     }
297 }
298
299 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 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 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  */