Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH RFC 2/2] ipv6: Add support for IPsec virtual tunnel interfaces
From: Dan Williams @ 2013-08-26 16:37 UTC (permalink / raw)
  To: Steffen Klassert; +Cc: netdev
In-Reply-To: <20130819062730.GP26773@secunet.com>

On Mon, 2013-08-19 at 08:27 +0200, Steffen Klassert wrote:
> This patch adds IPv6  support for IPsec virtual tunnel interfaces
> (vti). IPsec virtual tunnel interfaces provide a routable interface
> for IPsec tunnel endpoints.

Are new ioctls for this kind of thing kosher?  Or should it be using
netlink instead?

Dan

> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
> ---
>  net/ipv6/Kconfig   |   11 +
>  net/ipv6/Makefile  |    1 +
>  net/ipv6/ip6_vti.c | 1092 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1104 insertions(+)
>  create mode 100644 net/ipv6/ip6_vti.c
> 
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index 11b13ea..e1a8d90 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -153,6 +153,17 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
>  	---help---
>  	  Support for MIPv6 route optimization mode.
>  
> +config IPV6_VTI
> +tristate "Virtual (secure) IPv6: tunneling"
> +	select IPV6_TUNNEL
> +	depends on INET6_XFRM_MODE_TUNNEL
> +	---help---
> +	Tunneling means encapsulating data of one protocol type within
> +	another protocol and sending it over a channel that understands the
> +	encapsulating protocol. This can be used with xfrm mode tunnel to give
> +	the notion of a secure tunnel for IPSEC and then use routing protocol
> +	on top.
> +
>  config IPV6_SIT
>  	tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)"
>  	select INET_TUNNEL
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index 470a9c0..17bb830 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
>  obj-$(CONFIG_IPV6_MIP6) += mip6.o
>  obj-$(CONFIG_NETFILTER)	+= netfilter/
>  
> +obj-$(CONFIG_IPV6_VTI) += ip6_vti.o
>  obj-$(CONFIG_IPV6_SIT) += sit.o
>  obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
>  obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
> diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
> new file mode 100644
> index 0000000..fb0b6b0
> --- /dev/null
> +++ b/net/ipv6/ip6_vti.c
> @@ -0,0 +1,1092 @@
> +/*
> + *	IPv6 virtual tunneling interface
> + *
> + *	Copyright (C) 2013 secunet Security Networks AG
> + *
> + *	Author:
> + *	Steffen Klassert <steffen.klassert@secunet.com>
> + *
> + *	Based on:
> + *	net/ipv6/ip6_tunnel.c
> + *
> + *	This program is free software; you can redistribute it and/or
> + *	modify it under the terms of the GNU General Public License
> + *	as published by the Free Software Foundation; either version
> + *	2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/capability.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/sockios.h>
> +#include <linux/icmp.h>
> +#include <linux/if.h>
> +#include <linux/in.h>
> +#include <linux/ip.h>
> +#include <linux/if_tunnel.h>
> +#include <linux/net.h>
> +#include <linux/in6.h>
> +#include <linux/netdevice.h>
> +#include <linux/if_arp.h>
> +#include <linux/icmpv6.h>
> +#include <linux/init.h>
> +#include <linux/route.h>
> +#include <linux/rtnetlink.h>
> +#include <linux/netfilter_ipv6.h>
> +#include <linux/slab.h>
> +#include <linux/hash.h>
> +
> +#include <asm/uaccess.h>
> +#include <linux/atomic.h>
> +
> +#include <net/icmp.h>
> +#include <net/ip.h>
> +#include <net/ip_tunnels.h>
> +#include <net/ipv6.h>
> +#include <net/ip6_route.h>
> +#include <net/addrconf.h>
> +#include <net/ip6_tunnel.h>
> +#include <net/xfrm.h>
> +#include <net/net_namespace.h>
> +#include <net/netns/generic.h>
> +
> +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
> +
> +#define HASH_SIZE_SHIFT  5
> +#define HASH_SIZE (1 << HASH_SIZE_SHIFT)
> +
> +static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
> +{
> +	u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
> +
> +	return hash_32(hash, HASH_SIZE_SHIFT);
> +}
> +
> +static int vti6_dev_init(struct net_device *dev);
> +static void vti6_dev_setup(struct net_device *dev);
> +static struct rtnl_link_ops vti6_link_ops __read_mostly;
> +
> +static int vti6_net_id __read_mostly;
> +struct vti6_net {
> +	/* the IPv6 tunnel fallback device */
> +	struct net_device *fb_tnl_dev;
> +	/* lists for storing tunnels in use */
> +	struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE];
> +	struct ip6_tnl __rcu *tnls_wc[1];
> +	struct ip6_tnl __rcu **tnls[2];
> +};
> +
> +static struct net_device_stats *vti6_get_stats(struct net_device *dev)
> +{
> +	struct pcpu_tstats sum = { 0 };
> +	int i;
> +
> +	for_each_possible_cpu(i) {
> +		const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
> +
> +		sum.rx_packets += tstats->rx_packets;
> +		sum.rx_bytes   += tstats->rx_bytes;
> +		sum.tx_packets += tstats->tx_packets;
> +		sum.tx_bytes   += tstats->tx_bytes;
> +	}
> +	dev->stats.rx_packets = sum.rx_packets;
> +	dev->stats.rx_bytes   = sum.rx_bytes;
> +	dev->stats.tx_packets = sum.tx_packets;
> +	dev->stats.tx_bytes   = sum.tx_bytes;
> +	return &dev->stats;
> +}
> +
> +#define for_each_vti6_tunnel_rcu(start) \
> +	for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
> +
> +/**
> + * vti6_tnl_lookup - fetch tunnel matching the end-point addresses
> + *   @net: network namespace
> + *   @remote: the address of the tunnel exit-point
> + *   @local: the address of the tunnel entry-point
> + *
> + * Return:
> + *   tunnel matching given end-points if found,
> + *   else fallback tunnel if its device is up,
> + *   else %NULL
> + **/
> +static struct ip6_tnl *
> +vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
> +		const struct in6_addr *local)
> +{
> +	unsigned int hash = HASH(remote, local);
> +	struct ip6_tnl *t;
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
> +		if (ipv6_addr_equal(local, &t->parms.laddr) &&
> +		    ipv6_addr_equal(remote, &t->parms.raddr) &&
> +		    (t->dev->flags & IFF_UP))
> +			return t;
> +	}
> +	t = rcu_dereference(ip6n->tnls_wc[0]);
> +	if (t && (t->dev->flags & IFF_UP))
> +		return t;
> +
> +	return NULL;
> +}
> +
> +/**
> + * vti6_tnl_bucket - get head of list matching given tunnel parameters
> + *   @p: parameters containing tunnel end-points
> + *
> + * Description:
> + *   vti6_tnl_bucket() returns the head of the list matching the
> + *   &struct in6_addr entries laddr and raddr in @p.
> + *
> + * Return: head of IPv6 tunnel list
> + **/
> +static struct ip6_tnl __rcu **
> +vti6_tnl_bucket(struct vti6_net *ip6n, const struct __ip6_tnl_parm *p)
> +{
> +	const struct in6_addr *remote = &p->raddr;
> +	const struct in6_addr *local = &p->laddr;
> +	unsigned int h = 0;
> +	int prio = 0;
> +
> +	if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
> +		prio = 1;
> +		h = HASH(remote, local);
> +	}
> +	return &ip6n->tnls[prio][h];
> +}
> +
> +static void
> +vti6_tnl_link(struct vti6_net *ip6n, struct ip6_tnl *t)
> +{
> +	struct ip6_tnl __rcu **tp = vti6_tnl_bucket(ip6n, &t->parms);
> +
> +	rcu_assign_pointer(t->next , rtnl_dereference(*tp));
> +	rcu_assign_pointer(*tp, t);
> +}
> +
> +static void
> +vti6_tnl_unlink(struct vti6_net *ip6n, struct ip6_tnl *t)
> +{
> +	struct ip6_tnl __rcu **tp;
> +	struct ip6_tnl *iter;
> +
> +	for (tp = vti6_tnl_bucket(ip6n, &t->parms);
> +	     (iter = rtnl_dereference(*tp)) != NULL;
> +	     tp = &iter->next) {
> +		if (t == iter) {
> +			rcu_assign_pointer(*tp, t->next);
> +			break;
> +		}
> +	}
> +}
> +
> +static void vti6_dev_free(struct net_device *dev)
> +{
> +	free_percpu(dev->tstats);
> +	free_netdev(dev);
> +}
> +
> +static int vti6_tnl_create2(struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	struct net *net = dev_net(dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +	int err;
> +
> +	err = vti6_dev_init(dev);
> +	if (err < 0)
> +		goto out;
> +
> +	err = register_netdevice(dev);
> +	if (err < 0)
> +		goto out;
> +
> +	strcpy(t->parms.name, dev->name);
> +	dev->rtnl_link_ops = &vti6_link_ops;
> +
> +	dev_hold(dev);
> +	vti6_tnl_link(ip6n, t);
> +
> +	return 0;
> +
> +out:
> +	return err;
> +}
> +static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
> +{
> +	struct net_device *dev;
> +	struct ip6_tnl *t;
> +	char name[IFNAMSIZ];
> +	int err;
> +
> +	if (p->name[0])
> +		strlcpy(name, p->name, IFNAMSIZ);
> +	else
> +		sprintf(name, "ip6_vti%%d");
> +
> +	dev = alloc_netdev(sizeof (*t), name, vti6_dev_setup);
> +	if (dev == NULL)
> +		goto failed;
> +
> +	dev_net_set(dev, net);
> +
> +	t = netdev_priv(dev);
> +	t->parms = *p;
> +	t->net = dev_net(dev);
> +
> +	err = vti6_tnl_create2(dev);
> +	if (err < 0)
> +		goto failed_free;
> +
> +	return t;
> +
> +failed_free:
> +	vti6_dev_free(dev);
> +failed:
> +	return NULL;
> +}
> +
> +/**
> + * vti6_locate - find or create tunnel matching given parameters
> + *   @net: network namespace
> + *   @p: tunnel parameters
> + *   @create: != 0 if allowed to create new tunnel if no match found
> + *
> + * Description:
> + *   vti6_locate() first tries to locate an existing tunnel
> + *   based on @parms. If this is unsuccessful, but @create is set a new
> + *   tunnel device is created and registered for use.
> + *
> + * Return:
> + *   matching tunnel or NULL
> + **/
> +static struct ip6_tnl *vti6_locate(struct net *net, struct __ip6_tnl_parm *p, int create)
> +{
> +	const struct in6_addr *remote = &p->raddr;
> +	const struct in6_addr *local = &p->laddr;
> +	struct ip6_tnl __rcu **tp;
> +	struct ip6_tnl *t;
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	for (tp = vti6_tnl_bucket(ip6n, p);
> +	     (t = rtnl_dereference(*tp)) != NULL;
> +	     tp = &t->next) {
> +		if (ipv6_addr_equal(local, &t->parms.laddr) &&
> +		    ipv6_addr_equal(remote, &t->parms.raddr))
> +			return t;
> +	}
> +	if (!create)
> +		return NULL;
> +	return vti6_tnl_create(net, p);
> +}
> +
> +/**
> + * vti6_dev_uninit - tunnel device uninitializer
> + *   @dev: the device to be destroyed
> + *
> + * Description:
> + *   vti6_dev_uninit() removes tunnel from its list
> + **/
> +static void
> +vti6_dev_uninit(struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	struct net *net = dev_net(dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	if (dev == ip6n->fb_tnl_dev)
> +		RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
> +	else
> +		vti6_tnl_unlink(ip6n, t);
> +	ip6_tnl_dst_reset(t);
> +	dev_put(dev);
> +}
> +
> +/**
> + * vti6_tnl_err - tunnel error handler
> + *
> + * Description:
> + *   vti6_err() handle errors in the tunnel.
> + **/
> +static int
> +vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
> +	 u8 type, u8 code, int offset, __be32 info)
> +{
> +	struct net *net = dev_net(skb->dev);
> +	const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) skb->data;
> +	struct ip6_tnl *t;
> +	int err = -ENOENT;
> +
> +	rcu_read_lock();
> +	if ((t = vti6_tnl_lookup(net, &ipv6h->daddr,
> +				 &ipv6h->saddr)) == NULL)
> +		goto out;
> +
> +	if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0)
> +		goto out;
> +
> +	err = 0;
> +
> +	switch (type) {
> +	case ICMPV6_DEST_UNREACH:
> +	case ICMPV6_TIME_EXCEED:
> +	case ICMPV6_PARAMPROB:
> +	break;
> +	case ICMPV6_PKT_TOOBIG:
> +		ip6_update_pmtu(skb, net, info, 0, 0);
> +	}
> +
> +
> +out:
> +	rcu_read_unlock();
> +	return err;
> +}
> +
> +static int vti6_rcv(struct sk_buff *skb)
> +{
> +	struct ip6_tnl *t;
> +	const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
> +
> +	rcu_read_lock();
> +
> +	if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
> +					&ipv6h->daddr)) != NULL) {
> +		struct pcpu_tstats *tstats;
> +
> +		if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
> +			rcu_read_unlock();
> +			goto discard;
> +		}
> +
> +		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
> +			rcu_read_unlock();
> +			return 0;
> +		}
> +
> +		if (!ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) {
> +			t->dev->stats.rx_dropped++;
> +			rcu_read_unlock();
> +			goto discard;
> +		}
> +
> +		tstats = this_cpu_ptr(t->dev->tstats);
> +		tstats->rx_packets++;
> +		tstats->rx_bytes += skb->len;
> +
> +		skb->mark = 0;
> +		secpath_reset(skb);
> +		skb->dev = t->dev;
> +
> +		rcu_read_unlock();
> +		return 0;
> +	}
> +	rcu_read_unlock();
> +	return 1;
> +
> +discard:
> +	kfree_skb(skb);
> +	return 0;
> +}
> +
> +/**
> + * vti6_addr_conflict - compare packet addresses to tunnel's own
> + *   @t: the outgoing tunnel device
> + *   @hdr: IPv6 header from the incoming packet
> + *
> + * Description:
> + *   Avoid trivial tunneling loop by checking that tunnel exit-point
> + *   doesn't match source of incoming packet.
> + *
> + * Return:
> + *   1 if conflict,
> + *   0 else
> + **/
> +static inline bool
> +vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
> +{
> +	return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
> +}
> +
> +/**
> + * vti6_xmit - send a packet
> + *   @skb: the outgoing socket buffer
> + *   @dev: the outgoing tunnel device
> + **/
> +static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	struct net *net = dev_net(dev);
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	struct net_device_stats *stats = &t->dev->stats;
> +	struct dst_entry *dst = NULL, *ndst = NULL;
> +	struct flowi6 fl6;
> +	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
> +	struct net_device *tdev;
> +	int err = -1;
> +
> +	if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
> +	    !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
> +		return err;
> +
> +	dst = ip6_tnl_dst_check(t);
> +	if (!dst) {
> +		memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
> +
> +		ndst = ip6_route_output(net, NULL, &fl6);
> +
> +		if (ndst->error)
> +			goto tx_err_link_failure;
> +		ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0);
> +		if (IS_ERR(ndst)) {
> +			err = PTR_ERR(ndst);
> +			ndst = NULL;
> +			goto tx_err_link_failure;
> +		}
> +		dst = ndst;
> +	}
> +
> +	if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL)
> +		goto tx_err_link_failure;
> +
> +	tdev = dst->dev;
> +
> +	if (tdev == dev) {
> +		stats->collisions++;
> +		net_warn_ratelimited("%s: Local routing loop detected!\n",
> +				     t->parms.name);
> +		goto tx_err_dst_release;
> +	}
> +
> +
> +	skb_dst_drop(skb);
> +	skb_dst_set_noref(skb, dst);
> +
> +	ip6tunnel_xmit(skb, dev);
> +	if (ndst)
> +		ip6_tnl_dst_store(t, ndst);
> +	return 0;
> +tx_err_link_failure:
> +	stats->tx_carrier_errors++;
> +	dst_link_failure(skb);
> +tx_err_dst_release:
> +	dst_release(ndst);
> +	return err;
> +}
> +
> +static netdev_tx_t
> +vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	struct net_device_stats *stats = &t->dev->stats;
> +	int ret;
> +
> +	switch (skb->protocol) {
> +	case htons(ETH_P_IPV6):
> +		ret = vti6_xmit(skb, dev);
> +		break;
> +	default:
> +		goto tx_err;
> +	}
> +
> +	if (ret < 0)
> +		goto tx_err;
> +
> +	return NETDEV_TX_OK;
> +
> +tx_err:
> +	stats->tx_errors++;
> +	stats->tx_dropped++;
> +	kfree_skb(skb);
> +	return NETDEV_TX_OK;
> +}
> +
> +static void vti6_link_config(struct ip6_tnl *t)
> +{
> +	struct net_device *dev = t->dev;
> +	struct __ip6_tnl_parm *p = &t->parms;
> +	struct flowi6 *fl6 = &t->fl.u.ip6;
> +
> +	memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
> +	memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
> +
> +	/* Set up flowi template */
> +	fl6->saddr = p->laddr;
> +	fl6->daddr = p->raddr;
> +	fl6->flowi6_oif = p->link;
> +	fl6->flowi6_mark = p->i_key;
> +	fl6->flowi6_proto = p->proto;
> +	fl6->flowlabel = 0;
> +
> +	p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
> +	p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
> +
> +	if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
> +		dev->flags |= IFF_POINTOPOINT;
> +	else
> +		dev->flags &= ~IFF_POINTOPOINT;
> +
> +	dev->iflink = p->link;
> +
> +	if (p->flags & IP6_TNL_F_CAP_XMIT) {
> +		int strict = (ipv6_addr_type(&p->raddr) &
> +			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
> +
> +		struct rt6_info *rt = rt6_lookup(dev_net(dev),
> +						 &p->raddr, &p->laddr,
> +						 p->link, strict);
> +
> +		if (rt == NULL)
> +			return;
> +
> +		if (rt->dst.dev) {
> +			dev->hard_header_len = rt->dst.dev->hard_header_len +
> +				sizeof (struct ipv6hdr);
> +
> +			dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr);
> +
> +			if (dev->mtu < IPV6_MIN_MTU)
> +				dev->mtu = IPV6_MIN_MTU;
> +		}
> +		ip6_rt_put(rt);
> +	}
> +}
> +
> +/**
> + * vti6_tnl_change - update the tunnel parameters
> + *   @t: tunnel to be changed
> + *   @p: tunnel configuration parameters
> + *
> + * Description:
> + *   vti6_tnl_change() updates the tunnel parameters
> + **/
> +static int
> +vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
> +{
> +	t->parms.laddr = p->laddr;
> +	t->parms.raddr = p->raddr;
> +	t->parms.link = p->link;
> +	t->parms.i_key = p->i_key;
> +	t->parms.o_key = p->o_key;
> +	t->parms.proto = p->proto;
> +	ip6_tnl_dst_reset(t);
> +	vti6_link_config(t);
> +	return 0;
> +}
> +
> +static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
> +{
> +	struct net *net = dev_net(t->dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +	int err;
> +
> +	vti6_tnl_unlink(ip6n, t);
> +	synchronize_net();
> +	err = vti6_tnl_change(t, p);
> +	vti6_tnl_link(ip6n, t);
> +	netdev_state_change(t->dev);
> +	return err;
> +}
> +
> +static void
> +vti6_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm2 *u)
> +{
> +	p->laddr = u->laddr;
> +	p->raddr = u->raddr;
> +	p->link = u->link;
> +	p->i_key = u->i_key;
> +	p->o_key = u->o_key;
> +
> +	memcpy(p->name, u->name, sizeof(u->name));
> +}
> +
> +static void
> +vti6_parm_to_user(struct ip6_tnl_parm2 *u, const struct __ip6_tnl_parm *p)
> +{
> +	u->laddr = p->laddr;
> +	u->raddr = p->raddr;
> +	u->link = p->link;
> +	u->i_key = p->i_key;
> +	u->o_key = p->o_key;
> +	memcpy(u->name, p->name, sizeof(u->name));
> +}
> +
> +/**
> + * vti6_tnl_ioctl - configure vti6 tunnels from userspace
> + *   @dev: virtual device associated with tunnel
> + *   @ifr: parameters passed from userspace
> + *   @cmd: command to be performed
> + *
> + * Description:
> + *   vti6_ioctl() is used for managing IPv6 tunnels
> + *   from userspace.
> + *
> + *   The possible commands are the following:
> + *     %SIOCGETTUNNEL: get tunnel parameters for device
> + *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
> + *     %SIOCCHGTUNNEL: change tunnel parameters to those given
> + *     %SIOCDELTUNNEL: delete tunnel
> + *
> + *   The fallback device "ip6tnl0", created during module
> + *   initialization, can be used for creating other tunnel devices.
> + *
> + * Return:
> + *   0 on success,
> + *   %-EFAULT if unable to copy data to or from userspace,
> + *   %-EPERM if current process hasn't %CAP_NET_ADMIN set
> + *   %-EINVAL if passed tunnel parameters are invalid,
> + *   %-EEXIST if changing a tunnel's parameters would cause a conflict
> + *   %-ENODEV if attempting to change or delete a nonexisting device
> + **/
> +static int
> +vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> +{
> +	int err = 0;
> +	struct ip6_tnl_parm2 p;
> +	struct __ip6_tnl_parm p1;
> +	struct ip6_tnl *t = NULL;
> +	struct net *net = dev_net(dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	switch (cmd) {
> +	case SIOCGETTUNNEL:
> +		if (dev == ip6n->fb_tnl_dev) {
> +			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
> +				err = -EFAULT;
> +				break;
> +			}
> +			vti6_parm_from_user(&p1, &p);
> +			t = vti6_locate(net, &p1, 0);
> +		} else {
> +			memset(&p, 0, sizeof(p));
> +		}
> +		if (t == NULL)
> +			t = netdev_priv(dev);
> +		vti6_parm_to_user(&p, &t->parms);
> +		if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
> +			err = -EFAULT;
> +		}
> +		break;
> +	case SIOCADDTUNNEL:
> +	case SIOCCHGTUNNEL:
> +		err = -EPERM;
> +		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
> +			break;
> +		err = -EFAULT;
> +		if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
> +			break;
> +		err = -EINVAL;
> +		if (p.proto != IPPROTO_IPV6  && p.proto != 0)
> +			break;
> +		vti6_parm_from_user(&p1, &p);
> +		t = vti6_locate(net, &p1, cmd == SIOCADDTUNNEL);
> +		if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
> +			if (t != NULL) {
> +				if (t->dev != dev) {
> +					err = -EEXIST;
> +					break;
> +				}
> +			} else
> +				t = netdev_priv(dev);
> +
> +			err = vti6_update(t, &p1);
> +		}
> +		if (t) {
> +			err = 0;
> +			vti6_parm_to_user(&p, &t->parms);
> +			if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
> +				err = -EFAULT;
> +
> +		} else
> +			err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
> +		break;
> +	case SIOCDELTUNNEL:
> +		err = -EPERM;
> +		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
> +			break;
> +
> +		if (dev == ip6n->fb_tnl_dev) {
> +			err = -EFAULT;
> +			if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
> +				break;
> +			err = -ENOENT;
> +			vti6_parm_from_user(&p1, &p);
> +			t = vti6_locate(net, &p1, 0);
> +			if (t == NULL)
> +				break;
> +			err = -EPERM;
> +			if (t->dev == ip6n->fb_tnl_dev)
> +				break;
> +			dev = t->dev;
> +		}
> +		err = 0;
> +		unregister_netdevice(dev);
> +		break;
> +	default:
> +		err = -EINVAL;
> +	}
> +	return err;
> +}
> +
> +/**
> + * vti6_tnl_change_mtu - change mtu manually for tunnel device
> + *   @dev: virtual device associated with tunnel
> + *   @new_mtu: the new mtu
> + *
> + * Return:
> + *   0 on success,
> + *   %-EINVAL if mtu too small
> + **/
> +static int vti6_change_mtu(struct net_device *dev, int new_mtu)
> +{
> +	if (new_mtu < IPV6_MIN_MTU) {
> +		return -EINVAL;
> +	}
> +	dev->mtu = new_mtu;
> +	return 0;
> +}
> +
> +static const struct net_device_ops vti6_netdev_ops = {
> +	.ndo_uninit	= vti6_dev_uninit,
> +	.ndo_start_xmit = vti6_tnl_xmit,
> +	.ndo_do_ioctl	= vti6_ioctl,
> +	.ndo_change_mtu = vti6_change_mtu,
> +	.ndo_get_stats	= vti6_get_stats,
> +};
> +
> +/**
> + * vti6_dev_setup - setup virtual tunnel device
> + *   @dev: virtual device associated with tunnel
> + *
> + * Description:
> + *   Initialize function pointers and device parameters
> + **/
> +static void vti6_dev_setup(struct net_device *dev)
> +{
> +	struct ip6_tnl *t;
> +
> +	dev->netdev_ops = &vti6_netdev_ops;
> +	dev->destructor = vti6_dev_free;
> +
> +	dev->type = ARPHRD_TUNNEL6;
> +	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
> +	dev->mtu = ETH_DATA_LEN;
> +	t = netdev_priv(dev);
> +	dev->flags |= IFF_NOARP;
> +	dev->addr_len = sizeof(struct in6_addr);
> +	dev->features |= NETIF_F_NETNS_LOCAL;
> +	dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
> +}
> +
> +/**
> + * vti6_dev_init_gen - general initializer for all tunnel devices
> + *   @dev: virtual device associated with tunnel
> + **/
> +static inline int vti6_dev_init_gen(struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +
> +	t->dev = dev;
> +	t->net = dev_net(dev);
> +	dev->tstats = alloc_percpu(struct pcpu_tstats);
> +	if (!dev->tstats)
> +		return -ENOMEM;
> +	return 0;
> +}
> +
> +/**
> + * vti6_dev_init - initializer for all non fallback tunnel devices
> + *   @dev: virtual device associated with tunnel
> + **/
> +static int vti6_dev_init(struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	int err = vti6_dev_init_gen(dev);
> +
> +	if (err)
> +		return err;
> +	vti6_link_config(t);
> +	return 0;
> +}
> +
> +/**
> + * vti6_fb_tnl_dev_init - initializer for fallback tunnel device
> + *   @dev: fallback device
> + *
> + * Return: 0
> + **/
> +static int __net_init vti6_fb_tnl_dev_init(struct net_device *dev)
> +{
> +	struct ip6_tnl *t = netdev_priv(dev);
> +	struct net *net = dev_net(dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +	int err = vti6_dev_init_gen(dev);
> +
> +	if (err)
> +		return err;
> +
> +	t->parms.proto = IPPROTO_IPV6;
> +	dev_hold(dev);
> +
> +	vti6_link_config(t);
> +
> +	rcu_assign_pointer(ip6n->tnls_wc[0], t);
> +	return 0;
> +}
> +
> +static int vti6_validate(struct nlattr *tb[], struct nlattr *data[])
> +{
> +	return 0;
> +}
> +
> +static void vti6_netlink_parms(struct nlattr *data[],
> +			       struct __ip6_tnl_parm *parms)
> +{
> +	memset(parms, 0, sizeof(*parms));
> +
> +	if (!data)
> +		return;
> +
> +	if (data[IFLA_VTI_LINK])
> +		parms->link = nla_get_u32(data[IFLA_VTI_LINK]);
> +
> +	if (data[IFLA_VTI_LOCAL])
> +		nla_memcpy(&parms->laddr, data[IFLA_VTI_LOCAL],
> +			   sizeof(struct in6_addr));
> +
> +	if (data[IFLA_VTI_REMOTE])
> +		nla_memcpy(&parms->raddr, data[IFLA_VTI_REMOTE],
> +			   sizeof(struct in6_addr));
> +
> +	if (data[IFLA_VTI_IKEY])
> +		parms->i_key = nla_get_u32(data[IFLA_VTI_IKEY]);
> +
> +	if (data[IFLA_VTI_OKEY])
> +		parms->o_key = nla_get_u32(data[IFLA_VTI_OKEY]);
> +}
> +
> +static int vti6_newlink(struct net *src_net, struct net_device *dev,
> +			struct nlattr *tb[], struct nlattr *data[])
> +{
> +	struct net *net = dev_net(dev);
> +	struct ip6_tnl *nt;
> +
> +	nt = netdev_priv(dev);
> +	vti6_netlink_parms(data, &nt->parms);
> +
> +	nt->parms.proto = IPPROTO_IPV6;
> +
> +	if (vti6_locate(net, &nt->parms, 0))
> +		return -EEXIST;
> +
> +	return vti6_tnl_create2(dev);
> +}
> +
> +static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
> +			   struct nlattr *data[])
> +{
> +	struct ip6_tnl *t;
> +	struct __ip6_tnl_parm p;
> +	struct net *net = dev_net(dev);
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	if (dev == ip6n->fb_tnl_dev)
> +		return -EINVAL;
> +
> +	vti6_netlink_parms(data, &p);
> +
> +	t = vti6_locate(net, &p, 0);
> +
> +	if (t) {
> +		if (t->dev != dev)
> +			return -EEXIST;
> +	} else
> +		t = netdev_priv(dev);
> +
> +	return vti6_update(t, &p);
> +}
> +
> +static size_t vti6_get_size(const struct net_device *dev)
> +{
> +	return
> +		/* IFLA_VTI_LINK */
> +		nla_total_size(4) +
> +		/* IFLA_VTI_LOCAL */
> +		nla_total_size(sizeof(struct in6_addr)) +
> +		/* IFLA_VTI_REMOTE */
> +		nla_total_size(sizeof(struct in6_addr)) +
> +		/* IFLA_VTI_IKEY */
> +		nla_total_size(4) +
> +		/* IFLA_VTI_OKEY */
> +		nla_total_size(4) +
> +		0;
> +}
> +
> +static int vti6_fill_info(struct sk_buff *skb, const struct net_device *dev)
> +{
> +	struct ip6_tnl *tunnel = netdev_priv(dev);
> +	struct __ip6_tnl_parm *parm = &tunnel->parms;
> +
> +	if (nla_put_u32(skb, IFLA_VTI_LINK, parm->link) ||
> +	    nla_put(skb, IFLA_VTI_LOCAL, sizeof(struct in6_addr),
> +		    &parm->laddr) ||
> +	    nla_put(skb, IFLA_VTI_REMOTE, sizeof(struct in6_addr),
> +		    &parm->raddr) ||
> +	    nla_put_u32(skb, IFLA_VTI_IKEY, parm->i_key) ||
> +	    nla_put_u32(skb, IFLA_VTI_OKEY, parm->o_key))
> +		goto nla_put_failure;
> +	return 0;
> +
> +nla_put_failure:
> +	return -EMSGSIZE;
> +}
> +
> +static const struct nla_policy vti6_policy[IFLA_VTI_MAX + 1] = {
> +	[IFLA_VTI_LINK]			= { .type = NLA_U32 },
> +	[IFLA_VTI_LOCAL]		= { .len = sizeof(struct in6_addr) },
> +	[IFLA_VTI_REMOTE]		= { .len = sizeof(struct in6_addr) },
> +	[IFLA_VTI_IKEY]			= { .type = NLA_U32 },
> +	[IFLA_VTI_OKEY]			= { .type = NLA_U32 },
> +};
> +
> +static struct rtnl_link_ops vti6_link_ops __read_mostly = {
> +	.kind		= "vti6",
> +	.maxtype	= IFLA_VTI_MAX,
> +	.policy		= vti6_policy,
> +	.priv_size	= sizeof(struct ip6_tnl),
> +	.setup		= vti6_dev_setup,
> +	.validate	= vti6_validate,
> +	.newlink	= vti6_newlink,
> +	.changelink	= vti6_changelink,
> +	.get_size	= vti6_get_size,
> +	.fill_info	= vti6_fill_info,
> +};
> +
> +static struct xfrm6_tunnel vti6_handler __read_mostly = {
> +	.handler	= vti6_rcv,
> +	.err_handler	= vti6_err,
> +	.priority	=	1,
> +};
> +
> +static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
> +{
> +	int h;
> +	struct ip6_tnl *t;
> +	LIST_HEAD(list);
> +
> +	for (h = 0; h < HASH_SIZE; h++) {
> +		t = rtnl_dereference(ip6n->tnls_r_l[h]);
> +		while (t != NULL) {
> +			unregister_netdevice_queue(t->dev, &list);
> +			t = rtnl_dereference(t->next);
> +		}
> +	}
> +
> +	t = rtnl_dereference(ip6n->tnls_wc[0]);
> +	unregister_netdevice_queue(t->dev, &list);
> +	unregister_netdevice_many(&list);
> +}
> +
> +static int __net_init vti6_init_net(struct net *net)
> +{
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +	struct ip6_tnl *t = NULL;
> +	int err;
> +
> +	ip6n->tnls[0] = ip6n->tnls_wc;
> +	ip6n->tnls[1] = ip6n->tnls_r_l;
> +
> +	err = -ENOMEM;
> +	ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6_vti0",
> +					vti6_dev_setup);
> +
> +	if (!ip6n->fb_tnl_dev)
> +		goto err_alloc_dev;
> +	dev_net_set(ip6n->fb_tnl_dev, net);
> +
> +	err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
> +	if (err < 0)
> +		goto err_register;
> +
> +	err = register_netdev(ip6n->fb_tnl_dev);
> +	if (err < 0)
> +		goto err_register;
> +
> +	t = netdev_priv(ip6n->fb_tnl_dev);
> +
> +	strcpy(t->parms.name, ip6n->fb_tnl_dev->name);
> +	return 0;
> +
> +err_register:
> +	vti6_dev_free(ip6n->fb_tnl_dev);
> +err_alloc_dev:
> +	return err;
> +}
> +
> +static void __net_exit vti6_exit_net(struct net *net)
> +{
> +	struct vti6_net *ip6n = net_generic(net, vti6_net_id);
> +
> +	rtnl_lock();
> +	vti6_destroy_tunnels(ip6n);
> +	rtnl_unlock();
> +}
> +
> +static struct pernet_operations vti6_net_ops = {
> +	.init = vti6_init_net,
> +	.exit = vti6_exit_net,
> +	.id   = &vti6_net_id,
> +	.size = sizeof(struct vti6_net),
> +};
> +
> +/**
> + * vti6_tunnel_init - register protocol and reserve needed resources
> + *
> + * Return: 0 on success
> + **/
> +static int __init vti6_tunnel_init(void)
> +{
> +	int  err;
> +
> +	err = register_pernet_device(&vti6_net_ops);
> +	if (err < 0)
> +		goto out_pernet;
> +
> +	err = xfrm6_mode_tunnel_input_register(&vti6_handler);
> +	if (err < 0) {
> +		pr_err("%s: can't register vti6\n", __func__);
> +		goto out;
> +	}
> +	err = rtnl_link_register(&vti6_link_ops);
> +	if (err < 0)
> +		goto rtnl_link_failed;
> +
> +	return 0;
> +
> +rtnl_link_failed:
> +	xfrm6_mode_tunnel_input_deregister(&vti6_handler);
> +out:
> +	unregister_pernet_device(&vti6_net_ops);
> +out_pernet:
> +	return err;
> +}
> +
> +/**
> + * vti6_tunnel_cleanup - free resources and unregister protocol
> + **/
> +static void __exit vti6_tunnel_cleanup(void)
> +{
> +	rtnl_link_unregister(&vti6_link_ops);
> +	if (xfrm6_mode_tunnel_input_deregister(&vti6_handler))
> +		pr_info("%s: can't deregister vti6\n", __func__);
> +
> +	unregister_pernet_device(&vti6_net_ops);
> +}
> +
> +module_init(vti6_tunnel_init);
> +module_exit(vti6_tunnel_cleanup);
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS_RTNL_LINK("vti6");
> +MODULE_ALIAS_NETDEV("ip6_vti0");
> +MODULE_AUTHOR("Steffen Klassert");
> +MODULE_DESCRIPTION("IPv6 virtual tunnel interface");

