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

Cache object: e536ff9686cc1b85625b5f6350f6971b


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