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/netgraph/ng_source.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 /*
    2  * ng_source.c
    3  *
    4  * Copyright 2002 Sandvine Inc.
    5  * All rights reserved.
    6  *
    7  * Subject to the following obligations and disclaimer of warranty, use and
    8  * redistribution of this software, in source or object code forms, with or
    9  * without modifications are expressly permitted by Sandvine Inc.; provided,
   10  * however, that:
   11  * 1. Any and all reproductions of the source or object code must include the
   12  *    copyright notice above and the following disclaimer of warranties; and
   13  * 2. No rights are granted, in any manner or form, to use Sandvine Inc.
   14  *    trademarks, including the mark "SANDVINE" on advertising, endorsements,
   15  *    or otherwise except as such appears in the above copyright notice or in
   16  *    the software.
   17  *
   18  * THIS SOFTWARE IS BEING PROVIDED BY SANDVINE "AS IS", AND TO THE MAXIMUM
   19  * EXTENT PERMITTED BY LAW, SANDVINE MAKES NO REPRESENTATIONS OR WARRANTIES,
   20  * EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, INCLUDING WITHOUT LIMITATION,
   21  * ANY AND ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
   22  * PURPOSE, OR NON-INFRINGEMENT.  SANDVINE DOES NOT WARRANT, GUARANTEE, OR
   23  * MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE
   24  * USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY
   25  * OR OTHERWISE.  IN NO EVENT SHALL SANDVINE BE LIABLE FOR ANY DAMAGES
   26  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   27  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   28  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   29  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   32  * THIS SOFTWARE, EVEN IF SANDVINE IS ADVISED OF THE POSSIBILITY OF SUCH
   33  * DAMAGE.
   34  *
   35  * Author: Dave Chapeskie <dchapeskie@sandvine.com>
   36  *
   37  * $FreeBSD: releng/5.0/sys/netgraph/ng_source.c 106435 2002-11-05 01:08:11Z julian $
   38  */
   39 
   40 /*
   41  * This node is used for high speed packet geneneration.  It queues
   42  * all data recieved on it's 'input' hook and when told to start via
   43  * a control message it sends the packets out it's 'output' hook.  In
   44  * this way this node can be preloaded with a packet stream which is
   45  * continuously sent.
   46  *
   47  * Currently it just copies the mbufs as required.  It could do various
   48  * tricks to try and avoid this.  Probably the best performance would
   49  * be achieved by modifying the appropriate drivers to be told to
   50  * self-re-enqueue packets (e.g. the if_bge driver could reuse the same
   51  * transmit descriptors) under control of this node; perhaps via some
   52  * flag in the mbuf or some such.  The node would peak at an appropriate
   53  * ifnet flag to see if such support is available for the connected
   54  * interface.
   55  */
   56 
   57 #include <sys/param.h>
   58 #include <sys/systm.h>
   59 #include <sys/errno.h>
   60 #include <sys/kernel.h>
   61 #include <sys/malloc.h>
   62 #include <sys/mbuf.h>
   63 #include <sys/socket.h>
   64 #include <net/if.h>
   65 #include <net/if_var.h>
   66 #include <netgraph/ng_message.h>
   67 #include <netgraph/netgraph.h>
   68 #include <netgraph/ng_parse.h>
   69 #include <netgraph/ng_ether.h>
   70 #include <netgraph/ng_source.h>
   71 
   72 #define NG_SOURCE_INTR_TICKS            1
   73 #define NG_SOURCE_DRIVER_IFQ_MAXLEN     (4*1024)
   74 
   75 
   76 /* Per hook info */
   77 struct source_hookinfo {
   78         hook_p                          hook;
   79 };
   80 
   81 /* Per node info */
   82 struct privdata {
   83         node_p                          node;
   84         struct source_hookinfo          input;
   85         struct source_hookinfo          output;
   86         struct ng_source_stats          stats;
   87         struct ifqueue                  snd_queue;      /* packets to send */
   88         struct ifnet                    *output_ifp;
   89         struct callout_handle           intr_ch;
   90         u_int64_t                       packets;        /* packets to send */
   91         u_int32_t                       queueOctets;
   92 };
   93 typedef struct privdata *sc_p;
   94 
   95 /* Node flags */
   96 #define NG_SOURCE_ACTIVE        (NGF_TYPE1)
   97 
   98 /* XXX */
   99 #if 1
  100 #undef KASSERT
  101 #define KASSERT(expr,msg) do {                  \
  102                 if (!(expr)) {                  \
  103                         printf msg ;            \
  104                         panic("Assertion");     \
  105                 }                               \
  106         } while(0)
  107 #endif
  108 
  109 /* Netgraph methods */
  110 static ng_constructor_t ng_source_constructor;
  111 static ng_rcvmsg_t      ng_source_rcvmsg;
  112 static ng_shutdown_t    ng_source_rmnode;
  113 static ng_newhook_t     ng_source_newhook;
  114 static ng_rcvdata_t     ng_source_rcvdata;
  115 static ng_disconnect_t  ng_source_disconnect;
  116 
  117 /* Other functions */
  118 static timeout_t        ng_source_intr;
  119 static void             ng_source_request_output_ifp (sc_p);
  120 static void             ng_source_clr_data (sc_p);
  121 static void             ng_source_start (sc_p);
  122 static void             ng_source_stop (sc_p);
  123 static int              ng_source_send (sc_p, int, int *);
  124 static int              ng_source_store_output_ifp(sc_p sc,
  125                             struct ng_mesg *msg);
  126 
  127 
  128 /* Parse type for timeval */
  129 static const struct ng_parse_struct_field ng_source_timeval_type_fields[] =
  130 {
  131         { "tv_sec",             &ng_parse_int32_type    },
  132         { "tv_usec",            &ng_parse_int32_type    },
  133         { NULL }
  134 };
  135 const struct ng_parse_type ng_source_timeval_type = {
  136         &ng_parse_struct_type,
  137         &ng_source_timeval_type_fields
  138 };
  139 
  140 /* Parse type for struct ng_source_stats */
  141 static const struct ng_parse_struct_field ng_source_stats_type_fields[]
  142         = NG_SOURCE_STATS_TYPE_INFO;
  143 static const struct ng_parse_type ng_source_stats_type = {
  144         &ng_parse_struct_type,
  145         &ng_source_stats_type_fields
  146 };
  147 
  148 /* List of commands and how to convert arguments to/from ASCII */
  149 static const struct ng_cmdlist ng_source_cmds[] = {
  150         {
  151           NGM_SOURCE_COOKIE,
  152           NGM_SOURCE_GET_STATS,
  153           "getstats",
  154           NULL,
  155           &ng_source_stats_type
  156         },
  157         {
  158           NGM_SOURCE_COOKIE,
  159           NGM_SOURCE_CLR_STATS,
  160           "clrstats",
  161           NULL,
  162           NULL
  163         },
  164         {
  165           NGM_SOURCE_COOKIE,
  166           NGM_SOURCE_GETCLR_STATS,
  167           "getclrstats",
  168           NULL,
  169           &ng_source_stats_type
  170         },
  171         {
  172           NGM_SOURCE_COOKIE,
  173           NGM_SOURCE_START,
  174           "start",
  175           &ng_parse_uint64_type,
  176           NULL
  177         },
  178         {
  179           NGM_SOURCE_COOKIE,
  180           NGM_SOURCE_STOP,
  181           "stop",
  182           NULL,
  183           NULL
  184         },
  185         {
  186           NGM_SOURCE_COOKIE,
  187           NGM_SOURCE_CLR_DATA,
  188           "clrdata",
  189           NULL,
  190           NULL
  191         },
  192         { 0 }
  193 };
  194 
  195 /* Netgraph type descriptor */
  196 static struct ng_type ng_source_typestruct = {
  197         NG_VERSION,
  198         NG_SOURCE_NODE_TYPE,
  199         NULL,                                   /* module event handler */
  200         ng_source_constructor,
  201         ng_source_rcvmsg,
  202         ng_source_rmnode,
  203         ng_source_newhook,
  204         NULL,                                   /* findhook */
  205         NULL,
  206         ng_source_rcvdata,                      /* rcvdata */
  207         ng_source_disconnect,
  208         ng_source_cmds
  209 };
  210 NETGRAPH_INIT(source, &ng_source_typestruct);
  211 
  212 /*
  213  * Node constructor
  214  */
  215 static int
  216 ng_source_constructor(node_p node)
  217 {
  218         sc_p sc;
  219 
  220         MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT);
  221         if (sc == NULL)
  222                 return (ENOMEM);
  223         bzero(sc, sizeof(*sc));
  224 
  225         NG_NODE_SET_PRIVATE(node, sc);
  226         sc->node = node;
  227         sc->snd_queue.ifq_maxlen = 2048;        /* XXX not checked */
  228         callout_handle_init(&sc->intr_ch);   /* XXX fix.. will
  229                                                 cause problems. */
  230         return (0);
  231 }
  232 
  233 /*
  234  * Add a hook
  235  */
  236 static int
  237 ng_source_newhook(node_p node, hook_p hook, const char *name)
  238 {
  239         sc_p sc;
  240 
  241         sc = NG_NODE_PRIVATE(node);
  242         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  243         if (strcmp(name, NG_SOURCE_HOOK_INPUT) == 0) {
  244                 sc->input.hook = hook;
  245                 NG_HOOK_SET_PRIVATE(hook, &sc->input);
  246         } else if (strcmp(name, NG_SOURCE_HOOK_OUTPUT) == 0) {
  247                 sc->output.hook = hook;
  248                 NG_HOOK_SET_PRIVATE(hook, &sc->output);
  249                 sc->output_ifp = 0;
  250                 bzero(&sc->stats, sizeof(sc->stats));
  251         } else
  252                 return (EINVAL);
  253         return (0);
  254 }
  255 
  256 /*
  257  * Receive a control message
  258  */
  259 static int
  260 ng_source_rcvmsg(node_p node, item_p item, hook_p lasthook)
  261 {
  262         sc_p sc;
  263         struct ng_mesg *resp = NULL;
  264         int error = 0;
  265         struct ng_mesg *msg;
  266 
  267         sc = NG_NODE_PRIVATE(node);
  268         NGI_GET_MSG(item, msg);
  269         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  270         switch (msg->header.typecookie) {
  271         case NGM_SOURCE_COOKIE:
  272                 if (msg->header.flags & NGF_RESP) {
  273                         error = EINVAL;
  274                         break;
  275                 }
  276                 switch (msg->header.cmd) {
  277                 case NGM_SOURCE_GET_STATS:
  278                 case NGM_SOURCE_CLR_STATS:
  279                 case NGM_SOURCE_GETCLR_STATS:
  280                     {
  281                         struct ng_source_stats *stats;
  282 
  283                         if (msg->header.cmd != NGM_SOURCE_CLR_STATS) {
  284                                 NG_MKRESPONSE(resp, msg,
  285                                     sizeof(*stats), M_NOWAIT);
  286                                 if (resp == NULL) {
  287                                         error = ENOMEM;
  288                                         goto done;
  289                                 }
  290                                 sc->stats.queueOctets = sc->queueOctets;
  291                                 sc->stats.queueFrames = sc->snd_queue.ifq_len;
  292                                 if ((sc->node->nd_flags & NG_SOURCE_ACTIVE)
  293                                     && !timevalisset(&sc->stats.endTime)) {
  294                                         getmicrotime(&sc->stats.elapsedTime);
  295                                         timevalsub(&sc->stats.elapsedTime,
  296                                             &sc->stats.startTime);
  297                                 }
  298                                 stats = (struct ng_source_stats *)resp->data;
  299                                 bcopy(&sc->stats, stats, sizeof(* stats));
  300                         }
  301                         if (msg->header.cmd != NGM_SOURCE_GET_STATS)
  302                                 bzero(&sc->stats, sizeof(sc->stats));
  303                     }
  304                     break;
  305                 case NGM_SOURCE_START:
  306                     {
  307                         u_int64_t packets = *(u_int64_t *)msg->data;
  308                         if (sc->output.hook == NULL) {
  309                                 printf("%s: start on node with no output hook\n"
  310                                     , __FUNCTION__);
  311                                 error = EINVAL;
  312                                 break;
  313                         }
  314                         /* TODO validation of packets */
  315                         sc->packets = packets;
  316                         ng_source_start(sc);
  317                     }
  318                     break;
  319                 case NGM_SOURCE_STOP:
  320                         ng_source_stop(sc);
  321                         break;
  322                 case NGM_SOURCE_CLR_DATA:
  323                         ng_source_clr_data(sc);
  324                         break;
  325                 default:
  326                         error = EINVAL;
  327                         break;
  328                 }
  329                 break;
  330         case NGM_ETHER_COOKIE:
  331                 if (!(msg->header.flags & NGF_RESP)) {
  332                         error = EINVAL;
  333                         break;
  334                 }
  335                 switch (msg->header.cmd) {
  336                 case NGM_ETHER_GET_IFINDEX:
  337                         if (ng_source_store_output_ifp(sc, msg) == 0) {
  338                                 ng_source_set_autosrc(sc, 0);
  339                                 sc->node->nd_flags |= NG_SOURCE_ACTIVE;
  340                                 timevalclear(&sc->stats.elapsedTime);
  341                                 timevalclear(&sc->stats.endTime);
  342                                 getmicrotime(&sc->stats.startTime);
  343                                 sc->intr_ch = timeout(ng_source_intr, sc, 0);
  344                         }
  345                         break;
  346                 default:
  347                         error = EINVAL;
  348                 }
  349                 break;
  350         default:
  351                 error = EINVAL;
  352                 break;
  353         }
  354 
  355 done:
  356         /* Take care of synchronous response, if any */
  357         NG_RESPOND_MSG(error, node, item, resp);
  358         /* Free the message and return */
  359         NG_FREE_MSG(msg);
  360         return (error);
  361 }
  362 
  363 /*
  364  * Receive data on a hook
  365  *
  366  * If data comes in the input hook, enqueue it on the send queue.
  367  * If data comes in the output hook, discard it.
  368  */
  369 static int
  370 ng_source_rcvdata(hook_p hook, item_p item)
  371 {
  372         sc_p sc;
  373         struct source_hookinfo *hinfo;
  374         int error = 0;
  375         struct mbuf *m;
  376 
  377         sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  378         NGI_GET_M(item, m);
  379         NG_FREE_ITEM(item);
  380         hinfo = NG_HOOK_PRIVATE(hook);
  381         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  382         KASSERT(hinfo != NULL, ("%s: null hook info", __FUNCTION__));
  383 
  384         /* Which hook? */
  385         if (hinfo == &sc->output) {
  386                 /* discard */
  387                 NG_FREE_M(m);
  388                 return (error);
  389         }
  390         KASSERT(hinfo == &sc->input, ("%s: no hook!", __FUNCTION__));
  391 
  392         if ((m->m_flags & M_PKTHDR) == 0) {
  393                 printf("%s: mbuf without PKTHDR\n", __FUNCTION__);
  394                 NG_FREE_M(m);
  395                 return (EINVAL);
  396         }
  397 
  398         /* enque packet */
  399         /* XXX should we check IF_QFULL() ? */
  400         IF_ENQUEUE(&sc->snd_queue, m);
  401         sc->queueOctets += m->m_pkthdr.len;
  402 
  403         return (0);
  404 }
  405 
  406 /*
  407  * Shutdown processing
  408  */
  409 static int
  410 ng_source_rmnode(node_p node)
  411 {
  412         sc_p sc;
  413 
  414         sc = NG_NODE_PRIVATE(node);
  415         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  416         node->nd_flags |= NG_INVALID;
  417         ng_source_stop(sc);
  418         ng_source_clr_data(sc);
  419         NG_NODE_SET_PRIVATE(node, NULL);
  420         NG_NODE_UNREF(node);
  421         FREE(sc, M_NETGRAPH);
  422         return (0);
  423 }
  424 
  425 /*
  426  * Hook disconnection
  427  */
  428 static int
  429 ng_source_disconnect(hook_p hook)
  430 {
  431         struct source_hookinfo *hinfo;
  432         sc_p sc;
  433 
  434         hinfo = NG_HOOK_PRIVATE(hook);
  435         sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  436         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  437         hinfo->hook = NULL;
  438         if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 || hinfo == &sc->output)
  439                 ng_rmnode_self(NG_HOOK_NODE(hook));
  440         return (0);
  441 }
  442 
  443 /*
  444  * 
  445  * Ask out neighbour on the output hook side to send us it's interface
  446  * information.
  447  */
  448 static void
  449 ng_source_request_output_ifp(sc_p sc)
  450 {
  451         struct ng_mesg *msg;
  452         int error = 0;
  453 
  454         sc->output_ifp = NULL;
  455 
  456         /* Ask the attached node for the connected interface's index */
  457         NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_GET_IFINDEX, 0, M_NOWAIT);
  458         if (msg == NULL)
  459                 return (ENOBUFS);
  460 
  461         NG_SEND_MSG_HOOK(error, sc->node, msg, sc->output.hook, NULL);
  462         return (error);
  463 }
  464 
  465 /*
  466  * Set sc->output_ifp to point to the the struct ifnet of the interface
  467  * reached via our output hook.
  468  */
  469 static int
  470 ng_source_store_output_ifp(sc_p sc, struct ng_mesg *msg)
  471 {
  472         struct ifnet *ifp;
  473         u_int32_t if_index;
  474         int s;
  475 
  476         if (msg->header.arglen < sizeof(u_int32_t))
  477                 return (EINVAL);
  478 
  479         if_index = *(u_int32_t *)msg->data;
  480         /* Could use ifindex2ifnet[if_index] except that we have no
  481          * way of verifying if_index is valid since if_indexlim is
  482          * local to if_attach()
  483          */
  484         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  485                 if (ifp->if_index == if_index)
  486                         break;
  487         }
  488 
  489         if (ifp == NULL) {
  490                 printf("%s: can't find interface %d\n", __FUNCTION__, if_index);
  491                 return (EINVAL);
  492         }
  493         sc->output_ifp = ifp;
  494 
  495 #if 1
  496         /* XXX mucking with a drivers ifqueue size is ugly but we need it
  497          * to queue a lot of packets to get close to line rate on a gigabit
  498          * interface with small packets.
  499          * XXX we should restore the original value at stop or disconnect
  500          */
  501         s = splimp();           /* XXX is this required? */
  502         if (ifp->if_snd.ifq_maxlen < NG_SOURCE_DRIVER_IFQ_MAXLEN)
  503         {
  504                 printf("ng_source: changing ifq_maxlen from %d to %d\n",
  505                     ifp->if_snd.ifq_maxlen, NG_SOURCE_DRIVER_IFQ_MAXLEN);
  506                 ifp->if_snd.ifq_maxlen = NG_SOURCE_DRIVER_IFQ_MAXLEN;
  507         }
  508         splx(s);
  509 #endif
  510         return (0);
  511 }
  512 
  513 /*
  514  * Set the attached ethernet node's ethernet source address override flag.
  515  */
  516 static int
  517 ng_source_set_autosrc(sc_p sc, u_int32_t flag)
  518 {
  519         struct ng_mesg *msg;
  520         int error = 0;
  521 
  522         NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_SET_AUTOSRC,
  523                         sizeof (u_int32_t), M_NOWAIT);
  524         if (msg == NULL)
  525                 return(ENOBUFS);
  526 
  527         *(u_int32_t *)msg->data = flag;
  528         NG_SEND_MSG_HOOK(error, sc->node, msg, sc->output.hook, NULL);
  529         return (error);
  530 }
  531 
  532 /*
  533  * Clear out the data we've queued
  534  */
  535 static void
  536 ng_source_clr_data (sc_p sc)
  537 {
  538         struct mbuf *m;
  539 
  540         for (;;) {
  541                 IF_DEQUEUE(&sc->snd_queue, m);
  542                 if (m == NULL)
  543                         break;
  544                 NG_FREE_M(m);
  545         }
  546         sc->queueOctets = 0;
  547 }
  548 
  549 /*
  550  * Start sending queued data out the output hook
  551  */
  552 static void
  553 ng_source_start (sc_p sc)
  554 {
  555         KASSERT(sc->output.hook != NULL,
  556                         ("%s: output hook unconnected", __FUNCTION__));
  557         if (((sc->node->nd_flags & NG_SOURCE_ACTIVE) == 0) &&
  558             (sc->output_ifp == NULL))
  559                 ng_source_request_output_ifp(sc);
  560 }
  561 
  562 /*
  563  * Stop sending queued data out the output hook
  564  */
  565 static void
  566 ng_source_stop (sc_p sc)
  567 {
  568         if (sc->node->nd_flags & NG_SOURCE_ACTIVE) {
  569                 untimeout(ng_source_intr, sc, sc->intr_ch);
  570                 sc->node->nd_flags &= ~NG_SOURCE_ACTIVE;
  571                 getmicrotime(&sc->stats.endTime);
  572                 sc->stats.elapsedTime = sc->stats.endTime;
  573                 timevalsub(&sc->stats.elapsedTime, &sc->stats.startTime);
  574                 /* XXX should set this to the initial value instead */
  575                 ng_source_set_autosrc(sc, 1);
  576         }
  577 }
  578 
  579 /*
  580  * While active called every NG_SOURCE_INTR_TICKS ticks.
  581  * Sends as many packets as the interface connected to our
  582  * output hook is able to enqueue.
  583  */
  584 static void
  585 ng_source_intr (void *arg)
  586 {
  587         sc_p sc = (sc_p) arg;
  588         struct ifqueue *ifq;
  589         int packets;
  590 
  591         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  592 
  593         callout_handle_init(&sc->intr_ch);
  594         if (sc->packets == 0 || sc->output.hook == NULL
  595             || (sc->node->nd_flags & NG_SOURCE_ACTIVE) == 0) {
  596                 ng_source_stop(sc);
  597                 return;
  598         }
  599 
  600         ifq = &sc->output_ifp->if_snd;
  601         packets = ifq->ifq_maxlen - ifq->ifq_len;
  602         ng_source_send(sc, packets, NULL);
  603         if (sc->packets == 0) {
  604                 int s = splnet();
  605                 ng_source_stop(sc);
  606                 splx(s);
  607         } else
  608                 sc->intr_ch = timeout(ng_source_intr, sc, NG_SOURCE_INTR_TICKS);
  609 }
  610 
  611 /*
  612  * Send packets out our output hook
  613  */
  614 static int
  615 ng_source_send (sc_p sc, int tosend, int *sent_p)
  616 {
  617         struct ifqueue tmp_queue;
  618         struct mbuf *m, *m2;
  619         int sent = 0;
  620         int error = 0;
  621         int s, s2;
  622 
  623         KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__));
  624         KASSERT(tosend >= 0, ("%s: negative tosend param", __FUNCTION__));
  625         KASSERT(sc->node->nd_flags & NG_SOURCE_ACTIVE,
  626                         ("%s: inactive node", __FUNCTION__));
  627 
  628         if ((u_int64_t)tosend > sc->packets)
  629                 tosend = sc->packets;
  630 
  631         /* Copy the required number of packets to a temporary queue */
  632         bzero (&tmp_queue, sizeof (tmp_queue));
  633         for (sent = 0; error == 0 && sent < tosend; ++sent) {
  634                 s = splnet();
  635                 IF_DEQUEUE(&sc->snd_queue, m);
  636                 splx(s);
  637                 if (m == NULL)
  638                         break;
  639 
  640                 /* duplicate the packet */
  641                 m2 = m_copypacket(m, M_NOWAIT);
  642                 if (m2 == NULL) {
  643                         s = splnet();
  644                         IF_PREPEND(&sc->snd_queue, m);
  645                         splx(s);
  646                         error = ENOBUFS;
  647                         break;
  648                 }
  649 
  650                 /* re-enqueue the original packet for us */
  651                 s = splnet();
  652                 IF_ENQUEUE(&sc->snd_queue, m);
  653                 splx(s);
  654 
  655                 /* queue the copy for sending at smplimp */
  656                 IF_ENQUEUE(&tmp_queue, m2);
  657         }
  658 
  659         sent = 0;
  660         s = splimp();
  661         for (;;) {
  662                 IF_DEQUEUE(&tmp_queue, m2);
  663                 if (m2 == NULL)
  664                         break;
  665                 if (error == 0) {
  666                         ++sent;
  667                         sc->stats.outFrames++;
  668                         sc->stats.outOctets += m2->m_pkthdr.len;
  669                         s2 = splnet();
  670                         NG_SEND_DATA_ONLY(error, sc->output.hook, m2);
  671                         splx(s2);
  672                 } else {
  673                         NG_FREE_M(m2);
  674                 }
  675         }
  676         splx(s);
  677 
  678         sc->packets -= sent;
  679         if (sent_p != NULL)
  680                 *sent_p = sent;
  681         return (error);
  682 }

Cache object: 4b96434b6c6bbe10aaf2172add0b42ad


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