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

Cache object: 19154a330795e297c19a32a9ae551729


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