168810Sarchie/* 268810Sarchie * ng_one2many.c 3139823Simp */ 4139823Simp 5139823Simp/*- 668810Sarchie * Copyright (c) 2000 Whistle Communications, Inc. 768810Sarchie * All rights reserved. 868810Sarchie * 968810Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1068810Sarchie * redistribution of this software, in source or object code forms, with or 1168810Sarchie * without modifications are expressly permitted by Whistle Communications; 1268810Sarchie * provided, however, that: 1368810Sarchie * 1. Any and all reproductions of the source or object code must include the 1468810Sarchie * copyright notice above and the following disclaimer of warranties; and 1568810Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1668810Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1768810Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1868810Sarchie * such appears in the above copyright notice or in the software. 1968810Sarchie * 2068810Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2168810Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2268810Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2368810Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2468810Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2568810Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2668810Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2768810Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2868810Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2968810Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3068810Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3168810Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3268810Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3368810Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3468810Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3568810Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3668810Sarchie * OF SUCH DAMAGE. 3768810Sarchie * 3868810Sarchie * Author: Archie Cobbs <archie@freebsd.org> 3968810Sarchie * 4068810Sarchie * $FreeBSD$ 4168810Sarchie */ 4268810Sarchie 4368810Sarchie/* 4468810Sarchie * ng_one2many(4) netgraph node type 4568810Sarchie * 4668810Sarchie * Packets received on the "one" hook are sent out each of the 4771738Sjulian * "many" hooks accoring to an algorithm. Packets received on any 4868810Sarchie * "many" hook are always delivered to the "one" hook. 4968810Sarchie */ 5068810Sarchie 5168810Sarchie#include <sys/param.h> 5268810Sarchie#include <sys/systm.h> 5368810Sarchie#include <sys/kernel.h> 5468810Sarchie#include <sys/malloc.h> 5568810Sarchie#include <sys/ctype.h> 5668810Sarchie#include <sys/mbuf.h> 5768810Sarchie#include <sys/errno.h> 5868810Sarchie 5968810Sarchie#include <netgraph/ng_message.h> 6068810Sarchie#include <netgraph/netgraph.h> 6168810Sarchie#include <netgraph/ng_parse.h> 6268810Sarchie#include <netgraph/ng_one2many.h> 6368810Sarchie 6468810Sarchie/* Per-link private data */ 6568810Sarchiestruct ng_one2many_link { 6668810Sarchie hook_p hook; /* netgraph hook */ 6768810Sarchie struct ng_one2many_link_stats stats; /* link stats */ 6868810Sarchie}; 6968810Sarchie 7068810Sarchie/* Per-node private data */ 7168810Sarchiestruct ng_one2many_private { 72138010Sglebius node_p node; /* link to node */ 7368810Sarchie struct ng_one2many_config conf; /* node configuration */ 7468810Sarchie struct ng_one2many_link one; /* "one" hook */ 7568810Sarchie struct ng_one2many_link many[NG_ONE2MANY_MAX_LINKS]; 7668810Sarchie u_int16_t nextMany; /* next round-robin */ 7768810Sarchie u_int16_t numActiveMany; /* # active "many" */ 7868810Sarchie u_int16_t activeMany[NG_ONE2MANY_MAX_LINKS]; 7968810Sarchie}; 8068810Sarchietypedef struct ng_one2many_private *priv_p; 8168810Sarchie 8268810Sarchie/* Netgraph node methods */ 8368810Sarchiestatic ng_constructor_t ng_one2many_constructor; 8468810Sarchiestatic ng_rcvmsg_t ng_one2many_rcvmsg; 8570700Sjulianstatic ng_shutdown_t ng_one2many_shutdown; 8668810Sarchiestatic ng_newhook_t ng_one2many_newhook; 8768810Sarchiestatic ng_rcvdata_t ng_one2many_rcvdata; 8868810Sarchiestatic ng_disconnect_t ng_one2many_disconnect; 8968810Sarchie 9068810Sarchie/* Other functions */ 9168810Sarchiestatic void ng_one2many_update_many(priv_p priv); 92138010Sglebiusstatic void ng_one2many_notify(priv_p priv, uint32_t cmd); 9368810Sarchie 9468810Sarchie/****************************************************************** 9568810Sarchie NETGRAPH PARSE TYPES 9668810Sarchie******************************************************************/ 9768810Sarchie 9868810Sarchie/* Parse type for struct ng_one2many_config */ 9968810Sarchiestatic const struct ng_parse_fixedarray_info 10068810Sarchie ng_one2many_enableLinks_array_type_info = { 10168810Sarchie &ng_parse_uint8_type, 10268810Sarchie NG_ONE2MANY_MAX_LINKS 10368810Sarchie}; 10468810Sarchiestatic const struct ng_parse_type ng_one2many_enableLinks_array_type = { 10568810Sarchie &ng_parse_fixedarray_type, 10668810Sarchie &ng_one2many_enableLinks_array_type_info, 10768810Sarchie}; 10897685Sarchiestatic const struct ng_parse_struct_field ng_one2many_config_type_fields[] 10968810Sarchie = NG_ONE2MANY_CONFIG_TYPE_INFO(&ng_one2many_enableLinks_array_type); 11068810Sarchiestatic const struct ng_parse_type ng_one2many_config_type = { 11168810Sarchie &ng_parse_struct_type, 11297685Sarchie &ng_one2many_config_type_fields 11368810Sarchie}; 11468810Sarchie 11568810Sarchie/* Parse type for struct ng_one2many_link_stats */ 11697685Sarchiestatic const struct ng_parse_struct_field ng_one2many_link_stats_type_fields[] 11797685Sarchie = NG_ONE2MANY_LINK_STATS_TYPE_INFO; 11868810Sarchiestatic const struct ng_parse_type ng_one2many_link_stats_type = { 11968810Sarchie &ng_parse_struct_type, 12097685Sarchie &ng_one2many_link_stats_type_fields 12168810Sarchie}; 12268810Sarchie 12368810Sarchie/* List of commands and how to convert arguments to/from ASCII */ 12468810Sarchiestatic const struct ng_cmdlist ng_one2many_cmdlist[] = { 12568810Sarchie { 12668810Sarchie NGM_ONE2MANY_COOKIE, 12768810Sarchie NGM_ONE2MANY_SET_CONFIG, 12868810Sarchie "setconfig", 12968810Sarchie &ng_one2many_config_type, 13068810Sarchie NULL 13168810Sarchie }, 13268810Sarchie { 13368810Sarchie NGM_ONE2MANY_COOKIE, 13468810Sarchie NGM_ONE2MANY_GET_CONFIG, 13568810Sarchie "getconfig", 13668810Sarchie NULL, 13768810Sarchie &ng_one2many_config_type 13868810Sarchie }, 13968810Sarchie { 14068810Sarchie NGM_ONE2MANY_COOKIE, 14168810Sarchie NGM_ONE2MANY_GET_STATS, 14268810Sarchie "getstats", 14368810Sarchie &ng_parse_int32_type, 14468810Sarchie &ng_one2many_link_stats_type 14568810Sarchie }, 14668810Sarchie { 14768810Sarchie NGM_ONE2MANY_COOKIE, 14868810Sarchie NGM_ONE2MANY_CLR_STATS, 14968810Sarchie "clrstats", 15068810Sarchie &ng_parse_int32_type, 15168810Sarchie NULL, 15268810Sarchie }, 15368810Sarchie { 15468810Sarchie NGM_ONE2MANY_COOKIE, 15568810Sarchie NGM_ONE2MANY_GETCLR_STATS, 15668810Sarchie "getclrstats", 15768810Sarchie &ng_parse_int32_type, 15868810Sarchie &ng_one2many_link_stats_type 15968810Sarchie }, 16068810Sarchie { 0 } 16168810Sarchie}; 16268810Sarchie 16368810Sarchie/* Node type descriptor */ 16468810Sarchiestatic struct ng_type ng_one2many_typestruct = { 165129823Sjulian .version = NG_ABI_VERSION, 166129823Sjulian .name = NG_ONE2MANY_NODE_TYPE, 167129823Sjulian .constructor = ng_one2many_constructor, 168129823Sjulian .rcvmsg = ng_one2many_rcvmsg, 169129823Sjulian .shutdown = ng_one2many_shutdown, 170129823Sjulian .newhook = ng_one2many_newhook, 171129823Sjulian .rcvdata = ng_one2many_rcvdata, 172129823Sjulian .disconnect = ng_one2many_disconnect, 173129823Sjulian .cmdlist = ng_one2many_cmdlist, 17468810Sarchie}; 17568810SarchieNETGRAPH_INIT(one2many, &ng_one2many_typestruct); 17668810Sarchie 17768810Sarchie/****************************************************************** 17868810Sarchie NETGRAPH NODE METHODS 17968810Sarchie******************************************************************/ 18068810Sarchie 18168810Sarchie/* 18268810Sarchie * Node constructor 18368810Sarchie */ 18468810Sarchiestatic int 18570700Sjulianng_one2many_constructor(node_p node) 18668810Sarchie{ 18768810Sarchie priv_p priv; 18868810Sarchie 18968810Sarchie /* Allocate and initialize private info */ 190220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); 19168810Sarchie priv->conf.xmitAlg = NG_ONE2MANY_XMIT_ROUNDROBIN; 19268810Sarchie priv->conf.failAlg = NG_ONE2MANY_FAIL_MANUAL; 19368810Sarchie 194138010Sglebius /* cross reference */ 19570784Sjulian NG_NODE_SET_PRIVATE(node, priv); 196138010Sglebius priv->node = node; 19768810Sarchie 19868810Sarchie /* Done */ 19968810Sarchie return (0); 20068810Sarchie} 20168810Sarchie 20268810Sarchie/* 20368810Sarchie * Method for attaching a new hook 20468810Sarchie */ 20568810Sarchiestatic int 20668810Sarchieng_one2many_newhook(node_p node, hook_p hook, const char *name) 20768810Sarchie{ 20870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 20968810Sarchie struct ng_one2many_link *link; 21068810Sarchie int linkNum; 21168810Sarchie u_long i; 21268810Sarchie 21368810Sarchie /* Which hook? */ 21468810Sarchie if (strncmp(name, NG_ONE2MANY_HOOK_MANY_PREFIX, 21568810Sarchie strlen(NG_ONE2MANY_HOOK_MANY_PREFIX)) == 0) { 21668810Sarchie const char *cp; 21768810Sarchie char *eptr; 21868810Sarchie 21968810Sarchie cp = name + strlen(NG_ONE2MANY_HOOK_MANY_PREFIX); 22068810Sarchie if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) 22168810Sarchie return (EINVAL); 22268810Sarchie i = strtoul(cp, &eptr, 10); 22368810Sarchie if (*eptr != '\0' || i < 0 || i >= NG_ONE2MANY_MAX_LINKS) 22468810Sarchie return (EINVAL); 22568810Sarchie linkNum = (int)i; 22668810Sarchie link = &priv->many[linkNum]; 22768810Sarchie } else if (strcmp(name, NG_ONE2MANY_HOOK_ONE) == 0) { 22868810Sarchie linkNum = NG_ONE2MANY_ONE_LINKNUM; 22968810Sarchie link = &priv->one; 23068810Sarchie } else 23168810Sarchie return (EINVAL); 23268810Sarchie 23368810Sarchie /* Is hook already connected? (should never happen) */ 23468810Sarchie if (link->hook != NULL) 23568810Sarchie return (EISCONN); 23668810Sarchie 23768810Sarchie /* Setup private info for this link */ 238106665Sjhb NG_HOOK_SET_PRIVATE(hook, (void *)(intptr_t)linkNum); 23968810Sarchie link->hook = hook; 24068810Sarchie bzero(&link->stats, sizeof(link->stats)); 24168810Sarchie if (linkNum != NG_ONE2MANY_ONE_LINKNUM) { 24268810Sarchie priv->conf.enabledLinks[linkNum] = 1; /* auto-enable link */ 24368810Sarchie ng_one2many_update_many(priv); 24468810Sarchie } 24568810Sarchie 24668810Sarchie /* Done */ 24768810Sarchie return (0); 24868810Sarchie} 24968810Sarchie 25068810Sarchie/* 25168810Sarchie * Receive a control message 25268810Sarchie */ 25368810Sarchiestatic int 25470700Sjulianng_one2many_rcvmsg(node_p node, item_p item, hook_p lasthook) 25568810Sarchie{ 25670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 25768810Sarchie struct ng_mesg *resp = NULL; 25868810Sarchie int error = 0; 25970700Sjulian struct ng_mesg *msg; 26068810Sarchie 26170700Sjulian NGI_GET_MSG(item, msg); 26268810Sarchie switch (msg->header.typecookie) { 26368810Sarchie case NGM_ONE2MANY_COOKIE: 26468810Sarchie switch (msg->header.cmd) { 26568810Sarchie case NGM_ONE2MANY_SET_CONFIG: 26668810Sarchie { 26768810Sarchie struct ng_one2many_config *conf; 26868810Sarchie int i; 26968810Sarchie 27068810Sarchie /* Check that new configuration is valid */ 27168810Sarchie if (msg->header.arglen != sizeof(*conf)) { 27268810Sarchie error = EINVAL; 27368810Sarchie break; 27468810Sarchie } 27568810Sarchie conf = (struct ng_one2many_config *)msg->data; 27668810Sarchie switch (conf->xmitAlg) { 27768810Sarchie case NG_ONE2MANY_XMIT_ROUNDROBIN: 27871738Sjulian case NG_ONE2MANY_XMIT_ALL: 279219127Sae case NG_ONE2MANY_XMIT_FAILOVER: 28068810Sarchie break; 28168810Sarchie default: 28268810Sarchie error = EINVAL; 28368810Sarchie break; 28468810Sarchie } 28568810Sarchie switch (conf->failAlg) { 28668810Sarchie case NG_ONE2MANY_FAIL_MANUAL: 287138010Sglebius case NG_ONE2MANY_FAIL_NOTIFY: 28868810Sarchie break; 28968810Sarchie default: 29068810Sarchie error = EINVAL; 29168810Sarchie break; 29268810Sarchie } 29368810Sarchie if (error != 0) 29468810Sarchie break; 29568810Sarchie 29668810Sarchie /* Normalized many link enabled bits */ 29768810Sarchie for (i = 0; i < NG_ONE2MANY_MAX_LINKS; i++) 29868810Sarchie conf->enabledLinks[i] = !!conf->enabledLinks[i]; 29968810Sarchie 30068810Sarchie /* Copy config and reset */ 30168810Sarchie bcopy(conf, &priv->conf, sizeof(*conf)); 30268810Sarchie ng_one2many_update_many(priv); 30368810Sarchie break; 30468810Sarchie } 30568810Sarchie case NGM_ONE2MANY_GET_CONFIG: 30668810Sarchie { 30768810Sarchie struct ng_one2many_config *conf; 30868810Sarchie 30968810Sarchie NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); 31068810Sarchie if (resp == NULL) { 31168810Sarchie error = ENOMEM; 31268810Sarchie break; 31368810Sarchie } 31468810Sarchie conf = (struct ng_one2many_config *)resp->data; 31568810Sarchie bcopy(&priv->conf, conf, sizeof(priv->conf)); 31668810Sarchie break; 31768810Sarchie } 31868810Sarchie case NGM_ONE2MANY_GET_STATS: 31968810Sarchie case NGM_ONE2MANY_CLR_STATS: 32068810Sarchie case NGM_ONE2MANY_GETCLR_STATS: 32168810Sarchie { 32268810Sarchie struct ng_one2many_link *link; 32368810Sarchie int linkNum; 32468810Sarchie 32568810Sarchie /* Get link */ 32668810Sarchie if (msg->header.arglen != sizeof(int32_t)) { 32768810Sarchie error = EINVAL; 32868810Sarchie break; 32968810Sarchie } 33068810Sarchie linkNum = *((int32_t *)msg->data); 33168810Sarchie if (linkNum == NG_ONE2MANY_ONE_LINKNUM) 33268810Sarchie link = &priv->one; 333143404Sglebius else if (linkNum >= 0 33468810Sarchie && linkNum < NG_ONE2MANY_MAX_LINKS) { 33568810Sarchie link = &priv->many[linkNum]; 33668810Sarchie } else { 33768810Sarchie error = EINVAL; 33868810Sarchie break; 33968810Sarchie } 34068810Sarchie 34168810Sarchie /* Get/clear stats */ 34268810Sarchie if (msg->header.cmd != NGM_ONE2MANY_CLR_STATS) { 34368810Sarchie NG_MKRESPONSE(resp, msg, 34468810Sarchie sizeof(link->stats), M_NOWAIT); 34568810Sarchie if (resp == NULL) { 34668810Sarchie error = ENOMEM; 34768810Sarchie break; 34868810Sarchie } 34968810Sarchie bcopy(&link->stats, 35068810Sarchie resp->data, sizeof(link->stats)); 35168810Sarchie } 35268810Sarchie if (msg->header.cmd != NGM_ONE2MANY_GET_STATS) 35368810Sarchie bzero(&link->stats, sizeof(link->stats)); 35468810Sarchie break; 35568810Sarchie } 35668810Sarchie default: 35768810Sarchie error = EINVAL; 35868810Sarchie break; 35968810Sarchie } 36068810Sarchie break; 361138010Sglebius /* 362138010Sglebius * One of our downstreams notifies us of link change. If we are 363138010Sglebius * configured to listen to these message, then we remove/add 364138010Sglebius * this hook from array of active hooks. 365138010Sglebius */ 366138010Sglebius case NGM_FLOW_COOKIE: 367138010Sglebius { 368138010Sglebius int linkNum; 369138010Sglebius 370138010Sglebius if (priv->conf.failAlg != NG_ONE2MANY_FAIL_NOTIFY) 371138010Sglebius break; 372138010Sglebius 373138010Sglebius if (lasthook == NULL) 374138010Sglebius break; 375138010Sglebius 376138010Sglebius linkNum = (intptr_t)NG_HOOK_PRIVATE(lasthook); 377138010Sglebius if (linkNum == NG_ONE2MANY_ONE_LINKNUM) 378138010Sglebius break; 379138010Sglebius 380138010Sglebius KASSERT((linkNum >= 0 && linkNum < NG_ONE2MANY_MAX_LINKS), 381138010Sglebius ("%s: linkNum=%d", __func__, linkNum)); 382138010Sglebius 383138010Sglebius switch (msg->header.cmd) { 384138010Sglebius case NGM_LINK_IS_UP: 385138010Sglebius priv->conf.enabledLinks[linkNum] = 1; 386138010Sglebius ng_one2many_update_many(priv); 387138010Sglebius break; 388138010Sglebius case NGM_LINK_IS_DOWN: 389138010Sglebius priv->conf.enabledLinks[linkNum] = 0; 390138010Sglebius ng_one2many_update_many(priv); 391138010Sglebius break; 392138010Sglebius default: 393138010Sglebius break; 394138010Sglebius } 395138010Sglebius break; 396138010Sglebius } 39768810Sarchie default: 39868810Sarchie error = EINVAL; 39968810Sarchie break; 40068810Sarchie } 40168810Sarchie 40268810Sarchie /* Done */ 40370700Sjulian NG_RESPOND_MSG(error, node, item, resp); 40470700Sjulian NG_FREE_MSG(msg); 40568810Sarchie return (error); 40668810Sarchie} 40768810Sarchie 40868810Sarchie/* 40968810Sarchie * Receive data on a hook 41068810Sarchie */ 41168810Sarchiestatic int 41270700Sjulianng_one2many_rcvdata(hook_p hook, item_p item) 41368810Sarchie{ 41470784Sjulian const node_p node = NG_HOOK_NODE(hook); 41570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 41668810Sarchie struct ng_one2many_link *src; 41771849Sjulian struct ng_one2many_link *dst = NULL; 41868810Sarchie int error = 0; 41968810Sarchie int linkNum; 42071738Sjulian int i; 42170700Sjulian struct mbuf *m; 42268810Sarchie 42370700Sjulian m = NGI_M(item); /* just peaking, mbuf still owned by item */ 42468810Sarchie /* Get link number */ 425106665Sjhb linkNum = (intptr_t)NG_HOOK_PRIVATE(hook); 42668810Sarchie KASSERT(linkNum == NG_ONE2MANY_ONE_LINKNUM 42768810Sarchie || (linkNum >= 0 && linkNum < NG_ONE2MANY_MAX_LINKS), 42887599Sobrien ("%s: linkNum=%d", __func__, linkNum)); 42968810Sarchie 43068810Sarchie /* Figure out source link */ 43168810Sarchie src = (linkNum == NG_ONE2MANY_ONE_LINKNUM) ? 43268810Sarchie &priv->one : &priv->many[linkNum]; 43387599Sobrien KASSERT(src->hook != NULL, ("%s: no src%d", __func__, linkNum)); 43468810Sarchie 43568810Sarchie /* Update receive stats */ 43668810Sarchie src->stats.recvPackets++; 43768810Sarchie src->stats.recvOctets += m->m_pkthdr.len; 43868810Sarchie 43968810Sarchie /* Figure out destination link */ 44068810Sarchie if (linkNum == NG_ONE2MANY_ONE_LINKNUM) { 44168810Sarchie if (priv->numActiveMany == 0) { 44270700Sjulian NG_FREE_ITEM(item); 44368810Sarchie return (ENOTCONN); 44468810Sarchie } 44571738Sjulian switch(priv->conf.xmitAlg) { 44671738Sjulian case NG_ONE2MANY_XMIT_ROUNDROBIN: 44771738Sjulian dst = &priv->many[priv->activeMany[priv->nextMany]]; 44871738Sjulian priv->nextMany = (priv->nextMany + 1) % priv->numActiveMany; 44971738Sjulian break; 45071738Sjulian case NG_ONE2MANY_XMIT_ALL: 45171738Sjulian /* no need to copy data for the 1st one */ 45271738Sjulian dst = &priv->many[priv->activeMany[0]]; 45371738Sjulian 45471738Sjulian /* make copies of data and send for all links 45571738Sjulian * except the first one, which we'll do last 45671738Sjulian */ 45771738Sjulian for (i = 1; i < priv->numActiveMany; i++) { 45871738Sjulian struct mbuf *m2; 45971738Sjulian struct ng_one2many_link *mdst; 46071738Sjulian 46171738Sjulian mdst = &priv->many[priv->activeMany[i]]; 462111119Simp m2 = m_dup(m, M_DONTWAIT); /* XXX m_copypacket() */ 46371738Sjulian if (m2 == NULL) { 46471738Sjulian mdst->stats.memoryFailures++; 46571738Sjulian NG_FREE_ITEM(item); 46671738Sjulian NG_FREE_M(m); 46771738Sjulian return (ENOBUFS); 46871738Sjulian } 46971738Sjulian /* Update transmit stats */ 47071738Sjulian mdst->stats.xmitPackets++; 47171738Sjulian mdst->stats.xmitOctets += m->m_pkthdr.len; 472131155Sjulian NG_SEND_DATA_ONLY(error, mdst->hook, m2); 47371738Sjulian } 47471738Sjulian break; 475219127Sae case NG_ONE2MANY_XMIT_FAILOVER: 476219127Sae dst = &priv->many[priv->activeMany[0]]; 477219127Sae break; 47871738Sjulian#ifdef INVARIANTS 47971738Sjulian default: 48087599Sobrien panic("%s: invalid xmitAlg", __func__); 48171738Sjulian#endif 48271738Sjulian } 48371849Sjulian } else { 48468810Sarchie dst = &priv->one; 48571849Sjulian } 48668810Sarchie 48768810Sarchie /* Update transmit stats */ 48868810Sarchie dst->stats.xmitPackets++; 48968810Sarchie dst->stats.xmitOctets += m->m_pkthdr.len; 49068810Sarchie 49168810Sarchie /* Deliver packet */ 49270784Sjulian NG_FWD_ITEM_HOOK(error, item, dst->hook); 49368810Sarchie return (error); 49468810Sarchie} 49568810Sarchie 49668810Sarchie/* 49768810Sarchie * Shutdown node 49868810Sarchie */ 49968810Sarchiestatic int 50070700Sjulianng_one2many_shutdown(node_p node) 50168810Sarchie{ 50270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 50368810Sarchie 50468810Sarchie KASSERT(priv->numActiveMany == 0, 50587599Sobrien ("%s: numActiveMany=%d", __func__, priv->numActiveMany)); 506184205Sdes free(priv, M_NETGRAPH); 50770784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 50870784Sjulian NG_NODE_UNREF(node); 50968810Sarchie return (0); 51068810Sarchie} 51168810Sarchie 51268810Sarchie/* 51368810Sarchie * Hook disconnection. 51468810Sarchie */ 51568810Sarchiestatic int 51668810Sarchieng_one2many_disconnect(hook_p hook) 51768810Sarchie{ 51870784Sjulian const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 51968810Sarchie int linkNum; 52068810Sarchie 52168810Sarchie /* Get link number */ 522106665Sjhb linkNum = (intptr_t)NG_HOOK_PRIVATE(hook); 52368810Sarchie KASSERT(linkNum == NG_ONE2MANY_ONE_LINKNUM 52468810Sarchie || (linkNum >= 0 && linkNum < NG_ONE2MANY_MAX_LINKS), 52587599Sobrien ("%s: linkNum=%d", __func__, linkNum)); 52668810Sarchie 52768810Sarchie /* Nuke the link */ 52868810Sarchie if (linkNum == NG_ONE2MANY_ONE_LINKNUM) 52968810Sarchie priv->one.hook = NULL; 53068810Sarchie else { 53168810Sarchie priv->many[linkNum].hook = NULL; 53268810Sarchie priv->conf.enabledLinks[linkNum] = 0; 53368810Sarchie ng_one2many_update_many(priv); 53468810Sarchie } 53568810Sarchie 53668810Sarchie /* If no hooks left, go away */ 53770784Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 53870784Sjulian && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 53970784Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 54068810Sarchie return (0); 54168810Sarchie} 54268810Sarchie 54368810Sarchie/****************************************************************** 54468810Sarchie OTHER FUNCTIONS 54568810Sarchie******************************************************************/ 54668810Sarchie 54768810Sarchie/* 54868810Sarchie * Update internal state after the addition or removal of a "many" link 54968810Sarchie */ 55068810Sarchiestatic void 55168810Sarchieng_one2many_update_many(priv_p priv) 55268810Sarchie{ 553138010Sglebius uint16_t saveActive = priv->numActiveMany; 55468810Sarchie int linkNum; 55568810Sarchie 55668810Sarchie /* Update list of which "many" links are up */ 55768810Sarchie priv->numActiveMany = 0; 55868810Sarchie for (linkNum = 0; linkNum < NG_ONE2MANY_MAX_LINKS; linkNum++) { 55968810Sarchie switch (priv->conf.failAlg) { 56068810Sarchie case NG_ONE2MANY_FAIL_MANUAL: 561138010Sglebius case NG_ONE2MANY_FAIL_NOTIFY: 56268810Sarchie if (priv->many[linkNum].hook != NULL 56368810Sarchie && priv->conf.enabledLinks[linkNum]) { 56468810Sarchie priv->activeMany[priv->numActiveMany] = linkNum; 56568810Sarchie priv->numActiveMany++; 56668810Sarchie } 56768810Sarchie break; 56868810Sarchie#ifdef INVARIANTS 56968810Sarchie default: 57087599Sobrien panic("%s: invalid failAlg", __func__); 57168810Sarchie#endif 57268810Sarchie } 57368810Sarchie } 57468810Sarchie 575138010Sglebius if (priv->numActiveMany == 0 && saveActive > 0) 576138010Sglebius ng_one2many_notify(priv, NGM_LINK_IS_DOWN); 577138010Sglebius 578138010Sglebius if (saveActive == 0 && priv->numActiveMany > 0) 579138010Sglebius ng_one2many_notify(priv, NGM_LINK_IS_UP); 580138010Sglebius 58168810Sarchie /* Update transmit algorithm state */ 58268810Sarchie switch (priv->conf.xmitAlg) { 58368810Sarchie case NG_ONE2MANY_XMIT_ROUNDROBIN: 58468810Sarchie if (priv->numActiveMany > 0) 58568810Sarchie priv->nextMany %= priv->numActiveMany; 58668810Sarchie break; 58771738Sjulian case NG_ONE2MANY_XMIT_ALL: 588219127Sae case NG_ONE2MANY_XMIT_FAILOVER: 58971738Sjulian break; 59068810Sarchie#ifdef INVARIANTS 59168810Sarchie default: 59287599Sobrien panic("%s: invalid xmitAlg", __func__); 59368810Sarchie#endif 59468810Sarchie } 59568810Sarchie} 59668810Sarchie 597138010Sglebius/* 598138010Sglebius * Notify upstream if we are out of links, or we have at least one link. 599138010Sglebius */ 600138010Sglebiusstatic void 601138010Sglebiusng_one2many_notify(priv_p priv, uint32_t cmd) 602138010Sglebius{ 603138010Sglebius struct ng_mesg *msg; 604138010Sglebius int dummy_error = 0; 60568810Sarchie 606138010Sglebius if (priv->one.hook == NULL) 607138010Sglebius return; 608138010Sglebius 609138010Sglebius NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT); 610138010Sglebius if (msg != NULL) 611138010Sglebius NG_SEND_MSG_HOOK(dummy_error, priv->node, msg, priv->one.hook, 0); 612138010Sglebius} 613