svn commit: r194012 - in head: . sys/netgraph sys/sys

Marko Zec zec at freebsd.org
Thu Jun 11 16:56:42 UTC 2009


On Thursday 11 June 2009 18:50:49 Marko Zec wrote:
> Author: zec
> Date: Thu Jun 11 16:50:49 2009
> New Revision: 194012
> URL: http://svn.freebsd.org/changeset/base/194012
>
> Log:
>   Introduce a mechanism for detecting calls from outbound path of the
>   network stack when reentering the inbound path from netgraph, and
>   force queueing of mbufs at the outbound netgraph node.
                                   ^^^^^^^^

s/outbound/inbound/ -> the framework prevents direct call dispatching at the 
egress netgraph node, i.e. the one reentering the network stack from below, 
not on the output path.

Sorry for the typo...

Marko

>
>   The mechanism relies on two components.  First, in netgraph nodes
>   where outbound path of the network stack calls into netgraph, the
>   current thread has to be appropriately marked using the new
>   NG_OUTBOUND_THREAD_REF() macro before proceeding to call further
>   into the netgraph topology, and unmarked using the
>   NG_OUTBOUND_THREAD_UNREF() macro before returning to the caller.
>   Second, netgraph nodes which can potentially reenter the network
>   stack in the inbound path have to mark their inbound hooks using
>   NG_HOOK_SET_TO_INBOUND() macro.  The netgraph framework will then
>   detect when there is a danger of a call graph looping back from
>   outbound to inbound path via netgraph, and defer handing off the
>   mbufs to the "inbound" node to a worker thread with a clean stack.
>
>   In this first pass only the most obvious netgraph nodes have been
>   updated to ensure no outbound to inbound calls can occur.  Nodes
>   such as ng_ipfw, ng_gif etc. should be further examined whether a
>   potential for outbound to inbound call looping exists.
>
>   This commit changes the layout of struct thread, but due to
>   __FreeBSD_version number shortage a version bump has been omitted
>   at this time, nevertheless kernel and modules have to be rebuilt.
>
>   Reviewed by:	julian, rwatson, bz
>   Approved by:	julian (mentor)
>
> Modified:
>   head/UPDATING
>   head/sys/netgraph/netgraph.h
>   head/sys/netgraph/ng_base.c
>   head/sys/netgraph/ng_eiface.c
>   head/sys/netgraph/ng_ether.c
>   head/sys/netgraph/ng_iface.c
>   head/sys/netgraph/ng_ip_input.c
>   head/sys/sys/proc.h
>
> Modified: head/UPDATING
> ===========================================================================
>=== --- head/UPDATING	Thu Jun 11 16:48:59 2009	(r194011)
> +++ head/UPDATING	Thu Jun 11 16:50:49 2009	(r194012)
> @@ -22,6 +22,10 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 8.
>  	to maximize performance.  (To disable malloc debugging, run
>  	ln -s aj /etc/malloc.conf.)
>
> +20090611:
> +	The layout of struct thread has changed.  Kernel and modules
> +	need to be rebuilt.
> +
>  20090608:
>  	The layout of structs ifnet, domain, protosw and vnet_net has
>  	changed.  Kernel modules need to be rebuilt.
>
> Modified: head/sys/netgraph/netgraph.h
> ===========================================================================
>=== --- head/sys/netgraph/netgraph.h	Thu Jun 11 16:48:59 2009	(r194011) +++
> head/sys/netgraph/netgraph.h	Thu Jun 11 16:50:49 2009	(r194012) @@ -130,6
> +130,7 @@ struct ng_hook {
>  #define HK_FORCE_WRITER		0x0004	/* Incoming data queued as a writer */
>  #define HK_DEAD			0x0008	/* This is the dead hook.. don't free */
>  #define HK_HI_STACK		0x0010	/* Hook has hi stack usage */
> +#define HK_TO_INBOUND		0x0020	/* Hook on ntw. stack inbound path. */
>
>  /*
>   * Public Methods for hook
> @@ -150,6 +151,8 @@ void ng_unref_hook(hook_p hook); /* don'
>  #define _NG_HOOK_FORCE_WRITER(hook)				\
>  		do { hook->hk_flags |= HK_FORCE_WRITER; } while (0)
>  #define _NG_HOOK_FORCE_QUEUE(hook) do { hook->hk_flags |= HK_QUEUE; }
> while (0) +#define _NG_HOOK_SET_TO_INBOUND(hook)				\
> +		do { hook->hk_flags |= HK_TO_INBOUND; } while (0)
>  #define _NG_HOOK_HI_STACK(hook) do { hook->hk_flags |= HK_HI_STACK; }
> while (0)
>
>  /* Some shortcuts */
> @@ -176,8 +179,11 @@ static __inline int	_ng_hook_is_valid(ho
>  static __inline node_p	_ng_hook_node(hook_p hook, char * file, int line);
>  static __inline hook_p	_ng_hook_peer(hook_p hook, char * file, int line);
>  static __inline void	_ng_hook_force_writer(hook_p hook, char * file,
> -					int line);
> -static __inline void	_ng_hook_force_queue(hook_p hook, char * file, int
> line); +				int line);
> +static __inline void	_ng_hook_force_queue(hook_p hook, char * file,
> +				int line);
> +static __inline void	_ng_hook_set_to_inbound(hook_p hook, char * file,
> +				int line);
>
>  static __inline void
>  _chkhook(hook_p hook, char *file, int line)
> @@ -282,6 +288,13 @@ _ng_hook_force_queue(hook_p hook, char *
>  }
>
>  static __inline void
> +_ng_hook_set_to_inbound(hook_p hook, char * file, int line)
> +{
> +	_chkhook(hook, file, line);
> +	_NG_HOOK_SET_TO_INBOUND(hook);
> +}
> +
> +static __inline void
>  _ng_hook_hi_stack(hook_p hook, char * file, int line)
>  {
>  	_chkhook(hook, file, line);
> @@ -302,6 +315,7 @@ _ng_hook_hi_stack(hook_p hook, char * fi
>  #define NG_HOOK_PEER(hook)		_ng_hook_peer(hook, _NN_)
>  #define NG_HOOK_FORCE_WRITER(hook)	_ng_hook_force_writer(hook, _NN_)
>  #define NG_HOOK_FORCE_QUEUE(hook)	_ng_hook_force_queue(hook, _NN_)
> +#define NG_HOOK_SET_TO_INBOUND(hook)	_ng_hook_set_to_inbound(hook, _NN_)
>  #define NG_HOOK_HI_STACK(hook)		_ng_hook_hi_stack(hook, _NN_)
>
>  #else	/* NETGRAPH_DEBUG */
> /*----------------------------------------------*/ @@ -319,6 +333,7 @@
> _ng_hook_hi_stack(hook_p hook, char * fi
>  #define NG_HOOK_PEER(hook)		_NG_HOOK_PEER(hook)
>  #define NG_HOOK_FORCE_WRITER(hook)	_NG_HOOK_FORCE_WRITER(hook)
>  #define NG_HOOK_FORCE_QUEUE(hook)	_NG_HOOK_FORCE_QUEUE(hook)
> +#define NG_HOOK_SET_TO_INBOUND(hook)	_NG_HOOK_SET_TO_INBOUND(hook)
>  #define NG_HOOK_HI_STACK(hook)		_NG_HOOK_HI_STACK(hook)
>
>  #endif	/* NETGRAPH_DEBUG */
> /*----------------------------------------------*/ @@ -1189,6 +1204,20 @@
> typedef void *meta_p;
>  #define	NG_ID_HASH_SIZE 128 /* most systems wont need even this many */
>  #define	NG_NAME_HASH_SIZE 128 /* most systems wont need even this many */
>
> +/*
> + * Mark the current thread when called from the outbound path of the
> + * network stack, in order to enforce queuing on ng nodes calling into
> + * the inbound network stack path.
> + */
> +#define NG_OUTBOUND_THREAD_REF()					\
> +	curthread->td_ng_outbound++
> +#define NG_OUTBOUND_THREAD_UNREF()					\
> +	do {								\
> +		curthread->td_ng_outbound--;				\
> +		KASSERT(curthread->td_ng_outbound >= 0,			\
> +		    ("%s: negative td_ng_outbound", __func__));		\
> +	} while (0)
> +
>  /* Virtualization macros */
>  #define	INIT_VNET_NETGRAPH(vnet) \
>  	INIT_FROM_VNET(vnet, VNET_MOD_NETGRAPH, \
>
> Modified: head/sys/netgraph/ng_base.c
> ===========================================================================
>=== --- head/sys/netgraph/ng_base.c	Thu Jun 11 16:48:59 2009	(r194011) +++
> head/sys/netgraph/ng_base.c	Thu Jun 11 16:50:49 2009	(r194012) @@ -2213,11
> +2213,15 @@ ng_snd_item(item_p item, int flags)
>  	}
>
>  	/*
> -	 * If sender or receiver requests queued delivery or stack usage
> +	 * If sender or receiver requests queued delivery, or call graph
> +	 * loops back from outbound to inbound path, or stack usage
>  	 * level is dangerous - enqueue message.
>  	 */
>  	if ((flags & NG_QUEUE) || (hook && (hook->hk_flags & HK_QUEUE))) {
>  		queue = 1;
> +	} else if (hook && (hook->hk_flags & HK_TO_INBOUND) &&
> +	    curthread->td_ng_outbound) {
> +		queue = 1;
>  	} else {
>  		queue = 0;
>  #ifdef GET_STACK_USAGE
>
> Modified: head/sys/netgraph/ng_eiface.c
> ===========================================================================
>=== --- head/sys/netgraph/ng_eiface.c	Thu Jun 11 16:48:59 2009	(r194011) +++
> head/sys/netgraph/ng_eiface.c	Thu Jun 11 16:50:49 2009	(r194012) @@ -261,7
> +261,9 @@ ng_eiface_start2(node_p node, hook_p hoo
>  		 * Send packet; if hook is not connected, mbuf will get
>  		 * freed.
>  		 */
> +		NG_OUTBOUND_THREAD_REF();
>  		NG_SEND_DATA_ONLY(error, priv->ether, m);
> +		NG_OUTBOUND_THREAD_UNREF();
>
>  		/* Update stats */
>  		if (error == 0)
> @@ -414,6 +416,7 @@ ng_eiface_newhook(node_p node, hook_p ho
>  		return (EISCONN);
>  	priv->ether = hook;
>  	NG_HOOK_SET_PRIVATE(hook, &priv->ether);
> +	NG_HOOK_SET_TO_INBOUND(hook);
>
>  	if_link_state_change(ifp, LINK_STATE_UP);
>
>
> Modified: head/sys/netgraph/ng_ether.c
> ===========================================================================
>=== --- head/sys/netgraph/ng_ether.c	Thu Jun 11 16:48:59 2009	(r194011) +++
> head/sys/netgraph/ng_ether.c	Thu Jun 11 16:50:49 2009	(r194012) @@ -282,7
> +282,9 @@ ng_ether_output(struct ifnet *ifp, struc
>  		return (0);
>
>  	/* Send it out "upper" hook */
> +	NG_OUTBOUND_THREAD_REF();
>  	NG_SEND_DATA_ONLY(error, priv->upper, *mp);
> +	NG_OUTBOUND_THREAD_UNREF();
>  	return (error);
>  }
>
> @@ -416,6 +418,7 @@ ng_ether_newhook(node_p node, hook_p hoo
>  	if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) {
>  		hookptr = &priv->upper;
>  		NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_upper);
> +		NG_HOOK_SET_TO_INBOUND(hook);
>  	} else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) {
>  		hookptr = &priv->lower;
>  		NG_HOOK_SET_RCVDATA(hook, ng_ether_rcv_lower);
>
> Modified: head/sys/netgraph/ng_iface.c
> ===========================================================================
>=== --- head/sys/netgraph/ng_iface.c	Thu Jun 11 16:48:59 2009	(r194011) +++
> head/sys/netgraph/ng_iface.c	Thu Jun 11 16:50:49 2009	(r194012) @@ -482,9
> +482,10 @@ ng_iface_send(struct ifnet *ifp, struct
>  	/* Copy length before the mbuf gets invalidated. */
>  	len = m->m_pkthdr.len;
>
> -	/* Send packet. If hook is not connected,
> -	   mbuf will get freed. */
> +	/* Send packet. If hook is not connected, mbuf will get freed. */
> +	NG_OUTBOUND_THREAD_REF();
>  	NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m);
> +	NG_OUTBOUND_THREAD_UNREF();
>
>  	/* Update stats. */
>  	if (error == 0) {
> @@ -610,6 +611,7 @@ ng_iface_newhook(node_p node, hook_p hoo
>  		return (EISCONN);
>  	*hookptr = hook;
>  	NG_HOOK_HI_STACK(hook);
> +	NG_HOOK_SET_TO_INBOUND(hook);
>  	return (0);
>  }
>
>
> Modified: head/sys/netgraph/ng_ip_input.c
> ===========================================================================
>=== --- head/sys/netgraph/ng_ip_input.c	Thu Jun 11 16:48:59 2009	(r194011)
> +++ head/sys/netgraph/ng_ip_input.c	Thu Jun 11 16:50:49 2009	(r194012) @@
> -77,6 +77,7 @@
>  #include <sys/malloc.h>
>  #include <sys/mbuf.h>
>  #include <sys/socket.h>
> +#include <sys/proc.h>
>  #include <net/if.h>
>  #include <net/if_types.h>
>  #include <net/if_var.h>
> @@ -120,7 +121,10 @@ ngipi_rcvdata(hook_p hook, item_p item)
>
>  	NGI_GET_M(item, m);
>  	NG_FREE_ITEM(item);
> -	netisr_dispatch(NETISR_IP, m);
> +	if (curthread->td_ng_outbound)
> +		netisr_queue(NETISR_IP, m);
> +	else
> +		netisr_dispatch(NETISR_IP, m);
>  	return 0;
>  }
>
>
> Modified: head/sys/sys/proc.h
> ===========================================================================
>=== --- head/sys/sys/proc.h	Thu Jun 11 16:48:59 2009	(r194011)
> +++ head/sys/sys/proc.h	Thu Jun 11 16:50:49 2009	(r194012)
> @@ -235,6 +235,7 @@ struct thread {
>  	char		td_name[MAXCOMLEN + 1];	/* (*) Thread name. */
>  	struct file	*td_fpop;	/* (k) file referencing cdev under op */
>  	int		td_dbgflags;	/* (c) Userland debugger flags */
> +	int		td_ng_outbound;	/* (k) Thread entered ng from above. */
>  	struct osd	td_osd;		/* (k) Object specific data. */
>  #define	td_endzero td_base_pri


More information about the svn-src-all mailing list