xref: /xnu-8792.61.2/bsd/skywalk/namespace/flowidns.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1*42e22086SApple OSS Distributions /*
2*42e22086SApple OSS Distributions  * Copyright (c) 2021 Apple Inc. All rights reserved.
3*42e22086SApple OSS Distributions  *
4*42e22086SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*42e22086SApple OSS Distributions  *
6*42e22086SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*42e22086SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*42e22086SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*42e22086SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*42e22086SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*42e22086SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*42e22086SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*42e22086SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*42e22086SApple OSS Distributions  *
15*42e22086SApple OSS Distributions  * Please obtain a copy of the License at
16*42e22086SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*42e22086SApple OSS Distributions  *
18*42e22086SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*42e22086SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*42e22086SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*42e22086SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*42e22086SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*42e22086SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*42e22086SApple OSS Distributions  * limitations under the License.
25*42e22086SApple OSS Distributions  *
26*42e22086SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*42e22086SApple OSS Distributions  */
28*42e22086SApple OSS Distributions 
29*42e22086SApple OSS Distributions /*
30*42e22086SApple OSS Distributions  * The flowidns (Flow ID namespace) module provides functionality to allocate
31*42e22086SApple OSS Distributions  * globally unique identifier for a flow.
32*42e22086SApple OSS Distributions  * Currently we have four modules (flowswitch, inpcb, PF & IPSec driver) in our
33*42e22086SApple OSS Distributions  * stack which need to generate flow identifiers. These modules stamp every
34*42e22086SApple OSS Distributions  * outgoing packet with a flowID. This flowID can be used by other upstream
35*42e22086SApple OSS Distributions  * components in the device for flow classification purpose. For example, the
36*42e22086SApple OSS Distributions  * FQ-Codel algorithm relies on this per packet flowID to avoid parsing every
37*42e22086SApple OSS Distributions  * packet header for flow classification. A globally unique flowID can also be
38*42e22086SApple OSS Distributions  * used by the networking feature offload engines operating at link layer to
39*42e22086SApple OSS Distributions  * avoid flow classification operations.
40*42e22086SApple OSS Distributions  * For performance reasons we use the concept of a flow domain and the
41*42e22086SApple OSS Distributions  * data structures used by the flowidns module have per domain instance.
42*42e22086SApple OSS Distributions  * These domains represent the above mentioned four modules generating the
43*42e22086SApple OSS Distributions  * flowID. This allows us to avoid global lock being used while allocating &
44*42e22086SApple OSS Distributions  * releasing flowID. FlowID is a 32-bit unsigned integer and the 2 most
45*42e22086SApple OSS Distributions  * significant bits of flowID are used to encode the domain ID. This
46*42e22086SApple OSS Distributions  * encoding also means that the flowID generator only needs to ensure
47*42e22086SApple OSS Distributions  * uniqueness of identifier within a domain.
48*42e22086SApple OSS Distributions  */
49*42e22086SApple OSS Distributions 
50*42e22086SApple OSS Distributions #include <skywalk/os_skywalk.h>
51*42e22086SApple OSS Distributions #include <skywalk/os_skywalk_private.h>
52*42e22086SApple OSS Distributions #include <skywalk/namespace/flowidns.h>
53*42e22086SApple OSS Distributions #include <dev/random/randomdev.h>
54*42e22086SApple OSS Distributions #include <sys/sdt.h>
55*42e22086SApple OSS Distributions 
56*42e22086SApple OSS Distributions /* maximum number of flowID generation retries in case of collision */
57*42e22086SApple OSS Distributions #define FLOWIDNS_MAX_FLOWID_GEN_RETRY  5
58*42e22086SApple OSS Distributions 
59*42e22086SApple OSS Distributions /* 2 most significant bits of the flowID are used to encode the flow domain */
60*42e22086SApple OSS Distributions #define FLOWIDNS_FLOWID_DOMAIN_SHIFT   30
61*42e22086SApple OSS Distributions #define FLOWIDNS_FLOWID_DOMAIN_MASK    (0x03 << FLOWIDNS_FLOWID_DOMAIN_SHIFT)
62*42e22086SApple OSS Distributions 
63*42e22086SApple OSS Distributions #define FLOWIDNS_FLOWID_SET_DOMAIN(_dom, _fid)    do {         \
64*42e22086SApple OSS Distributions 	(_fid) &= ~FLOWIDNS_FLOWID_DOMAIN_MASK;                \
65*42e22086SApple OSS Distributions 	(_fid) |= ((_dom) << FLOWIDNS_FLOWID_DOMAIN_SHIFT);    \
66*42e22086SApple OSS Distributions } while (0)
67*42e22086SApple OSS Distributions 
68*42e22086SApple OSS Distributions #define FLOWIDNS_FLOWID_GET_DOMAIN(_dom, _fid)    do {    \
69*42e22086SApple OSS Distributions 	(_dom) = (_fid) >> FLOWIDNS_FLOWID_DOMAIN_SHIFT;  \
70*42e22086SApple OSS Distributions } while (0)
71*42e22086SApple OSS Distributions 
72*42e22086SApple OSS Distributions #define FLOWIDNS_DOM_LOCK(_dom)    \
73*42e22086SApple OSS Distributions 	lck_mtx_lock(&(flowidns_domain_array[(_dom)].fd_mtx))
74*42e22086SApple OSS Distributions #define FLOWIDNS_DOM_UNLOCK(_dom)    \
75*42e22086SApple OSS Distributions 	lck_mtx_unlock(&(flowidns_domain_array[(_dom)].fd_mtx))
76*42e22086SApple OSS Distributions 
77*42e22086SApple OSS Distributions struct flowidns_flowid_tree_node {
78*42e22086SApple OSS Distributions 	RB_ENTRY(flowidns_flowid_tree_node) fftn_link;
79*42e22086SApple OSS Distributions 	struct flowidns_flow_key            fftn_flowkey;
80*42e22086SApple OSS Distributions 	flowidns_flowid_t                   fftn_flowid;
81*42e22086SApple OSS Distributions };
82*42e22086SApple OSS Distributions 
83*42e22086SApple OSS Distributions static LCK_GRP_DECLARE(flowidns_lock_group, "flowidns_lock");
84*42e22086SApple OSS Distributions static int __flowidns_inited = 0;
85*42e22086SApple OSS Distributions 
86*42e22086SApple OSS Distributions static ZONE_DEFINE(flowidns_fftn_zone, SKMEM_ZONE_PREFIX ".flowidns.fftn",
87*42e22086SApple OSS Distributions     sizeof(struct flowidns_flowid_tree_node), ZC_NONE);
88*42e22086SApple OSS Distributions 
89*42e22086SApple OSS Distributions __attribute__((always_inline))
90*42e22086SApple OSS Distributions static inline int
fftn_cmp(const struct flowidns_flowid_tree_node * fftn1,const struct flowidns_flowid_tree_node * fftn2)91*42e22086SApple OSS Distributions fftn_cmp(const struct flowidns_flowid_tree_node *fftn1,
92*42e22086SApple OSS Distributions     const struct flowidns_flowid_tree_node *fftn2)
93*42e22086SApple OSS Distributions {
94*42e22086SApple OSS Distributions 	return (signed)(fftn1->fftn_flowid - fftn2->fftn_flowid);
95*42e22086SApple OSS Distributions }
96*42e22086SApple OSS Distributions 
97*42e22086SApple OSS Distributions RB_HEAD(flowidns_flowid_tree, flowidns_flowid_tree_node);
98*42e22086SApple OSS Distributions RB_PROTOTYPE(flowidns_flowid_tree, flowidns_flowid_tree_node, fftn_link,
99*42e22086SApple OSS Distributions     fftn_cmp);
100*42e22086SApple OSS Distributions RB_GENERATE(flowidns_flowid_tree, flowidns_flowid_tree_node, fftn_link,
101*42e22086SApple OSS Distributions     fftn_cmp);
102*42e22086SApple OSS Distributions 
103*42e22086SApple OSS Distributions struct flowidns_domain {
104*42e22086SApple OSS Distributions 	decl_lck_mtx_data(, fd_mtx);
105*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree    fd_flowid_tree;
106*42e22086SApple OSS Distributions 	uint32_t                       fd_id;
107*42e22086SApple OSS Distributions 	uint64_t                       fd_nallocs;
108*42e22086SApple OSS Distributions 	uint64_t                       fd_nreleases;
109*42e22086SApple OSS Distributions 	uint64_t                       fd_ncollisions;
110*42e22086SApple OSS Distributions };
111*42e22086SApple OSS Distributions 
112*42e22086SApple OSS Distributions static struct flowidns_domain flowidns_domain_array[FLOWIDNS_DOMAIN_MAX + 1];
113*42e22086SApple OSS Distributions 
114*42e22086SApple OSS Distributions static struct flowidns_flowid_tree_node *
flowidns_fftn_alloc(bool can_block)115*42e22086SApple OSS Distributions flowidns_fftn_alloc(bool can_block)
116*42e22086SApple OSS Distributions {
117*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node *fftn = NULL;
118*42e22086SApple OSS Distributions 	zalloc_flags_t zflags;
119*42e22086SApple OSS Distributions 
120*42e22086SApple OSS Distributions 	zflags = can_block ? Z_WAITOK_ZERO : Z_NOWAIT_ZERO;
121*42e22086SApple OSS Distributions 	fftn = zalloc_flags(flowidns_fftn_zone, zflags);
122*42e22086SApple OSS Distributions 	return fftn;
123*42e22086SApple OSS Distributions }
124*42e22086SApple OSS Distributions 
125*42e22086SApple OSS Distributions static void
flowidns_fftn_free(struct flowidns_flowid_tree_node * fftn)126*42e22086SApple OSS Distributions flowidns_fftn_free(struct flowidns_flowid_tree_node *fftn)
127*42e22086SApple OSS Distributions {
128*42e22086SApple OSS Distributions 	zfree(flowidns_fftn_zone, fftn);
129*42e22086SApple OSS Distributions }
130*42e22086SApple OSS Distributions 
131*42e22086SApple OSS Distributions static struct flowidns_flowid_tree_node *
flowidns_find_fftn(flowidns_flowid_t flowid,flowidns_domain_id_t domain)132*42e22086SApple OSS Distributions flowidns_find_fftn(flowidns_flowid_t flowid, flowidns_domain_id_t domain)
133*42e22086SApple OSS Distributions {
134*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node find = { .fftn_flowid = flowid };
135*42e22086SApple OSS Distributions 
136*42e22086SApple OSS Distributions 	return RB_FIND(flowidns_flowid_tree,
137*42e22086SApple OSS Distributions 	           &(flowidns_domain_array[domain].fd_flowid_tree), &find);
138*42e22086SApple OSS Distributions }
139*42e22086SApple OSS Distributions 
140*42e22086SApple OSS Distributions void
flowidns_allocate_flowid(flowidns_domain_id_t domain,struct flowidns_flow_key * pflow_key,flowidns_flowid_t * pflowid)141*42e22086SApple OSS Distributions flowidns_allocate_flowid(flowidns_domain_id_t domain,
142*42e22086SApple OSS Distributions     struct flowidns_flow_key *pflow_key, flowidns_flowid_t *pflowid)
143*42e22086SApple OSS Distributions {
144*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node *fftn = NULL, *dup = NULL;
145*42e22086SApple OSS Distributions 	uint32_t flowid = 0;
146*42e22086SApple OSS Distributions 	int retry_cnt = 0;
147*42e22086SApple OSS Distributions 
148*42e22086SApple OSS Distributions 	VERIFY(__flowidns_inited == 1);
149*42e22086SApple OSS Distributions 	VERIFY(pflowid != NULL);
150*42e22086SApple OSS Distributions 	VERIFY(pflow_key != NULL);
151*42e22086SApple OSS Distributions 	VERIFY(domain >= FLOWIDNS_DOMAIN_MIN &&
152*42e22086SApple OSS Distributions 	    domain <= FLOWIDNS_DOMAIN_MAX);
153*42e22086SApple OSS Distributions 
154*42e22086SApple OSS Distributions 	FLOWIDNS_DOM_LOCK(domain);
155*42e22086SApple OSS Distributions 
156*42e22086SApple OSS Distributions 	fftn = flowidns_fftn_alloc(true);
157*42e22086SApple OSS Distributions 	if (__improbable(fftn == NULL)) {
158*42e22086SApple OSS Distributions 		panic_plain("failed to allocate flowid node\n");
159*42e22086SApple OSS Distributions 	}
160*42e22086SApple OSS Distributions retry:
161*42e22086SApple OSS Distributions 	/* try to get a non-zero flow identifier */
162*42e22086SApple OSS Distributions 	do {
163*42e22086SApple OSS Distributions 		read_frandom(&flowid, sizeof(flowid));
164*42e22086SApple OSS Distributions 	} while (__improbable(flowid == 0));
165*42e22086SApple OSS Distributions 
166*42e22086SApple OSS Distributions 	FLOWIDNS_FLOWID_SET_DOMAIN(domain, flowid);
167*42e22086SApple OSS Distributions 
168*42e22086SApple OSS Distributions 	fftn->fftn_flowid = flowid;
169*42e22086SApple OSS Distributions 	fftn->fftn_flowkey = *pflow_key;
170*42e22086SApple OSS Distributions 	dup = RB_INSERT(flowidns_flowid_tree,
171*42e22086SApple OSS Distributions 	    &(flowidns_domain_array[domain].fd_flowid_tree), fftn);
172*42e22086SApple OSS Distributions 
173*42e22086SApple OSS Distributions 	/* try to get a unique flow identifier */
174*42e22086SApple OSS Distributions 	if (dup != NULL) {
175*42e22086SApple OSS Distributions 		retry_cnt++;
176*42e22086SApple OSS Distributions 		flowidns_domain_array[domain].fd_ncollisions++;
177*42e22086SApple OSS Distributions 		SK_ERR("duplicate flowid 0x%x generated, retrying %d",
178*42e22086SApple OSS Distributions 		    flowid, retry_cnt);
179*42e22086SApple OSS Distributions 		/*
180*42e22086SApple OSS Distributions 		 * safeguard to check if we need a better hash strategy.
181*42e22086SApple OSS Distributions 		 */
182*42e22086SApple OSS Distributions 		VERIFY(retry_cnt <= FLOWIDNS_MAX_FLOWID_GEN_RETRY);
183*42e22086SApple OSS Distributions 		goto retry;
184*42e22086SApple OSS Distributions 	}
185*42e22086SApple OSS Distributions 	*pflowid = flowid;
186*42e22086SApple OSS Distributions 	flowidns_domain_array[domain].fd_nallocs++;
187*42e22086SApple OSS Distributions 	VERIFY(flowidns_domain_array[domain].fd_nallocs != 0);
188*42e22086SApple OSS Distributions 
189*42e22086SApple OSS Distributions 	FLOWIDNS_DOM_UNLOCK(domain);
190*42e22086SApple OSS Distributions 
191*42e22086SApple OSS Distributions 	DTRACE_SKYWALK2(fidalloc, uint32_t, domain, uint32_t, flowid);
192*42e22086SApple OSS Distributions }
193*42e22086SApple OSS Distributions 
194*42e22086SApple OSS Distributions void
flowidns_release_flowid(flowidns_flowid_t flowid)195*42e22086SApple OSS Distributions flowidns_release_flowid(flowidns_flowid_t flowid)
196*42e22086SApple OSS Distributions {
197*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node *fftn;
198*42e22086SApple OSS Distributions 	flowidns_domain_id_t domain;
199*42e22086SApple OSS Distributions 
200*42e22086SApple OSS Distributions 	VERIFY(__flowidns_inited == 1);
201*42e22086SApple OSS Distributions 	VERIFY(flowid != 0);
202*42e22086SApple OSS Distributions 
203*42e22086SApple OSS Distributions 	FLOWIDNS_FLOWID_GET_DOMAIN(domain, flowid);
204*42e22086SApple OSS Distributions 	VERIFY(domain >= FLOWIDNS_DOMAIN_MIN &&
205*42e22086SApple OSS Distributions 	    domain <= FLOWIDNS_DOMAIN_MAX);
206*42e22086SApple OSS Distributions 
207*42e22086SApple OSS Distributions 	DTRACE_SKYWALK2(fidrel, uint32_t, domain, uint32_t, flowid);
208*42e22086SApple OSS Distributions 
209*42e22086SApple OSS Distributions 	FLOWIDNS_DOM_LOCK(domain);
210*42e22086SApple OSS Distributions 
211*42e22086SApple OSS Distributions 	fftn = flowidns_find_fftn(flowid, domain);
212*42e22086SApple OSS Distributions 	if (fftn == NULL) {
213*42e22086SApple OSS Distributions 		panic_plain("flowid 0x%x not found in domain %d\n", flowid,
214*42e22086SApple OSS Distributions 		    domain);
215*42e22086SApple OSS Distributions 	}
216*42e22086SApple OSS Distributions 	RB_REMOVE(flowidns_flowid_tree,
217*42e22086SApple OSS Distributions 	    &(flowidns_domain_array[domain].fd_flowid_tree), fftn);
218*42e22086SApple OSS Distributions 	ASSERT(fftn->fftn_flowid == flowid);
219*42e22086SApple OSS Distributions 	flowidns_fftn_free(fftn);
220*42e22086SApple OSS Distributions 	flowidns_domain_array[domain].fd_nreleases++;
221*42e22086SApple OSS Distributions 	VERIFY(flowidns_domain_array[domain].fd_nreleases != 0);
222*42e22086SApple OSS Distributions 
223*42e22086SApple OSS Distributions 	FLOWIDNS_DOM_UNLOCK(domain);
224*42e22086SApple OSS Distributions }
225*42e22086SApple OSS Distributions 
226*42e22086SApple OSS Distributions int
flowidns_init()227*42e22086SApple OSS Distributions flowidns_init()
228*42e22086SApple OSS Distributions {
229*42e22086SApple OSS Distributions 	flowidns_domain_id_t domain;
230*42e22086SApple OSS Distributions 
231*42e22086SApple OSS Distributions 	VERIFY(__flowidns_inited == 0);
232*42e22086SApple OSS Distributions 	_CASSERT(SFH_DOMAIN_IPSEC == FLOWIDNS_DOMAIN_IPSEC);
233*42e22086SApple OSS Distributions 	_CASSERT(SFH_DOMAIN_FLOWSWITCH == FLOWIDNS_DOMAIN_FLOWSWITCH);
234*42e22086SApple OSS Distributions 	_CASSERT(SFH_DOMAIN_INPCB == FLOWIDNS_DOMAIN_INPCB);
235*42e22086SApple OSS Distributions 	_CASSERT(SFH_DOMAIN_PF == FLOWIDNS_DOMAIN_PF);
236*42e22086SApple OSS Distributions 	_CASSERT(FLOWIDNS_DOMAIN_MIN == 0);
237*42e22086SApple OSS Distributions 	/*
238*42e22086SApple OSS Distributions 	 * FLOWIDNS_FLOWID_DOMAIN_{MASK, SHIFT} macros are based on below
239*42e22086SApple OSS Distributions 	 * assumption.
240*42e22086SApple OSS Distributions 	 */
241*42e22086SApple OSS Distributions 	_CASSERT(FLOWIDNS_DOMAIN_MAX == 3);
242*42e22086SApple OSS Distributions 
243*42e22086SApple OSS Distributions 	for (domain = FLOWIDNS_DOMAIN_MIN; domain <= FLOWIDNS_DOMAIN_MAX;
244*42e22086SApple OSS Distributions 	    domain++) {
245*42e22086SApple OSS Distributions 		bzero(&flowidns_domain_array[domain],
246*42e22086SApple OSS Distributions 		    sizeof(struct flowidns_domain));
247*42e22086SApple OSS Distributions 		flowidns_domain_array[domain].fd_id = domain;
248*42e22086SApple OSS Distributions 		lck_mtx_init(&(flowidns_domain_array[domain].fd_mtx),
249*42e22086SApple OSS Distributions 		    &flowidns_lock_group, NULL);
250*42e22086SApple OSS Distributions 		RB_INIT(&(flowidns_domain_array[domain].fd_flowid_tree));
251*42e22086SApple OSS Distributions 	}
252*42e22086SApple OSS Distributions 
253*42e22086SApple OSS Distributions 	__flowidns_inited = 1;
254*42e22086SApple OSS Distributions 	SK_D("initialized flow ID namespace");
255*42e22086SApple OSS Distributions 	return 0;
256*42e22086SApple OSS Distributions }
257*42e22086SApple OSS Distributions 
258*42e22086SApple OSS Distributions void
flowidns_fini(void)259*42e22086SApple OSS Distributions flowidns_fini(void)
260*42e22086SApple OSS Distributions {
261*42e22086SApple OSS Distributions 	flowidns_domain_id_t domain;
262*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node *fftn, *fftn_tmp;
263*42e22086SApple OSS Distributions 
264*42e22086SApple OSS Distributions 	VERIFY(__flowidns_inited == 1);
265*42e22086SApple OSS Distributions 
266*42e22086SApple OSS Distributions 	for (domain = FLOWIDNS_DOMAIN_MIN; domain <= FLOWIDNS_DOMAIN_MAX;
267*42e22086SApple OSS Distributions 	    domain++) {
268*42e22086SApple OSS Distributions 		FLOWIDNS_DOM_LOCK(domain);
269*42e22086SApple OSS Distributions 
270*42e22086SApple OSS Distributions 		RB_FOREACH_SAFE(fftn, flowidns_flowid_tree,
271*42e22086SApple OSS Distributions 		    &(flowidns_domain_array[domain].fd_flowid_tree),
272*42e22086SApple OSS Distributions 		    fftn_tmp) {
273*42e22086SApple OSS Distributions 			RB_REMOVE(flowidns_flowid_tree,
274*42e22086SApple OSS Distributions 			    &(flowidns_domain_array[domain].fd_flowid_tree),
275*42e22086SApple OSS Distributions 			    fftn);
276*42e22086SApple OSS Distributions 			flowidns_fftn_free(fftn);
277*42e22086SApple OSS Distributions 		}
278*42e22086SApple OSS Distributions 
279*42e22086SApple OSS Distributions 		FLOWIDNS_DOM_UNLOCK(domain);
280*42e22086SApple OSS Distributions 
281*42e22086SApple OSS Distributions 		lck_mtx_destroy(&(flowidns_domain_array[domain].fd_mtx),
282*42e22086SApple OSS Distributions 		    &flowidns_lock_group);
283*42e22086SApple OSS Distributions 	}
284*42e22086SApple OSS Distributions 
285*42e22086SApple OSS Distributions 	__flowidns_inited = 0;
286*42e22086SApple OSS Distributions }
287*42e22086SApple OSS Distributions 
288*42e22086SApple OSS Distributions static int flowidns_stats_sysctl SYSCTL_HANDLER_ARGS;
289*42e22086SApple OSS Distributions SYSCTL_PROC(_kern_skywalk_stats, OID_AUTO, flowidns,
290*42e22086SApple OSS Distributions     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
291*42e22086SApple OSS Distributions     0, 0, flowidns_stats_sysctl, "-",
292*42e22086SApple OSS Distributions     "flowid allocations (struct sk_stats_flowidns_header, "
293*42e22086SApple OSS Distributions     "skywalk/os_stats_private.h)");
294*42e22086SApple OSS Distributions 
295*42e22086SApple OSS Distributions static int
flowidns_dump_domain(struct sysctl_req * req,struct flowidns_domain * domain)296*42e22086SApple OSS Distributions flowidns_dump_domain(struct sysctl_req *req, struct flowidns_domain *domain)
297*42e22086SApple OSS Distributions {
298*42e22086SApple OSS Distributions 	struct flowidns_flowid_tree_node *fftn;
299*42e22086SApple OSS Distributions 	struct sk_stats_flowidns_header header;
300*42e22086SApple OSS Distributions 	struct sk_stats_flowidns_record record;
301*42e22086SApple OSS Distributions 	uint64_t n_records;
302*42e22086SApple OSS Distributions 	int err;
303*42e22086SApple OSS Distributions 
304*42e22086SApple OSS Distributions 	/* Fill out header */
305*42e22086SApple OSS Distributions 	memset(&header, 0, sizeof(header));
306*42e22086SApple OSS Distributions 	header.sfh_domain = domain->fd_id;
307*42e22086SApple OSS Distributions 	header.sfh_nallocs = domain->fd_nallocs;
308*42e22086SApple OSS Distributions 	header.sfh_nreleases = domain->fd_nreleases;
309*42e22086SApple OSS Distributions 	header.sfh_ncollisions = domain->fd_ncollisions;
310*42e22086SApple OSS Distributions 	n_records = domain->fd_nallocs - domain->fd_nreleases;
311*42e22086SApple OSS Distributions 	VERIFY(n_records <= UINT32_MAX);
312*42e22086SApple OSS Distributions 	header.sfh_nrecords = (uint32_t)n_records;
313*42e22086SApple OSS Distributions 
314*42e22086SApple OSS Distributions 	err = SYSCTL_OUT(req, &header, sizeof(header));
315*42e22086SApple OSS Distributions 	if (err) {
316*42e22086SApple OSS Distributions 		return err;
317*42e22086SApple OSS Distributions 	}
318*42e22086SApple OSS Distributions 
319*42e22086SApple OSS Distributions 	/* Fill out records */
320*42e22086SApple OSS Distributions 	RB_FOREACH(fftn, flowidns_flowid_tree, &domain->fd_flowid_tree) {
321*42e22086SApple OSS Distributions 		VERIFY(n_records > 0);
322*42e22086SApple OSS Distributions 		n_records--;
323*42e22086SApple OSS Distributions 		bzero(&record, sizeof(record));
324*42e22086SApple OSS Distributions 		record.sfr_flowid = fftn->fftn_flowid;
325*42e22086SApple OSS Distributions 		record.sfr_af = fftn->fftn_flowkey.ffk_af;
326*42e22086SApple OSS Distributions 		record.sfr_ipproto = fftn->fftn_flowkey.ffk_proto;
327*42e22086SApple OSS Distributions 		record.sfr_protoid = fftn->fftn_flowkey.ffk_protoid;
328*42e22086SApple OSS Distributions 		_CASSERT(sizeof(fftn->fftn_flowkey.ffk_laddr) ==
329*42e22086SApple OSS Distributions 		    sizeof(record.sfr_laddr));
330*42e22086SApple OSS Distributions 		_CASSERT(sizeof(fftn->fftn_flowkey.ffk_raddr) ==
331*42e22086SApple OSS Distributions 		    sizeof(record.sfr_raddr));
332*42e22086SApple OSS Distributions 		bcopy(&(fftn->fftn_flowkey.ffk_laddr), &record.sfr_laddr,
333*42e22086SApple OSS Distributions 		    sizeof(record.sfr_laddr));
334*42e22086SApple OSS Distributions 		bcopy(&(fftn->fftn_flowkey.ffk_raddr), &record.sfr_raddr,
335*42e22086SApple OSS Distributions 		    sizeof(record.sfr_raddr));
336*42e22086SApple OSS Distributions 
337*42e22086SApple OSS Distributions 		err = SYSCTL_OUT(req, &record, sizeof(record));
338*42e22086SApple OSS Distributions 		if (err) {
339*42e22086SApple OSS Distributions 			return err;
340*42e22086SApple OSS Distributions 		}
341*42e22086SApple OSS Distributions 	}
342*42e22086SApple OSS Distributions 	VERIFY(n_records == 0);
343*42e22086SApple OSS Distributions 	return 0;
344*42e22086SApple OSS Distributions }
345*42e22086SApple OSS Distributions 
346*42e22086SApple OSS Distributions static int
347*42e22086SApple OSS Distributions flowidns_stats_sysctl SYSCTL_HANDLER_ARGS
348*42e22086SApple OSS Distributions {
349*42e22086SApple OSS Distributions #pragma unused(oidp, arg1, arg2)
350*42e22086SApple OSS Distributions 	flowidns_domain_id_t domain;
351*42e22086SApple OSS Distributions 	int err = 0;
352*42e22086SApple OSS Distributions 
353*42e22086SApple OSS Distributions 	if (!kauth_cred_issuser(kauth_cred_get())) {
354*42e22086SApple OSS Distributions 		return EPERM;
355*42e22086SApple OSS Distributions 	}
356*42e22086SApple OSS Distributions 
357*42e22086SApple OSS Distributions 	if (__flowidns_inited == 0) {
358*42e22086SApple OSS Distributions 		return ENOTSUP;
359*42e22086SApple OSS Distributions 	}
360*42e22086SApple OSS Distributions 
361*42e22086SApple OSS Distributions 	net_update_uptime();
362*42e22086SApple OSS Distributions 
363*42e22086SApple OSS Distributions 	for (domain = FLOWIDNS_DOMAIN_MIN; domain <= FLOWIDNS_DOMAIN_MAX;
364*42e22086SApple OSS Distributions 	    domain++) {
365*42e22086SApple OSS Distributions 		FLOWIDNS_DOM_LOCK(domain);
366*42e22086SApple OSS Distributions 		err = flowidns_dump_domain(req, &flowidns_domain_array[domain]);
367*42e22086SApple OSS Distributions 		FLOWIDNS_DOM_UNLOCK(domain);
368*42e22086SApple OSS Distributions 		if (err != 0) {
369*42e22086SApple OSS Distributions 			return err;
370*42e22086SApple OSS Distributions 		}
371*42e22086SApple OSS Distributions 	}
372*42e22086SApple OSS Distributions 	/*
373*42e22086SApple OSS Distributions 	 * If this is just a request for length, add slop because
374*42e22086SApple OSS Distributions 	 * this is dynamically changing data
375*42e22086SApple OSS Distributions 	 */
376*42e22086SApple OSS Distributions 	if (req->oldptr == USER_ADDR_NULL) {
377*42e22086SApple OSS Distributions 		req->oldidx += 20 * sizeof(struct sk_stats_flowidns_record);
378*42e22086SApple OSS Distributions 	}
379*42e22086SApple OSS Distributions 	return err;
380*42e22086SApple OSS Distributions }
381