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.5 2003/11/09 22:11:12 christos Exp $  */
    2 /*      $KAME: altq_fifoq.c,v 1.7 2000/12/14 08:12:45 thorpej Exp $     */
    3 
    4 /*
    5  * Copyright (C) 1997-2000
    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.5 2003/11/09 22:11:12 christos Exp $");
   32 
   33 #if defined(__FreeBSD__) || defined(__NetBSD__)
   34 #include "opt_altq.h"
   35 #endif /* __FreeBSD__ || __NetBSD__ */
   36 #ifdef ALTQ_FIFOQ  /* fifoq is enabled by ALTQ_FIFOQ option in opt_altq.h */
   37 
   38 /*
   39  * FIFOQ is an altq sample implementation.  There will be little
   40  * need to use FIFOQ as an alternative queueing scheme.
   41  * But this code is provided as a template for those who want to
   42  * write their own queueing schemes.
   43  */
   44 
   45 #include <sys/param.h>
   46 #include <sys/malloc.h>
   47 #include <sys/mbuf.h>
   48 #include <sys/socket.h>
   49 #include <sys/sockio.h>
   50 #include <sys/systm.h>
   51 #include <sys/proc.h>
   52 #include <sys/errno.h>
   53 #include <sys/kernel.h>
   54 
   55 #include <net/if.h>
   56 #include <net/if_types.h>
   57 #include <netinet/in.h>
   58 
   59 #include <altq/altq.h>
   60 #include <altq/altq_conf.h>
   61 #include <altq/altq_fifoq.h>
   62 
   63 /* fifoq_list keeps all fifoq_state_t's allocated. */
   64 static fifoq_state_t *fifoq_list = NULL;
   65 
   66 /* internal function prototypes */
   67 static int              fifoq_enqueue __P((struct ifaltq *, struct mbuf *,
   68                                            struct altq_pktattr *));
   69 static struct mbuf      *fifoq_dequeue __P((struct ifaltq *, int));
   70 static int              fifoq_detach __P((fifoq_state_t *));
   71 static int              fifoq_request __P((struct ifaltq *, int, void *));
   72 static void             fifoq_purge __P((fifoq_state_t *));
   73 
   74 /*
   75  * fifoq device interface
   76  */
   77 altqdev_decl(fifoq);
   78 
   79 int
   80 fifoqopen(dev, flag, fmt, p)
   81         dev_t dev;
   82         int flag, fmt;
   83         struct proc *p;
   84 {
   85         /* everything will be done when the queueing scheme is attached. */
   86         return 0;
   87 }
   88 
   89 /*
   90  * there are 2 ways to act on close.
   91  *   detach-all-on-close:
   92  *      use for the daemon style approach.  if the daemon dies, all the
   93  *      resource will be released.
   94  *   no-action-on-close:
   95  *      use for the command style approach.  (e.g.  fifoq on/off)
   96  *
   97  * note: close is called not on every close but when the last reference
   98  *       is removed (only once with multiple simultaneous references.)
   99  */
  100 int
  101 fifoqclose(dev, flag, fmt, p)
  102         dev_t dev;
  103         int flag, fmt;
  104         struct proc *p;
  105 {
  106         fifoq_state_t *q;
  107         int err, error = 0;
  108 
  109         while ((q = fifoq_list) != NULL) {
  110                 /* destroy all */
  111                 err = fifoq_detach(q);
  112                 if (err != 0 && error == 0)
  113                         error = err;
  114         }
  115 
  116         return error;
  117 }
  118 
  119 int
  120 fifoqioctl(dev, cmd, addr, flag, p)
  121         dev_t dev;
  122         ioctlcmd_t cmd;
  123         caddr_t addr;
  124         int flag;
  125         struct proc *p;
  126 {
  127         fifoq_state_t *q;
  128         struct fifoq_interface *ifacep;
  129         struct ifnet *ifp;
  130         int     error = 0;
  131 
  132         /* check super-user privilege */
  133         switch (cmd) {
  134         case FIFOQ_GETSTATS:
  135                 break;
  136         default:
  137 #if (__FreeBSD_version > 400000)
  138                 if ((error = suser(p)) != 0)
  139                         return (error);
  140 #else
  141                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 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                 MALLOC(q, fifoq_state_t *, sizeof(fifoq_state_t),
  177                        M_DEVBUF, M_WAITOK);
  178                 if (q == NULL) {
  179                         error = ENOMEM;
  180                         break;
  181                 }
  182                 (void)memset(q, 0, sizeof(fifoq_state_t));
  183 
  184                 q->q_ifq = &ifp->if_snd;
  185                 q->q_head = q->q_tail = NULL;
  186                 q->q_len = 0;
  187                 q->q_limit = FIFOQ_LIMIT;
  188 
  189                 /*
  190                  * set FIFOQ to this ifnet structure.
  191                  */
  192                 error = altq_attach(q->q_ifq, ALTQT_FIFOQ, q,
  193                                     fifoq_enqueue, fifoq_dequeue, fifoq_request,
  194                                     NULL, NULL);
  195                 if (error) {
  196                         FREE(q, M_DEVBUF);
  197                         break;
  198                 }
  199 
  200                 /* add this state to the fifoq list */
  201                 q->q_next = fifoq_list;
  202                 fifoq_list = q;
  203                 break;
  204 
  205         case FIFOQ_IF_DETACH:
  206                 ifacep = (struct fifoq_interface *)addr;
  207                 if ((q = altq_lookup(ifacep->fifoq_ifname, ALTQT_FIFOQ))
  208                     == NULL) {
  209                         error = EBADF;
  210                         break;
  211                 }
  212                 error = fifoq_detach(q);
  213                 break;
  214 
  215         case FIFOQ_GETSTATS:
  216                 do {
  217                         struct fifoq_getstats *q_stats;
  218 
  219                         q_stats = (struct fifoq_getstats *)addr;
  220                         if ((q = altq_lookup(q_stats->iface.fifoq_ifname,
  221                                              ALTQT_FIFOQ)) == NULL) {
  222                                 error = EBADF;
  223                                 break;
  224                         }
  225 
  226                         q_stats->q_len          = q->q_len;
  227                         q_stats->q_limit        = q->q_limit;
  228                         q_stats->xmit_cnt       = q->q_stats.xmit_cnt;
  229                         q_stats->drop_cnt       = q->q_stats.drop_cnt;
  230                         q_stats->period         = q->q_stats.period;
  231                 } while (0);
  232                 break;
  233 
  234         case FIFOQ_CONFIG:
  235                 do {
  236                         struct fifoq_conf *fc;
  237                         int limit;
  238 
  239                         fc = (struct fifoq_conf *)addr;
  240                         if ((q = altq_lookup(fc->iface.fifoq_ifname,
  241                                              ALTQT_FIFOQ)) == NULL) {
  242                                 error = EBADF;
  243                                 break;
  244                         }
  245                         limit = fc->fifoq_limit;
  246                         if (limit < 0)
  247                                 limit = 0;
  248                         q->q_limit = limit;
  249                         fc->fifoq_limit = limit;
  250                 } while (0);
  251                 break;
  252 
  253         default:
  254                 error = EINVAL;
  255                 break;
  256         }
  257         return error;
  258 }
  259 
  260 /*
  261  * fifoq support routines
  262  */
  263 
  264 /*
  265  * enqueue routine:
  266  *
  267  *      returns: 0 when successfully queued.
  268  *               ENOBUFS when drop occurs.
  269  */
  270 static int
  271 fifoq_enqueue(ifq, m, pktattr)
  272         struct ifaltq *ifq;
  273         struct mbuf *m;
  274         struct altq_pktattr *pktattr;
  275 {
  276         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  277 
  278         /* if the queue is full, drop the incoming packet(drop-tail) */
  279         if (q->q_len >= q->q_limit) {
  280 #ifdef FIFOQ_STATS
  281                 PKTCNTR_ADD(&q->q_stats.drop_cnt, m_pktlen(m));
  282 #endif
  283                 m_freem(m);
  284                 return (ENOBUFS);
  285         }
  286 
  287         /* enqueue the packet at the taile of the queue */
  288         m->m_nextpkt = NULL;
  289         if (q->q_tail == NULL)
  290                 q->q_head = m;
  291         else
  292                 q->q_tail->m_nextpkt = m;
  293         q->q_tail = m;
  294         q->q_len++;
  295         ifq->ifq_len++;
  296         return 0;
  297 }
  298 
  299 /*
  300  * dequeue routine:
  301  *      must be called in splnet.
  302  *
  303  *      returns: mbuf dequeued.
  304  *               NULL when no packet is available in the queue.
  305  */
  306 /*
  307  * ALTDQ_PEEK is provided for drivers which need to know the next packet
  308  * to send in advance.
  309  * when ALTDQ_PEEK is specified, the next packet to be dequeued is
  310  * returned without dequeueing the packet.
  311  * when ALTDQ_DEQUEUE is called *immediately after* an ALTDQ_PEEK
  312  * operation, the same packet should be returned.
  313  */
  314 static struct mbuf *
  315 fifoq_dequeue(ifq, op)
  316         struct ifaltq *ifq;
  317         int op;
  318 {
  319         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  320         struct mbuf *m = NULL;
  321 
  322         if (op == ALTDQ_POLL)
  323                 return (q->q_head);
  324                 
  325         if ((m = q->q_head) == NULL)
  326                 return (NULL);
  327 
  328         if ((q->q_head = m->m_nextpkt) == NULL)
  329                 q->q_tail = NULL;
  330         m->m_nextpkt = NULL;
  331         q->q_len--;
  332         ifq->ifq_len--;
  333 #ifdef FIFOQ_STATS
  334         PKTCNTR_ADD(&q->q_stats.xmit_cnt, m_pktlen(m));
  335         if (q->q_len == 0)
  336                 q->q_stats.period++;
  337 #endif
  338         return (m);
  339 }
  340 
  341 static int
  342 fifoq_request(ifq, req, arg)
  343         struct ifaltq *ifq;
  344         int req;
  345         void *arg;
  346 {
  347         fifoq_state_t *q = (fifoq_state_t *)ifq->altq_disc;
  348 
  349         switch (req) {
  350         case ALTRQ_PURGE:
  351                 fifoq_purge(q);
  352                 break;
  353         }
  354         return (0);
  355 }
  356 
  357 
  358 static int fifoq_detach(q)
  359         fifoq_state_t *q;
  360 {
  361         fifoq_state_t *tmp;
  362         int error = 0;
  363 
  364         if (ALTQ_IS_ENABLED(q->q_ifq))
  365                 altq_disable(q->q_ifq);
  366 
  367         fifoq_purge(q);
  368 
  369         if ((error = altq_detach(q->q_ifq)))
  370                 return (error);
  371 
  372         if (fifoq_list == q)
  373                 fifoq_list = q->q_next;
  374         else {
  375                 for (tmp = fifoq_list; tmp != NULL; tmp = tmp->q_next)
  376                         if (tmp->q_next == q) {
  377                                 tmp->q_next = q->q_next;
  378                                 break;
  379                         }
  380                 if (tmp == NULL)
  381                         printf("fifoq_detach: no state in fifoq_list!\n");
  382         }
  383 
  384         FREE(q, M_DEVBUF);
  385         return (error);
  386 }
  387 
  388 /*
  389  * fifoq_purge
  390  * should be called in splnet or after disabling the fifoq.
  391  */
  392 static void fifoq_purge(q)
  393         fifoq_state_t *q;
  394 {
  395         struct mbuf *m;
  396 
  397         while ((m = q->q_head) != NULL) {
  398                 q->q_head = m->m_nextpkt;
  399                 m_freem(m);
  400         }
  401         q->q_tail = NULL;
  402         q->q_len = 0;
  403         if (ALTQ_IS_ENABLED(q->q_ifq))
  404                 q->q_ifq->ifq_len = 0;
  405 }
  406 
  407 #ifdef KLD_MODULE
  408 
  409 static struct altqsw fifoq_sw =
  410         {"fifoq", fifoqopen, fifoqclose, fifoqioctl};
  411 
  412 ALTQ_MODULE(altq_fifoq, ALTQT_FIFOQ, &fifoq_sw);
  413 
  414 #endif /* KLD_MODULE */
  415 
  416 #endif /* ALTQ_FIFOQ */

Cache object: 3e433b6c85b9a75c38f2312c282316a6


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