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