Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 May 2006 15:51:46 +0400
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        Yann Berthier <yb@bashibuzuk.net>
Cc:        net@FreeBSD.org
Subject:   Re: (fwd) Re: netgraph on disc(4)
Message-ID:  <20060529115146.GQ27819@cell.sick.ru>
In-Reply-To: <20060528194319.GL1424@bashibuzuk.net>
References:  <20060528194319.GL1424@bashibuzuk.net>

next in thread | previous in thread | raw e-mail | index | archive | help

--YrQNB5Deg1WGKZi3
Content-Type: text/plain; charset=koi8-r
Content-Disposition: inline

On Sun, May 28, 2006 at 09:43:19PM +0200, Yann Berthier wrote:
Y> 
Y>    Hello Gleb,
Y> 
Y>    err, sorry for the forward if you saw the thread already but, have
Y>    you any input on this ? that's not critical but still, i see value in
Y>    being able to use ng_netflow on traffic flowing on dummy interfaces
Y>    (lo, disc, ...)

I've have written some code to wrap any interface some time ago. Here
it is attached. Sorry, I didn't ever used it and not sure it is compilable
on recent FreeBSD versions.

Y>    best regards,
Y> 
Y>       - yann
Y> 
Y> ----- Forwarded message from Julian Elischer <julian@elischer.org> -----
Y> 
Y> From: Julian Elischer <julian@elischer.org>
Y> Subject: Re: netgraph on disc(4)
Y> To: Yann Berthier <yb@bashibuzuk.net>
Y> CC: freebsd-net@freebsd.org
Y> X-Original-To: yb@cc.6f2.net
Y> Delivered-To: yb@cc.6f2.net
Y> Date: Thu, 25 May 2006 11:46:18 -0700
Y> User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.13) Gecko/20060414
Y> X-Accept-Language: en-us, en
Y> In-Reply-To: <20060525152228.GL1424@bashibuzuk.net>
Y> 
Y> Yann Berthier wrote:
Y> 
Y> I think that Gleb had some changes that allowed netgraph to attach to 
Y> ANY interface.
Y> 
Y> Gleb?
Y> 
Y> >  Hello,
Y> >
Y> >  I wanted to use ng_netflow on a disc interface, but it seems that no
Y> >  node is created for loopback and the like . Indeed, I found an old
Y> >  post from gnn@ dating back from march 2000 on this subject, along
Y> >  with the PR kern/17631. Is somebody reconsidering this idea by any
Y> >  chance ?
Y> >
Y> >  thnaks,
Y> >
Y> >     - yann
Y> >_______________________________________________
Y> >freebsd-net@freebsd.org mailing list
Y> >http://lists.freebsd.org/mailman/listinfo/freebsd-net
Y> >To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"
Y> > 
Y> >
Y> 
Y> ----- End forwarded message -----
Y> 
Y> -- 
Y> http://flowog.6f2.net/ - A NetFlow collecting house

-- 
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE

--YrQNB5Deg1WGKZi3
Content-Type: text/plain; charset=koi8-r
Content-Disposition: attachment; filename="ng_ifwrap.c"

/*-
 * Copyright (c) 2004 Gleb Smirnoff
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON 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 ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#if 0
#define DFUNC(msg) printf("ifwrap: %s: %s\n", __func__, msg);
#define DLINE(msg) printf("ifwrap: -%d-: %s", __LINE__, msg );
#else
#define DFUNC(msg)
#define DLINE(msg)
#endif

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/errno.h>
#include <sys/socket.h>

#include <net/if.h>
#include <net/if_var.h>
#include <net/route.h>

#include <netgraph/ng_message.h>
#include <netgraph/ng_parse.h>
#include <netgraph/netgraph.h>

#include <netgraph/ng_ifwrap.h>

#define ERROUT(x)	do { error = (x); goto done; } while (0)

/* Netgraph methods */
static ng_constructor_t	ng_ifwrap_constructor;
static ng_rcvmsg_t	ng_ifwrap_rcvmsg;
static ng_shutdown_t	ng_ifwrap_shutdown;
static ng_newhook_t	ng_ifwrap_newhook;
static ng_rcvdata_t	ng_ifwrap_rcvdata;
static ng_disconnect_t	ng_ifwrap_disconnect;

/* New routines for interface */
static int	ng_ifwrap_output(struct ifnet *, struct mbuf *,
			struct sockaddr *, struct rtentry *);
static void	ng_ifwrap_input(struct ifnet *, struct mbuf *);

/*
 * Our internal tag to store next hop and rtentry. It is declared
 * here, since noone except of this node should take care of it.
 */
struct ifwrap_tag {
	struct m_tag    mt;
	struct rtentry	*rt;
	struct sockaddr sa;
};
#define	TAGSIZ	(sizeof(struct ifwrap_tag) - sizeof(struct m_tag))

/* Free method for our tags */
static void ifwrap_tag_free(struct m_tag *);