^ permalink raw reply

* Re: [PATCH net-next v2 0/6] bonding: remove bond->vlan_list
From: Veaceslav Falico @ 2013-08-26 16:31 UTC (permalink / raw)
  To: netdev
  Cc: Jay Vosburgh, Andy Gospodarek, Patrick McHardy, David S. Miller,
	Nikolay Aleksandrov
In-Reply-To: <1375981079-2936-1-git-send-email-vfalico@redhat.com>

On Thu, Aug 08, 2013 at 06:57:53PM +0200, Veaceslav Falico wrote:
>RFC -> v1: Got some feedback from Nikolay Aleksandrov (privately), tried to
>	   address it, also fixed some bugs that I've found on the way. I
>	   think it's ready to be considered a patchset for
>	   review/inclusion in net-next.
>
>v1  -> v2: Remove ASSERT_RTNL() from vlan_uses_dev(), cause it can be
>	   already called under rcu, without rtnl. Don't check for master
>	   device in __vlan_find_dev_next(), otherwise we won't be able to
>	   work in situations when a device has both vlans and master
>	   device. Properly init vlan_dev in bond_has_this_ip() before
>	   using (sigh). There was a proposal of making a macro
>	   "dev_for_each_vlan_from(dev, vlan_dev, i, from)", which would
>	   use __vlan_find_dev_deep() inside, with its strong and weak
>	   parts, but I've decided to stick to the "while (dev = next())"
>	   scheme currently - it might be added anytime, and now the only
>	   user (bonding) doesn't really need it.

