xref: /freebsd/sys/netinet/in_pcb_var.h (revision 1dda8ba77a20d983774a3bf0e94c51c93f1d8758)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1982, 1986, 1990, 1993
5  *	The Regents of the University of California.
6  * Copyright (c) 2010-2011 Juniper Networks, Inc.
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Robert N. M. Watson under
10  * contract to Juniper Networks, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef _NETINET_IN_PCB_VAR_H_
38 #define _NETINET_IN_PCB_VAR_H_
39 
40 /*
41  * Definitions shared between netinet/in_pcb.c and netinet6/in6_pcb.c
42  */
43 
44 #define	INP_UNCONNECTED	0x04000000	/* Not inserted into hashes. */
45 #define	INP_INLBGROUP	0x01000000	/* Inserted into inpcblbgroup. */
46 
47 /*
48  * The inpcb database change context used by bind(2) and connect(2) operations.
49  * Normally it is located on the stack and is initialized like this:
50  *	struct inpcbinfo_ctx ipictx = {
51  *		.pcbinfo = pcbinfo
52  *	};
53  */
54 struct inpcbinfo_ctx {
55 	struct inpcbinfo	*pcbinfo;
56 	struct inpbucket	*ebucket,	/* Target exact bucket */
57 				*wbucket,	/* Target(or old) wild bucket */
58 				*pbucket;	/* Port bucket */
59 	struct lbgroupbucket	*lbbucket;	/* Load balancer bucket */
60 };
61 
62 #define	INPBUCKET_LOCK(bucket)		mtx_lock(&(bucket)->lock)
63 #define	INPBUCKET_UNLOCK(bucket)	mtx_unlock(&(bucket)->lock)
64 #define	INPBUCKET_LOCK_ASSERT(bucket)	mtx_assert(&(bucket)->lock, MA_OWNED)
65 
66 #define	IPI_LOCK(ipi)	INPBUCKET_LOCK(&(ipi)->ipi_list_unconn)
67 #define	IPI_UNLOCK(ipi)	INPBUCKET_UNLOCK(&(ipi)->ipi_list_unconn)
68 #define	IPI_LOCK_ASSERT(ipi)	INPBUCKET_LOCK_ASSERT(&(ipi)->ipi_list_unconn)
69 
70 static inline void
inpcbinfo_ctx_wildlock(struct inpcbinfo_ctx * ipictx,uint16_t lport)71 inpcbinfo_ctx_wildlock(struct inpcbinfo_ctx *ipictx, uint16_t lport)
72 {
73 	if (ipictx->wbucket == NULL) {
74 		ipictx->wbucket = &ipictx->pcbinfo->ipi_hash_wild[
75 		    INP_PCBHASH_WILD(lport, ipictx->pcbinfo->ipi_hashmask)];
76 		INPBUCKET_LOCK(ipictx->wbucket);
77 	} else {
78 		MPASS(ipictx->wbucket == &ipictx->pcbinfo->ipi_hash_wild[
79 		    INP_PCBHASH_WILD(lport, ipictx->pcbinfo->ipi_hashmask)]);
80 		INPBUCKET_LOCK_ASSERT(ipictx->wbucket);
81 	}
82 }
83 
84 static inline void
inpcbinfo_ctx_portlock(struct inpcbinfo_ctx * ipictx,uint16_t lport)85 inpcbinfo_ctx_portlock(struct inpcbinfo_ctx *ipictx, uint16_t lport)
86 {
87 	if (ipictx->pbucket == NULL) {
88 		ipictx->pbucket = &ipictx->pcbinfo->ipi_porthash[
89 		    INP_PCBPORTHASH(lport, ipictx->pcbinfo->ipi_porthashmask)];
90 		INPBUCKET_LOCK(ipictx->pbucket);
91 	} else {
92 		MPASS(ipictx->pbucket == &ipictx->pcbinfo->ipi_porthash[
93 		    INP_PCBPORTHASH(lport, ipictx->pcbinfo->ipi_porthashmask)]);
94 		INPBUCKET_LOCK_ASSERT(ipictx->pbucket);
95 	}
96 }
97 
98 static inline void
inpcbinfo_ctx_release(struct inpcbinfo_ctx * ipictx)99 inpcbinfo_ctx_release(struct inpcbinfo_ctx *ipictx)
100 {
101 	if (ipictx->ebucket != NULL)
102 		INPBUCKET_UNLOCK(ipictx->ebucket);
103 	if (ipictx->wbucket != NULL)
104 		INPBUCKET_UNLOCK(ipictx->wbucket);
105 	if (ipictx->pbucket != NULL)
106 		INPBUCKET_UNLOCK(ipictx->pbucket);
107 	if (ipictx->lbbucket != NULL)
108 		INPBUCKET_UNLOCK(ipictx->lbbucket);
109 }
110 
111 void	inp_lock(struct inpcb *inp, const inp_lookup_t lock);
112 void	inp_unlock(struct inpcb *inp, const inp_lookup_t lock);
113 int	inp_trylock(struct inpcb *inp, const inp_lookup_t lock);
114 bool	inp_smr_lock(struct inpcb *, const inp_lookup_t);
115 int	in_pcb_lport(struct inpcbinfo_ctx *, struct inpcb *, struct in_addr *,
116 	    u_short *, struct ucred *, int);
117 int	in_pcb_lport_dest(struct inpcbinfo_ctx *ipictx,
118 	    struct inpcb *inp, const struct sockaddr *lsa,
119 	    const struct sockaddr *fsa, u_short fport, struct ucred *cred,
120 	    int lookupflags, u_short *lportp);
121 struct inpcb *in_pcblookup_local(struct inpcbinfo_ctx *, struct in_addr,
122 	    u_short, int, int, struct ucred *);
123 struct inpcb *in6_pcblookup_local(struct inpcbinfo_ctx *,
124 	    const struct in6_addr *, u_short, int, int, struct ucred *);
125 struct inpcb *in6_pcblookup_internal(struct inpcbinfo_ctx *ipictx,
126 	    const struct in6_addr *faddr, u_int fport_arg,
127 	    const struct in6_addr *laddr, u_int lport_arg,
128 	    int lookupflags, uint8_t numa_domain, int fib);
129 int     in_pcbinshash(struct inpcb *, struct inpcbinfo_ctx *);
130 void    in_pcbrehash(struct inpcb *, struct inpcbinfo_ctx *);
131 void    in_pcbremhash(struct inpcb *);
132 struct inpcblbgroup *in_pcblbgroup_find(struct inpcb *inp,
133 	    struct lbgroupbucket **bucket);
134 
135 /*
136  * Load balance groups used for the SO_REUSEPORT_LB socket option. Each group
137  * (or unique address:port combination) can be re-used at most
138  * INPCBLBGROUP_SIZMAX (256) times. The inpcbs are stored in il_inp which
139  * is dynamically resized as processes bind/unbind to that specific group.
140  */
141 struct inpcblbgroup {
142 	CK_LIST_ENTRY(inpcblbgroup) il_list;
143 	LIST_HEAD(, inpcb) il_pending;	/* PCBs waiting for listen() */
144 	struct epoch_context il_epoch_ctx;
145 	struct ucred	*il_cred;
146 	uint16_t	il_lport;			/* (c) */
147 	u_char		il_vflag;			/* (c) */
148 	uint8_t		il_numa_domain;
149 	int		il_fibnum;
150 	union in_dependaddr il_dependladdr;		/* (c) */
151 #define	il_laddr	il_dependladdr.id4_addr
152 #define	il6_laddr	il_dependladdr.id6_addr
153 	uint32_t	il_inpsiz; /* max count in il_inp[] (h) */
154 	uint32_t	il_inpcnt; /* cur count in il_inp[] (h) */
155 	uint32_t	il_pendcnt; /* cur count in il_pending (h) */
156 	struct inpcb	*il_inp[];			/* (h) */
157 };
158 
159 #endif /* !_NETINET_IN_PCB_VAR_H_ */
160