/* List of commands and how to convert arguments to/from ASCII */
static const struct ng_cmdlist ng_ifwrap_cmdlist[] = {
	{
	  NGM_IFWRAP_COOKIE,
	  NGM_IFWRAP_ATTACH,
	  "attach",
	  &ng_parse_string_type,
	  NULL
	},
	{ 0 }
};

/* Netgraph node type descriptor */
static struct ng_type ng_ifwrap_typestruct = {
	.version =	NG_ABI_VERSION,
	.name =		NG_IFWRAP_NODE_TYPE,
	.constructor =	ng_ifwrap_constructor,
	.rcvmsg =	ng_ifwrap_rcvmsg,
	.shutdown =	ng_ifwrap_shutdown,
	.newhook =	ng_ifwrap_newhook,
	.rcvdata =	ng_ifwrap_rcvdata,
	.disconnect =	ng_ifwrap_disconnect,
	.cmdlist =	ng_ifwrap_cmdlist,
};
NETGRAPH_INIT(ifwrap, &ng_ifwrap_typestruct);

/* Information we store for each node */
struct ng_ifwrap_priv {
	struct ifnet	*ifp;		/* pointer to our ifnet */
	node_p		node;		/* back pointer to node */
	hook_p		upper;		/* hook for input */
	hook_p		lower;		/* hook for output */

	/* Pointers to original routines */
        int	(*if_output) (struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *);
        void 	(*if_input)  (struct ifnet *, struct mbuf *);
};
typedef struct ng_ifwrap_priv *priv_p;

/* This is where we store pointer from iface to node private date. This
 * makes us incompatible with ng_fec(4).
 */
#define IFP2NG(ifp)	(priv_p )(ifp->if_afdata[AF_NETGRAPH])
#define IFP2NG_SET(ifp, val)	ifp->if_afdata[AF_NETGRAPH] = (val);

/******************************************************************************
 *  Netgraph methods
 ******************************************************************************/

static int
ng_ifwrap_constructor(node_p node)
{
	priv_p priv;

	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
	if (priv == NULL)
		return (ENOMEM);

	NG_NODE_SET_PRIVATE(node, priv);
	priv->node = node;

	return (0);
}

/*
 * Hooks are almost the same as ng_ether's, and so is this callback.
 */
static int
ng_ifwrap_newhook(node_p node, hook_p hook, const char *name)
{
	const priv_p priv = NG_NODE_PRIVATE(node);
	hook_p *hookptr;

	if (strcmp(name, NG_IFWRAP_HOOK_UPPER) == 0)
		hookptr = &priv->upper;
	else if (strcmp(name, NG_IFWRAP_HOOK_LOWER) == 0)
		hookptr = &priv->lower;
	else
		return (EINVAL);

	/* Check if already connected */
        if (*hookptr != NULL)
		return (EISCONN);

	*hookptr = hook;

	return (0);
}

static int
ng_ifwrap_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
	const priv_p priv = NG_NODE_PRIVATE(node);
	struct ng_mesg *msg, *resp = NULL;
	int error = 0;

	NGI_GET_MSG(item, msg);

	switch (msg->header.typecookie) {
	case NGM_IFWRAP_COOKIE: 
		switch (msg->header.cmd) {
		case NGM_IFWRAP_ATTACH:

			/* Check if we are already initialized */
			if (priv->ifp != NULL)
				ERROUT(EISCONN);

			if (msg->header.arglen == 0)
				ERROUT(EINVAL);

			if ((priv->ifp = ifunit((char *)msg->data)) == NULL)
				ERROUT(ENOENT);

			/*
			 * Not all interfaces have both input and output
			 * method. Those are not supported.
			 */
			if (priv->ifp->if_input == NULL ||
			    priv->ifp->if_output == NULL)
				ERROUT(ENOTSUP);

			/*
			 * XXX: There is no mutex to lock struct ifnet yet,
			 * so we will hold afdata_mtx for the whole surgery
			 * procedure. This will not stop races, since other
			 * struct-ifnet-surgeons does not do it same way.
			 */
			IF_AFDATA_LOCK(priv->ifp);

			/* Check if someone already have grabbed AF_NETGRAPH */
			if(IFP2NG(priv->ifp) != NULL) {
				IF_AFDATA_UNLOCK(priv->ifp);
				priv->ifp = NULL;
				ERROUT(EISCONN);
			}

			IFP2NG_SET(priv->ifp, priv);
			priv->if_input = priv->ifp->if_input;
			priv->ifp->if_input = ng_ifwrap_input;
			priv->if_output = priv->ifp->if_output;
			priv->ifp->if_output = ng_ifwrap_output;

			IF_AFDATA_UNLOCK(priv->ifp);

			break;
		default:
			error = EINVAL;
			break;
		}
		break;
	default:
		error = EINVAL;
		break;
	}

done:
	NG_RESPOND_MSG(error, node, item, resp);
	NG_FREE_MSG(msg);

	return(error);
}