I've taken a different (less intrusive for non-bonding stuff) approach on
the issue, so sent the new patchset not as a v3, but as a standalone one:

[PATCH net-next 0/8] bonding: remove vlan special handling

Thanks all for the help.

^ permalink raw reply

* Re: [PATCH net-next 1/8] net: move netdev_upper to netdevice.h
From: Jiri Pirko @ 2013-08-26 16:41 UTC (permalink / raw)
  To: Veaceslav Falico
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang
In-Reply-To: <1377534533-6944-2-git-send-email-vfalico@redhat.com>

Mon, Aug 26, 2013 at 06:28:46PM CEST, vfalico@redhat.com wrote:
>So that any device can work with it to see its upper/master devices. It is
>rcu'd and rtnl_lock protected, so one should either hold the rtnl_lock() or
>to use the _rcu() functions for it.
>
>CC: "David S. Miller" <davem@davemloft.net>
>CC: Eric Dumazet <edumazet@google.com>
>CC: Jiri Pirko <jiri@resnulli.us>
>CC: Alexander Duyck <alexander.h.duyck@intel.com>
>CC: Cong Wang <amwang@redhat.com>
>Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
>---
> include/linux/netdevice.h |    8 ++++++++
> net/core/dev.c            |    8 --------
> 2 files changed, 8 insertions(+), 8 deletions(-)
>
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index 077363d..8cc7f43 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -2764,6 +2764,14 @@ extern int		netdev_tstamp_prequeue;
> extern int		weight_p;
> extern int		bpf_jit_enable;
> 
>+struct netdev_upper {
>+	struct net_device *dev;
>+	bool master;
>+	struct list_head list;
>+	struct rcu_head rcu;
>+	struct list_head search_list;
>+};
>+


