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_priq.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_priq.c,v 1.7 2003/11/09 22:11:12 christos Exp $   */
    2 /*      $KAME: altq_priq.c,v 1.2 2001/10/26 04:56:11 kjc Exp $  */
    3 /*
    4  * Copyright (C) 2000
    5  *      Sony Computer Science Laboratories Inc.  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  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*
   29  * priority queue
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __KERNEL_RCSID(0, "$NetBSD: altq_priq.c,v 1.7 2003/11/09 22:11:12 christos Exp $");
   34 
   35 #if defined(__FreeBSD__) || defined(__NetBSD__)
   36 #include "opt_altq.h"
   37 #if (__FreeBSD__ != 2)
   38 #include "opt_inet.h"
   39 #ifdef __FreeBSD__
   40 #include "opt_inet6.h"
   41 #endif
   42 #endif
   43 #endif /* __FreeBSD__ || __NetBSD__ */
   44 
   45 #ifdef ALTQ_PRIQ  /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */
   46 
   47 #include <sys/param.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/socket.h>
   51 #include <sys/sockio.h>
   52 #include <sys/systm.h>
   53 #include <sys/proc.h>
   54 #include <sys/errno.h>
   55 #include <sys/kernel.h>
   56 #include <sys/queue.h>
   57 
   58 #include <net/if.h>
   59 #include <net/if_types.h>
   60 
   61 #include <altq/altq.h>
   62 #include <altq/altq_conf.h>
   63 #include <altq/altq_priq.h>
   64 
   65 /*
   66  * function prototypes
   67  */
   68 static struct priq_if *priq_attach __P((struct ifaltq *, u_int));
   69 static int priq_detach __P((struct priq_if *));
   70 static int priq_clear_interface __P((struct priq_if *));
   71 static int priq_request __P((struct ifaltq *, int, void *));
   72 static void priq_purge __P((struct priq_if *));
   73 static struct priq_class *priq_class_create __P((struct priq_if *,
   74                                                  int, int, int));
   75 static int priq_class_destroy __P((struct priq_class *));
   76 static int priq_enqueue __P((struct ifaltq *, struct mbuf *,
   77                              struct altq_pktattr *));
   78 static struct mbuf *priq_dequeue __P((struct ifaltq *, int));
   79 
   80 static int priq_addq __P((struct priq_class *, struct mbuf *));
   81 static struct mbuf *priq_getq __P((struct priq_class *));
   82 static struct mbuf *priq_pollq __P((struct priq_class *));
   83 static void priq_purgeq __P((struct priq_class *));
   84 
   85 int priqopen __P((dev_t, int, int, struct proc *));
   86 int priqclose __P((dev_t, int, int, struct proc *));
   87 int priqioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct proc *));
   88 static int priqcmd_if_attach __P((struct priq_interface *));
   89 static int priqcmd_if_detach __P((struct priq_interface *));
   90 static int priqcmd_add_class __P((struct priq_add_class *));
   91 static int priqcmd_delete_class __P((struct priq_delete_class *));
   92 static int priqcmd_modify_class __P((struct priq_modify_class *));
   93 static int priqcmd_add_filter __P((struct priq_add_filter *));
   94 static int priqcmd_delete_filter __P((struct priq_delete_filter *));
   95 static int priqcmd_class_stats __P((struct priq_class_stats *));
   96 static void get_class_stats __P((struct priq_basic_class_stats *,
   97     struct priq_class *));
   98 static struct priq_class *clh_to_clp __P((struct priq_if *, u_long));
   99 static u_long clp_to_clh __P((struct priq_class *));
  100 
  101 /* pif_list keeps all priq_if's allocated. */
  102 static struct priq_if *pif_list = NULL;
  103 
  104 static struct priq_if *
  105 priq_attach(ifq, bandwidth)
  106         struct ifaltq *ifq;
  107         u_int bandwidth;
  108 {
  109         struct priq_if *pif;
  110 
  111         MALLOC(pif, struct priq_if *, sizeof(struct priq_if),
  112                M_DEVBUF, M_WAITOK);
  113         if (pif == NULL)
  114                 return (NULL);
  115         (void)memset(pif, 0, sizeof(struct priq_if));
  116         pif->pif_bandwidth = bandwidth;
  117         pif->pif_maxpri = -1;
  118         pif->pif_ifq = ifq;
  119 
  120         /* add this state to the priq list */
  121         pif->pif_next = pif_list;
  122         pif_list = pif;
  123 
  124         return (pif);
  125 }
  126 
  127 static int
  128 priq_detach(pif)
  129         struct priq_if *pif;
  130 {
  131         (void)priq_clear_interface(pif);
  132 
  133         /* remove this interface from the pif list */
  134         if (pif_list == pif)
  135                 pif_list = pif->pif_next;
  136         else {
  137                 struct priq_if *p;
  138         
  139                 for (p = pif_list; p != NULL; p = p->pif_next)
  140                         if (p->pif_next == pif) {
  141                                 p->pif_next = pif->pif_next;
  142                                 break;
  143                         }
  144                 ASSERT(p != NULL);
  145         }
  146 
  147         FREE(pif, M_DEVBUF);
  148         return (0);
  149 }
  150 
  151 /*
  152  * bring the interface back to the initial state by discarding
  153  * all the filters and classes.
  154  */
  155 static int
  156 priq_clear_interface(pif)
  157         struct priq_if *pif;
  158 {
  159         struct priq_class       *cl;
  160         int pri;
  161 
  162         /* free the filters for this interface */
  163         acc_discard_filters(&pif->pif_classifier, NULL, 1);
  164 
  165         /* clear out the classes */
  166         for (pri = 0; pri <= pif->pif_maxpri; pri++)
  167                 if ((cl = pif->pif_classes[pri]) != NULL)
  168                         priq_class_destroy(cl);
  169 
  170         return (0);
  171 }
  172 
  173 static int
  174 priq_request(ifq, req, arg)
  175         struct ifaltq *ifq;
  176         int req;
  177         void *arg;
  178 {
  179         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  180 
  181         switch (req) {
  182         case ALTRQ_PURGE:
  183                 priq_purge(pif);
  184                 break;
  185         }
  186         return (0);
  187 }
  188 
  189 /* discard all the queued packets on the interface */
  190 static void
  191 priq_purge(pif)
  192         struct priq_if *pif;
  193 {
  194         struct priq_class *cl;
  195         int pri;
  196 
  197         for (pri = 0; pri <= pif->pif_maxpri; pri++) {
  198                 if ((cl = pif->pif_classes[pri]) != NULL && !qempty(cl->cl_q))
  199                         priq_purgeq(cl);
  200         }
  201         if (ALTQ_IS_ENABLED(pif->pif_ifq))
  202                 pif->pif_ifq->ifq_len = 0;
  203 }
  204 
  205 static struct priq_class *
  206 priq_class_create(pif, pri, qlimit, flags)
  207         struct priq_if *pif;
  208         int pri, qlimit, flags;
  209 {
  210         struct priq_class *cl;
  211         int s;
  212 
  213 #ifndef ALTQ_RED
  214         if (flags & PRCF_RED) {
  215                 printf("priq_class_create: RED not configured for PRIQ!\n");
  216                 return (NULL);
  217         }
  218 #endif
  219 
  220         if ((cl = pif->pif_classes[pri]) != NULL) {
  221                 /* modify the class instead of creating a new one */
  222                 s = splnet();
  223                 if (!qempty(cl->cl_q))
  224                         priq_purgeq(cl);
  225                 splx(s);
  226 #ifdef ALTQ_RIO
  227                 if (q_is_rio(cl->cl_q))
  228                         rio_destroy((rio_t *)cl->cl_red);
  229 #endif
  230 #ifdef ALTQ_RED
  231                 if (q_is_red(cl->cl_q))
  232                         red_destroy(cl->cl_red);
  233 #endif
  234         } else {
  235                 MALLOC(cl, struct priq_class *, sizeof(struct priq_class),
  236                        M_DEVBUF, M_WAITOK);
  237                 if (cl == NULL)
  238                         return (NULL);
  239                 (void)memset(cl, 0, sizeof(struct priq_class));
  240 
  241                 MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t),
  242                        M_DEVBUF, M_WAITOK);
  243                 if (cl->cl_q == NULL)
  244                         goto err_ret;
  245                 (void)memset(cl->cl_q, 0, sizeof(class_queue_t));
  246         }
  247 
  248         pif->pif_classes[pri] = cl;
  249         if (flags & PRCF_DEFAULTCLASS)
  250                 pif->pif_default = cl;
  251         if (qlimit == 0)
  252                 qlimit = 50;  /* use default */
  253         qlimit(cl->cl_q) = qlimit;
  254         qtype(cl->cl_q) = Q_DROPTAIL;
  255         qlen(cl->cl_q) = 0;
  256         cl->cl_flags = flags;
  257         cl->cl_pri = pri;
  258         if (pri > pif->pif_maxpri)
  259                 pif->pif_maxpri = pri;
  260         cl->cl_pif = pif;
  261         cl->cl_handle = (u_long)cl;  /* XXX: just a pointer to this class */
  262 
  263 #ifdef ALTQ_RED
  264         if (flags & (PRCF_RED|PRCF_RIO)) {
  265                 int red_flags, red_pkttime;
  266 
  267                 red_flags = 0;
  268                 if (flags & PRCF_ECN)
  269                         red_flags |= REDF_ECN;
  270 #ifdef ALTQ_RIO
  271                 if (flags & PRCF_CLEARDSCP)
  272                         red_flags |= RIOF_CLEARDSCP;
  273 #endif
  274                 if (pif->pif_bandwidth < 8)
  275                         red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
  276                 else
  277                         red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu
  278                           * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8);
  279 #ifdef ALTQ_RIO
  280                 if (flags & PRCF_RIO) {
  281                         cl->cl_red = (red_t *)rio_alloc(0, NULL,
  282                                                 red_flags, red_pkttime);
  283                         if (cl->cl_red != NULL)
  284                                 qtype(cl->cl_q) = Q_RIO;
  285                 } else 
  286 #endif
  287                 if (flags & PRCF_RED) {
  288                         cl->cl_red = red_alloc(0, 0, 0, 0,
  289                                                red_flags, red_pkttime);
  290                         if (cl->cl_red != NULL)
  291                                 qtype(cl->cl_q) = Q_RED;
  292                 }
  293         }
  294 #endif /* ALTQ_RED */
  295 
  296         return (cl);
  297 
  298  err_ret:
  299         if (cl->cl_red != NULL) {
  300 #ifdef ALTQ_RIO
  301                 if (q_is_rio(cl->cl_q))
  302                         rio_destroy((rio_t *)cl->cl_red);
  303 #endif
  304 #ifdef ALTQ_RED
  305                 if (q_is_red(cl->cl_q))
  306                         red_destroy(cl->cl_red);
  307 #endif
  308         }
  309         if (cl->cl_q != NULL)
  310                 FREE(cl->cl_q, M_DEVBUF);
  311         FREE(cl, M_DEVBUF);
  312         return (NULL);
  313 }
  314 
  315 static int
  316 priq_class_destroy(cl)
  317         struct priq_class *cl;
  318 {
  319         struct priq_if *pif;
  320         int s, pri;
  321 
  322         s = splnet();
  323 
  324         /* delete filters referencing to this class */
  325         acc_discard_filters(&cl->cl_pif->pif_classifier, cl, 0);
  326 
  327         if (!qempty(cl->cl_q))
  328                 priq_purgeq(cl);
  329 
  330         pif = cl->cl_pif;
  331         pif->pif_classes[cl->cl_pri] = NULL;
  332         if (pif->pif_maxpri == cl->cl_pri) {
  333                 for (pri = cl->cl_pri; pri >= 0; pri--)
  334                         if (pif->pif_classes[pri] != NULL) {
  335                                 pif->pif_maxpri = pri;
  336                                 break;
  337                         }
  338                 if (pri < 0)
  339                         pif->pif_maxpri = -1;
  340         }
  341         splx(s);
  342 
  343         if (cl->cl_red != NULL) {
  344 #ifdef ALTQ_RIO
  345                 if (q_is_rio(cl->cl_q))
  346                         rio_destroy((rio_t *)cl->cl_red);
  347 #endif
  348 #ifdef ALTQ_RED
  349                 if (q_is_red(cl->cl_q))
  350                         red_destroy(cl->cl_red);
  351 #endif
  352         }
  353         FREE(cl->cl_q, M_DEVBUF);
  354         FREE(cl, M_DEVBUF);
  355         return (0);
  356 }
  357 
  358 /*
  359  * priq_enqueue is an enqueue function to be registered to
  360  * (*altq_enqueue) in struct ifaltq.
  361  */
  362 static int 
  363 priq_enqueue(ifq, m, pktattr)
  364         struct ifaltq *ifq;
  365         struct mbuf *m;
  366         struct altq_pktattr *pktattr;
  367 {
  368         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  369         struct priq_class *cl;
  370         int len;
  371 
  372         /* grab class set by classifier */
  373         if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
  374                 cl = pif->pif_default;
  375         cl->cl_pktattr = pktattr;  /* save proto hdr used by ECN */
  376 
  377         len = m_pktlen(m);
  378         if (priq_addq(cl, m) != 0) {
  379                 /* drop occurred.  mbuf was freed in priq_addq. */
  380                 PKTCNTR_ADD(&cl->cl_dropcnt, len);
  381                 return (ENOBUFS);
  382         }
  383         IFQ_INC_LEN(ifq);
  384 
  385         /* successfully queued. */
  386         return (0);
  387 }
  388 
  389 /*
  390  * priq_dequeue is a dequeue function to be registered to
  391  * (*altq_dequeue) in struct ifaltq.
  392  *
  393  * note: ALTDQ_POLL returns the next packet without removing the packet
  394  *      from the queue.  ALTDQ_REMOVE is a normal dequeue operation.
  395  *      ALTDQ_REMOVE must return the same packet if called immediately
  396  *      after ALTDQ_POLL.
  397  */
  398 static struct mbuf *
  399 priq_dequeue(ifq, op)
  400         struct ifaltq   *ifq;
  401         int             op;
  402 {
  403         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  404         struct priq_class *cl;
  405         struct mbuf *m;
  406         int pri;
  407 
  408         if (IFQ_IS_EMPTY(ifq))
  409                 /* no packet in the queue */
  410                 return (NULL);
  411 
  412         for (pri = pif->pif_maxpri;  pri >= 0; pri--) {
  413                 if ((cl = pif->pif_classes[pri]) != NULL &&
  414                     !qempty(cl->cl_q)) {
  415                         if (op == ALTDQ_POLL)
  416                                 return (priq_pollq(cl));
  417 
  418                         m = priq_getq(cl);
  419                         if (m != NULL) {
  420                                 IFQ_DEC_LEN(ifq);
  421                                 if (qempty(cl->cl_q))
  422                                         cl->cl_period++;
  423                                 PKTCNTR_ADD(&cl->cl_xmitcnt, m_pktlen(m));
  424                         }
  425                         return (m);
  426                 }
  427         }
  428         return (NULL);
  429 }
  430 
  431 static int
  432 priq_addq(cl, m)
  433         struct priq_class *cl;
  434         struct mbuf *m;
  435 {
  436 
  437 #ifdef ALTQ_RIO
  438         if (q_is_rio(cl->cl_q))
  439                 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, m,
  440                                 cl->cl_pktattr);
  441 #endif
  442 #ifdef ALTQ_RED
  443         if (q_is_red(cl->cl_q))
  444                 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
  445 #endif
  446         if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
  447                 m_freem(m);
  448                 return (-1);
  449         }
  450         
  451         if (cl->cl_flags & PRCF_CLEARDSCP)
  452                 write_dsfield(m, cl->cl_pktattr, 0);
  453 
  454         _addq(cl->cl_q, m);
  455 
  456         return (0);
  457 }
  458 
  459 static struct mbuf *
  460 priq_getq(cl)
  461         struct priq_class *cl;
  462 {
  463 #ifdef ALTQ_RIO
  464         if (q_is_rio(cl->cl_q))
  465                 return rio_getq((rio_t *)cl->cl_red, cl->cl_q);
  466 #endif
  467 #ifdef ALTQ_RED
  468         if (q_is_red(cl->cl_q))
  469                 return red_getq(cl->cl_red, cl->cl_q);
  470 #endif
  471         return _getq(cl->cl_q);
  472 }
  473 
  474 static struct mbuf *
  475 priq_pollq(cl)
  476         struct priq_class *cl;
  477 {
  478         return qhead(cl->cl_q);
  479 }
  480 
  481 static void
  482 priq_purgeq(cl)
  483         struct priq_class *cl;
  484 {
  485         struct mbuf *m;
  486 
  487         if (qempty(cl->cl_q))
  488                 return;
  489 
  490         while ((m = _getq(cl->cl_q)) != NULL) {
  491                 PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m));
  492                 m_freem(m);
  493         }
  494         ASSERT(qlen(cl->cl_q) == 0);
  495 }
  496 
  497 /*
  498  * priq device interface
  499  */
  500 int
  501 priqopen(dev, flag, fmt, p)
  502         dev_t dev;
  503         int flag, fmt;
  504         struct proc *p;
  505 {
  506         /* everything will be done when the queueing scheme is attached. */
  507         return 0;
  508 }
  509 
  510 int
  511 priqclose(dev, flag, fmt, p)
  512         dev_t dev;
  513         int flag, fmt;
  514         struct proc *p;
  515 {
  516         struct priq_if *pif;
  517         int err, error = 0;
  518 
  519         while ((pif = pif_list) != NULL) {
  520                 /* destroy all */
  521                 if (ALTQ_IS_ENABLED(pif->pif_ifq))
  522                         altq_disable(pif->pif_ifq);
  523 
  524                 err = altq_detach(pif->pif_ifq);
  525                 if (err == 0)
  526                         err = priq_detach(pif);
  527                 if (err != 0 && error == 0)
  528                         error = err;
  529         }
  530 
  531         return error;
  532 }
  533 
  534 int
  535 priqioctl(dev, cmd, addr, flag, p)
  536         dev_t dev;
  537         ioctlcmd_t cmd;
  538         caddr_t addr;
  539         int flag;
  540         struct proc *p;
  541 {
  542         struct priq_if *pif;
  543         struct priq_interface *ifacep;
  544         int     error = 0;
  545 
  546         /* check super-user privilege */
  547         switch (cmd) {
  548         case PRIQ_GETSTATS:
  549                 break;
  550         default:
  551 #if (__FreeBSD_version > 400000)
  552                 if ((error = suser(p)) != 0)
  553                         return (error);
  554 #else
  555                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
  556                         return (error);
  557 #endif
  558                 break;
  559         }
  560     
  561         switch (cmd) {
  562 
  563         case PRIQ_IF_ATTACH:
  564                 error = priqcmd_if_attach((struct priq_interface *)addr);
  565                 break;
  566 
  567         case PRIQ_IF_DETACH:
  568                 error = priqcmd_if_detach((struct priq_interface *)addr);
  569                 break;
  570 
  571         case PRIQ_ENABLE:
  572         case PRIQ_DISABLE:
  573         case PRIQ_CLEAR:
  574                 ifacep = (struct priq_interface *)addr;
  575                 if ((pif = altq_lookup(ifacep->ifname,
  576                                        ALTQT_PRIQ)) == NULL) {
  577                         error = EBADF;
  578                         break;
  579                 }
  580 
  581                 switch (cmd) {
  582                 case PRIQ_ENABLE:
  583                         if (pif->pif_default == NULL) {
  584 #if 1
  585                                 printf("priq: no default class\n");
  586 #endif
  587                                 error = EINVAL;
  588                                 break;
  589                         }
  590                         error = altq_enable(pif->pif_ifq);
  591                         break;
  592 
  593                 case PRIQ_DISABLE:
  594                         error = altq_disable(pif->pif_ifq);
  595                         break;
  596 
  597                 case PRIQ_CLEAR:
  598                         priq_clear_interface(pif);
  599                         break;
  600                 }
  601                 break;
  602 
  603         case PRIQ_ADD_CLASS:
  604                 error = priqcmd_add_class((struct priq_add_class *)addr);
  605                 break;
  606 
  607         case PRIQ_DEL_CLASS:
  608                 error = priqcmd_delete_class((struct priq_delete_class *)addr);
  609                 break;
  610 
  611         case PRIQ_MOD_CLASS:
  612                 error = priqcmd_modify_class((struct priq_modify_class *)addr);
  613                 break;
  614 
  615         case PRIQ_ADD_FILTER:
  616                 error = priqcmd_add_filter((struct priq_add_filter *)addr);
  617                 break;
  618 
  619         case PRIQ_DEL_FILTER:
  620                 error = priqcmd_delete_filter((struct priq_delete_filter *)addr);
  621                 break;
  622 
  623         case PRIQ_GETSTATS:
  624                 error = priqcmd_class_stats((struct priq_class_stats *)addr);
  625                 break;
  626 
  627         default:
  628                 error = EINVAL;
  629                 break;
  630         }
  631         return error;
  632 }
  633 
  634 static int
  635 priqcmd_if_attach(ap)
  636         struct priq_interface *ap;
  637 {
  638         struct priq_if *pif;
  639         struct ifnet *ifp;
  640         int error;
  641         
  642         if ((ifp = ifunit(ap->ifname)) == NULL)
  643                 return (ENXIO);
  644 
  645         if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL)
  646                 return (ENOMEM);
  647         
  648         /*
  649          * set PRIQ to this ifnet structure.
  650          */
  651         if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif,
  652                                  priq_enqueue, priq_dequeue, priq_request,
  653                                  &pif->pif_classifier, acc_classify)) != 0)
  654                 (void)priq_detach(pif);
  655 
  656         return (error);
  657 }
  658 
  659 static int
  660 priqcmd_if_detach(ap)
  661         struct priq_interface *ap;
  662 {
  663         struct priq_if *pif;
  664         int error;
  665 
  666         if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL)
  667                 return (EBADF);
  668         
  669         if (ALTQ_IS_ENABLED(pif->pif_ifq))
  670                 altq_disable(pif->pif_ifq);
  671 
  672         if ((error = altq_detach(pif->pif_ifq)))
  673                 return (error);
  674 
  675         return priq_detach(pif);
  676 }
  677 
  678 static int
  679 priqcmd_add_class(ap)
  680         struct priq_add_class *ap;
  681 {
  682         struct priq_if *pif;
  683         struct priq_class *cl;
  684 
  685         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  686                 return (EBADF);
  687 
  688         if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
  689                 return (EINVAL);
  690 
  691         if ((cl = priq_class_create(pif, ap->pri,
  692                                     ap->qlimit, ap->flags)) == NULL)
  693                 return (ENOMEM);
  694                 
  695         /* return a class handle to the user */
  696         ap->class_handle = clp_to_clh(cl);
  697         return (0);
  698 }
  699 
  700 static int
  701 priqcmd_delete_class(ap)
  702         struct priq_delete_class *ap;
  703 {
  704         struct priq_if *pif;
  705         struct priq_class *cl;
  706 
  707         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  708                 return (EBADF);
  709 
  710         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  711                 return (EINVAL);
  712         
  713         return priq_class_destroy(cl);
  714 }
  715 
  716 static int
  717 priqcmd_modify_class(ap)
  718         struct priq_modify_class *ap;
  719 {
  720         struct priq_if *pif;
  721         struct priq_class *cl;
  722 
  723         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  724                 return (EBADF);
  725 
  726         if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
  727                 return (EINVAL);
  728 
  729         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  730                 return (EINVAL);
  731 
  732         /*
  733          * if priority is changed, move the class to the new priority
  734          */
  735         if (pif->pif_classes[ap->pri] != cl) {
  736                 if (pif->pif_classes[ap->pri] != NULL)
  737                         return (EEXIST);
  738                 pif->pif_classes[cl->cl_pri] = NULL;
  739                 pif->pif_classes[ap->pri] = cl;
  740                 cl->cl_pri = ap->pri;
  741         }
  742 
  743         /* call priq_class_create to change class parameters */
  744         if ((cl = priq_class_create(pif, ap->pri,
  745                                     ap->qlimit, ap->flags)) == NULL)
  746                 return (ENOMEM);
  747         return 0;
  748 }
  749 
  750 static int
  751 priqcmd_add_filter(ap)
  752         struct priq_add_filter *ap;
  753 {
  754         struct priq_if *pif;
  755         struct priq_class *cl;
  756 
  757         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  758                 return (EBADF);
  759 
  760         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  761                 return (EINVAL);
  762 
  763         return acc_add_filter(&pif->pif_classifier, &ap->filter,
  764                               cl, &ap->filter_handle);
  765 }
  766 
  767 static int
  768 priqcmd_delete_filter(ap)
  769         struct priq_delete_filter *ap;
  770 {
  771         struct priq_if *pif;
  772 
  773         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  774                 return (EBADF);
  775 
  776         return acc_delete_filter(&pif->pif_classifier,
  777                                  ap->filter_handle);
  778 }
  779 
  780 static int
  781 priqcmd_class_stats(ap)
  782         struct priq_class_stats *ap;
  783 {
  784         struct priq_if *pif;
  785         struct priq_class *cl;
  786         struct priq_basic_class_stats stats, *usp;
  787         int     pri, error;
  788         
  789         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  790                 return (EBADF);
  791 
  792         ap->maxpri = pif->pif_maxpri;
  793 
  794         /* then, read the next N classes in the tree */
  795         usp = ap->stats;
  796         for (pri = 0; pri <= pif->pif_maxpri; pri++) {
  797                 cl = pif->pif_classes[pri];
  798                 if (cl != NULL)
  799                         get_class_stats(&stats, cl);
  800                 else
  801                         (void)memset(&stats, 0, sizeof(stats));
  802                 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
  803                                      sizeof(stats))) != 0)
  804                         return (error);
  805         }
  806         return (0);
  807 }
  808 
  809 static void get_class_stats(sp, cl)
  810         struct priq_basic_class_stats *sp;
  811         struct priq_class *cl;
  812 {
  813         sp->class_handle = clp_to_clh(cl);
  814 
  815         sp->qlength = qlen(cl->cl_q);
  816         sp->period = cl->cl_period;
  817         sp->xmitcnt = cl->cl_xmitcnt;
  818         sp->dropcnt = cl->cl_dropcnt;
  819 
  820         sp->qtype = qtype(cl->cl_q);
  821 #ifdef ALTQ_RED
  822         if (q_is_red(cl->cl_q))
  823                 red_getstats(cl->cl_red, &sp->red[0]);
  824 #endif
  825 #ifdef ALTQ_RIO
  826         if (q_is_rio(cl->cl_q))
  827                 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
  828 #endif
  829 
  830 }
  831 
  832 /* convert a class handle to the corresponding class pointer */
  833 static struct priq_class *
  834 clh_to_clp(pif, chandle)
  835         struct priq_if *pif;
  836         u_long chandle;
  837 {
  838         struct priq_class *cl;
  839 
  840         cl = (struct priq_class *)chandle;
  841         if (chandle != ALIGN(cl)) {
  842 #if 1
  843                 printf("clh_to_cl: unaligned pointer %p\n", cl);
  844 #endif
  845                 return (NULL);
  846         }
  847 
  848         if (cl == NULL || cl->cl_handle != chandle || cl->cl_pif != pif)
  849                 return (NULL);
  850         return (cl);
  851 }
  852 
  853 /* convert a class pointer to the corresponding class handle */
  854 static u_long
  855 clp_to_clh(cl)
  856         struct priq_class *cl;
  857 {
  858         return (cl->cl_handle);
  859 }
  860 
  861 #ifdef KLD_MODULE
  862 
  863 static struct altqsw priq_sw =
  864         {"priq", priqopen, priqclose, priqioctl};
  865 
  866 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw);
  867 
  868 #endif /* KLD_MODULE */
  869 
  870 #endif /* ALTQ_PRIQ */

Cache object: f664132de16c8dc8a20b78d06cdc1025


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