ng_source.c revision 106266
1106266Sjulian/* 2106266Sjulian * ng_source.c 3106266Sjulian * 4106266Sjulian * Copyright 2002 Sandvine Inc. 5106266Sjulian * All rights reserved. 6106266Sjulian * 7106266Sjulian * Subject to the following obligations and disclaimer of warranty, use and 8106266Sjulian * redistribution of this software, in source or object code forms, with or 9106266Sjulian * without modifications are expressly permitted by Sandvine Inc.; 10106266Sjulianprovided, 11106266Sjulian * however, that: 12106266Sjulian * 1. Any and all reproductions of the source or object code must include 13106266Sjulianthe 14106266Sjulian * copyright notice above and the following disclaimer of warranties; 15106266Sjulianand 16106266Sjulian * 2. No rights are granted, in any manner or form, to use Sandvine Inc. 17106266Sjulian * trademarks, including the mark "SANDVINE" on advertising, 18106266Sjulianendorsements, 19106266Sjulian * or otherwise except as such appears in the above copyright notice or 20106266Sjulianin 21106266Sjulian * the software. 22106266Sjulian * 23106266Sjulian * THIS SOFTWARE IS BEING PROVIDED BY SANDVINE "AS IS", AND TO THE MAXIMUM 24106266Sjulian * EXTENT PERMITTED BY LAW, SANDVINE MAKES NO REPRESENTATIONS OR 25106266SjulianWARRANTIES, 26106266Sjulian * EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, INCLUDING WITHOUT 27106266SjulianLIMITATION, 28106266Sjulian * ANY AND ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 29106266SjulianPARTICULAR 30106266Sjulian * PURPOSE, OR NON-INFRINGEMENT. SANDVINE DOES NOT WARRANT, GUARANTEE, OR 31106266Sjulian * MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE 32106266Sjulian * USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY 33106266Sjulian * OR OTHERWISE. IN NO EVENT SHALL SANDVINE BE LIABLE FOR ANY DAMAGES 34106266Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 35106266Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36106266SjulianEXEMPLARY, 37106266Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 38106266Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 39106266Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40106266Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 41106266Sjulian * THIS SOFTWARE, EVEN IF SANDVINE IS ADVISED OF THE POSSIBILITY OF SUCH 42106266Sjulian * DAMAGE. 43106266Sjulian * 44106266Sjulian * Author: Dave Chapeskie <dchapeskie@sandvine.com> 45106266Sjulian * 46106266Sjulian * $FreeBSD: head/sys/netgraph/ng_source.c 106266 2002-10-31 23:03:09Z julian $ 47106266Sjulian */ 48106266Sjulian 49106266Sjulian/* 50106266Sjulian * This node is used for high speed packet geneneration. It queues 51106266Sjulian * all data recieved on it's 'input' hook and when told to start via 52106266Sjulian * a control message it sends the packets out it's 'output' hook. In 53106266Sjulian * this way this node can be preloaded with a packet stream which is 54106266Sjulian * continuously sent. 55106266Sjulian * 56106266Sjulian * Currently it just copies the mbufs as required. It could do various 57106266Sjulian * tricks to try and avoid this. Probably the best performance would 58106266Sjulian * be achieved by modifying the appropriate drivers to be told to 59106266Sjulian * self-re-enqueue packets (e.g. the if_bge driver could reuse the same 60106266Sjulian * transmit descriptors) under control of this node; perhaps via some 61106266Sjulian * flag in the mbuf or some such. The node would peak at an appropriate 62106266Sjulian * ifnet flag to see if such support is available for the connected 63106266Sjulian * interface. 64106266Sjulian */ 65106266Sjulian 66106266Sjulian#include <sys/param.h> 67106266Sjulian#include <sys/systm.h> 68106266Sjulian#include <sys/errno.h> 69106266Sjulian#include <sys/kernel.h> 70106266Sjulian#include <sys/malloc.h> 71106266Sjulian#include <sys/mbuf.h> 72106266Sjulian#include <sys/socket.h> 73106266Sjulian#include <net/if.h> 74106266Sjulian#include <net/if_var.h> 75106266Sjulian#include <netgraph/ng_message.h> 76106266Sjulian#include <netgraph/netgraph.h> 77106266Sjulian#include <netgraph/ng_parse.h> 78106266Sjulian#include <netgraph/ng_ether.h> 79106266Sjulian#include <netgraph/ng_source.h> 80106266Sjulian 81106266Sjulian#define NG_SOURCE_INTR_TICKS 1 82106266Sjulian#define NG_SOURCE_DRIVER_IFQ_MAXLEN (4*1024) 83106266Sjulian 84106266Sjulian 85106266Sjulian/* Per hook info */ 86106266Sjulianstruct source_hookinfo { 87106266Sjulian hook_p hook; 88106266Sjulian}; 89106266Sjulian 90106266Sjulian/* Per node info */ 91106266Sjulianstruct privdata { 92106266Sjulian node_p node; 93106266Sjulian struct source_hookinfo input; 94106266Sjulian struct source_hookinfo output; 95106266Sjulian struct ng_source_stats stats; 96106266Sjulian struct ifqueue snd_queue; /* packets to send 97106266Sjulian*/ 98106266Sjulian struct ifnet *output_ifp; 99106266Sjulian struct callout_handle intr_ch; 100106266Sjulian u_int64_t packets; /* packets to send 101106266Sjulian*/ 102106266Sjulian u_int32_t queueOctets; 103106266Sjulian}; 104106266Sjuliantypedef struct privdata *sc_p; 105106266Sjulian 106106266Sjulian/* Node flags */ 107106266Sjulian#define NG_SOURCE_ACTIVE (NGF_TYPE1) 108106266Sjulian 109106266Sjulian/* XXX */ 110106266Sjulian#if 1 111106266Sjulian#undef KASSERT 112106266Sjulian#define KASSERT(expr,msg) do { \ 113106266Sjulian if (!(expr)) { \ 114106266Sjulian printf msg ; \ 115106266Sjulian panic("Assertion"); \ 116106266Sjulian } \ 117106266Sjulian } while(0) 118106266Sjulian#endif 119106266Sjulian 120106266Sjulian/* Netgraph methods */ 121106266Sjulianstatic ng_constructor_t ng_source_constructor; 122106266Sjulianstatic ng_rcvmsg_t ng_source_rcvmsg; 123106266Sjulianstatic ng_shutdown_t ng_source_rmnode; 124106266Sjulianstatic ng_newhook_t ng_source_newhook; 125106266Sjulianstatic ng_rcvdata_t ng_source_rcvdata; 126106266Sjulianstatic ng_disconnect_t ng_source_disconnect; 127106266Sjulian 128106266Sjulian/* Other functions */ 129106266Sjulianstatic timeout_t ng_source_intr; 130106266Sjulianstatic int ng_source_get_output_ifp (sc_p); 131106266Sjulianstatic void ng_source_clr_data (sc_p); 132106266Sjulianstatic void ng_source_start (sc_p); 133106266Sjulianstatic void ng_source_stop (sc_p); 134106266Sjulianstatic int ng_source_send (sc_p, int, int *); 135106266Sjulian 136106266Sjulian 137106266Sjulian/* Parse type for timeval */ 138106266Sjulianstatic const struct ng_parse_struct_field ng_source_timeval_type_fields[] = 139106266Sjulian{ 140106266Sjulian { "tv_sec", &ng_parse_int32_type }, 141106266Sjulian { "tv_usec", &ng_parse_int32_type }, 142106266Sjulian { NULL } 143106266Sjulian}; 144106266Sjulianconst struct ng_parse_type ng_source_timeval_type = { 145106266Sjulian &ng_parse_struct_type, 146106266Sjulian &ng_source_timeval_type_fields 147106266Sjulian}; 148106266Sjulian 149106266Sjulian/* Parse type for struct ng_source_stats */ 150106266Sjulianstatic const struct ng_parse_struct_field ng_source_stats_type_fields[] 151106266Sjulian = NG_SOURCE_STATS_TYPE_INFO; 152106266Sjulianstatic const struct ng_parse_type ng_source_stats_type = { 153106266Sjulian &ng_parse_struct_type, 154106266Sjulian &ng_source_stats_type_fields 155106266Sjulian}; 156106266Sjulian 157106266Sjulian/* List of commands and how to convert arguments to/from ASCII */ 158106266Sjulianstatic const struct ng_cmdlist ng_source_cmds[] = { 159106266Sjulian { 160106266Sjulian NGM_SOURCE_COOKIE, 161106266Sjulian NGM_SOURCE_GET_STATS, 162106266Sjulian "getstats", 163106266Sjulian NULL, 164106266Sjulian &ng_source_stats_type 165106266Sjulian }, 166106266Sjulian { 167106266Sjulian NGM_SOURCE_COOKIE, 168106266Sjulian NGM_SOURCE_CLR_STATS, 169106266Sjulian "clrstats", 170106266Sjulian NULL, 171106266Sjulian NULL 172106266Sjulian }, 173106266Sjulian { 174106266Sjulian NGM_SOURCE_COOKIE, 175106266Sjulian NGM_SOURCE_GETCLR_STATS, 176106266Sjulian "getclrstats", 177106266Sjulian NULL, 178106266Sjulian &ng_source_stats_type 179106266Sjulian }, 180106266Sjulian { 181106266Sjulian NGM_SOURCE_COOKIE, 182106266Sjulian NGM_SOURCE_START, 183106266Sjulian "start", 184106266Sjulian &ng_parse_uint64_type, 185106266Sjulian NULL 186106266Sjulian }, 187106266Sjulian { 188106266Sjulian NGM_SOURCE_COOKIE, 189106266Sjulian NGM_SOURCE_STOP, 190106266Sjulian "stop", 191106266Sjulian NULL, 192106266Sjulian NULL 193106266Sjulian }, 194106266Sjulian { 195106266Sjulian NGM_SOURCE_COOKIE, 196106266Sjulian NGM_SOURCE_CLR_DATA, 197106266Sjulian "clrdata", 198106266Sjulian NULL, 199106266Sjulian NULL 200106266Sjulian }, 201106266Sjulian { 0 } 202106266Sjulian}; 203106266Sjulian 204106266Sjulian/* Netgraph type descriptor */ 205106266Sjulianstatic struct ng_type ng_source_typestruct = { 206106266Sjulian NG_VERSION, 207106266Sjulian NG_SOURCE_NODE_TYPE, 208106266Sjulian NULL, /* module event handler */ 209106266Sjulian ng_source_constructor, 210106266Sjulian ng_source_rcvmsg, 211106266Sjulian ng_source_rmnode, 212106266Sjulian ng_source_newhook, 213106266Sjulian NULL, /* findhook */ 214106266Sjulian NULL, 215106266Sjulian ng_source_rcvdata, /* rcvdata */ 216106266Sjulian ng_source_rcvdata, /* rcvdataq */ 217106266Sjulian ng_source_disconnect, 218106266Sjulian ng_source_cmds 219106266Sjulian}; 220106266SjulianNETGRAPH_INIT(source, &ng_source_typestruct); 221106266Sjulian 222106266Sjulian/* 223106266Sjulian * Node constructor 224106266Sjulian */ 225106266Sjulianstatic int 226106266Sjulianng_source_constructor(node_p *nodep) 227106266Sjulian{ 228106266Sjulian sc_p sc; 229106266Sjulian int error = 0; 230106266Sjulian 231106266Sjulian MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT); 232106266Sjulian if (sc == NULL) 233106266Sjulian return (ENOMEM); 234106266Sjulian bzero(sc, sizeof(*sc)); 235106266Sjulian 236106266Sjulian if ((error = ng_make_node_common(&ng_source_typestruct, nodep))) { 237106266Sjulian FREE(sc, M_NETGRAPH); 238106266Sjulian return (error); 239106266Sjulian } 240106266Sjulian (*nodep)->private = sc; 241106266Sjulian sc->node = *nodep; 242106266Sjulian sc->snd_queue.ifq_maxlen = 2048; /* XXX not checked */ 243106266Sjulian callout_handle_init(&sc->intr_ch); 244106266Sjulian return (0); 245106266Sjulian} 246106266Sjulian 247106266Sjulian/* 248106266Sjulian * Add a hook 249106266Sjulian */ 250106266Sjulianstatic int 251106266Sjulianng_source_newhook(node_p node, hook_p hook, const char *name) 252106266Sjulian{ 253106266Sjulian const sc_p sc = node->private; 254106266Sjulian 255106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 256106266Sjulian if (strcmp(name, NG_SOURCE_HOOK_INPUT) == 0) { 257106266Sjulian sc->input.hook = hook; 258106266Sjulian hook->private = &sc->input; 259106266Sjulian } else if (strcmp(name, NG_SOURCE_HOOK_OUTPUT) == 0) { 260106266Sjulian sc->output.hook = hook; 261106266Sjulian hook->private = &sc->output; 262106266Sjulian sc->output_ifp = 0; 263106266Sjulian bzero(&sc->stats, sizeof(sc->stats)); 264106266Sjulian } else 265106266Sjulian return (EINVAL); 266106266Sjulian return (0); 267106266Sjulian} 268106266Sjulian 269106266Sjulian/* 270106266Sjulian * Receive a control message 271106266Sjulian */ 272106266Sjulianstatic int 273106266Sjulianng_source_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 274106266Sjulian struct ng_mesg **rptr) 275106266Sjulian{ 276106266Sjulian const sc_p sc = node->private; 277106266Sjulian struct ng_mesg *resp = NULL; 278106266Sjulian int error = 0; 279106266Sjulian 280106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 281106266Sjulian switch (msg->header.typecookie) { 282106266Sjulian case NGM_SOURCE_COOKIE: 283106266Sjulian switch (msg->header.cmd) { 284106266Sjulian case NGM_SOURCE_GET_STATS: 285106266Sjulian case NGM_SOURCE_CLR_STATS: 286106266Sjulian case NGM_SOURCE_GETCLR_STATS: 287106266Sjulian { 288106266Sjulian struct ng_source_stats *stats; 289106266Sjulian 290106266Sjulian if (msg->header.cmd != NGM_SOURCE_CLR_STATS) { 291106266Sjulian NG_MKRESPONSE(resp, msg, 292106266Sjulian sizeof(*stats), M_NOWAIT); 293106266Sjulian if (resp == NULL) { 294106266Sjulian error = ENOMEM; 295106266Sjulian goto done; 296106266Sjulian } 297106266Sjulian sc->stats.queueOctets = sc->queueOctets; 298106266Sjulian sc->stats.queueFrames = 299106266Sjuliansc->snd_queue.ifq_len; 300106266Sjulian if ((sc->node->flags & NG_SOURCE_ACTIVE) 301106266Sjulian && !timevalisset(&sc->stats.endTime)) { 302106266Sjulian 303106266Sjuliangetmicrotime(&sc->stats.elapsedTime); 304106266Sjulian timevalsub(&sc->stats.elapsedTime, 305106266Sjulian 306106266Sjulian&sc->stats.startTime); 307106266Sjulian } 308106266Sjulian stats = (struct ng_source_stats 309106266Sjulian*)resp->data; 310106266Sjulian bcopy(&sc->stats, stats, sizeof(* stats)); 311106266Sjulian } 312106266Sjulian if (msg->header.cmd != NGM_SOURCE_GET_STATS) 313106266Sjulian bzero(&sc->stats, sizeof(sc->stats)); 314106266Sjulian } 315106266Sjulian break; 316106266Sjulian case NGM_SOURCE_START: 317106266Sjulian { 318106266Sjulian u_int64_t packets = *(u_int64_t *)msg->data; 319106266Sjulian if (sc->output.hook == NULL) { 320106266Sjulian printf("%s: start on node with no output 321106266Sjulianhook\n", __FUNCTION__); 322106266Sjulian error = EINVAL; 323106266Sjulian break; 324106266Sjulian } 325106266Sjulian /* TODO validation of packets */ 326106266Sjulian sc->packets = packets; 327106266Sjulian ng_source_start(sc); 328106266Sjulian } 329106266Sjulian break; 330106266Sjulian case NGM_SOURCE_STOP: 331106266Sjulian ng_source_stop(sc); 332106266Sjulian break; 333106266Sjulian case NGM_SOURCE_CLR_DATA: 334106266Sjulian ng_source_clr_data(sc); 335106266Sjulian break; 336106266Sjulian default: 337106266Sjulian error = EINVAL; 338106266Sjulian break; 339106266Sjulian } 340106266Sjulian break; 341106266Sjulian default: 342106266Sjulian error = EINVAL; 343106266Sjulian break; 344106266Sjulian } 345106266Sjulian if (rptr) 346106266Sjulian *rptr = resp; 347106266Sjulian else if (resp) 348106266Sjulian FREE(resp, M_NETGRAPH); 349106266Sjulian 350106266Sjuliandone: 351106266Sjulian FREE(msg, M_NETGRAPH); 352106266Sjulian return (error); 353106266Sjulian} 354106266Sjulian 355106266Sjulian/* 356106266Sjulian * Receive data on a hook 357106266Sjulian * 358106266Sjulian * If data comes in the input hook, enqueue it on the send queue. 359106266Sjulian * If data comes in the output hook, discard it. 360106266Sjulian */ 361106266Sjulianstatic int 362106266Sjulianng_source_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 363106266Sjulian{ 364106266Sjulian const sc_p sc = hook->node->private; 365106266Sjulian struct source_hookinfo *const hinfo = (struct source_hookinfo *) 366106266Sjulianhook->private; 367106266Sjulian int error = 0; 368106266Sjulian 369106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 370106266Sjulian KASSERT(hinfo != NULL, ("%s: null hook info", __FUNCTION__)); 371106266Sjulian 372106266Sjulian /* Which hook? */ 373106266Sjulian if (hinfo == &sc->output) { 374106266Sjulian /* discard */ 375106266Sjulian NG_FREE_DATA(m, meta); 376106266Sjulian return (error); 377106266Sjulian } 378106266Sjulian KASSERT(hinfo == &sc->input, ("%s: no hook!", __FUNCTION__)); 379106266Sjulian 380106266Sjulian if ((m->m_flags & M_PKTHDR) == 0) { 381106266Sjulian printf("%s: mbuf without PKTHDR\n", __FUNCTION__); 382106266Sjulian NG_FREE_DATA(m, meta); 383106266Sjulian return (EINVAL); 384106266Sjulian } 385106266Sjulian 386106266Sjulian /* XXX we discard the meta data for now */ 387106266Sjulian NG_FREE_META(meta); 388106266Sjulian 389106266Sjulian /* enque packet */ 390106266Sjulian /* XXX should we check IF_QFULL() ? */ 391106266Sjulian IF_ENQUEUE(&sc->snd_queue, m); 392106266Sjulian sc->queueOctets += m->m_pkthdr.len; 393106266Sjulian 394106266Sjulian return (0); 395106266Sjulian} 396106266Sjulian 397106266Sjulian/* 398106266Sjulian * Shutdown processing 399106266Sjulian */ 400106266Sjulianstatic int 401106266Sjulianng_source_rmnode(node_p node) 402106266Sjulian{ 403106266Sjulian const sc_p sc = node->private; 404106266Sjulian 405106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 406106266Sjulian node->flags |= NG_INVALID; 407106266Sjulian ng_source_stop(sc); 408106266Sjulian ng_cutlinks(node); 409106266Sjulian ng_source_clr_data(sc); 410106266Sjulian ng_unname(node); 411106266Sjulian node->private = NULL; 412106266Sjulian ng_unref(sc->node); 413106266Sjulian FREE(sc, M_NETGRAPH); 414106266Sjulian return (0); 415106266Sjulian} 416106266Sjulian 417106266Sjulian/* 418106266Sjulian * Hook disconnection 419106266Sjulian */ 420106266Sjulianstatic int 421106266Sjulianng_source_disconnect(hook_p hook) 422106266Sjulian{ 423106266Sjulian struct source_hookinfo *const hinfo = (struct source_hookinfo *) 424106266Sjulianhook->private; 425106266Sjulian sc_p sc = (sc_p) hinfo->hook->node->private; 426106266Sjulian 427106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 428106266Sjulian hinfo->hook = NULL; 429106266Sjulian if (hook->node->numhooks == 0 || hinfo == &sc->output) 430106266Sjulian ng_rmnode(hook->node); 431106266Sjulian return (0); 432106266Sjulian} 433106266Sjulian 434106266Sjulian/* 435106266Sjulian * Set sc->output_ifp to point to the the struct ifnet of the interface 436106266Sjulian * reached via our output hook. 437106266Sjulian */ 438106266Sjulianstatic int 439106266Sjulianng_source_get_output_ifp(sc_p sc) 440106266Sjulian{ 441106266Sjulian struct ng_mesg *msg, *rsp; 442106266Sjulian struct ifnet *ifp; 443106266Sjulian u_int32_t if_index; 444106266Sjulian int error = 0; 445106266Sjulian int s; 446106266Sjulian 447106266Sjulian sc->output_ifp = NULL; 448106266Sjulian 449106266Sjulian /* Ask the attached node for the connected interface's index */ 450106266Sjulian NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_GET_IFINDEX, 0, 451106266SjulianM_NOWAIT); 452106266Sjulian if (msg == NULL) 453106266Sjulian return (ENOBUFS); 454106266Sjulian 455106266Sjulian error = ng_send_msg(sc->node, msg, NG_SOURCE_HOOK_OUTPUT, &rsp); 456106266Sjulian if (error != 0) 457106266Sjulian return (error); 458106266Sjulian 459106266Sjulian if (rsp == NULL) 460106266Sjulian return (EINVAL); 461106266Sjulian 462106266Sjulian if (rsp->header.arglen < sizeof(u_int32_t)) 463106266Sjulian return (EINVAL); 464106266Sjulian 465106266Sjulian if_index = *(u_int32_t *)rsp->data; 466106266Sjulian /* Could use ifindex2ifnet[if_index] except that we have no 467106266Sjulian * way of verifying if_index is valid since if_indexlim is 468106266Sjulian * local to if_attach() 469106266Sjulian */ 470106266Sjulian TAILQ_FOREACH(ifp, &ifnet, if_link) { 471106266Sjulian if (ifp->if_index == if_index) 472106266Sjulian break; 473106266Sjulian } 474106266Sjulian 475106266Sjulian if (ifp == NULL) { 476106266Sjulian printf("%s: can't find interface %d\n", __FUNCTION__, 477106266Sjulianif_index); 478106266Sjulian return (EINVAL); 479106266Sjulian } 480106266Sjulian sc->output_ifp = ifp; 481106266Sjulian 482106266Sjulian#if 1 483106266Sjulian /* XXX mucking with a drivers ifqueue size is ugly but we need it 484106266Sjulian * to queue a lot of packets to get close to line rate on a gigabit 485106266Sjulian * interface with small packets. 486106266Sjulian * XXX we should restore the original value at stop or disconnect 487106266Sjulian */ 488106266Sjulian s = splimp(); /* XXX is this required? */ 489106266Sjulian if (ifp->if_snd.ifq_maxlen < NG_SOURCE_DRIVER_IFQ_MAXLEN) 490106266Sjulian { 491106266Sjulian printf("ng_source: changing ifq_maxlen from %d to %d\n", 492106266Sjulian ifp->if_snd.ifq_maxlen, 493106266SjulianNG_SOURCE_DRIVER_IFQ_MAXLEN); 494106266Sjulian ifp->if_snd.ifq_maxlen = NG_SOURCE_DRIVER_IFQ_MAXLEN; 495106266Sjulian } 496106266Sjulian splx(s); 497106266Sjulian#endif 498106266Sjulian return (0); 499106266Sjulian} 500106266Sjulian 501106266Sjulian/* 502106266Sjulian * Set the attached ethernet node's ethernet source address override flag. 503106266Sjulian */ 504106266Sjulianstatic int 505106266Sjulianng_source_set_autosrc(sc_p sc, u_int32_t flag) 506106266Sjulian{ 507106266Sjulian struct ng_mesg *msg; 508106266Sjulian int error = 0; 509106266Sjulian 510106266Sjulian NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_SET_AUTOSRC, 511106266Sjulian sizeof (u_int32_t), M_NOWAIT); 512106266Sjulian if (msg == NULL) 513106266Sjulian return(ENOBUFS); 514106266Sjulian 515106266Sjulian *(u_int32_t *)msg->data = flag; 516106266Sjulian error = ng_send_msg(sc->node, msg, NG_SOURCE_HOOK_OUTPUT, NULL); 517106266Sjulian return (error); 518106266Sjulian} 519106266Sjulian 520106266Sjulian/* 521106266Sjulian * Clear out the data we've queued 522106266Sjulian */ 523106266Sjulianstatic void 524106266Sjulianng_source_clr_data (sc_p sc) 525106266Sjulian{ 526106266Sjulian struct mbuf *m; 527106266Sjulian 528106266Sjulian SPLASSERT(net, __FUNCTION__); 529106266Sjulian for (;;) { 530106266Sjulian IF_DEQUEUE(&sc->snd_queue, m); 531106266Sjulian if (m == NULL) 532106266Sjulian break; 533106266Sjulian NG_FREE_M(m); 534106266Sjulian } 535106266Sjulian sc->queueOctets = 0; 536106266Sjulian} 537106266Sjulian 538106266Sjulian/* 539106266Sjulian * Start sending queued data out the output hook 540106266Sjulian */ 541106266Sjulianstatic void 542106266Sjulianng_source_start (sc_p sc) 543106266Sjulian{ 544106266Sjulian SPLASSERT(net, __FUNCTION__); 545106266Sjulian KASSERT(sc->output.hook != NULL, 546106266Sjulian ("%s: output hook unconnected", __FUNCTION__)); 547106266Sjulian if ((sc->node->flags & NG_SOURCE_ACTIVE) == 0) { 548106266Sjulian if (sc->output_ifp == NULL && ng_source_get_output_ifp(sc) 549106266Sjulian!= 0) 550106266Sjulian return; 551106266Sjulian ng_source_set_autosrc(sc, 0); 552106266Sjulian sc->node->flags |= NG_SOURCE_ACTIVE; 553106266Sjulian timevalclear(&sc->stats.elapsedTime); 554106266Sjulian timevalclear(&sc->stats.endTime); 555106266Sjulian getmicrotime(&sc->stats.startTime); 556106266Sjulian sc->intr_ch = timeout(ng_source_intr, sc, 0); 557106266Sjulian } 558106266Sjulian} 559106266Sjulian 560106266Sjulian/* 561106266Sjulian * Stop sending queued data out the output hook 562106266Sjulian */ 563106266Sjulianstatic void 564106266Sjulianng_source_stop (sc_p sc) 565106266Sjulian{ 566106266Sjulian SPLASSERT(net, __FUNCTION__); 567106266Sjulian if (sc->node->flags & NG_SOURCE_ACTIVE) { 568106266Sjulian untimeout(ng_source_intr, sc, sc->intr_ch); 569106266Sjulian sc->node->flags &= ~NG_SOURCE_ACTIVE; 570106266Sjulian getmicrotime(&sc->stats.endTime); 571106266Sjulian sc->stats.elapsedTime = sc->stats.endTime; 572106266Sjulian timevalsub(&sc->stats.elapsedTime, &sc->stats.startTime); 573106266Sjulian /* XXX should set this to the initial value instead */ 574106266Sjulian ng_source_set_autosrc(sc, 1); 575106266Sjulian } 576106266Sjulian} 577106266Sjulian 578106266Sjulian/* 579106266Sjulian * While active called every NG_SOURCE_INTR_TICKS ticks. 580106266Sjulian * Sends as many packets as the interface connected to our 581106266Sjulian * output hook is able to enqueue. 582106266Sjulian */ 583106266Sjulianstatic void 584106266Sjulianng_source_intr (void *arg) 585106266Sjulian{ 586106266Sjulian const sc_p sc = (sc_p) arg; 587106266Sjulian struct ifqueue *ifq; 588106266Sjulian int packets; 589106266Sjulian 590106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 591106266Sjulian 592106266Sjulian callout_handle_init(&sc->intr_ch); 593106266Sjulian if (sc->packets == 0 || sc->output.hook == NULL 594106266Sjulian || (sc->node->flags & NG_SOURCE_ACTIVE) == 0) { 595106266Sjulian ng_source_stop(sc); 596106266Sjulian return; 597106266Sjulian } 598106266Sjulian 599106266Sjulian ifq = &sc->output_ifp->if_snd; 600106266Sjulian packets = ifq->ifq_maxlen - ifq->ifq_len; 601106266Sjulian ng_source_send(sc, packets, NULL); 602106266Sjulian if (sc->packets == 0) { 603106266Sjulian int s = splnet(); 604106266Sjulian ng_source_stop(sc); 605106266Sjulian splx(s); 606106266Sjulian } else 607106266Sjulian sc->intr_ch = timeout(ng_source_intr, sc, 608106266SjulianNG_SOURCE_INTR_TICKS); 609106266Sjulian} 610106266Sjulian 611106266Sjulian/* 612106266Sjulian * Send packets out our output hook 613106266Sjulian */ 614106266Sjulianstatic int 615106266Sjulianng_source_send (sc_p sc, int tosend, int *sent_p) 616106266Sjulian{ 617106266Sjulian struct ifqueue tmp_queue; 618106266Sjulian struct mbuf *m, *m2; 619106266Sjulian int sent = 0; 620106266Sjulian int error = 0; 621106266Sjulian int s, s2; 622106266Sjulian 623106266Sjulian KASSERT(sc != NULL, ("%s: null node private", __FUNCTION__)); 624106266Sjulian KASSERT(tosend >= 0, ("%s: negative tosend param", __FUNCTION__)); 625106266Sjulian KASSERT(sc->node->flags & NG_SOURCE_ACTIVE, 626106266Sjulian ("%s: inactive node", __FUNCTION__)); 627106266Sjulian 628106266Sjulian if ((u_int64_t)tosend > sc->packets) 629106266Sjulian tosend = sc->packets; 630106266Sjulian 631106266Sjulian /* Copy the required number of packets to a temporary queue */ 632106266Sjulian bzero (&tmp_queue, sizeof (tmp_queue)); 633106266Sjulian for (sent = 0; error == 0 && sent < tosend; ++sent) { 634106266Sjulian s = splnet(); 635106266Sjulian IF_DEQUEUE(&sc->snd_queue, m); 636106266Sjulian splx(s); 637106266Sjulian if (m == NULL) 638106266Sjulian break; 639106266Sjulian 640106266Sjulian /* duplicate the packet */ 641106266Sjulian m2 = m_copypacket(m, M_NOWAIT); 642106266Sjulian if (m2 == NULL) { 643106266Sjulian s = splnet(); 644106266Sjulian IF_PREPEND(&sc->snd_queue, m); 645106266Sjulian splx(s); 646106266Sjulian error = ENOBUFS; 647106266Sjulian break; 648106266Sjulian } 649106266Sjulian 650106266Sjulian /* re-enqueue the original packet for us */ 651106266Sjulian s = splnet(); 652106266Sjulian IF_ENQUEUE(&sc->snd_queue, m); 653106266Sjulian splx(s); 654106266Sjulian 655106266Sjulian /* queue the copy for sending at smplimp */ 656106266Sjulian IF_ENQUEUE(&tmp_queue, m2); 657106266Sjulian } 658106266Sjulian 659106266Sjulian sent = 0; 660106266Sjulian s = splimp(); 661106266Sjulian for (;;) { 662106266Sjulian IF_DEQUEUE(&tmp_queue, m2); 663106266Sjulian if (m2 == NULL) 664106266Sjulian break; 665106266Sjulian if (error == 0) { 666106266Sjulian ++sent; 667106266Sjulian sc->stats.outFrames++; 668106266Sjulian sc->stats.outOctets += m2->m_pkthdr.len; 669106266Sjulian s2 = splnet(); 670106266Sjulian NG_SEND_DATA_ONLY(error, sc->output.hook, m2); 671106266Sjulian splx(s2); 672106266Sjulian } else { 673106266Sjulian NG_FREE_M(m2); 674106266Sjulian } 675106266Sjulian } 676106266Sjulian splx(s); 677106266Sjulian 678106266Sjulian sc->packets -= sent; 679106266Sjulian if (sent_p != NULL) 680106266Sjulian *sent_p = sent; 681106266Sjulian return (error); 682106266Sjulian} 683