Home | History | Annotate | Line # | Download | only in altq
altq_cbq.c revision 1.24
      1  1.24  christos /*	$NetBSD: altq_cbq.c,v 1.24 2007/03/04 05:59:00 christos 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.24  christos __KERNEL_RCSID(0, "$NetBSD: altq_cbq.c,v 1.24 2007/03/04 05:59:00 christos 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.23  christos cbq_request(struct ifaltq *ifq, int req, void *arg)
    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.22     peter 	int		i, error;
    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.22     peter 		error = rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp,
    393  1.22     peter 		    opts->ns_per_byte, cbqrestart, a->qlimit, RM_MAXQUEUED,
    394  1.19     peter 		    opts->maxidle, opts->minidle, opts->offtime,
    395  1.19     peter 		    opts->flags);
    396  1.22     peter 		if (error != 0)
    397  1.22     peter 			return (error);
    398  1.19     peter 		cl = cbqp->ifnp.root_;
    399  1.19     peter 	} else {
    400  1.19     peter 		cl = rmc_newclass(a->priority,
    401  1.19     peter 				  &cbqp->ifnp, opts->ns_per_byte,
    402  1.19     peter 				  rmc_delay_action, a->qlimit, parent, borrow,
    403  1.19     peter 				  opts->maxidle, opts->minidle, opts->offtime,
    404  1.19     peter 				  opts->pktsize, opts->flags);
    405  1.19     peter 	}
    406  1.19     peter 	if (cl == NULL)
    407  1.19     peter 		return (ENOMEM);
    408  1.19     peter 
    409  1.19     peter 	/* return handle to user space. */
    410  1.19     peter 	cl->stats_.handle = a->qid;
    411  1.19     peter 	cl->stats_.depth = cl->depth_;
    412  1.19     peter 
    413  1.19     peter 	/* save the allocated class */
    414  1.19     peter 	cbqp->cbq_class_tbl[i] = cl;
    415  1.19     peter 
    416  1.19     peter 	if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS)
    417  1.19     peter 		cbqp->ifnp.default_ = cl;
    418  1.19     peter 
    419  1.19     peter 	return (0);
    420  1.19     peter }
    421  1.19     peter 
    422  1.19     peter int
    423  1.19     peter cbq_remove_queue(struct pf_altq *a)
    424  1.19     peter {
    425  1.19     peter 	struct rm_class	*cl;
    426  1.19     peter 	cbq_state_t	*cbqp;
    427  1.19     peter 	int		i;
    428  1.19     peter 
    429  1.19     peter 	if ((cbqp = a->altq_disc) == NULL)
    430  1.19     peter 		return (EINVAL);
    431  1.19     peter 
    432  1.19     peter 	if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
    433  1.19     peter 		return (EINVAL);
    434  1.19     peter 
    435  1.19     peter 	/* if we are a parent class, then return an error. */
    436  1.19     peter 	if (is_a_parent_class(cl))
    437  1.19     peter 		return (EINVAL);
    438  1.19     peter 
    439  1.19     peter 	/* delete the class */
    440  1.19     peter 	rmc_delete_class(&cbqp->ifnp, cl);
    441  1.19     peter 
    442  1.19     peter 	/*
    443  1.19     peter 	 * free the class handle
    444  1.19     peter 	 */
    445  1.19     peter 	for (i = 0; i < CBQ_MAX_CLASSES; i++)
    446  1.19     peter 		if (cbqp->cbq_class_tbl[i] == cl) {
    447  1.19     peter 			cbqp->cbq_class_tbl[i] = NULL;
    448  1.19     peter 			if (cl == cbqp->ifnp.root_)
    449  1.19     peter 				cbqp->ifnp.root_ = NULL;
    450  1.19     peter 			if (cl == cbqp->ifnp.default_)
    451  1.19     peter 				cbqp->ifnp.default_ = NULL;
    452  1.19     peter 			break;
    453  1.19     peter 		}
    454  1.19     peter 
    455  1.19     peter 	return (0);
    456  1.19     peter }
    457  1.19     peter 
    458  1.19     peter int
    459  1.19     peter cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
    460  1.19     peter {
    461  1.19     peter 	cbq_state_t	*cbqp;
    462  1.19     peter 	struct rm_class	*cl;
    463  1.19     peter 	class_stats_t	 stats;
    464  1.19     peter 	int		 error = 0;
    465  1.19     peter 
    466  1.19     peter 	if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
    467  1.19     peter 		return (EBADF);
    468  1.19     peter 
    469  1.19     peter 	if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
    470  1.19     peter 		return (EINVAL);
    471  1.19     peter 
    472  1.19     peter 	if (*nbytes < sizeof(stats))
    473  1.19     peter 		return (EINVAL);
    474  1.19     peter 
    475  1.19     peter 	get_class_stats(&stats, cl);
    476  1.19     peter 
    477  1.24  christos 	if ((error = copyout((void *)&stats, ubuf, sizeof(stats))) != 0)
    478  1.19     peter 		return (error);
    479  1.19     peter 	*nbytes = sizeof(stats);
    480  1.19     peter 	return (0);
    481  1.19     peter }
    482  1.20     peter #endif /* NPF > 0 */
    483  1.19     peter 
    484  1.19     peter /*
    485  1.19     peter  * int
    486  1.19     peter  * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
    487  1.19     peter  *		- Queue data packets.
    488  1.19     peter  *
    489  1.19     peter  *	cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
    490  1.19     peter  *	layer (e.g. ether_output).  cbq_enqueue queues the given packet
    491  1.19     peter  *	to the cbq, then invokes the driver's start routine.
    492  1.19     peter  *
    493  1.19     peter  *	Assumptions:	called in splnet
    494  1.19     peter  *	Returns:	0 if the queueing is successful.
    495  1.19     peter  *			ENOBUFS if a packet dropping occurred as a result of
    496  1.19     peter  *			the queueing.
    497  1.19     peter  */
    498  1.19     peter 
    499  1.19     peter static int
    500  1.19     peter cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
    501  1.19     peter {
    502  1.19     peter 	cbq_state_t	*cbqp = (cbq_state_t *)ifq->altq_disc;
    503  1.19     peter 	struct rm_class	*cl;
    504  1.19     peter 	struct m_tag	*t;
    505  1.19     peter 	int		 len;
    506  1.19     peter 
    507  1.19     peter 	/* grab class set by classifier */
    508  1.19     peter 	if ((m->m_flags & M_PKTHDR) == 0) {
    509  1.19     peter 		/* should not happen */
    510  1.19     peter 		printf("altq: packet for %s does not have pkthdr\n",
    511  1.19     peter 		    ifq->altq_ifp->if_xname);
    512  1.19     peter 		m_freem(m);
    513  1.19     peter 		return (ENOBUFS);
    514  1.19     peter 	}
    515  1.19     peter 	cl = NULL;
    516  1.19     peter 	if ((t = m_tag_find(m, PACKET_TAG_PF_QID, NULL)) != NULL)
    517  1.19     peter 		cl = clh_to_clp(cbqp, ((struct altq_tag *)(t+1))->qid);
    518  1.19     peter #ifdef ALTQ3_COMPAT
    519  1.19     peter 	else if ((ifq->altq_flags & ALTQF_CLASSIFY) && pktattr != NULL)
    520  1.19     peter 		cl = pktattr->pattr_class;
    521  1.19     peter #endif
    522  1.19     peter 	if (cl == NULL) {
    523  1.19     peter 		cl = cbqp->ifnp.default_;
    524  1.19     peter 		if (cl == NULL) {
    525  1.19     peter 			m_freem(m);
    526  1.19     peter 			return (ENOBUFS);
    527  1.19     peter 		}
    528  1.19     peter 	}
    529  1.19     peter #ifdef ALTQ3_COMPAT
    530  1.19     peter 	if (pktattr != NULL)
    531  1.19     peter 		cl->pktattr_ = pktattr;  /* save proto hdr used by ECN */
    532  1.19     peter 	else
    533  1.19     peter #endif
    534  1.19     peter 		cl->pktattr_ = NULL;
    535  1.19     peter 	len = m_pktlen(m);
    536  1.19     peter 	if (rmc_queue_packet(cl, m) != 0) {
    537  1.19     peter 		/* drop occurred.  some mbuf was freed in rmc_queue_packet. */
    538  1.19     peter 		PKTCNTR_ADD(&cl->stats_.drop_cnt, len);
    539  1.19     peter 		return (ENOBUFS);
    540  1.19     peter 	}
    541  1.19     peter 
    542  1.19     peter 	/* successfully queued. */
    543  1.19     peter 	++cbqp->cbq_qlen;
    544  1.19     peter 	IFQ_INC_LEN(ifq);
    545  1.19     peter 	return (0);
    546  1.19     peter }
    547  1.19     peter 
    548  1.19     peter static struct mbuf *
    549  1.19     peter cbq_dequeue(struct ifaltq *ifq, int op)
    550  1.19     peter {
    551  1.19     peter 	cbq_state_t	*cbqp = (cbq_state_t *)ifq->altq_disc;
    552  1.19     peter 	struct mbuf	*m;
    553  1.19     peter 
    554  1.19     peter 	m = rmc_dequeue_next(&cbqp->ifnp, op);
    555  1.19     peter 
    556  1.19     peter 	if (m && op == ALTDQ_REMOVE) {
    557  1.19     peter 		--cbqp->cbq_qlen;  /* decrement # of packets in cbq */
    558  1.19     peter 		IFQ_DEC_LEN(ifq);
    559  1.19     peter 
    560  1.19     peter 		/* Update the class. */
    561  1.19     peter 		rmc_update_class_util(&cbqp->ifnp);
    562  1.19     peter 	}
    563  1.19     peter 	return (m);
    564  1.19     peter }
    565  1.19     peter 
    566  1.19     peter /*
    567  1.19     peter  * void
    568  1.19     peter  * cbqrestart(queue_t *) - Restart sending of data.
    569  1.19     peter  * called from rmc_restart in splnet via timeout after waking up
    570  1.19     peter  * a suspended class.
    571  1.19     peter  *	Returns:	NONE
    572  1.19     peter  */
    573  1.19     peter 
    574  1.19     peter static void
    575  1.19     peter cbqrestart(struct ifaltq *ifq)
    576  1.19     peter {
    577  1.19     peter 	cbq_state_t	*cbqp;
    578  1.19     peter 	struct ifnet	*ifp;
    579  1.19     peter 
    580  1.19     peter 	if (!ALTQ_IS_ENABLED(ifq))
    581  1.19     peter 		/* cbq must have been detached */
    582  1.19     peter 		return;
    583  1.19     peter 
    584  1.19     peter 	if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL)
    585  1.19     peter 		/* should not happen */
    586  1.19     peter 		return;
    587  1.19     peter 
    588  1.19     peter 	ifp = ifq->altq_ifp;
    589  1.19     peter 	if (ifp->if_start &&
    590  1.19     peter 	    cbqp->cbq_qlen > 0 && (ifp->if_flags & IFF_OACTIVE) == 0)
    591  1.19     peter 		(*ifp->if_start)(ifp);
    592  1.19     peter }
    593   1.1   thorpej 
    594  1.19     peter static void
    595  1.19     peter cbq_purge(cbq_state_t *cbqp)
    596  1.19     peter {
    597  1.19     peter 	struct rm_class	*cl;
    598  1.19     peter 	int		 i;
    599   1.1   thorpej 
    600  1.19     peter 	for (i = 0; i < CBQ_MAX_CLASSES; i++)
    601  1.19     peter 		if ((cl = cbqp->cbq_class_tbl[i]) != NULL)
    602  1.19     peter 			rmc_dropall(cl);
    603  1.19     peter 	if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_))
    604  1.19     peter 		cbqp->ifnp.ifq_->ifq_len = 0;
    605  1.19     peter }
    606  1.19     peter #ifdef ALTQ3_COMPAT
    607   1.1   thorpej 
    608   1.1   thorpej static int
    609  1.19     peter cbq_add_class(struct cbq_add_class *acp)
    610   1.1   thorpej {
    611   1.1   thorpej 	char		*ifacename;
    612   1.1   thorpej 	struct rm_class	*borrow, *parent;
    613   1.1   thorpej 	cbq_state_t	*cbqp;
    614   1.1   thorpej 
    615   1.1   thorpej 	ifacename = acp->cbq_iface.cbq_ifacename;
    616   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    617   1.1   thorpej 		return (EBADF);
    618   1.1   thorpej 
    619   1.1   thorpej 	/* check parameters */
    620   1.7    itojun 	if (acp->cbq_class.priority >= CBQ_MAXPRI ||
    621   1.1   thorpej 	    acp->cbq_class.maxq > CBQ_MAXQSIZE)
    622   1.1   thorpej 		return (EINVAL);
    623   1.1   thorpej 
    624   1.1   thorpej 	/* Get pointers to parent and borrow classes.  */
    625   1.1   thorpej 	parent = clh_to_clp(cbqp, acp->cbq_class.parent_class_handle);
    626   1.1   thorpej 	borrow = clh_to_clp(cbqp, acp->cbq_class.borrow_class_handle);
    627   1.1   thorpej 
    628   1.1   thorpej 	/*
    629   1.1   thorpej 	 * A class must borrow from it's parent or it can not
    630   1.1   thorpej 	 * borrow at all.  Hence, borrow can be null.
    631   1.1   thorpej 	 */
    632   1.1   thorpej 	if (parent == NULL && (acp->cbq_class.flags & CBQCLF_ROOTCLASS) == 0) {
    633   1.1   thorpej 		printf("cbq_add_class: no parent class!\n");
    634   1.1   thorpej 		return (EINVAL);
    635   1.1   thorpej 	}
    636   1.1   thorpej 
    637   1.1   thorpej 	if ((borrow != parent)  && (borrow != NULL)) {
    638   1.1   thorpej 		printf("cbq_add_class: borrow class != parent\n");
    639   1.1   thorpej 		return (EINVAL);
    640   1.1   thorpej 	}
    641   1.1   thorpej 
    642   1.1   thorpej 	return cbq_class_create(cbqp, acp, parent, borrow);
    643   1.1   thorpej }
    644   1.1   thorpej 
    645   1.1   thorpej static int
    646  1.19     peter cbq_delete_class(struct cbq_delete_class *dcp)
    647   1.1   thorpej {
    648   1.1   thorpej 	char		*ifacename;
    649   1.1   thorpej 	struct rm_class	*cl;
    650   1.1   thorpej 	cbq_state_t	*cbqp;
    651   1.1   thorpej 
    652   1.1   thorpej 	ifacename = dcp->cbq_iface.cbq_ifacename;
    653   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    654   1.1   thorpej 		return (EBADF);
    655   1.1   thorpej 
    656   1.1   thorpej 	if ((cl = clh_to_clp(cbqp, dcp->cbq_class_handle)) == NULL)
    657   1.1   thorpej 		return (EINVAL);
    658   1.1   thorpej 
    659   1.1   thorpej 	/* if we are a parent class, then return an error. */
    660   1.1   thorpej 	if (is_a_parent_class(cl))
    661   1.1   thorpej 		return (EINVAL);
    662   1.1   thorpej 
    663   1.1   thorpej 	/* if a filter has a reference to this class delete the filter */
    664   1.1   thorpej 	acc_discard_filters(&cbqp->cbq_classifier, cl, 0);
    665   1.1   thorpej 
    666   1.1   thorpej 	return cbq_class_destroy(cbqp, cl);
    667   1.1   thorpej }
    668   1.1   thorpej 
    669   1.1   thorpej static int
    670  1.19     peter cbq_modify_class(struct cbq_modify_class *acp)
    671   1.1   thorpej {
    672   1.1   thorpej 	char		*ifacename;
    673   1.1   thorpej 	struct rm_class	*cl;
    674   1.1   thorpej 	cbq_state_t	*cbqp;
    675   1.1   thorpej 
    676   1.1   thorpej 	ifacename = acp->cbq_iface.cbq_ifacename;
    677   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    678   1.1   thorpej 		return (EBADF);
    679   1.1   thorpej 
    680   1.1   thorpej 	/* Get pointer to this class */
    681   1.1   thorpej 	if ((cl = clh_to_clp(cbqp, acp->cbq_class_handle)) == NULL)
    682   1.1   thorpej 		return (EINVAL);
    683   1.1   thorpej 
    684   1.1   thorpej 	if (rmc_modclass(cl, acp->cbq_class.nano_sec_per_byte,
    685   1.1   thorpej 			 acp->cbq_class.maxq, acp->cbq_class.maxidle,
    686   1.1   thorpej 			 acp->cbq_class.minidle, acp->cbq_class.offtime,
    687   1.1   thorpej 			 acp->cbq_class.pktsize) < 0)
    688   1.1   thorpej 		return (EINVAL);
    689   1.1   thorpej 	return (0);
    690   1.1   thorpej }
    691   1.1   thorpej 
    692   1.1   thorpej /*
    693   1.1   thorpej  * struct rm_class *
    694   1.1   thorpej  * cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp,
    695  1.19     peter  *		struct rm_class *parent, struct rm_class *borrow)
    696   1.1   thorpej  *
    697   1.1   thorpej  * This function create a new traffic class in the CBQ class hierarchy of
    698  1.19     peter  * given paramters.  The class that created is either the root, default,
    699  1.19     peter  * or a new dynamic class.  If CBQ is not initilaized, the the root class
    700  1.19     peter  * will be created.
    701   1.1   thorpej  */
    702   1.1   thorpej static int
    703  1.19     peter cbq_class_create(cbq_state_t *cbqp, struct cbq_add_class *acp,
    704  1.19     peter     struct rm_class *parent, struct rm_class *borrow)
    705   1.1   thorpej {
    706   1.1   thorpej 	struct rm_class	*cl;
    707   1.1   thorpej 	cbq_class_spec_t *spec = &acp->cbq_class;
    708  1.19     peter 	u_int32_t	chandle;
    709  1.22     peter 	int		i, error;
    710   1.1   thorpej 
    711   1.1   thorpej 	/*
    712   1.1   thorpej 	 * allocate class handle
    713   1.1   thorpej 	 */
    714  1.19     peter 	for (i = 1; i < CBQ_MAX_CLASSES; i++)
    715  1.19     peter 		if (cbqp->cbq_class_tbl[i] == NULL)
    716  1.19     peter 			break;
    717  1.19     peter 	if (i == CBQ_MAX_CLASSES)
    718   1.1   thorpej 		return (EINVAL);
    719  1.19     peter 	chandle = i;	/* use the slot number as class handle */
    720   1.1   thorpej 
    721   1.1   thorpej 	/*
    722   1.1   thorpej 	 * create a class.  if this is a root class, initialize the
    723   1.1   thorpej 	 * interface.
    724   1.1   thorpej 	 */
    725  1.19     peter 	if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) {
    726  1.22     peter 		error = rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp,
    727  1.22     peter 		    spec->nano_sec_per_byte, cbqrestart, spec->maxq,
    728  1.22     peter 		    RM_MAXQUEUED, spec->maxidle, spec->minidle, spec->offtime,
    729  1.22     peter 		    spec->flags);
    730  1.22     peter 		if (error)
    731  1.22     peter 			return (error);
    732   1.1   thorpej 		cl = cbqp->ifnp.root_;
    733   1.1   thorpej 	} else {
    734   1.1   thorpej 		cl = rmc_newclass(spec->priority,
    735   1.1   thorpej 				  &cbqp->ifnp, spec->nano_sec_per_byte,
    736   1.1   thorpej 				  rmc_delay_action, spec->maxq, parent, borrow,
    737   1.1   thorpej 				  spec->maxidle, spec->minidle, spec->offtime,
    738   1.1   thorpej 				  spec->pktsize, spec->flags);
    739   1.1   thorpej 	}
    740   1.1   thorpej 	if (cl == NULL)
    741   1.1   thorpej 		return (ENOMEM);
    742   1.1   thorpej 
    743   1.1   thorpej 	/* return handle to user space. */
    744   1.1   thorpej 	acp->cbq_class_handle = chandle;
    745   1.1   thorpej 
    746   1.1   thorpej 	cl->stats_.handle = chandle;
    747   1.1   thorpej 	cl->stats_.depth = cl->depth_;
    748   1.1   thorpej 
    749   1.1   thorpej 	/* save the allocated class */
    750  1.19     peter 	cbqp->cbq_class_tbl[i] = cl;
    751  1.19     peter 
    752  1.19     peter 	if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS)
    753   1.1   thorpej 		cbqp->ifnp.default_ = cl;
    754  1.19     peter 	if ((spec->flags & CBQCLF_CLASSMASK) == CBQCLF_CTLCLASS)
    755   1.1   thorpej 		cbqp->ifnp.ctl_ = cl;
    756   1.1   thorpej 
    757   1.1   thorpej 	return (0);
    758   1.1   thorpej }
    759   1.1   thorpej 
    760   1.1   thorpej static int
    761  1.19     peter cbq_add_filter(struct cbq_add_filter *afp)
    762   1.1   thorpej {
    763   1.1   thorpej 	char		*ifacename;
    764   1.1   thorpej 	cbq_state_t	*cbqp;
    765   1.1   thorpej 	struct rm_class	*cl;
    766   1.1   thorpej 
    767   1.1   thorpej 	ifacename = afp->cbq_iface.cbq_ifacename;
    768   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    769   1.1   thorpej 		return (EBADF);
    770   1.1   thorpej 
    771   1.1   thorpej 	/* Get the pointer to class. */
    772   1.1   thorpej 	if ((cl = clh_to_clp(cbqp, afp->cbq_class_handle)) == NULL)
    773   1.1   thorpej 		return (EINVAL);
    774   1.1   thorpej 
    775   1.1   thorpej 	return acc_add_filter(&cbqp->cbq_classifier, &afp->cbq_filter,
    776   1.1   thorpej 			      cl, &afp->cbq_filter_handle);
    777   1.1   thorpej }
    778   1.1   thorpej 
    779   1.1   thorpej static int
    780  1.19     peter cbq_delete_filter(struct cbq_delete_filter *dfp)
    781   1.1   thorpej {
    782   1.1   thorpej 	char		*ifacename;
    783   1.1   thorpej 	cbq_state_t	*cbqp;
    784  1.11     perry 
    785   1.1   thorpej 	ifacename = dfp->cbq_iface.cbq_ifacename;
    786   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    787   1.1   thorpej 		return (EBADF);
    788  1.11     perry 
    789   1.1   thorpej 	return acc_delete_filter(&cbqp->cbq_classifier,
    790   1.1   thorpej 				 dfp->cbq_filter_handle);
    791   1.1   thorpej }
    792   1.1   thorpej 
    793   1.1   thorpej /*
    794   1.1   thorpej  * cbq_clear_hierarchy deletes all classes and their filters on the
    795   1.1   thorpej  * given interface.
    796   1.1   thorpej  */
    797   1.1   thorpej static int
    798  1.19     peter cbq_clear_hierarchy(struct cbq_interface *ifacep)
    799   1.1   thorpej {
    800   1.1   thorpej 	char		*ifacename;
    801   1.1   thorpej 	cbq_state_t	*cbqp;
    802   1.1   thorpej 
    803   1.1   thorpej 	ifacename = ifacep->cbq_ifacename;
    804   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    805   1.1   thorpej 		return (EBADF);
    806   1.1   thorpej 
    807   1.1   thorpej 	return cbq_clear_interface(cbqp);
    808   1.1   thorpej }
    809   1.1   thorpej 
    810   1.1   thorpej /*
    811   1.1   thorpej  * static int
    812   1.1   thorpej  * cbq_set_enable(struct cbq_enable *ep) - this function processed the
    813   1.1   thorpej  *	ioctl request to enable class based queueing.  It searches the list
    814   1.1   thorpej  *	of interfaces for the specified interface and then enables CBQ on
    815   1.1   thorpej  *	that interface.
    816   1.1   thorpej  *
    817   1.1   thorpej  *	Returns:	0, for no error.
    818   1.1   thorpej  *			EBADF, for specified inteface not found.
    819   1.1   thorpej  */
    820   1.1   thorpej 
    821   1.1   thorpej static int
    822  1.19     peter cbq_set_enable(struct cbq_interface *ep, int enable)
    823   1.1   thorpej {
    824   1.1   thorpej 	int 	error = 0;
    825   1.1   thorpej 	cbq_state_t	*cbqp;
    826   1.1   thorpej 	char 	*ifacename;
    827   1.1   thorpej 
    828   1.1   thorpej 	ifacename = ep->cbq_ifacename;
    829   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    830   1.1   thorpej 		return (EBADF);
    831   1.1   thorpej 
    832   1.1   thorpej 	switch (enable) {
    833   1.1   thorpej 	case ENABLE:
    834   1.1   thorpej 		if (cbqp->ifnp.root_ == NULL || cbqp->ifnp.default_ == NULL ||
    835   1.1   thorpej 		    cbqp->ifnp.ctl_ == 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 			if (cbqp->ifnp.ctl_ == NULL)
    841   1.1   thorpej 				printf("No Control Class for %s\n", ifacename);
    842   1.1   thorpej 			error = EINVAL;
    843   1.1   thorpej 		} else if ((error = altq_enable(cbqp->ifnp.ifq_)) == 0) {
    844   1.1   thorpej 			cbqp->cbq_qlen = 0;
    845   1.1   thorpej 		}
    846   1.1   thorpej 		break;
    847   1.1   thorpej 
    848   1.1   thorpej 	case DISABLE:
    849   1.1   thorpej 		error = altq_disable(cbqp->ifnp.ifq_);
    850   1.1   thorpej 		break;
    851   1.1   thorpej 	}
    852   1.1   thorpej 	return (error);
    853   1.1   thorpej }
    854   1.1   thorpej 
    855   1.1   thorpej static int
    856  1.19     peter cbq_getstats(struct cbq_getstats *gsp)
    857   1.1   thorpej {
    858   1.1   thorpej 	char		*ifacename;
    859  1.19     peter 	int		i, n, nclasses;
    860   1.1   thorpej 	cbq_state_t	*cbqp;
    861   1.1   thorpej 	struct rm_class	*cl;
    862   1.1   thorpej 	class_stats_t	stats, *usp;
    863   1.1   thorpej 	int error = 0;
    864   1.1   thorpej 
    865   1.1   thorpej 	ifacename = gsp->iface.cbq_ifacename;
    866   1.1   thorpej 	nclasses = gsp->nclasses;
    867   1.1   thorpej 	usp = gsp->stats;
    868   1.1   thorpej 
    869   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    870   1.1   thorpej 		return (EBADF);
    871   1.1   thorpej 	if (nclasses <= 0)
    872   1.1   thorpej 		return (EINVAL);
    873   1.1   thorpej 
    874  1.19     peter 	for (n = 0, i = 0; n < nclasses && i < CBQ_MAX_CLASSES; n++, i++) {
    875  1.19     peter 		while ((cl = cbqp->cbq_class_tbl[i]) == NULL)
    876  1.19     peter 			if (++i >= CBQ_MAX_CLASSES)
    877  1.19     peter 				goto out;
    878   1.1   thorpej 
    879   1.1   thorpej 		get_class_stats(&stats, cl);
    880  1.19     peter 		stats.handle = cl->stats_.handle;
    881   1.1   thorpej 
    882  1.24  christos 		if ((error = copyout((void *)&stats, (void *)usp++,
    883  1.19     peter 		    sizeof(stats))) != 0)
    884   1.1   thorpej 			return (error);
    885   1.1   thorpej 	}
    886   1.1   thorpej 
    887   1.1   thorpej  out:
    888   1.1   thorpej 	gsp->nclasses = n;
    889   1.1   thorpej 	return (error);
    890   1.1   thorpej }
    891   1.1   thorpej 
    892   1.1   thorpej static int
    893  1.19     peter cbq_ifattach(struct cbq_interface *ifacep)
    894   1.1   thorpej {
    895   1.1   thorpej 	int		error = 0;
    896   1.1   thorpej 	char		*ifacename;
    897   1.1   thorpej 	cbq_state_t	*new_cbqp;
    898   1.1   thorpej 	struct ifnet 	*ifp;
    899   1.1   thorpej 
    900   1.1   thorpej 	ifacename = ifacep->cbq_ifacename;
    901   1.1   thorpej 	if ((ifp = ifunit(ifacename)) == NULL)
    902   1.1   thorpej 		return (ENXIO);
    903   1.1   thorpej 	if (!ALTQ_IS_READY(&ifp->if_snd))
    904   1.1   thorpej 		return (ENXIO);
    905   1.1   thorpej 
    906   1.1   thorpej 	/* allocate and initialize cbq_state_t */
    907  1.13  christos 	new_cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
    908   1.1   thorpej 	if (new_cbqp == NULL)
    909   1.1   thorpej 		return (ENOMEM);
    910   1.1   thorpej  	CALLOUT_INIT(&new_cbqp->cbq_callout);
    911  1.19     peter 
    912   1.1   thorpej 	new_cbqp->cbq_qlen = 0;
    913   1.1   thorpej 	new_cbqp->ifnp.ifq_ = &ifp->if_snd;	    /* keep the ifq */
    914  1.11     perry 
    915   1.1   thorpej 	/*
    916   1.1   thorpej 	 * set CBQ to this ifnet structure.
    917   1.1   thorpej 	 */
    918   1.1   thorpej 	error = altq_attach(&ifp->if_snd, ALTQT_CBQ, new_cbqp,
    919   1.1   thorpej 			    cbq_enqueue, cbq_dequeue, cbq_request,
    920   1.1   thorpej 			    &new_cbqp->cbq_classifier, acc_classify);
    921   1.1   thorpej 	if (error) {
    922  1.14  christos 		free(new_cbqp, M_DEVBUF);
    923   1.1   thorpej 		return (error);
    924   1.1   thorpej 	}
    925   1.1   thorpej 
    926   1.1   thorpej 	/* prepend to the list of cbq_state_t's. */
    927   1.1   thorpej 	new_cbqp->cbq_next = cbq_list;
    928   1.1   thorpej 	cbq_list = new_cbqp;
    929   1.1   thorpej 
    930   1.1   thorpej 	return (0);
    931   1.1   thorpej }
    932   1.1   thorpej 
    933   1.1   thorpej static int
    934  1.19     peter cbq_ifdetach(struct cbq_interface *ifacep)
    935   1.1   thorpej {
    936   1.1   thorpej 	char		*ifacename;
    937   1.1   thorpej 	cbq_state_t 	*cbqp;
    938   1.1   thorpej 
    939   1.1   thorpej 	ifacename = ifacep->cbq_ifacename;
    940   1.1   thorpej 	if ((cbqp = altq_lookup(ifacename, ALTQT_CBQ)) == NULL)
    941   1.1   thorpej 		return (EBADF);
    942   1.1   thorpej 
    943   1.1   thorpej 	(void)cbq_set_enable(ifacep, DISABLE);
    944   1.1   thorpej 
    945   1.1   thorpej 	cbq_clear_interface(cbqp);
    946   1.1   thorpej 
    947   1.1   thorpej 	/* remove CBQ from the ifnet structure. */
    948   1.1   thorpej 	(void)altq_detach(cbqp->ifnp.ifq_);
    949   1.1   thorpej 
    950   1.1   thorpej 	/* remove from the list of cbq_state_t's. */
    951   1.1   thorpej 	if (cbq_list == cbqp)
    952   1.1   thorpej 		cbq_list = cbqp->cbq_next;
    953   1.1   thorpej 	else {
    954   1.1   thorpej 		cbq_state_t *cp;
    955   1.1   thorpej 
    956   1.6    itojun 		for (cp = cbq_list; cp != NULL; cp = cp->cbq_next)
    957   1.1   thorpej 			if (cp->cbq_next == cbqp) {
    958   1.1   thorpej 				cp->cbq_next = cbqp->cbq_next;
    959   1.1   thorpej 				break;
    960   1.1   thorpej 			}
    961   1.1   thorpej 		ASSERT(cp != NULL);
    962   1.1   thorpej 	}
    963   1.1   thorpej 
    964   1.1   thorpej 	/* deallocate cbq_state_t */
    965  1.14  christos 	free(cbqp, M_DEVBUF);
    966   1.1   thorpej 
    967   1.1   thorpej 	return (0);
    968   1.1   thorpej }
    969   1.1   thorpej 
    970   1.1   thorpej /*
    971   1.1   thorpej  * cbq device interface
    972   1.1   thorpej  */
    973   1.1   thorpej 
    974   1.1   thorpej altqdev_decl(cbq);
    975   1.1   thorpej 
    976   1.1   thorpej int
    977  1.23  christos cbqopen(dev_t dev, int flag, int fmt,
    978  1.23  christos     struct lwp *l)
    979   1.1   thorpej {
    980   1.1   thorpej 	return (0);
    981   1.1   thorpej }
    982   1.1   thorpej 
    983   1.1   thorpej int
    984  1.23  christos cbqclose(dev_t dev, int flag, int fmt,
    985  1.23  christos     struct lwp *l)
    986   1.1   thorpej {
    987   1.1   thorpej 	struct ifnet *ifp;
    988   1.1   thorpej 	struct cbq_interface iface;
    989   1.1   thorpej 	int err, error = 0;
    990   1.1   thorpej 
    991   1.1   thorpej 	while (cbq_list) {
    992   1.1   thorpej 		ifp = cbq_list->ifnp.ifq_->altq_ifp;
    993   1.1   thorpej 		sprintf(iface.cbq_ifacename, "%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.1   thorpej 	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.1   thorpej #if (__FreeBSD_version > 400000)
   1015   1.1   thorpej 		error = suser(p);
   1016   1.1   thorpej #else
   1017  1.21      elad 		error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_ALTQ,
   1018  1.21      elad 		    KAUTH_REQ_NETWORK_ALTQ_CBQ, NULL, NULL, NULL);
   1019   1.1   thorpej #endif
   1020   1.1   thorpej 		if (error)
   1021   1.1   thorpej 			return (error);
   1022   1.1   thorpej 		break;
   1023   1.1   thorpej 	}
   1024   1.1   thorpej 
   1025   1.1   thorpej 	switch (cmd) {
   1026   1.1   thorpej 
   1027   1.1   thorpej 	case CBQ_ENABLE:
   1028   1.1   thorpej 		error = cbq_set_enable((struct cbq_interface *)addr, ENABLE);
   1029   1.1   thorpej 		break;
   1030   1.1   thorpej 
   1031   1.1   thorpej 	case CBQ_DISABLE:
   1032   1.1   thorpej 		error = cbq_set_enable((struct cbq_interface *)addr, DISABLE);
   1033   1.1   thorpej 		break;
   1034   1.1   thorpej 
   1035   1.1   thorpej 	case CBQ_ADD_FILTER:
   1036   1.1   thorpej 		error = cbq_add_filter((struct cbq_add_filter *)addr);
   1037   1.1   thorpej 		break;
   1038   1.1   thorpej 
   1039   1.1   thorpej 	case CBQ_DEL_FILTER:
   1040   1.1   thorpej 		error = cbq_delete_filter((struct cbq_delete_filter *)addr);
   1041   1.1   thorpej 		break;
   1042   1.1   thorpej 
   1043   1.1   thorpej 	case CBQ_ADD_CLASS:
   1044   1.1   thorpej 		error = cbq_add_class((struct cbq_add_class *)addr);
   1045   1.1   thorpej 		break;
   1046   1.1   thorpej 
   1047   1.1   thorpej 	case CBQ_DEL_CLASS:
   1048   1.1   thorpej 		error = cbq_delete_class((struct cbq_delete_class *)addr);
   1049   1.1   thorpej 		break;
   1050   1.1   thorpej 
   1051   1.1   thorpej 	case CBQ_MODIFY_CLASS:
   1052   1.1   thorpej 		error = cbq_modify_class((struct cbq_modify_class *)addr);
   1053   1.1   thorpej 		break;
   1054   1.1   thorpej 
   1055   1.1   thorpej 	case CBQ_CLEAR_HIERARCHY:
   1056   1.1   thorpej 		error = cbq_clear_hierarchy((struct cbq_interface *)addr);
   1057   1.1   thorpej 		break;
   1058   1.1   thorpej 
   1059   1.1   thorpej 	case CBQ_IF_ATTACH:
   1060   1.1   thorpej 		error = cbq_ifattach((struct cbq_interface *)addr);
   1061   1.1   thorpej 		break;
   1062   1.1   thorpej 
   1063   1.1   thorpej 	case CBQ_IF_DETACH:
   1064   1.1   thorpej 		error = cbq_ifdetach((struct cbq_interface *)addr);
   1065   1.1   thorpej 		break;
   1066   1.1   thorpej 
   1067   1.1   thorpej 	case CBQ_GETSTATS:
   1068   1.1   thorpej 		error = cbq_getstats((struct cbq_getstats *)addr);
   1069   1.1   thorpej 		break;
   1070   1.1   thorpej 
   1071   1.1   thorpej 	default:
   1072   1.1   thorpej 		error = EINVAL;
   1073   1.1   thorpej 		break;
   1074   1.1   thorpej 	}
   1075   1.1   thorpej 
   1076   1.1   thorpej 	return error;
   1077   1.1   thorpej }
   1078   1.1   thorpej 
   1079   1.1   thorpej #if 0
   1080   1.1   thorpej /* for debug */
   1081   1.1   thorpej static void cbq_class_dump(int);
   1082   1.1   thorpej 
   1083  1.19     peter static void
   1084  1.19     peter cbq_class_dump(int i)
   1085   1.1   thorpej {
   1086   1.1   thorpej 	struct rm_class *cl;
   1087   1.1   thorpej 	rm_class_stats_t *s;
   1088   1.1   thorpej 	struct _class_queue_ *q;
   1089   1.1   thorpej 
   1090   1.1   thorpej 	if (cbq_list == NULL) {
   1091   1.1   thorpej 		printf("cbq_class_dump: no cbq_state found\n");
   1092   1.1   thorpej 		return;
   1093   1.1   thorpej 	}
   1094   1.1   thorpej 	cl = cbq_list->cbq_class_tbl[i];
   1095  1.11     perry 
   1096   1.1   thorpej 	printf("class %d cl=%p\n", i, cl);
   1097   1.1   thorpej 	if (cl != NULL) {
   1098   1.1   thorpej 		s = &cl->stats_;
   1099   1.1   thorpej 		q = cl->q_;
   1100   1.1   thorpej 
   1101   1.1   thorpej 		printf("pri=%d, depth=%d, maxrate=%d, allotment=%d\n",
   1102   1.1   thorpej 		       cl->pri_, cl->depth_, cl->maxrate_, cl->allotment_);
   1103   1.1   thorpej 		printf("w_allotment=%d, bytes_alloc=%d, avgidle=%d, maxidle=%d\n",
   1104   1.1   thorpej 		       cl->w_allotment_, cl->bytes_alloc_, cl->avgidle_,
   1105   1.1   thorpej 		       cl->maxidle_);
   1106   1.1   thorpej 		printf("minidle=%d, offtime=%d, sleeping=%d, leaf=%d\n",
   1107   1.1   thorpej 		       cl->minidle_, cl->offtime_, cl->sleeping_, cl->leaf_);
   1108   1.1   thorpej 		printf("handle=%d, depth=%d, packets=%d, bytes=%d\n",
   1109   1.1   thorpej 		       s->handle, s->depth,
   1110   1.1   thorpej 		       (int)s->xmit_cnt.packets, (int)s->xmit_cnt.bytes);
   1111   1.1   thorpej 		printf("over=%d\n, borrows=%d, drops=%d, overactions=%d, delays=%d\n",
   1112   1.1   thorpej 		       s->over, s->borrows, (int)s->drop_cnt.packets,
   1113   1.1   thorpej 		       s->overactions, s->delays);
   1114   1.1   thorpej 		printf("tail=%p, head=%p, qlen=%d, qlim=%d, qthresh=%d,qtype=%d\n",
   1115   1.1   thorpej 		       q->tail_, q->head_, q->qlen_, q->qlim_,
   1116   1.1   thorpej 		       q->qthresh_, q->qtype_);
   1117   1.1   thorpej 	}
   1118   1.1   thorpej }
   1119   1.1   thorpej #endif /* 0 */
   1120   1.1   thorpej 
   1121   1.1   thorpej #ifdef KLD_MODULE
   1122   1.1   thorpej 
   1123   1.1   thorpej static struct altqsw cbq_sw =
   1124   1.1   thorpej 	{"cbq", cbqopen, cbqclose, cbqioctl};
   1125   1.1   thorpej 
   1126   1.1   thorpej ALTQ_MODULE(altq_cbq, ALTQT_CBQ, &cbq_sw);
   1127  1.19     peter MODULE_DEPEND(altq_cbq, altq_red, 1, 1, 1);
   1128  1.19     peter MODULE_DEPEND(altq_cbq, altq_rio, 1, 1, 1);
   1129   1.1   thorpej 
   1130   1.1   thorpej #endif /* KLD_MODULE */
   1131  1.19     peter #endif /* ALTQ3_COMPAT */
   1132   1.1   thorpej 
   1133   1.1   thorpej #endif /* ALTQ_CBQ */
   1134