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_rio.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_rio.c,v 1.17 2006/11/16 01:32:37 christos Exp $   */
    2 /*      $KAME: altq_rio.c,v 1.19 2005/04/13 03:44:25 suz Exp $  */
    3 
    4 /*
    5  * Copyright (C) 1998-2003
    6  *      Sony Computer Science Laboratories Inc.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 /*
   30  * Copyright (c) 1990-1994 Regents of the University of California.
   31  * All rights reserved.
   32  *
   33  * Redistribution and use in source and binary forms, with or without
   34  * modification, are permitted provided that the following conditions
   35  * are met:
   36  * 1. Redistributions of source code must retain the above copyright
   37  *    notice, this list of conditions and the following disclaimer.
   38  * 2. Redistributions in binary form must reproduce the above copyright
   39  *    notice, this list of conditions and the following disclaimer in the
   40  *    documentation and/or other materials provided with the distribution.
   41  * 3. All advertising materials mentioning features or use of this software
   42  *    must display the following acknowledgement:
   43  *      This product includes software developed by the Computer Systems
   44  *      Engineering Group at Lawrence Berkeley Laboratory.
   45  * 4. Neither the name of the University nor of the Laboratory may be used
   46  *    to endorse or promote products derived from this software without
   47  *    specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  */
   61 
   62 #include <sys/cdefs.h>
   63 __KERNEL_RCSID(0, "$NetBSD: altq_rio.c,v 1.17 2006/11/16 01:32:37 christos Exp $");
   64 
   65 #ifdef _KERNEL_OPT
   66 #include "opt_altq.h"
   67 #include "opt_inet.h"
   68 #include "pf.h"
   69 #endif
   70 
   71 #ifdef ALTQ_RIO /* rio is enabled by ALTQ_RIO option in opt_altq.h */
   72 
   73 #include <sys/param.h>
   74 #include <sys/malloc.h>
   75 #include <sys/mbuf.h>
   76 #include <sys/socket.h>
   77 #include <sys/systm.h>
   78 #include <sys/errno.h>
   79 #include <sys/kauth.h>
   80 #if 1 /* ALTQ3_COMPAT */
   81 #include <sys/proc.h>
   82 #include <sys/sockio.h>
   83 #include <sys/kernel.h>
   84 #endif
   85 #include <sys/kauth.h>
   86 
   87 #include <net/if.h>
   88 
   89 #include <netinet/in.h>
   90 #include <netinet/in_systm.h>
   91 #include <netinet/ip.h>
   92 #ifdef INET6
   93 #include <netinet/ip6.h>
   94 #endif
   95 
   96 #if NPF > 0
   97 #include <net/pfvar.h>
   98 #endif
   99 #include <altq/altq.h>
  100 #include <altq/altq_cdnr.h>
  101 #include <altq/altq_red.h>
  102 #include <altq/altq_rio.h>
  103 #ifdef ALTQ3_COMPAT
  104 #include <altq/altq_conf.h>
  105 #endif
  106 
  107 /*
  108  * RIO: RED with IN/OUT bit
  109  *   described in
  110  *      "Explicit Allocation of Best Effort Packet Delivery Service"
  111  *      David D. Clark and Wenjia Fang, MIT Lab for Computer Science
  112  *      http://diffserv.lcs.mit.edu/Papers/exp-alloc-ddc-wf.{ps,pdf}
  113  *
  114  * this implementation is extended to support more than 2 drop precedence
  115  * values as described in RFC2597 (Assured Forwarding PHB Group).
  116  *
  117  */
  118 /*
  119  * AF DS (differentiated service) codepoints.
  120  * (classes can be mapped to CBQ or H-FSC classes.)
  121  *
  122  *      0   1   2   3   4   5   6   7
  123  *    +---+---+---+---+---+---+---+---+
  124  *    |   CLASS   |DropPre| 0 |  CU   |
  125  *    +---+---+---+---+---+---+---+---+
  126  *
  127  *    class 1: 001
  128  *    class 2: 010
  129  *    class 3: 011
  130  *    class 4: 100
  131  *
  132  *    low drop prec:    01
  133  *    medium drop prec: 10
  134  *    high drop prec:   11
  135  */
  136 
  137 /* normal red parameters */
  138 #define W_WEIGHT        512     /* inverse of weight of EWMA (511/512) */
  139                                 /* q_weight = 0.00195 */
  140 
  141 /* red parameters for a slow link */
  142 #define W_WEIGHT_1      128     /* inverse of weight of EWMA (127/128) */
  143                                 /* q_weight = 0.0078125 */
  144 
  145 /* red parameters for a very slow link (e.g., dialup) */
  146 #define W_WEIGHT_2      64      /* inverse of weight of EWMA (63/64) */
  147                                 /* q_weight = 0.015625 */
  148 
  149 /* fixed-point uses 12-bit decimal places */
  150 #define FP_SHIFT        12      /* fixed-point shift */
  151 
  152 /* red parameters for drop probability */
  153 #define INV_P_MAX       10      /* inverse of max drop probability */
  154 #define TH_MIN           5      /* min threshold */
  155 #define TH_MAX          15      /* max threshold */
  156 
  157 #define RIO_LIMIT       60      /* default max queue lenght */
  158 #define RIO_STATS               /* collect statistics */
  159 
  160 #define TV_DELTA(a, b, delta) {                                 \
  161         register int    xxs;                                    \
  162                                                                 \
  163         delta = (a)->tv_usec - (b)->tv_usec;                    \
  164         if ((xxs = (a)->tv_sec - (b)->tv_sec) != 0) {           \
  165                 if (xxs < 0) {                                  \
  166                         delta = 60000000;                       \
  167                 } else if (xxs > 4)  {                          \
  168                         if (xxs > 60)                           \
  169                                 delta = 60000000;               \
  170                         else                                    \
  171                                 delta += xxs * 1000000;         \
  172                 } else while (xxs > 0) {                        \
  173                         delta += 1000000;                       \
  174                         xxs--;                                  \
  175                 }                                               \
  176         }                                                       \
  177 }
  178 
  179 #ifdef ALTQ3_COMPAT
  180 /* rio_list keeps all rio_queue_t's allocated. */
  181 static rio_queue_t *rio_list = NULL;
  182 #endif
  183 /* default rio parameter values */
  184 static struct redparams default_rio_params[RIO_NDROPPREC] = {
  185   /* th_min,             th_max,     inv_pmax */
  186   { TH_MAX * 2 + TH_MIN, TH_MAX * 3, INV_P_MAX }, /* low drop precedence */
  187   { TH_MAX + TH_MIN,     TH_MAX * 2, INV_P_MAX }, /* medium drop precedence */
  188   { TH_MIN,              TH_MAX,     INV_P_MAX }  /* high drop precedence */
  189 };
  190 
  191 /* internal function prototypes */
  192 static int dscp2index(u_int8_t);
  193 #ifdef ALTQ3_COMPAT
  194 static int rio_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
  195 static struct mbuf *rio_dequeue(struct ifaltq *, int);
  196 static int rio_request(struct ifaltq *, int, void *);
  197 static int rio_detach(rio_queue_t *);
  198 
  199 /*
  200  * rio device interface
  201  */
  202 altqdev_decl(rio);
  203 
  204 #endif /* ALTQ3_COMPAT */
  205 
  206 rio_t *
  207 rio_alloc(int weight, struct redparams *params, int flags, int pkttime)
  208 {
  209         rio_t   *rp;
  210         int      w, i;
  211         int      npkts_per_sec;
  212 
  213         rp = malloc(sizeof(rio_t), M_DEVBUF, M_WAITOK|M_ZERO);
  214         if (rp == NULL)
  215                 return (NULL);
  216 
  217         rp->rio_flags = flags;
  218         if (pkttime == 0)
  219                 /* default packet time: 1000 bytes / 10Mbps * 8 * 1000000 */
  220                 rp->rio_pkttime = 800;
  221         else
  222                 rp->rio_pkttime = pkttime;
  223 
  224         if (weight != 0)
  225                 rp->rio_weight = weight;
  226         else {
  227                 /* use default */
  228                 rp->rio_weight = W_WEIGHT;
  229 
  230                 /* when the link is very slow, adjust red parameters */
  231                 npkts_per_sec = 1000000 / rp->rio_pkttime;
  232                 if (npkts_per_sec < 50) {
  233                         /* up to about 400Kbps */
  234                         rp->rio_weight = W_WEIGHT_2;
  235                 } else if (npkts_per_sec < 300) {
  236                         /* up to about 2.4Mbps */
  237                         rp->rio_weight = W_WEIGHT_1;
  238                 }
  239         }
  240 
  241         /* calculate wshift.  weight must be power of 2 */
  242         w = rp->rio_weight;
  243         for (i = 0; w > 1; i++)
  244                 w = w >> 1;
  245         rp->rio_wshift = i;
  246         w = 1 << rp->rio_wshift;
  247         if (w != rp->rio_weight) {
  248                 printf("invalid weight value %d for red! use %d\n",
  249                        rp->rio_weight, w);
  250                 rp->rio_weight = w;
  251         }
  252 
  253         /* allocate weight table */
  254         rp->rio_wtab = wtab_alloc(rp->rio_weight);
  255 
  256         for (i = 0; i < RIO_NDROPPREC; i++) {
  257                 struct dropprec_state *prec = &rp->rio_precstate[i];
  258 
  259                 prec->avg = 0;
  260                 prec->idle = 1;
  261 
  262                 if (params == NULL || params[i].inv_pmax == 0)
  263                         prec->inv_pmax = default_rio_params[i].inv_pmax;
  264                 else
  265                         prec->inv_pmax = params[i].inv_pmax;
  266                 if (params == NULL || params[i].th_min == 0)
  267                         prec->th_min = default_rio_params[i].th_min;
  268                 else
  269                         prec->th_min = params[i].th_min;
  270                 if (params == NULL || params[i].th_max == 0)
  271                         prec->th_max = default_rio_params[i].th_max;
  272                 else
  273                         prec->th_max = params[i].th_max;
  274 
  275                 /*
  276                  * th_min_s and th_max_s are scaled versions of th_min
  277                  * and th_max to be compared with avg.
  278                  */
  279                 prec->th_min_s = prec->th_min << (rp->rio_wshift + FP_SHIFT);
  280                 prec->th_max_s = prec->th_max << (rp->rio_wshift + FP_SHIFT);
  281 
  282                 /*
  283                  * precompute probability denominator
  284                  *  probd = (2 * (TH_MAX-TH_MIN) / pmax) in fixed-point
  285                  */
  286                 prec->probd = (2 * (prec->th_max - prec->th_min)
  287                                * prec->inv_pmax) << FP_SHIFT;
  288 
  289                 microtime(&prec->last);
  290         }
  291 
  292         return (rp);
  293 }
  294 
  295 void
  296 rio_destroy(rio_t *rp)
  297 {
  298         wtab_destroy(rp->rio_wtab);
  299         free(rp, M_DEVBUF);
  300 }
  301 
  302 void
  303 rio_getstats(rio_t *rp, struct redstats *sp)
  304 {
  305         int     i;
  306 
  307         for (i = 0; i < RIO_NDROPPREC; i++) {
  308                 bcopy(&rp->q_stats[i], sp, sizeof(struct redstats));
  309                 sp->q_avg = rp->rio_precstate[i].avg >> rp->rio_wshift;
  310                 sp++;
  311         }
  312 }
  313 
  314 #if (RIO_NDROPPREC == 3)
  315 /*
  316  * internally, a drop precedence value is converted to an index
  317  * starting from 0.
  318  */
  319 static int
  320 dscp2index(u_int8_t dscp)
  321 {
  322         int     dpindex = dscp & AF_DROPPRECMASK;
  323 
  324         if (dpindex == 0)
  325                 return (0);
  326         return ((dpindex >> 3) - 1);
  327 }
  328 #endif
  329 
  330 #if 1
  331 /*
  332  * kludge: when a packet is dequeued, we need to know its drop precedence
  333  * in order to keep the queue length of each drop precedence.
  334  * use m_pkthdr.rcvif to pass this info.
  335  */
  336 #define RIOM_SET_PRECINDEX(m, idx)      \
  337         do { (m)->m_pkthdr.rcvif = (struct ifnet *)((long)(idx)); } while (0)
  338 #define RIOM_GET_PRECINDEX(m)   \
  339         ({ long idx; idx = (long)((m)->m_pkthdr.rcvif); \
  340         (m)->m_pkthdr.rcvif = NULL; idx; })
  341 #endif
  342 
  343 int
  344 rio_addq(rio_t *rp, class_queue_t *q, struct mbuf *m,
  345     struct altq_pktattr *pktattr)
  346 {
  347         int                      avg, droptype;
  348         u_int8_t                 dsfield, odsfield;
  349         int                      dpindex, i, n, t;
  350         struct timeval           now;
  351         struct dropprec_state   *prec;
  352 
  353         dsfield = odsfield = read_dsfield(m, pktattr);
  354         dpindex = dscp2index(dsfield);
  355 
  356         /*
  357          * update avg of the precedence states whose drop precedence
  358          * is larger than or equal to the drop precedence of the packet
  359          */
  360         now.tv_sec = 0;
  361         for (i = dpindex; i < RIO_NDROPPREC; i++) {
  362                 prec = &rp->rio_precstate[i];
  363                 avg = prec->avg;
  364                 if (prec->idle) {
  365                         prec->idle = 0;
  366                         if (now.tv_sec == 0)
  367                                 microtime(&now);
  368                         t = (now.tv_sec - prec->last.tv_sec);
  369                         if (t > 60)
  370                                 avg = 0;
  371                         else {
  372                                 t = t * 1000000 +
  373                                         (now.tv_usec - prec->last.tv_usec);
  374                                 n = t / rp->rio_pkttime;
  375                                 /* calculate (avg = (1 - Wq)^n * avg) */
  376                                 if (n > 0)
  377                                         avg = (avg >> FP_SHIFT) *
  378                                                 pow_w(rp->rio_wtab, n);
  379                         }
  380                 }
  381 
  382                 /* run estimator. (avg is scaled by WEIGHT in fixed-point) */
  383                 avg += (prec->qlen << FP_SHIFT) - (avg >> rp->rio_wshift);
  384                 prec->avg = avg;                /* save the new value */
  385                 /*
  386                  * count keeps a tally of arriving traffic that has not
  387                  * been dropped.
  388                  */
  389                 prec->count++;
  390         }
  391 
  392         prec = &rp->rio_precstate[dpindex];
  393         avg = prec->avg;
  394 
  395         /* see if we drop early */
  396         droptype = DTYPE_NODROP;
  397         if (avg >= prec->th_min_s && prec->qlen > 1) {
  398                 if (avg >= prec->th_max_s) {
  399                         /* avg >= th_max: forced drop */
  400                         droptype = DTYPE_FORCED;
  401                 } else if (prec->old == 0) {
  402                         /* first exceeds th_min */
  403                         prec->count = 1;
  404                         prec->old = 1;
  405                 } else if (drop_early((avg - prec->th_min_s) >> rp->rio_wshift,
  406                                       prec->probd, prec->count)) {
  407                         /* unforced drop by red */
  408                         droptype = DTYPE_EARLY;
  409                 }
  410         } else {
  411                 /* avg < th_min */
  412                 prec->old = 0;
  413         }
  414 
  415         /*
  416          * if the queue length hits the hard limit, it's a forced drop.
  417          */
  418         if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q))
  419                 droptype = DTYPE_FORCED;
  420 
  421         if (droptype != DTYPE_NODROP) {
  422                 /* always drop incoming packet (as opposed to randomdrop) */
  423                 for (i = dpindex; i < RIO_NDROPPREC; i++)
  424                         rp->rio_precstate[i].count = 0;
  425 #ifdef RIO_STATS
  426                 if (droptype == DTYPE_EARLY)
  427                         rp->q_stats[dpindex].drop_unforced++;
  428                 else
  429                         rp->q_stats[dpindex].drop_forced++;
  430                 PKTCNTR_ADD(&rp->q_stats[dpindex].drop_cnt, m_pktlen(m));
  431 #endif
  432                 m_freem(m);
  433                 return (-1);
  434         }
  435 
  436         for (i = dpindex; i < RIO_NDROPPREC; i++)
  437                 rp->rio_precstate[i].qlen++;
  438 
  439         /* save drop precedence index in mbuf hdr */
  440         RIOM_SET_PRECINDEX(m, dpindex);
  441 
  442         if (rp->rio_flags & RIOF_CLEARDSCP)
  443                 dsfield &= ~DSCP_MASK;
  444 
  445         if (dsfield != odsfield)
  446                 write_dsfield(m, pktattr, dsfield);
  447 
  448         _addq(q, m);
  449 
  450 #ifdef RIO_STATS
  451         PKTCNTR_ADD(&rp->q_stats[dpindex].xmit_cnt, m_pktlen(m));
  452 #endif
  453         return (0);
  454 }
  455 
  456 struct mbuf *
  457 rio_getq(rio_t *rp, class_queue_t *q)
  458 {
  459         struct mbuf     *m;
  460         int              dpindex, i;
  461 
  462         if ((m = _getq(q)) == NULL)
  463                 return NULL;
  464 
  465         dpindex = RIOM_GET_PRECINDEX(m);
  466         for (i = dpindex; i < RIO_NDROPPREC; i++) {
  467                 if (--rp->rio_precstate[i].qlen == 0) {
  468                         if (rp->rio_precstate[i].idle == 0) {
  469                                 rp->rio_precstate[i].idle = 1;
  470                                 microtime(&rp->rio_precstate[i].last);
  471                         }
  472                 }
  473         }
  474         return (m);
  475 }
  476 
  477 #ifdef ALTQ3_COMPAT
  478 int
  479 rioopen(dev_t dev, int flag, int fmt,
  480     struct lwp *l)
  481 {
  482         /* everything will be done when the queueing scheme is attached. */
  483         return 0;
  484 }
  485 
  486 int
  487 rioclose(dev_t dev, int flag, int fmt,
  488     struct lwp *l)
  489 {
  490         rio_queue_t *rqp;
  491         int err, error = 0;
  492 
  493         while ((rqp = rio_list) != NULL) {
  494                 /* destroy all */
  495                 err = rio_detach(rqp);
  496                 if (err != 0 && error == 0)
  497                         error = err;
  498         }
  499 
  500         return error;
  501 }
  502 
  503 int
  504 rioioctl(dev_t dev, ioctlcmd_t cmd, caddr_t addr, int flag,
  505     struct lwp *l)
  506 {
  507         rio_queue_t *rqp;
  508         struct rio_interface *ifacep;
  509         struct ifnet *ifp;
  510         int     error = 0;
  511 
  512         /* check super-user privilege */
  513         switch (cmd) {
  514         case RIO_GETSTATS:
  515                 break;
  516         default:
  517 #if (__FreeBSD_version > 400000)
  518                 if ((error = suser(p)) != 0)
  519                         return (error);
  520 #else
  521                 if ((error = kauth_authorize_network(l->l_cred,
  522                     KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_RIO, NULL,
  523                     NULL, NULL)) != 0)
  524                         return (error);
  525 #endif
  526                 break;
  527         }
  528 
  529         switch (cmd) {
  530 
  531         case RIO_ENABLE:
  532                 ifacep = (struct rio_interface *)addr;
  533                 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) {
  534                         error = EBADF;
  535                         break;
  536                 }
  537                 error = altq_enable(rqp->rq_ifq);
  538                 break;
  539 
  540         case RIO_DISABLE:
  541                 ifacep = (struct rio_interface *)addr;
  542                 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) {
  543                         error = EBADF;
  544                         break;
  545                 }
  546                 error = altq_disable(rqp->rq_ifq);
  547                 break;
  548 
  549         case RIO_IF_ATTACH:
  550                 ifp = ifunit(((struct rio_interface *)addr)->rio_ifname);
  551                 if (ifp == NULL) {
  552                         error = ENXIO;
  553                         break;
  554                 }
  555 
  556                 /* allocate and initialize rio_queue_t */
  557                 rqp = malloc(sizeof(rio_queue_t), M_DEVBUF, M_WAITOK|M_ZERO);
  558                 if (rqp == NULL) {
  559                         error = ENOMEM;
  560                         break;
  561                 }
  562 
  563                 rqp->rq_q = malloc(sizeof(class_queue_t), M_DEVBUF,
  564                     M_WAITOK|M_ZERO);
  565                 if (rqp->rq_q == NULL) {
  566                         free(rqp, M_DEVBUF);
  567                         error = ENOMEM;
  568                         break;
  569                 }
  570 
  571                 rqp->rq_rio = rio_alloc(0, NULL, 0, 0);
  572                 if (rqp->rq_rio == NULL) {
  573                         free(rqp->rq_q, M_DEVBUF);
  574                         free(rqp, M_DEVBUF);
  575                         error = ENOMEM;
  576                         break;
  577                 }
  578 
  579                 rqp->rq_ifq = &ifp->if_snd;
  580                 qtail(rqp->rq_q) = NULL;
  581                 qlen(rqp->rq_q) = 0;
  582                 qlimit(rqp->rq_q) = RIO_LIMIT;
  583                 qtype(rqp->rq_q) = Q_RIO;
  584 
  585                 /*
  586                  * set RIO to this ifnet structure.
  587                  */
  588                 error = altq_attach(rqp->rq_ifq, ALTQT_RIO, rqp,
  589                                     rio_enqueue, rio_dequeue, rio_request,
  590                                     NULL, NULL);
  591                 if (error) {
  592                         rio_destroy(rqp->rq_rio);
  593                         free(rqp->rq_q, M_DEVBUF);
  594                         free(rqp, M_DEVBUF);
  595                         break;
  596                 }
  597 
  598                 /* add this state to the rio list */
  599                 rqp->rq_next = rio_list;
  600                 rio_list = rqp;
  601                 break;
  602 
  603         case RIO_IF_DETACH:
  604                 ifacep = (struct rio_interface *)addr;
  605                 if ((rqp = altq_lookup(ifacep->rio_ifname, ALTQT_RIO)) == NULL) {
  606                         error = EBADF;
  607                         break;
  608                 }
  609                 error = rio_detach(rqp);
  610                 break;
  611 
  612         case RIO_GETSTATS:
  613                 do {
  614                         struct rio_stats *q_stats;
  615                         rio_t *rp;
  616                         int i;
  617 
  618                         q_stats = (struct rio_stats *)addr;
  619                         if ((rqp = altq_lookup(q_stats->iface.rio_ifname,
  620                                                ALTQT_RIO)) == NULL) {
  621                                 error = EBADF;
  622                                 break;
  623                         }
  624 
  625                         rp = rqp->rq_rio;
  626 
  627                         q_stats->q_limit = qlimit(rqp->rq_q);
  628                         q_stats->weight = rp->rio_weight;
  629                         q_stats->flags = rp->rio_flags;
  630 
  631                         for (i = 0; i < RIO_NDROPPREC; i++) {
  632                                 q_stats->q_len[i] = rp->rio_precstate[i].qlen;
  633                                 bcopy(&rp->q_stats[i], &q_stats->q_stats[i],
  634                                       sizeof(struct redstats));
  635                                 q_stats->q_stats[i].q_avg =
  636                                     rp->rio_precstate[i].avg >> rp->rio_wshift;
  637 
  638                                 q_stats->q_params[i].inv_pmax
  639                                         = rp->rio_precstate[i].inv_pmax;
  640                                 q_stats->q_params[i].th_min
  641                                         = rp->rio_precstate[i].th_min;
  642                                 q_stats->q_params[i].th_max
  643                                         = rp->rio_precstate[i].th_max;
  644                         }
  645                 } while (/*CONSTCOND*/ 0);
  646                 break;
  647 
  648         case RIO_CONFIG:
  649                 do {
  650                         struct rio_conf *fc;
  651                         rio_t   *new;
  652                         int s, limit, i;
  653 
  654                         fc = (struct rio_conf *)addr;
  655                         if ((rqp = altq_lookup(fc->iface.rio_ifname,
  656                                                ALTQT_RIO)) == NULL) {
  657                                 error = EBADF;
  658                                 break;
  659                         }
  660 
  661                         new = rio_alloc(fc->rio_weight, &fc->q_params[0],
  662                                         fc->rio_flags, fc->rio_pkttime);
  663                         if (new == NULL) {
  664                                 error = ENOMEM;
  665                                 break;
  666                         }
  667 
  668                         s = splnet();
  669                         _flushq(rqp->rq_q);
  670                         limit = fc->rio_limit;
  671                         if (limit < fc->q_params[RIO_NDROPPREC-1].th_max)
  672                                 limit = fc->q_params[RIO_NDROPPREC-1].th_max;
  673                         qlimit(rqp->rq_q) = limit;
  674 
  675                         rio_destroy(rqp->rq_rio);
  676                         rqp->rq_rio = new;
  677 
  678                         splx(s);
  679 
  680                         /* write back new values */
  681                         fc->rio_limit = limit;
  682                         for (i = 0; i < RIO_NDROPPREC; i++) {
  683                                 fc->q_params[i].inv_pmax =
  684                                         rqp->rq_rio->rio_precstate[i].inv_pmax;
  685                                 fc->q_params[i].th_min =
  686                                         rqp->rq_rio->rio_precstate[i].th_min;
  687                                 fc->q_params[i].th_max =
  688                                         rqp->rq_rio->rio_precstate[i].th_max;
  689                         }
  690                 } while (/*CONSTCOND*/ 0);
  691                 break;
  692 
  693         case RIO_SETDEFAULTS:
  694                 do {
  695                         struct redparams *rp;
  696                         int i;
  697 
  698                         rp = (struct redparams *)addr;
  699                         for (i = 0; i < RIO_NDROPPREC; i++)
  700                                 default_rio_params[i] = rp[i];
  701                 } while (/*CONSTCOND*/ 0);
  702                 break;
  703 
  704         default:
  705                 error = EINVAL;
  706                 break;
  707         }
  708 
  709         return error;
  710 }
  711 
  712 static int
  713 rio_detach(rio_queue_t *rqp)
  714 {
  715         rio_queue_t *tmp;
  716         int error = 0;
  717 
  718         if (ALTQ_IS_ENABLED(rqp->rq_ifq))
  719                 altq_disable(rqp->rq_ifq);
  720 
  721         if ((error = altq_detach(rqp->rq_ifq)))
  722                 return (error);
  723 
  724         if (rio_list == rqp)
  725                 rio_list = rqp->rq_next;
  726         else {
  727                 for (tmp = rio_list; tmp != NULL; tmp = tmp->rq_next)
  728                         if (tmp->rq_next == rqp) {
  729                                 tmp->rq_next = rqp->rq_next;
  730                                 break;
  731                         }
  732                 if (tmp == NULL)
  733                         printf("rio_detach: no state found in rio_list!\n");
  734         }
  735 
  736         rio_destroy(rqp->rq_rio);
  737         free(rqp->rq_q, M_DEVBUF);
  738         free(rqp, M_DEVBUF);
  739         return (error);
  740 }
  741 
  742 /*
  743  * rio support routines
  744  */
  745 static int
  746 rio_request(struct ifaltq *ifq, int req, void *arg)
  747 {
  748         rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc;
  749 
  750         switch (req) {
  751         case ALTRQ_PURGE:
  752                 _flushq(rqp->rq_q);
  753                 if (ALTQ_IS_ENABLED(ifq))
  754                         ifq->ifq_len = 0;
  755                 break;
  756         }
  757         return (0);
  758 }
  759 
  760 /*
  761  * enqueue routine:
  762  *
  763  *      returns: 0 when successfully queued.
  764  *               ENOBUFS when drop occurs.
  765  */
  766 static int
  767 rio_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
  768 {
  769         rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc;
  770         int error = 0;
  771 
  772         if (rio_addq(rqp->rq_rio, rqp->rq_q, m, pktattr) == 0)
  773                 ifq->ifq_len++;
  774         else
  775                 error = ENOBUFS;
  776         return error;
  777 }
  778 
  779 /*
  780  * dequeue routine:
  781  *      must be called in splnet.
  782  *
  783  *      returns: mbuf dequeued.
  784  *               NULL when no packet is available in the queue.
  785  */
  786 
  787 static struct mbuf *
  788 rio_dequeue(struct ifaltq *ifq, int op)
  789 {
  790         rio_queue_t *rqp = (rio_queue_t *)ifq->altq_disc;
  791         struct mbuf *m = NULL;
  792 
  793         if (op == ALTDQ_POLL)
  794                 return qhead(rqp->rq_q);
  795 
  796         m = rio_getq(rqp->rq_rio, rqp->rq_q);
  797         if (m != NULL)
  798                 ifq->ifq_len--;
  799         return m;
  800 }
  801 
  802 #ifdef KLD_MODULE
  803 
  804 static struct altqsw rio_sw =
  805         {"rio", rioopen, rioclose, rioioctl};
  806 
  807 ALTQ_MODULE(altq_rio, ALTQT_RIO, &rio_sw);
  808 MODULE_VERSION(altq_rio, 1);
  809 MODULE_DEPEND(altq_rio, altq_red, 1, 1, 1);
  810 
  811 #endif /* KLD_MODULE */
  812 #endif /* ALTQ3_COMPAT */
  813 
  814 #endif /* ALTQ_RIO */

Cache object: 118b98801113507f4b7c064ac208555b


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