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 */ 52static 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 */ 68static 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 */ 80void 81rss_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 */ 91uint32_t 92rss_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 */ 192uint32_t 193rss_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