Home | History | Annotate | Line # | Download | only in altq
altq_cbq.c revision 1.3
      1 /*	$NetBSD: altq_cbq.c,v 1.3 2001/04/13 23:29:55 thorpej Exp $	*/
      2 /*	$KAME: altq_cbq.c,v 1.9 2000/12/14 08:12:45 thorpej Exp $	*/
      3 
      4 /*
      5  * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *      This product includes software developed by the SMCC Technology
     21  *      Development Group at Sun Microsystems, Inc.
     22  *
     23  * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
     24  *      promote products derived from this software without specific prior
     25  *      written permission.
     26  *
     27  * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
     28  * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is
     29  * provided "as is" without express or implied warranty of any kind.
     30  *
     31  * These notices must be retained in any copies of any part of this software.
     32  */
     33 
     34 #if defined(__FreeBSD__) || defined(__NetBSD__)
     35 #include "opt_altq.h"
     36 #if (__FreeBSD__ != 2)
     37 #include "opt_inet.h"
     38 #ifdef __FreeBSD__
     39 #include "opt_inet6.h"
     40 #endif
     41 #endif
     42 #endif /* __FreeBSD__ || __NetBSD__ */
     43 #ifdef ALTQ_CBQ	/* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
     44 
     45 /* #pragma ident "@(#)cbq.c  1.39     98/05/13 SMI" */
     46 
     47 #include <sys/param.h>
     48 #include <sys/malloc.h>
     49 #include <sys/mbuf.h>
     50 #include <sys/uio.h>
     51 #include <sys/socket.h>
     52 #include <sys/systm.h>
     53 #include <sys/proc.h>
     54 #include <sys/errno.h>
     55 #include <sys/time.h>
     56 #include <sys/kernel.h>
     57 
     58 #include <net/if.h>
     59 #include <net/if_types.h>
     60 #include <netinet/in.h>
     61 
     62 #include <altq/altq.h>
     63 #include <altq/altq_conf.h>
     64 #include <altq/altq_cbq.h>
     65 
     66 /*
     67  * Local Data structures.
     68  */
     69 static cbq_state_t *cbq_list = NULL;
     70 
     71 /*
     72  * Forward Declarations.
     73  */
     74 
     75 static int	cbq_add_class __P((struct cbq_add_class *));
     76 static int	cbq_delete_class __P((struct cbq_delete_class *));
     77 static int	cbq_modify_class __P((struct cbq_modify_class *));
     78 static int 	cbq_class_create __P((cbq_state_t *, struct cbq_add_class *,
     79 				      struct rm_class *, struct rm_class *));
     80 static int	cbq_class_destroy __P((cbq_state_t *, struct rm_class *));
     81 static struct rm_class  *clh_to_clp __P((cbq_state_t *, u_long));
     82 static int	cbq_add_filter __P((struct cbq_add_filter *));
     83 static int	cbq_delete_filter __P((struct cbq_delete_filter *));
     84 
     85 static int	cbq_clear_hierarchy __P((struct cbq_interface *));
     86 static int	cbq_clear_interface __P((cbq_state_t *));
     87 static int	cbq_request __P((struct ifaltq *, int, void *));
     88 static int	cbq_set_enable __P((struct cbq_interface *, int));
     89 static int	cbq_ifattach __P((struct cbq_interface *));
     90 static int	cbq_ifdetach __P((struct cbq_interface *));
     91 static int	cbq_enqueue __P((struct ifaltq *, struct mbuf *,
     92 				 struct altq_pktattr *));
     93 static struct mbuf 	*cbq_dequeue __P((struct ifaltq *, int));
     94 static void	cbqrestart __P((struct ifaltq *));
     95 static void 	get_class_stats __P((class_stats_t *, struct rm_class *));
     96 static int 	cbq_getstats __P((struct cbq_getstats *));
     97 static void	cbq_purge(cbq_state_t *);
     98 
     99 static int
    100 cbq_add_class(acp)
    101 	struct cbq_add_class *acp;
    102 {
    103 	char		*ifacename;
    104 	struct rm_class	*borrow, *parent;
    105 	cbq_state_t	*cbqp;
    106 
    107 	ifacename = acp->cbq_iface.cbq_ifacename;
    108 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    109 		return (EBADF);
    110 
    111 	/* check parameters */
    112 	if (acp->cbq_class.priority >= RM_MAXPRIO ||
    113 	    acp->cbq_class.maxq > CBQ_MAXQSIZE)
    114 		return (EINVAL);
    115 
    116 	/* Get pointers to parent and borrow classes.  */
    117 	parent = clh_to_clp(cbqp, acp->cbq_class.parent_class_handle);
    118 	borrow = clh_to_clp(cbqp, acp->cbq_class.borrow_class_handle);
    119 
    120 	/*
    121 	 * A class must borrow from it's parent or it can not
    122 	 * borrow at all.  Hence, borrow can be null.
    123 	 */
    124 	if (parent == NULL && (acp->cbq_class.flags & CBQCLF_ROOTCLASS) == 0) {
    125 		printf("cbq_add_class: no parent class!\n");
    126 		return (EINVAL);
    127 	}
    128 
    129 	if ((borrow != parent)  && (borrow != NULL)) {
    130 		printf("cbq_add_class: borrow class != parent\n");
    131 		return (EINVAL);
    132 	}
    133 
    134 	return cbq_class_create(cbqp, acp, parent, borrow);
    135 }
    136 
    137 static int
    138 cbq_delete_class(dcp)
    139 	struct cbq_delete_class *dcp;
    140 {
    141 	char		*ifacename;
    142 	struct rm_class	*cl;
    143 	cbq_state_t	*cbqp;
    144 
    145 	ifacename = dcp->cbq_iface.cbq_ifacename;
    146 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    147 		return (EBADF);
    148 
    149 	if ((cl = clh_to_clp(cbqp, dcp->cbq_class_handle)) == NULL)
    150 		return (EINVAL);
    151 
    152 	/* if we are a parent class, then return an error. */
    153 	if (is_a_parent_class(cl))
    154 		return (EINVAL);
    155 
    156 	/* if a filter has a reference to this class delete the filter */
    157 	acc_discard_filters(&cbqp->cbq_classifier, cl, 0);
    158 
    159 	return cbq_class_destroy(cbqp, cl);
    160 }
    161 
    162 static int
    163 cbq_modify_class(acp)
    164 	struct cbq_modify_class *acp;
    165 {
    166 	char		*ifacename;
    167 	struct rm_class	*cl;
    168 	cbq_state_t	*cbqp;
    169 
    170 	ifacename = acp->cbq_iface.cbq_ifacename;
    171 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    172 		return (EBADF);
    173 
    174 	/* Get pointer to this class */
    175 	if ((cl = clh_to_clp(cbqp, acp->cbq_class_handle)) == NULL)
    176 		return (EINVAL);
    177 
    178 	if (rmc_modclass(cl, acp->cbq_class.nano_sec_per_byte,
    179 			 acp->cbq_class.maxq, acp->cbq_class.maxidle,
    180 			 acp->cbq_class.minidle, acp->cbq_class.offtime,
    181 			 acp->cbq_class.pktsize) < 0)
    182 		return (EINVAL);
    183 	return (0);
    184 }
    185 
    186 /*
    187  * struct rm_class *
    188  * cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp,
    189  *		u_long handle, struct rm_class *parent,
    190  *		struct rm_class *borrow)
    191  *
    192  * This function create a new traffic class in the CBQ class hierarchy of
    193  * given paramters.  The class that created is either the root, default,
    194  * or a new dynamic class.  If CBQ is not initilaized, the the root class
    195  * will be created.
    196  */
    197 static int
    198 cbq_class_create(cbqp, acp, parent, borrow)
    199 	cbq_state_t *cbqp;
    200 	struct cbq_add_class *acp;
    201 	struct rm_class *parent, *borrow;
    202 {
    203 	struct rm_class	*cl;
    204 	cbq_class_spec_t *spec = &acp->cbq_class;
    205 	u_long		chandle;
    206 	int		i;
    207 
    208 	/*
    209 	 * allocate class handle
    210 	 */
    211 	switch (spec->flags & CBQCLF_CLASSMASK) {
    212 	case CBQCLF_ROOTCLASS:
    213 		if (parent != NULL)
    214 			return (EINVAL);
    215 		if (cbqp->ifnp.root_)
    216 			return (EINVAL);
    217 		chandle = ROOT_CLASS_HANDLE;
    218 		break;
    219 	case CBQCLF_DEFCLASS:
    220 		if (cbqp->ifnp.default_)
    221 			return (EINVAL);
    222 		chandle = DEFAULT_CLASS_HANDLE;
    223 		break;
    224 	case CBQCLF_CTLCLASS:
    225 		if (cbqp->ifnp.ctl_)
    226 			return (EINVAL);
    227 		chandle = CTL_CLASS_HANDLE;
    228 		break;
    229 	case 0:
    230 		/* find a free class slot */
    231 		for (i = 0; i < CBQ_MAX_CLASSES; i++)
    232 			if (cbqp->cbq_class_tbl[i] == NULL)
    233 				break;
    234 		if (i == CBQ_MAX_CLASSES)
    235 			return (ENOSPC);
    236 		chandle = (u_long)i;
    237 		break;
    238 	default:
    239 		/* more than two flags bits set */
    240 		return (EINVAL);
    241 	}
    242 
    243 	/*
    244 	 * create a class.  if this is a root class, initialize the
    245 	 * interface.
    246 	 */
    247 	if (chandle == ROOT_CLASS_HANDLE) {
    248 		rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, spec->nano_sec_per_byte,
    249 			 cbqrestart, spec->maxq, RM_MAXQUEUED,
    250 			 spec->maxidle, spec->minidle, spec->offtime,
    251 			 spec->flags);
    252 		cl = cbqp->ifnp.root_;
    253 	} else {
    254 		cl = rmc_newclass(spec->priority,
    255 				  &cbqp->ifnp, spec->nano_sec_per_byte,
    256 				  rmc_delay_action, spec->maxq, parent, borrow,
    257 				  spec->maxidle, spec->minidle, spec->offtime,
    258 				  spec->pktsize, spec->flags);
    259 	}
    260 	if (cl == NULL)
    261 		return (ENOMEM);
    262 
    263 	/* return handle to user space. */
    264 	acp->cbq_class_handle = chandle;
    265 
    266 	cl->stats_.handle = chandle;
    267 	cl->stats_.depth = cl->depth_;
    268 
    269 	/* save the allocated class */
    270 	switch (chandle) {
    271 	case NULL_CLASS_HANDLE:
    272 	case ROOT_CLASS_HANDLE:
    273 		break;
    274 	case DEFAULT_CLASS_HANDLE:
    275 		cbqp->ifnp.default_ = cl;
    276 		break;
    277 	case CTL_CLASS_HANDLE:
    278 		cbqp->ifnp.ctl_ = cl;
    279 		break;
    280 	default:
    281 		cbqp->cbq_class_tbl[chandle] = cl;
    282 		break;
    283 	}
    284 	return (0);
    285 }
    286 
    287 /*
    288  * int
    289  * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
    290  *	function destroys a given traffic class.  Before destorying
    291  *	the class, all traffic for that class is released.
    292  */
    293 static int
    294 cbq_class_destroy(cbqp, cl)
    295 	cbq_state_t *cbqp;
    296 	struct rm_class *cl;
    297 {
    298 	u_long	chandle;
    299 
    300 	chandle = cl->stats_.handle;
    301 
    302 	/* delete the class */
    303 	rmc_delete_class(&cbqp->ifnp, cl);
    304 
    305 	/*
    306 	 * free the class handle
    307 	 */
    308 	switch (chandle) {
    309 	case ROOT_CLASS_HANDLE:
    310 		cbqp->ifnp.root_ = NULL;
    311 		break;
    312 	case DEFAULT_CLASS_HANDLE:
    313 		cbqp->ifnp.default_ = NULL;
    314 		break;
    315 	case CTL_CLASS_HANDLE:
    316 		cbqp->ifnp.ctl_ = NULL;
    317 		break;
    318 	case NULL_CLASS_HANDLE:
    319 		break;
    320 	default:
    321 		if (chandle >= CBQ_MAX_CLASSES)
    322 			break;
    323 		cbqp->cbq_class_tbl[chandle] = NULL;
    324 	}
    325 
    326 	return (0);
    327 }
    328 
    329 /* convert class handle to class pointer */
    330 static struct rm_class *
    331 clh_to_clp(cbqp, chandle)
    332 	cbq_state_t *cbqp;
    333 	u_long chandle;
    334 {
    335 	switch (chandle) {
    336 	case NULL_CLASS_HANDLE:
    337 		return (NULL);
    338 	case ROOT_CLASS_HANDLE:
    339 		return (cbqp->ifnp.root_);
    340 	case DEFAULT_CLASS_HANDLE:
    341 		return (cbqp->ifnp.default_);
    342 	case CTL_CLASS_HANDLE:
    343 		return (cbqp->ifnp.ctl_);
    344 	}
    345 
    346 	if (chandle >= CBQ_MAX_CLASSES)
    347 		return (NULL);
    348 
    349 	return (cbqp->cbq_class_tbl[chandle]);
    350 }
    351 
    352 static int
    353 cbq_add_filter(afp)
    354 	struct cbq_add_filter *afp;
    355 {
    356 	char		*ifacename;
    357 	cbq_state_t	*cbqp;
    358 	struct rm_class	*cl;
    359 
    360 	ifacename = afp->cbq_iface.cbq_ifacename;
    361 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    362 		return (EBADF);
    363 
    364 	/* Get the pointer to class. */
    365 	if ((cl = clh_to_clp(cbqp, afp->cbq_class_handle)) == NULL)
    366 		return (EINVAL);
    367 
    368 	return acc_add_filter(&cbqp->cbq_classifier, &afp->cbq_filter,
    369 			      cl, &afp->cbq_filter_handle);
    370 }
    371 
    372 static int
    373 cbq_delete_filter(dfp)
    374 	struct cbq_delete_filter *dfp;
    375 {
    376 	char		*ifacename;
    377 	cbq_state_t	*cbqp;
    378 
    379 	ifacename = dfp->cbq_iface.cbq_ifacename;
    380 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    381 		return (EBADF);
    382 
    383 	return acc_delete_filter(&cbqp->cbq_classifier,
    384 				 dfp->cbq_filter_handle);
    385 }
    386 
    387 /*
    388  * cbq_clear_hierarchy deletes all classes and their filters on the
    389  * given interface.
    390  */
    391 static int
    392 cbq_clear_hierarchy(ifacep)
    393 	struct cbq_interface *ifacep;
    394 {
    395 	char		*ifacename;
    396 	cbq_state_t	*cbqp;
    397 
    398 	ifacename = ifacep->cbq_ifacename;
    399 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    400 		return (EBADF);
    401 
    402 	return cbq_clear_interface(cbqp);
    403 }
    404 
    405 static int
    406 cbq_clear_interface(cbqp)
    407 	cbq_state_t *cbqp;
    408 {
    409 	int		again, i;
    410 	struct rm_class	*cl;
    411 
    412 	/* free the filters for this interface */
    413 	acc_discard_filters(&cbqp->cbq_classifier, NULL, 1);
    414 
    415 	/* clear out the classes now */
    416 	do {
    417 		again = 0;
    418 		for (i = 0; i < CBQ_MAX_CLASSES; i++) {
    419 			if ((cl = cbqp->cbq_class_tbl[i]) != NULL) {
    420 				if (is_a_parent_class(cl))
    421 					again++;
    422 				else {
    423 					cbq_class_destroy(cbqp, cl);
    424 					cbqp->cbq_class_tbl[i] = NULL;
    425 				}
    426 			}
    427 		}
    428 		if (cbqp->ifnp.ctl_ != NULL &&
    429 		    !is_a_parent_class(cbqp->ifnp.ctl_)) {
    430 			cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
    431 			cbqp->ifnp.ctl_ = NULL;
    432 		}
    433 		if (cbqp->ifnp.default_ != NULL &&
    434 		    !is_a_parent_class(cbqp->ifnp.default_)) {
    435 			cbq_class_destroy(cbqp, cbqp->ifnp.default_);
    436 			cbqp->ifnp.default_ = NULL;
    437 		}
    438 		if (cbqp->ifnp.root_ != NULL &&
    439 		    !is_a_parent_class(cbqp->ifnp.root_)) {
    440 			cbq_class_destroy(cbqp, cbqp->ifnp.root_);
    441 			cbqp->ifnp.root_ = NULL;
    442 		}
    443 	} while (again);
    444 
    445 	return (0);
    446 }
    447 
    448 static int
    449 cbq_request(ifq, req, arg)
    450 	struct ifaltq *ifq;
    451 	int req;
    452 	void *arg;
    453 {
    454 	cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc;
    455 
    456 	switch (req) {
    457 	case ALTRQ_PURGE:
    458 		cbq_purge(cbqp);
    459 		break;
    460 	}
    461 	return (0);
    462 }
    463 
    464 /*
    465  * static int
    466  * cbq_set_enable(struct cbq_enable *ep) - this function processed the
    467  *	ioctl request to enable class based queueing.  It searches the list
    468  *	of interfaces for the specified interface and then enables CBQ on
    469  *	that interface.
    470  *
    471  *	Returns:	0, for no error.
    472  *			EBADF, for specified inteface not found.
    473  */
    474 
    475 static int
    476 cbq_set_enable(ep, enable)
    477 	struct cbq_interface *ep;
    478 	int enable;
    479 {
    480 	int 	error = 0;
    481 	cbq_state_t	*cbqp;
    482 	char 	*ifacename;
    483 
    484 	ifacename = ep->cbq_ifacename;
    485 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    486 		return (EBADF);
    487 
    488 	switch (enable) {
    489 	case ENABLE:
    490 		if (cbqp->ifnp.root_ == NULL || cbqp->ifnp.default_ == NULL ||
    491 		    cbqp->ifnp.ctl_ == NULL) {
    492 			if (cbqp->ifnp.root_ == NULL)
    493 				printf("No Root Class for %s\n", ifacename);
    494 			if (cbqp->ifnp.default_ == NULL)
    495 				printf("No Default Class for %s\n", ifacename);
    496 			if (cbqp->ifnp.ctl_ == NULL)
    497 				printf("No Control Class for %s\n", ifacename);
    498 			error = EINVAL;
    499 		} else if ((error = altq_enable(cbqp->ifnp.ifq_)) == 0) {
    500 			cbqp->cbq_qlen = 0;
    501 		}
    502 		break;
    503 
    504 	case DISABLE:
    505 		error = altq_disable(cbqp->ifnp.ifq_);
    506 		break;
    507 	}
    508 	return (error);
    509 }
    510 
    511 /* copy the stats info in rm_class to class_states_t */
    512 static void
    513 get_class_stats(statsp, cl)
    514 	class_stats_t	*statsp;
    515 	struct rm_class	*cl;
    516 {
    517 	statsp->xmit_cnt 	= cl->stats_.xmit_cnt;
    518 	statsp->drop_cnt 	= cl->stats_.drop_cnt;
    519 	statsp->over		= cl->stats_.over;
    520 	statsp->borrows 	= cl->stats_.borrows;
    521 	statsp->overactions 	= cl->stats_.overactions;
    522 	statsp->delays 		= cl->stats_.delays;
    523 
    524 	statsp->depth 		= cl->depth_;
    525 	statsp->priority	= cl->pri_;
    526 	statsp->maxidle		= cl->maxidle_;
    527 	statsp->minidle		= cl->minidle_;
    528 	statsp->offtime		= cl->offtime_;
    529 	statsp->qmax		= qlimit(cl->q_);
    530 	statsp->ns_per_byte	= cl->ns_per_byte_;
    531 	statsp->wrr_allot	= cl->w_allotment_;
    532 	statsp->qcnt		= qlen(cl->q_);
    533 	statsp->avgidle		= cl->avgidle_;
    534 
    535 	statsp->qtype		= qtype(cl->q_);
    536 #ifdef ALTQ_RED
    537 	if (q_is_red(cl->q_))
    538 		red_getstats(cl->red_, &statsp->red[0]);
    539 #endif
    540 #ifdef ALTQ_RIO
    541 	if (q_is_rio(cl->q_))
    542 		rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
    543 #endif
    544 }
    545 
    546 static int
    547 cbq_getstats(gsp)
    548 	struct cbq_getstats *gsp;
    549 {
    550 	char		*ifacename;
    551 	int		chandle, n, nclasses;
    552 	cbq_state_t	*cbqp;
    553 	struct rm_class	*cl;
    554 	class_stats_t	stats, *usp;
    555 	int error = 0;
    556 
    557 	ifacename = gsp->iface.cbq_ifacename;
    558 	nclasses = gsp->nclasses;
    559 	usp = gsp->stats;
    560 
    561 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    562 		return (EBADF);
    563 	if (nclasses <= 0)
    564 		return (EINVAL);
    565 
    566 	for (n = 0, chandle = 0; n < nclasses && chandle < CBQ_MAX_CLASSES;
    567 	     n++) {
    568 		switch(n) {
    569 		case 0:
    570 			cl = cbqp->ifnp.root_;
    571 			stats.handle = ROOT_CLASS_HANDLE;
    572 			break;
    573 		case 1:
    574 			cl = cbqp->ifnp.default_;
    575 			stats.handle = DEFAULT_CLASS_HANDLE;
    576 			break;
    577 		case 2:
    578 			cl = cbqp->ifnp.ctl_;
    579 			stats.handle = CTL_CLASS_HANDLE;
    580 			break;
    581 		default:
    582 			while ((cl = cbqp->cbq_class_tbl[chandle]) == NULL)
    583 				if (++chandle >= CBQ_MAX_CLASSES)
    584 					goto out;
    585 			stats.handle = chandle++;
    586 			break;
    587 		}
    588 
    589 		get_class_stats(&stats, cl);
    590 
    591 		if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
    592 				     sizeof(stats))) != 0)
    593 			return (error);
    594 	}
    595 
    596  out:
    597 	gsp->nclasses = n;
    598 	return (error);
    599 }
    600 
    601 static int
    602 cbq_ifattach(ifacep)
    603 	struct cbq_interface *ifacep;
    604 {
    605 	int		error = 0;
    606 	char		*ifacename;
    607 	cbq_state_t	*new_cbqp;
    608 	struct ifnet 	*ifp;
    609 
    610 	ifacename = ifacep->cbq_ifacename;
    611 	if ((ifp = ifunit(ifacename)) == NULL)
    612 		return (ENXIO);
    613 	if (!ALTQ_IS_READY(&ifp->if_snd))
    614 		return (ENXIO);
    615 
    616 	/* allocate and initialize cbq_state_t */
    617 	MALLOC(new_cbqp, cbq_state_t *, sizeof(cbq_state_t), M_DEVBUF, M_WAITOK);
    618 	if (new_cbqp == NULL)
    619 		return (ENOMEM);
    620 	bzero(new_cbqp, sizeof(cbq_state_t));
    621  	CALLOUT_INIT(&new_cbqp->cbq_callout);
    622 	MALLOC(new_cbqp->cbq_class_tbl, struct rm_class **,
    623 	       sizeof(struct rm_class *) * CBQ_MAX_CLASSES, M_DEVBUF, M_WAITOK);
    624 	if (new_cbqp->cbq_class_tbl == NULL) {
    625 		FREE(new_cbqp, M_DEVBUF);
    626 		return (ENOMEM);
    627 	}
    628 	bzero(new_cbqp->cbq_class_tbl, sizeof(struct rm_class *) * CBQ_MAX_CLASSES);
    629 	new_cbqp->cbq_qlen = 0;
    630 	new_cbqp->ifnp.ifq_ = &ifp->if_snd;	    /* keep the ifq */
    631 
    632 	/*
    633 	 * set CBQ to this ifnet structure.
    634 	 */
    635 	error = altq_attach(&ifp->if_snd, ALTQT_CBQ, new_cbqp,
    636 			    cbq_enqueue, cbq_dequeue, cbq_request,
    637 			    &new_cbqp->cbq_classifier, acc_classify);
    638 	if (error) {
    639 		FREE(new_cbqp->cbq_class_tbl, M_DEVBUF);
    640 		FREE(new_cbqp, M_DEVBUF);
    641 		return (error);
    642 	}
    643 
    644 	/* prepend to the list of cbq_state_t's. */
    645 	new_cbqp->cbq_next = cbq_list;
    646 	cbq_list = new_cbqp;
    647 
    648 	return (0);
    649 }
    650 
    651 static int
    652 cbq_ifdetach(ifacep)
    653 	struct cbq_interface *ifacep;
    654 {
    655 	char		*ifacename;
    656 	cbq_state_t 	*cbqp;
    657 
    658 	ifacename = ifacep->cbq_ifacename;
    659 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    660 		return (EBADF);
    661 
    662 	(void)cbq_set_enable(ifacep, DISABLE);
    663 
    664 	cbq_clear_interface(cbqp);
    665 
    666 	if (cbqp->ifnp.ctl_)
    667 		cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
    668 	if (cbqp->ifnp.default_)
    669 		cbq_class_destroy(cbqp, cbqp->ifnp.default_);
    670 	if (cbqp->ifnp.root_)
    671 		cbq_class_destroy(cbqp, cbqp->ifnp.root_);
    672 
    673 	/* remove CBQ from the ifnet structure. */
    674 	(void)altq_detach(cbqp->ifnp.ifq_);
    675 
    676 	/* remove from the list of cbq_state_t's. */
    677 	if (cbq_list == cbqp)
    678 		cbq_list = cbqp->cbq_next;
    679 	else {
    680 		cbq_state_t *cp;
    681 
    682 		for (cp = cbq_list; cp != NULL; cp = cbqp->cbq_next)
    683 			if (cp->cbq_next == cbqp) {
    684 				cp->cbq_next = cbqp->cbq_next;
    685 				break;
    686 			}
    687 		ASSERT(cp != NULL);
    688 	}
    689 
    690 	/* deallocate cbq_state_t */
    691 	FREE(cbqp->cbq_class_tbl, M_DEVBUF);
    692 	FREE(cbqp, M_DEVBUF);
    693 
    694 	return (0);
    695 }
    696 
    697 /*
    698  * int
    699  * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
    700  *		- Queue data packets.
    701  *
    702  *	cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
    703  *	layer (e.g. ether_output).  cbq_enqueue queues the given packet
    704  *	to the cbq, then invokes the driver's start routine.
    705  *
    706  *	Assumptions:	called in splnet
    707  *	Returns:	0 if the queueing is successful.
    708  *			ENOBUFS if a packet dropping occured as a result of
    709  *			the queueing.
    710  */
    711 
    712 static int
    713 cbq_enqueue(ifq, m, pktattr)
    714 	struct ifaltq *ifq;
    715 	struct mbuf *m;
    716 	struct altq_pktattr *pktattr;
    717 {
    718 	cbq_state_t *cbqp = (cbq_state_t *)ifq->altq_disc;
    719 	struct rm_class *cl;
    720 	int len;
    721 
    722 	/* grab class set by classifier */
    723 	if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
    724 		cl = cbqp->ifnp.default_;
    725 	cl->pktattr_ = pktattr;  /* save proto hdr used by ECN */
    726 
    727 	len = m_pktlen(m);
    728 	if (rmc_queue_packet(cl, m) != 0) {
    729 		/* drop occurred.  some mbuf was freed in rmc_queue_packet. */
    730 		PKTCNTR_ADD(&cl->stats_.drop_cnt, len);
    731 		return (ENOBUFS);
    732 	}
    733 
    734 	/* successfully queued. */
    735 	++cbqp->cbq_qlen;
    736 	IFQ_INC_LEN(ifq);
    737 	return (0);
    738 }
    739 
    740 static struct mbuf *
    741 cbq_dequeue(ifq, op)
    742 	struct ifaltq *ifq;
    743 	int op;
    744 {
    745 	cbq_state_t 	*cbqp = (cbq_state_t *)ifq->altq_disc;
    746 	struct mbuf 	*m;
    747 
    748 	m = rmc_dequeue_next(&cbqp->ifnp, op);
    749 
    750 	if (m && op == ALTDQ_REMOVE) {
    751 		--cbqp->cbq_qlen;  /* decrement # of packets in cbq */
    752 		IFQ_DEC_LEN(ifq);
    753 
    754 		/* Update the class. */
    755 		rmc_update_class_util(&cbqp->ifnp);
    756 	}
    757 	return (m);
    758 }
    759 
    760 /*
    761  * void
    762  * cbqrestart(queue_t *) - Restart sending of data.
    763  * called from rmc_restart in splnet via timeout after waking up
    764  * a suspended class.
    765  *	Returns:	NONE
    766  */
    767 
    768 static void
    769 cbqrestart(ifq)
    770 	struct ifaltq *ifq;
    771 {
    772 	cbq_state_t	*cbqp;
    773 	struct ifnet	*ifp;
    774 
    775 	if (!ALTQ_IS_ENABLED(ifq))
    776 		/* cbq must have been detached */
    777 		return;
    778 	if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL)
    779 		/* should not happen */
    780 		return;
    781 
    782 	ifp = ifq->altq_ifp;
    783 	if (ifp->if_start &&
    784 	    cbqp->cbq_qlen > 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
    785 		(*ifp->if_start)(ifp);
    786 }
    787 
    788 static void cbq_purge(cbqp)
    789 	cbq_state_t *cbqp;
    790 {
    791 	struct rm_class	*cl;
    792 	int 		i;
    793 
    794 	for (i = 0; i < CBQ_MAX_CLASSES; i++)
    795 		if ((cl = cbqp->cbq_class_tbl[i]) != NULL)
    796 			rmc_dropall(cl);
    797 	if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_))
    798 		cbqp->ifnp.ifq_->ifq_len = 0;
    799 }
    800 
    801 /*
    802  * cbq device interface
    803  */
    804 
    805 altqdev_decl(cbq);
    806 
    807 int
    808 cbqopen(dev, flag, fmt, p)
    809 	dev_t dev;
    810 	int flag, fmt;
    811 	struct proc *p;
    812 {
    813 	return (0);
    814 }
    815 
    816 int
    817 cbqclose(dev, flag, fmt, p)
    818 	dev_t dev;
    819 	int flag, fmt;
    820 	struct proc *p;
    821 {
    822 	struct ifnet *ifp;
    823 	struct cbq_interface iface;
    824 	int err, error = 0;
    825 
    826 	while (cbq_list) {
    827 		ifp = cbq_list->ifnp.ifq_->altq_ifp;
    828 #if defined(__NetBSD__) || defined(__OpenBSD__)
    829 		sprintf(iface.cbq_ifacename, "%s", ifp->if_xname);
    830 #else
    831 		sprintf(iface.cbq_ifacename,
    832 			"%s%d", ifp->if_name, ifp->if_unit);
    833 #endif
    834 		err = cbq_ifdetach(&iface);
    835 		if (err != 0 && error == 0)
    836 			error = err;
    837 	}
    838 
    839 	return (error);
    840 }
    841 
    842 int
    843 cbqioctl(dev, cmd, addr, flag, p)
    844 	dev_t dev;
    845 	ioctlcmd_t cmd;
    846 	caddr_t addr;
    847 	int flag;
    848 	struct proc *p;
    849 {
    850 	int	error = 0;
    851 
    852 	/* check cmd for superuser only */
    853 	switch (cmd) {
    854 	case CBQ_GETSTATS:
    855 		/* currently only command that an ordinary user can call */
    856 		break;
    857 	default:
    858 #if (__FreeBSD_version > 400000)
    859 		error = suser(p);
    860 #else
    861 		error = suser(p->p_ucred, &p->p_acflag);
    862 #endif
    863 		if (error)
    864 			return (error);
    865 		break;
    866 	}
    867 
    868 	switch (cmd) {
    869 
    870 	case CBQ_ENABLE:
    871 		error = cbq_set_enable((struct cbq_interface *)addr, ENABLE);
    872 		break;
    873 
    874 	case CBQ_DISABLE:
    875 		error = cbq_set_enable((struct cbq_interface *)addr, DISABLE);
    876 		break;
    877 
    878 	case CBQ_ADD_FILTER:
    879 		error = cbq_add_filter((struct cbq_add_filter *)addr);
    880 		break;
    881 
    882 	case CBQ_DEL_FILTER:
    883 		error = cbq_delete_filter((struct cbq_delete_filter *)addr);
    884 		break;
    885 
    886 	case CBQ_ADD_CLASS:
    887 		error = cbq_add_class((struct cbq_add_class *)addr);
    888 		break;
    889 
    890 	case CBQ_DEL_CLASS:
    891 		error = cbq_delete_class((struct cbq_delete_class *)addr);
    892 		break;
    893 
    894 	case CBQ_MODIFY_CLASS:
    895 		error = cbq_modify_class((struct cbq_modify_class *)addr);
    896 		break;
    897 
    898 	case CBQ_CLEAR_HIERARCHY:
    899 		error = cbq_clear_hierarchy((struct cbq_interface *)addr);
    900 		break;
    901 
    902 	case CBQ_IF_ATTACH:
    903 		error = cbq_ifattach((struct cbq_interface *)addr);
    904 		break;
    905 
    906 	case CBQ_IF_DETACH:
    907 		error = cbq_ifdetach((struct cbq_interface *)addr);
    908 		break;
    909 
    910 	case CBQ_GETSTATS:
    911 		error = cbq_getstats((struct cbq_getstats *)addr);
    912 		break;
    913 
    914 	default:
    915 		error = EINVAL;
    916 		break;
    917 	}
    918 
    919 	return error;
    920 }
    921 
    922 #if 0
    923 /* for debug */
    924 static void cbq_class_dump(int);
    925 
    926 static void cbq_class_dump(i)
    927 	int i;
    928 {
    929 	struct rm_class *cl;
    930 	rm_class_stats_t *s;
    931 	struct _class_queue_ *q;
    932 
    933 	if (cbq_list == NULL) {
    934 		printf("cbq_class_dump: no cbq_state found\n");
    935 		return;
    936 	}
    937 	cl = cbq_list->cbq_class_tbl[i];
    938 
    939 	printf("class %d cl=%p\n", i, cl);
    940 	if (cl != NULL) {
    941 		s = &cl->stats_;
    942 		q = cl->q_;
    943 
    944 		printf("pri=%d, depth=%d, maxrate=%d, allotment=%d\n",
    945 		       cl->pri_, cl->depth_, cl->maxrate_, cl->allotment_);
    946 		printf("w_allotment=%d, bytes_alloc=%d, avgidle=%d, maxidle=%d\n",
    947 		       cl->w_allotment_, cl->bytes_alloc_, cl->avgidle_,
    948 		       cl->maxidle_);
    949 		printf("minidle=%d, offtime=%d, sleeping=%d, leaf=%d\n",
    950 		       cl->minidle_, cl->offtime_, cl->sleeping_, cl->leaf_);
    951 		printf("handle=%d, depth=%d, packets=%d, bytes=%d\n",
    952 		       s->handle, s->depth,
    953 		       (int)s->xmit_cnt.packets, (int)s->xmit_cnt.bytes);
    954 		printf("over=%d\n, borrows=%d, drops=%d, overactions=%d, delays=%d\n",
    955 		       s->over, s->borrows, (int)s->drop_cnt.packets,
    956 		       s->overactions, s->delays);
    957 		printf("tail=%p, head=%p, qlen=%d, qlim=%d, qthresh=%d,qtype=%d\n",
    958 		       q->tail_, q->head_, q->qlen_, q->qlim_,
    959 		       q->qthresh_, q->qtype_);
    960 	}
    961 }
    962 #endif /* 0 */
    963 
    964 #ifdef KLD_MODULE
    965 
    966 static struct altqsw cbq_sw =
    967 	{"cbq", cbqopen, cbqclose, cbqioctl};
    968 
    969 ALTQ_MODULE(altq_cbq, ALTQT_CBQ, &cbq_sw);
    970 
    971 #endif /* KLD_MODULE */
    972 
    973 #endif /* ALTQ_CBQ */
    974