]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/netmap/pkt_hash.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / tools / tools / netmap / pkt_hash.c
1 /*
2  ** Copyright (c) 2015, Asim Jamshed, Robin Sommer, Seth Hall
3  ** and the International Computer Science Institute. All rights reserved.
4  **
5  ** Redistribution and use in source and binary forms, with or without
6  ** modification, are permitted provided that the following conditions are met:
7  **
8  ** (1) Redistributions of source code must retain the above copyright
9  **     notice, this list of conditions and the following disclaimer.
10  **
11  ** (2) Redistributions in binary form must reproduce the above copyright
12  **     notice, this list of conditions and the following disclaimer in the
13  **     documentation and/or other materials provided with the distribution.
14  **
15  **
16  ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  ** ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  ** POSSIBILITY OF SUCH DAMAGE.
27  **/
28 /* $FreeBSD$ */
29
30 /* for func prototypes */
31 #include "pkt_hash.h"
32
33 /* Make Linux headers choose BSD versions of some of the data structures */
34 #define __FAVOR_BSD
35
36 /* for types */
37 #include <sys/types.h>
38 /* for [n/h]to[h/n][ls] */
39 #include <netinet/in.h>
40 /* iphdr */
41 #include <netinet/ip.h>
42 /* ipv6hdr */
43 #include <netinet/ip6.h>
44 /* tcphdr */
45 #include <netinet/tcp.h>
46 /* udphdr */
47 #include <netinet/udp.h>
48 /* eth hdr */
49 #include <net/ethernet.h>
50 /* for memset */
51 #include <string.h>
52
53 #include <stdio.h>
54 #include <assert.h>
55
56 //#include <libnet.h>
57 /*---------------------------------------------------------------------*/
58 /**
59  *  * The cache table is used to pick a nice seed for the hash value. It is
60  *   * built only once when sym_hash_fn is called for the very first time
61  *    */
62 static void
63 build_sym_key_cache(uint32_t *cache, int cache_len)
64 {
65         static const uint8_t key[] = { 0x50, 0x6d };
66
67         uint32_t result = (((uint32_t)key[0]) << 24) |
68                 (((uint32_t)key[1]) << 16) |
69                 (((uint32_t)key[0]) << 8)  |
70                 ((uint32_t)key[1]);
71
72         uint32_t idx = 32;
73         int i;
74
75         for (i = 0; i < cache_len; i++, idx++) {
76                 uint8_t shift = (idx % 8);
77                 uint32_t bit;
78
79                 cache[i] = result;
80                 bit = ((key[(idx/8) & 1] << shift) & 0x80) ? 1 : 0;
81                 result = ((result << 1) | bit);
82         }
83 }
84
85 static void
86 build_byte_cache(uint32_t byte_cache[256][4])
87 {
88 #define KEY_CACHE_LEN                   96
89         int i, j, k;
90         uint32_t key_cache[KEY_CACHE_LEN];
91
92         build_sym_key_cache(key_cache, KEY_CACHE_LEN);
93
94         for (i = 0; i < 4; i++) {
95                 for (j = 0; j < 256; j++) {
96                         uint8_t b = j;
97                         byte_cache[j][i] = 0;
98                         for (k = 0; k < 8; k++) {
99                                 if (b & 0x80)
100                                         byte_cache[j][i] ^= key_cache[8 * i + k];
101                                 b <<= 1U;
102                         }
103                 }
104         }
105 }
106
107
108 /*---------------------------------------------------------------------*/
109 /**
110  ** Computes symmetric hash based on the 4-tuple header data
111  **/
112 static uint32_t
113 sym_hash_fn(uint32_t sip, uint32_t dip, uint16_t sp, uint32_t dp)
114 {
115         uint32_t rc = 0;
116         static int first_time = 1;
117         static uint32_t byte_cache[256][4];
118         uint8_t *sip_b = (uint8_t *)&sip,
119                 *dip_b = (uint8_t *)&dip,
120                 *sp_b  = (uint8_t *)&sp,
121                 *dp_b  = (uint8_t *)&dp;
122
123         if (first_time) {
124                 build_byte_cache(byte_cache);
125                 first_time = 0;
126         }
127
128         rc = byte_cache[sip_b[3]][0] ^
129              byte_cache[sip_b[2]][1] ^
130              byte_cache[sip_b[1]][2] ^
131              byte_cache[sip_b[0]][3] ^
132              byte_cache[dip_b[3]][0] ^
133              byte_cache[dip_b[2]][1] ^
134              byte_cache[dip_b[1]][2] ^
135              byte_cache[dip_b[0]][3] ^
136              byte_cache[sp_b[1]][0] ^
137              byte_cache[sp_b[0]][1] ^
138              byte_cache[dp_b[1]][2] ^
139              byte_cache[dp_b[0]][3];
140
141         return rc;
142 }
143 static uint32_t decode_gre_hash(const uint8_t *, uint8_t, uint8_t);
144 /*---------------------------------------------------------------------*/
145 /**
146  ** Parser + hash function for the IPv4 packet
147  **/
148 static uint32_t
149 decode_ip_n_hash(const struct ip *iph, uint8_t hash_split, uint8_t seed)
150 {
151         uint32_t rc = 0;
152
153         if (hash_split == 2) {
154                 rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
155                         ntohl(iph->ip_dst.s_addr),
156                         ntohs(0xFFFD) + seed,
157                         ntohs(0xFFFE) + seed);
158         } else {
159                 const struct tcphdr *tcph = NULL;
160                 const struct udphdr *udph = NULL;
161
162                 switch (iph->ip_p) {
163                 case IPPROTO_TCP:
164                         tcph = (const struct tcphdr *)((const uint8_t *)iph + (iph->ip_hl<<2));
165                         rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
166                                          ntohl(iph->ip_dst.s_addr),
167                                          ntohs(tcph->th_sport) + seed,
168                                          ntohs(tcph->th_dport) + seed);
169                         break;
170                 case IPPROTO_UDP:
171                         udph = (const struct udphdr *)((const uint8_t *)iph + (iph->ip_hl<<2));
172                         rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
173                                          ntohl(iph->ip_dst.s_addr),
174                                          ntohs(udph->uh_sport) + seed,
175                                          ntohs(udph->uh_dport) + seed);
176                         break;
177                 case IPPROTO_IPIP:
178                         /* tunneling */
179                         rc = decode_ip_n_hash((const struct ip *)((const uint8_t *)iph + (iph->ip_hl<<2)),
180                                               hash_split, seed);
181                         break;
182                 case IPPROTO_GRE:
183                         rc = decode_gre_hash((const uint8_t *)iph + (iph->ip_hl<<2),
184                                         hash_split, seed);
185                         break;
186                 case IPPROTO_ICMP:
187                 case IPPROTO_ESP:
188                 case IPPROTO_PIM:
189                 case IPPROTO_IGMP:
190                 default:
191                         /*
192                          ** the hash strength (although weaker but) should still hold
193                          ** even with 2 fields
194                          **/
195                         rc = sym_hash_fn(ntohl(iph->ip_src.s_addr),
196                                          ntohl(iph->ip_dst.s_addr),
197                                          ntohs(0xFFFD) + seed,
198                                          ntohs(0xFFFE) + seed);
199                         break;
200                 }
201         }
202         return rc;
203 }
204 /*---------------------------------------------------------------------*/
205 /**
206  ** Parser + hash function for the IPv6 packet
207  **/
208 static uint32_t
209 decode_ipv6_n_hash(const struct ip6_hdr *ipv6h, uint8_t hash_split, uint8_t seed)
210 {
211         uint32_t saddr, daddr;
212         uint32_t rc = 0;
213
214         /* Get only the first 4 octets */
215         saddr = ipv6h->ip6_src.s6_addr[0] |
216                 (ipv6h->ip6_src.s6_addr[1] << 8) |
217                 (ipv6h->ip6_src.s6_addr[2] << 16) |
218                 (ipv6h->ip6_src.s6_addr[3] << 24);
219         daddr = ipv6h->ip6_dst.s6_addr[0] |
220                 (ipv6h->ip6_dst.s6_addr[1] << 8) |
221                 (ipv6h->ip6_dst.s6_addr[2] << 16) |
222                 (ipv6h->ip6_dst.s6_addr[3] << 24);
223
224         if (hash_split == 2) {
225                 rc = sym_hash_fn(ntohl(saddr),
226                                  ntohl(daddr),
227                                  ntohs(0xFFFD) + seed,
228                                  ntohs(0xFFFE) + seed);
229         } else {
230                 const struct tcphdr *tcph = NULL;
231                 const struct udphdr *udph = NULL;
232
233                 switch(ntohs(ipv6h->ip6_ctlun.ip6_un1.ip6_un1_nxt)) {
234                 case IPPROTO_TCP:
235                         tcph = (const struct tcphdr *)(ipv6h + 1);
236                         rc = sym_hash_fn(ntohl(saddr),
237                                          ntohl(daddr),
238                                          ntohs(tcph->th_sport) + seed,
239                                          ntohs(tcph->th_dport) + seed);
240                         break;
241                 case IPPROTO_UDP:
242                         udph = (const struct udphdr *)(ipv6h + 1);
243                         rc = sym_hash_fn(ntohl(saddr),
244                                          ntohl(daddr),
245                                          ntohs(udph->uh_sport) + seed,
246                                          ntohs(udph->uh_dport) + seed);
247                         break;
248                 case IPPROTO_IPIP:
249                         /* tunneling */
250                         rc = decode_ip_n_hash((const struct ip *)(ipv6h + 1),
251                                               hash_split, seed);
252                         break;
253                 case IPPROTO_IPV6:
254                         /* tunneling */
255                         rc = decode_ipv6_n_hash((const struct ip6_hdr *)(ipv6h + 1),
256                                                 hash_split, seed);
257                         break;
258                 case IPPROTO_GRE:
259                         rc = decode_gre_hash((const uint8_t *)(ipv6h + 1), hash_split, seed);
260                         break;
261                 case IPPROTO_ICMP:
262                 case IPPROTO_ESP:
263                 case IPPROTO_PIM:
264                 case IPPROTO_IGMP:
265                 default:
266                         /*
267                          ** the hash strength (although weaker but) should still hold
268                          ** even with 2 fields
269                          **/
270                         rc = sym_hash_fn(ntohl(saddr),
271                                          ntohl(daddr),
272                                          ntohs(0xFFFD) + seed,
273                                          ntohs(0xFFFE) + seed);
274                 }
275         }
276         return rc;
277 }
278 /*---------------------------------------------------------------------*/
279 /**
280  *  *  A temp solution while hash for other protocols are filled...
281  *   * (See decode_vlan_n_hash & pkt_hdr_hash functions).
282  *    */
283 static uint32_t
284 decode_others_n_hash(const struct ether_header *ethh, uint8_t seed)
285 {
286         uint32_t saddr, daddr, rc;
287
288         saddr = ethh->ether_shost[5] |
289                 (ethh->ether_shost[4] << 8) |
290                 (ethh->ether_shost[3] << 16) |
291                 (ethh->ether_shost[2] << 24);
292         daddr = ethh->ether_dhost[5] |
293                 (ethh->ether_dhost[4] << 8) |
294                 (ethh->ether_dhost[3] << 16) |
295                 (ethh->ether_dhost[2] << 24);
296
297         rc = sym_hash_fn(ntohl(saddr),
298                          ntohl(daddr),
299                          ntohs(0xFFFD) + seed,
300                          ntohs(0xFFFE) + seed);
301
302         return rc;
303 }
304 /*---------------------------------------------------------------------*/
305 /**
306  ** Parser + hash function for VLAN packet
307  **/
308 static inline uint32_t
309 decode_vlan_n_hash(const struct ether_header *ethh, uint8_t hash_split, uint8_t seed)
310 {
311         uint32_t rc = 0;
312         const struct vlanhdr *vhdr = (const struct vlanhdr *)(ethh + 1);
313
314         switch (ntohs(vhdr->proto)) {
315         case ETHERTYPE_IP:
316                 rc = decode_ip_n_hash((const struct ip *)(vhdr + 1),
317                                       hash_split, seed);
318                 break;
319         case ETHERTYPE_IPV6:
320                 rc = decode_ipv6_n_hash((const struct ip6_hdr *)(vhdr + 1),
321                                         hash_split, seed);
322                 break;
323         case ETHERTYPE_ARP:
324         default:
325                 /* others */
326                 rc = decode_others_n_hash(ethh, seed);
327                 break;
328         }
329         return rc;
330 }
331
332 /*---------------------------------------------------------------------*/
333 /**
334  ** General parser + hash function...
335  **/
336 uint32_t
337 pkt_hdr_hash(const unsigned char *buffer, uint8_t hash_split, uint8_t seed)
338 {
339         uint32_t rc = 0;
340         const struct ether_header *ethh = (const struct ether_header *)buffer;
341
342         switch (ntohs(ethh->ether_type)) {
343         case ETHERTYPE_IP:
344                 rc = decode_ip_n_hash((const struct ip *)(ethh + 1),
345                                       hash_split, seed);
346                 break;
347         case ETHERTYPE_IPV6:
348                 rc = decode_ipv6_n_hash((const struct ip6_hdr *)(ethh + 1),
349                                         hash_split, seed);
350                 break;
351         case ETHERTYPE_VLAN:
352                 rc = decode_vlan_n_hash(ethh, hash_split, seed);
353                 break;
354         case ETHERTYPE_ARP:
355         default:
356                 /* others */
357                 rc = decode_others_n_hash(ethh, seed);
358                 break;
359         }
360
361         return rc;
362 }
363
364 /*---------------------------------------------------------------------*/
365 /**
366  ** Parser + hash function for the GRE packet
367  **/
368 static uint32_t
369 decode_gre_hash(const uint8_t *grehdr, uint8_t hash_split, uint8_t seed)
370 {
371         uint32_t rc = 0;
372         int len = 4 + 2 * (!!(*grehdr & 1) + /* Checksum */
373                            !!(*grehdr & 2) + /* Routing */
374                            !!(*grehdr & 4) + /* Key */
375                            !!(*grehdr & 8)); /* Sequence Number */
376         uint16_t proto = ntohs(*(const uint16_t *)(const void *)(grehdr + 2));
377
378         switch (proto) {
379         case ETHERTYPE_IP:
380                 rc = decode_ip_n_hash((const struct ip *)(grehdr + len),
381                                       hash_split, seed);
382                 break;
383         case ETHERTYPE_IPV6:
384                 rc = decode_ipv6_n_hash((const struct ip6_hdr *)(grehdr + len),
385                                         hash_split, seed);
386                 break;
387         case 0x6558: /* Transparent Ethernet Bridging */
388                 rc = pkt_hdr_hash(grehdr + len, hash_split, seed);
389                 break;
390         default:
391                 /* others */
392                 break;
393         }
394         return rc;
395 }
396 /*---------------------------------------------------------------------*/
397