1/* 2 * Copyright (c) 2007-2012 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_cbq.c,v 1.23 2007/09/13 20:40:02 chl Exp $ */ 30/* $KAME: altq_cbq.c,v 1.9 2000/12/14 08:12:45 thorpej Exp $ */ 31 32/* 33 * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the SMCC Technology 49 * Development Group at Sun Microsystems, Inc. 50 * 51 * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or 52 * promote products derived from this software without specific prior 53 * written permission. 54 * 55 * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE 56 * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is 57 * provided "as is" without express or implied warranty of any kind. 58 * 59 * These notices must be retained in any copies of any part of this software. 60 */ 61 62#if PKTSCHED_CBQ 63 64#include <sys/cdefs.h> 65#include <sys/param.h> 66#include <sys/malloc.h> 67#include <sys/mbuf.h> 68#include <sys/systm.h> 69#include <sys/errno.h> 70#include <sys/kernel.h> 71#include <sys/syslog.h> 72 73#include <kern/zalloc.h> 74 75#include <net/if.h> 76#include <net/net_osdep.h> 77 78#include <net/pktsched/pktsched_cbq.h> 79#include <netinet/in.h> 80 81/* 82 * Forward Declarations. 83 */ 84#if 0 85static int cbq_enqueue_ifclassq(struct ifclassq *, struct mbuf *); 86static struct mbuf *cbq_dequeue_ifclassq(struct ifclassq *, cqdq_op_t); 87static int cbq_request_ifclassq(struct ifclassq *, cqrq_t, void *); 88#endif 89static int cbq_class_destroy(cbq_state_t *, struct rm_class *); 90static int cbq_destroy_locked(cbq_state_t *); 91static struct rm_class *cbq_clh_to_clp(cbq_state_t *, u_int32_t); 92static const char *cbq_style(cbq_state_t *); 93static int cbq_clear_interface(cbq_state_t *); 94static void cbqrestart(struct ifclassq *); 95 96#define CBQ_ZONE_MAX 32 /* maximum elements in zone */ 97#define CBQ_ZONE_NAME "pktsched_cbq" /* zone name */ 98 99static unsigned int cbq_size; /* size of zone element */ 100static struct zone *cbq_zone; /* zone for cbq */ 101 102void 103cbq_init(void) 104{ 105 _CASSERT(CBQCLF_RED == RMCF_RED); 106 _CASSERT(CBQCLF_ECN == RMCF_ECN); 107 _CASSERT(CBQCLF_RIO == RMCF_RIO); 108 _CASSERT(CBQCLF_FLOWVALVE == RMCF_FLOWVALVE); 109 _CASSERT(CBQCLF_CLEARDSCP == RMCF_CLEARDSCP); 110 _CASSERT(CBQCLF_WRR == RMCF_WRR); 111 _CASSERT(CBQCLF_EFFICIENT == RMCF_EFFICIENT); 112 _CASSERT(CBQCLF_BLUE == RMCF_BLUE); 113 _CASSERT(CBQCLF_SFB == RMCF_SFB); 114 _CASSERT(CBQCLF_FLOWCTL == RMCF_FLOWCTL); 115 _CASSERT(CBQCLF_LAZY == RMCF_LAZY); 116 117 cbq_size = sizeof (cbq_state_t); 118 cbq_zone = zinit(cbq_size, CBQ_ZONE_MAX * cbq_size, 0, CBQ_ZONE_NAME); 119 if (cbq_zone == NULL) { 120 panic("%s: failed allocating %s", __func__, CBQ_ZONE_NAME); 121 /* NOTREACHED */ 122 } 123 zone_change(cbq_zone, Z_EXPAND, TRUE); 124 zone_change(cbq_zone, Z_CALLERACCT, TRUE); 125 126 rmclass_init(); 127} 128 129cbq_state_t * 130cbq_alloc(struct ifnet *ifp, int how, boolean_t altq) 131{ 132 cbq_state_t *cbqp; 133 134 /* allocate and initialize cbq_state_t */ 135 cbqp = (how == M_WAITOK) ? zalloc(cbq_zone) : zalloc_noblock(cbq_zone); 136 if (cbqp == NULL) 137 return (NULL); 138 139 bzero(cbqp, cbq_size); 140 CALLOUT_INIT(&cbqp->cbq_callout); 141 cbqp->cbq_qlen = 0; 142 cbqp->ifnp.ifq_ = &ifp->if_snd; /* keep the ifclassq */ 143 if (altq) 144 cbqp->cbq_flags |= CBQSF_ALTQ; 145 146 if (pktsched_verbose) { 147 log(LOG_DEBUG, "%s: %s scheduler allocated\n", 148 if_name(ifp), cbq_style(cbqp)); 149 } 150 151 return (cbqp); 152} 153 154int 155cbq_destroy(cbq_state_t *cbqp) 156{ 157 struct ifclassq *ifq = cbqp->ifnp.ifq_; 158 int err; 159 160 IFCQ_LOCK(ifq); 161 err = cbq_destroy_locked(cbqp); 162 IFCQ_UNLOCK(ifq); 163 164 return (err); 165} 166 167static int 168cbq_destroy_locked(cbq_state_t *cbqp) 169{ 170 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 171 172 (void) cbq_clear_interface(cbqp); 173 174 if (pktsched_verbose) { 175 log(LOG_DEBUG, "%s: %s scheduler destroyed\n", 176 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 177 } 178 179 if (cbqp->ifnp.default_) 180 cbq_class_destroy(cbqp, cbqp->ifnp.default_); 181 if (cbqp->ifnp.root_) 182 cbq_class_destroy(cbqp, cbqp->ifnp.root_); 183 184 /* deallocate cbq_state_t */ 185 zfree(cbq_zone, cbqp); 186 187 return (0); 188} 189 190int 191cbq_add_queue(cbq_state_t *cbqp, u_int32_t qlimit, u_int32_t priority, 192 u_int32_t minburst, u_int32_t maxburst, u_int32_t pktsize, 193 u_int32_t maxpktsize, u_int32_t ns_per_byte, u_int32_t maxidle, int minidle, 194 u_int32_t offtime, u_int32_t flags, u_int32_t parent_qid, u_int32_t qid, 195 struct rm_class **clp) 196{ 197#pragma unused(minburst, maxburst, maxpktsize) 198 struct rm_class *borrow, *parent; 199 struct rm_class *cl; 200 int i, error; 201 202 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 203 204 /* Sanitize flags unless internally configured */ 205 if (cbqp->cbq_flags & CBQSF_ALTQ) 206 flags &= CBQCLF_USERFLAGS; 207 208 /* 209 * find a free slot in the class table. if the slot matching 210 * the lower bits of qid is free, use this slot. otherwise, 211 * use the first free slot. 212 */ 213 i = qid % CBQ_MAX_CLASSES; 214 if (cbqp->cbq_class_tbl[i] != NULL) { 215 for (i = 0; i < CBQ_MAX_CLASSES; i++) 216 if (cbqp->cbq_class_tbl[i] == NULL) 217 break; 218 if (i == CBQ_MAX_CLASSES) 219 return (EINVAL); 220 } 221 222 /* check parameters */ 223 if (priority >= CBQ_MAXPRI) 224 return (EINVAL); 225 226 if (ns_per_byte == 0) { 227 log(LOG_ERR, "%s: %s invalid inverse data rate\n", 228 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 229 return (EINVAL); 230 } 231 232 /* Get pointers to parent and borrow classes. */ 233 parent = cbq_clh_to_clp(cbqp, parent_qid); 234 if (flags & CBQCLF_BORROW) 235 borrow = parent; 236 else 237 borrow = NULL; 238 239 /* 240 * A class must borrow from its parent or it can not 241 * borrow at all. Hence, borrow can be null. 242 */ 243 if (parent == NULL && (flags & CBQCLF_ROOTCLASS) == 0) { 244 log(LOG_ERR, "%s: %s no parent class!\n", 245 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 246 return (EINVAL); 247 } 248 249 if ((borrow != parent) && (borrow != NULL)) { 250 log(LOG_ERR, "%s: %s borrow class != parent\n", 251 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 252 return (EINVAL); 253 } 254 255 /* 256 * check parameters 257 */ 258 switch (flags & CBQCLF_CLASSMASK) { 259 case CBQCLF_ROOTCLASS: 260 if (parent != NULL) { 261 log(LOG_ERR, "%s: %s parent exists\n", 262 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 263 return (EINVAL); 264 } 265 if (cbqp->ifnp.root_) { 266 log(LOG_ERR, "%s: %s root class exists\n", 267 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 268 return (EINVAL); 269 } 270 break; 271 case CBQCLF_DEFCLASS: 272 if (cbqp->ifnp.default_) { 273 log(LOG_ERR, "%s: %s default class exists\n", 274 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp)); 275 return (EINVAL); 276 } 277 break; 278 case 0: 279 break; 280 default: 281 /* more than two flags bits set */ 282 log(LOG_ERR, "%s: %s invalid class flags 0x%x\n", 283 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp), 284 (flags & CBQCLF_CLASSMASK)); 285 return (EINVAL); 286 } 287 288 /* 289 * create a class. if this is a root class, initialize the 290 * interface. 291 */ 292 if ((flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) { 293 error = rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, ns_per_byte, 294 cbqrestart, qid, qlimit, RM_MAXQUEUED, maxidle, minidle, 295 offtime, flags); 296 if (error != 0) 297 return (error); 298 cl = cbqp->ifnp.root_; 299 } else { 300 cl = rmc_newclass(priority, &cbqp->ifnp, ns_per_byte, 301 rmc_delay_action, qid, qlimit, parent, borrow, maxidle, 302 minidle, offtime, pktsize, flags); 303 } 304 if (cl == NULL) 305 return (ENOMEM); 306 307 /* return handle to user space. */ 308 cl->stats_.handle = qid; 309 cl->stats_.depth = cl->depth_; 310 311 /* save the allocated class */ 312 cbqp->cbq_class_tbl[i] = cl; 313 314 if ((flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS) 315 cbqp->ifnp.default_ = cl; 316 317 if (clp != NULL) 318 *clp = cl; 319 320 if (pktsched_verbose) { 321 log(LOG_DEBUG, "%s: %s created qid=%d pri=%d qlimit=%d " 322 "flags=%b\n", if_name(CBQS_IFP(cbqp)), cbq_style(cbqp), 323 qid, priority, qlimit, flags, CBQCLF_BITS); 324 } 325 326 return (0); 327} 328 329int 330cbq_remove_queue(cbq_state_t *cbqp, u_int32_t qid) 331{ 332 struct rm_class *cl; 333 int i; 334 335 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 336 337 if ((cl = cbq_clh_to_clp(cbqp, qid)) == NULL) 338 return (EINVAL); 339 340 /* if we are a parent class, then return an error. */ 341 if (RMC_IS_A_PARENT_CLASS(cl)) 342 return (EINVAL); 343 344 /* delete the class */ 345 rmc_delete_class(&cbqp->ifnp, cl); 346 347 /* 348 * free the class handle 349 */ 350 for (i = 0; i < CBQ_MAX_CLASSES; i++) { 351 if (cbqp->cbq_class_tbl[i] == cl) { 352 cbqp->cbq_class_tbl[i] = NULL; 353 if (cl == cbqp->ifnp.root_) 354 cbqp->ifnp.root_ = NULL; 355 if (cl == cbqp->ifnp.default_) 356 cbqp->ifnp.default_ = NULL; 357 break; 358 } 359 } 360 return (0); 361} 362 363/* 364 * int 365 * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This 366 * function destroys a given traffic class. Before destroying 367 * the class, all traffic for that class is released. 368 */ 369static int 370cbq_class_destroy(cbq_state_t *cbqp, struct rm_class *cl) 371{ 372 int i; 373 374 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 375 376 if (pktsched_verbose) { 377 log(LOG_DEBUG, "%s: %s destroyed qid=%d pri=%d\n", 378 if_name(CBQS_IFP(cbqp)), cbq_style(cbqp), 379 cl->stats_.handle, cl->pri_); 380 } 381 382 /* delete the class */ 383 rmc_delete_class(&cbqp->ifnp, cl); 384 385 /* 386 * free the class handle 387 */ 388 for (i = 0; i < CBQ_MAX_CLASSES; i++) 389 if (cbqp->cbq_class_tbl[i] == cl) 390 cbqp->cbq_class_tbl[i] = NULL; 391 392 if (cl == cbqp->ifnp.root_) 393 cbqp->ifnp.root_ = NULL; 394 if (cl == cbqp->ifnp.default_) 395 cbqp->ifnp.default_ = NULL; 396 397 return (0); 398} 399 400/* convert class handle to class pointer */ 401static struct rm_class * 402cbq_clh_to_clp(cbq_state_t *cbqp, u_int32_t chandle) 403{ 404 int i; 405 struct rm_class *cl; 406 407 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 408 409 /* 410 * first, try optimistically the slot matching the lower bits of 411 * the handle. if it fails, do the linear table search. 412 */ 413 i = chandle % CBQ_MAX_CLASSES; 414 if ((cl = cbqp->cbq_class_tbl[i]) != NULL && 415 cl->stats_.handle == chandle) 416 return (cl); 417 for (i = 0; i < CBQ_MAX_CLASSES; i++) 418 if ((cl = cbqp->cbq_class_tbl[i]) != NULL && 419 cl->stats_.handle == chandle) 420 return (cl); 421 return (NULL); 422} 423 424static const char * 425cbq_style(cbq_state_t *cbqp) 426{ 427 return ((cbqp->cbq_flags & CBQSF_ALTQ) ? "ALTQ_CBQ" : "CBQ"); 428} 429 430static int 431cbq_clear_interface(cbq_state_t *cbqp) 432{ 433 int again, i; 434 struct rm_class *cl; 435 436 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 437 438 /* clear out the classes now */ 439 do { 440 again = 0; 441 for (i = 0; i < CBQ_MAX_CLASSES; i++) { 442 if ((cl = cbqp->cbq_class_tbl[i]) != NULL) { 443 if (RMC_IS_A_PARENT_CLASS(cl)) 444 again++; 445 else { 446 cbq_class_destroy(cbqp, cl); 447 cbqp->cbq_class_tbl[i] = NULL; 448 if (cl == cbqp->ifnp.root_) 449 cbqp->ifnp.root_ = NULL; 450 if (cl == cbqp->ifnp.default_) 451 cbqp->ifnp.default_ = NULL; 452 } 453 } 454 } 455 } while (again); 456 457 return (0); 458} 459 460/* copy the stats info in rm_class to class_states_t */ 461int 462cbq_get_class_stats(cbq_state_t *cbqp, u_int32_t qid, class_stats_t *statsp) 463{ 464 struct rm_class *cl; 465 466 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 467 468 if ((cl = cbq_clh_to_clp(cbqp, qid)) == NULL) 469 return (EINVAL); 470 471 statsp->xmit_cnt = cl->stats_.xmit_cnt; 472 statsp->drop_cnt = cl->stats_.drop_cnt; 473 statsp->over = cl->stats_.over; 474 statsp->borrows = cl->stats_.borrows; 475 statsp->overactions = cl->stats_.overactions; 476 statsp->delays = cl->stats_.delays; 477 478 statsp->depth = cl->depth_; 479 statsp->priority = cl->pri_; 480 statsp->maxidle = cl->maxidle_; 481 statsp->minidle = cl->minidle_; 482 statsp->offtime = cl->offtime_; 483 statsp->qmax = qlimit(&cl->q_); 484 statsp->ns_per_byte = cl->ns_per_byte_; 485 statsp->wrr_allot = cl->w_allotment_; 486 statsp->qcnt = qlen(&cl->q_); 487 statsp->avgidle = cl->avgidle_; 488 489 statsp->qtype = qtype(&cl->q_); 490 statsp->qstate = qstate(&cl->q_); 491#if CLASSQ_RED 492 if (q_is_red(&cl->q_)) 493 red_getstats(cl->red_, &statsp->red[0]); 494#endif /* CLASSQ_RED */ 495#if CLASSQ_RIO 496 if (q_is_rio(&cl->q_)) 497 rio_getstats(cl->rio_, &statsp->red[0]); 498#endif /* CLASSQ_RIO */ 499#if CLASSQ_BLUE 500 if (q_is_blue(&cl->q_)) 501 blue_getstats(cl->blue_, &statsp->blue); 502#endif /* CLASSQ_BLUE */ 503 if (q_is_sfb(&cl->q_) && cl->sfb_ != NULL) 504 sfb_getstats(cl->sfb_, &statsp->sfb); 505 506 return (0); 507} 508 509int 510cbq_enqueue(cbq_state_t *cbqp, struct rm_class *cl, struct mbuf *m, 511 struct pf_mtag *t) 512{ 513 struct ifclassq *ifq = cbqp->ifnp.ifq_; 514 int len, ret; 515 516 IFCQ_LOCK_ASSERT_HELD(ifq); 517 518 /* grab class set by classifier */ 519 if (!(m->m_flags & M_PKTHDR)) { 520 /* should not happen */ 521 log(LOG_ERR, "%s: packet for %s does not have pkthdr\n", 522 if_name(ifq->ifcq_ifp)); 523 IFCQ_CONVERT_LOCK(ifq); 524 m_freem(m); 525 return (ENOBUFS); 526 } 527 528 if (cl == NULL) { 529#if PF_ALTQ 530 cl = cbq_clh_to_clp(cbqp, t->pftag_qid); 531#else /* !PF_ALTQ */ 532 cl = cbq_clh_to_clp(cbqp, 0); 533#endif /* !PF_ALTQ */ 534 if (cl == NULL) { 535 cl = cbqp->ifnp.default_; 536 if (cl == NULL) { 537 IFCQ_CONVERT_LOCK(ifq); 538 m_freem(m); 539 return (ENOBUFS); 540 } 541 } 542 } 543 544 len = m_pktlen(m); 545 546 ret = rmc_queue_packet(cl, m, t); 547 if (ret != 0) { 548 if (ret == CLASSQEQ_SUCCESS_FC) { 549 /* packet enqueued, return advisory feedback */ 550 ret = EQFULL; 551 } else { 552 VERIFY(ret == CLASSQEQ_DROPPED || 553 ret == CLASSQEQ_DROPPED_FC || 554 ret == CLASSQEQ_DROPPED_SP); 555 /* packet has been freed in rmc_queue_packet */ 556 PKTCNTR_ADD(&cl->stats_.drop_cnt, 1, len); 557 IFCQ_DROP_ADD(ifq, 1, len); 558 switch (ret) { 559 case CLASSQEQ_DROPPED: 560 return (ENOBUFS); 561 case CLASSQEQ_DROPPED_FC: 562 return (EQFULL); 563 case CLASSQEQ_DROPPED_SP: 564 return (EQSUSPENDED); 565 } 566 /* NOT REACHED */ 567 } 568 } 569 570 /* successfully queued. */ 571 ++cbqp->cbq_qlen; 572 IFCQ_INC_LEN(ifq); 573 574 return (ret); 575} 576 577struct mbuf * 578cbq_dequeue(cbq_state_t *cbqp, cqdq_op_t op) 579{ 580 struct ifclassq *ifq = cbqp->ifnp.ifq_; 581 struct mbuf *m; 582 583 IFCQ_LOCK_ASSERT_HELD(ifq); 584 585 m = rmc_dequeue_next(&cbqp->ifnp, op); 586 587 if (m && op == CLASSQDQ_REMOVE) { 588 --cbqp->cbq_qlen; /* decrement # of packets in cbq */ 589 IFCQ_DEC_LEN(ifq); 590 IFCQ_XMIT_ADD(ifq, 1, m_pktlen(m)); 591 592 /* Update the class. */ 593 rmc_update_class_util(&cbqp->ifnp); 594 } 595 return (m); 596} 597 598/* 599 * void 600 * cbqrestart(queue_t *) - Restart sending of data. 601 * called from rmc_restart via timeout after waking up 602 * a suspended class. 603 * Returns: NONE 604 */ 605 606static void 607cbqrestart(struct ifclassq *ifq) 608{ 609 u_int32_t qlen; 610 611 IFCQ_LOCK(ifq); 612 qlen = IFCQ_LEN(ifq); 613 IFCQ_UNLOCK(ifq); 614 615 if (qlen > 0) 616 ifnet_start(ifq->ifcq_ifp); 617} 618 619void 620cbq_purge(cbq_state_t *cbqp) 621{ 622 struct rm_class *cl; 623 int i; 624 625 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 626 627 for (i = 0; i < CBQ_MAX_CLASSES; i++) { 628 if ((cl = cbqp->cbq_class_tbl[i]) != NULL) { 629 if (!qempty(&cl->q_) && pktsched_verbose) { 630 log(LOG_DEBUG, "%s: %s purge qid=%d pri=%d " 631 "qlen=%d\n", if_name(CBQS_IFP(cbqp)), 632 cbq_style(cbqp), cl->stats_.handle, 633 cl->pri_, qlen(&cl->q_)); 634 } 635 rmc_dropall(cl); 636 } 637 } 638} 639 640void 641cbq_event(cbq_state_t *cbqp, cqev_t ev) 642{ 643 struct rm_class *cl; 644 int i; 645 646 IFCQ_LOCK_ASSERT_HELD(cbqp->ifnp.ifq_); 647 648 for (i = 0; i < CBQ_MAX_CLASSES; i++) { 649 if ((cl = cbqp->cbq_class_tbl[i]) != NULL) { 650 if (pktsched_verbose) { 651 log(LOG_DEBUG, "%s: %s update qid=%d pri=%d " 652 "event=%s\n", if_name(CBQS_IFP(cbqp)), 653 cbq_style(cbqp), cl->stats_.handle, 654 cl->pri_, ifclassq_ev2str(ev)); 655 } 656 rmc_updateq(cl, ev); 657 } 658 } 659} 660 661int 662cqb_setup_ifclassq(struct ifclassq *ifq, u_int32_t flags) 663{ 664#pragma unused(ifq, flags) 665 return (ENXIO); /* not yet */ 666} 667 668int 669cbq_teardown_ifclassq(struct ifclassq *ifq) 670{ 671 cbq_state_t *cbqp = ifq->ifcq_disc; 672 int i; 673 674 IFCQ_LOCK_ASSERT_HELD(ifq); 675 VERIFY(cbqp != NULL && ifq->ifcq_type == PKTSCHEDT_CBQ); 676 677 (void) cbq_destroy_locked(cbqp); 678 679 ifq->ifcq_disc = NULL; 680 for (i = 0; i < IFCQ_SC_MAX; i++) { 681 ifq->ifcq_disc_slots[i].qid = 0; 682 ifq->ifcq_disc_slots[i].cl = NULL; 683 } 684 685 return (ifclassq_detach(ifq)); 686} 687 688int 689cbq_getqstats_ifclassq(struct ifclassq *ifq, u_int32_t slot, 690 struct if_ifclassq_stats *ifqs) 691{ 692 cbq_state_t *cbqp = ifq->ifcq_disc; 693 694 IFCQ_LOCK_ASSERT_HELD(ifq); 695 VERIFY(ifq->ifcq_type == PKTSCHEDT_CBQ); 696 697 if (slot >= IFCQ_SC_MAX) 698 return (EINVAL); 699 700 return (cbq_get_class_stats(cbqp, ifq->ifcq_disc_slots[slot].qid, 701 &ifqs->ifqs_cbq_stats)); 702} 703#endif /* PKTSCHED_CBQ */ 704