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_fifoq.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_fifoq.c,v 1.18 2021/09/21 14:30:15 christos Exp $ */
    2 /*      $KAME: altq_fifoq.c,v 1.12 2003/07/10 12:07:48 kjc Exp $        */
    3 
    4 /*
    5  * Copyright (C) 1997-2002
    6  *      Sony Computer Science Laboratories Inc.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __KERNEL_RCSID(0, "$NetBSD: altq_fifoq.c,v 1.18 2021/09/21 14:30:15 christos Exp $");
   32 
   33 #ifdef _KERNEL_OPT
   34 #include "opt_altq.h"
   35 #endif
   36 
   37 #ifdef ALTQ_FIFOQ  /* fifoq is enabled by ALTQ_FIFOQ option in opt_altq.h */
   38 
   39 /*
   40  * FIFOQ is an altq sample implementation.  There will be little
   41  * need to use FIFOQ as an alternative queueing scheme.
   42  * But this code is provided as a template for those who want to
   43  * write their own queueing schemes.
   44  */
   45 
   46 #include <sys/param.h>
   47 #include <sys/malloc.h>
   48 #include <sys/mbuf.h>
   49 #include <sys/socket.h>
   50 #include <sys/sockio.h>
   51 #include <sys/systm.h>
   52 #include <sys/proc.h>
   53 #include <sys/errno.h>
   54 #include <sys/kernel.h>
   55 #include <sys/kauth.h>
   56 
   57 #include <net/if.h>
   58 #include <net/if_types.h>
   59 #include <netinet/in.h>
   60 
   61 #include <altq/altq.h>
   62 #include <altq/altq_conf.h>
   63 #include <altq/altq_fifoq.h>
   64 
   65 #ifdef ALTQ3_COMPAT
   66 
   67 #define FIFOQ_STATS     /* collect statistics */
   68 
   69 /* fifoq_list keeps all fifoq_state_t's allocated. */
   70 static fifoq_state_t *fifoq_list = NULL;
   71 
   72 /* internal function prototypes */
   73 static int              fifoq_enqueue(struct ifaltq *, struct mbuf *);
   74 static struct mbuf      *fifoq_dequeue(struct ifaltq *, int);
   75 static int              fifoq_detach(fifoq_state_t *);
   76 static int              fifoq_request(struct ifaltq *, int, void *);
   77 static void             fifoq_purge(fifoq_state_t *);
   78 
   79 /*
   80  * fifoq device interface
   81  */
   82 altqdev_decl(fifoq);
   83 
   84 int
   85 fifoqopen(dev_t dev, int flag, int fmt,
   86     struct lwp *l)
   87 {
   88         /* everything will be done when the queueing scheme is attached. */
   89         return 0;
   90 }
   91 
   92 /*
   93  * there are 2 ways to act on close.
   94  *   detach-all-on-close:
   95  *      use for the daemon style approach.  if the daemon dies, all the
   96  *      resource will be released.
   97  *   no-action-on-close:
   98  *      use for the command style approach.  (e.g.  fifoq on/off)
   99  *
  100  * note: close is called not on every close but when the last reference
  101  *       is removed (only once with multiple simultaneous references.)
  102  */
  103 int
  104 fifoqclose(dev_t dev, int flag, int fmt,
  105     struct lwp *l)
  106 {
  107         fifoq_state_t *q;
  108         int err, error = 0;
  109 
  110         while ((q = fifoq_list) != NULL) {
  111                 /* destroy all */
  112                 err = fifoq_detach(q);
  113                 if (err != 0 && error == 0)
  114                         error = err;
  115         }
  116 
  117         return error;
  118 }
  119 
  120 int
  121 fifoqioctl(dev_t dev, ioctlcmd_t cmd, void *addr, int flag,
  122     struct lwp *l)
  123 {
  124         fifoq_state_t *q;
  125         struct fifoq_interface *ifacep;
  126         struct ifnet *ifp;
  127         int     error = 0;
  128 
  129         /* check super-user privilege */
  130         switch (cmd) {
  131         case FIFOQ_GETSTATS:
  132                 break;
  133         default:
  134                 if ((error = kauth_authorize_network(l->l_cred,
  135                     KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_FIFOQ, NULL,
  136                     NULL, NULL)) != 0)
  137                         return (error);
  138                 break;
  139         }
  140 
  141         switch (cmd) {
  142         case FIFOQ_ENABLE:
  143                 ifacep = (struct fifoq_interface *)addr;
  144                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  145                     == NULL) {
  146                         error = EBADF;
  147                         break;
  148                 }
  149                 error = altq_enable(q->q_ifq);
  150                 break;
  151 
  152         case FIFOQ_DISABLE:
  153                 ifacep = (struct fifoq_interface *)addr;
  154                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  155                     == NULL) {
  156                         error = EBADF;
  157                         break;
  158                 }
  159                 error = altq_disable(q->q_ifq);
  160                 break;
  161 
  162         case FIFOQ_IF_ATTACH:
  163                 ifp = ifunit(((struct fifoq_interface *)addr)->fifoq_ifname);
  164                 if (ifp == NULL) {
  165                         error = ENXIO;
  166                         break;
  167                 }
  168 
  169                 /* allocate and initialize fifoq_state_t */
  170                 q = malloc(sizeof(fifoq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
  171                 if (q == NULL) {
  172                         error = ENOMEM;
  173                         break;
  174                 }
  175 
  176                 q->q_ifq = &ifp->if_snd;
  177                 q->q_head = q->q_tail = NULL;
  178                 q->q_len = 0;
  179                 q->q_limit = FIFOQ_LIMIT;
  180 
  181                 /*
  182                  * set FIFOQ to this ifnet structure.
  183                  */
  184                 error = altq_attach(q->q_ifq, ALTQT_FIFOQ, q,
  185                                     fifoq_enqueue, fifoq_dequeue, fifoq_request,
  186                                     NULL, NULL);
  187                 if (error) {
  188                         free(q, M_DEVBUF);
  189                         break;
  190                 }
  191 
  192                 /* add this state to the fifoq list */
  193                 q->q_next = fifoq_list;
  194                 fifoq_list = q;
  195                 break;
  196 
  197         case FIFOQ_IF_DETACH:
  198                 ifacep = (struct fifoq_interface *)addr;
  199                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  200                     == NULL) {
  201                         error = EBADF;
  202                         break;
  203                 }
  204                 error = fifoq_detach(q);
  205                 break;
  206 
  207         case FIFOQ_GETSTATS:
  208                 do {
  209                         struct fifoq_getstats *q_stats;
  210 
  211                         q_stats = (struct fifoq_getstats *)addr;
  212                         if ((q = altq_lookup(q_stats->iface.fifoq_ifname,
  213                                              ALTQT_FIFOQ)) == NULL) {
  214                                 error = EBADF;
  215                                 break;
  216                         }
  217 
  218                         q_stats->q_len          = q->q_len;
  219                         q_stats->q_limit        = q->q_limit;
  220                         q_stats->xmit_cnt       = q->q_stats.xmit_cnt;
  221                         q_stats->drop_cnt       = q->q_stats.drop_cnt;
  222                         q_stats->period         = q->q_stats.period;
  223                 } while (/*CONSTCOND*/ 0);
  224                 break;
  225 
  226         case FIFOQ_CONFIG:
  227                 do {
  228                         struct fifoq_conf *fc;
  229                         int limit;
  230 
  231                         fc = (struct fifoq_conf *)addr;
  232                         if ((q = altq_lookup(fc->iface.fifoq_ifname,
  233                                              ALTQT_FIFOQ)) == NULL) {
  234                                 error = EBADF;
  235                                 break;
  236                         }
  237                         limit = fc->fifoq_limit;
  238                         if (limit < 0)
  239                                 limit = 0;
  240                         q->q_limit = limit;
  241                         fc->fifoq_limit = limit;
  242                 } while (/*CONSTCOND*/ 0);
  243                 break;
  244 
  245         default:
  246                 error = EINVAL;
  247                 break;
  248         }
  249         return error;
  250 }
  251 
  252 /*
  253  * fifoq support routines
  254  */
  255 
  256 /*
  257  * enqueue routine:
  258  *
  259  *      returns: 0 when successfully queued.
  260  *               ENOBUFS when drop occurs.
  261  */
  262 static int
  263 fifoq_enqueue(struct ifaltq *ifq, struct mbuf *m)
  264 {
  265         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  266 
  267         /* if the queue is full, drop the incoming packet(drop-tail) */
  268         if (q->q_len >= q->q_limit) {
  269 #ifdef FIFOQ_STATS
  270                 PKTCNTR_ADD(&q->q_stats.drop_cnt, m_pktlen(m));
  271 #endif
  272                 m_freem(m);
  273                 return (ENOBUFS);
  274         }
  275 
  276         /* enqueue the packet at the taile of the queue */
  277         m->m_nextpkt = NULL;
  278         if (q->q_tail == NULL)
  279                 q->q_head = m;
  280         else
  281                 q->q_tail->m_nextpkt = m;
  282         q->q_tail = m;
  283         q->q_len++;
  284         ifq->ifq_len++;
  285         return 0;
  286 }
  287 
  288 /*
  289  * dequeue routine:
  290  *      must be called in splnet.
  291  *
  292  *      returns: mbuf dequeued.
  293  *               NULL when no packet is available in the queue.
  294  */
  295 /*
  296  * ALTDQ_PEEK is provided for drivers which need to know the next packet
  297  * to send in advance.
  298  * when ALTDQ_PEEK is specified, the next packet to be dequeued is
  299  * returned without dequeueing the packet.
  300  * when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
  301  * operation, the same packet should be returned.
  302  */
  303 static struct mbuf *
  304 fifoq_dequeue(struct ifaltq *ifq, int op)
  305 {
  306         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  307         struct mbuf *m = NULL;
  308 
  309         if (op == ALTDQ_POLL)
  310                 return (q->q_head);
  311 
  312         if ((m = q->q_head) == NULL)
  313                 return (NULL);
  314 
  315         if ((q->q_head = m->m_nextpkt) == NULL)
  316                 q->q_tail = NULL;
  317         m->m_nextpkt = NULL;
  318         q->q_len--;
  319         ifq->ifq_len--;
  320 #ifdef FIFOQ_STATS
  321         PKTCNTR_ADD(&q->q_stats.xmit_cnt, m_pktlen(m));
  322         if (q->q_len == 0)
  323                 q->q_stats.period++;
  324 #endif
  325         return (m);
  326 }
  327 
  328 static int
  329 fifoq_request(struct ifaltq *ifq, int req, void *arg)
  330 {
  331         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  332 
  333         switch (req) {
  334         case ALTRQ_PURGE:
  335                 fifoq_purge(q);
  336                 break;
  337         }
  338         return (0);
  339 }
  340 
  341 
  342 static int
  343 fifoq_detach(fifoq_state_t *q)
  344 {
  345         fifoq_state_t *tmp;
  346         int error = 0;
  347 
  348         if (ALTQ_IS_ENABLED(q->q_ifq))
  349                 altq_disable(q->q_ifq);
  350 
  351         fifoq_purge(q);
  352 
  353         if ((error = altq_detach(q->q_ifq)))
  354                 return (error);
  355 
  356         if (fifoq_list == q)
  357                 fifoq_list = q->q_next;
  358         else {
  359                 for (tmp = fifoq_list; tmp != NULL; tmp = tmp->q_next)
  360                         if (tmp->q_next == q) {
  361                                 tmp->q_next = q->q_next;
  362                                 break;
  363                         }
  364                 if (tmp == NULL)
  365                         printf("fifoq_detach: no state in fifoq_list!\n");
  366         }
  367 
  368         free(q, M_DEVBUF);
  369         return (error);
  370 }
  371 
  372 /*
  373  * fifoq_purge
  374  * should be called in splnet or after disabling the fifoq.
  375  */
  376 static void
  377 fifoq_purge(fifoq_state_t *q)
  378 {
  379         struct mbuf *m;
  380 
  381         while ((m = q->q_head) != NULL) {
  382                 q->q_head = m->m_nextpkt;
  383                 m_freem(m);
  384         }
  385         q->q_tail = NULL;
  386         q->q_len = 0;
  387         if (ALTQ_IS_ENABLED(q->q_ifq))
  388                 q->q_ifq->ifq_len = 0;
  389 }
  390 
  391 #ifdef KLD_MODULE
  392 
  393 static struct altqsw fifoq_sw =
  394         {"fifoq", fifoqopen, fifoqclose, fifoqioctl};
  395 
  396 ALTQ_MODULE(altq_fifoq, ALTQT_FIFOQ, &fifoq_sw);
  397 
  398 #endif /* KLD_MODULE */
  399 
  400 #endif /* ALTQ3_COMPAT */
  401 #endif /* ALTQ_FIFOQ */

Cache object: d09bcf9367a41816e82e05771c7556da


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