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