static int
ng_ifwrap_rcvdata(hook_p hook, item_p item )
{
	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
	struct mbuf *m;
	int error = 0;

	NGI_GET_M(item, m);
	NG_FREE_ITEM(item);

	/* Check if we have attached interface */
	if (priv->ifp == NULL) {
		NG_FREE_M(m);
		return (ENOTCONN);
	}

	if (hook == priv->upper) {
		(priv->if_input)(priv->ifp, m);
		return (0);
	} else if (hook == priv->lower) {
		struct ifwrap_tag *tag;
		struct sockaddr	*dst;

		tag = (struct ifwrap_tag *)m_tag_locate(m, NGM_IFWRAP_COOKIE,
		    NG_IFWRAP_TAG_OUTPUT, NULL);
		if (tag == NULL) {
			DFUNC("no tag in input packet");
			NG_FREE_M(m);
			return (EDESTADDRREQ);
		}

		dst = &tag->sa;
		
		error =  (priv->if_output)(priv->ifp, m, dst, tag->rt);

		return (error);
	} else
		panic("ng_ifwrap: unknown hook");

	/* not reach */
	return (0);
}

static int
ng_ifwrap_shutdown(node_p node)
{
	const priv_p priv = NG_NODE_PRIVATE(node);

	if (priv->ifp != NULL) {
		IF_AFDATA_LOCK(priv->ifp);

		IFP2NG_SET(priv->ifp, NULL);

		/* Restore old methods */
		priv->ifp->if_input = priv->if_input;
		priv->ifp->if_output = priv->if_output;

		IF_AFDATA_UNLOCK(priv->ifp);
	}

	NG_NODE_UNREF(node);
	FREE(priv, M_NETGRAPH);

	return (0);
}

static int
ng_ifwrap_disconnect(hook_p hook)
{
	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));

	if (hook == priv->lower)
		priv->lower = NULL;

	if (hook == priv->upper)
		priv->upper = NULL;

	return (0);
}

static int
ng_ifwrap_output(struct ifnet *ifp, struct mbuf *m,
	struct sockaddr *dst, struct rtentry *rt)
{
	const priv_p priv = IFP2NG(ifp);
	struct ifwrap_tag *tag;
	int error = 0;

	DFUNC("in");
	if (priv->upper == NULL)
		return (priv->if_output)(ifp, m, dst, rt);

	/* Save rt and dst in mbuf tag */
	if ((tag = (struct ifwrap_tag *)m_tag_alloc(NGM_IFWRAP_COOKIE,
	    NG_IFWRAP_TAG_OUTPUT, TAGSIZ, M_DONTWAIT)) == NULL) {
		m_freem(m);
		return (ENOMEM);
	}
	tag->mt.m_tag_free = &ifwrap_tag_free;
	bcopy(dst, &tag->sa, dst->sa_len);

	/* do not allow ip_output() to free our rt */
	if (rt != NULL) {
		RT_LOCK(rt);
		RT_ADDREF(rt);
		RT_UNLOCK(rt);

		tag->rt = rt;
	} else
		tag->rt = NULL;

	m_tag_prepend(m, &tag->mt);

	NG_SEND_DATA_ONLY(error, priv->upper, m);

	return (error);
}

static void
ng_ifwrap_input(struct ifnet *ifp, struct mbuf *m)
{
	const priv_p priv = IFP2NG(ifp);
	int error;

	DFUNC("in");
	if (priv->lower == NULL)
		return (priv->if_input)(ifp, m);

	NG_SEND_DATA_ONLY(error, priv->lower, m);

	return;
}

/******************************************************************************
 *  Helper functions
 ******************************************************************************/

static void
ifwrap_tag_free(struct m_tag *mt)
{
	struct ifwrap_tag *tag = (struct ifwrap_tag *)mt;

	DFUNC("in");
	if (tag->rt != NULL)
		RTFREE(tag->rt);

	m_tag_free_default(mt);
}

--YrQNB5Deg1WGKZi3
Content-Type: text/plain; charset=koi8-r
Content-Disposition: attachment; filename="ng_ifwrap.h"

/*-
 * Copyright (c) 2004 Gleb Smirnoff
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHIFWRAP IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _NETGRAPH_NG_IFWRAP_H_
#define _NETGRAPH_NG_IFWRAP_H_

#define NG_IFWRAP_NODE_TYPE	"ifwrap"
#define NGM_IFWRAP_COOKIE	1094849975

/* Hook names, just like in ng_ether */
#define NG_IFWRAP_HOOK_LOWER     "lower"	/* -> input */
#define NG_IFWRAP_HOOK_UPPER     "upper"	/* -> output */

/* Tags */
enum {
	NG_IFWRAP_TAG_OUTPUT,	/* stores parameters of if_output() */
};

/* Netgraph commands */
enum {
	NGM_IFWRAP_ATTACH,	/* attach to interface */
};

#endif /* _NETGRAPH_NG_IFWRAP_H_ */

--YrQNB5Deg1WGKZi3--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060529115146.GQ27819>