I like your patchset.  However I'm not entirely comfortable with exposing
this struct. I would love to have it "under control" in net/core/dev.c

I'm thinking of some getter/iterator for this use. It can work by
type as well so you would be able to remove the checks from bonding
code.

^ permalink raw reply

* Re: [PATCH RFC 2/2] ipv6: Add support for IPsec virtual tunnel interfaces
From: Eric Dumazet @ 2013-08-26 16:51 UTC (permalink / raw)
  To: Dan Williams; +Cc: Steffen Klassert, netdev
In-Reply-To: <1377535058.11709.21.camel@dcbw.foobar.com>

On Mon, 2013-08-26 at 11:37 -0500, Dan Williams wrote:
> On Mon, 2013-08-19 at 08:27 +0200, Steffen Klassert wrote:
> > This patch adds IPv6  support for IPsec virtual tunnel interfaces
> > (vti). IPsec virtual tunnel interfaces provide a routable interface
> > for IPsec tunnel endpoints.
> 
> Are new ioctls for this kind of thing kosher?  Or should it be using
> netlink instead?

Please don't copy paste 1000 lines of patch, if you only had one
comment.

^ permalink raw reply

* Re: [PATCH net-next 1/8] net: move netdev_upper to netdevice.h
From: Veaceslav Falico @ 2013-08-26 16:55 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang
In-Reply-To: <20130826164115.GA1413@minipsycho.brq.redhat.com>

On Mon, Aug 26, 2013 at 06:41:15PM +0200, Jiri Pirko wrote:
>Mon, Aug 26, 2013 at 06:28:46PM CEST, vfalico@redhat.com wrote:
...snip...
>>+struct netdev_upper {
>>+	struct net_device *dev;
>>+	bool master;
>>+	struct list_head list;
>>+	struct rcu_head rcu;
>>+	struct list_head search_list;
>>+};
>>+
>
>
>I like your patchset.  However I'm not entirely comfortable with exposing
>this struct. I would love to have it "under control" in net/core/dev.c

I've taken this approach first, however the change to non-bonding stuff
became a bit too big to justify the (only) bonding use.

