The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_source.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 34d28fa0a29eda8edc59faa7a870c82c


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