diff options
-rw-r--r-- | share/man/man4/Makefile | 1 | ||||
-rw-r--r-- | share/man/man4/ng_one2many.4 | 208 | ||||
-rw-r--r-- | sys/modules/netgraph/one2many/Makefile | 7 | ||||
-rw-r--r-- | sys/netgraph/ng_one2many.c | 521 | ||||
-rw-r--r-- | sys/netgraph/ng_one2many.h | 112 |
5 files changed, 849 insertions, 0 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 4358176..306f87d 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -90,6 +90,7 @@ MAN4= aac.4 \ ng_ksocket.4 \ ng_lmi.4 \ ng_mppc.4 \ + ng_one2many.4 \ ng_ppp.4 \ ng_pppoe.4 \ ng_pptpgre.4 \ diff --git a/share/man/man4/ng_one2many.4 b/share/man/man4/ng_one2many.4 new file mode 100644 index 0000000..a04d884 --- /dev/null +++ b/share/man/man4/ng_one2many.4 @@ -0,0 +1,208 @@ +.\" Copyright (c) 2000 Whistle Communications, Inc. +.\" All rights reserved. +.\" +.\" Subject to the following obligations and disclaimer of warranty, use and +.\" redistribution of this software, in source or object code forms, with or +.\" without modifications are expressly permitted by Whistle Communications; +.\" provided, however, that: +.\" 1. Any and all reproductions of the source or object code must include the +.\" copyright notice above and the following disclaimer of warranties; and +.\" 2. No rights are granted, in any manner or form, to use Whistle +.\" Communications, Inc. trademarks, including the mark "WHISTLE +.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as +.\" such appears in the above copyright notice or in the software. +.\" +.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND +.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO +.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, +.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. +.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY +.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS +.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. +.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES +.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING +.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY +.\" OF SUCH DAMAGE. +.\" +.\" Author: Archie Cobbs <archie@freebsd.org> +.\" +.\" $FreeBSD$ +.\" +.Dd November 15, 2000 +.Dt NG_ONE2MANY 4 +.Os FreeBSD +.Sh NAME +.Nm ng_one2many +.Nd packet multiplexing netgraph node type +.Sh SYNOPSIS +.Fd #include <netgraph/ng_one2many.h> +.Sh DESCRIPTION +The +.Nm one2many +provides a simple mechanism for routing packets over several links +in a one-to-many (and in the reverse direction, many-to-one) fashion. +There is a single hook named +.Dv one , +and multiple hooks named +.Dv many0 , +.Dv many1 , +etc. +Packets received on any of the +.Dv many +hooks are forwarded out the +.Dv one +hook. +Packets received on the +.Dv one +hook are forwarded out one of the +.Dv many +hooks; which hook is determined by the node's configured +transmit algorithm. +Packets are not altered in any way. +.Pp +Each of the connected many links may be considered to be up or down. +Packets are never delivered out a many hook that is down. +How a link is determined to be up or down depends on the node's +configured link failure detection algorithm. +.Sh TRANSMIT ALGORITHMS +At this time, the only algorithm for determing the outgoing +.Dv many +hook is a simple round-robin delivery algorithm. +Packets are delivered out the many hooks in sequential order. +.Pp +In the future other algorithms may be added as well. +.Sh LINK FAILURE DETECTION +At this time, the only algorithm for determining when a link +has failed, other than the hook being disconnected, is the +``manual'' algorithm: the node is explicitly told which of +the links are up via the +.Dv NGM_ONE2MANY_SET_CONFIG +control message (see below). +Newly connected links are down until configured otherwise. +.Pp +In the future other algorithms may be added as well. +.Sh HOOKS +This node type supports up to +.Dv NG_ONE2MANY_MAX_LINKS +hooks named +.Dv many0 , +.Dv many1 , +etc., +plus a single hook named +.Dv one . +.Sh CONTROL MESSAGES +This node type supports the generic control messages, plus the +following: +.Bl -tag -width foo +.It Dv NGM_ONE2MANY_SET_CONFIG +Sets the node configuration using a +.Dv "struct ng_one2many_link_config" +as the control message argument: +.Bd -literal -offset 0 +/* Node configuration structure */ +struct ng_one2many_config { + u_int32_t xmitAlg; /* how to distribute packets */ + u_int32_t failAlg; /* how to detect link failure */ + u_char enabledLinks[NG_ONE2MANY_MAX_LINKS]; +}; +.Ed +.Pp +Currently, the only valid setting for the +.Dv xmitAlg +field is +.Dv NG_ONE2MANY_XMIT_ROUNDROBIN ; +this is also the default setting. +The only valid setting for +.Dv failAlg +is +.Dv NG_ONE2MANY_FAIL_MANUAL ; +this is also the default setting. +.It Dv NGM_ONE2MANY_GET_CONFIG +Returns the current node configuration in a +.Dv "struct ng_one2many_link_config" . +.It Dv NGM_ONE2MANY_GET_STATS +This command takes a 32 bit link number as an argument and +returns a +.Dv "struct ng_one2many_link_stats" +containing statistics for the corresponding +.Dv many +link, which may or may not be currently connected: +.Bd -literal -offset 0 +/* Statistics structure (one for each link) */ +struct ng_one2many_link_stats { + u_int64_t recvOctets; /* total octets rec'd on link */ + u_int64_t recvPackets; /* total pkts rec'd on link */ + u_int64_t xmitOctets; /* total octets xmit'd on link */ + u_int64_t xmitPackets; /* total pkts xmit'd on link */ +}; +.Ed +.Pp +To access statistics for the +.Dv one +link, use the link number +.Dv -1 . +.It Dv NGM_ONE2MANY_CLR_STATS +This command takes a 32 bit link number as an argument and +clears the statistics for that link. +.It Dv NGM_ONE2MANY_GETCLR_STATS +Same as +.Dv NGM_ONE2MANY_GET_STATS , +but also atomically clears the statistics for the link as well. +.Sh SHUTDOWN +This node shuts down upon receipt of a +.Dv NGM_SHUTDOWN +control message, or when all hooks have been disconnected. +.Sh EXAMPLE +The following commands will set up Ethernet interfaces +.Dv fxp0 +to deliver packets alternating over the physical interfaces +corresponding to networking interfaces +.Dv fxp0 +through +.Dv fxp3 : +.Bd -literal -offset 0 + # Plumb nodes together + ngctl mkpeer fxp0: ng_one2many upper one + ngctl connect fxp0: fxp0:upper lower many0 + ngctl connect fxp1: fxp0:upper lower many1 + ngctl connect fxp2: fxp0:upper lower many2 + ngctl connect fxp3: fxp0:upper lower many3 + # Allow fxp1 through fxp3 to xmit/recv fxp0 frames + ngctl msg fxp1: setpromisc 1 + ngctl msg fxp3: setpromisc 1 + ngctl msg fxp2: setpromisc 1 + ngctl msg fxp1: setautosrc 0 + ngctl msg fxp3: setautosrc 0 + ngctl msg fxp2: setautosrc 0 + # Configure all four links as up + ngctl msg fxp0:upper \\ + setconfig "{ xmitAlg=1 failAlg=1 enabledLinks={ 1 1 1 1 } }" + # Bring up interface + ifconfig fxp0 192.168.1.1 netmask 0xfffffffc +.Ed +.Pp +With a similar setup on a peer machine (using the address +192.168.1.2), a point-to-point +Ethernet connection with four times normal bandwidth is +achieved. +.Sh BUGS +More transmit and link failure algorithms should be supported. +A good candidate is Cisco's Etherchannel. +.Sh SEE ALSO +.Xr netgraph 4 , +.Xr ng_bridge 4 , +.Xr ng_ether 4 , +.Xr ngctl 8 +.Sh HISTORY +The +.Nm +node type was implemented in +.Fx 4.2 . +.Sh AUTHORS +.An Archie Cobbs Aq archie@freebsd.org diff --git a/sys/modules/netgraph/one2many/Makefile b/sys/modules/netgraph/one2many/Makefile new file mode 100644 index 0000000..a49cfc7 --- /dev/null +++ b/sys/modules/netgraph/one2many/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +KMOD= ng_one2many +SRCS= ng_one2many.c +NOMAN= + +.include <bsd.kmod.mk> diff --git a/sys/netgraph/ng_one2many.c b/sys/netgraph/ng_one2many.c new file mode 100644 index 0000000..3189b95 --- /dev/null +++ b/sys/netgraph/ng_one2many.c @@ -0,0 +1,521 @@ + +/* + * ng_one2many.c + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +/* + * ng_one2many(4) netgraph node type + * + * Packets received on the "one" hook are sent out each of the + * "many" hooks in round-robin fashion. Packets received on any + * "many" hook are always delivered to the "one" hook. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/ctype.h> +#include <sys/mbuf.h> +#include <sys/errno.h> + +#include <netgraph/ng_message.h> +#include <netgraph/netgraph.h> +#include <netgraph/ng_parse.h> +#include <netgraph/ng_one2many.h> + +/* Per-link private data */ +struct ng_one2many_link { + hook_p hook; /* netgraph hook */ + struct ng_one2many_link_stats stats; /* link stats */ +}; + +/* Per-node private data */ +struct ng_one2many_private { + struct ng_one2many_config conf; /* node configuration */ + struct ng_one2many_link one; /* "one" hook */ + struct ng_one2many_link many[NG_ONE2MANY_MAX_LINKS]; + u_int16_t nextMany; /* next round-robin */ + u_int16_t numActiveMany; /* # active "many" */ + u_int16_t activeMany[NG_ONE2MANY_MAX_LINKS]; +}; +typedef struct ng_one2many_private *priv_p; + +/* Netgraph node methods */ +static ng_constructor_t ng_one2many_constructor; +static ng_rcvmsg_t ng_one2many_rcvmsg; +static ng_shutdown_t ng_one2many_rmnode; +static ng_newhook_t ng_one2many_newhook; +static ng_rcvdata_t ng_one2many_rcvdata; +static ng_disconnect_t ng_one2many_disconnect; + +/* Other functions */ +static void ng_one2many_update_many(priv_p priv); + +/* Store each hook's link number in the private field */ +#define LINK_NUM(hook) (*(int16_t *)(&(hook)->private)) + +/****************************************************************** + NETGRAPH PARSE TYPES +******************************************************************/ + +/* Parse type for struct ng_one2many_config */ +static const struct ng_parse_fixedarray_info + ng_one2many_enableLinks_array_type_info = { + &ng_parse_uint8_type, + NG_ONE2MANY_MAX_LINKS +}; +static const struct ng_parse_type ng_one2many_enableLinks_array_type = { + &ng_parse_fixedarray_type, + &ng_one2many_enableLinks_array_type_info, +}; +static const struct ng_parse_struct_info ng_one2many_config_type_info + = NG_ONE2MANY_CONFIG_TYPE_INFO(&ng_one2many_enableLinks_array_type); +static const struct ng_parse_type ng_one2many_config_type = { + &ng_parse_struct_type, + &ng_one2many_config_type_info, +}; + +/* Parse type for struct ng_one2many_link_stats */ +static const struct ng_parse_struct_info + ng_one2many_link_stats_type_info = NG_ONE2MANY_LINK_STATS_TYPE_INFO; +static const struct ng_parse_type ng_one2many_link_stats_type = { + &ng_parse_struct_type, + &ng_one2many_link_stats_type_info +}; + +/* List of commands and how to convert arguments to/from ASCII */ +static const struct ng_cmdlist ng_one2many_cmdlist[] = { + { + NGM_ONE2MANY_COOKIE, + NGM_ONE2MANY_SET_CONFIG, + "setconfig", + &ng_one2many_config_type, + NULL + }, + { + NGM_ONE2MANY_COOKIE, + NGM_ONE2MANY_GET_CONFIG, + "getconfig", + NULL, + &ng_one2many_config_type + }, + { + NGM_ONE2MANY_COOKIE, + NGM_ONE2MANY_GET_STATS, + "getstats", + &ng_parse_int32_type, + &ng_one2many_link_stats_type + }, + { + NGM_ONE2MANY_COOKIE, + NGM_ONE2MANY_CLR_STATS, + "clrstats", + &ng_parse_int32_type, + NULL, + }, + { + NGM_ONE2MANY_COOKIE, + NGM_ONE2MANY_GETCLR_STATS, + "getclrstats", + &ng_parse_int32_type, + &ng_one2many_link_stats_type + }, + { 0 } +}; + +/* Node type descriptor */ +static struct ng_type ng_one2many_typestruct = { + NG_VERSION, + NG_ONE2MANY_NODE_TYPE, + NULL, + ng_one2many_constructor, + ng_one2many_rcvmsg, + ng_one2many_rmnode, + ng_one2many_newhook, + NULL, + NULL, + ng_one2many_rcvdata, + ng_one2many_rcvdata, + ng_one2many_disconnect, + ng_one2many_cmdlist, +}; +NETGRAPH_INIT(one2many, &ng_one2many_typestruct); + +/****************************************************************** + NETGRAPH NODE METHODS +******************************************************************/ + +/* + * Node constructor + */ +static int +ng_one2many_constructor(node_p *nodep) +{ + priv_p priv; + int error; + + /* Allocate and initialize private info */ + MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); + if (priv == NULL) + return (ENOMEM); + priv->conf.xmitAlg = NG_ONE2MANY_XMIT_ROUNDROBIN; + priv->conf.failAlg = NG_ONE2MANY_FAIL_MANUAL; + + /* Call superclass constructor */ + if ((error = ng_make_node_common(&ng_one2many_typestruct, nodep))) { + FREE(priv, M_NETGRAPH); + return (error); + } + (*nodep)->private = priv; + + /* Done */ + return (0); +} + +/* + * Method for attaching a new hook + */ +static int +ng_one2many_newhook(node_p node, hook_p hook, const char *name) +{ + const priv_p priv = node->private; + struct ng_one2many_link *link; + int linkNum; + u_long i; + + /* Which hook? */ + if (strncmp(name, NG_ONE2MANY_HOOK_MANY_PREFIX, + strlen(NG_ONE2MANY_HOOK_MANY_PREFIX)) == 0) { + const char *cp; + char *eptr; + + cp = name + strlen(NG_ONE2MANY_HOOK_MANY_PREFIX); + if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) + return (EINVAL); + i = strtoul(cp, &eptr, 10); + if (*eptr != '\0' || i < 0 || i >= NG_ONE2MANY_MAX_LINKS) + return (EINVAL); + linkNum = (int)i; + link = &priv->many[linkNum]; + } else if (strcmp(name, NG_ONE2MANY_HOOK_ONE) == 0) { + linkNum = NG_ONE2MANY_ONE_LINKNUM; + link = &priv->one; + } else + return (EINVAL); + + /* Is hook already connected? (should never happen) */ + if (link->hook != NULL) + return (EISCONN); + + /* Setup private info for this link */ + LINK_NUM(hook) = linkNum; + link->hook = hook; + bzero(&link->stats, sizeof(link->stats)); + if (linkNum != NG_ONE2MANY_ONE_LINKNUM) { + priv->conf.enabledLinks[linkNum] = 1; /* auto-enable link */ + ng_one2many_update_many(priv); + } + + /* Done */ + return (0); +} + +/* + * Receive a control message + */ +static int +ng_one2many_rcvmsg(node_p node, struct ng_mesg *msg, + const char *retaddr, struct ng_mesg **rptr, hook_p lasthook) +{ + const priv_p priv = node->private; + struct ng_mesg *resp = NULL; + int error = 0; + + switch (msg->header.typecookie) { + case NGM_ONE2MANY_COOKIE: + switch (msg->header.cmd) { + case NGM_ONE2MANY_SET_CONFIG: + { + struct ng_one2many_config *conf; + int i; + + /* Check that new configuration is valid */ + if (msg->header.arglen != sizeof(*conf)) { + error = EINVAL; + break; + } + conf = (struct ng_one2many_config *)msg->data; + switch (conf->xmitAlg) { + case NG_ONE2MANY_XMIT_ROUNDROBIN: + break; + default: + error = EINVAL; + break; + } + switch (conf->failAlg) { + case NG_ONE2MANY_FAIL_MANUAL: + break; + default: + error = EINVAL; + break; + } + if (error != 0) + break; + + /* Normalized many link enabled bits */ + for (i = 0; i < NG_ONE2MANY_MAX_LINKS; i++) + conf->enabledLinks[i] = !!conf->enabledLinks[i]; + + /* Copy config and reset */ + bcopy(conf, &priv->conf, sizeof(*conf)); + ng_one2many_update_many(priv); + break; + } + case NGM_ONE2MANY_GET_CONFIG: + { + struct ng_one2many_config *conf; + + NG_MKRESPONSE(resp, msg, sizeof(*conf), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + conf = (struct ng_one2many_config *)resp->data; + bcopy(&priv->conf, conf, sizeof(priv->conf)); + break; + } + case NGM_ONE2MANY_GET_STATS: + case NGM_ONE2MANY_CLR_STATS: + case NGM_ONE2MANY_GETCLR_STATS: + { + struct ng_one2many_link *link; + int linkNum; + + /* Get link */ + if (msg->header.arglen != sizeof(int32_t)) { + error = EINVAL; + break; + } + linkNum = *((int32_t *)msg->data); + if (linkNum == NG_ONE2MANY_ONE_LINKNUM) + link = &priv->one; + else if (linkNum == 0 + && linkNum < NG_ONE2MANY_MAX_LINKS) { + link = &priv->many[linkNum]; + } else { + error = EINVAL; + break; + } + + /* Get/clear stats */ + if (msg->header.cmd != NGM_ONE2MANY_CLR_STATS) { + NG_MKRESPONSE(resp, msg, + sizeof(link->stats), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + bcopy(&link->stats, + resp->data, sizeof(link->stats)); + } + if (msg->header.cmd != NGM_ONE2MANY_GET_STATS) + bzero(&link->stats, sizeof(link->stats)); + break; + } + default: + error = EINVAL; + break; + } + break; + default: + error = EINVAL; + break; + } + + /* Done */ + if (rptr) + *rptr = resp; + else if (resp != NULL) + FREE(resp, M_NETGRAPH); + FREE(msg, M_NETGRAPH); + return (error); +} + +/* + * Receive data on a hook + */ +static int +ng_one2many_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, + struct mbuf **ret_m, meta_p *ret_meta) +{ + const node_p node = hook->node; + const priv_p priv = node->private; + struct ng_one2many_link *src; + struct ng_one2many_link *dst; + int error = 0; + int linkNum; + + /* Get link number */ + linkNum = LINK_NUM(hook); + KASSERT(linkNum == NG_ONE2MANY_ONE_LINKNUM + || (linkNum >= 0 && linkNum < NG_ONE2MANY_MAX_LINKS), + ("%s: linkNum=%d", __FUNCTION__, linkNum)); + + /* Figure out source link */ + src = (linkNum == NG_ONE2MANY_ONE_LINKNUM) ? + &priv->one : &priv->many[linkNum]; + KASSERT(src->hook != NULL, ("%s: no src%d", __FUNCTION__, linkNum)); + + /* Update receive stats */ + src->stats.recvPackets++; + src->stats.recvOctets += m->m_pkthdr.len; + + /* Figure out destination link */ + if (linkNum == NG_ONE2MANY_ONE_LINKNUM) { + if (priv->numActiveMany == 0) { + NG_FREE_DATA(m, meta); + return (ENOTCONN); + } + dst = &priv->many[priv->activeMany[priv->nextMany]]; + priv->nextMany = (priv->nextMany + 1) % priv->numActiveMany; + } else + dst = &priv->one; + + /* Update transmit stats */ + dst->stats.xmitPackets++; + dst->stats.xmitOctets += m->m_pkthdr.len; + + /* Deliver packet */ + NG_SEND_DATA(error, dst->hook, m, meta); + return (error); +} + +/* + * Shutdown node + */ +static int +ng_one2many_rmnode(node_p node) +{ + const priv_p priv = node->private; + + ng_unname(node); + ng_cutlinks(node); + KASSERT(priv->numActiveMany == 0, + ("%s: numActiveMany=%d", __FUNCTION__, priv->numActiveMany)); + FREE(priv, M_NETGRAPH); + node->private = NULL; + ng_unref(node); + return (0); +} + +/* + * Hook disconnection. + */ +static int +ng_one2many_disconnect(hook_p hook) +{ + const priv_p priv = hook->node->private; + int linkNum; + + /* Get link number */ + linkNum = LINK_NUM(hook); + KASSERT(linkNum == NG_ONE2MANY_ONE_LINKNUM + || (linkNum >= 0 && linkNum < NG_ONE2MANY_MAX_LINKS), + ("%s: linkNum=%d", __FUNCTION__, linkNum)); + + /* Nuke the link */ + if (linkNum == NG_ONE2MANY_ONE_LINKNUM) + priv->one.hook = NULL; + else { + priv->many[linkNum].hook = NULL; + priv->conf.enabledLinks[linkNum] = 0; + ng_one2many_update_many(priv); + } + + /* If no hooks left, go away */ + if (hook->node->numhooks == 0) + ng_rmnode(hook->node); + return (0); +} + +/****************************************************************** + OTHER FUNCTIONS +******************************************************************/ + +/* + * Update internal state after the addition or removal of a "many" link + */ +static void +ng_one2many_update_many(priv_p priv) +{ + int linkNum; + + /* Update list of which "many" links are up */ + priv->numActiveMany = 0; + for (linkNum = 0; linkNum < NG_ONE2MANY_MAX_LINKS; linkNum++) { + switch (priv->conf.failAlg) { + case NG_ONE2MANY_FAIL_MANUAL: + if (priv->many[linkNum].hook != NULL + && priv->conf.enabledLinks[linkNum]) { + priv->activeMany[priv->numActiveMany] = linkNum; + priv->numActiveMany++; + } + break; +#ifdef INVARIANTS + default: + panic("%s: invalid failAlg", __FUNCTION__); +#endif + } + } + + /* Update transmit algorithm state */ + switch (priv->conf.xmitAlg) { + case NG_ONE2MANY_XMIT_ROUNDROBIN: + if (priv->numActiveMany > 0) + priv->nextMany %= priv->numActiveMany; + break; +#ifdef INVARIANTS + default: + panic("%s: invalid xmitAlg", __FUNCTION__); +#endif + } +} + + diff --git a/sys/netgraph/ng_one2many.h b/sys/netgraph/ng_one2many.h new file mode 100644 index 0000000..182a7d1 --- /dev/null +++ b/sys/netgraph/ng_one2many.h @@ -0,0 +1,112 @@ + +/* + * ng_one2many.h + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +#ifndef _NETGRAPH_NG_ONE2MANY_H_ +#define _NETGRAPH_NG_ONE2MANY_H_ + +/* Node type name and magic cookie */ +#define NG_ONE2MANY_NODE_TYPE "one2many" +#define NGM_ONE2MANY_COOKIE 971111383 + +/* Hook names */ +#define NG_ONE2MANY_HOOK_ONE "one" +#define NG_ONE2MANY_HOOK_MANY_PREFIX "many" /* append decimal integer */ +#define NG_ONE2MANY_HOOK_MANY_FMT "many%d" /* for use with printf(3) */ + +/* Maximum number of supported "many" links */ +#define NG_ONE2MANY_MAX_LINKS 64 + +/* Link number used to indicate the "one" hook */ +#define NG_ONE2MANY_ONE_LINKNUM (-1) + +/* Algorithms for outgoing packet distribution (XXX only one so far) */ +#define NG_ONE2MANY_XMIT_ROUNDROBIN 1 /* round-robin delivery */ + +/* Algorithms for detecting link failure (XXX only one so far) */ +#define NG_ONE2MANY_FAIL_MANUAL 1 /* use enabledLinks[] array */ + +/* Node configuration structure */ +struct ng_one2many_config { + u_int32_t xmitAlg; /* how to distribute packets */ + u_int32_t failAlg; /* how to detect link failure */ + u_char enabledLinks[NG_ONE2MANY_MAX_LINKS]; +}; + +/* Keep this in sync with the above structure definition */ +#define NG_ONE2MANY_CONFIG_TYPE_INFO(atype) { \ + { \ + { "xmitAlg", &ng_parse_uint64_type }, \ + { "failAlg", &ng_parse_uint64_type }, \ + { "enabledLinks", (atype) }, \ + { NULL } \ + } \ +} + +/* Statistics structure (one for each link) */ +struct ng_one2many_link_stats { + u_int64_t recvOctets; /* total octets rec'd on link */ + u_int64_t recvPackets; /* total pkts rec'd on link */ + u_int64_t xmitOctets; /* total octets xmit'd on link */ + u_int64_t xmitPackets; /* total pkts xmit'd on link */ +}; + +/* Keep this in sync with the above structure definition */ +#define NG_ONE2MANY_LINK_STATS_TYPE_INFO { \ + { \ + { "recvOctets", &ng_parse_uint64_type }, \ + { "recvPackets", &ng_parse_uint64_type }, \ + { "xmitOctets", &ng_parse_uint64_type }, \ + { "xmitPackets", &ng_parse_uint64_type }, \ + { NULL } \ + } \ +} + +/* Netgraph control messages */ +enum { + NGM_ONE2MANY_SET_CONFIG, /* set configuration */ + NGM_ONE2MANY_GET_CONFIG, /* get configuration */ + NGM_ONE2MANY_GET_STATS, /* get link stats */ + NGM_ONE2MANY_CLR_STATS, /* clear link stats */ + NGM_ONE2MANY_GETCLR_STATS, /* atomically get & clear link stats */ +}; + +#endif /* _NETGRAPH_NG_ONE2MANY_H_ */ + |