bonding only reads from it, and there are already primitives in dev.c to
modify it, so if they will be used for it it's still the dev.c who controls
it (if someone writes directly to it - it's a bug, and can be NAKed).

>
>I'm thinking of some getter/iterator for this use. It can work by
>type as well so you would be able to remove the checks from bonding
>code.

There are 3 checks in bonding - looking for vlan devs, for a specific dev
and for a specific ip address. list_for_each_entry() fits here perfectly
for each case, otherwise the best way to do this would be to

while ((next_dev = netdev_upper_get_next_dev(dev, next_dev)))

or something like that, which adds quite a bit of overhead (looking for the
previous dev and then returning the next one on each iteration), and looks
ugly.

So, given that it's a plain list actually, and any modification to this
list can (and should be) done via functions from dev.c, while reading can
be done with standard list_for_each_entry(_rcu)(), I think it's better to
expose it this way.

^ permalink raw reply

* Darlehen Angebot bei 3%
From: FIRST TRUST LOAN @ 2013-08-26 17:00 UTC (permalink / raw)


Sehr geehrte Kunden,

Wir helfen Menschen mit finanziellen Schwierigkeiten. müssen
Das Darlehen ist eine ernsthafte Erkrankung, sondern braucht Hilfe
Finanzielle Vermögenswerte? Abgelehnt von Banken und Gehäuse
Loans ". Bereitstellung öffentlicher finanzieller Unterstützung zu niedrig
, 3% bzw. 2.000 € für € 500.000 (Verbraucherkredite)
20 000 € auf 20 Mio. € (Kredite) und Kredite
In jeder Währung. 100% des Projekts und
Sicherheit der persönlichen Finanzen und Bürgschaften
Verfügbar.


Für weitere Informationen, geben Sie bitte die folgenden Informationen:

(1) Die Höhe der beantragten Kredit:
(2) Der Zweck des Darlehens:
(3) Status:
(4) Dauer:

In diesem Fall sind die Anforderungen, die nötig sind, und fordert
,
Zusammen mit den Kreditbedingungen.

Willkommen und danke Ihnen für Ihre Gastfreundschaft

aufrichtig
Mr.William
E-mail: Firsttrustloan2@gmail.com
First Trust Darlehen

^ permalink raw reply

* Re: [PATCH net-next 1/8] net: move netdev_upper to netdevice.h
From: Jiri Pirko @ 2013-08-26 17:38 UTC (permalink / raw)
  To: Veaceslav Falico
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang
In-Reply-To: <20130826165535.GG1992@redhat.com>

Mon, Aug 26, 2013 at 06:55:35PM CEST, vfalico@redhat.com wrote:
>On Mon, Aug 26, 2013 at 06:41:15PM +0200, Jiri Pirko wrote:
>>Mon, Aug 26, 2013 at 06:28:46PM CEST, vfalico@redhat.com wrote:
>...snip...
>>>+struct netdev_upper {
>>>+	struct net_device *dev;
>>>+	bool master;
>>>+	struct list_head list;
>>>+	struct rcu_head rcu;
>>>+	struct list_head search_list;
>>>+};
>>>+
>>
>>
>>I like your patchset.  However I'm not entirely comfortable with exposing
>>this struct. I would love to have it "under control" in net/core/dev.c
>
>I've taken this approach first, however the change to non-bonding stuff
>became a bit too big to justify the (only) bonding use.
>
>bonding only reads from it, and there are already primitives in dev.c to
>modify it, so if they will be used for it it's still the dev.c who controls
>it (if someone writes directly to it - it's a bug, and can be NAKed).
>
>>
>>I'm thinking of some getter/iterator for this use. It can work by
>>type as well so you would be able to remove the checks from bonding
>>code.
>
>There are 3 checks in bonding - looking for vlan devs, for a specific dev
>and for a specific ip address. list_for_each_entry() fits here perfectly
>for each case, otherwise the best way to do this would be to
>
>while ((next_dev = netdev_upper_get_next_dev(dev, next_dev)))

I was imagine something like:

struct list_head *iter;
struct net_device *dev, *upper;

netdev_for_each_upper_dev(dev, upper, iter) {

}

This macro can be easily implented using netdev_upper_get_next_dev()
from dev.c

Not much of added overhead other than netdev_upper_get_next_dev calls
(without any search when using list_head iter).
	
>
>or something like that, which adds quite a bit of overhead (looking for the
>previous dev and then returning the next one on each iteration), and looks
>ugly.
>
>So, given that it's a plain list actually, and any modification to this
>list can (and should be) done via functions from dev.c, while reading can
>be done with standard list_for_each_entry(_rcu)(), I think it's better to
>expose it this way.

^ permalink raw reply

* Re: [PATCH net-next 1/8] net: move netdev_upper to netdevice.h
From: Veaceslav Falico @ 2013-08-26 18:10 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: netdev, David S. Miller, Eric Dumazet, Alexander Duyck, Cong Wang
In-Reply-To: <20130826173844.GA1437@minipsycho.orion>

On Mon, Aug 26, 2013 at 07:38:44PM +0200, Jiri Pirko wrote:
>I was imagine something like:
>
>struct list_head *iter;
>struct net_device *dev, *upper;
>
>netdev_for_each_upper_dev(dev, upper, iter) {
>
>}
>
>This macro can be easily implented using netdev_upper_get_next_dev()
>from dev.c
>
>Not much of added overhead other than netdev_upper_get_next_dev calls
>(without any search when using list_head iter).

Great idea, didn't think of it.

Thanks a lot, will try implement it and send v2.

^ permalink raw reply

* RE: pcie_get_minimum_link returns 0 width
From: Keller, Jacob E @ 2013-08-26 18:27 UTC (permalink / raw)
  To: Yuval Mintz
  Cc: bhelgaas@google.com, linux-pci@vger.kernel.org,
	netdev@vger.kernel.org
In-Reply-To: <979A8436335E3744ADCD3A9F2A2B68A52AD136BE@SJEXCHMB10.corp.ad.broadcom.com>

> -----Original Message-----
> From: Yuval Mintz [mailto:yuvalmin@broadcom.com]
> Sent: Sunday, August 25, 2013 4:22 AM
> To: Keller, Jacob E
> Cc: bhelgaas@google.com; linux-pci@vger.kernel.org;
> netdev@vger.kernel.org
> Subject: pcie_get_minimum_link returns 0 width
> 
> Hi,
> 
> I tried adding support for the newly added 'pcie_get_minimum_link' into
> the
> bnx2x driver, but found out the some of my devices started showing
> width x0.
> 
> By adding debug prints, I've found out there were devices up the chain
> that
> Showed 0 when their PCI_EXP_LNKSTA was read by said function.
> However, when I tried looking via lspci the output claimed the width was
> x4.
> 
> lspci -vt output:
> [0000:00]-+-00.0  Intel Corporation 5000P Chipset Memory Controller
> Hub
> 	     +-02.0-[09-12]--+-00.0-[0a-11]--+-00.0-[0b-0d]--
> 					     +-01.0-[0e-10]--+-00.0
> Broadcom
> 					Corporation NetXtreme II
> BCM57710
> 					10-Gigabit PCIe [Everest]
> 
> Where:
> 00:02.0 PCI bridge: Intel Corporation 5000 Series Chipset PCI Express x4
> Port
> 2 (rev 93)
> 09:00.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express
> Upstream
> Port (rev 01)
> 0a:01.0 PCI bridge: Intel Corporation 6311ESB/6321ESB PCI Express
> Downstream Port E2 (rev 01)
> 0e:00.0 Ethernet controller: Broadcom Corporation NetXtreme II
> BCM57710
> 10-Gigabit PCIe [Everest] (rev 01)
> 
> The output for "lspci -vvvv | grep LnkSta for all four is:
> LnkSta:	Speed 2.5GT/s, Width x4, TrErr- Train- SlotClk+ DLActive-
> BWMgmt-
> ABWMgmt-
> 
> But added prints inside the function's loop show:
> LnkSta 1041 [000e:00.00]
> LnkSta 0000 [000a:01.00]
> LnkSta 0000 [0009:00.00]
> LnkSta 3041 [0000:02.00]
> (PCI_EXP_LNKSTA value, bus->number, PCI_SLOT, PCI_FUNC)
> 
> Thanks,
> Yuval

Interesting... It looks like the entire LnkSta  read failed for the two in the middle..  I don't know how much I can help on this issue because I don't have a machine that exhibits this symptom.. Any suggestions?

Regards,
Jake

^ permalink raw reply

* Re: [PATCH v6 2/5] net: ethernet: cpsw: add optional third memory region for CONTROL module
From: Mugunthan V N @ 2013-08-26 18:49 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Daniel Mack, netdev, bcousson, nsekhar, sergei.shtylyov, davem,
	ujhelyi.m, vaibhav.bedia, d-gerlach, linux-arm-kernel, linux-omap,
	devicetree
In-Reply-To: <20130826090422.GB7656@atomide.com>

On Monday 26 August 2013 02:34 PM, Tony Lindgren wrote:
> * Daniel Mack <zonque@gmail.com> [130823 12:39]:
>> At least the AM33xx SoC has a control module register to configure
>> details such as the hardware ethernet interface mode.
>>
>> I'm not sure whether all SoCs which feature the cpsw block have such a
>> register, so that third memory region is considered optional for now.
> Assuming you're talking about omap SCM registers here..
>
> This should be in a separate driver module so the control module
> parts can eventually be children of the SCM driver as they are
> really separate devices on the bus. See how the USB PHY parts were done
> for example.
>
> What do these control module registers do? If it's just multiplexing
> and pinconf, then you can use pinctrl-single,bits most likely for it and
> access it using the named modes.
>
> However, if the register also contains comparators and control for
> regulators, you should only use pinctrl-single for the multiplexing
> and pinconf parts.
>
I will take a look into usb control module driver and will try to adopt
the driver here also.

Regards
Mugunthan V N

^ permalink raw reply

* Re: [PATCH v2 net-next] tcp: TSO packets automatic sizing
From: Yuchung Cheng @ 2013-08-26 19:09 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Miller, netdev, Neal Cardwell, Van Jacobson, Tom Herbert
In-Reply-To: <1377491162.8828.116.camel@edumazet-glaptop>

On Sun, Aug 25, 2013 at 9:26 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> After hearing many people over past years complaining against TSO being
> bursty or even buggy, we are proud to present automatic sizing of TSO
> packets.
>
> One part of the problem is that tcp_tso_should_defer() uses an heuristic
> relying on upcoming ACKS instead of a timer, but more generally, having
> big TSO packets makes little sense for low rates, as it tends to create
> micro bursts on the network, and general consensus is to reduce the
> buffering amount.
>
> This patch introduces a per socket sk_pacing_rate, that approximates
> the current sending rate, and allows us to size the TSO packets so
> that we try to send one packet every ms.
>
> This field could be set by other transports.
>
> Patch has no impact for high speed flows, where having large TSO packets
> makes sense to reach line rate.
>
> For other flows, this helps better packet scheduling and ACK clocking.
>
> This patch increases performance of TCP flows in lossy environments.
>
> A new sysctl (tcp_min_tso_segs) is added, to specify the
> minimal size of a TSO packet (default being 2).
>
> A follow-up patch will provide a new packet scheduler (FQ), using
> sk_pacing_rate as an input to perform optional per flow pacing.
>
> This explains why we chose to set sk_pacing_rate to twice the current
> rate, allowing 'slow start' ramp up.
>
> sk_pacing_rate = 2 * cwnd * mss / srtt
>
> v2: Neal Cardwell reported a suspect deferring of last two segments on
> initial write of 10 MSS, I had to change tcp_tso_should_defer() to take
> into account tp->xmit_size_goal_segs
init write of 10MSS now looks good, but the delay still shows up if 9
< write-size < 10 MSS...

I use packetdrill to do write(14599) bytes of MSS 1460

0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
0.000 bind(3, ..., ...) = 0
0.000 listen(3, 1) = 0

0.100 < S 299245565:299245565(0) win 32792 <mss
1460,sackOK,nop,nop,nop,wscale 7>
0.100 > S. 0:0(0) ack 299245566 <mss 1460,nop,nop,sackOK,nop,wscale 6>
0.200 < . 1:1(0) ack 1 win 257
0.200 accept(3, ..., ...) = 4
+.000 write(4, ..., 13141) = 13141
+3 %{ print "done" }%

and tcpdump shows

31.819958 IP cli > srv: S 299245565:299245565(0) win 32792 <mss 1460,sackOK,nop,
nop,nop,wscale 7>
000034 IP srv > cli: S 203810874:203810874(0) ack 299245566 win 29200
<mss 1460,nop,nop,sackOK,nop,wscale 6>
099966 IP cli > srv: . ack 1 win 257
000079 IP srv > cli: . 1:2921(2920) ack 1 win 457
000010 IP srv > cli: . 2921:5841(2920) ack 1 win 457
000005 IP srv > cli: . 5841:8761(2920) ack 1 win 457
000004 IP srv > cli: . 8761:11681(2920) ack 1 win 457
199659 IP srv > cli: . 11681:13141(1460) ack 1 win 457
...


>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Neal Cardwell <ncardwell@google.com>
> Cc: Yuchung Cheng <ycheng@google.com>
> Cc: Van Jacobson <vanj@google.com>
> Cc: Tom Herbert <therbert@google.com>
> ---
>  Documentation/networking/ip-sysctl.txt |    9 ++++++
>  include/net/sock.h                     |    2 +
>  include/net/tcp.h                      |    1
>  net/ipv4/sysctl_net_ipv4.c             |   10 +++++++
>  net/ipv4/tcp.c                         |   28 +++++++++++++++++---
>  net/ipv4/tcp_input.c                   |   31 ++++++++++++++++++++++-
>  net/ipv4/tcp_output.c                  |    2 -
>  7 files changed, 76 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
> index debfe85..ce5bb43 100644
> --- a/Documentation/networking/ip-sysctl.txt
> +++ b/Documentation/networking/ip-sysctl.txt
> @@ -482,6 +482,15 @@ tcp_syn_retries - INTEGER
>  tcp_timestamps - BOOLEAN
>         Enable timestamps as defined in RFC1323.
>
> +tcp_min_tso_segs - INTEGER
> +       Minimal number of segments per TSO frame.
> +       Since linux-3.12, TCP does an automatic sizing of TSO frames,
> +       depending on flow rate, instead of filling 64Kbytes packets.
> +       For specific usages, it's possible to force TCP to build big
> +       TSO frames. Note that TCP stack might split too big TSO packets
> +       if available window is too small.
> +       Default: 2
> +
>  tcp_tso_win_divisor - INTEGER
>         This allows control over what percentage of the congestion window
>         can be consumed by a single TSO frame.
> diff --git a/include/net/sock.h b/include/net/sock.h
> index e4bbcbf..6ba2e7b 100644
> --- a/include/net/sock.h
> +++ b/include/net/sock.h
> @@ -232,6 +232,7 @@ struct cg_proto;
>    *    @sk_napi_id: id of the last napi context to receive data for sk
>    *    @sk_ll_usec: usecs to busypoll when there is no data
>    *    @sk_allocation: allocation mode
> +  *    @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler)
>    *    @sk_sndbuf: size of send buffer in bytes
>    *    @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
>    *               %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
> @@ -361,6 +362,7 @@ struct sock {
>         kmemcheck_bitfield_end(flags);
>         int                     sk_wmem_queued;
>         gfp_t                   sk_allocation;
> +       u32                     sk_pacing_rate; /* bytes per second */
>         netdev_features_t       sk_route_caps;
>         netdev_features_t       sk_route_nocaps;
>         int                     sk_gso_type;
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index 09cb5c1..73fcd7c 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -281,6 +281,7 @@ extern int sysctl_tcp_early_retrans;
>  extern int sysctl_tcp_limit_output_bytes;
>  extern int sysctl_tcp_challenge_ack_limit;
>  extern unsigned int sysctl_tcp_notsent_lowat;
> +extern int sysctl_tcp_min_tso_segs;
>
>  extern atomic_long_t tcp_memory_allocated;
>  extern struct percpu_counter tcp_sockets_allocated;
> diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
> index 8ed7c32..540279f 100644
> --- a/net/ipv4/sysctl_net_ipv4.c
> +++ b/net/ipv4/sysctl_net_ipv4.c
> @@ -29,6 +29,7 @@
>  static int zero;
>  static int one = 1;
>  static int four = 4;
> +static int gso_max_segs = GSO_MAX_SEGS;
>  static int tcp_retr1_max = 255;
>  static int ip_local_port_range_min[] = { 1, 1 };
>  static int ip_local_port_range_max[] = { 65535, 65535 };
> @@ -761,6 +762,15 @@ static struct ctl_table ipv4_table[] = {
>                 .extra2         = &four,
>         },
>         {
> +               .procname       = "tcp_min_tso_segs",
> +               .data           = &sysctl_tcp_min_tso_segs,
> +               .maxlen         = sizeof(int),
> +               .mode           = 0644,
> +               .proc_handler   = proc_dointvec_minmax,
> +               .extra1         = &zero,
> +               .extra2         = &gso_max_segs,
> +       },
> +       {
>                 .procname       = "udp_mem",
>                 .data           = &sysctl_udp_mem,
>                 .maxlen         = sizeof(sysctl_udp_mem),
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index ab64eea..e1714ee 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -283,6 +283,8 @@
>
>  int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
>
> +int sysctl_tcp_min_tso_segs __read_mostly = 2;
> +
>  struct percpu_counter tcp_orphan_count;
>  EXPORT_SYMBOL_GPL(tcp_orphan_count);
>
> @@ -785,12 +787,28 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
>         xmit_size_goal = mss_now;
>
>         if (large_allowed && sk_can_gso(sk)) {
> -               xmit_size_goal = ((sk->sk_gso_max_size - 1) -
> -                                 inet_csk(sk)->icsk_af_ops->net_header_len -
> -                                 inet_csk(sk)->icsk_ext_hdr_len -
> -                                 tp->tcp_header_len);
> +               u32 gso_size, hlen;
> +
> +               /* Maybe we should/could use sk->sk_prot->max_header here ? */
> +               hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
> +                      inet_csk(sk)->icsk_ext_hdr_len +
> +                      tp->tcp_header_len;
> +
> +               /* Goal is to send at least one packet per ms,
> +                * not one big TSO packet every 100 ms.
> +                * This preserves ACK clocking and is consistent
> +                * with tcp_tso_should_defer() heuristic.
> +                */
> +               gso_size = sk->sk_pacing_rate / (2 * MSEC_PER_SEC);
> +               gso_size = max_t(u32, gso_size,
> +                                sysctl_tcp_min_tso_segs * mss_now);
> +
> +               xmit_size_goal = min_t(u32, gso_size,
> +                                      sk->sk_gso_max_size - 1 - hlen);
>
> -               /* TSQ : try to have two TSO segments in flight */
> +               /* TSQ : try to have at least two segments in flight
> +                * (one in NIC TX ring, another in Qdisc)
> +                */
>                 xmit_size_goal = min_t(u32, xmit_size_goal,
>                                        sysctl_tcp_limit_output_bytes >> 1);
>
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index ec492ea..3d63db7 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -688,6 +688,33 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
>         }
>  }
>
> +/* Set sk_pacing_rate to allow proper sizing of TSO packets.
> + * Note: TCP stack does not yet implement pacing.
> + * FQ packet scheduler can be used to implement cheap but effective
> + * TCP pacing, to smooth the burst on large writes when packets
> + * in flight is significantly lower than cwnd (or rwin)
> + */
> +static void tcp_update_pacing_rate(struct sock *sk)
> +{
> +       const struct tcp_sock *tp = tcp_sk(sk);
> +       u64 rate;
> +
> +       /* set sk_pacing_rate to 200 % of current rate (mss * cwnd / rtt) */
> +       rate = (u64)tp->mss_cache * 8 * 2 * USEC_PER_SEC;
> +
> +       rate *= max(tp->snd_cwnd, tp->packets_out);
> +
> +       do_div(rate, jiffies_to_usecs(tp->srtt));
> +
> +       /* Correction for small srtt : minimum srtt being 8 (1 jiffy),
> +        * be conservative and assume rtt = 1/(8*HZ) instead of 1/HZ s
> +        * We probably need usec resolution in the future.
> +        */
> +       if (tp->srtt <= 8 + 2)
> +               rate <<= 3;
> +       sk->sk_pacing_rate = min_t(u64, rate, ~0U);
> +}
> +
>  /* Calculate rto without backoff.  This is the second half of Van Jacobson's
>   * routine referred to above.
>   */
> @@ -3278,7 +3305,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
>         u32 ack_seq = TCP_SKB_CB(skb)->seq;
>         u32 ack = TCP_SKB_CB(skb)->ack_seq;
>         bool is_dupack = false;
> -       u32 prior_in_flight;
> +       u32 prior_in_flight, prior_cwnd = tp->snd_cwnd, prior_rtt = tp->srtt;
>         u32 prior_fackets;
>         int prior_packets = tp->packets_out;
>         const int prior_unsacked = tp->packets_out - tp->sacked_out;
> @@ -3383,6 +3410,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
>
>         if (icsk->icsk_pending == ICSK_TIME_RETRANS)
>                 tcp_schedule_loss_probe(sk);
> +       if (tp->srtt != prior_rtt || tp->snd_cwnd != prior_cwnd)
> +               tcp_update_pacing_rate(sk);
>         return 1;
>
>  no_queue:
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index 884efff..e63ae4c 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -1631,7 +1631,7 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
>
>         /* If a full-sized TSO skb can be sent, do it. */
>         if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
> -                          sk->sk_gso_max_segs * tp->mss_cache))
> +                          tp->xmit_size_goal_segs * tp->mss_cache))
>                 goto send_now;
>
>         /* Middle in queue won't get any more data, full sendable already? */
>
>

