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

Cache object: f4e696e299bd0d69f33e88f0383e1875


[ 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.