1cc85a685SSepherosa Ziehau /*
2cc85a685SSepherosa Ziehau * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3cc85a685SSepherosa Ziehau *
4cc85a685SSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project
5cc85a685SSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com>
6cc85a685SSepherosa Ziehau *
7cc85a685SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
8cc85a685SSepherosa Ziehau * modification, are permitted provided that the following conditions
9cc85a685SSepherosa Ziehau * are met:
10cc85a685SSepherosa Ziehau *
11cc85a685SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
12cc85a685SSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
13cc85a685SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
14cc85a685SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in
15cc85a685SSepherosa Ziehau * the documentation and/or other materials provided with the
16cc85a685SSepherosa Ziehau * distribution.
17cc85a685SSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its
18cc85a685SSepherosa Ziehau * contributors may be used to endorse or promote products derived
19cc85a685SSepherosa Ziehau * from this software without specific, prior written permission.
20cc85a685SSepherosa Ziehau *
21cc85a685SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22cc85a685SSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23cc85a685SSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24cc85a685SSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25cc85a685SSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26cc85a685SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27cc85a685SSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28cc85a685SSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29cc85a685SSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30cc85a685SSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31cc85a685SSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32cc85a685SSepherosa Ziehau * SUCH DAMAGE.
33cc85a685SSepherosa Ziehau */
34cc85a685SSepherosa Ziehau
35cc85a685SSepherosa Ziehau /*
36cc85a685SSepherosa Ziehau * Toeplitz hash function
37cc85a685SSepherosa Ziehau *
38cc85a685SSepherosa Ziehau * This function is used to support Receive Side Scaling:
39cc85a685SSepherosa Ziehau * http://www.microsoft.com/whdc/device/network/ndis_rss.mspx
40cc85a685SSepherosa Ziehau *
41cc85a685SSepherosa Ziehau * Two things are changed from the above paper:
42cc85a685SSepherosa Ziehau * o Instead of creating random 40 bytes key string, we replicate
43cc85a685SSepherosa Ziehau * 2 user defined bytes to form the 40 bytes key string. So the
44cc85a685SSepherosa Ziehau * hash result of TCP segment is commutative. '2' is chosen,
45cc85a685SSepherosa Ziehau * since the hash is calculated upon the binary string formed by
46cc85a685SSepherosa Ziehau * concatenating faddr,laddr,fport,lport; the smallest unit is
47cc85a685SSepherosa Ziehau * the size of the fport/lport, which is 2 bytes.
48cc85a685SSepherosa Ziehau * o Precalculated hash result cache is used to reduce the heavy
49cc85a685SSepherosa Ziehau * computation burden
50cc85a685SSepherosa Ziehau *
51cc85a685SSepherosa Ziehau * Thank Simon 'corecode' Schubert <corecode@fs.ei.tum.de> very much
52cc85a685SSepherosa Ziehau * for various constructive suggestions. Without him, this will not
53cc85a685SSepherosa Ziehau * be possible.
54cc85a685SSepherosa Ziehau */
55cc85a685SSepherosa Ziehau
564d334cdbSSepherosa Ziehau #include "opt_rss.h"
574d334cdbSSepherosa Ziehau
58cc85a685SSepherosa Ziehau #include <sys/param.h>
59cc85a685SSepherosa Ziehau #include <sys/kernel.h>
60cc85a685SSepherosa Ziehau #include <sys/systm.h>
61cc85a685SSepherosa Ziehau #include <sys/sysctl.h>
62cc85a685SSepherosa Ziehau
63cc85a685SSepherosa Ziehau #include <net/toeplitz.h>
64cc85a685SSepherosa Ziehau #include <net/toeplitz2.h>
65cc85a685SSepherosa Ziehau
66cc85a685SSepherosa Ziehau #define TOEPLITZ_KEYSEED0 0x6d
67cc85a685SSepherosa Ziehau #define TOEPLITZ_KEYSEED1 0x5a
68d9304583SSepherosa Ziehau #define TOEPLITZ_INIT_KEYLEN (TOEPLITZ_KEYSEED_CNT + sizeof(uint32_t))
69cc85a685SSepherosa Ziehau
70cc85a685SSepherosa Ziehau static uint32_t toeplitz_keyseeds[TOEPLITZ_KEYSEED_CNT] =
71cc85a685SSepherosa Ziehau { TOEPLITZ_KEYSEED0, TOEPLITZ_KEYSEED1 };
72cc85a685SSepherosa Ziehau
73cc85a685SSepherosa Ziehau uint32_t toeplitz_cache[TOEPLITZ_KEYSEED_CNT][256];
74cc85a685SSepherosa Ziehau
75cc85a685SSepherosa Ziehau TUNABLE_INT("net.toeplitz.keyseed0", &toeplitz_keyseeds[0]);
76cc85a685SSepherosa Ziehau TUNABLE_INT("net.toeplitz.keyseed1", &toeplitz_keyseeds[1]);
77cc85a685SSepherosa Ziehau
78cc85a685SSepherosa Ziehau SYSCTL_NODE(_net, OID_AUTO, toeplitz, CTLFLAG_RW, 0, "Toeplitz hash");
79cc85a685SSepherosa Ziehau SYSCTL_INT(_net_toeplitz, OID_AUTO, keyseed0, CTLFLAG_RD,
80cc85a685SSepherosa Ziehau &toeplitz_keyseeds[0], 0, "Toeplitz hash key seed0");
81cc85a685SSepherosa Ziehau SYSCTL_INT(_net_toeplitz, OID_AUTO, keyseed1, CTLFLAG_RD,
82cc85a685SSepherosa Ziehau &toeplitz_keyseeds[1], 0, "Toeplitz hash key seed1");
83cc85a685SSepherosa Ziehau
84cc85a685SSepherosa Ziehau static void
toeplitz_cache_create(uint32_t cache[][256],int cache_len,const uint8_t key_str[],int key_strlen)85cc85a685SSepherosa Ziehau toeplitz_cache_create(uint32_t cache[][256], int cache_len,
86cc85a685SSepherosa Ziehau const uint8_t key_str[], int key_strlen)
87cc85a685SSepherosa Ziehau {
88cc85a685SSepherosa Ziehau int i;
89cc85a685SSepherosa Ziehau
90cc85a685SSepherosa Ziehau for (i = 0; i < cache_len; ++i) {
91cc85a685SSepherosa Ziehau uint32_t key[NBBY];
92cc85a685SSepherosa Ziehau int j, b, shift, val;
93cc85a685SSepherosa Ziehau
94cc85a685SSepherosa Ziehau bzero(key, sizeof(key));
95cc85a685SSepherosa Ziehau
96cc85a685SSepherosa Ziehau /*
97cc85a685SSepherosa Ziehau * Calculate 32bit keys for one byte; one key for each bit.
98cc85a685SSepherosa Ziehau */
99cc85a685SSepherosa Ziehau for (b = 0; b < NBBY; ++b) {
100cc85a685SSepherosa Ziehau for (j = 0; j < 32; ++j) {
101cc85a685SSepherosa Ziehau uint8_t k;
102cc85a685SSepherosa Ziehau int bit;
103cc85a685SSepherosa Ziehau
104cc85a685SSepherosa Ziehau bit = (i * NBBY) + b + j;
105cc85a685SSepherosa Ziehau
106cc85a685SSepherosa Ziehau k = key_str[bit / NBBY];
107cc85a685SSepherosa Ziehau shift = NBBY - (bit % NBBY) - 1;
108cc85a685SSepherosa Ziehau if (k & (1 << shift))
109cc85a685SSepherosa Ziehau key[b] |= 1 << (31 - j);
110cc85a685SSepherosa Ziehau }
111cc85a685SSepherosa Ziehau }
112cc85a685SSepherosa Ziehau
113cc85a685SSepherosa Ziehau /*
114cc85a685SSepherosa Ziehau * Cache the results of all possible bit combination of
115cc85a685SSepherosa Ziehau * one byte.
116cc85a685SSepherosa Ziehau */
117cc85a685SSepherosa Ziehau for (val = 0; val < 256; ++val) {
118cc85a685SSepherosa Ziehau uint32_t res = 0;
119cc85a685SSepherosa Ziehau
120cc85a685SSepherosa Ziehau for (b = 0; b < NBBY; ++b) {
121cc85a685SSepherosa Ziehau shift = NBBY - b - 1;
122cc85a685SSepherosa Ziehau if (val & (1 << shift))
123cc85a685SSepherosa Ziehau res ^= key[b];
124cc85a685SSepherosa Ziehau }
125cc85a685SSepherosa Ziehau cache[i][val] = res;
126cc85a685SSepherosa Ziehau }
127cc85a685SSepherosa Ziehau }
128cc85a685SSepherosa Ziehau }
129cc85a685SSepherosa Ziehau
1304d334cdbSSepherosa Ziehau #ifdef RSS_DEBUG
1314d334cdbSSepherosa Ziehau
1324d334cdbSSepherosa Ziehau static void
toeplitz_verify(void)1334d334cdbSSepherosa Ziehau toeplitz_verify(void)
1344d334cdbSSepherosa Ziehau {
1354d334cdbSSepherosa Ziehau in_addr_t faddr, laddr;
1364d334cdbSSepherosa Ziehau in_port_t fport, lport;
1374d334cdbSSepherosa Ziehau
1384d334cdbSSepherosa Ziehau /*
1394d334cdbSSepherosa Ziehau * The first IPv4 example in the verification suite
1404d334cdbSSepherosa Ziehau */
1414d334cdbSSepherosa Ziehau
1424d334cdbSSepherosa Ziehau /* 66.9.149.187:2794 */
1434d334cdbSSepherosa Ziehau faddr = 0xbb950942;
1444d334cdbSSepherosa Ziehau fport = 0xea0a;
1454d334cdbSSepherosa Ziehau
1464d334cdbSSepherosa Ziehau /* 161.142.100.80:1766 */
1474d334cdbSSepherosa Ziehau laddr = 0x50648ea1;
1484d334cdbSSepherosa Ziehau lport = 0xe606;
1494d334cdbSSepherosa Ziehau
1504d334cdbSSepherosa Ziehau kprintf("toeplitz: verify addr/port 0x%08x, addr 0x%08x\n",
151b73d4152SSepherosa Ziehau toeplitz_rawhash_addrport(faddr, laddr, fport, lport),
152b73d4152SSepherosa Ziehau toeplitz_rawhash_addr(faddr, laddr));
1534d334cdbSSepherosa Ziehau }
1544d334cdbSSepherosa Ziehau
1554d334cdbSSepherosa Ziehau #endif /* RSS_DEBUG */
1564d334cdbSSepherosa Ziehau
157cc85a685SSepherosa Ziehau static void
toeplitz_init(void * dummy __unused)158cc85a685SSepherosa Ziehau toeplitz_init(void *dummy __unused)
159cc85a685SSepherosa Ziehau {
160d9304583SSepherosa Ziehau uint8_t key[TOEPLITZ_INIT_KEYLEN];
161cc85a685SSepherosa Ziehau int i;
162cc85a685SSepherosa Ziehau
163cc85a685SSepherosa Ziehau for (i = 0; i < TOEPLITZ_KEYSEED_CNT; ++i)
164cc85a685SSepherosa Ziehau toeplitz_keyseeds[i] &= 0xff;
165cc85a685SSepherosa Ziehau
166d9304583SSepherosa Ziehau toeplitz_get_key(key, TOEPLITZ_INIT_KEYLEN);
167cc85a685SSepherosa Ziehau
1684d334cdbSSepherosa Ziehau #ifdef RSS_DEBUG
1694d334cdbSSepherosa Ziehau kprintf("toeplitz: keystr ");
170d9304583SSepherosa Ziehau for (i = 0; i < TOEPLITZ_INIT_KEYLEN; ++i)
171d9304583SSepherosa Ziehau kprintf("%02x ", key[i]);
1724d334cdbSSepherosa Ziehau kprintf("\n");
1734d334cdbSSepherosa Ziehau #endif
1744d334cdbSSepherosa Ziehau
175cc85a685SSepherosa Ziehau toeplitz_cache_create(toeplitz_cache, TOEPLITZ_KEYSEED_CNT,
176d9304583SSepherosa Ziehau key, TOEPLITZ_INIT_KEYLEN);
1774d334cdbSSepherosa Ziehau
1784d334cdbSSepherosa Ziehau #ifdef RSS_DEBUG
1794d334cdbSSepherosa Ziehau toeplitz_verify();
1804d334cdbSSepherosa Ziehau #endif
181cc85a685SSepherosa Ziehau }
182*f8c589f3SSepherosa Ziehau /* After netisr_init */
1833c5b1eb8SSepherosa Ziehau SYSINIT(toeplitz, SI_SUB_PRE_DRIVERS, SI_ORDER_SECOND, toeplitz_init, NULL);
184b263df52SSepherosa Ziehau
185b263df52SSepherosa Ziehau void
toeplitz_get_key(uint8_t * key,int keylen)186b263df52SSepherosa Ziehau toeplitz_get_key(uint8_t *key, int keylen)
187b263df52SSepherosa Ziehau {
188b263df52SSepherosa Ziehau int i;
189b263df52SSepherosa Ziehau
190b263df52SSepherosa Ziehau if (keylen > TOEPLITZ_KEYLEN_MAX)
191ed20d0e3SSascha Wildner panic("invalid key length %d", keylen);
192b263df52SSepherosa Ziehau
193b263df52SSepherosa Ziehau /* Replicate key seeds to form key */
194b263df52SSepherosa Ziehau for (i = 0; i < keylen; ++i)
195b263df52SSepherosa Ziehau key[i] = toeplitz_keyseeds[i % TOEPLITZ_KEYSEED_CNT];
196b263df52SSepherosa Ziehau }
197