2 * Copyright (c) 2011-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/cdefs.h>
31 #include <sys/param.h>
32 #include <sys/malloc.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/errno.h>
37 #include <sys/mcache.h>
38 #include <sys/sysctl.h>
40 #include <dev/random/randomdev.h>
42 #include <net/if_var.h>
43 #include <net/if_dl.h>
44 #include <net/if_types.h>
45 #include <net/net_osdep.h>
46 #include <net/pktsched/pktsched.h>
47 #include <net/pktsched/pktsched_fq_codel.h>
48 #include <net/pktsched/pktsched_netem.h>
50 #include <pexpert/pexpert.h>
53 u_int32_t machclk_freq
= 0;
54 u_int64_t machclk_per_sec
= 0;
55 u_int32_t pktsched_verbose
= 0; /* more noise if greater than 1 */
57 static void init_machclk(void);
59 SYSCTL_NODE(_net
, OID_AUTO
, pktsched
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "pktsched");
61 SYSCTL_UINT(_net_pktsched
, OID_AUTO
, verbose
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
62 &pktsched_verbose
, 0, "Packet scheduler verbosity level");
68 if (machclk_freq
== 0) {
69 panic("%s: no CPU clock available!\n", __func__
);
80 * Initialize machclk_freq using the timerbase frequency
81 * value from device specific info.
83 machclk_freq
= (uint32_t)gPEClockFrequencyInfo
.timebase_frequency_hz
;
85 clock_interval_to_absolutetime_interval(1, NSEC_PER_SEC
,
90 pktsched_abs_to_nsecs(u_int64_t abstime
)
94 absolutetime_to_nanoseconds(abstime
, &nsecs
);
99 pktsched_nsecs_to_abstime(u_int64_t nsecs
)
103 nanoseconds_to_absolutetime(nsecs
, &abstime
);
108 pktsched_setup(struct ifclassq
*ifq
, u_int32_t scheduler
, u_int32_t sflags
,
109 classq_pkt_type_t ptype
)
114 IFCQ_LOCK_ASSERT_HELD(ifq
);
116 VERIFY(machclk_freq
!= 0);
118 /* Nothing to do unless the scheduler type changes */
119 if (ifq
->ifcq_type
== scheduler
) {
124 * Remember the flags that need to be restored upon success, as
125 * they may be cleared when we tear down existing scheduler.
127 rflags
= (ifq
->ifcq_flags
& IFCQF_ENABLED
);
129 if (ifq
->ifcq_type
!= PKTSCHEDT_NONE
) {
130 pktsched_teardown(ifq
);
132 /* Teardown should have succeeded */
133 VERIFY(ifq
->ifcq_type
== PKTSCHEDT_NONE
);
134 VERIFY(ifq
->ifcq_disc
== NULL
);
137 error
= fq_if_setup_ifclassq(ifq
, sflags
, ptype
);
139 ifq
->ifcq_flags
|= rflags
;
146 pktsched_teardown(struct ifclassq
*ifq
)
148 IFCQ_LOCK_ASSERT_HELD(ifq
);
150 if_qflush(ifq
->ifcq_ifp
, 1);
151 VERIFY(IFCQ_IS_EMPTY(ifq
));
153 ifq
->ifcq_flags
&= ~IFCQF_ENABLED
;
155 if (ifq
->ifcq_type
== PKTSCHEDT_FQ_CODEL
) {
156 /* Could be PKTSCHEDT_NONE */
157 fq_if_teardown_ifclassq(ifq
);
164 pktsched_getqstats(struct ifclassq
*ifq
, u_int32_t qid
,
165 struct if_ifclassq_stats
*ifqs
)
169 IFCQ_LOCK_ASSERT_HELD(ifq
);
171 if (ifq
->ifcq_type
== PKTSCHEDT_FQ_CODEL
) {
172 /* Could be PKTSCHEDT_NONE */
173 error
= fq_if_getqstats_ifclassq(ifq
, qid
, ifqs
);
180 pktsched_pkt_encap(pktsched_pkt_t
*pkt
, classq_pkt_t
*cpkt
)
182 pkt
->pktsched_pkt
= *cpkt
;
183 pkt
->pktsched_tail
= *cpkt
;
184 pkt
->pktsched_pcnt
= 1;
186 switch (cpkt
->cp_ptype
) {
189 (uint32_t)m_pktlen(pkt
->pktsched_pkt_mbuf
);
196 __builtin_unreachable();
201 pktsched_pkt_encap_chain(pktsched_pkt_t
*pkt
, classq_pkt_t
*cpkt
,
202 classq_pkt_t
*tail
, uint32_t cnt
, uint32_t bytes
)
204 pkt
->pktsched_pkt
= *cpkt
;
205 pkt
->pktsched_tail
= *tail
;
206 pkt
->pktsched_pcnt
= cnt
;
207 pkt
->pktsched_plen
= bytes
;
209 switch (cpkt
->cp_ptype
) {
217 __builtin_unreachable();
222 pktsched_clone_pkt(pktsched_pkt_t
*pkt1
, pktsched_pkt_t
*pkt2
)
224 struct mbuf
*m1
, *m2
;
226 ASSERT(pkt1
!= NULL
);
227 ASSERT(pkt1
->pktsched_pkt_mbuf
!= NULL
);
228 ASSERT(pkt1
->pktsched_pcnt
== 1);
230 /* allow in place clone, but make sure pkt2->pktsched_pkt won't leak */
231 ASSERT((pkt1
== pkt2
&& pkt1
->pktsched_pkt_mbuf
==
232 pkt2
->pktsched_pkt_mbuf
) || (pkt1
!= pkt2
&&
233 pkt2
->pktsched_pkt_mbuf
== NULL
));
235 switch (pkt1
->pktsched_ptype
) {
237 m1
= (struct mbuf
*)pkt1
->pktsched_pkt_mbuf
;
238 m2
= m_dup(m1
, M_NOWAIT
);
239 if (__improbable(m2
== NULL
)) {
242 pkt2
->pktsched_pkt_mbuf
= m2
;
249 __builtin_unreachable();
252 pkt2
->pktsched_plen
= pkt1
->pktsched_plen
;
253 pkt2
->pktsched_ptype
= pkt1
->pktsched_ptype
;
254 pkt2
->pktsched_tail
= pkt2
->pktsched_pkt
;
255 pkt2
->pktsched_pcnt
= 1;
260 pktsched_corrupt_packet(pktsched_pkt_t
*pkt
)
262 struct mbuf
*m
= NULL
;
263 uint8_t *data
= NULL
;
264 uint32_t data_len
= 0;
265 uint32_t rand32
, rand_off
, rand_bit
;
267 switch (pkt
->pktsched_ptype
) {
269 m
= pkt
->pktsched_pkt_mbuf
;
270 data
= mtod(m
, uint8_t *);
271 data_len
= m
->m_pkthdr
.len
;
277 __builtin_unreachable();
280 read_frandom(&rand32
, sizeof(rand32
));
281 rand_bit
= rand32
& 0x8;
282 rand_off
= (rand32
>> 3) % data_len
;
283 data
[rand_off
] ^= 1 << rand_bit
;
287 pktsched_free_pkt(pktsched_pkt_t
*pkt
)
289 uint32_t cnt
= pkt
->pktsched_pcnt
;
292 switch (pkt
->pktsched_ptype
) {
296 m
= pkt
->pktsched_pkt_mbuf
;
298 VERIFY(m
->m_nextpkt
== NULL
);
300 VERIFY(m
->m_nextpkt
!= NULL
);
309 __builtin_unreachable();
311 pkt
->pktsched_pkt
= CLASSQ_PKT_INITIALIZER(pkt
->pktsched_pkt
);
312 pkt
->pktsched_tail
= CLASSQ_PKT_INITIALIZER(pkt
->pktsched_tail
);
313 pkt
->pktsched_plen
= 0;
314 pkt
->pktsched_pcnt
= 0;
318 pktsched_get_pkt_svc(pktsched_pkt_t
*pkt
)
320 mbuf_svc_class_t svc
= MBUF_SC_UNSPEC
;
322 switch (pkt
->pktsched_ptype
) {
324 svc
= m_get_service_class(pkt
->pktsched_pkt_mbuf
);
331 __builtin_unreachable();
338 pktsched_get_pkt_vars(pktsched_pkt_t
*pkt
, volatile uint32_t **flags
,
339 uint64_t **timestamp
, uint32_t *flowid
, uint8_t *flowsrc
, uint8_t *proto
,
340 uint32_t *comp_gencnt
)
342 switch (pkt
->pktsched_ptype
) {
344 struct pkthdr
*pkth
= &(pkt
->pktsched_pkt_mbuf
->m_pkthdr
);
347 *flags
= &pkth
->pkt_flags
;
349 if (timestamp
!= NULL
) {
350 *timestamp
= &pkth
->pkt_timestamp
;
352 if (flowid
!= NULL
) {
353 *flowid
= pkth
->pkt_flowid
;
355 if (flowsrc
!= NULL
) {
356 *flowsrc
= pkth
->pkt_flowsrc
;
359 *proto
= pkth
->pkt_proto
;
361 if (comp_gencnt
!= NULL
) {
362 *comp_gencnt
= pkth
->comp_gencnt
;
372 __builtin_unreachable();
376 struct flowadv_fcentry
*
377 pktsched_alloc_fcentry(pktsched_pkt_t
*pkt
, struct ifnet
*ifp
, int how
)
380 struct flowadv_fcentry
*fce
= NULL
;
382 switch (pkt
->pktsched_ptype
) {
384 struct mbuf
*m
= pkt
->pktsched_pkt_mbuf
;
386 fce
= flowadv_alloc_entry(how
);
391 _CASSERT(sizeof(m
->m_pkthdr
.pkt_flowid
) ==
392 sizeof(fce
->fce_flowid
));
394 fce
->fce_flowsrc_type
= m
->m_pkthdr
.pkt_flowsrc
;
395 fce
->fce_flowid
= m
->m_pkthdr
.pkt_flowid
;
403 __builtin_unreachable();
410 pktsched_get_pkt_sfb_vars(pktsched_pkt_t
*pkt
, uint32_t **sfb_flags
)
412 uint32_t *hashp
= NULL
;
414 switch (pkt
->pktsched_ptype
) {
416 struct pkthdr
*pkth
= &(pkt
->pktsched_pkt_mbuf
->m_pkthdr
);
418 _CASSERT(sizeof(pkth
->pkt_mpriv_hash
) == sizeof(uint32_t));
419 _CASSERT(sizeof(pkth
->pkt_mpriv_flags
) == sizeof(uint32_t));
420 *sfb_flags
= &pkth
->pkt_mpriv_flags
;
421 hashp
= &pkth
->pkt_mpriv_hash
;
429 __builtin_unreachable();