xref: /xnu-11215/bsd/net/dlil_sysctl.c (revision 8d741a5d)
1 /*
2  * Copyright (c) 1999-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
30  * support for mandatory and extensible security protections.  This notice
31  * is included in support of clause 2.2 (b) of the Apple Public License,
32  * Version 2.0.
33  */
34 
35 #include <stdint.h>
36 
37 #include <net/dlil_sysctl.h>
38 #include <net/dlil_var_private.h>
39 #include <net/net_api_stats.h>
40 #include <net/net_sysctl.h>
41 
42 #if SKYWALK
43 #include <skywalk/os_skywalk_private.h>
44 #endif /* SKYWALK */
45 
46 static int sysctl_rxpoll SYSCTL_HANDLER_ARGS;
47 static int sysctl_rxpoll_mode_holdtime SYSCTL_HANDLER_ARGS;
48 static int sysctl_rxpoll_sample_holdtime SYSCTL_HANDLER_ARGS;
49 static int sysctl_rxpoll_interval_time SYSCTL_HANDLER_ARGS;
50 static int sysctl_rxpoll_wlowat SYSCTL_HANDLER_ARGS;
51 static int sysctl_rxpoll_whiwat SYSCTL_HANDLER_ARGS;
52 static int sysctl_sndq_maxlen SYSCTL_HANDLER_ARGS;
53 static int sysctl_rcvq_maxlen SYSCTL_HANDLER_ARGS;
54 static int sysctl_rcvq_burst_limit SYSCTL_HANDLER_ARGS;
55 static int sysctl_rcvq_trim_pct SYSCTL_HANDLER_ARGS;
56 static int sysctl_hwcksum_dbg_mode SYSCTL_HANDLER_ARGS;
57 static int sysctl_hwcksum_dbg_partial_rxoff_forced SYSCTL_HANDLER_ARGS;
58 static int sysctl_hwcksum_dbg_partial_rxoff_adj SYSCTL_HANDLER_ARGS;
59 static int sysctl_tx_chain_len_stats SYSCTL_HANDLER_ARGS;
60 static int if_enable_fsw_transport_netagent_sysctl SYSCTL_HANDLER_ARGS;
61 
62 #if TEST_INPUT_THREAD_TERMINATION
63 static int sysctl_input_thread_termination_spin SYSCTL_HANDLER_ARGS;
64 #endif /* TEST_INPUT_THREAD_TERMINATION */
65 
66 #if (DEVELOPMENT || DEBUG)
67 static int sysctl_get_kao_frames SYSCTL_HANDLER_ARGS;
68 static int if_attach_nx_sysctl SYSCTL_HANDLER_ARGS;
69 #endif /* DEVELOPMENT | DEBUG */
70 
71 
72 
73 SYSCTL_DECL(_net_link_generic_system);
74 
75 /******************************************************************************
76 * Section: DLIL send and receive queues.                                     *
77 ******************************************************************************/
78 #define IF_SNDQ_MINLEN  32
79 uint32_t if_sndq_maxlen = IFQ_MAXLEN; /* should it be IFQ_SNDQ_MAXLEN ? */
80 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, sndq_maxlen,
81     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_sndq_maxlen, IFQ_MAXLEN,
82     sysctl_sndq_maxlen, "I", "Default transmit queue max length");
83 
84 uint32_t if_rcvq_maxlen = IF_RCVQ_MAXLEN;
85 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rcvq_maxlen,
86     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rcvq_maxlen, IFQ_MAXLEN,
87     sysctl_rcvq_maxlen, "I", "Default receive queue max length");
88 
89 uint32_t if_delaybased_queue = 1;
90 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, delaybased_queue,
91     CTLFLAG_RW | CTLFLAG_LOCKED, &if_delaybased_queue, 1,
92     "enable delay based dynamic queue sizing");
93 
94 uint32_t ifnet_start_delayed = 0;
95 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, start_delayed,
96     CTLFLAG_RW | CTLFLAG_LOCKED, &ifnet_start_delayed, 0,
97     "number of times start was delayed");
98 
99 uint32_t ifnet_delay_start_disabled = 0;
100 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, start_delay_disabled,
101     CTLFLAG_RW | CTLFLAG_LOCKED, &ifnet_delay_start_disabled, 0,
102     "number of times start was delayed");
103 
104 /*
105  * Protect against possible memory starvation that may happen
106  * when the driver is pushing data faster than the AP can process.
107  *
108  * If at any point during DLIL input phase any of the input queues
109  * exceeds the burst limit, DLIL will start to trim the queue,
110  * by returning mbufs in the input queue to the cache from which
111  * the mbufs were originally allocated, starting from the oldest
112  * mbuf and continuing until the new limit (see below) is reached.
113  *
114  * In order to avoid a steplocked equilibrium, the trimming
115  * will continue PAST the burst limit, until the corresponding
116  * input queue is reduced to `if_rcvq_trim_pct' %.
117  *
118  * For example, if the input queue limit is 1024 packets,
119  * and the trim percentage (`if_rcvq_trim_pct') is 80 %,
120  * the trimming will continue until the queue contains 819 packets
121  * (1024 * 80 / 100 == 819).
122  *
123  * Setting the burst limit too low can hurt the throughput,
124  * while setting the burst limit too high can defeat the purpose.
125  */
126 #define IF_RCVQ_BURST_LIMIT_MIN         1024
127 #define IF_RCVQ_BURST_LIMIT_DEFAULT     8192
128 #define IF_RCVQ_BURST_LIMIT_MAX         32768
129 uint32_t if_rcvq_burst_limit = IF_RCVQ_BURST_LIMIT_DEFAULT;
130 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rcvq_burst_limit,
131     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rcvq_burst_limit, IF_RCVQ_BURST_LIMIT_DEFAULT,
132     sysctl_rcvq_burst_limit, "I", "Upper memory limit for inbound data");
133 
134 #define IF_RCVQ_TRIM_PCT_MIN            20
135 #define IF_RCVQ_TRIM_PCT_DEFAULT        80
136 #define IF_RCVQ_TRIM_PCT_MAX            100
137 uint32_t if_rcvq_trim_pct = IF_RCVQ_TRIM_PCT_DEFAULT;
138 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rcvq_trim_pct,
139     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rcvq_trim_pct, IF_RCVQ_TRIM_PCT_DEFAULT,
140     sysctl_rcvq_trim_pct, "I",
141     "Percentage (0 - 100) of the queue limit to keep after detecting an overflow burst");
142 
143 struct chain_len_stats tx_chain_len_stats;
144 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, tx_chain_len_stats,
145     CTLFLAG_RD | CTLFLAG_LOCKED, 0, 9,
146     sysctl_tx_chain_len_stats, "S", "");
147 
148 uint32_t tx_chain_len_count = 0;
149 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, tx_chain_len_count,
150     CTLFLAG_RW | CTLFLAG_LOCKED, &tx_chain_len_count, 0, "");
151 
152 /******************************************************************************
153 * Section: DLIL opportunistic rx polling.                                    *
154 ******************************************************************************/
155 
156 uint32_t if_rxpoll = 1;
157 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll,
158     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll, 0,
159     sysctl_rxpoll, "I", "enable opportunistic input polling");
160 
161 #define IF_RXPOLL_DECAY                 2   /* ilog2 of EWMA decay rate (4) */
162 uint32_t if_rxpoll_decay = IF_RXPOLL_DECAY;
163 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, rxpoll_decay,
164     CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_decay, IF_RXPOLL_DECAY,
165     "ilog2 of EWMA decay rate of avg inbound packets");
166 
167 #define IF_RXPOLL_MODE_HOLDTIME_MIN     (10ULL * 1000 * 1000)   /* 10 ms */
168 #define IF_RXPOLL_MODE_HOLDTIME         (1000ULL * 1000 * 1000) /* 1 sec */
169 uint64_t if_rxpoll_mode_holdtime = IF_RXPOLL_MODE_HOLDTIME;
170 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll_freeze_time,
171     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_mode_holdtime,
172     IF_RXPOLL_MODE_HOLDTIME, sysctl_rxpoll_mode_holdtime,
173     "Q", "input poll mode freeze time");
174 
175 #define IF_RXPOLL_SAMPLETIME_MIN        (1ULL * 1000 * 1000)    /* 1 ms */
176 #define IF_RXPOLL_SAMPLETIME            (10ULL * 1000 * 1000)   /* 10 ms */
177 uint64_t if_rxpoll_sample_holdtime = IF_RXPOLL_SAMPLETIME;
178 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll_sample_time,
179     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_sample_holdtime,
180     IF_RXPOLL_SAMPLETIME, sysctl_rxpoll_sample_holdtime,
181     "Q", "input poll sampling time");
182 
183 /* Input poll interval definitions */
184 #define IF_RXPOLL_INTERVALTIME_MIN      (1ULL * 1000)           /* 1 us */
185 #define IF_RXPOLL_INTERVALTIME          (1ULL * 1000 * 1000)    /* 1 ms */
186 uint64_t if_rxpoll_interval_time = IF_RXPOLL_INTERVALTIME;
187 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll_interval_time,
188     CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_interval_time,
189     IF_RXPOLL_INTERVALTIME, sysctl_rxpoll_interval_time,
190     "Q", "input poll interval (time)");
191 
192 #define IF_RXPOLL_INTERVAL_PKTS         0   /* 0 (disabled) */
193 uint32_t if_rxpoll_interval_pkts = IF_RXPOLL_INTERVAL_PKTS;
194 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, rxpoll_interval_pkts,
195     CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_interval_pkts,
196     IF_RXPOLL_INTERVAL_PKTS, "input poll interval (packets)");
197 
198 #define IF_RXPOLL_WLOWAT                10
199 uint32_t if_sysctl_rxpoll_wlowat = IF_RXPOLL_WLOWAT;
200 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll_wakeups_lowat,
201     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_sysctl_rxpoll_wlowat,
202     IF_RXPOLL_WLOWAT, sysctl_rxpoll_wlowat,
203     "I", "input poll wakeup low watermark");
204 
205 #define IF_RXPOLL_WHIWAT                100
206 uint32_t if_sysctl_rxpoll_whiwat = IF_RXPOLL_WHIWAT;
207 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, rxpoll_wakeups_hiwat,
208     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &if_sysctl_rxpoll_whiwat,
209     IF_RXPOLL_WHIWAT, sysctl_rxpoll_whiwat,
210     "I", "input poll wakeup high watermark");
211 
212 uint32_t if_rxpoll_max = 0;  /* automatic */
213 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, rxpoll_max,
214     CTLFLAG_RW | CTLFLAG_LOCKED, &if_rxpoll_max, 0,
215     "max packets per poll call");
216 
217 #if TEST_INPUT_THREAD_TERMINATION
218 uint32_t if_input_thread_termination_spin = 0 /* disabled */;
219 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, input_thread_termination_spin,
220     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
221     &if_input_thread_termination_spin, 0,
222     sysctl_input_thread_termination_spin,
223     "I", "input thread termination spin limit");
224 #endif /* TEST_INPUT_THREAD_TERMINATION */
225 
226 uint32_t cur_dlil_input_threads = 0;
227 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, dlil_input_threads,
228     CTLFLAG_RD | CTLFLAG_LOCKED, &cur_dlil_input_threads, 0,
229     "Current number of DLIL input threads");
230 
231 
232 /******************************************************************************
233 * Section: hardware-assisted checksum mechanism.                             *
234 ******************************************************************************/
235 
236 uint32_t hwcksum_tx = 1;
237 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, hwcksum_tx,
238     CTLFLAG_RW | CTLFLAG_LOCKED, &hwcksum_tx, 0,
239     "enable transmit hardware checksum offload");
240 
241 uint32_t hwcksum_rx = 1;
242 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, hwcksum_rx,
243     CTLFLAG_RW | CTLFLAG_LOCKED, &hwcksum_rx, 0,
244     "enable receive hardware checksum offload");
245 
246 uint64_t hwcksum_in_invalidated = 0;
247 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
248     hwcksum_in_invalidated, CTLFLAG_RD | CTLFLAG_LOCKED,
249     &hwcksum_in_invalidated, "inbound packets with invalidated hardware cksum");
250 
251 uint32_t hwcksum_dbg = 0;
252 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, hwcksum_dbg,
253     CTLFLAG_RW | CTLFLAG_LOCKED, &hwcksum_dbg, 0,
254     "enable hardware cksum debugging");
255 
256 uint32_t hwcksum_dbg_mode = 0;
257 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, hwcksum_dbg_mode,
258     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &hwcksum_dbg_mode,
259     0, sysctl_hwcksum_dbg_mode, "I", "hardware cksum debugging mode");
260 
261 uint64_t hwcksum_dbg_partial_forced = 0;
262 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
263     hwcksum_dbg_partial_forced, CTLFLAG_RD | CTLFLAG_LOCKED,
264     &hwcksum_dbg_partial_forced, "packets forced using partial cksum");
265 
266 uint64_t hwcksum_dbg_partial_forced_bytes = 0;
267 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
268     hwcksum_dbg_partial_forced_bytes, CTLFLAG_RD | CTLFLAG_LOCKED,
269     &hwcksum_dbg_partial_forced_bytes, "bytes forced using partial cksum");
270 
271 uint32_t hwcksum_dbg_partial_rxoff_forced = 0;
272 SYSCTL_PROC(_net_link_generic_system, OID_AUTO,
273     hwcksum_dbg_partial_rxoff_forced, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
274     &hwcksum_dbg_partial_rxoff_forced, 0,
275     sysctl_hwcksum_dbg_partial_rxoff_forced, "I",
276     "forced partial cksum rx offset");
277 
278 uint32_t hwcksum_dbg_partial_rxoff_adj = 0;
279 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, hwcksum_dbg_partial_rxoff_adj,
280     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED, &hwcksum_dbg_partial_rxoff_adj,
281     0, sysctl_hwcksum_dbg_partial_rxoff_adj, "I",
282     "adjusted partial cksum rx offset");
283 
284 uint64_t hwcksum_dbg_verified = 0;
285 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
286     hwcksum_dbg_verified, CTLFLAG_RD | CTLFLAG_LOCKED,
287     &hwcksum_dbg_verified, "packets verified for having good checksum");
288 
289 uint64_t hwcksum_dbg_bad_cksum = 0;
290 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
291     hwcksum_dbg_bad_cksum, CTLFLAG_RD | CTLFLAG_LOCKED,
292     &hwcksum_dbg_bad_cksum, "packets with bad hardware calculated checksum");
293 
294 uint64_t hwcksum_dbg_bad_rxoff = 0;
295 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
296     hwcksum_dbg_bad_rxoff, CTLFLAG_RD | CTLFLAG_LOCKED,
297     &hwcksum_dbg_bad_rxoff, "packets with invalid rxoff");
298 
299 uint64_t hwcksum_dbg_adjusted = 0;
300 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
301     hwcksum_dbg_adjusted, CTLFLAG_RD | CTLFLAG_LOCKED,
302     &hwcksum_dbg_adjusted, "packets with rxoff adjusted");
303 
304 uint64_t hwcksum_dbg_finalized_hdr = 0;
305 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
306     hwcksum_dbg_finalized_hdr, CTLFLAG_RD | CTLFLAG_LOCKED,
307     &hwcksum_dbg_finalized_hdr, "finalized headers");
308 
309 uint64_t hwcksum_dbg_finalized_data = 0;
310 SYSCTL_QUAD(_net_link_generic_system, OID_AUTO,
311     hwcksum_dbg_finalized_data, CTLFLAG_RD | CTLFLAG_LOCKED,
312     &hwcksum_dbg_finalized_data, "finalized payloads");
313 
314 
315 /******************************************************************************
316 * Section: DLIL debugging, notifications and sanity checks                   *
317 ******************************************************************************/
318 
319 uint32_t if_flowadv = 1;
320 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, flow_advisory,
321     CTLFLAG_RW | CTLFLAG_LOCKED, &if_flowadv, 1,
322     "enable flow-advisory mechanism");
323 
324 uint32_t threshold_notify = 1;           /* enable/disable */
325 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, threshold_notify,
326     CTLFLAG_RW | CTLFLAG_LOCKED, &threshold_notify, 0, "");
327 
328 uint32_t threshold_interval = 2; /* in seconds */;
329 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, threshold_interval,
330     CTLFLAG_RW | CTLFLAG_LOCKED, &threshold_interval, 0, "");
331 
332 struct net_api_stats net_api_stats;
333 SYSCTL_STRUCT(_net, OID_AUTO, api_stats, CTLFLAG_RD | CTLFLAG_LOCKED,
334     &net_api_stats, net_api_stats, "");
335 
336 #if DEBUG
337 int dlil_verbose = 1;
338 #else
339 int dlil_verbose = 0;
340 #endif /* DEBUG */
341 
342 SYSCTL_INT(_net_link_generic_system, OID_AUTO, dlil_verbose,
343     CTLFLAG_RW | CTLFLAG_LOCKED, &dlil_verbose, 0, "Log DLIL error messages");
344 
345 uint32_t net_wake_pkt_debug = 0;
346 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, wake_pkt_debug,
347     CTLFLAG_RW | CTLFLAG_LOCKED, &net_wake_pkt_debug, 0, "");
348 
349 #if IFNET_INPUT_SANITY_CHK
350 uint32_t dlil_input_sanity_check = 0;
351 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, dlil_input_sanity_check,
352     CTLFLAG_RW | CTLFLAG_LOCKED, &dlil_input_sanity_check, 0,
353     "Turn on sanity checking in DLIL input");
354 #endif /* IFNET_INPUT_SANITY_CHK */
355 
356 
357 #if (DEVELOPMENT || DEBUG)
358 
359 static int sysctl_get_kao_frames SYSCTL_HANDLER_ARGS;
360 SYSCTL_NODE(_net_link_generic_system, OID_AUTO, get_kao_frames,
361     CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_get_kao_frames, "");
362 
363 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, if_attach_nx,
364     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
365     0, 0, &if_attach_nx_sysctl, "IU", "attach nexus");
366 
367 #endif /* DEVELOPMENT || DEBUG */
368 
369 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, enable_netagent,
370     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
371     0, 0, &if_enable_fsw_transport_netagent_sysctl, "IU",
372     "enable flowswitch netagent");
373 
374 
375 
376 #if TEST_INPUT_THREAD_TERMINATION
377 static int
378 sysctl_input_thread_termination_spin SYSCTL_HANDLER_ARGS
379 {
380 #pragma unused(arg1, arg2)
381 	uint32_t i;
382 	int err;
383 
384 	i = if_input_thread_termination_spin;
385 
386 	err = sysctl_handle_int(oidp, &i, 0, req);
387 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
388 		return err;
389 	}
390 
391 	if (net_rxpoll == 0) {
392 		return ENXIO;
393 	}
394 
395 	if_input_thread_termination_spin = i;
396 	return err;
397 }
398 #endif /* TEST_INPUT_THREAD_TERMINATION */
399 
400 static int
401 sysctl_rxpoll SYSCTL_HANDLER_ARGS
402 {
403 #pragma unused(arg1, arg2)
404 	uint32_t i;
405 	int err;
406 
407 	i = if_rxpoll;
408 
409 	err = sysctl_handle_int(oidp, &i, 0, req);
410 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
411 		return err;
412 	}
413 
414 	if (net_rxpoll == 0) {
415 		return ENXIO;
416 	}
417 
418 	if_rxpoll = i;
419 	return err;
420 }
421 
422 static int
423 sysctl_rxpoll_mode_holdtime SYSCTL_HANDLER_ARGS
424 {
425 #pragma unused(arg1, arg2)
426 	uint64_t q;
427 	int err;
428 
429 	q = if_rxpoll_mode_holdtime;
430 
431 	err = sysctl_handle_quad(oidp, &q, 0, req);
432 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
433 		return err;
434 	}
435 
436 	if (q < IF_RXPOLL_MODE_HOLDTIME_MIN) {
437 		q = IF_RXPOLL_MODE_HOLDTIME_MIN;
438 	}
439 
440 	if_rxpoll_mode_holdtime = q;
441 
442 	return err;
443 }
444 
445 static int
446 sysctl_rxpoll_sample_holdtime SYSCTL_HANDLER_ARGS
447 {
448 #pragma unused(arg1, arg2)
449 	uint64_t q;
450 	int err;
451 
452 	q = if_rxpoll_sample_holdtime;
453 
454 	err = sysctl_handle_quad(oidp, &q, 0, req);
455 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
456 		return err;
457 	}
458 
459 	if (q < IF_RXPOLL_SAMPLETIME_MIN) {
460 		q = IF_RXPOLL_SAMPLETIME_MIN;
461 	}
462 
463 	if_rxpoll_sample_holdtime = q;
464 
465 	return err;
466 }
467 
468 static int
469 sysctl_rxpoll_interval_time SYSCTL_HANDLER_ARGS
470 {
471 #pragma unused(arg1, arg2)
472 	uint64_t q;
473 	int err;
474 
475 	q = if_rxpoll_interval_time;
476 
477 	err = sysctl_handle_quad(oidp, &q, 0, req);
478 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
479 		return err;
480 	}
481 
482 	if (q < IF_RXPOLL_INTERVALTIME_MIN) {
483 		q = IF_RXPOLL_INTERVALTIME_MIN;
484 	}
485 
486 	if_rxpoll_interval_time = q;
487 
488 	return err;
489 }
490 
491 static int
492 sysctl_rxpoll_wlowat SYSCTL_HANDLER_ARGS
493 {
494 #pragma unused(arg1, arg2)
495 	uint32_t i;
496 	int err;
497 
498 	i = if_sysctl_rxpoll_wlowat;
499 
500 	err = sysctl_handle_int(oidp, &i, 0, req);
501 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
502 		return err;
503 	}
504 
505 	if (i == 0 || i >= if_sysctl_rxpoll_whiwat) {
506 		return EINVAL;
507 	}
508 
509 	if_sysctl_rxpoll_wlowat = i;
510 	return err;
511 }
512 
513 static int
514 sysctl_rxpoll_whiwat SYSCTL_HANDLER_ARGS
515 {
516 #pragma unused(arg1, arg2)
517 	uint32_t i;
518 	int err;
519 
520 	i = if_sysctl_rxpoll_whiwat;
521 
522 	err = sysctl_handle_int(oidp, &i, 0, req);
523 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
524 		return err;
525 	}
526 
527 	if (i <= if_sysctl_rxpoll_wlowat) {
528 		return EINVAL;
529 	}
530 
531 	if_sysctl_rxpoll_whiwat = i;
532 	return err;
533 }
534 
535 static int
536 sysctl_sndq_maxlen SYSCTL_HANDLER_ARGS
537 {
538 #pragma unused(arg1, arg2)
539 	int i, err;
540 
541 	i = if_sndq_maxlen;
542 
543 	err = sysctl_handle_int(oidp, &i, 0, req);
544 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
545 		return err;
546 	}
547 
548 	if (i < IF_SNDQ_MINLEN) {
549 		i = IF_SNDQ_MINLEN;
550 	}
551 
552 	if_sndq_maxlen = i;
553 	return err;
554 }
555 
556 static int
557 sysctl_rcvq_maxlen SYSCTL_HANDLER_ARGS
558 {
559 #pragma unused(arg1, arg2)
560 	int i, err;
561 
562 	i = if_rcvq_maxlen;
563 
564 	err = sysctl_handle_int(oidp, &i, 0, req);
565 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
566 		return err;
567 	}
568 
569 	if (i < IF_RCVQ_MINLEN) {
570 		i = IF_RCVQ_MINLEN;
571 	}
572 
573 	if_rcvq_maxlen = i;
574 	return err;
575 }
576 
577 static int
578 sysctl_rcvq_burst_limit SYSCTL_HANDLER_ARGS
579 {
580 #pragma unused(arg1, arg2)
581 	int i, err;
582 
583 	i = if_rcvq_burst_limit;
584 
585 	err = sysctl_handle_int(oidp, &i, 0, req);
586 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
587 		return err;
588 	}
589 
590 /*
591  * Safeguard the burst limit to "sane" values on customer builds.
592  */
593 #if !(DEVELOPMENT || DEBUG)
594 	if (i < IF_RCVQ_BURST_LIMIT_MIN) {
595 		i = IF_RCVQ_BURST_LIMIT_MIN;
596 	}
597 
598 	if (IF_RCVQ_BURST_LIMIT_MAX < i) {
599 		i = IF_RCVQ_BURST_LIMIT_MAX;
600 	}
601 #endif
602 
603 	if_rcvq_burst_limit = i;
604 	return err;
605 }
606 
607 static int
608 sysctl_rcvq_trim_pct SYSCTL_HANDLER_ARGS
609 {
610 #pragma unused(arg1, arg2)
611 	int i, err;
612 
613 	i = if_rcvq_burst_limit;
614 
615 	err = sysctl_handle_int(oidp, &i, 0, req);
616 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
617 		return err;
618 	}
619 
620 	if (IF_RCVQ_TRIM_PCT_MAX < i) {
621 		i = IF_RCVQ_TRIM_PCT_MAX;
622 	}
623 
624 	if (i < IF_RCVQ_TRIM_PCT_MIN) {
625 		i = IF_RCVQ_TRIM_PCT_MIN;
626 	}
627 
628 	if_rcvq_trim_pct = i;
629 	return err;
630 }
631 
632 static int
633 sysctl_hwcksum_dbg_mode SYSCTL_HANDLER_ARGS
634 {
635 #pragma unused(arg1, arg2)
636 	uint32_t i;
637 	int err;
638 
639 	i = hwcksum_dbg_mode;
640 
641 	err = sysctl_handle_int(oidp, &i, 0, req);
642 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
643 		return err;
644 	}
645 
646 	if (hwcksum_dbg == 0) {
647 		return ENODEV;
648 	}
649 
650 	if ((i & ~HWCKSUM_DBG_MASK) != 0) {
651 		return EINVAL;
652 	}
653 
654 	hwcksum_dbg_mode = (i & HWCKSUM_DBG_MASK);
655 
656 	return err;
657 }
658 
659 static int
660 sysctl_hwcksum_dbg_partial_rxoff_forced SYSCTL_HANDLER_ARGS
661 {
662 #pragma unused(arg1, arg2)
663 	u_int32_t i;
664 	int err;
665 
666 	i = hwcksum_dbg_partial_rxoff_forced;
667 
668 	err = sysctl_handle_int(oidp, &i, 0, req);
669 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
670 		return err;
671 	}
672 
673 	if (!(hwcksum_dbg_mode & HWCKSUM_DBG_PARTIAL_FORCED)) {
674 		return ENODEV;
675 	}
676 
677 	hwcksum_dbg_partial_rxoff_forced = i;
678 
679 	return err;
680 }
681 
682 static int
683 sysctl_hwcksum_dbg_partial_rxoff_adj SYSCTL_HANDLER_ARGS
684 {
685 #pragma unused(arg1, arg2)
686 	u_int32_t i;
687 	int err;
688 
689 	i = hwcksum_dbg_partial_rxoff_adj;
690 
691 	err = sysctl_handle_int(oidp, &i, 0, req);
692 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
693 		return err;
694 	}
695 
696 	if (!(hwcksum_dbg_mode & HWCKSUM_DBG_PARTIAL_RXOFF_ADJ)) {
697 		return ENODEV;
698 	}
699 
700 	hwcksum_dbg_partial_rxoff_adj = i;
701 
702 	return err;
703 }
704 
705 static int
706 sysctl_tx_chain_len_stats SYSCTL_HANDLER_ARGS
707 {
708 #pragma unused(oidp, arg1, arg2)
709 	int err;
710 
711 	if (req->oldptr == USER_ADDR_NULL) {
712 	}
713 	if (req->newptr != USER_ADDR_NULL) {
714 		return EPERM;
715 	}
716 	err = SYSCTL_OUT(req, &tx_chain_len_stats,
717 	    sizeof(struct chain_len_stats));
718 
719 	return err;
720 }
721 
722 #if (DEVELOPMENT || DEBUG)
723 /*
724  * The sysctl variable name contains the input parameters of
725  * ifnet_get_keepalive_offload_frames()
726  *  ifp (interface index): name[0]
727  *  frames_array_count:    name[1]
728  *  frame_data_offset:     name[2]
729  * The return length gives used_frames_count
730  */
731 static int
732 sysctl_get_kao_frames SYSCTL_HANDLER_ARGS
733 {
734 #pragma unused(oidp)
735 	DECLARE_SYSCTL_HANDLER_ARG_ARRAY(int, 3, name, namelen);
736 	int idx;
737 	ifnet_t ifp = NULL;
738 	u_int32_t frames_array_count;
739 	size_t frame_data_offset;
740 	u_int32_t used_frames_count;
741 	struct ifnet_keepalive_offload_frame *frames_array = NULL;
742 	int error = 0;
743 	u_int32_t i;
744 
745 	/*
746 	 * Only root can get look at other people TCP frames
747 	 */
748 	error = proc_suser(current_proc());
749 	if (error != 0) {
750 		goto done;
751 	}
752 	/*
753 	 * Validate the input parameters
754 	 */
755 	if (req->newptr != USER_ADDR_NULL) {
756 		error = EPERM;
757 		goto done;
758 	}
759 	if (req->oldptr == USER_ADDR_NULL) {
760 		error = EINVAL;
761 		goto done;
762 	}
763 	if (req->oldlen == 0) {
764 		error = EINVAL;
765 		goto done;
766 	}
767 	idx = name[0];
768 	frames_array_count = name[1];
769 	frame_data_offset = name[2];
770 
771 	/* Make sure the passed buffer is large enough */
772 	if (frames_array_count * sizeof(struct ifnet_keepalive_offload_frame) >
773 	    req->oldlen) {
774 		error = ENOMEM;
775 		goto done;
776 	}
777 
778 	ifnet_head_lock_shared();
779 	if (!IF_INDEX_IN_RANGE(idx)) {
780 		ifnet_head_done();
781 		error = ENOENT;
782 		goto done;
783 	}
784 	ifp = ifindex2ifnet[idx];
785 	ifnet_head_done();
786 
787 	frames_array = (struct ifnet_keepalive_offload_frame *)kalloc_data(
788 		frames_array_count * sizeof(struct ifnet_keepalive_offload_frame),
789 		Z_WAITOK);
790 	if (frames_array == NULL) {
791 		error = ENOMEM;
792 		goto done;
793 	}
794 
795 	error = ifnet_get_keepalive_offload_frames(ifp, frames_array,
796 	    frames_array_count, frame_data_offset, &used_frames_count);
797 	if (error != 0) {
798 		DLIL_PRINTF("%s: ifnet_get_keepalive_offload_frames error %d\n",
799 		    __func__, error);
800 		goto done;
801 	}
802 
803 	for (i = 0; i < used_frames_count; i++) {
804 		error = SYSCTL_OUT(req, frames_array + i,
805 		    sizeof(struct ifnet_keepalive_offload_frame));
806 		if (error != 0) {
807 			goto done;
808 		}
809 	}
810 done:
811 	if (frames_array != NULL) {
812 		kfree_data(frames_array, frames_array_count *
813 		    sizeof(struct ifnet_keepalive_offload_frame));
814 	}
815 	return error;
816 }
817 
818 static int
819 if_attach_nx_sysctl SYSCTL_HANDLER_ARGS
820 {
821 #pragma unused(oidp, arg1, arg2)
822 	unsigned int new_value;
823 	int changed;
824 	int error = sysctl_io_number(req, if_attach_nx, sizeof(if_attach_nx),
825 	    &new_value, &changed);
826 	if (error) {
827 		return error;
828 	}
829 	if (changed) {
830 		if ((new_value & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT) !=
831 		    (if_attach_nx & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT)) {
832 			return ENOTSUP;
833 		}
834 		if_attach_nx = new_value;
835 	}
836 	return 0;
837 }
838 
839 #endif /* DEVELOPMENT || DEBUG */
840 
841 static int
842 if_enable_fsw_transport_netagent_sysctl SYSCTL_HANDLER_ARGS
843 {
844 #pragma unused(oidp, arg1, arg2)
845 	unsigned int new_value;
846 	int changed;
847 	int error;
848 
849 	error = sysctl_io_number(req, if_enable_fsw_transport_netagent,
850 	    sizeof(if_enable_fsw_transport_netagent),
851 	    &new_value, &changed);
852 	if (error == 0 && changed != 0) {
853 		if (new_value != 0 && new_value != 1) {
854 			/* only allow 0 or 1 */
855 			error = EINVAL;
856 		} else if ((if_attach_nx & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT) != 0) {
857 			/* netagent can be enabled/disabled */
858 			if_enable_fsw_transport_netagent = new_value;
859 			if (new_value == 0) {
860 				kern_nexus_deregister_netagents();
861 			} else {
862 				kern_nexus_register_netagents();
863 			}
864 		} else {
865 			/* netagent can't be enabled */
866 			error = ENOTSUP;
867 		}
868 	}
869 	return error;
870 }
871