1 /* $NetBSD: rss_config.c,v 1.3 2021/09/24 04:11:02 knakahara Exp $ */
2
3 /*
4 * Copyright (c) 2018 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE 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
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: rss_config.c,v 1.3 2021/09/24 04:11:02 knakahara Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/mbuf.h>
36
37 #include <net/rss_config.h>
38 #include <net/toeplitz.h>
39
40 #include <netinet/in.h>
41 #include <netinet/ip.h>
42 #include <netinet/tcp.h>
43 #include <netinet/udp.h>
44 #include <netinet/ip6.h>
45
46 /*
47 * Same as FreeBSD.
48 *
49 * This rss key is assumed for verification suite in many intel Gigabit and
50 * 10 Gigabit Controller specifications.
51 */
52 static uint8_t rss_default_key[RSS_KEYSIZE] = {
53 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
54 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
55 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
56 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
57 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa,
58 };
59
60 #ifdef NOTYET
61 /*
62 * Same as DragonFlyBSD.
63 *
64 * This rss key make rss hash value symmetric, that is, the hash value
65 * calculated by func("source address", "destination address") equals to
66 * the hash value calculated by func("destination address", "source address").
67 */
68 static uint8_t rss_symmetric_key[RSS_KEYSIZE] = {
69 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
70 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
71 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
72 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
73 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
74 };
75 #endif
76
77 /*
78 * sizeof(key) must be more than or equal to RSS_KEYSIZE.
79 */
80 void
rss_getkey(uint8_t * key)81 rss_getkey(uint8_t *key)
82 {
83
84 memcpy(key, rss_default_key, sizeof(rss_default_key));
85 }
86
87 /*
88 * Calculate rss hash value from IPv4 mbuf.
89 * This function should be called before ip_input().
90 */
91 uint32_t
rss_toeplitz_hash_from_mbuf_ipv4(const struct mbuf * m,u_int flag)92 rss_toeplitz_hash_from_mbuf_ipv4(const struct mbuf *m, u_int flag)
93 {
94 struct ip *ip;
95 int hlen;
96 uint8_t key[RSS_KEYSIZE];
97
98 KASSERT((m->m_flags & M_PKTHDR) != 0);
99 KASSERT(m->m_len >= sizeof (struct ip));
100
101 ip = mtod(m, struct ip *);
102 KASSERT(ip->ip_v == IPVERSION);
103
104 hlen = ip->ip_hl << 2;
105 if (hlen < sizeof(struct ip))
106 return 0;
107
108 rss_getkey(key);
109
110 switch (ip->ip_p) {
111 case IPPROTO_TCP:
112 {
113 if ((flag & RSS_TOEPLITZ_USE_TCP_PORT) != 0) {
114 if (m->m_len >= hlen + sizeof(struct tcphdr)) {
115 struct tcphdr *th;
116
117 th = (struct tcphdr *)(mtod(m, char *) + hlen);
118 return toeplitz_vhash(key, sizeof(key),
119 /* ip_src and ip_dst in struct ip must be sequential */
120 &ip->ip_src, sizeof(ip->ip_src) * 2,
121 /* th_sport and th_dport in tcphdr must be sequential */
122 &th->th_sport, sizeof(th->th_sport) * 2,
123 NULL);
124 } else if (m->m_pkthdr.len >= hlen + sizeof(struct tcphdr)) {
125 uint16_t ports[2];
126
127 /* ditto */
128 m_copydata(__UNCONST(m), hlen + offsetof(struct tcphdr, th_sport),
129 sizeof(ports), ports);
130 return toeplitz_vhash(key, sizeof(key),
131 &ip->ip_src, sizeof(ip->ip_src) * 2,
132 ports, sizeof(ports),
133 NULL);
134 }
135 }
136 /*
137 * Treat as raw packet.
138 */
139 return toeplitz_vhash(key, sizeof(key),
140 /* ditto */
141 &ip->ip_src, sizeof(ip->ip_src) * 2,
142 NULL);
143 }
144 case IPPROTO_UDP:
145 {
146 if ((flag & RSS_TOEPLITZ_USE_UDP_PORT) != 0) {
147 if (m->m_len >= hlen + sizeof(struct udphdr)) {
148 struct udphdr *uh;
149
150 uh = (struct udphdr *)(mtod(m, char *) + hlen);
151 return toeplitz_vhash(key, sizeof(key),
152 /* ip_src and ip_dst in struct ip must sequential */
153 &ip->ip_src, sizeof(ip->ip_src) * 2,
154 /* uh_sport and uh_dport in udphdr must be sequential */
155 &uh->uh_sport, sizeof(uh->uh_sport) * 2,
156 NULL);
157 } else if (m->m_pkthdr.len >= hlen + sizeof(struct udphdr)) {
158 uint16_t ports[2];
159
160 /* ditto */
161 m_copydata(__UNCONST(m), hlen + offsetof(struct udphdr, uh_sport),
162 sizeof(ports), ports);
163 return toeplitz_vhash(key, sizeof(key),
164 &ip->ip_src, sizeof(ip->ip_src) * 2,
165 ports, sizeof(ports),
166 NULL);
167 }
168 }
169 /*
170 * Treat as raw packet.
171 */
172 return toeplitz_vhash(key, sizeof(key),
173 /* ditto */
174 &ip->ip_src, sizeof(ip->ip_src) * 2,
175 NULL);
176 }
177 /*
178 * Other protocols are treated as raw packets to apply RPS.
179 */
180 default:
181 return toeplitz_vhash(key, sizeof(key),
182 /* ditto */
183 &ip->ip_src, sizeof(ip->ip_src) * 2,
184 NULL);
185 }
186 }
187
188 /*
189 * Calculate rss hash value from IPv6 mbuf.
190 * This function should be called before ip6_input().
191 */
192 uint32_t
rss_toeplitz_hash_from_mbuf_ipv6(const struct mbuf * m,u_int flag)193 rss_toeplitz_hash_from_mbuf_ipv6(const struct mbuf *m, u_int flag)
194 {
195 struct ip6_hdr *ip6;
196 int hlen;
197 uint8_t key[RSS_KEYSIZE];
198
199 KASSERT((m->m_flags & M_PKTHDR) != 0);
200 KASSERT(m->m_len >= sizeof (struct ip6_hdr));
201
202 ip6 = mtod(m, struct ip6_hdr *);
203 KASSERT((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION);
204
205 hlen = sizeof(struct ip6_hdr);
206 rss_getkey(key);
207
208 switch (ip6->ip6_nxt) {
209 case IPPROTO_TCP:
210 {
211 if ((flag & RSS_TOEPLITZ_USE_TCP_PORT) != 0) {
212 if (m->m_len >= hlen + sizeof(struct tcphdr)) {
213 struct tcphdr *th;
214
215 th = (struct tcphdr *)(mtod(m, char *) + hlen);
216 return toeplitz_vhash(key, sizeof(key),
217 /* ip6_src and ip6_dst in ip6_hdr must be sequential */
218 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
219 /* th_sport and th_dport in tcphdr must be sequential */
220 &th->th_sport, sizeof(th->th_sport) * 2,
221 NULL);
222 } else if (m->m_pkthdr.len >= hlen + sizeof(struct tcphdr)) {
223 uint16_t ports[2];
224
225 /* ditto */
226 m_copydata(__UNCONST(m), hlen + offsetof(struct tcphdr, th_sport),
227 sizeof(ports), ports);
228 return toeplitz_vhash(key, sizeof(key),
229 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
230 ports, sizeof(ports),
231 NULL);
232 }
233 }
234 /*
235 * Treat as raw packet.
236 */
237 return toeplitz_vhash(key, sizeof(key),
238 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
239 NULL);
240 }
241 case IPPROTO_UDP:
242 {
243 if ((flag & RSS_TOEPLITZ_USE_UDP_PORT) != 0) {
244 if (m->m_len >= hlen + sizeof(struct udphdr)) {
245 struct udphdr *uh;
246
247 uh = (struct udphdr *)(mtod(m, char *) + hlen);
248 return toeplitz_vhash(key, sizeof(key),
249 /* ip6_src and ip6_dst in ip6_hdr must sequential */
250 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
251 /* uh_sport and uh_dport in udphdr must be sequential */
252 &uh->uh_sport, sizeof(uh->uh_sport) * 2,
253 NULL);
254 } else if (m->m_pkthdr.len >= hlen + sizeof(struct udphdr)) {
255 uint16_t ports[2];
256
257 /* ditto */
258 m_copydata(__UNCONST(m), hlen + offsetof(struct udphdr, uh_sport),
259 sizeof(ports), ports);
260 return toeplitz_vhash(key, sizeof(key),
261 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
262 &ports, sizeof(ports),
263 NULL);
264 }
265 }
266 /*
267 * Treat as raw packet.
268 */
269 return toeplitz_vhash(key, sizeof(key),
270 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
271 NULL);
272 }
273 /*
274 * Other protocols are treated as raw packets to apply RPS.
275 */
276 default:
277 return toeplitz_vhash(key, sizeof(key),
278 &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
279 NULL);
280 }
281
282 return 0;
283 }
284