^ permalink raw reply

* 確認您的Webmail身份
From: 系統管理員 @ 2013-08-26 19:19 UTC (permalink / raw)


確認您的Webmail身份
  您的郵箱已超過其配額限制由administrator.You設置將無法發送或接收所有新郵件,直到你升級你的郵箱seize.Click下面的鏈接,並按照其中的說明,以增加您的
    
              http://webadminnunitt.phpforms.net/f/webadmin
的問候,
企業郵局支持幫助台
版權所有©2013年,企業郵局,技術支持團隊,並保留所有權利

^ permalink raw reply

* Re: [PATCH 0/2] Rename nsproxy.pid_ns and fix a related security bug
From: David Miller @ 2013-08-26 19:59 UTC (permalink / raw)
  To: luto; +Cc: ebiederm, security, linux-kernel, netdev
In-Reply-To: <cover.1377196394.git.luto@amacapital.net>

From: Andy Lutomirski <luto@amacapital.net>
Date: Thu, 22 Aug 2013 11:39:14 -0700

>     commit 92f28d973cce45ef5823209aab3138eb45d8b349
>     Author: Eric W. Biederman <ebiederm@xmission.com>
>     Date:   Fri Mar 15 01:03:33 2013 -0700
> 
>         scm: Require CAP_SYS_ADMIN over the current pidns to spoof pids.
> 
> Eric fell for my bogus claim that nsproxy->pid_ns was the current'
> process's pid ns.  This isn't true.
> 
> Let's fix the bug and rename pid_ns so that no one gets this wrong again.
> 
> Signed-off-by: Andy Lutomirski <luto@amacapital.net>

