]>
Commit | Line | Data |
---|---|---|
316670eb A |
1 | /* |
2 | * Copyright (c) 2007-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 | /* $OpenBSD: altq_subr.c,v 1.24 2007/12/11 00:30:14 mikeb Exp $ */ | |
30 | /* $KAME: altq_subr.c,v 1.11 2002/01/11 08:11:49 kjc Exp $ */ | |
31 | ||
32 | /* | |
33 | * Copyright (C) 1997-2003 | |
34 | * Sony Computer Science Laboratories Inc. All rights reserved. | |
35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | |
39 | * 1. Redistributions of source code must retain the above copyright | |
40 | * notice, this list of conditions and the following disclaimer. | |
41 | * 2. Redistributions in binary form must reproduce the above copyright | |
42 | * notice, this list of conditions and the following disclaimer in the | |
43 | * documentation and/or other materials provided with the distribution. | |
44 | * | |
45 | * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND | |
46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
48 | * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE | |
49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
55 | * SUCH DAMAGE. | |
56 | */ | |
57 | ||
58 | #include <sys/cdefs.h> | |
59 | ||
60 | #include <sys/param.h> | |
61 | #include <sys/malloc.h> | |
62 | #include <sys/mbuf.h> | |
63 | #include <sys/systm.h> | |
64 | #include <sys/proc.h> | |
65 | #include <sys/socket.h> | |
66 | #include <sys/socketvar.h> | |
67 | #include <sys/kernel.h> | |
68 | #include <sys/errno.h> | |
69 | #include <sys/syslog.h> | |
70 | #include <sys/sysctl.h> | |
71 | #include <sys/queue.h> | |
72 | #include <sys/mcache.h> | |
73 | ||
74 | #include <net/if.h> | |
75 | #include <net/if_var.h> | |
76 | #include <net/if_dl.h> | |
77 | #include <net/if_types.h> | |
78 | #include <net/pfvar.h> | |
79 | #include <net/altq/altq.h> | |
80 | #include <net/pktsched/pktsched.h> | |
81 | ||
82 | #include <pexpert/pexpert.h> | |
83 | ||
84 | SYSCTL_NODE(_net, OID_AUTO, altq, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "ALTQ"); | |
85 | ||
86 | static u_int32_t altq_debug; | |
87 | SYSCTL_UINT(_net_altq, OID_AUTO, debug, CTLFLAG_RW, &altq_debug, 0, | |
88 | "Enable ALTQ debugging"); | |
89 | ||
90 | /* | |
91 | * look up the queue state by the interface name and the queueing type; | |
92 | * upon success, returns with the interface send queue lock held, and | |
93 | * the caller is responsible for releasing it. | |
94 | */ | |
95 | void * | |
96 | altq_lookup(char *name, u_int32_t type) | |
97 | { | |
98 | struct ifnet *ifp; | |
99 | void *state = NULL; | |
100 | ||
101 | if ((ifp = ifunit(name)) != NULL) { | |
102 | IFCQ_LOCK(&ifp->if_snd); | |
103 | if (type != ALTQT_NONE && | |
104 | IFCQ_ALTQ(&ifp->if_snd)->altq_type == type) | |
105 | state = IFCQ_ALTQ(&ifp->if_snd)->altq_disc; | |
106 | if (state == NULL) | |
107 | IFCQ_UNLOCK(&ifp->if_snd); | |
108 | } | |
109 | ||
110 | if (state != NULL) | |
111 | IFCQ_LOCK_ASSERT_HELD(&ifp->if_snd); | |
112 | ||
113 | return (state); | |
114 | } | |
115 | ||
116 | int | |
117 | altq_attach(struct ifaltq *altq, u_int32_t type, void *discipline, | |
118 | altq_enq_func enqueue, altq_deq_func dequeue, | |
119 | altq_deq_sc_func dequeue_sc, altq_req_func request) | |
120 | { | |
121 | IFCQ_LOCK_ASSERT_HELD(altq->altq_ifcq); | |
122 | ||
123 | if (!ALTQ_IS_READY(altq)) | |
124 | return (ENXIO); | |
125 | ||
126 | VERIFY(enqueue != NULL); | |
127 | VERIFY(!(dequeue != NULL && dequeue_sc != NULL)); | |
128 | VERIFY(request != NULL); | |
129 | ||
130 | altq->altq_type = type; | |
131 | altq->altq_disc = discipline; | |
132 | altq->altq_enqueue = enqueue; | |
133 | altq->altq_dequeue = dequeue; | |
134 | altq->altq_dequeue_sc = dequeue_sc; | |
135 | altq->altq_request = request; | |
136 | altq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED); | |
137 | ||
138 | return (0); | |
139 | } | |
140 | ||
141 | int | |
142 | altq_detach(struct ifaltq *altq) | |
143 | { | |
144 | IFCQ_LOCK_ASSERT_HELD(altq->altq_ifcq); | |
145 | ||
146 | if (!ALTQ_IS_READY(altq)) | |
147 | return (ENXIO); | |
148 | if (ALTQ_IS_ENABLED(altq)) | |
149 | return (EBUSY); | |
150 | if (!ALTQ_IS_ATTACHED(altq)) | |
151 | return (0); | |
152 | ||
153 | altq->altq_type = ALTQT_NONE; | |
154 | altq->altq_disc = NULL; | |
155 | altq->altq_enqueue = NULL; | |
156 | altq->altq_dequeue = NULL; | |
157 | altq->altq_dequeue_sc = NULL; | |
158 | altq->altq_request = NULL; | |
159 | altq->altq_flags &= ALTQF_CANTCHANGE; | |
160 | ||
161 | return (0); | |
162 | } | |
163 | ||
164 | int | |
165 | altq_enable(struct ifaltq *altq) | |
166 | { | |
167 | struct ifclassq *ifq = altq->altq_ifcq; | |
168 | ||
169 | IFCQ_LOCK_ASSERT_HELD(ifq); | |
170 | ||
171 | if (!ALTQ_IS_READY(altq)) | |
172 | return (ENXIO); | |
173 | if (ALTQ_IS_ENABLED(altq)) | |
174 | return (0); | |
175 | ||
176 | altq->altq_flags |= ALTQF_ENABLED; | |
177 | ||
178 | return (0); | |
179 | } | |
180 | ||
181 | int | |
182 | altq_disable(struct ifaltq *altq) | |
183 | { | |
184 | struct ifclassq *ifq = altq->altq_ifcq; | |
185 | ||
186 | IFCQ_LOCK_ASSERT_HELD(ifq); | |
187 | ||
188 | if (!ALTQ_IS_ENABLED(altq)) | |
189 | return (0); | |
190 | ||
191 | if_qflush(ifq->ifcq_ifp, 1); | |
192 | ||
193 | altq->altq_flags &= ~ALTQF_ENABLED; | |
194 | ||
195 | return (0); | |
196 | } | |
197 | ||
198 | /* | |
199 | * add a discipline or a queue | |
200 | */ | |
201 | int | |
202 | altq_add(struct pf_altq *a) | |
203 | { | |
204 | int error = 0; | |
205 | ||
206 | VERIFY(machclk_freq != 0); | |
207 | ||
208 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
209 | ||
210 | if (a->qname[0] != 0) | |
211 | return (altq_add_queue(a)); | |
212 | ||
213 | switch (a->scheduler) { | |
214 | #if PKTSCHED_CBQ | |
215 | case ALTQT_CBQ: | |
216 | error = altq_cbq_add(a); | |
217 | break; | |
218 | #endif /* PKTSCHED_CBQ */ | |
219 | #if PKTSCHED_PRIQ | |
220 | case ALTQT_PRIQ: | |
221 | error = altq_priq_add(a); | |
222 | break; | |
223 | #endif /* PKTSCHED_PRIQ */ | |
224 | #if PKTSCHED_HFSC | |
225 | case ALTQT_HFSC: | |
226 | error = altq_hfsc_add(a); | |
227 | break; | |
228 | #endif /* PKTSCHED_HFSC */ | |
229 | #if PKTSCHED_FAIRQ | |
230 | case ALTQT_FAIRQ: | |
231 | error = altq_fairq_add(a); | |
232 | break; | |
233 | #endif /* PKTSCHED_FAIRQ */ | |
234 | case ALTQT_QFQ: | |
235 | error = altq_qfq_add(a); | |
236 | break; | |
237 | default: | |
238 | error = ENXIO; | |
239 | } | |
240 | ||
241 | return (error); | |
242 | } | |
243 | ||
244 | /* | |
245 | * remove a discipline or a queue | |
246 | */ | |
247 | int | |
248 | altq_remove(struct pf_altq *a) | |
249 | { | |
250 | int error = 0; | |
251 | ||
252 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
253 | ||
254 | if (a->qname[0] != 0) | |
255 | return (altq_remove_queue(a)); | |
256 | ||
257 | switch (a->scheduler) { | |
258 | #if PKTSCHED_CBQ | |
259 | case ALTQT_CBQ: | |
260 | error = altq_cbq_remove(a); | |
261 | break; | |
262 | #endif /* PKTSCHED_CBQ */ | |
263 | #if PKTSCHED_PRIQ | |
264 | case ALTQT_PRIQ: | |
265 | error = altq_priq_remove(a); | |
266 | break; | |
267 | #endif /* PKTSCHED_PRIQ */ | |
268 | #if PKTSCHED_HFSC | |
269 | case ALTQT_HFSC: | |
270 | error = altq_hfsc_remove(a); | |
271 | break; | |
272 | #endif /* PKTSCHED_HFSC */ | |
273 | #if PKTSCHED_FAIRQ | |
274 | case ALTQT_FAIRQ: | |
275 | error = altq_fairq_remove(a); | |
276 | break; | |
277 | #endif /* PKTSCHED_FAIRQ */ | |
278 | case ALTQT_QFQ: | |
279 | error = altq_qfq_remove(a); | |
280 | break; | |
281 | default: | |
282 | error = ENXIO; | |
283 | } | |
284 | ||
285 | return (error); | |
286 | } | |
287 | ||
288 | /* | |
289 | * add a queue to the discipline | |
290 | */ | |
291 | int | |
292 | altq_add_queue(struct pf_altq *a) | |
293 | { | |
294 | int error = 0; | |
295 | ||
296 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
297 | ||
298 | switch (a->scheduler) { | |
299 | #if PKTSCHED_CBQ | |
300 | case ALTQT_CBQ: | |
301 | error = altq_cbq_add_queue(a); | |
302 | break; | |
303 | #endif /* PKTSCHED_CBQ */ | |
304 | #if PKTSCHED_PRIQ | |
305 | case ALTQT_PRIQ: | |
306 | error = altq_priq_add_queue(a); | |
307 | break; | |
308 | #endif /* PKTSCHED_PRIQ */ | |
309 | #if PKTSCHED_HFSC | |
310 | case ALTQT_HFSC: | |
311 | error = altq_hfsc_add_queue(a); | |
312 | break; | |
313 | #endif /* PKTSCHED_HFSC */ | |
314 | #if PKTSCHED_FAIRQ | |
315 | case ALTQT_FAIRQ: | |
316 | error = altq_fairq_add_queue(a); | |
317 | break; | |
318 | #endif /* PKTSCHED_FAIRQ */ | |
319 | case ALTQT_QFQ: | |
320 | error = altq_qfq_add_queue(a); | |
321 | break; | |
322 | default: | |
323 | error = ENXIO; | |
324 | } | |
325 | ||
326 | return (error); | |
327 | } | |
328 | ||
329 | /* | |
330 | * remove a queue from the discipline | |
331 | */ | |
332 | int | |
333 | altq_remove_queue(struct pf_altq *a) | |
334 | { | |
335 | int error = 0; | |
336 | ||
337 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
338 | ||
339 | switch (a->scheduler) { | |
340 | #if PKTSCHED_CBQ | |
341 | case ALTQT_CBQ: | |
342 | error = altq_cbq_remove_queue(a); | |
343 | break; | |
344 | #endif /* PKTSCHED_CBQ */ | |
345 | #if PKTSCHED_PRIQ | |
346 | case ALTQT_PRIQ: | |
347 | error = altq_priq_remove_queue(a); | |
348 | break; | |
349 | #endif /* PKTSCHED_PRIQ */ | |
350 | #if PKTSCHED_HFSC | |
351 | case ALTQT_HFSC: | |
352 | error = altq_hfsc_remove_queue(a); | |
353 | break; | |
354 | #endif /* PKTSCHED_HFSC */ | |
355 | #if PKTSCHED_FAIRQ | |
356 | case ALTQT_FAIRQ: | |
357 | error = altq_fairq_remove_queue(a); | |
358 | break; | |
359 | #endif /* PKTSCHED_FAIRQ */ | |
360 | case ALTQT_QFQ: | |
361 | error = altq_qfq_remove_queue(a); | |
362 | break; | |
363 | default: | |
364 | error = ENXIO; | |
365 | } | |
366 | ||
367 | return (error); | |
368 | } | |
369 | ||
370 | /* | |
371 | * get queue statistics | |
372 | */ | |
373 | int | |
374 | altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) | |
375 | { | |
376 | int error = 0; | |
377 | ||
378 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
379 | ||
380 | switch (a->scheduler) { | |
381 | #if PKTSCHED_CBQ | |
382 | case ALTQT_CBQ: | |
383 | error = altq_cbq_getqstats(a, ubuf, nbytes); | |
384 | break; | |
385 | #endif /* PKTSCHED_CBQ */ | |
386 | #if PKTSCHED_PRIQ | |
387 | case ALTQT_PRIQ: | |
388 | error = altq_priq_getqstats(a, ubuf, nbytes); | |
389 | break; | |
390 | #endif /* PKTSCHED_PRIQ */ | |
391 | #if PKTSCHED_HFSC | |
392 | case ALTQT_HFSC: | |
393 | error = altq_hfsc_getqstats(a, ubuf, nbytes); | |
394 | break; | |
395 | #endif /* PKTSCHED_HFSC */ | |
396 | #if PKTSCHED_FAIRQ | |
397 | case ALTQT_FAIRQ: | |
398 | error = altq_fairq_getqstats(a, ubuf, nbytes); | |
399 | break; | |
400 | #endif /* PKTSCHED_FAIRQ */ | |
401 | case ALTQT_QFQ: | |
402 | error = altq_qfq_getqstats(a, ubuf, nbytes); | |
403 | break; | |
404 | default: | |
405 | error = ENXIO; | |
406 | } | |
407 | ||
408 | return (error); | |
409 | } | |
410 | ||
411 | /* | |
412 | * attach a discipline to the interface. if one already exists, it is | |
413 | * overridden. | |
414 | */ | |
415 | int | |
416 | altq_pfattach(struct pf_altq *a) | |
417 | { | |
418 | int error = 0; | |
419 | ||
420 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
421 | ||
422 | switch (a->scheduler) { | |
423 | case ALTQT_NONE: | |
424 | break; | |
425 | #if PKTSCHED_CBQ | |
426 | case ALTQT_CBQ: | |
427 | error = altq_cbq_pfattach(a); | |
428 | break; | |
429 | #endif /* PKTSCHED_CBQ */ | |
430 | #if PKTSCHED_PRIQ | |
431 | case ALTQT_PRIQ: | |
432 | error = altq_priq_pfattach(a); | |
433 | break; | |
434 | #endif /* PKTSCHED_PRIQ */ | |
435 | #if PKTSCHED_HFSC | |
436 | case ALTQT_HFSC: | |
437 | error = altq_hfsc_pfattach(a); | |
438 | break; | |
439 | #endif /* PKTSCHED_HFSC */ | |
440 | #if PKTSCHED_FAIRQ | |
441 | case ALTQT_FAIRQ: | |
442 | error = altq_fairq_pfattach(a); | |
443 | break; | |
444 | #endif /* PKTSCHED_FAIRQ */ | |
445 | case ALTQT_QFQ: | |
446 | error = altq_qfq_pfattach(a); | |
447 | break; | |
448 | default: | |
449 | error = ENXIO; | |
450 | } | |
451 | ||
452 | return (error); | |
453 | } | |
454 | ||
455 | /* | |
456 | * detach a discipline from the interface. | |
457 | * it is possible that the discipline was already overridden by another | |
458 | * discipline. | |
459 | */ | |
460 | int | |
461 | altq_pfdetach(struct pf_altq *a) | |
462 | { | |
463 | struct ifnet *ifp; | |
464 | int error = 0; | |
465 | ||
466 | lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); | |
467 | ||
468 | if ((ifp = ifunit(a->ifname)) == NULL) | |
469 | return (EINVAL); | |
470 | ||
471 | /* if this discipline is no longer referenced, just return */ | |
472 | IFCQ_LOCK(&ifp->if_snd); | |
473 | if (a->altq_disc == NULL || | |
474 | a->altq_disc != IFCQ_ALTQ(&ifp->if_snd)->altq_disc) { | |
475 | IFCQ_UNLOCK(&ifp->if_snd); | |
476 | return (0); | |
477 | } | |
478 | ||
479 | if (ALTQ_IS_ENABLED(IFCQ_ALTQ(&ifp->if_snd))) | |
480 | error = altq_disable(IFCQ_ALTQ(&ifp->if_snd)); | |
481 | if (error == 0) | |
482 | error = altq_detach(IFCQ_ALTQ(&ifp->if_snd)); | |
483 | IFCQ_UNLOCK(&ifp->if_snd); | |
484 | return (error); | |
485 | } | |
486 | ||
487 |