xref: /xnu-12377.41.6/bsd/net/dlil_sysctl.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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 #define DEFAULT_IF_LINK_HEURISTIC \
375     (IF_LINK_HEURISTICS_CELLULAR | IF_LINK_HEURISTICS_LINK_CONGESTED)
376 uint32_t if_link_heuristics_flags = DEFAULT_IF_LINK_HEURISTIC;
377 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, link_heuristics_flags,
378     CTLFLAG_RW | CTLFLAG_LOCKED, &if_link_heuristics_flags, DEFAULT_IF_LINK_HEURISTIC, "");
379 
380 int if_link_heuristics_lqm_max = 0;
381 SYSCTL_INT(_net_link_generic_system, OID_AUTO, link_heuristics_lqm_max,
382     CTLFLAG_RW | CTLFLAG_LOCKED, &if_link_heuristics_lqm_max, 0, "Max value to enable link heuristics");
383 
384 uint32_t if_link_heuristics_delay = IF_LINK_HEURISTICS_DELAY_MSECS;
385 SYSCTL_UINT(_net_link_generic_system, OID_AUTO, link_heuristics_delay,
386     CTLFLAG_RW | CTLFLAG_LOCKED, &if_link_heuristics_delay, IF_LINK_HEURISTICS_DELAY_MSECS, "");
387 
388 
389 #if TEST_INPUT_THREAD_TERMINATION
390 static int
391 sysctl_input_thread_termination_spin SYSCTL_HANDLER_ARGS
392 {
393 #pragma unused(arg1, arg2)
394 	uint32_t i;
395 	int err;
396 
397 	i = if_input_thread_termination_spin;
398 
399 	err = sysctl_handle_int(oidp, &i, 0, req);
400 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
401 		return err;
402 	}
403 
404 	if (net_rxpoll == 0) {
405 		return ENXIO;
406 	}
407 
408 	if_input_thread_termination_spin = i;
409 	return err;
410 }
411 #endif /* TEST_INPUT_THREAD_TERMINATION */
412 
413 static int
414 sysctl_rxpoll SYSCTL_HANDLER_ARGS
415 {
416 #pragma unused(arg1, arg2)
417 	uint32_t i;
418 	int err;
419 
420 	i = if_rxpoll;
421 
422 	err = sysctl_handle_int(oidp, &i, 0, req);
423 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
424 		return err;
425 	}
426 
427 	if (net_rxpoll == 0) {
428 		return ENXIO;
429 	}
430 
431 	if_rxpoll = i;
432 	return err;
433 }
434 
435 static int
436 sysctl_rxpoll_mode_holdtime SYSCTL_HANDLER_ARGS
437 {
438 #pragma unused(arg1, arg2)
439 	uint64_t q;
440 	int err;
441 
442 	q = if_rxpoll_mode_holdtime;
443 
444 	err = sysctl_handle_quad(oidp, &q, 0, req);
445 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
446 		return err;
447 	}
448 
449 	if (q < IF_RXPOLL_MODE_HOLDTIME_MIN) {
450 		q = IF_RXPOLL_MODE_HOLDTIME_MIN;
451 	}
452 
453 	if_rxpoll_mode_holdtime = q;
454 
455 	return err;
456 }
457 
458 static int
459 sysctl_rxpoll_sample_holdtime SYSCTL_HANDLER_ARGS
460 {
461 #pragma unused(arg1, arg2)
462 	uint64_t q;
463 	int err;
464 
465 	q = if_rxpoll_sample_holdtime;
466 
467 	err = sysctl_handle_quad(oidp, &q, 0, req);
468 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
469 		return err;
470 	}
471 
472 	if (q < IF_RXPOLL_SAMPLETIME_MIN) {
473 		q = IF_RXPOLL_SAMPLETIME_MIN;
474 	}
475 
476 	if_rxpoll_sample_holdtime = q;
477 
478 	return err;
479 }
480 
481 static int
482 sysctl_rxpoll_interval_time SYSCTL_HANDLER_ARGS
483 {
484 #pragma unused(arg1, arg2)
485 	uint64_t q;
486 	int err;
487 
488 	q = if_rxpoll_interval_time;
489 
490 	err = sysctl_handle_quad(oidp, &q, 0, req);
491 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
492 		return err;
493 	}
494 
495 	if (q < IF_RXPOLL_INTERVALTIME_MIN) {
496 		q = IF_RXPOLL_INTERVALTIME_MIN;
497 	}
498 
499 	if_rxpoll_interval_time = q;
500 
501 	return err;
502 }
503 
504 static int
505 sysctl_rxpoll_wlowat SYSCTL_HANDLER_ARGS
506 {
507 #pragma unused(arg1, arg2)
508 	uint32_t i;
509 	int err;
510 
511 	i = if_sysctl_rxpoll_wlowat;
512 
513 	err = sysctl_handle_int(oidp, &i, 0, req);
514 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
515 		return err;
516 	}
517 
518 	if (i == 0 || i >= if_sysctl_rxpoll_whiwat) {
519 		return EINVAL;
520 	}
521 
522 	if_sysctl_rxpoll_wlowat = i;
523 	return err;
524 }
525 
526 static int
527 sysctl_rxpoll_whiwat SYSCTL_HANDLER_ARGS
528 {
529 #pragma unused(arg1, arg2)
530 	uint32_t i;
531 	int err;
532 
533 	i = if_sysctl_rxpoll_whiwat;
534 
535 	err = sysctl_handle_int(oidp, &i, 0, req);
536 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
537 		return err;
538 	}
539 
540 	if (i <= if_sysctl_rxpoll_wlowat) {
541 		return EINVAL;
542 	}
543 
544 	if_sysctl_rxpoll_whiwat = i;
545 	return err;
546 }
547 
548 static int
549 sysctl_sndq_maxlen SYSCTL_HANDLER_ARGS
550 {
551 #pragma unused(arg1, arg2)
552 	int i, err;
553 
554 	i = if_sndq_maxlen;
555 
556 	err = sysctl_handle_int(oidp, &i, 0, req);
557 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
558 		return err;
559 	}
560 
561 	if (i < IF_SNDQ_MINLEN) {
562 		i = IF_SNDQ_MINLEN;
563 	}
564 
565 	if_sndq_maxlen = i;
566 	return err;
567 }
568 
569 static int
570 sysctl_rcvq_maxlen SYSCTL_HANDLER_ARGS
571 {
572 #pragma unused(arg1, arg2)
573 	int i, err;
574 
575 	i = if_rcvq_maxlen;
576 
577 	err = sysctl_handle_int(oidp, &i, 0, req);
578 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
579 		return err;
580 	}
581 
582 	if (i < IF_RCVQ_MINLEN) {
583 		i = IF_RCVQ_MINLEN;
584 	}
585 
586 	if_rcvq_maxlen = i;
587 	return err;
588 }
589 
590 static int
591 sysctl_rcvq_burst_limit SYSCTL_HANDLER_ARGS
592 {
593 #pragma unused(arg1, arg2)
594 	int i, err;
595 
596 	i = if_rcvq_burst_limit;
597 
598 	err = sysctl_handle_int(oidp, &i, 0, req);
599 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
600 		return err;
601 	}
602 
603 /*
604  * Safeguard the burst limit to "sane" values on customer builds.
605  */
606 #if !(DEVELOPMENT || DEBUG)
607 	if (i < IF_RCVQ_BURST_LIMIT_MIN) {
608 		i = IF_RCVQ_BURST_LIMIT_MIN;
609 	}
610 
611 	if (IF_RCVQ_BURST_LIMIT_MAX < i) {
612 		i = IF_RCVQ_BURST_LIMIT_MAX;
613 	}
614 #endif
615 
616 	if_rcvq_burst_limit = i;
617 	return err;
618 }
619 
620 static int
621 sysctl_rcvq_trim_pct SYSCTL_HANDLER_ARGS
622 {
623 #pragma unused(arg1, arg2)
624 	int i, err;
625 
626 	i = if_rcvq_burst_limit;
627 
628 	err = sysctl_handle_int(oidp, &i, 0, req);
629 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
630 		return err;
631 	}
632 
633 	if (IF_RCVQ_TRIM_PCT_MAX < i) {
634 		i = IF_RCVQ_TRIM_PCT_MAX;
635 	}
636 
637 	if (i < IF_RCVQ_TRIM_PCT_MIN) {
638 		i = IF_RCVQ_TRIM_PCT_MIN;
639 	}
640 
641 	if_rcvq_trim_pct = i;
642 	return err;
643 }
644 
645 static int
646 sysctl_hwcksum_dbg_mode SYSCTL_HANDLER_ARGS
647 {
648 #pragma unused(arg1, arg2)
649 	uint32_t i;
650 	int err;
651 
652 	i = hwcksum_dbg_mode;
653 
654 	err = sysctl_handle_int(oidp, &i, 0, req);
655 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
656 		return err;
657 	}
658 
659 	if (hwcksum_dbg == 0) {
660 		return ENODEV;
661 	}
662 
663 	if ((i & ~HWCKSUM_DBG_MASK) != 0) {
664 		return EINVAL;
665 	}
666 
667 	hwcksum_dbg_mode = (i & HWCKSUM_DBG_MASK);
668 
669 	return err;
670 }
671 
672 static int
673 sysctl_hwcksum_dbg_partial_rxoff_forced SYSCTL_HANDLER_ARGS
674 {
675 #pragma unused(arg1, arg2)
676 	u_int32_t i;
677 	int err;
678 
679 	i = hwcksum_dbg_partial_rxoff_forced;
680 
681 	err = sysctl_handle_int(oidp, &i, 0, req);
682 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
683 		return err;
684 	}
685 
686 	if (!(hwcksum_dbg_mode & HWCKSUM_DBG_PARTIAL_FORCED)) {
687 		return ENODEV;
688 	}
689 
690 	hwcksum_dbg_partial_rxoff_forced = i;
691 
692 	return err;
693 }
694 
695 static int
696 sysctl_hwcksum_dbg_partial_rxoff_adj SYSCTL_HANDLER_ARGS
697 {
698 #pragma unused(arg1, arg2)
699 	u_int32_t i;
700 	int err;
701 
702 	i = hwcksum_dbg_partial_rxoff_adj;
703 
704 	err = sysctl_handle_int(oidp, &i, 0, req);
705 	if (err != 0 || req->newptr == USER_ADDR_NULL) {
706 		return err;
707 	}
708 
709 	if (!(hwcksum_dbg_mode & HWCKSUM_DBG_PARTIAL_RXOFF_ADJ)) {
710 		return ENODEV;
711 	}
712 
713 	hwcksum_dbg_partial_rxoff_adj = i;
714 
715 	return err;
716 }
717 
718 static int
719 sysctl_tx_chain_len_stats SYSCTL_HANDLER_ARGS
720 {
721 #pragma unused(oidp, arg1, arg2)
722 	int err;
723 
724 	if (req->oldptr == USER_ADDR_NULL) {
725 	}
726 	if (req->newptr != USER_ADDR_NULL) {
727 		return EPERM;
728 	}
729 	err = SYSCTL_OUT(req, &tx_chain_len_stats,
730 	    sizeof(struct chain_len_stats));
731 
732 	return err;
733 }
734 
735 #if (DEVELOPMENT || DEBUG)
736 /*
737  * The sysctl variable name contains the input parameters of
738  * ifnet_get_keepalive_offload_frames()
739  *  ifp (interface index): name[0]
740  *  frames_array_count:    name[1]
741  *  frame_data_offset:     name[2]
742  * The return length gives used_frames_count
743  */
744 static int
745 sysctl_get_kao_frames SYSCTL_HANDLER_ARGS
746 {
747 #pragma unused(oidp)
748 	DECLARE_SYSCTL_HANDLER_ARG_ARRAY(int, 3, name, namelen);
749 	int idx;
750 	ifnet_t ifp = NULL;
751 	u_int32_t frames_array_count;
752 	size_t frame_data_offset;
753 	u_int32_t used_frames_count;
754 	struct ifnet_keepalive_offload_frame *frames_array = NULL;
755 	int error = 0;
756 	u_int32_t i;
757 
758 	/*
759 	 * Only root can get look at other people TCP frames
760 	 */
761 	error = proc_suser(current_proc());
762 	if (error != 0) {
763 		goto done;
764 	}
765 	/*
766 	 * Validate the input parameters
767 	 */
768 	if (req->newptr != USER_ADDR_NULL) {
769 		error = EPERM;
770 		goto done;
771 	}
772 	if (req->oldptr == USER_ADDR_NULL) {
773 		error = EINVAL;
774 		goto done;
775 	}
776 	if (req->oldlen == 0) {
777 		error = EINVAL;
778 		goto done;
779 	}
780 	idx = name[0];
781 	frames_array_count = name[1];
782 	frame_data_offset = name[2];
783 
784 	/* Make sure the passed buffer is large enough */
785 	if (frames_array_count * sizeof(struct ifnet_keepalive_offload_frame) >
786 	    req->oldlen) {
787 		error = ENOMEM;
788 		goto done;
789 	}
790 
791 	ifnet_head_lock_shared();
792 	if (!IF_INDEX_IN_RANGE(idx)) {
793 		ifnet_head_done();
794 		error = ENOENT;
795 		goto done;
796 	}
797 	ifp = ifindex2ifnet[idx];
798 	ifnet_head_done();
799 
800 	frames_array = (struct ifnet_keepalive_offload_frame *)kalloc_data(
801 		frames_array_count * sizeof(struct ifnet_keepalive_offload_frame),
802 		Z_WAITOK);
803 	if (frames_array == NULL) {
804 		error = ENOMEM;
805 		goto done;
806 	}
807 
808 	error = ifnet_get_keepalive_offload_frames(ifp, frames_array,
809 	    frames_array_count, frame_data_offset, &used_frames_count);
810 	if (error != 0) {
811 		DLIL_PRINTF("%s: ifnet_get_keepalive_offload_frames error %d\n",
812 		    __func__, error);
813 		goto done;
814 	}
815 
816 	for (i = 0; i < used_frames_count; i++) {
817 		error = SYSCTL_OUT(req, frames_array + i,
818 		    sizeof(struct ifnet_keepalive_offload_frame));
819 		if (error != 0) {
820 			goto done;
821 		}
822 	}
823 done:
824 	if (frames_array != NULL) {
825 		kfree_data(frames_array, frames_array_count *
826 		    sizeof(struct ifnet_keepalive_offload_frame));
827 	}
828 	return error;
829 }
830 
831 static int
832 if_attach_nx_sysctl SYSCTL_HANDLER_ARGS
833 {
834 #pragma unused(oidp, arg1, arg2)
835 	unsigned int new_value;
836 	int changed;
837 	int error = sysctl_io_number(req, if_attach_nx, sizeof(if_attach_nx),
838 	    &new_value, &changed);
839 	if (error) {
840 		return error;
841 	}
842 	if (changed) {
843 		if ((new_value & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT) !=
844 		    (if_attach_nx & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT)) {
845 			return ENOTSUP;
846 		}
847 		if_attach_nx = new_value;
848 	}
849 	return 0;
850 }
851 
852 #endif /* DEVELOPMENT || DEBUG */
853 
854 static int
855 if_enable_fsw_transport_netagent_sysctl SYSCTL_HANDLER_ARGS
856 {
857 #pragma unused(oidp, arg1, arg2)
858 	unsigned int new_value;
859 	int changed;
860 	int error;
861 
862 	error = sysctl_io_number(req, if_enable_fsw_transport_netagent,
863 	    sizeof(if_enable_fsw_transport_netagent),
864 	    &new_value, &changed);
865 	if (error == 0 && changed != 0) {
866 		if (new_value != 0 && new_value != 1) {
867 			/* only allow 0 or 1 */
868 			error = EINVAL;
869 		} else if ((if_attach_nx & IF_ATTACH_NX_FSW_TRANSPORT_NETAGENT) != 0) {
870 			/* netagent can be enabled/disabled */
871 			if_enable_fsw_transport_netagent = new_value;
872 			if (new_value == 0) {
873 				kern_nexus_deregister_netagents();
874 			} else {
875 				kern_nexus_register_netagents();
876 			}
877 		} else {
878 			/* netagent can't be enabled */
879 			error = ENOTSUP;
880 		}
881 	}
882 	return error;
883 }
884