1*67bc29b4Sknakahara /* $NetBSD: rss_config.c,v 1.3 2021/09/24 04:11:02 knakahara Exp $ */
24a6a088aSknakahara
34a6a088aSknakahara /*
44a6a088aSknakahara * Copyright (c) 2018 Internet Initiative Japan Inc.
54a6a088aSknakahara * All rights reserved.
64a6a088aSknakahara *
74a6a088aSknakahara * Redistribution and use in source and binary forms, with or without
84a6a088aSknakahara * modification, are permitted provided that the following conditions
94a6a088aSknakahara * are met:
104a6a088aSknakahara * 1. Redistributions of source code must retain the above copyright
114a6a088aSknakahara * notice, this list of conditions and the following disclaimer.
124a6a088aSknakahara * 2. Redistributions in binary form must reproduce the above copyright
134a6a088aSknakahara * notice, this list of conditions and the following disclaimer in the
144a6a088aSknakahara * documentation and/or other materials provided with the distribution.
154a6a088aSknakahara *
164a6a088aSknakahara * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
174a6a088aSknakahara * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
184a6a088aSknakahara * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
194a6a088aSknakahara * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
204a6a088aSknakahara * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214a6a088aSknakahara * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224a6a088aSknakahara * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234a6a088aSknakahara * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244a6a088aSknakahara * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
254a6a088aSknakahara * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
264a6a088aSknakahara * POSSIBILITY OF SUCH DAMAGE.
274a6a088aSknakahara */
284a6a088aSknakahara
294a6a088aSknakahara #include <sys/cdefs.h>
30*67bc29b4Sknakahara __KERNEL_RCSID(0, "$NetBSD: rss_config.c,v 1.3 2021/09/24 04:11:02 knakahara Exp $");
314a6a088aSknakahara
324a6a088aSknakahara #include <sys/param.h>
334a6a088aSknakahara #include <sys/systm.h>
344a6a088aSknakahara #include <sys/kernel.h>
35*67bc29b4Sknakahara #include <sys/mbuf.h>
364a6a088aSknakahara
374a6a088aSknakahara #include <net/rss_config.h>
38*67bc29b4Sknakahara #include <net/toeplitz.h>
39*67bc29b4Sknakahara
40*67bc29b4Sknakahara #include <netinet/in.h>
41*67bc29b4Sknakahara #include <netinet/ip.h>
42*67bc29b4Sknakahara #include <netinet/tcp.h>
43*67bc29b4Sknakahara #include <netinet/udp.h>
44*67bc29b4Sknakahara #include <netinet/ip6.h>
454a6a088aSknakahara
464a6a088aSknakahara /*
474a6a088aSknakahara * Same as FreeBSD.
484a6a088aSknakahara *
494a6a088aSknakahara * This rss key is assumed for verification suite in many intel Gigabit and
504a6a088aSknakahara * 10 Gigabit Controller specifications.
514a6a088aSknakahara */
524a6a088aSknakahara static uint8_t rss_default_key[RSS_KEYSIZE] = {
534a6a088aSknakahara 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
544a6a088aSknakahara 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
554a6a088aSknakahara 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
564a6a088aSknakahara 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
574a6a088aSknakahara 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa,
584a6a088aSknakahara };
594a6a088aSknakahara
604a6a088aSknakahara #ifdef NOTYET
614a6a088aSknakahara /*
624a6a088aSknakahara * Same as DragonFlyBSD.
634a6a088aSknakahara *
644a6a088aSknakahara * This rss key make rss hash value symmetric, that is, the hash value
654a6a088aSknakahara * calculated by func("source address", "destination address") equals to
664a6a088aSknakahara * the hash value calculated by func("destination address", "source address").
674a6a088aSknakahara */
684a6a088aSknakahara static uint8_t rss_symmetric_key[RSS_KEYSIZE] = {
694a6a088aSknakahara 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
704a6a088aSknakahara 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
714a6a088aSknakahara 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
724a6a088aSknakahara 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
7347b4370aSknakahara 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a, 0x6d, 0x5a,
744a6a088aSknakahara };
754a6a088aSknakahara #endif
764a6a088aSknakahara
774a6a088aSknakahara /*
784a6a088aSknakahara * sizeof(key) must be more than or equal to RSS_KEYSIZE.
794a6a088aSknakahara */
804a6a088aSknakahara void
rss_getkey(uint8_t * key)814a6a088aSknakahara rss_getkey(uint8_t *key)
824a6a088aSknakahara {
834a6a088aSknakahara
844a6a088aSknakahara memcpy(key, rss_default_key, sizeof(rss_default_key));
854a6a088aSknakahara }
86*67bc29b4Sknakahara
87*67bc29b4Sknakahara /*
88*67bc29b4Sknakahara * Calculate rss hash value from IPv4 mbuf.
89*67bc29b4Sknakahara * This function should be called before ip_input().
90*67bc29b4Sknakahara */
91*67bc29b4Sknakahara uint32_t
rss_toeplitz_hash_from_mbuf_ipv4(const struct mbuf * m,u_int flag)92*67bc29b4Sknakahara rss_toeplitz_hash_from_mbuf_ipv4(const struct mbuf *m, u_int flag)
93*67bc29b4Sknakahara {
94*67bc29b4Sknakahara struct ip *ip;
95*67bc29b4Sknakahara int hlen;
96*67bc29b4Sknakahara uint8_t key[RSS_KEYSIZE];
97*67bc29b4Sknakahara
98*67bc29b4Sknakahara KASSERT((m->m_flags & M_PKTHDR) != 0);
99*67bc29b4Sknakahara KASSERT(m->m_len >= sizeof (struct ip));
100*67bc29b4Sknakahara
101*67bc29b4Sknakahara ip = mtod(m, struct ip *);
102*67bc29b4Sknakahara KASSERT(ip->ip_v == IPVERSION);
103*67bc29b4Sknakahara
104*67bc29b4Sknakahara hlen = ip->ip_hl << 2;
105*67bc29b4Sknakahara if (hlen < sizeof(struct ip))
106*67bc29b4Sknakahara return 0;
107*67bc29b4Sknakahara
108*67bc29b4Sknakahara rss_getkey(key);
109*67bc29b4Sknakahara
110*67bc29b4Sknakahara switch (ip->ip_p) {
111*67bc29b4Sknakahara case IPPROTO_TCP:
112*67bc29b4Sknakahara {
113*67bc29b4Sknakahara if ((flag & RSS_TOEPLITZ_USE_TCP_PORT) != 0) {
114*67bc29b4Sknakahara if (m->m_len >= hlen + sizeof(struct tcphdr)) {
115*67bc29b4Sknakahara struct tcphdr *th;
116*67bc29b4Sknakahara
117*67bc29b4Sknakahara th = (struct tcphdr *)(mtod(m, char *) + hlen);
118*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
119*67bc29b4Sknakahara /* ip_src and ip_dst in struct ip must be sequential */
120*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
121*67bc29b4Sknakahara /* th_sport and th_dport in tcphdr must be sequential */
122*67bc29b4Sknakahara &th->th_sport, sizeof(th->th_sport) * 2,
123*67bc29b4Sknakahara NULL);
124*67bc29b4Sknakahara } else if (m->m_pkthdr.len >= hlen + sizeof(struct tcphdr)) {
125*67bc29b4Sknakahara uint16_t ports[2];
126*67bc29b4Sknakahara
127*67bc29b4Sknakahara /* ditto */
128*67bc29b4Sknakahara m_copydata(__UNCONST(m), hlen + offsetof(struct tcphdr, th_sport),
129*67bc29b4Sknakahara sizeof(ports), ports);
130*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
131*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
132*67bc29b4Sknakahara ports, sizeof(ports),
133*67bc29b4Sknakahara NULL);
134*67bc29b4Sknakahara }
135*67bc29b4Sknakahara }
136*67bc29b4Sknakahara /*
137*67bc29b4Sknakahara * Treat as raw packet.
138*67bc29b4Sknakahara */
139*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
140*67bc29b4Sknakahara /* ditto */
141*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
142*67bc29b4Sknakahara NULL);
143*67bc29b4Sknakahara }
144*67bc29b4Sknakahara case IPPROTO_UDP:
145*67bc29b4Sknakahara {
146*67bc29b4Sknakahara if ((flag & RSS_TOEPLITZ_USE_UDP_PORT) != 0) {
147*67bc29b4Sknakahara if (m->m_len >= hlen + sizeof(struct udphdr)) {
148*67bc29b4Sknakahara struct udphdr *uh;
149*67bc29b4Sknakahara
150*67bc29b4Sknakahara uh = (struct udphdr *)(mtod(m, char *) + hlen);
151*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
152*67bc29b4Sknakahara /* ip_src and ip_dst in struct ip must sequential */
153*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
154*67bc29b4Sknakahara /* uh_sport and uh_dport in udphdr must be sequential */
155*67bc29b4Sknakahara &uh->uh_sport, sizeof(uh->uh_sport) * 2,
156*67bc29b4Sknakahara NULL);
157*67bc29b4Sknakahara } else if (m->m_pkthdr.len >= hlen + sizeof(struct udphdr)) {
158*67bc29b4Sknakahara uint16_t ports[2];
159*67bc29b4Sknakahara
160*67bc29b4Sknakahara /* ditto */
161*67bc29b4Sknakahara m_copydata(__UNCONST(m), hlen + offsetof(struct udphdr, uh_sport),
162*67bc29b4Sknakahara sizeof(ports), ports);
163*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
164*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
165*67bc29b4Sknakahara ports, sizeof(ports),
166*67bc29b4Sknakahara NULL);
167*67bc29b4Sknakahara }
168*67bc29b4Sknakahara }
169*67bc29b4Sknakahara /*
170*67bc29b4Sknakahara * Treat as raw packet.
171*67bc29b4Sknakahara */
172*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
173*67bc29b4Sknakahara /* ditto */
174*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
175*67bc29b4Sknakahara NULL);
176*67bc29b4Sknakahara }
177*67bc29b4Sknakahara /*
178*67bc29b4Sknakahara * Other protocols are treated as raw packets to apply RPS.
179*67bc29b4Sknakahara */
180*67bc29b4Sknakahara default:
181*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
182*67bc29b4Sknakahara /* ditto */
183*67bc29b4Sknakahara &ip->ip_src, sizeof(ip->ip_src) * 2,
184*67bc29b4Sknakahara NULL);
185*67bc29b4Sknakahara }
186*67bc29b4Sknakahara }
187*67bc29b4Sknakahara
188*67bc29b4Sknakahara /*
189*67bc29b4Sknakahara * Calculate rss hash value from IPv6 mbuf.
190*67bc29b4Sknakahara * This function should be called before ip6_input().
191*67bc29b4Sknakahara */
192*67bc29b4Sknakahara uint32_t
rss_toeplitz_hash_from_mbuf_ipv6(const struct mbuf * m,u_int flag)193*67bc29b4Sknakahara rss_toeplitz_hash_from_mbuf_ipv6(const struct mbuf *m, u_int flag)
194*67bc29b4Sknakahara {
195*67bc29b4Sknakahara struct ip6_hdr *ip6;
196*67bc29b4Sknakahara int hlen;
197*67bc29b4Sknakahara uint8_t key[RSS_KEYSIZE];
198*67bc29b4Sknakahara
199*67bc29b4Sknakahara KASSERT((m->m_flags & M_PKTHDR) != 0);
200*67bc29b4Sknakahara KASSERT(m->m_len >= sizeof (struct ip6_hdr));
201*67bc29b4Sknakahara
202*67bc29b4Sknakahara ip6 = mtod(m, struct ip6_hdr *);
203*67bc29b4Sknakahara KASSERT((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION);
204*67bc29b4Sknakahara
205*67bc29b4Sknakahara hlen = sizeof(struct ip6_hdr);
206*67bc29b4Sknakahara rss_getkey(key);
207*67bc29b4Sknakahara
208*67bc29b4Sknakahara switch (ip6->ip6_nxt) {
209*67bc29b4Sknakahara case IPPROTO_TCP:
210*67bc29b4Sknakahara {
211*67bc29b4Sknakahara if ((flag & RSS_TOEPLITZ_USE_TCP_PORT) != 0) {
212*67bc29b4Sknakahara if (m->m_len >= hlen + sizeof(struct tcphdr)) {
213*67bc29b4Sknakahara struct tcphdr *th;
214*67bc29b4Sknakahara
215*67bc29b4Sknakahara th = (struct tcphdr *)(mtod(m, char *) + hlen);
216*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
217*67bc29b4Sknakahara /* ip6_src and ip6_dst in ip6_hdr must be sequential */
218*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
219*67bc29b4Sknakahara /* th_sport and th_dport in tcphdr must be sequential */
220*67bc29b4Sknakahara &th->th_sport, sizeof(th->th_sport) * 2,
221*67bc29b4Sknakahara NULL);
222*67bc29b4Sknakahara } else if (m->m_pkthdr.len >= hlen + sizeof(struct tcphdr)) {
223*67bc29b4Sknakahara uint16_t ports[2];
224*67bc29b4Sknakahara
225*67bc29b4Sknakahara /* ditto */
226*67bc29b4Sknakahara m_copydata(__UNCONST(m), hlen + offsetof(struct tcphdr, th_sport),
227*67bc29b4Sknakahara sizeof(ports), ports);
228*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
229*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
230*67bc29b4Sknakahara ports, sizeof(ports),
231*67bc29b4Sknakahara NULL);
232*67bc29b4Sknakahara }
233*67bc29b4Sknakahara }
234*67bc29b4Sknakahara /*
235*67bc29b4Sknakahara * Treat as raw packet.
236*67bc29b4Sknakahara */
237*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
238*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
239*67bc29b4Sknakahara NULL);
240*67bc29b4Sknakahara }
241*67bc29b4Sknakahara case IPPROTO_UDP:
242*67bc29b4Sknakahara {
243*67bc29b4Sknakahara if ((flag & RSS_TOEPLITZ_USE_UDP_PORT) != 0) {
244*67bc29b4Sknakahara if (m->m_len >= hlen + sizeof(struct udphdr)) {
245*67bc29b4Sknakahara struct udphdr *uh;
246*67bc29b4Sknakahara
247*67bc29b4Sknakahara uh = (struct udphdr *)(mtod(m, char *) + hlen);
248*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
249*67bc29b4Sknakahara /* ip6_src and ip6_dst in ip6_hdr must sequential */
250*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
251*67bc29b4Sknakahara /* uh_sport and uh_dport in udphdr must be sequential */
252*67bc29b4Sknakahara &uh->uh_sport, sizeof(uh->uh_sport) * 2,
253*67bc29b4Sknakahara NULL);
254*67bc29b4Sknakahara } else if (m->m_pkthdr.len >= hlen + sizeof(struct udphdr)) {
255*67bc29b4Sknakahara uint16_t ports[2];
256*67bc29b4Sknakahara
257*67bc29b4Sknakahara /* ditto */
258*67bc29b4Sknakahara m_copydata(__UNCONST(m), hlen + offsetof(struct udphdr, uh_sport),
259*67bc29b4Sknakahara sizeof(ports), ports);
260*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
261*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
262*67bc29b4Sknakahara &ports, sizeof(ports),
263*67bc29b4Sknakahara NULL);
264*67bc29b4Sknakahara }
265*67bc29b4Sknakahara }
266*67bc29b4Sknakahara /*
267*67bc29b4Sknakahara * Treat as raw packet.
268*67bc29b4Sknakahara */
269*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
270*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
271*67bc29b4Sknakahara NULL);
272*67bc29b4Sknakahara }
273*67bc29b4Sknakahara /*
274*67bc29b4Sknakahara * Other protocols are treated as raw packets to apply RPS.
275*67bc29b4Sknakahara */
276*67bc29b4Sknakahara default:
277*67bc29b4Sknakahara return toeplitz_vhash(key, sizeof(key),
278*67bc29b4Sknakahara &ip6->ip6_src, sizeof(ip6->ip6_src) * 2,
279*67bc29b4Sknakahara NULL);
280*67bc29b4Sknakahara }
281*67bc29b4Sknakahara
282*67bc29b4Sknakahara return 0;
283*67bc29b4Sknakahara }
284