xref: /netbsd-src/sys/net/rss_config.c (revision 67bc29b45be0513ed7e26fd77c28d11474a4232b)
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