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.20 2008/06/18 09:06:27 yamt Exp $      */
    2 /*      $KAME: altq_priq.c,v 1.13 2005/04/13 03:44:25 suz Exp $ */
    3 /*
    4  * Copyright (C) 2000-2003
    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 /*
   30  * priority queue
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: altq_priq.c,v 1.20 2008/06/18 09:06:27 yamt Exp $");
   35 
   36 #ifdef _KERNEL_OPT
   37 #include "opt_altq.h"
   38 #include "opt_inet.h"
   39 #include "pf.h"
   40 #endif
   41 
   42 #ifdef ALTQ_PRIQ  /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */
   43 
   44 #include <sys/param.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/socket.h>
   48 #include <sys/sockio.h>
   49 #include <sys/systm.h>
   50 #include <sys/proc.h>
   51 #include <sys/errno.h>
   52 #include <sys/kernel.h>
   53 #include <sys/queue.h>
   54 #include <sys/kauth.h>
   55 
   56 #include <net/if.h>
   57 #include <netinet/in.h>
   58 
   59 #if NPF > 0
   60 #include <net/pfvar.h>
   61 #endif
   62 #include <altq/altq.h>
   63 #include <altq/altq_conf.h>
   64 #include <altq/altq_priq.h>
   65 
   66 /*
   67  * function prototypes
   68  */
   69 #ifdef ALTQ3_COMPAT
   70 static struct priq_if *priq_attach(struct ifaltq *, u_int);
   71 static int priq_detach(struct priq_if *);
   72 #endif
   73 static int priq_clear_interface(struct priq_if *);
   74 static int priq_request(struct ifaltq *, int, void *);
   75 static void priq_purge(struct priq_if *);
   76 static struct priq_class *priq_class_create(struct priq_if *, int, int, int,
   77     int);
   78 static int priq_class_destroy(struct priq_class *);
   79 static int priq_enqueue(struct ifaltq *, struct mbuf *, struct altq_pktattr *);
   80 static struct mbuf *priq_dequeue(struct ifaltq *, int);
   81 
   82 static int priq_addq(struct priq_class *, struct mbuf *);
   83 static struct mbuf *priq_getq(struct priq_class *);
   84 static struct mbuf *priq_pollq(struct priq_class *);
   85 static void priq_purgeq(struct priq_class *);
   86 
   87 #ifdef ALTQ3_COMPAT
   88 static int priqcmd_if_attach(struct priq_interface *);
   89 static int priqcmd_if_detach(struct priq_interface *);
   90 static int priqcmd_add_class(struct priq_add_class *);
   91 static int priqcmd_delete_class(struct priq_delete_class *);
   92 static int priqcmd_modify_class(struct priq_modify_class *);
   93 static int priqcmd_add_filter(struct priq_add_filter *);
   94 static int priqcmd_delete_filter(struct priq_delete_filter *);
   95 static int priqcmd_class_stats(struct priq_class_stats *);
   96 #endif /* ALTQ3_COMPAT */
   97 
   98 static void get_class_stats(struct priq_classstats *, struct priq_class *);
   99 static struct priq_class *clh_to_clp(struct priq_if *, u_int32_t);
  100 
  101 #ifdef ALTQ3_COMPAT
  102 altqdev_decl(priq);
  103 
  104 /* pif_list keeps all priq_if's allocated. */
  105 static struct priq_if *pif_list = NULL;
  106 #endif /* ALTQ3_COMPAT */
  107 
  108 #if NPF > 0
  109 int
  110 priq_pfattach(struct pf_altq *a)
  111 {
  112         struct ifnet *ifp;
  113         int s, error;
  114 
  115         if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
  116                 return (EINVAL);
  117         s = splnet();
  118         error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, a->altq_disc,
  119             priq_enqueue, priq_dequeue, priq_request, NULL, NULL);
  120         splx(s);
  121         return (error);
  122 }
  123 
  124 int
  125 priq_add_altq(struct pf_altq *a)
  126 {
  127         struct priq_if  *pif;
  128         struct ifnet    *ifp;
  129 
  130         if ((ifp = ifunit(a->ifname)) == NULL)
  131                 return (EINVAL);
  132         if (!ALTQ_IS_READY(&ifp->if_snd))
  133                 return (ENODEV);
  134 
  135         pif = malloc(sizeof(struct priq_if), M_DEVBUF, M_WAITOK|M_ZERO);
  136         if (pif == NULL)
  137                 return (ENOMEM);
  138         pif->pif_bandwidth = a->ifbandwidth;
  139         pif->pif_maxpri = -1;
  140         pif->pif_ifq = &ifp->if_snd;
  141 
  142         /* keep the state in pf_altq */
  143         a->altq_disc = pif;
  144 
  145         return (0);
  146 }
  147 
  148 int
  149 priq_remove_altq(struct pf_altq *a)
  150 {
  151         struct priq_if *pif;
  152 
  153         if ((pif = a->altq_disc) == NULL)
  154                 return (EINVAL);
  155         a->altq_disc = NULL;
  156 
  157         (void)priq_clear_interface(pif);
  158 
  159         free(pif, M_DEVBUF);
  160         return (0);
  161 }
  162 
  163 int
  164 priq_add_queue(struct pf_altq *a)
  165 {
  166         struct priq_if *pif;
  167         struct priq_class *cl;
  168 
  169         if ((pif = a->altq_disc) == NULL)
  170                 return (EINVAL);
  171 
  172         /* check parameters */
  173         if (a->priority >= PRIQ_MAXPRI)
  174                 return (EINVAL);
  175         if (a->qid == 0)
  176                 return (EINVAL);
  177         if (pif->pif_classes[a->priority] != NULL)
  178                 return (EBUSY);
  179         if (clh_to_clp(pif, a->qid) != NULL)
  180                 return (EBUSY);
  181 
  182         cl = priq_class_create(pif, a->priority, a->qlimit,
  183             a->pq_u.priq_opts.flags, a->qid);
  184         if (cl == NULL)
  185                 return (ENOMEM);
  186 
  187         return (0);
  188 }
  189 
  190 int
  191 priq_remove_queue(struct pf_altq *a)
  192 {
  193         struct priq_if *pif;
  194         struct priq_class *cl;
  195 
  196         if ((pif = a->altq_disc) == NULL)
  197                 return (EINVAL);
  198 
  199         if ((cl = clh_to_clp(pif, a->qid)) == NULL)
  200                 return (EINVAL);
  201 
  202         return (priq_class_destroy(cl));
  203 }
  204 
  205 int
  206 priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
  207 {
  208         struct priq_if *pif;
  209         struct priq_class *cl;
  210         struct priq_classstats stats;
  211         int error = 0;
  212 
  213         if ((pif = altq_lookup(a->ifname, ALTQT_PRIQ)) == NULL)
  214                 return (EBADF);
  215 
  216         if ((cl = clh_to_clp(pif, a->qid)) == NULL)
  217                 return (EINVAL);
  218 
  219         if (*nbytes < sizeof(stats))
  220                 return (EINVAL);
  221 
  222         get_class_stats(&stats, cl);
  223 
  224         if ((error = copyout((void *)&stats, ubuf, sizeof(stats))) != 0)
  225                 return (error);
  226         *nbytes = sizeof(stats);
  227         return (0);
  228 }
  229 #endif /* NPF > 0 */
  230 
  231 /*
  232  * bring the interface back to the initial state by discarding
  233  * all the filters and classes.
  234  */
  235 static int
  236 priq_clear_interface(struct priq_if *pif)
  237 {
  238         struct priq_class       *cl;
  239         int pri;
  240 
  241 #ifdef ALTQ3_CLFIER_COMPAT
  242         /* free the filters for this interface */
  243         acc_discard_filters(&pif->pif_classifier, NULL, 1);
  244 #endif
  245 
  246         /* clear out the classes */
  247         for (pri = 0; pri <= pif->pif_maxpri; pri++)
  248                 if ((cl = pif->pif_classes[pri]) != NULL)
  249                         priq_class_destroy(cl);
  250 
  251         return (0);
  252 }
  253 
  254 static int
  255 priq_request(struct ifaltq *ifq, int req, void *arg)
  256 {
  257         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  258 
  259         switch (req) {
  260         case ALTRQ_PURGE:
  261                 priq_purge(pif);
  262                 break;
  263         }
  264         return (0);
  265 }
  266 
  267 /* discard all the queued packets on the interface */
  268 static void
  269 priq_purge(struct priq_if *pif)
  270 {
  271         struct priq_class *cl;
  272         int pri;
  273 
  274         for (pri = 0; pri <= pif->pif_maxpri; pri++) {
  275                 if ((cl = pif->pif_classes[pri]) != NULL && !qempty(cl->cl_q))
  276                         priq_purgeq(cl);
  277         }
  278         if (ALTQ_IS_ENABLED(pif->pif_ifq))
  279                 pif->pif_ifq->ifq_len = 0;
  280 }
  281 
  282 static struct priq_class *
  283 priq_class_create(struct priq_if *pif, int pri, int qlimit, int flags, int qid)
  284 {
  285         struct priq_class *cl;
  286         int s;
  287 
  288 #ifndef ALTQ_RED
  289         if (flags & PRCF_RED) {
  290 #ifdef ALTQ_DEBUG
  291                 printf("priq_class_create: RED not configured for PRIQ!\n");
  292 #endif
  293                 return (NULL);
  294         }
  295 #endif
  296 
  297         if ((cl = pif->pif_classes[pri]) != NULL) {
  298                 /* modify the class instead of creating a new one */
  299                 s = splnet();
  300                 if (!qempty(cl->cl_q))
  301                         priq_purgeq(cl);
  302                 splx(s);
  303 #ifdef ALTQ_RIO
  304                 if (q_is_rio(cl->cl_q))
  305                         rio_destroy((rio_t *)cl->cl_red);
  306 #endif
  307 #ifdef ALTQ_RED
  308                 if (q_is_red(cl->cl_q))
  309                         red_destroy(cl->cl_red);
  310 #endif
  311         } else {
  312                 cl = malloc(sizeof(struct priq_class), M_DEVBUF,
  313                     M_WAITOK|M_ZERO);
  314                 if (cl == NULL)
  315                         return (NULL);
  316 
  317                 cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF,
  318                     M_WAITOK|M_ZERO);
  319                 if (cl->cl_q == NULL)
  320                         goto err_ret;
  321         }
  322 
  323         pif->pif_classes[pri] = cl;
  324         if (flags & PRCF_DEFAULTCLASS)
  325                 pif->pif_default = cl;
  326         if (qlimit == 0)
  327                 qlimit = 50;  /* use default */
  328         qlimit(cl->cl_q) = qlimit;
  329         qtype(cl->cl_q) = Q_DROPTAIL;
  330         qlen(cl->cl_q) = 0;
  331         cl->cl_flags = flags;
  332         cl->cl_pri = pri;
  333         if (pri > pif->pif_maxpri)
  334                 pif->pif_maxpri = pri;
  335         cl->cl_pif = pif;
  336         cl->cl_handle = qid;
  337 
  338 #ifdef ALTQ_RED
  339         if (flags & (PRCF_RED|PRCF_RIO)) {
  340                 int red_flags, red_pkttime;
  341 
  342                 red_flags = 0;
  343                 if (flags & PRCF_ECN)
  344                         red_flags |= REDF_ECN;
  345 #ifdef ALTQ_RIO
  346                 if (flags & PRCF_CLEARDSCP)
  347                         red_flags |= RIOF_CLEARDSCP;
  348 #endif
  349                 if (pif->pif_bandwidth < 8)
  350                         red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
  351                 else
  352                         red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu
  353                           * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8);
  354 #ifdef ALTQ_RIO
  355                 if (flags & PRCF_RIO) {
  356                         cl->cl_red = (red_t *)rio_alloc(0, NULL,
  357                                                 red_flags, red_pkttime);
  358                         if (cl->cl_red != NULL)
  359                                 qtype(cl->cl_q) = Q_RIO;
  360                 } else
  361 #endif
  362                 if (flags & PRCF_RED) {
  363                         cl->cl_red = red_alloc(0, 0,
  364                             qlimit(cl->cl_q) * 10/100,
  365                             qlimit(cl->cl_q) * 30/100,
  366                             red_flags, red_pkttime);
  367                         if (cl->cl_red != NULL)
  368                                 qtype(cl->cl_q) = Q_RED;
  369                 }
  370         }
  371 #endif /* ALTQ_RED */
  372 
  373         return (cl);
  374 
  375  err_ret:
  376         if (cl->cl_red != NULL) {
  377 #ifdef ALTQ_RIO
  378                 if (q_is_rio(cl->cl_q))
  379                         rio_destroy((rio_t *)cl->cl_red);
  380 #endif
  381 #ifdef ALTQ_RED
  382                 if (q_is_red(cl->cl_q))
  383                         red_destroy(cl->cl_red);
  384 #endif
  385         }
  386         if (cl->cl_q != NULL)
  387                 free(cl->cl_q, M_DEVBUF);
  388         free(cl, M_DEVBUF);
  389         return (NULL);
  390 }
  391 
  392 static int
  393 priq_class_destroy(struct priq_class *cl)
  394 {
  395         struct priq_if *pif;
  396         int s, pri;
  397 
  398         s = splnet();
  399 
  400 #ifdef ALTQ3_CLFIER_COMPAT
  401         /* delete filters referencing to this class */
  402         acc_discard_filters(&cl->cl_pif->pif_classifier, cl, 0);
  403 #endif
  404 
  405         if (!qempty(cl->cl_q))
  406                 priq_purgeq(cl);
  407 
  408         pif = cl->cl_pif;
  409         pif->pif_classes[cl->cl_pri] = NULL;
  410         if (pif->pif_maxpri == cl->cl_pri) {
  411                 for (pri = cl->cl_pri; pri >= 0; pri--)
  412                         if (pif->pif_classes[pri] != NULL) {
  413                                 pif->pif_maxpri = pri;
  414                                 break;
  415                         }
  416                 if (pri < 0)
  417                         pif->pif_maxpri = -1;
  418         }
  419         splx(s);
  420 
  421         if (cl->cl_red != NULL) {
  422 #ifdef ALTQ_RIO
  423                 if (q_is_rio(cl->cl_q))
  424                         rio_destroy((rio_t *)cl->cl_red);
  425 #endif
  426 #ifdef ALTQ_RED
  427                 if (q_is_red(cl->cl_q))
  428                         red_destroy(cl->cl_red);
  429 #endif
  430         }
  431         free(cl->cl_q, M_DEVBUF);
  432         free(cl, M_DEVBUF);
  433         return (0);
  434 }
  435 
  436 /*
  437  * priq_enqueue is an enqueue function to be registered to
  438  * (*altq_enqueue) in struct ifaltq.
  439  */
  440 static int
  441 priq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
  442 {
  443         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  444         struct priq_class *cl;
  445         struct m_tag *t;
  446         int len;
  447 
  448         /* grab class set by classifier */
  449         if ((m->m_flags & M_PKTHDR) == 0) {
  450                 /* should not happen */
  451                 printf("altq: packet for %s does not have pkthdr\n",
  452                     ifq->altq_ifp->if_xname);
  453                 m_freem(m);
  454                 return (ENOBUFS);
  455         }
  456         cl = NULL;
  457         if ((t = m_tag_find(m, PACKET_TAG_ALTQ_QID, NULL)) != NULL)
  458                 cl = clh_to_clp(pif, ((struct altq_tag *)(t+1))->qid);
  459 #ifdef ALTQ3_COMPAT
  460         else if ((ifq->altq_flags & ALTQF_CLASSIFY) && pktattr != NULL)
  461                 cl = pktattr->pattr_class;
  462 #endif
  463         if (cl == NULL) {
  464                 cl = pif->pif_default;
  465                 if (cl == NULL) {
  466                         m_freem(m);
  467                         return (ENOBUFS);
  468                 }
  469         }
  470 #ifdef ALTQ3_COMPAT
  471         if (pktattr != NULL)
  472                 cl->cl_pktattr = pktattr;  /* save proto hdr used by ECN */
  473         else
  474 #endif
  475                 cl->cl_pktattr = NULL;
  476         len = m_pktlen(m);
  477         if (priq_addq(cl, m) != 0) {
  478                 /* drop occurred.  mbuf was freed in priq_addq. */
  479                 PKTCNTR_ADD(&cl->cl_dropcnt, len);
  480                 return (ENOBUFS);
  481         }
  482         IFQ_INC_LEN(ifq);
  483 
  484         /* successfully queued. */
  485         return (0);
  486 }
  487 
  488 /*
  489  * priq_dequeue is a dequeue function to be registered to
  490  * (*altq_dequeue) in struct ifaltq.
  491  *
  492  * note: ALTDQ_POLL returns the next packet without removing the packet
  493  *      from the queue.  ALTDQ_REMOVE is a normal dequeue operation.
  494  *      ALTDQ_REMOVE must return the same packet if called immediately
  495  *      after ALTDQ_POLL.
  496  */
  497 static struct mbuf *
  498 priq_dequeue(struct ifaltq *ifq, int op)
  499 {
  500         struct priq_if  *pif = (struct priq_if *)ifq->altq_disc;
  501         struct priq_class *cl;
  502         struct mbuf *m;
  503         int pri;
  504 
  505         if (IFQ_IS_EMPTY(ifq))
  506                 /* no packet in the queue */
  507                 return (NULL);
  508 
  509         for (pri = pif->pif_maxpri;  pri >= 0; pri--) {
  510                 if ((cl = pif->pif_classes[pri]) != NULL &&
  511                     !qempty(cl->cl_q)) {
  512                         if (op == ALTDQ_POLL)
  513                                 return (priq_pollq(cl));
  514 
  515                         m = priq_getq(cl);
  516                         if (m != NULL) {
  517                                 IFQ_DEC_LEN(ifq);
  518                                 if (qempty(cl->cl_q))
  519                                         cl->cl_period++;
  520                                 PKTCNTR_ADD(&cl->cl_xmitcnt, m_pktlen(m));
  521                         }
  522                         return (m);
  523                 }
  524         }
  525         return (NULL);
  526 }
  527 
  528 static int
  529 priq_addq(struct priq_class *cl, struct mbuf *m)
  530 {
  531 
  532 #ifdef ALTQ_RIO
  533         if (q_is_rio(cl->cl_q))
  534                 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, m,
  535                                 cl->cl_pktattr);
  536 #endif
  537 #ifdef ALTQ_RED
  538         if (q_is_red(cl->cl_q))
  539                 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
  540 #endif
  541         if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
  542                 m_freem(m);
  543                 return (-1);
  544         }
  545 
  546         if (cl->cl_flags & PRCF_CLEARDSCP)
  547                 write_dsfield(m, cl->cl_pktattr, 0);
  548 
  549         _addq(cl->cl_q, m);
  550 
  551         return (0);
  552 }
  553 
  554 static struct mbuf *
  555 priq_getq(struct priq_class *cl)
  556 {
  557 #ifdef ALTQ_RIO
  558         if (q_is_rio(cl->cl_q))
  559                 return rio_getq((rio_t *)cl->cl_red, cl->cl_q);
  560 #endif
  561 #ifdef ALTQ_RED
  562         if (q_is_red(cl->cl_q))
  563                 return red_getq(cl->cl_red, cl->cl_q);
  564 #endif
  565         return _getq(cl->cl_q);
  566 }
  567 
  568 static struct mbuf *
  569 priq_pollq(cl)
  570         struct priq_class *cl;
  571 {
  572         return qhead(cl->cl_q);
  573 }
  574 
  575 static void
  576 priq_purgeq(struct priq_class *cl)
  577 {
  578         struct mbuf *m;
  579 
  580         if (qempty(cl->cl_q))
  581                 return;
  582 
  583         while ((m = _getq(cl->cl_q)) != NULL) {
  584                 PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m));
  585                 m_freem(m);
  586         }
  587         ASSERT(qlen(cl->cl_q) == 0);
  588 }
  589 
  590 static void
  591 get_class_stats(struct priq_classstats *sp, struct priq_class *cl)
  592 {
  593         sp->class_handle = cl->cl_handle;
  594         sp->qlength = qlen(cl->cl_q);
  595         sp->qlimit = qlimit(cl->cl_q);
  596         sp->period = cl->cl_period;
  597         sp->xmitcnt = cl->cl_xmitcnt;
  598         sp->dropcnt = cl->cl_dropcnt;
  599 
  600         sp->qtype = qtype(cl->cl_q);
  601 #ifdef ALTQ_RED
  602         if (q_is_red(cl->cl_q))
  603                 red_getstats(cl->cl_red, &sp->red[0]);
  604 #endif
  605 #ifdef ALTQ_RIO
  606         if (q_is_rio(cl->cl_q))
  607                 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
  608 #endif
  609 
  610 }
  611 
  612 /* convert a class handle to the corresponding class pointer */
  613 static struct priq_class *
  614 clh_to_clp(struct priq_if *pif, u_int32_t chandle)
  615 {
  616         struct priq_class *cl;
  617         int idx;
  618 
  619         if (chandle == 0)
  620                 return (NULL);
  621 
  622         for (idx = pif->pif_maxpri; idx >= 0; idx--)
  623                 if ((cl = pif->pif_classes[idx]) != NULL &&
  624                     cl->cl_handle == chandle)
  625                         return (cl);
  626 
  627         return (NULL);
  628 }
  629 
  630 
  631 #ifdef ALTQ3_COMPAT
  632 
  633 static struct priq_if *
  634 priq_attach(struct ifaltq *ifq, u_int bandwidth)
  635 {
  636         struct priq_if *pif;
  637 
  638         pif = malloc(sizeof(struct priq_if), M_DEVBUF, M_WAITOK|M_ZERO);
  639         if (pif == NULL)
  640                 return (NULL);
  641         pif->pif_bandwidth = bandwidth;
  642         pif->pif_maxpri = -1;
  643         pif->pif_ifq = ifq;
  644 
  645         /* add this state to the priq list */
  646         pif->pif_next = pif_list;
  647         pif_list = pif;
  648 
  649         return (pif);
  650 }
  651 
  652 static int
  653 priq_detach(struct priq_if *pif)
  654 {
  655         (void)priq_clear_interface(pif);
  656 
  657         /* remove this interface from the pif list */
  658         if (pif_list == pif)
  659                 pif_list = pif->pif_next;
  660         else {
  661                 struct priq_if *p;
  662 
  663                 for (p = pif_list; p != NULL; p = p->pif_next)
  664                         if (p->pif_next == pif) {
  665                                 p->pif_next = pif->pif_next;
  666                                 break;
  667                         }
  668                 ASSERT(p != NULL);
  669         }
  670 
  671         free(pif, M_DEVBUF);
  672         return (0);
  673 }
  674 
  675 /*
  676  * priq device interface
  677  */
  678 int
  679 priqopen(dev_t dev, int flag, int fmt,
  680     struct lwp *l)
  681 {
  682         /* everything will be done when the queueing scheme is attached. */
  683         return 0;
  684 }
  685 
  686 int
  687 priqclose(dev_t dev, int flag, int fmt,
  688     struct lwp *l)
  689 {
  690         struct priq_if *pif;
  691         int err, error = 0;
  692 
  693         while ((pif = pif_list) != NULL) {
  694                 /* destroy all */
  695                 if (ALTQ_IS_ENABLED(pif->pif_ifq))
  696                         altq_disable(pif->pif_ifq);
  697 
  698                 err = altq_detach(pif->pif_ifq);
  699                 if (err == 0)
  700                         err = priq_detach(pif);
  701                 if (err != 0 && error == 0)
  702                         error = err;
  703         }
  704 
  705         return error;
  706 }
  707 
  708 int
  709 priqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
  710     struct lwp *l)
  711 {
  712         struct priq_if *pif;
  713         struct priq_interface *ifacep;
  714         int     error = 0;
  715 
  716         /* check super-user privilege */
  717         switch (cmd) {
  718         case PRIQ_GETSTATS:
  719                 break;
  720         default:
  721 #if (__FreeBSD_version > 400000)
  722                 if ((error = suser(p)) != 0)
  723                         return (error);
  724 #else
  725                 if ((error = kauth_authorize_network(l->l_cred,
  726                     KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_PRIQ, NULL,
  727                     NULL, NULL)) != 0)
  728                         return (error);
  729 #endif
  730                 break;
  731         }
  732 
  733         switch (cmd) {
  734 
  735         case PRIQ_IF_ATTACH:
  736                 error = priqcmd_if_attach((struct priq_interface *)addr);
  737                 break;
  738 
  739         case PRIQ_IF_DETACH:
  740                 error = priqcmd_if_detach((struct priq_interface *)addr);
  741                 break;
  742 
  743         case PRIQ_ENABLE:
  744         case PRIQ_DISABLE:
  745         case PRIQ_CLEAR:
  746                 ifacep = (struct priq_interface *)addr;
  747                 if ((pif = altq_lookup(ifacep->ifname,
  748                                        ALTQT_PRIQ)) == NULL) {
  749                         error = EBADF;
  750                         break;
  751                 }
  752 
  753                 switch (cmd) {
  754                 case PRIQ_ENABLE:
  755                         if (pif->pif_default == NULL) {
  756 #ifdef ALTQ_DEBUG
  757                                 printf("priq: no default class\n");
  758 #endif
  759                                 error = EINVAL;
  760                                 break;
  761                         }
  762                         error = altq_enable(pif->pif_ifq);
  763                         break;
  764 
  765                 case PRIQ_DISABLE:
  766                         error = altq_disable(pif->pif_ifq);
  767                         break;
  768 
  769                 case PRIQ_CLEAR:
  770                         priq_clear_interface(pif);
  771                         break;
  772                 }
  773                 break;
  774 
  775         case PRIQ_ADD_CLASS:
  776                 error = priqcmd_add_class((struct priq_add_class *)addr);
  777                 break;
  778 
  779         case PRIQ_DEL_CLASS:
  780                 error = priqcmd_delete_class((struct priq_delete_class *)addr);
  781                 break;
  782 
  783         case PRIQ_MOD_CLASS:
  784                 error = priqcmd_modify_class((struct priq_modify_class *)addr);
  785                 break;
  786 
  787         case PRIQ_ADD_FILTER:
  788                 error = priqcmd_add_filter((struct priq_add_filter *)addr);
  789                 break;
  790 
  791         case PRIQ_DEL_FILTER:
  792                 error = priqcmd_delete_filter((struct priq_delete_filter *)addr);
  793                 break;
  794 
  795         case PRIQ_GETSTATS:
  796                 error = priqcmd_class_stats((struct priq_class_stats *)addr);
  797                 break;
  798 
  799         default:
  800                 error = EINVAL;
  801                 break;
  802         }
  803         return error;
  804 }
  805 
  806 static int
  807 priqcmd_if_attach(struct priq_interface *ap)
  808 {
  809         struct priq_if *pif;
  810         struct ifnet *ifp;
  811         int error;
  812 
  813         if ((ifp = ifunit(ap->ifname)) == NULL)
  814                 return (ENXIO);
  815 
  816         if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL)
  817                 return (ENOMEM);
  818 
  819         /*
  820          * set PRIQ to this ifnet structure.
  821          */
  822         if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif,
  823                                  priq_enqueue, priq_dequeue, priq_request,
  824                                  &pif->pif_classifier, acc_classify)) != 0)
  825                 (void)priq_detach(pif);
  826 
  827         return (error);
  828 }
  829 
  830 static int
  831 priqcmd_if_detach(struct priq_interface *ap)
  832 {
  833         struct priq_if *pif;
  834         int error;
  835 
  836         if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL)
  837                 return (EBADF);
  838 
  839         if (ALTQ_IS_ENABLED(pif->pif_ifq))
  840                 altq_disable(pif->pif_ifq);
  841 
  842         if ((error = altq_detach(pif->pif_ifq)))
  843                 return (error);
  844 
  845         return priq_detach(pif);
  846 }
  847 
  848 static int
  849 priqcmd_add_class(struct priq_add_class *ap)
  850 {
  851         struct priq_if *pif;
  852         struct priq_class *cl;
  853         int qid;
  854 
  855         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  856                 return (EBADF);
  857 
  858         if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
  859                 return (EINVAL);
  860         if (pif->pif_classes[ap->pri] != NULL)
  861                 return (EBUSY);
  862 
  863         qid = ap->pri + 1;
  864         if ((cl = priq_class_create(pif, ap->pri,
  865             ap->qlimit, ap->flags, qid)) == NULL)
  866                 return (ENOMEM);
  867 
  868         /* return a class handle to the user */
  869         ap->class_handle = cl->cl_handle;
  870 
  871         return (0);
  872 }
  873 
  874 static int
  875 priqcmd_delete_class(struct priq_delete_class *ap)
  876 {
  877         struct priq_if *pif;
  878         struct priq_class *cl;
  879 
  880         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  881                 return (EBADF);
  882 
  883         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  884                 return (EINVAL);
  885 
  886         return priq_class_destroy(cl);
  887 }
  888 
  889 static int
  890 priqcmd_modify_class(struct priq_modify_class *ap)
  891 {
  892         struct priq_if *pif;
  893         struct priq_class *cl;
  894 
  895         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  896                 return (EBADF);
  897 
  898         if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
  899                 return (EINVAL);
  900 
  901         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  902                 return (EINVAL);
  903 
  904         /*
  905          * if priority is changed, move the class to the new priority
  906          */
  907         if (pif->pif_classes[ap->pri] != cl) {
  908                 if (pif->pif_classes[ap->pri] != NULL)
  909                         return (EEXIST);
  910                 pif->pif_classes[cl->cl_pri] = NULL;
  911                 pif->pif_classes[ap->pri] = cl;
  912                 cl->cl_pri = ap->pri;
  913         }
  914 
  915         /* call priq_class_create to change class parameters */
  916         if ((cl = priq_class_create(pif, ap->pri,
  917             ap->qlimit, ap->flags, ap->class_handle)) == NULL)
  918                 return (ENOMEM);
  919         return 0;
  920 }
  921 
  922 static int
  923 priqcmd_add_filter(struct priq_add_filter *ap)
  924 {
  925         struct priq_if *pif;
  926         struct priq_class *cl;
  927 
  928         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  929                 return (EBADF);
  930 
  931         if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
  932                 return (EINVAL);
  933 
  934         return acc_add_filter(&pif->pif_classifier, &ap->filter,
  935                               cl, &ap->filter_handle);
  936 }
  937 
  938 static int
  939 priqcmd_delete_filter(struct priq_delete_filter *ap)
  940 {
  941         struct priq_if *pif;
  942 
  943         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  944                 return (EBADF);
  945 
  946         return acc_delete_filter(&pif->pif_classifier,
  947                                  ap->filter_handle);
  948 }
  949 
  950 static int
  951 priqcmd_class_stats(struct priq_class_stats *ap)
  952 {
  953         struct priq_if *pif;
  954         struct priq_class *cl;
  955         struct priq_classstats stats, *usp;
  956         int     pri, error;
  957 
  958         if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
  959                 return (EBADF);
  960 
  961         ap->maxpri = pif->pif_maxpri;
  962 
  963         /* then, read the next N classes in the tree */
  964         usp = ap->stats;
  965         for (pri = 0; pri <= pif->pif_maxpri; pri++) {
  966                 cl = pif->pif_classes[pri];
  967                 if (cl != NULL)
  968                         get_class_stats(&stats, cl);
  969                 else
  970                         memset(&stats, 0, sizeof(stats));
  971                 if ((error = copyout((void *)&stats, (void *)usp++,
  972                                      sizeof(stats))) != 0)
  973                         return (error);
  974         }
  975         return (0);
  976 }
  977 
  978 #ifdef KLD_MODULE
  979 
  980 static struct altqsw priq_sw =
  981         {"priq", priqopen, priqclose, priqioctl};
  982 
  983 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw);
  984 MODULE_DEPEND(altq_priq, altq_red, 1, 1, 1);
  985 MODULE_DEPEND(altq_priq, altq_rio, 1, 1, 1);
  986 
  987 #endif /* KLD_MODULE */
  988 
  989 #endif /* ALTQ3_COMPAT */
  990 #endif /* ALTQ_PRIQ */

Cache object: 34d5de719947b5132fef315d6ce02766


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