The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/altq/altq_cbq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 929606f5739f8114eaa2f5197e20e2a2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.