Eric please take the time to review these changes, thanks.

^ permalink raw reply

* Re: [PATCH 0/2] net/cadence/macb: add support for dt phy definition
From: David Miller @ 2013-08-26 20:04 UTC (permalink / raw)
  To: b.brezillon
  Cc: nicolas.ferre, rob.herring, pawel.moll, mark.rutland, swarren,
	ian.campbell, linux, f.fainelli, netdev, linux-kernel,
	linux-arm-kernel, devicetree
In-Reply-To: <1377186980-21902-1-git-send-email-b.brezillon@overkiz.com>

From: Boris BREZILLON <b.brezillon@overkiz.com>
Date: Thu, 22 Aug 2013 17:56:20 +0200

> This patch series adds support for ethernet phy definition using device
> tree.
> 
> This may help in moving some at91 boards to dt (some of them define an
> interrupt pin).
> 
> Tested on samad31ek.

Series applied to net-next, thanks.

^ permalink raw reply

* Re: sendto() bug?
From: Chris Clark @ 2013-08-26 20:14 UTC (permalink / raw)
  To: Julian Anastasov; +Cc: davem, netdev
In-Reply-To: <alpine.LFD.2.00.1308241105220.1641@ja.ssi.bg>

On Sat, 24 Aug 2013, Julian Anastasov wrote:
> On Fri, 23 Aug 2013, Chris Clark wrote:
> > In the same vein as 2ad5b9e4, I'm soliciting feedback on something
> > similar for raw_sendmsg():
[snip]

> 	So, something like
> (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0) ?


Many thanks.  This patch indeed appears to resolve the problem:

diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index dd44e0a..61e60d6 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -571,7 +571,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
 			   RT_SCOPE_UNIVERSE,
 			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
-			   inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
+			   inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP |
+			    (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
 			   daddr, saddr, 0, 0);

 	if (!inet->hdrincl) {


Chris

^ permalink raw reply related

* Re: sendto() bug?
From: David Miller @ 2013-08-26 20:15 UTC (permalink / raw)
  To: chris.clark; +Cc: ja, netdev
In-Reply-To: <alpine.DEB.2.02.1308261319370.23968@optio.utah.ind.alcatel.com>

From: Chris Clark <chris.clark@alcatel-lucent.com>
Date: Mon, 26 Aug 2013 14:14:21 -0600 (MDT)

> On Sat, 24 Aug 2013, Julian Anastasov wrote:
>> On Fri, 23 Aug 2013, Chris Clark wrote:
>> > In the same vein as 2ad5b9e4, I'm soliciting feedback on something
>> > similar for raw_sendmsg():
> [snip]
> 
>> 	So, something like
>> (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0) ?
> 
> 
> Many thanks.  This patch indeed appears to resolve the problem:

Someone please submit this properly with a clean, well formed, commit
message and signoffs.

Thanks.

^ permalink raw reply

* Re: [PATCH net-next] {ipv4,xfrm}: Introduce xfrm_tunnel_notifier for xfrm tunnel mode callback
From: David Miller @ 2013-08-26 20:21 UTC (permalink / raw)
  To: fan.du; +Cc: steffen.klassert, saurabh.mohan, herbert, netdev
In-Reply-To: <1377240424-11758-1-git-send-email-fan.du@windriver.com>

From: Fan Du <fan.du@windriver.com>
Date: Fri, 23 Aug 2013 14:47:04 +0800

> Some thoughts on IPv4 VTI implementation:
> 
> The connection between VTI receiving part and xfrm tunnel mode input process
> is hardly a "xfrm_tunnel", xfrm_tunnel is used in places where, e.g ipip/sit
> and xfrm4_tunnel, acts like a true "tunnel" device.
> 
> In addition, IMHO, VTI doesn't need vti_err to do something meaningful, as all
> VTI needs is just a notifier to be called whenever xfrm_input ingress a packet
> to update statistics.
> 
> So this patch introduce xfrm_tunnel_notifier and meanwhile wipe out vti_erri
> code.
> 
> Signed-off-by: Fan Du <fan.du@windriver.com>

I don't understand why VTI doesn't need to propagate a PMTU update via
ipv4_update_pmtu().  Why is it different from a real xfrm_tunnel?

Your changelog has to explain this better and in more detail.

Thanks.

^ permalink raw reply

* Re: [PATCH RFC 0/6] SYNPROXY target v2
From: David Miller @ 2013-08-26 20:24 UTC (permalink / raw)
  To: kaber; +Cc: pablo, netfilter-devel, netdev, mph, jesper.brouer, as
In-Reply-To: <1377244329-20146-1-git-send-email-kaber@trash.net>

From: Patrick McHardy <kaber@trash.net>
Date: Fri, 23 Aug 2013 09:52:03 +0200

> The following patches contain the current version of the SYNPROXY target.
> Changes this the last posting are:
> 
> - use sysctl_ip_default_ttl instead of hardcoding 64
> 
> - use MAX_TCP_HEADER instead of LL_MAX_HEADER
> 
> - add some comments requested by Jesper regarding ack_seq initialization
>   in the server's SYN packet
> 
> - use consume_skb() instead of kfree_skb() in the synproxy hook
> 
> - remove a fixme and add explicit check for "-p tcp" in the SYNPROXY rule
>   in the IPv6 version
> 
> - some whitespace fixes
> 
> - a larger number of fixes for properly handling retransmissions and
>   out of order packets, please see the changelog included in patch 6/6
>   for details.
>   
>   I've kept those in a seperate patch for now to ease review, we'll do
>   some more extensive testing on monday and I'll fold the changes in
>   their respective patches before the final submission.
> 
> Comments welcome.

No objections to the non-netfilter portions:

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply

* Re: [PATCH v2 net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-26 20:28 UTC (permalink / raw)
  To: Yuchung Cheng
  Cc: David Miller, netdev, Neal Cardwell, Van Jacobson, Tom Herbert
In-Reply-To: <CAK6E8=dkp2soUUrv_gP5soBCqe7mf7KNY-iO-FoS0J4Pi4zXpg@mail.gmail.com>

On Mon, 2013-08-26 at 12:09 -0700, Yuchung Cheng wrote:

> init write of 10MSS now looks good, but the delay still shows up if 9
> < write-size < 10 MSS...
> 
> I use packetdrill to do write(14599) bytes of MSS 1460
> 
> 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> 0.000 bind(3, ..., ...) = 0
> 0.000 listen(3, 1) = 0
> 
> 0.100 < S 299245565:299245565(0) win 32792 <mss
> 1460,sackOK,nop,nop,nop,wscale 7>
> 0.100 > S. 0:0(0) ack 299245566 <mss 1460,nop,nop,sackOK,nop,wscale 6>
> 0.200 < . 1:1(0) ack 1 win 257
> 0.200 accept(3, ..., ...) = 4
> +.000 write(4, ..., 13141) = 13141
> +3 %{ print "done" }%
> 
> and tcpdump shows
> 
> 31.819958 IP cli > srv: S 299245565:299245565(0) win 32792 <mss 1460,sackOK,nop,
> nop,nop,wscale 7>
> 000034 IP srv > cli: S 203810874:203810874(0) ack 299245566 win 29200
> <mss 1460,nop,nop,sackOK,nop,wscale 6>
> 099966 IP cli > srv: . ack 1 win 257
> 000079 IP srv > cli: . 1:2921(2920) ack 1 win 457
> 000010 IP srv > cli: . 2921:5841(2920) ack 1 win 457
> 000005 IP srv > cli: . 5841:8761(2920) ack 1 win 457
> 000004 IP srv > cli: . 8761:11681(2920) ack 1 win 457
> 199659 IP srv > cli: . 11681:13141(1460) ack 1 win 457
> ...

It works correctly here, I wonder what's happening on your host.

lpq83:~# tcpdump -p -n -s 0 -i any port 8080 -ttt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
000000 IP 192.0.2.1.42148 > 192.168.0.1.8080: S 299245565:299245565(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
000042 IP 192.168.0.1.8080 > 192.0.2.1.42148: S 223873324:223873324(0) ack 299245566 win 29200 <mss 1460,nop,nop,sackOK,nop,wscale 6>
099946 IP 192.0.2.1.42148 > 192.168.0.1.8080: . ack 1 win 257
000087 IP 192.168.0.1.8080 > 192.0.2.1.42148: . 1:2921(2920) ack 1 win 457
000006 IP 192.168.0.1.8080 > 192.0.2.1.42148: . 2921:5841(2920) ack 1 win 457
000004 IP 192.168.0.1.8080 > 192.0.2.1.42148: . 5841:8761(2920) ack 1 win 457
000004 IP 192.168.0.1.8080 > 192.0.2.1.42148: . 8761:11681(2920) ack 1 win 457
000005 IP 192.168.0.1.8080 > 192.0.2.1.42148: . 11681:13141(1460) ack 1 win 457
000002 IP 192.168.0.1.8080 > 192.0.2.1.42148: P 13141:13142(1) ack 1 win 457

^ permalink raw reply

* Re: [PATCH RESEND V3 net-next 2/3] net: huawei_cdc_ncm: Introduce the huawei_cdc_ncm driver
From: David Miller @ 2013-08-26 20:31 UTC (permalink / raw)
  To: mrkiko.rs; +Cc: gregkh, oliver, linux-kernel, linux-usb, netdev
In-Reply-To: <1377244590-8558-3-git-send-email-mrkiko.rs@gmail.com>

From: Enrico Mioso <mrkiko.rs@gmail.com>
Date: Fri, 23 Aug 2013 09:56:29 +0200

> +	if ((on && atomic_add_return(1, &drvstate->pmcount) == 1) || (!on && atomic_dec_and_test(&drvstate->pmcount))) {

These line significantly exceeds 80 columns.

> +		subdriver = usb_cdc_wdm_register(ctx->control,
> +						 &usbnet_dev->status->desc,
> +						 256, /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
> +						 huawei_cdc_ncm_wdm_manage_power);

Likewise.

> +	if (intf == ctx->control && drvstate->subdriver && drvstate->subdriver->suspend)

Likewise.

> +	int ret = 0;
> +	struct usbnet *usbnet_dev = usb_get_intfdata(intf);
> +	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
> +	struct cdc_ncm_ctx *ctx = drvstate->ctx;
> +	bool callsub = (intf == ctx->control && drvstate->subdriver && drvstate->subdriver->resume); /* should we call subdriver's resume? ? */

Likewise, and order local function variable declarations by line
length, longest to shortest.

^ permalink raw reply

* [PATCH net-next v1 4/9] bonding: make bond_arp_send_all use upper device list
From: Veaceslav Falico @ 2013-08-26 20:32 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377549162-7522-1-git-send-email-vfalico@redhat.com>

Currently, bond_arp_send_all() is aware only of vlans, which breaks
configurations like bond <- bridge (or any other 'upper' device) with IP
(which is quite a common scenario for virt setups).

To fix this we convert the bond_arp_send_all() to first verify if the rt
device is the bond itself, and if not - to go through its list of upper
devices to see if any of them match the route device for the target. If the
match is a vlan device - we also save its vlan_id and tag it in
bond_arp_send().

Also, clean the function a bit to be more readable.

v1: use netdev_for_each_upper_dev()

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c |   84 ++++++++++++++------------------------
 1 files changed, 31 insertions(+), 53 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 7407e65..40eb250 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2444,30 +2444,16 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
 
 static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
-	int i, vlan_id;
-	__be32 *targets = bond->params.arp_targets;
-	struct vlan_entry *vlan;
-	struct net_device *vlan_dev = NULL;
+	struct net_device *upper;
+	struct list_head *iter;
 	struct rtable *rt;
+	__be32 *targets = bond->params.arp_targets, addr;
+	int i, vlan_id;
 
-	for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) {
-		__be32 addr;
-		if (!targets[i])
-			break;
+	for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
 		pr_debug("basa: target %pI4\n", &targets[i]);
-		if (!bond_vlan_used(bond)) {
-			pr_debug("basa: empty vlan: arp_send\n");
-			addr = bond_confirm_addr(bond->dev, targets[i], 0);
-			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-				      addr, 0);
-			continue;
-		}
 
-		/*
-		 * If VLANs are configured, we do a route lookup to
-		 * determine which VLAN interface would be used, so we
-		 * can tag the ARP with the proper VLAN tag.
-		 */
+		/* Find out through which dev should the packet go */
 		rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
 				     RTO_ONLINK, 0);
 		if (IS_ERR(rt)) {
@@ -2478,47 +2464,39 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 			continue;
 		}
 
-		/*
-		 * This target is not on a VLAN
-		 */
-		if (rt->dst.dev == bond->dev) {
-			ip_rt_put(rt);
-			pr_debug("basa: rtdev == bond->dev: arp_send\n");
-			addr = bond_confirm_addr(bond->dev, targets[i], 0);
-			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-				      addr, 0);
-			continue;
-		}
-
 		vlan_id = 0;
-		list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-			rcu_read_lock();
-			vlan_dev = __vlan_find_dev_deep(bond->dev,
-							htons(ETH_P_8021Q),
-							vlan->vlan_id);
-			rcu_read_unlock();
-			if (vlan_dev == rt->dst.dev) {
-				vlan_id = vlan->vlan_id;
-				pr_debug("basa: vlan match on %s %d\n",
-				       vlan_dev->name, vlan_id);
-				break;
-			}
-		}
 
