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 84SYSCTL_NODE(_net, OID_AUTO, altq, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "ALTQ"); 85 86static u_int32_t altq_debug; 87SYSCTL_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 */ 95void * 96altq_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 116int 117altq_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 141int 142altq_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 164int 165altq_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 181int 182altq_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 */ 201int 202altq_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 */ 247int 248altq_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 */ 291int 292altq_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 */ 332int 333altq_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 */ 373int 374altq_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 */ 415int 416altq_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 */ 460int 461altq_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 488