]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/pktsched/pktsched.c
xnu-3789.60.24.tar.gz
[apple/xnu.git] / bsd / net / pktsched / pktsched.c
1 /*
2 * Copyright (c) 2011 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 #include <sys/cdefs.h>
30
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/mbuf.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>
39
40 #include <net/if.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>
49 #if PKTSCHED_PRIQ
50 #include <net/pktsched/pktsched_priq.h>
51 #endif /* PKTSCHED_PRIQ */
52 #if PKTSCHED_FAIRQ
53 #include <net/pktsched/pktsched_fairq.h>
54 #endif /* PKTSCHED_FAIRQ */
55 #if PKTSCHED_CBQ
56 #include <net/pktsched/pktsched_cbq.h>
57 #endif /* PKTSCHED_CBQ */
58 #if PKTSCHED_HFSC
59 #include <net/pktsched/pktsched_hfsc.h>
60 #endif /* PKTSCHED_HFSC */
61
62 #include <pexpert/pexpert.h>
63
64 u_int32_t machclk_freq = 0;
65 u_int64_t machclk_per_sec = 0;
66 u_int32_t pktsched_verbose; /* more noise if greater than 1 */
67
68 static void init_machclk(void);
69
70 SYSCTL_NODE(_net, OID_AUTO, pktsched, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "pktsched");
71
72 SYSCTL_UINT(_net_pktsched, OID_AUTO, verbose, CTLFLAG_RW|CTLFLAG_LOCKED,
73 &pktsched_verbose, 0, "Packet scheduler verbosity level");
74
75 void
76 pktsched_init(void)
77 {
78 init_machclk();
79 if (machclk_freq == 0) {
80 panic("%s: no CPU clock available!\n", __func__);
81 /* NOTREACHED */
82 }
83
84 tcq_init();
85 qfq_init();
86 #if PKTSCHED_PRIQ
87 priq_init();
88 #endif /* PKTSCHED_PRIQ */
89 #if PKTSCHED_FAIRQ
90 fairq_init();
91 #endif /* PKTSCHED_FAIRQ */
92 #if PKTSCHED_CBQ
93 cbq_init();
94 #endif /* PKTSCHED_CBQ */
95 #if PKTSCHED_HFSC
96 hfsc_init();
97 #endif /* PKTSCHED_HFSC */
98 }
99
100 static void
101 init_machclk(void)
102 {
103 /*
104 * Initialize machclk_freq using the timerbase frequency
105 * value from device specific info.
106 */
107 machclk_freq = gPEClockFrequencyInfo.timebase_frequency_hz;
108
109 clock_interval_to_absolutetime_interval(1, NSEC_PER_SEC,
110 &machclk_per_sec);
111 }
112
113 u_int64_t
114 pktsched_abs_to_nsecs(u_int64_t abstime)
115 {
116 u_int64_t nsecs;
117
118 absolutetime_to_nanoseconds(abstime, &nsecs);
119 return (nsecs);
120 }
121
122 u_int64_t
123 pktsched_nsecs_to_abstime(u_int64_t nsecs)
124 {
125 u_int64_t abstime;
126
127 nanoseconds_to_absolutetime(nsecs, &abstime);
128 return (abstime);
129 }
130
131 int
132 pktsched_setup(struct ifclassq *ifq, u_int32_t scheduler, u_int32_t sflags)
133 {
134 int error = 0;
135 u_int32_t qflags = sflags;
136 u_int32_t rflags;
137
138 IFCQ_LOCK_ASSERT_HELD(ifq);
139
140 VERIFY(machclk_freq != 0);
141
142 /* Nothing to do unless the scheduler type changes */
143 if (ifq->ifcq_type == scheduler)
144 return (0);
145
146 qflags &= (PKTSCHEDF_QALG_RED | PKTSCHEDF_QALG_RIO |
147 PKTSCHEDF_QALG_BLUE | PKTSCHEDF_QALG_SFB);
148
149 /* These are mutually exclusive */
150 if (qflags != 0 &&
151 qflags != PKTSCHEDF_QALG_RED && qflags != PKTSCHEDF_QALG_RIO &&
152 qflags != PKTSCHEDF_QALG_BLUE && qflags != PKTSCHEDF_QALG_SFB) {
153 panic("%s: RED|RIO|BLUE|SFB mutually exclusive\n", __func__);
154 /* NOTREACHED */
155 }
156
157 /*
158 * Remember the flags that need to be restored upon success, as
159 * they may be cleared when we tear down existing scheduler.
160 */
161 rflags = (ifq->ifcq_flags & IFCQF_ENABLED);
162
163 if (ifq->ifcq_type != PKTSCHEDT_NONE) {
164 (void) pktsched_teardown(ifq);
165
166 /* Teardown should have succeeded */
167 VERIFY(ifq->ifcq_type == PKTSCHEDT_NONE);
168 VERIFY(ifq->ifcq_disc == NULL);
169 VERIFY(ifq->ifcq_enqueue == NULL);
170 VERIFY(ifq->ifcq_dequeue == NULL);
171 VERIFY(ifq->ifcq_dequeue_sc == NULL);
172 VERIFY(ifq->ifcq_request == NULL);
173 }
174
175 switch (scheduler) {
176 #if PKTSCHED_PRIQ
177 case PKTSCHEDT_PRIQ:
178 error = priq_setup_ifclassq(ifq, sflags);
179 break;
180 #endif /* PKTSCHED_PRIQ */
181
182 case PKTSCHEDT_TCQ:
183 error = tcq_setup_ifclassq(ifq, sflags);
184 break;
185
186 case PKTSCHEDT_QFQ:
187 error = qfq_setup_ifclassq(ifq, sflags);
188 break;
189 case PKTSCHEDT_FQ_CODEL:
190 error = fq_if_setup_ifclassq(ifq, sflags);
191 break;
192 default:
193 error = ENXIO;
194 break;
195 }
196
197 if (error == 0)
198 ifq->ifcq_flags |= rflags;
199
200 return (error);
201 }
202
203 int
204 pktsched_teardown(struct ifclassq *ifq)
205 {
206 int error = 0;
207
208 IFCQ_LOCK_ASSERT_HELD(ifq);
209
210 if_qflush(ifq->ifcq_ifp, 1);
211 VERIFY(IFCQ_IS_EMPTY(ifq));
212
213 ifq->ifcq_flags &= ~IFCQF_ENABLED;
214
215 switch (ifq->ifcq_type) {
216 case PKTSCHEDT_NONE:
217 break;
218
219 #if PKTSCHED_PRIQ
220 case PKTSCHEDT_PRIQ:
221 error = priq_teardown_ifclassq(ifq);
222 break;
223 #endif /* PKTSCHED_PRIQ */
224
225 case PKTSCHEDT_TCQ:
226 error = tcq_teardown_ifclassq(ifq);
227 break;
228
229 case PKTSCHEDT_QFQ:
230 error = qfq_teardown_ifclassq(ifq);
231 break;
232
233 case PKTSCHEDT_FQ_CODEL:
234 error = fq_if_teardown_ifclassq(ifq);
235 break;
236 default:
237 error = ENXIO;
238 break;
239 }
240 return (error);
241 }
242
243 int
244 pktsched_getqstats(struct ifclassq *ifq, u_int32_t qid,
245 struct if_ifclassq_stats *ifqs)
246 {
247 int error;
248
249 IFCQ_LOCK_ASSERT_HELD(ifq);
250
251 switch (ifq->ifcq_type) {
252 #if PKTSCHED_PRIQ
253 case PKTSCHEDT_PRIQ:
254 error = priq_getqstats_ifclassq(ifq, qid, ifqs);
255 break;
256 #endif /* PKTSCHED_PRIQ */
257
258 case PKTSCHEDT_TCQ:
259 error = tcq_getqstats_ifclassq(ifq, qid, ifqs);
260 break;
261
262 case PKTSCHEDT_QFQ:
263 error = qfq_getqstats_ifclassq(ifq, qid, ifqs);
264 break;
265
266 case PKTSCHEDT_FQ_CODEL:
267 error = fq_if_getqstats_ifclassq(ifq, qid, ifqs);
268 break;
269 default:
270 error = ENXIO;
271 break;
272 }
273
274 return (error);
275 }