-		if (vlan_id && vlan_dev) {
-			ip_rt_put(rt);
-			addr = bond_confirm_addr(vlan_dev, targets[i], 0);
-			bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-				      addr, vlan_id);
-			continue;
+		/* bond device itself */
+		if (rt->dst.dev == bond->dev)
+			goto found;
+
+		/* search for upper device, like vlan/bridge/team/etc */
+		rcu_read_lock();
+		netdev_for_each_upper_dev(bond->dev, upper, iter) {
+			if (upper == rt->dst.dev) {
+				/* if it's a vlan - get its VID */
+				if (is_vlan_dev(rt->dst.dev))
+					vlan_id = vlan_dev_vlan_id(rt->dst.dev);
+
+				rcu_read_unlock();
+				goto found;
+			}
 		}
+		rcu_read_unlock();
 
-		if (net_ratelimit()) {
+		/* Not our device - skip */
+		if (net_ratelimit())
 			pr_warning("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
 				   bond->dev->name, &targets[i],
 				   rt->dst.dev ? rt->dst.dev->name : "NULL");
-		}
 		ip_rt_put(rt);
+		continue;
+
+found:
+		addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
+		ip_rt_put(rt);
+		bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+			      addr, vlan_id);
 	}
 }
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v1 1/9] net: add netdev_upper_get_next_dev(dev, iter)
From: Veaceslav Falico @ 2013-08-26 20:32 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck, Cong Wang
In-Reply-To: <1377549162-7522-1-git-send-email-vfalico@redhat.com>

This function returns the next dev in the dev->upper_dev_list after the
struct list_head **iter position, and updates *iter accordingly. Returns
NULL if there are no devices left.

v1: new patch

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 net/core/dev.c |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 1ed2b66..566e99a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4477,6 +4477,31 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_get);
 
+/* netdev_upper_get_next_dev - Get the next dev from upper list
+ * @dev: device
+ * @iter: list_head ** of the current position
+ *
+ * Gets the next device from the dev's upper list, starting from iter
+ * position. The caller must hold RCU read lock.
+ */
+struct net_device *netdev_upper_get_next_dev(struct net_device *dev,
+					     struct list_head **iter)
+{
+	struct netdev_upper *upper;
+
+	WARN_ON_ONCE(!rcu_read_lock_held());
+
+	upper = list_entry_rcu((*iter)->next, struct netdev_upper, list);
+
+	if (&upper->list == &dev->upper_dev_list)
+		return NULL;
+
+	*iter = &upper->list;
+
+	return upper->dev;
+}
+EXPORT_SYMBOL(netdev_upper_get_next_dev);
+
 /**
  * netdev_master_upper_dev_get_rcu - Get master upper device
  * @dev: device
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v1 5/9] bonding: convert bond_has_this_ip() to use upper devices
From: Veaceslav Falico @ 2013-08-26 20:32 UTC (permalink / raw)
  To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377549162-7522-1-git-send-email-vfalico@redhat.com>

Currently, bond_has_this_ip() is aware only of vlan upper devices, and thus
will return false if the address is associated with the upper bridge or any
other device, and thus will break the arp logic.

Fix this by using the upper device list. For every upper device we verify
if the address associated with it is our address, and if yes - return true.

v1: use netdev_for_each_upper_dev()

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 drivers/net/bonding/bond_main.c |   25 +++++++++++++------------
 1 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 40eb250..dbac1ce 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2392,24 +2392,25 @@ re_arm:
 	}
 }
 
-static int bond_has_this_ip(struct bonding *bond, __be32 ip)
+static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
-	struct vlan_entry *vlan;
-	struct net_device *vlan_dev;
+	struct net_device *upper;
+	struct list_head *iter;
+	bool ret = false;
 
 	if (ip == bond_confirm_addr(bond->dev, 0, ip))
-		return 1;
+		return true;
 
-	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
-		rcu_read_lock();
-		vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q),
-						vlan->vlan_id);
-		rcu_read_unlock();
-		if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
-			return 1;
+	rcu_read_lock();
+	netdev_for_each_upper_dev(bond->dev, upper, iter) {
+		if (ip == bond_confirm_addr(upper, 0, ip)) {
+			ret = true;
+			break;
+		}
 	}
+	rcu_read_unlock();
 
-	return 0;
+	return ret;
 }
 
 /*
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next v1 0/9] bonding: remove vlan special handling
From: Veaceslav Falico @ 2013-08-26 20:32 UTC (permalink / raw)
  To: netdev
  Cc: Jay Vosburgh, Andy Gospodarek, David S. Miller, Eric Dumazet,
	Jiri Pirko, Alexander Duyck, Cong Wang, Veaceslav Falico

v1: Per Jiri's advice, remove the exported netdev_upper struct to keep it
    inside dev.c only, and instead implement a macro to iterate over the
    list and return only net_device *.

The aim of this patchset is to remove bondings' own vlan handling as much
as possible and replace it with the netdev upper device functionality.

This is achieved by adding a helper function to upper dev list handling -
netdev_upper_get_next_dev(dev, iter), which returns the next device after
the list_head **iter, and sets *iter to the next list_head *. This patchset
also adds netdev_for_each_upper_dev(dev, upper, iter), which iterates
through the whole dev->upper_dev_list, setting upper to the net_device.
The only special treatment of vlans remains in rlb code.

This patchset solves several issues with bonding, simplifies it overall,
RCUify further and exports upper list functions for any other users which
might also want to get rid of its own vlan_lists.

I'm testing it continuously currently, no issues found, will update on
anything.

CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>

---
 drivers/net/bonding/bond_alb.c  |   75 ++++++------
 drivers/net/bonding/bond_alb.h  |    2 -
 drivers/net/bonding/bond_main.c |  244 ++++++++-------------------------------
 drivers/net/bonding/bonding.h   |   21 +++-
 include/linux/netdevice.h       |   10 ++
 net/core/dev.c                  |   25 ++++
 6 files changed, 133 insertions(+), 244 deletions(-)

^ permalink raw reply

* [PATCH net-next v1 2/9] net: add netdev_for_each_upper_dev()
From: Veaceslav Falico @ 2013-08-26 20:32 UTC (permalink / raw)
  To: netdev
  Cc: Veaceslav Falico, David S. Miller, Eric Dumazet, Jiri Pirko,
	Alexander Duyck, Cong Wang
In-Reply-To: <1377549162-7522-1-git-send-email-vfalico@redhat.com>

The new macro netdev_for_each_upper_dev(dev, upper, iter) iterates through
the dev->upper_dev_list starting from the first element, using the
netdev_upper_get_next_dev(dev, &iter).

Must be called under RCU read lock.

v1: new patch

CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
 include/linux/netdevice.h |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 077363d..85590b6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2767,6 +2767,16 @@ extern int		bpf_jit_enable;
 extern bool netdev_has_upper_dev(struct net_device *dev,
 				 struct net_device *upper_dev);
 extern bool netdev_has_any_upper_dev(struct net_device *dev);
+extern struct net_device *netdev_upper_get_next_dev(struct net_device *dev,
+						    struct list_head **iter);
+
+/* iterate through upper list, must be called under RCU read lock */
+#define netdev_for_each_upper_dev(dev, upper, iter) \
+	for (iter = &(dev)->upper_dev_list, \
+	     upper = netdev_upper_get_next_dev(dev, &(iter)); \
+	     upper; \
+	     upper = netdev_upper_get_next_dev(dev, &(iter)))
+
 extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
 extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev);
 extern int netdev_upper_dev_link(struct net_device *dev,
-- 
1.7.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox