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

Cache object: f98f3e556cacd90dda550b9a2c932a20


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