Home | History | Annotate | Line # | Download | only in net
      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
     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
     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
    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