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

Cache object: ea6c975700c76f4de7aae50e260f6254


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