in6_pcbgroup.c revision 268914
1133359Sobrien/*- 268349Sobrien * Copyright (c) 2010-2011 Juniper Networks, Inc. 3139368Sobrien * All rights reserved. 468349Sobrien * 568349Sobrien * This software was developed by Robert N. M. Watson under contract 6139368Sobrien * to Juniper Networks, Inc. 768349Sobrien * 868349Sobrien * Redistribution and use in source and binary forms, with or without 9139368Sobrien * modification, are permitted provided that the following conditions 1084685Sobrien * are met: 1184685Sobrien * 1. Redistributions of source code must retain the above copyright 12139368Sobrien * notice, this list of conditions and the following disclaimer. 13139368Sobrien * 2. Redistributions in binary form must reproduce the above copyright 14133359Sobrien * notice, this list of conditions and the following disclaimer in the 15133359Sobrien * documentation and/or other materials provided with the distribution. 16133359Sobrien * 17133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22110949Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23110949Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133359Sobrien * SUCH DAMAGE. 28133359Sobrien */ 29133359Sobrien 30169962Sobrien#include <sys/cdefs.h> 31169962Sobrien 32169962Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/in6_pcbgroup.c 268914 2014-07-20 07:39:54Z adrian $"); 33133359Sobrien 34133359Sobrien#include "opt_inet6.h" 35133359Sobrien#include "opt_rss.h" 36139368Sobrien 37139368Sobrien#include <sys/param.h> 38139368Sobrien#include <sys/mbuf.h> 39133359Sobrien 40133359Sobrien#include <netinet/in.h> 41133359Sobrien#include <netinet/in_pcb.h> 42159764Sobrien#include <netinet/in_rss.h> 43159764Sobrien#ifdef INET6 44159764Sobrien#include <netinet6/in6_pcb.h> 45133359Sobrien#endif /* INET6 */ 46133359Sobrien 47133359Sobrien/* 48133359Sobrien * Given a hash of whatever the covered tuple might be, return a pcbgroup 49103373Sobrien * index. Where RSS is supported, try to align bucket selection with RSS CPU 50103373Sobrien * affinity strategy. 51133359Sobrien */ 5280588Sobrienstatic __inline u_int 5380588Sobrienin6_pcbgroup_getbucket(struct inpcbinfo *pcbinfo, uint32_t hash) 54159764Sobrien{ 55159764Sobrien 56159764Sobrien#ifdef RSS 57133359Sobrien return (rss_getbucket(hash)); 58133359Sobrien#else 59133359Sobrien return (hash % pcbinfo->ipi_npcbgroups); 60133359Sobrien#endif 61133359Sobrien} 62133359Sobrien 63133359Sobrien/* 6468349Sobrien * Map a (hashtype, hash) tuple into a connection group, or NULL if the hash 6568349Sobrien * information is insufficient to identify the pcbgroup. This might occur if 66133359Sobrien * a TCP packet turnsup with a 2-tuple hash, or if an RSS hash is present but 67133359Sobrien * RSS is not compiled into the kernel. 6868349Sobrien */ 69133359Sobrienstruct inpcbgroup * 70133359Sobrienin6_pcbgroup_byhash(struct inpcbinfo *pcbinfo, u_int hashtype, uint32_t hash) 71103373Sobrien{ 72169962Sobrien 73169962Sobrien#ifdef RSS 74169962Sobrien if ((pcbinfo->ipi_hashfields == IPI_HASHFIELDS_4TUPLE && 75133359Sobrien hashtype == M_HASHTYPE_RSS_TCP_IPV6) || 76133359Sobrien (pcbinfo->ipi_hashfields == IPI_HASHFIELDS_4TUPLE && 77103373Sobrien hashtype == M_HASHTYPE_RSS_UDP_IPV6) || 78133359Sobrien (pcbinfo->ipi_hashfields == IPI_HASHFIELDS_2TUPLE && 79133359Sobrien hashtype == M_HASHTYPE_RSS_IPV6)) 80110949Sobrien return (&pcbinfo->ipi_pcbgroups[ 81133359Sobrien in6_pcbgroup_getbucket(pcbinfo, hash)]); 82133359Sobrien#endif 83133359Sobrien return (NULL); 8468349Sobrien} 85133359Sobrien 8680588Sobrienstruct inpcbgroup * 8780588Sobrienin6_pcbgroup_bymbuf(struct inpcbinfo *pcbinfo, struct mbuf *m) 88133359Sobrien{ 89103373Sobrien 90103373Sobrien return (in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m), 91169962Sobrien m->m_pkthdr.flowid)); 92169962Sobrien} 93169962Sobrien 94133359Sobrienstruct inpcbgroup * 95103373Sobrienin6_pcbgroup_bytuple(struct inpcbinfo *pcbinfo, const struct in6_addr *laddrp, 96103373Sobrien u_short lport, const struct in6_addr *faddrp, u_short fport) 97133359Sobrien{ 98133359Sobrien uint32_t hash; 99133359Sobrien 100133359Sobrien /* 101133359Sobrien * RSS note: we pass foreign addr/port as source, and local addr/port 102133359Sobrien * as destination, as we want to align with what the hardware is 103139368Sobrien * doing. 104139368Sobrien */ 105139368Sobrien switch (pcbinfo->ipi_hashfields) { 106133359Sobrien case IPI_HASHFIELDS_4TUPLE: 107133359Sobrien#ifdef RSS 108133359Sobrien hash = rss_hash_ip6_4tuple(*faddrp, fport, *laddrp, lport); 109133359Sobrien#else 110133359Sobrien hash = faddrp->s6_addr32[3] ^ fport; 111133359Sobrien#endif 112133359Sobrien break; 11368349Sobrien 11468349Sobrien case IPI_HASHFIELDS_2TUPLE: 115133359Sobrien#ifdef RSS 116133359Sobrien hash = rss_hash_ip6_2tuple(*faddrp, *laddrp); 117103373Sobrien#else 118133359Sobrien hash = faddrp->s6_addr32[3] ^ laddrp->s6_addr32[3]; 119133359Sobrien#endif 120133359Sobrien break; 121133359Sobrien 122133359Sobrien default: 123133359Sobrien hash = 0; 124159764Sobrien } 125159764Sobrien return (&pcbinfo->ipi_pcbgroups[in6_pcbgroup_getbucket(pcbinfo, 126159764Sobrien hash)]); 127133359Sobrien} 128133359Sobrien 129133359Sobrienstruct inpcbgroup * 130169942Sobrienin6_pcbgroup_byinpcb(struct inpcb *inp) 131169942Sobrien{ 132169942Sobrien 133133359Sobrien#ifdef RSS 134133359Sobrien /* 135133359Sobrien * Listen sockets with INP_RSS_BUCKET_SET set have a pre-determined 136133359Sobrien * RSS bucket and thus we should use this pcbgroup, rather than 137133359Sobrien * using a tuple or hash. 138133359Sobrien * 139133359Sobrien * XXX should verify that there's actually pcbgroups and inp_rss_listen_bucket 140133359Sobrien * fits in that! 141133359Sobrien */ 142133359Sobrien if (inp->inp_flags2 & INP_RSS_BUCKET_SET) 143133359Sobrien return (&inp->inp_pcbinfo->ipi_pcbgroups[inp->inp_rss_listen_bucket]); 14468349Sobrien#endif 14568349Sobrien 14668349Sobrien return (in6_pcbgroup_bytuple(inp->inp_pcbinfo, &inp->in6p_laddr, 147133359Sobrien inp->inp_lport, &inp->in6p_faddr, inp->inp_fport)); 148133359Sobrien} 149133359Sobrien