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