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

Cache object: 8709e449999a7458dd060aff343b65ec


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