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