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/net/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 /*-
    2  * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by the SMCC Technology
   18  *      Development Group at Sun Microsystems, Inc.
   19  *
   20  * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
   21  *      promote products derived from this software without specific prior
   22  *      written permission.
   23  *
   24  * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
   25  * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is
   26  * provided "as is" without express or implied warranty of any kind.
   27  *
   28  * These notices must be retained in any copies of any part of this software.
   29  *
   30  * $KAME: altq_cbq.c,v 1.19 2003/09/17 14:23:25 kjc Exp $
   31  * $FreeBSD$
   32  */
   33 
   34 #include "opt_altq.h"
   35 #include "opt_inet.h"
   36 #include "opt_inet6.h"
   37 #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
   38 
   39 #include <sys/param.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/socket.h>
   43 #include <sys/systm.h>
   44 #include <sys/proc.h>
   45 #include <sys/errno.h>
   46 #include <sys/time.h>
   47 
   48 #include <net/if.h>
   49 #include <net/if_var.h>
   50 #include <net/if_private.h>
   51 #include <netinet/in.h>
   52 
   53 #include <netpfil/pf/pf.h>
   54 #include <netpfil/pf/pf_altq.h>
   55 #include <netpfil/pf/pf_mtag.h>
   56 #include <net/altq/altq.h>
   57 #include <net/altq/altq_cbq.h>
   58 
   59 /*
   60  * Forward Declarations.
   61  */
   62 static int               cbq_class_destroy(cbq_state_t *, struct rm_class *);
   63 static struct rm_class  *clh_to_clp(cbq_state_t *, u_int32_t);
   64 static int               cbq_clear_interface(cbq_state_t *);
   65 static int               cbq_request(struct ifaltq *, int, void *);
   66 static int               cbq_enqueue(struct ifaltq *, struct mbuf *,
   67                              struct altq_pktattr *);
   68 static struct mbuf      *cbq_dequeue(struct ifaltq *, int);
   69 static void              cbqrestart(struct ifaltq *);
   70 static void              get_class_stats(class_stats_t *, struct rm_class *);
   71 static void              cbq_purge(cbq_state_t *);
   72 
   73 /*
   74  * int
   75  * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
   76  *      function destroys a given traffic class.  Before destroying
   77  *      the class, all traffic for that class is released.
   78  */
   79 static int
   80 cbq_class_destroy(cbq_state_t *cbqp, struct rm_class *cl)
   81 {
   82         int     i;
   83 
   84         /* delete the class */
   85         rmc_delete_class(&cbqp->ifnp, cl);
   86 
   87         /*
   88          * free the class handle
   89          */
   90         for (i = 0; i < CBQ_MAX_CLASSES; i++)
   91                 if (cbqp->cbq_class_tbl[i] == cl)
   92                         cbqp->cbq_class_tbl[i] = NULL;
   93 
   94         if (cl == cbqp->ifnp.root_)
   95                 cbqp->ifnp.root_ = NULL;
   96         if (cl == cbqp->ifnp.default_)
   97                 cbqp->ifnp.default_ = NULL;
   98         return (0);
   99 }
  100 
  101 /* convert class handle to class pointer */
  102 static struct rm_class *
  103 clh_to_clp(cbq_state_t *cbqp, u_int32_t chandle)
  104 {
  105         int i;
  106         struct rm_class *cl;
  107 
  108         if (chandle == 0)
  109                 return (NULL);
  110         /*
  111          * first, try optimistically the slot matching the lower bits of
  112          * the handle.  if it fails, do the linear table search.
  113          */
  114         i = chandle % CBQ_MAX_CLASSES;
  115         if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
  116             cl->stats_.handle == chandle)
  117                 return (cl);
  118         for (i = 0; i < CBQ_MAX_CLASSES; i++)
  119                 if ((cl = cbqp->cbq_class_tbl[i]) != NULL &&
  120                     cl->stats_.handle == chandle)
  121                         return (cl);
  122         return (NULL);
  123 }
  124 
  125 static int
  126 cbq_clear_interface(cbq_state_t *cbqp)
  127 {
  128         int              again, i;
  129         struct rm_class *cl;
  130 
  131 #ifdef ALTQ3_CLFIER_COMPAT
  132         /* free the filters for this interface */
  133         acc_discard_filters(&cbqp->cbq_classifier, NULL, 1);
  134 #endif
  135 
  136         /* clear out the classes now */
  137         do {
  138                 again = 0;
  139                 for (i = 0; i < CBQ_MAX_CLASSES; i++) {
  140                         if ((cl = cbqp->cbq_class_tbl[i]) != NULL) {
  141                                 if (is_a_parent_class(cl))
  142                                         again++;
  143                                 else {
  144                                         cbq_class_destroy(cbqp, cl);
  145                                         cbqp->cbq_class_tbl[i] = NULL;
  146                                         if (cl == cbqp->ifnp.root_)
  147                                                 cbqp->ifnp.root_ = NULL;
  148                                         if (cl == cbqp->ifnp.default_)
  149                                                 cbqp->ifnp.default_ = NULL;
  150                                 }
  151                         }
  152                 }
  153         } while (again);
  154 
  155         return (0);
  156 }
  157 
  158 static int
  159 cbq_request(struct ifaltq *ifq, int req, void *arg)
  160 {
  161         cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
  162 
  163         IFQ_LOCK_ASSERT(ifq);
  164 
  165         switch (req) {
  166         case ALTRQ_PURGE:
  167                 cbq_purge(cbqp);
  168                 break;
  169         }
  170         return (0);
  171 }
  172 
  173 /* copy the stats info in rm_class to class_states_t */
  174 static void
  175 get_class_stats(class_stats_t *statsp, struct rm_class *cl)
  176 {
  177         statsp->xmit_cnt        = cl->stats_.xmit_cnt;
  178         statsp->drop_cnt        = cl->stats_.drop_cnt;
  179         statsp->over            = cl->stats_.over;
  180         statsp->borrows         = cl->stats_.borrows;
  181         statsp->overactions     = cl->stats_.overactions;
  182         statsp->delays          = cl->stats_.delays;
  183 
  184         statsp->depth           = cl->depth_;
  185         statsp->priority        = cl->pri_;
  186         statsp->maxidle         = cl->maxidle_;
  187         statsp->minidle         = cl->minidle_;
  188         statsp->offtime         = cl->offtime_;
  189         statsp->qmax            = qlimit(cl->q_);
  190         statsp->ns_per_byte     = cl->ns_per_byte_;
  191         statsp->wrr_allot       = cl->w_allotment_;
  192         statsp->qcnt            = qlen(cl->q_);
  193         statsp->avgidle         = cl->avgidle_;
  194 
  195         statsp->qtype           = qtype(cl->q_);
  196 #ifdef ALTQ_RED
  197         if (q_is_red(cl->q_))
  198                 red_getstats(cl->red_, &statsp->red[0]);
  199 #endif
  200 #ifdef ALTQ_RIO
  201         if (q_is_rio(cl->q_))
  202                 rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
  203 #endif
  204 #ifdef ALTQ_CODEL
  205         if (q_is_codel(cl->q_))
  206                 codel_getstats(cl->codel_, &statsp->codel);
  207 #endif
  208 }
  209 
  210 int
  211 cbq_pfattach(struct pf_altq *a)
  212 {
  213         struct ifnet    *ifp;
  214         int              s, error;
  215 
  216         if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
  217                 return (EINVAL);
  218         s = splnet();
  219         error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc,
  220             cbq_enqueue, cbq_dequeue, cbq_request);
  221         splx(s);
  222         return (error);
  223 }
  224 
  225 int
  226 cbq_add_altq(struct ifnet *ifp, struct pf_altq *a)
  227 {
  228         cbq_state_t     *cbqp;
  229 
  230         if (ifp == NULL)
  231                 return (EINVAL);
  232         if (!ALTQ_IS_READY(&ifp->if_snd))
  233                 return (ENODEV);
  234 
  235         /* allocate and initialize cbq_state_t */
  236         cbqp = malloc(sizeof(cbq_state_t), M_DEVBUF, M_NOWAIT | M_ZERO);
  237         if (cbqp == NULL)
  238                 return (ENOMEM);
  239         CALLOUT_INIT(&cbqp->cbq_callout);
  240         cbqp->cbq_qlen = 0;
  241         cbqp->ifnp.ifq_ = &ifp->if_snd;     /* keep the ifq */
  242 
  243         /* keep the state in pf_altq */
  244         a->altq_disc = cbqp;
  245 
  246         return (0);
  247 }
  248 
  249 int
  250 cbq_remove_altq(struct pf_altq *a)
  251 {
  252         cbq_state_t     *cbqp;
  253 
  254         if ((cbqp = a->altq_disc) == NULL)
  255                 return (EINVAL);
  256         a->altq_disc = NULL;
  257 
  258         cbq_clear_interface(cbqp);
  259 
  260         if (cbqp->ifnp.default_)
  261                 cbq_class_destroy(cbqp, cbqp->ifnp.default_);
  262         if (cbqp->ifnp.root_)
  263                 cbq_class_destroy(cbqp, cbqp->ifnp.root_);
  264 
  265         /* deallocate cbq_state_t */
  266         free(cbqp, M_DEVBUF);
  267 
  268         return (0);
  269 }
  270 
  271 int
  272 cbq_add_queue(struct pf_altq *a)
  273 {
  274         struct rm_class *borrow, *parent;
  275         cbq_state_t     *cbqp;
  276         struct rm_class *cl;
  277         struct cbq_opts *opts;
  278         int             i;
  279 
  280         if ((cbqp = a->altq_disc) == NULL)
  281                 return (EINVAL);
  282         if (a->qid == 0)
  283                 return (EINVAL);
  284 
  285         /*
  286          * find a free slot in the class table.  if the slot matching
  287          * the lower bits of qid is free, use this slot.  otherwise,
  288          * use the first free slot.
  289          */
  290         i = a->qid % CBQ_MAX_CLASSES;
  291         if (cbqp->cbq_class_tbl[i] != NULL) {
  292                 for (i = 0; i < CBQ_MAX_CLASSES; i++)
  293                         if (cbqp->cbq_class_tbl[i] == NULL)
  294                                 break;
  295                 if (i == CBQ_MAX_CLASSES)
  296                         return (EINVAL);
  297         }
  298 
  299         opts = &a->pq_u.cbq_opts;
  300         /* check parameters */
  301         if (a->priority >= CBQ_MAXPRI)
  302                 return (EINVAL);
  303 
  304         /* Get pointers to parent and borrow classes.  */
  305         parent = clh_to_clp(cbqp, a->parent_qid);
  306         if (opts->flags & CBQCLF_BORROW)
  307                 borrow = parent;
  308         else
  309                 borrow = NULL;
  310 
  311         /*
  312          * A class must borrow from it's parent or it can not
  313          * borrow at all.  Hence, borrow can be null.
  314          */
  315         if (parent == NULL && (opts->flags & CBQCLF_ROOTCLASS) == 0) {
  316                 printf("cbq_add_queue: no parent class!\n");
  317                 return (EINVAL);
  318         }
  319 
  320         if ((borrow != parent)  && (borrow != NULL)) {
  321                 printf("cbq_add_class: borrow class != parent\n");
  322                 return (EINVAL);
  323         }
  324 
  325         /*
  326          * check parameters
  327          */
  328         switch (opts->flags & CBQCLF_CLASSMASK) {
  329         case CBQCLF_ROOTCLASS:
  330                 if (parent != NULL)
  331                         return (EINVAL);
  332                 if (cbqp->ifnp.root_)
  333                         return (EINVAL);
  334                 break;
  335         case CBQCLF_DEFCLASS:
  336                 if (cbqp->ifnp.default_)
  337                         return (EINVAL);
  338                 break;
  339         case 0:
  340                 if (a->qid == 0)
  341                         return (EINVAL);
  342                 break;
  343         default:
  344                 /* more than two flags bits set */
  345                 return (EINVAL);
  346         }
  347 
  348         /*
  349          * create a class.  if this is a root class, initialize the
  350          * interface.
  351          */
  352         if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_ROOTCLASS) {
  353                 rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, opts->ns_per_byte,
  354                     cbqrestart, a->qlimit, RM_MAXQUEUED,
  355                     opts->maxidle, opts->minidle, opts->offtime,
  356                     opts->flags);
  357                 cl = cbqp->ifnp.root_;
  358         } else {
  359                 cl = rmc_newclass(a->priority,
  360                                   &cbqp->ifnp, opts->ns_per_byte,
  361                                   rmc_delay_action, a->qlimit, parent, borrow,
  362                                   opts->maxidle, opts->minidle, opts->offtime,
  363                                   opts->pktsize, opts->flags);
  364         }
  365         if (cl == NULL)
  366                 return (ENOMEM);
  367 
  368         /* return handle to user space. */
  369         cl->stats_.handle = a->qid;
  370         cl->stats_.depth = cl->depth_;
  371 
  372         /* save the allocated class */
  373         cbqp->cbq_class_tbl[i] = cl;
  374 
  375         if ((opts->flags & CBQCLF_CLASSMASK) == CBQCLF_DEFCLASS)
  376                 cbqp->ifnp.default_ = cl;
  377 
  378         return (0);
  379 }
  380 
  381 int
  382 cbq_remove_queue(struct pf_altq *a)
  383 {
  384         struct rm_class *cl;
  385         cbq_state_t     *cbqp;
  386         int             i;
  387 
  388         if ((cbqp = a->altq_disc) == NULL)
  389                 return (EINVAL);
  390 
  391         if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
  392                 return (EINVAL);
  393 
  394         /* if we are a parent class, then return an error. */
  395         if (is_a_parent_class(cl))
  396                 return (EINVAL);
  397 
  398         /* delete the class */
  399         rmc_delete_class(&cbqp->ifnp, cl);
  400 
  401         /*
  402          * free the class handle
  403          */
  404         for (i = 0; i < CBQ_MAX_CLASSES; i++)
  405                 if (cbqp->cbq_class_tbl[i] == cl) {
  406                         cbqp->cbq_class_tbl[i] = NULL;
  407                         if (cl == cbqp->ifnp.root_)
  408                                 cbqp->ifnp.root_ = NULL;
  409                         if (cl == cbqp->ifnp.default_)
  410                                 cbqp->ifnp.default_ = NULL;
  411                         break;
  412                 }
  413 
  414         return (0);
  415 }
  416 
  417 int
  418 cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
  419 {
  420         cbq_state_t     *cbqp;
  421         struct rm_class *cl;
  422         class_stats_t    stats;
  423         int              error = 0;
  424 
  425         if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
  426                 return (EBADF);
  427 
  428         if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
  429                 return (EINVAL);
  430 
  431         if (*nbytes < sizeof(stats))
  432                 return (EINVAL);
  433 
  434         get_class_stats(&stats, cl);
  435 
  436         if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
  437                 return (error);
  438         *nbytes = sizeof(stats);
  439         return (0);
  440 }
  441 
  442 /*
  443  * int
  444  * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
  445  *              - Queue data packets.
  446  *
  447  *      cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
  448  *      layer (e.g. ether_output).  cbq_enqueue queues the given packet
  449  *      to the cbq, then invokes the driver's start routine.
  450  *
  451  *      Assumptions:    called in splimp
  452  *      Returns:        0 if the queueing is successful.
  453  *                      ENOBUFS if a packet dropping occurred as a result of
  454  *                      the queueing.
  455  */
  456 
  457 static int
  458 cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
  459 {
  460         cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
  461         struct rm_class *cl;
  462         struct pf_mtag  *t;
  463         int              len;
  464 
  465         IFQ_LOCK_ASSERT(ifq);
  466 
  467         /* grab class set by classifier */
  468         if ((m->m_flags & M_PKTHDR) == 0) {
  469                 /* should not happen */
  470                 printf("altq: packet for %s does not have pkthdr\n",
  471                     ifq->altq_ifp->if_xname);
  472                 m_freem(m);
  473                 return (ENOBUFS);
  474         }
  475         cl = NULL;
  476         if ((t = pf_find_mtag(m)) != NULL)
  477                 cl = clh_to_clp(cbqp, t->qid);
  478         if (cl == NULL) {
  479                 cl = cbqp->ifnp.default_;
  480                 if (cl == NULL) {
  481                         m_freem(m);
  482                         return (ENOBUFS);
  483                 }
  484         }
  485         cl->pktattr_ = NULL;
  486         len = m_pktlen(m);
  487         if (rmc_queue_packet(cl, m) != 0) {
  488                 /* drop occurred.  some mbuf was freed in rmc_queue_packet. */
  489                 PKTCNTR_ADD(&cl->stats_.drop_cnt, len);
  490                 return (ENOBUFS);
  491         }
  492 
  493         /* successfully queued. */
  494         ++cbqp->cbq_qlen;
  495         IFQ_INC_LEN(ifq);
  496         return (0);
  497 }
  498 
  499 static struct mbuf *
  500 cbq_dequeue(struct ifaltq *ifq, int op)
  501 {
  502         cbq_state_t     *cbqp = (cbq_state_t *)ifq->altq_disc;
  503         struct mbuf     *m;
  504 
  505         IFQ_LOCK_ASSERT(ifq);
  506 
  507         m = rmc_dequeue_next(&cbqp->ifnp, op);
  508 
  509         if (m && op == ALTDQ_REMOVE) {
  510                 --cbqp->cbq_qlen;  /* decrement # of packets in cbq */
  511                 IFQ_DEC_LEN(ifq);
  512 
  513                 /* Update the class. */
  514                 rmc_update_class_util(&cbqp->ifnp);
  515         }
  516         return (m);
  517 }
  518 
  519 /*
  520  * void
  521  * cbqrestart(queue_t *) - Restart sending of data.
  522  * called from rmc_restart in splimp via timeout after waking up
  523  * a suspended class.
  524  *      Returns:        NONE
  525  */
  526 
  527 static void
  528 cbqrestart(struct ifaltq *ifq)
  529 {
  530         cbq_state_t     *cbqp;
  531         struct ifnet    *ifp;
  532 
  533         IFQ_LOCK_ASSERT(ifq);
  534 
  535         if (!ALTQ_IS_ENABLED(ifq))
  536                 /* cbq must have been detached */
  537                 return;
  538 
  539         if ((cbqp = (cbq_state_t *)ifq->altq_disc) == NULL)
  540                 /* should not happen */
  541                 return;
  542 
  543         ifp = ifq->altq_ifp;
  544         if (ifp->if_start &&
  545             cbqp->cbq_qlen > 0 && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
  546                 IFQ_UNLOCK(ifq);
  547                 (*ifp->if_start)(ifp);
  548                 IFQ_LOCK(ifq);
  549         }
  550 }
  551 
  552 static void cbq_purge(cbq_state_t *cbqp)
  553 {
  554         struct rm_class *cl;
  555         int              i;
  556 
  557         for (i = 0; i < CBQ_MAX_CLASSES; i++)
  558                 if ((cl = cbqp->cbq_class_tbl[i]) != NULL)
  559                         rmc_dropall(cl);
  560         if (ALTQ_IS_ENABLED(cbqp->ifnp.ifq_))
  561                 cbqp->ifnp.ifq_->ifq_len = 0;
  562 }
  563 
  564 #endif /* ALTQ_CBQ */

Cache object: 5f48b0e594a424b55a10626eee85a1b3


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