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