2 * Copyright (c) 2011-2017 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>
41 #include <net/if_var.h>
42 #include <net/if_dl.h>
43 #include <net/if_types.h>
44 #include <net/net_osdep.h>
45 #include <net/pktsched/pktsched.h>
46 #include <net/pktsched/pktsched_tcq.h>
47 #include <net/pktsched/pktsched_qfq.h>
48 #include <net/pktsched/pktsched_fq_codel.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
; /* 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__
);
81 * Initialize machclk_freq using the timerbase frequency
82 * value from device specific info.
84 machclk_freq
= gPEClockFrequencyInfo
.timebase_frequency_hz
;
86 clock_interval_to_absolutetime_interval(1, NSEC_PER_SEC
,
91 pktsched_abs_to_nsecs(u_int64_t abstime
)
95 absolutetime_to_nanoseconds(abstime
, &nsecs
);
100 pktsched_nsecs_to_abstime(u_int64_t nsecs
)
104 nanoseconds_to_absolutetime(nsecs
, &abstime
);
109 pktsched_setup(struct ifclassq
*ifq
, u_int32_t scheduler
, u_int32_t sflags
,
110 classq_pkt_type_t ptype
)
115 IFCQ_LOCK_ASSERT_HELD(ifq
);
117 VERIFY(machclk_freq
!= 0);
119 /* Nothing to do unless the scheduler type changes */
120 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 (void) pktsched_teardown(ifq
);
132 /* Teardown should have succeeded */
133 VERIFY(ifq
->ifcq_type
== PKTSCHEDT_NONE
);
134 VERIFY(ifq
->ifcq_disc
== NULL
);
135 VERIFY(ifq
->ifcq_enqueue
== NULL
);
136 VERIFY(ifq
->ifcq_dequeue
== NULL
);
137 VERIFY(ifq
->ifcq_dequeue_sc
== NULL
);
138 VERIFY(ifq
->ifcq_request
== NULL
);
143 error
= tcq_setup_ifclassq(ifq
, sflags
, ptype
);
147 error
= qfq_setup_ifclassq(ifq
, sflags
, ptype
);
149 case PKTSCHEDT_FQ_CODEL
:
150 error
= fq_if_setup_ifclassq(ifq
, sflags
, ptype
);
158 ifq
->ifcq_flags
|= rflags
;
164 pktsched_teardown(struct ifclassq
*ifq
)
168 IFCQ_LOCK_ASSERT_HELD(ifq
);
170 if_qflush(ifq
->ifcq_ifp
, 1);
171 VERIFY(IFCQ_IS_EMPTY(ifq
));
173 ifq
->ifcq_flags
&= ~IFCQF_ENABLED
;
175 switch (ifq
->ifcq_type
) {
180 error
= tcq_teardown_ifclassq(ifq
);
184 error
= qfq_teardown_ifclassq(ifq
);
187 case PKTSCHEDT_FQ_CODEL
:
188 error
= fq_if_teardown_ifclassq(ifq
);
198 pktsched_getqstats(struct ifclassq
*ifq
, u_int32_t qid
,
199 struct if_ifclassq_stats
*ifqs
)
203 IFCQ_LOCK_ASSERT_HELD(ifq
);
205 switch (ifq
->ifcq_type
) {
207 error
= tcq_getqstats_ifclassq(ifq
, qid
, ifqs
);
211 error
= qfq_getqstats_ifclassq(ifq
, qid
, ifqs
);
214 case PKTSCHEDT_FQ_CODEL
:
215 error
= fq_if_getqstats_ifclassq(ifq
, qid
, ifqs
);
226 pktsched_pkt_encap(pktsched_pkt_t
*pkt
, classq_pkt_type_t ptype
, void *pp
)
228 pkt
->pktsched_ptype
= ptype
;
229 pkt
->pktsched_pkt
= pp
;
234 (uint32_t)m_pktlen((struct mbuf
*)pkt
->pktsched_pkt
);
245 pktsched_free_pkt(pktsched_pkt_t
*pkt
)
247 switch (pkt
->pktsched_ptype
) {
249 m_freem(pkt
->pktsched_pkt
);
258 pkt
->pktsched_pkt
= NULL
;
259 pkt
->pktsched_plen
= 0;
260 pkt
->pktsched_ptype
= 0;
264 pktsched_get_pkt_len(pktsched_pkt_t
*pkt
)
266 return (pkt
->pktsched_plen
);
270 pktsched_get_pkt_svc(pktsched_pkt_t
*pkt
)
272 mbuf_svc_class_t svc
= MBUF_SC_UNSPEC
;
274 switch (pkt
->pktsched_ptype
) {
276 svc
= m_get_service_class((mbuf_t
)pkt
->pktsched_pkt
);
289 pktsched_get_pkt_vars(pktsched_pkt_t
*pkt
, uint32_t **flags
,
290 uint64_t **timestamp
, uint32_t *flowid
, uint8_t *flowsrc
, uint8_t *proto
,
291 uint32_t *tcp_start_seq
)
293 switch (pkt
->pktsched_ptype
) {
295 struct mbuf
*m
= (struct mbuf
*)pkt
->pktsched_pkt
;
296 struct pkthdr
*pkth
= &m
->m_pkthdr
;
299 *flags
= &pkth
->pkt_flags
;
300 if (timestamp
!= NULL
)
301 *timestamp
= &pkth
->pkt_timestamp
;
303 *flowid
= pkth
->pkt_flowid
;
305 *flowsrc
= pkth
->pkt_flowsrc
;
307 *proto
= pkth
->pkt_proto
;
309 * caller should use this value only if PKTF_START_SEQ
310 * is set in the mbuf packet flags
312 if (tcp_start_seq
!= NULL
)
313 *tcp_start_seq
= pkth
->tx_start_seq
;
325 struct flowadv_fcentry
*
326 pktsched_alloc_fcentry(pktsched_pkt_t
*pkt
, struct ifnet
*ifp
, int how
)
329 struct flowadv_fcentry
*fce
= NULL
;
331 switch (pkt
->pktsched_ptype
) {
333 struct mbuf
*m
= (struct mbuf
*)pkt
->pktsched_pkt
;
335 fce
= flowadv_alloc_entry(how
);
339 _CASSERT(sizeof (m
->m_pkthdr
.pkt_flowid
) ==
340 sizeof (fce
->fce_flowid
));
342 fce
->fce_flowsrc_type
= m
->m_pkthdr
.pkt_flowsrc
;
343 fce
->fce_flowid
= m
->m_pkthdr
.pkt_flowid
;
357 pktsched_get_pkt_sfb_vars(pktsched_pkt_t
*pkt
, uint32_t **sfb_flags
)
359 uint32_t *hashp
= NULL
;
361 switch (pkt
->pktsched_ptype
) {
363 struct mbuf
*m
= (struct mbuf
*)pkt
->pktsched_pkt
;
364 struct pkthdr
*pkth
= &m
->m_pkthdr
;
366 _CASSERT(sizeof (pkth
->pkt_mpriv_hash
) == sizeof (uint32_t));
367 _CASSERT(sizeof (pkth
->pkt_mpriv_flags
) == sizeof (uint32_t));
369 *sfb_flags
= &pkth
->pkt_mpriv_flags
;
370 hashp
= &pkth
->pkt_mpriv_hash
;