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