13fc12ce6ea72620d14157b9523c1f55d4d0e31d
[vpp.git] / src / vnet / hash / crc32_handoff_eth.c
1 /*
2  * Copyright (c) 2021 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vlib/vlib.h>
17 #include <vnet/ethernet/ethernet.h>
18 #include <vnet/hash/hash.h>
19 #include <vnet/ip/ip4_packet.h>
20 #include <vnet/ip/ip6_packet.h>
21 #include <vnet/mpls/packet.h>
22 #include <vppinfra/crc32.h>
23
24 static inline u64
25 ipv4_get_key (ip4_header_t * ip)
26 {
27   u64 hash_key;
28
29   hash_key = *((u64 *) (&ip->address_pair)) ^ ip->protocol;
30
31   return hash_key;
32 }
33
34 static inline u64
35 ipv6_get_key (ip6_header_t * ip)
36 {
37   u64 hash_key;
38
39   hash_key = ip->src_address.as_u64[0] ^
40     rotate_left (ip->src_address.as_u64[1], 13) ^
41     rotate_left (ip->dst_address.as_u64[0], 26) ^
42     rotate_left (ip->dst_address.as_u64[1], 39) ^ ip->protocol;
43
44   return hash_key;
45 }
46
47 #define MPLS_BOTTOM_OF_STACK_BIT_MASK   0x00000100U
48 #define MPLS_LABEL_MASK                 0xFFFFF000U
49
50 static inline u64
51 mpls_get_key (mpls_unicast_header_t * m)
52 {
53   u64 hash_key;
54   u8 ip_ver;
55
56
57   /* find the bottom of the MPLS label stack. */
58   if (PREDICT_TRUE (m->label_exp_s_ttl &
59                     clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)))
60     {
61       goto bottom_lbl_found;
62     }
63   m++;
64
65   if (PREDICT_TRUE (m->label_exp_s_ttl &
66                     clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK)))
67     {
68       goto bottom_lbl_found;
69     }
70   m++;
71
72   if (m->label_exp_s_ttl &
73       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
74     {
75       goto bottom_lbl_found;
76     }
77   m++;
78
79   if (m->label_exp_s_ttl &
80       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
81     {
82       goto bottom_lbl_found;
83     }
84   m++;
85
86   if (m->label_exp_s_ttl &
87       clib_net_to_host_u32 (MPLS_BOTTOM_OF_STACK_BIT_MASK))
88     {
89       goto bottom_lbl_found;
90     }
91
92   /* the bottom label was not found - use the last label */
93   hash_key = m->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK);
94
95   return hash_key;
96
97 bottom_lbl_found:
98   m++;
99   ip_ver = (*((u8 *) m) >> 4);
100
101   /* find out if it is IPV4 or IPV6 header */
102   if (PREDICT_TRUE (ip_ver == 4))
103     {
104       hash_key = ipv4_get_key ((ip4_header_t *) m);
105     }
106   else if (PREDICT_TRUE (ip_ver == 6))
107     {
108       hash_key = ipv6_get_key ((ip6_header_t *) m);
109     }
110   else
111     {
112       /* use the bottom label */
113       hash_key =
114         (m - 1)->label_exp_s_ttl & clib_net_to_host_u32 (MPLS_LABEL_MASK);
115     }
116
117   return hash_key;
118
119 }
120
121 static inline u64
122 eth_get_sym_key (ethernet_header_t * h0)
123 {
124   u64 hash_key;
125
126   if (PREDICT_TRUE (h0->type) == clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
127     {
128       ip4_header_t *ip = (ip4_header_t *) (h0 + 1);
129       hash_key =
130         (u64) (ip->src_address.as_u32 ^
131                ip->dst_address.as_u32 ^ ip->protocol);
132     }
133   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
134     {
135       ip6_header_t *ip = (ip6_header_t *) (h0 + 1);
136       hash_key = (u64) (ip->src_address.as_u64[0] ^
137                         ip->src_address.as_u64[1] ^
138                         ip->dst_address.as_u64[0] ^
139                         ip->dst_address.as_u64[1] ^ ip->protocol);
140     }
141   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
142     {
143       hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1));
144     }
145   else
146     if (PREDICT_FALSE
147         ((h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN))
148          || (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD))))
149     {
150       ethernet_vlan_header_t *outer = (ethernet_vlan_header_t *) (h0 + 1);
151
152       outer = (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ?
153         outer + 1 : outer;
154       if (PREDICT_TRUE (outer->type) ==
155           clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
156         {
157           ip4_header_t *ip = (ip4_header_t *) (outer + 1);
158           hash_key =
159             (u64) (ip->src_address.as_u32 ^
160                    ip->dst_address.as_u32 ^ ip->protocol);
161         }
162       else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
163         {
164           ip6_header_t *ip = (ip6_header_t *) (outer + 1);
165           hash_key =
166             (u64) (ip->src_address.as_u64[0] ^ ip->src_address.as_u64[1] ^
167                    ip->dst_address.as_u64[0] ^
168                    ip->dst_address.as_u64[1] ^ ip->protocol);
169         }
170       else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
171         {
172           hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1));
173         }
174       else
175         {
176           hash_key = outer->type;
177         }
178     }
179   else
180     {
181       hash_key = 0;
182     }
183
184   return hash_key;
185 }
186
187 static inline u64
188 eth_get_key (ethernet_header_t * h0)
189 {
190   u64 hash_key;
191
192   if (PREDICT_TRUE (h0->type) == clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
193     {
194       hash_key = ipv4_get_key ((ip4_header_t *) (h0 + 1));
195     }
196   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
197     {
198       hash_key = ipv6_get_key ((ip6_header_t *) (h0 + 1));
199     }
200   else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
201     {
202       hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1));
203     }
204   else if ((h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ||
205            (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_DOT1AD)))
206     {
207       ethernet_vlan_header_t *outer = (ethernet_vlan_header_t *) (h0 + 1);
208
209       outer = (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_VLAN)) ?
210         outer + 1 : outer;
211       if (PREDICT_TRUE (outer->type) ==
212           clib_host_to_net_u16 (ETHERNET_TYPE_IP4))
213         {
214           hash_key = ipv4_get_key ((ip4_header_t *) (outer + 1));
215         }
216       else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_IP6))
217         {
218           hash_key = ipv6_get_key ((ip6_header_t *) (outer + 1));
219         }
220       else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
221         {
222           hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1));
223         }
224       else
225         {
226           hash_key = outer->type;
227         }
228     }
229   else
230     {
231       hash_key = 0;
232     }
233
234   return hash_key;
235 }
236
237 void
238 handoff_eth_crc32c_func (void **p, u32 *hash, u32 n_packets)
239 {
240   u32 n_left_from = n_packets;
241
242   while (n_left_from >= 8)
243     {
244       u64 key[4] = {};
245
246       clib_prefetch_load (p[4]);
247       clib_prefetch_load (p[5]);
248       clib_prefetch_load (p[6]);
249       clib_prefetch_load (p[7]);
250
251       key[0] = eth_get_key ((ethernet_header_t *) p[0]);
252       key[1] = eth_get_key ((ethernet_header_t *) p[1]);
253       key[2] = eth_get_key ((ethernet_header_t *) p[2]);
254       key[3] = eth_get_key ((ethernet_header_t *) p[3]);
255
256       hash[0] = clib_crc32c ((u8 *) &key[0], sizeof (key[0]));
257       hash[1] = clib_crc32c ((u8 *) &key[1], sizeof (key[1]));
258       hash[2] = clib_crc32c ((u8 *) &key[2], sizeof (key[2]));
259       hash[3] = clib_crc32c ((u8 *) &key[3], sizeof (key[3]));
260
261       hash += 4;
262       n_left_from -= 4;
263       p += 4;
264     }
265
266   while (n_left_from > 0)
267     {
268       u64 key;
269
270       key = eth_get_key ((ethernet_header_t *) p[0]);
271       hash[0] = clib_crc32c ((u8 *) &key, sizeof (key));
272
273       hash += 1;
274       n_left_from -= 1;
275       p += 1;
276     }
277 }
278
279 VNET_REGISTER_HASH_FUNCTION (handoff_eth_crc32c, static) = {
280   .name = "handoff-eth-crc32c",
281   .description = "Ethernet/IPv4/IPv6/MPLS headers",
282   .priority = 2,
283   .function[VNET_HASH_FN_TYPE_ETHERNET] = handoff_eth_crc32c_func,
284 };
285
286 void
287 handoff_eth_sym_crc32c_func (void **p, u32 *hash, u32 n_packets)
288 {
289   u32 n_left_from = n_packets;
290
291   while (n_left_from >= 8)
292     {
293       u64 key[4] = {};
294
295       clib_prefetch_load (p[4]);
296       clib_prefetch_load (p[5]);
297       clib_prefetch_load (p[6]);
298       clib_prefetch_load (p[7]);
299
300       key[0] = eth_get_sym_key ((ethernet_header_t *) p[0]);
301       key[1] = eth_get_sym_key ((ethernet_header_t *) p[1]);
302       key[2] = eth_get_sym_key ((ethernet_header_t *) p[2]);
303       key[3] = eth_get_sym_key ((ethernet_header_t *) p[3]);
304
305       hash[0] = clib_crc32c ((u8 *) &key[0], sizeof (key[0]));
306       hash[1] = clib_crc32c ((u8 *) &key[1], sizeof (key[1]));
307       hash[2] = clib_crc32c ((u8 *) &key[2], sizeof (key[2]));
308       hash[3] = clib_crc32c ((u8 *) &key[3], sizeof (key[3]));
309
310       hash += 4;
311       n_left_from -= 4;
312       p += 4;
313     }
314
315   while (n_left_from > 0)
316     {
317       u64 key;
318
319       key = eth_get_sym_key ((ethernet_header_t *) p[0]);
320       hash[0] = clib_crc32c ((u8 *) &key, sizeof (key));
321
322       hash += 1;
323       n_left_from -= 1;
324       p += 1;
325     }
326 }
327
328 VNET_REGISTER_HASH_FUNCTION (handoff_eth_sym_crc32c, static) = {
329   .name = "handoff-eth-sym-crc32c",
330   .description = "Ethernet/IPv4/IPv6/MPLS headers Symmetric",
331   .priority = 1,
332   .function[VNET_HASH_FN_TYPE_ETHERNET] = handoff_eth_sym_crc32c_func,
333 };
334
335 /*
336  * fd.io coding-style-patch-verification: ON
337  *
338  * Local Variables:
339  * eval: (c-set-style "gnu")
340  * End:
341  */