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.4/sys/netgraph/ng_source.c 155097 2006-01-31 15:39: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         {
  185           NGM_SOURCE_COOKIE,
  186           NGM_SOURCE_SETPPS,
  187           "setpps",
  188           &ng_parse_uint32_type,
  189           NULL
  190         },
  191         { 0 }
  192 };
  193 
  194 /* Netgraph type descriptor */
  195 static struct ng_type ng_source_typestruct = {
  196         .version =      NG_ABI_VERSION,
  197         .name =         NG_SOURCE_NODE_TYPE,
  198         .constructor =  ng_source_constructor,
  199         .rcvmsg =       ng_source_rcvmsg,
  200         .shutdown =     ng_source_rmnode,
  201         .newhook =      ng_source_newhook,
  202         .connect =      ng_source_connect,
  203         .rcvdata =      ng_source_rcvdata,
  204         .disconnect =   ng_source_disconnect,
  205         .cmdlist =      ng_source_cmds,
  206 };
  207 NETGRAPH_INIT(source, &ng_source_typestruct);
  208 
  209 static int ng_source_set_autosrc(sc_p, uint32_t);
  210 
  211 /*
  212  * Node constructor
  213  */
  214 static int
  215 ng_source_constructor(node_p node)
  216 {
  217         sc_p sc;
  218 
  219         sc = malloc(sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO);
  220         if (sc == NULL)
  221                 return (ENOMEM);
  222 
  223         NG_NODE_SET_PRIVATE(node, sc);
  224         sc->node = node;
  225         sc->snd_queue.ifq_maxlen = 2048;        /* XXX not checked */
  226         ng_callout_init(&sc->intr_ch);
  227 
  228         return (0);
  229 }
  230 
  231 /*
  232  * Add a hook
  233  */
  234 static int
  235 ng_source_newhook(node_p node, hook_p hook, const char *name)
  236 {
  237         sc_p sc = NG_NODE_PRIVATE(node);
  238 
  239         if (strcmp(name, NG_SOURCE_HOOK_INPUT) == 0) {
  240                 sc->input = hook;
  241         } else if (strcmp(name, NG_SOURCE_HOOK_OUTPUT) == 0) {
  242                 sc->output = hook;
  243                 sc->output_ifp = 0;
  244                 bzero(&sc->stats, sizeof(sc->stats));
  245         } else
  246                 return (EINVAL);
  247 
  248         return (0);
  249 }
  250 
  251 /*
  252  * Hook has been added
  253  */
  254 static int
  255 ng_source_connect(hook_p hook)
  256 {
  257         sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  258         struct ng_mesg *msg;
  259         int dummy_error = 0;
  260 
  261         /*
  262          * If this is "output" hook, then request information
  263          * from our downstream.
  264          */
  265         if (hook == sc->output) {
  266                 NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_GET_IFNAME,
  267                     0, M_NOWAIT);
  268                 if (msg == NULL)
  269                         return (ENOBUFS);
  270 
  271                 /*
  272                  * Our hook and peer hook have HK_INVALID flag set,
  273                  * so we can't use NG_SEND_MSG_HOOK() macro here.
  274                  */
  275                 NG_SEND_MSG_ID(dummy_error, sc->node, msg,
  276                     NG_NODE_ID(NG_PEER_NODE(sc->output)), NG_NODE_ID(sc->node));
  277         }
  278 
  279         return (0);
  280 }
  281 
  282 /*
  283  * Receive a control message
  284  */
  285 static int
  286 ng_source_rcvmsg(node_p node, item_p item, hook_p lasthook)
  287 {
  288         sc_p sc = NG_NODE_PRIVATE(node);
  289         struct ng_mesg *msg, *resp = NULL;
  290         int error = 0;
  291 
  292         NGI_GET_MSG(item, msg);
  293 
  294         switch (msg->header.typecookie) {
  295         case NGM_SOURCE_COOKIE:
  296                 if (msg->header.flags & NGF_RESP) {
  297                         error = EINVAL;
  298                         break;
  299                 }
  300                 switch (msg->header.cmd) {
  301                 case NGM_SOURCE_GET_STATS:
  302                 case NGM_SOURCE_CLR_STATS:
  303                 case NGM_SOURCE_GETCLR_STATS:
  304                     {
  305                         struct ng_source_stats *stats;
  306 
  307                         if (msg->header.cmd != NGM_SOURCE_CLR_STATS) {
  308                                 NG_MKRESPONSE(resp, msg,
  309                                     sizeof(*stats), M_NOWAIT);
  310                                 if (resp == NULL) {
  311                                         error = ENOMEM;
  312                                         goto done;
  313                                 }
  314                                 sc->stats.queueOctets = sc->queueOctets;
  315                                 sc->stats.queueFrames = sc->snd_queue.ifq_len;
  316                                 if ((sc->node->nd_flags & NG_SOURCE_ACTIVE)
  317                                     && !timevalisset(&sc->stats.endTime)) {
  318                                         getmicrotime(&sc->stats.elapsedTime);
  319                                         timevalsub(&sc->stats.elapsedTime,
  320                                             &sc->stats.startTime);
  321                                 }
  322                                 stats = (struct ng_source_stats *)resp->data;
  323                                 bcopy(&sc->stats, stats, sizeof(* stats));
  324                         }
  325                         if (msg->header.cmd != NGM_SOURCE_GET_STATS)
  326                                 bzero(&sc->stats, sizeof(sc->stats));
  327                     }
  328                     break;
  329                 case NGM_SOURCE_START:
  330                     {
  331                         uint64_t packets;
  332 
  333                         if (msg->header.arglen != sizeof(uint64_t)) {
  334                                 error = EINVAL;
  335                                 break;
  336                         }
  337 
  338                         packets = *(uint64_t *)msg->data;
  339 
  340                         error = ng_source_start(sc, packets);
  341 
  342                         break;
  343                     }
  344                 case NGM_SOURCE_STOP:
  345                         ng_source_stop(sc);
  346                         break;
  347                 case NGM_SOURCE_CLR_DATA:
  348                         ng_source_clr_data(sc);
  349                         break;
  350                 case NGM_SOURCE_SETIFACE:
  351                     {
  352                         char *ifname = (char *)msg->data;
  353 
  354                         if (msg->header.arglen < 2) {
  355                                 error = EINVAL;
  356                                 break;
  357                         }
  358 
  359                         ng_source_store_output_ifp(sc, ifname);
  360                         break;
  361                     }
  362                 case NGM_SOURCE_SETPPS:
  363                     {
  364                         uint32_t pps;
  365 
  366                         if (msg->header.arglen != sizeof(uint32_t)) {
  367                                 error = EINVAL;
  368                                 break;
  369                         }
  370 
  371                         pps = *(uint32_t *)msg->data;
  372 
  373                         sc->stats.maxPps = pps;
  374 
  375                         break;
  376                     }
  377                 default:
  378                         error = EINVAL;
  379                         break;
  380                 }
  381                 break;
  382         case NGM_ETHER_COOKIE:
  383                 if (!(msg->header.flags & NGF_RESP)) {
  384                         error = EINVAL;
  385                         break;
  386                 }
  387                 switch (msg->header.cmd) {
  388                 case NGM_ETHER_GET_IFNAME:
  389                     {
  390                         char *ifname = (char *)msg->data;
  391 
  392                         if (msg->header.arglen < 2) {
  393                                 error = EINVAL;
  394                                 break;
  395                         }
  396 
  397                         if (ng_source_store_output_ifp(sc, ifname) == 0)
  398                                 ng_source_set_autosrc(sc, 0);
  399                         break;
  400                     }
  401                 default:
  402                         error = EINVAL;
  403                 }
  404                 break;
  405         default:
  406                 error = EINVAL;
  407                 break;
  408         }
  409 
  410 done:
  411         /* Take care of synchronous response, if any. */
  412         NG_RESPOND_MSG(error, node, item, resp);
  413         /* Free the message and return. */
  414         NG_FREE_MSG(msg);
  415         return (error);
  416 }
  417 
  418 /*
  419  * Receive data on a hook
  420  *
  421  * If data comes in the input hook, enqueue it on the send queue.
  422  * If data comes in the output hook, discard it.
  423  */
  424 static int
  425 ng_source_rcvdata(hook_p hook, item_p item)
  426 {
  427         sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  428         struct mbuf *m;
  429         int error = 0;
  430 
  431         NGI_GET_M(item, m);
  432         NG_FREE_ITEM(item);
  433 
  434         /* Which hook? */
  435         if (hook == sc->output) {
  436                 /* discard */
  437                 NG_FREE_M(m);
  438                 return (error);
  439         }
  440         KASSERT(hook == sc->input, ("%s: no hook!", __func__));
  441 
  442         /* Enqueue packet. */
  443         /* XXX should we check IF_QFULL() ? */
  444         _IF_ENQUEUE(&sc->snd_queue, m);
  445         sc->queueOctets += m->m_pkthdr.len;
  446 
  447         return (0);
  448 }
  449 
  450 /*
  451  * Shutdown processing
  452  */
  453 static int
  454 ng_source_rmnode(node_p node)
  455 {
  456         sc_p sc = NG_NODE_PRIVATE(node);
  457 
  458         ng_source_stop(sc);
  459         ng_source_clr_data(sc);
  460         NG_NODE_SET_PRIVATE(node, NULL);
  461         NG_NODE_UNREF(node);
  462         free(sc, M_NETGRAPH);
  463 
  464         return (0);
  465 }
  466 
  467 /*
  468  * Hook disconnection
  469  */
  470 static int
  471 ng_source_disconnect(hook_p hook)
  472 {
  473         sc_p sc;
  474 
  475         sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  476         KASSERT(sc != NULL, ("%s: null node private", __func__));
  477         if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 || hook == sc->output)
  478                 ng_rmnode_self(NG_HOOK_NODE(hook));
  479         return (0);
  480 }
  481 
  482 /*
  483  * Set sc->output_ifp to point to the the struct ifnet of the interface
  484  * reached via our output hook.
  485  */
  486 static int
  487 ng_source_store_output_ifp(sc_p sc, char *ifname)
  488 {
  489         struct ifnet *ifp;
  490         int s;
  491 
  492         ifp = ifunit(ifname);
  493 
  494         if (ifp == NULL) {
  495                 printf("%s: can't find interface %d\n", __func__, if_index);
  496                 return (EINVAL);
  497         }
  498         sc->output_ifp = ifp;
  499 
  500 #if 1
  501         /* XXX mucking with a drivers ifqueue size is ugly but we need it
  502          * to queue a lot of packets to get close to line rate on a gigabit
  503          * interface with small packets.
  504          * XXX we should restore the original value at stop or disconnect
  505          */
  506         s = splimp();           /* XXX is this required? */
  507         if (ifp->if_snd.ifq_maxlen < NG_SOURCE_DRIVER_IFQ_MAXLEN) {
  508                 printf("ng_source: changing ifq_maxlen from %d to %d\n",
  509                     ifp->if_snd.ifq_maxlen, NG_SOURCE_DRIVER_IFQ_MAXLEN);
  510                 ifp->if_snd.ifq_maxlen = NG_SOURCE_DRIVER_IFQ_MAXLEN;
  511         }
  512         splx(s);
  513 #endif
  514         return (0);
  515 }
  516 
  517 /*
  518  * Set the attached ethernet node's ethernet source address override flag.
  519  */
  520 static int
  521 ng_source_set_autosrc(sc_p sc, uint32_t flag)
  522 {
  523         struct ng_mesg *msg;
  524         int error = 0;
  525 
  526         NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_SET_AUTOSRC,
  527             sizeof (uint32_t), M_NOWAIT);
  528         if (msg == NULL)
  529                 return(ENOBUFS);
  530 
  531         *(uint32_t *)msg->data = flag;
  532         NG_SEND_MSG_HOOK(error, sc->node, msg, sc->output, 0);
  533         return (error);
  534 }
  535 
  536 /*
  537  * Clear out the data we've queued
  538  */
  539 static void
  540 ng_source_clr_data (sc_p sc)
  541 {
  542         struct mbuf *m;
  543 
  544         for (;;) {
  545                 _IF_DEQUEUE(&sc->snd_queue, m);
  546                 if (m == NULL)
  547                         break;
  548                 NG_FREE_M(m);
  549         }
  550         sc->queueOctets = 0;
  551 }
  552 
  553 /*
  554  * Start sending queued data out the output hook
  555  */
  556 static int
  557 ng_source_start(sc_p sc, uint64_t packets)
  558 {
  559         if (sc->output_ifp == NULL) {
  560                 printf("ng_source: start without iface configured\n");
  561                 return (ENXIO);
  562         }
  563 
  564         if (sc->node->nd_flags & NG_SOURCE_ACTIVE)
  565                 return (EBUSY);
  566 
  567         sc->node->nd_flags |= NG_SOURCE_ACTIVE;
  568 
  569         sc->packets = packets;
  570         timevalclear(&sc->stats.elapsedTime);
  571         timevalclear(&sc->stats.endTime);
  572         getmicrotime(&sc->stats.startTime);
  573         getmicrotime(&sc->stats.lastTime);
  574         ng_callout(&sc->intr_ch, sc->node, NULL, 0,
  575             ng_source_intr, sc, 0);
  576 
  577         return (0);
  578 }
  579 
  580 /*
  581  * Stop sending queued data out the output hook
  582  */
  583 static void
  584 ng_source_stop(sc_p sc)
  585 {
  586         ng_uncallout(&sc->intr_ch, sc->node);
  587         sc->node->nd_flags &= ~NG_SOURCE_ACTIVE;
  588         getmicrotime(&sc->stats.endTime);
  589         sc->stats.elapsedTime = sc->stats.endTime;
  590         timevalsub(&sc->stats.elapsedTime, &sc->stats.startTime);
  591 }
  592 
  593 /*
  594  * While active called every NG_SOURCE_INTR_TICKS ticks.
  595  * Sends as many packets as the interface connected to our
  596  * output hook is able to enqueue.
  597  */
  598 static void
  599 ng_source_intr(node_p node, hook_p hook, void *arg1, int arg2)
  600 {
  601         sc_p sc = (sc_p)arg1;
  602         struct ifqueue *ifq;
  603         int packets;
  604 
  605         KASSERT(sc != NULL, ("%s: null node private", __func__));
  606 
  607         if (sc->packets == 0 || sc->output == NULL
  608             || (sc->node->nd_flags & NG_SOURCE_ACTIVE) == 0) {
  609                 ng_source_stop(sc);
  610                 return;
  611         }
  612 
  613         if (sc->output_ifp != NULL) {
  614                 ifq = (struct ifqueue *)&sc->output_ifp->if_snd;
  615                 packets = ifq->ifq_maxlen - ifq->ifq_len;
  616         } else
  617                 packets = sc->snd_queue.ifq_len;
  618 
  619         if (sc->stats.maxPps != 0) {
  620                 struct timeval  now, elapsed;
  621                 uint64_t        usec;
  622                 int             maxpkt;
  623 
  624                 getmicrotime(&now);
  625                 elapsed = now;
  626                 timevalsub(&elapsed, &sc->stats.lastTime);
  627                 usec = elapsed.tv_sec * 1000000 + elapsed.tv_usec;
  628                 maxpkt = (uint64_t)sc->stats.maxPps * usec / 1000000;
  629                 sc->stats.lastTime = now;
  630                 if (packets > maxpkt)
  631                         packets = maxpkt;
  632         }
  633 
  634         ng_source_send(sc, packets, NULL);
  635         if (sc->packets == 0)
  636                 ng_source_stop(sc);
  637         else
  638                 ng_callout(&sc->intr_ch, node, NULL, NG_SOURCE_INTR_TICKS,
  639                     ng_source_intr, sc, 0);
  640 }
  641 
  642 /*
  643  * Send packets out our output hook.
  644  */
  645 static int
  646 ng_source_send(sc_p sc, int tosend, int *sent_p)
  647 {
  648         struct mbuf *m, *m2;
  649         int sent;
  650         int error = 0;
  651 
  652         KASSERT(tosend >= 0, ("%s: negative tosend param", __func__));
  653         KASSERT(sc->node->nd_flags & NG_SOURCE_ACTIVE,
  654             ("%s: inactive node", __func__));
  655 
  656         if ((uint64_t)tosend > sc->packets)
  657                 tosend = sc->packets;
  658 
  659         /* Go through the queue sending packets one by one. */
  660         for (sent = 0; error == 0 && sent < tosend; ++sent) {
  661                 _IF_DEQUEUE(&sc->snd_queue, m);
  662                 if (m == NULL)
  663                         break;
  664 
  665                 /* Duplicate the packet. */
  666                 m2 = m_copypacket(m, M_DONTWAIT);
  667                 if (m2 == NULL) {
  668                         _IF_PREPEND(&sc->snd_queue, m);
  669                         error = ENOBUFS;
  670                         break;
  671                 }
  672 
  673                 /* Re-enqueue the original packet for us. */
  674                 _IF_ENQUEUE(&sc->snd_queue, m);
  675 
  676                 sc->stats.outFrames++;
  677                 sc->stats.outOctets += m2->m_pkthdr.len;
  678                 NG_SEND_DATA_ONLY(error, sc->output, m2);
  679                 if (error)
  680                         break;
  681         }
  682 
  683         sc->packets -= sent;
  684         if (sent_p != NULL)
  685                 *sent_p = sent;
  686         return (error);
  687 }

Cache object: c07cb615740648226341e3fc7c4502a9


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