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.15 2006/11/16 01:32:37 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.15 2006/11/16 01:32:37 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                                       struct altq_pktattr *);
   75 static struct mbuf      *fifoq_dequeue(struct ifaltq *, int);
   76 static int              fifoq_detach(fifoq_state_t *);
   77 static int              fifoq_request(struct ifaltq *, int, void *);
   78 static void             fifoq_purge(fifoq_state_t *);
   79 
   80 /*
   81  * fifoq device interface
   82  */
   83 altqdev_decl(fifoq);
   84 
   85 int
   86 fifoqopen(dev_t dev, int flag, int fmt,
   87     struct lwp *l)
   88 {
   89         /* everything will be done when the queueing scheme is attached. */
   90         return 0;
   91 }
   92 
   93 /*
   94  * there are 2 ways to act on close.
   95  *   detach-all-on-close:
   96  *      use for the daemon style approach.  if the daemon dies, all the
   97  *      resource will be released.
   98  *   no-action-on-close:
   99  *      use for the command style approach.  (e.g.  fifoq on/off)
  100  *
  101  * note: close is called not on every close but when the last reference
  102  *       is removed (only once with multiple simultaneous references.)
  103  */
  104 int
  105 fifoqclose(dev_t dev, int flag, int fmt,
  106     struct lwp *l)
  107 {
  108         fifoq_state_t *q;
  109         int err, error = 0;
  110 
  111         while ((q = fifoq_list) != NULL) {
  112                 /* destroy all */
  113                 err = fifoq_detach(q);
  114                 if (err != 0 && error == 0)
  115                         error = err;
  116         }
  117 
  118         return error;
  119 }
  120 
  121 int
  122 fifoqioctl(dev_t dev, ioctlcmd_t cmd, caddr_t addr, int flag,
  123     struct lwp *l)
  124 {
  125         fifoq_state_t *q;
  126         struct fifoq_interface *ifacep;
  127         struct ifnet *ifp;
  128         int     error = 0;
  129 
  130         /* check super-user privilege */
  131         switch (cmd) {
  132         case FIFOQ_GETSTATS:
  133                 break;
  134         default:
  135 #if (__FreeBSD_version > 400000)
  136                 if ((error = suser(p)) != 0)
  137                         return (error);
  138 #else
  139                 if ((error = kauth_authorize_network(l->l_cred,
  140                     KAUTH_NETWORK_ALTQ, KAUTH_REQ_NETWORK_ALTQ_FIFOQ, NULL,
  141                     NULL, NULL)) != 0)
  142                         return (error);
  143 #endif
  144                 break;
  145         }
  146 
  147         switch (cmd) {
  148         case FIFOQ_ENABLE:
  149                 ifacep = (struct fifoq_interface *)addr;
  150                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  151                     == NULL) {
  152                         error = EBADF;
  153                         break;
  154                 }
  155                 error = altq_enable(q->q_ifq);
  156                 break;
  157 
  158         case FIFOQ_DISABLE:
  159                 ifacep = (struct fifoq_interface *)addr;
  160                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  161                     == NULL) {
  162                         error = EBADF;
  163                         break;
  164                 }
  165                 error = altq_disable(q->q_ifq);
  166                 break;
  167 
  168         case FIFOQ_IF_ATTACH:
  169                 ifp = ifunit(((struct fifoq_interface *)addr)->fifoq_ifname);
  170                 if (ifp == NULL) {
  171                         error = ENXIO;
  172                         break;
  173                 }
  174 
  175                 /* allocate and initialize fifoq_state_t */
  176                 q = malloc(sizeof(fifoq_state_t), M_DEVBUF, M_WAITOK|M_ZERO);
  177                 if (q == NULL) {
  178                         error = ENOMEM;
  179                         break;
  180                 }
  181 
  182                 q->q_ifq = &ifp->if_snd;
  183                 q->q_head = q->q_tail = NULL;
  184                 q->q_len = 0;
  185                 q->q_limit = FIFOQ_LIMIT;
  186 
  187                 /*
  188                  * set FIFOQ to this ifnet structure.
  189                  */
  190                 error = altq_attach(q->q_ifq, ALTQT_FIFOQ, q,
  191                                     fifoq_enqueue, fifoq_dequeue, fifoq_request,
  192                                     NULL, NULL);
  193                 if (error) {
  194                         free(q, M_DEVBUF);
  195                         break;
  196                 }
  197 
  198                 /* add this state to the fifoq list */
  199                 q->q_next = fifoq_list;
  200                 fifoq_list = q;
  201                 break;
  202 
  203         case FIFOQ_IF_DETACH:
  204                 ifacep = (struct fifoq_interface *)addr;
  205                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  206                     == NULL) {
  207                         error = EBADF;
  208                         break;
  209                 }
  210                 error = fifoq_detach(q);
  211                 break;
  212 
  213         case FIFOQ_GETSTATS:
  214                 do {
  215                         struct fifoq_getstats *q_stats;
  216 
  217                         q_stats = (struct fifoq_getstats *)addr;
  218                         if ((q = altq_lookup(q_stats->iface.fifoq_ifname,
  219                                              ALTQT_FIFOQ)) == NULL) {
  220                                 error = EBADF;
  221                                 break;
  222                         }
  223 
  224                         q_stats->q_len          = q->q_len;
  225                         q_stats->q_limit        = q->q_limit;
  226                         q_stats->xmit_cnt       = q->q_stats.xmit_cnt;
  227                         q_stats->drop_cnt       = q->q_stats.drop_cnt;
  228                         q_stats->period         = q->q_stats.period;
  229                 } while (/*CONSTCOND*/ 0);
  230                 break;
  231 
  232         case FIFOQ_CONFIG:
  233                 do {
  234                         struct fifoq_conf *fc;
  235                         int limit;
  236 
  237                         fc = (struct fifoq_conf *)addr;
  238                         if ((q = altq_lookup(fc->iface.fifoq_ifname,
  239                                              ALTQT_FIFOQ)) == NULL) {
  240                                 error = EBADF;
  241                                 break;
  242                         }
  243                         limit = fc->fifoq_limit;
  244                         if (limit < 0)
  245                                 limit = 0;
  246                         q->q_limit = limit;
  247                         fc->fifoq_limit = limit;
  248                 } while (/*CONSTCOND*/ 0);
  249                 break;
  250 
  251         default:
  252                 error = EINVAL;
  253                 break;
  254         }
  255         return error;
  256 }
  257 
  258 /*
  259  * fifoq support routines
  260  */
  261 
  262 /*
  263  * enqueue routine:
  264  *
  265  *      returns: 0 when successfully queued.
  266  *               ENOBUFS when drop occurs.
  267  */
  268 static int
  269 fifoq_enqueue(struct ifaltq *ifq, struct mbuf *m,
  270     struct altq_pktattr *pktattr)
  271 {
  272         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  273 
  274         /* if the queue is full, drop the incoming packet(drop-tail) */
  275         if (q->q_len >= q->q_limit) {
  276 #ifdef FIFOQ_STATS
  277                 PKTCNTR_ADD(&q->q_stats.drop_cnt, m_pktlen(m));
  278 #endif
  279                 m_freem(m);
  280                 return (ENOBUFS);
  281         }
  282 
  283         /* enqueue the packet at the taile of the queue */
  284         m->m_nextpkt = NULL;
  285         if (q->q_tail == NULL)
  286                 q->q_head = m;
  287         else
  288                 q->q_tail->m_nextpkt = m;
  289         q->q_tail = m;
  290         q->q_len++;
  291         ifq->ifq_len++;
  292         return 0;
  293 }
  294 
  295 /*
  296  * dequeue routine:
  297  *      must be called in splnet.
  298  *
  299  *      returns: mbuf dequeued.
  300  *               NULL when no packet is available in the queue.
  301  */
  302 /*
  303  * ALTDQ_PEEK is provided for drivers which need to know the next packet
  304  * to send in advance.
  305  * when ALTDQ_PEEK is specified, the next packet to be dequeued is
  306  * returned without dequeueing the packet.
  307  * when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
  308  * operation, the same packet should be returned.
  309  */
  310 static struct mbuf *
  311 fifoq_dequeue(struct ifaltq *ifq, int op)
  312 {
  313         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  314         struct mbuf *m = NULL;
  315 
  316         if (op == ALTDQ_POLL)
  317                 return (q->q_head);
  318 
  319         if ((m = q->q_head) == NULL)
  320                 return (NULL);
  321 
  322         if ((q->q_head = m->m_nextpkt) == NULL)
  323                 q->q_tail = NULL;
  324         m->m_nextpkt = NULL;
  325         q->q_len--;
  326         ifq->ifq_len--;
  327 #ifdef FIFOQ_STATS
  328         PKTCNTR_ADD(&q->q_stats.xmit_cnt, m_pktlen(m));
  329         if (q->q_len == 0)
  330                 q->q_stats.period++;
  331 #endif
  332         return (m);
  333 }
  334 
  335 static int
  336 fifoq_request(struct ifaltq *ifq, int req, void *arg)
  337 {
  338         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  339 
  340         switch (req) {
  341         case ALTRQ_PURGE:
  342                 fifoq_purge(q);
  343                 break;
  344         }
  345         return (0);
  346 }
  347 
  348 
  349 static int
  350 fifoq_detach(fifoq_state_t *q)
  351 {
  352         fifoq_state_t *tmp;
  353         int error = 0;
  354 
  355         if (ALTQ_IS_ENABLED(q->q_ifq))
  356                 altq_disable(q->q_ifq);
  357 
  358         fifoq_purge(q);
  359 
  360         if ((error = altq_detach(q->q_ifq)))
  361                 return (error);
  362 
  363         if (fifoq_list == q)
  364                 fifoq_list = q->q_next;
  365         else {
  366                 for (tmp = fifoq_list; tmp != NULL; tmp = tmp->q_next)
  367                         if (tmp->q_next == q) {
  368                                 tmp->q_next = q->q_next;
  369                                 break;
  370                         }
  371                 if (tmp == NULL)
  372                         printf("fifoq_detach: no state in fifoq_list!\n");
  373         }
  374 
  375         free(q, M_DEVBUF);
  376         return (error);
  377 }
  378 
  379 /*
  380  * fifoq_purge
  381  * should be called in splnet or after disabling the fifoq.
  382  */
  383 static void
  384 fifoq_purge(fifoq_state_t *q)
  385 {
  386         struct mbuf *m;
  387 
  388         while ((m = q->q_head) != NULL) {
  389                 q->q_head = m->m_nextpkt;
  390                 m_freem(m);
  391         }
  392         q->q_tail = NULL;
  393         q->q_len = 0;
  394         if (ALTQ_IS_ENABLED(q->q_ifq))
  395                 q->q_ifq->ifq_len = 0;
  396 }
  397 
  398 #ifdef KLD_MODULE
  399 
  400 static struct altqsw fifoq_sw =
  401         {"fifoq", fifoqopen, fifoqclose, fifoqioctl};
  402 
  403 ALTQ_MODULE(altq_fifoq, ALTQT_FIFOQ, &fifoq_sw);
  404 
  405 #endif /* KLD_MODULE */
  406 
  407 #endif /* ALTQ3_COMPAT */
  408 #endif /* ALTQ_FIFOQ */

Cache object: dfd12c3654ba50e47625aba3e18509dc


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