diff options
author | archie <archie@FreeBSD.org> | 2000-11-16 05:58:33 +0000 |
---|---|---|
committer | archie <archie@FreeBSD.org> | 2000-11-16 05:58:33 +0000 |
commit | 84d919eea0b0b2ce089897bad0f22e7f3ba17e2e (patch) | |
tree | a87b704b673b4e4354d5ef95d13b60d55f03c200 /sys | |
parent | 9c0e982aa6e4c552253d85bc311eb222ab3c375d (diff) | |
download | FreeBSD-src-84d919eea0b0b2ce089897bad0f22e7f3ba17e2e.zip FreeBSD-src-84d919eea0b0b2ce089897bad0f22e7f3ba17e2e.tar.gz |
New netgraph node type ng_one2many(4).
Diffstat (limited to 'sys')
-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 |
3 files changed, 640 insertions, 0 deletions
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_ */ + |