Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next-2.6 00/17] netdev: Fix queue count initialisation
From: Eric Dumazet @ 2010-09-28 12:07 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: David Miller, netdev, linux-net-drivers
In-Reply-To: <1285675327.2282.1.camel@achroite.uk.solarflarecom.com>

Le mardi 28 septembre 2010 à 13:02 +0100, Ben Hutchings a écrit :

> That seems a bit premature, as the driver maintainers have not had a
> chance to review these.  If it's not too late, perhaps you could roll
> these changes back for now.

I am afraid its not possible.

If you want to revert, please submit a patch.

However, changes should be small and we have some time before Linus
opens 2.6.37, dont you think ?




^ permalink raw reply

* [PATCH net-next-2.6] sit: fix percpu stats accounting
From: Eric Dumazet @ 2010-09-28 12:17 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

commit 15fc1f7056ebd (sit: percpu stats accounting) forgot the fallback
tunnel case (sit0), and can crash pretty fast.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/sit.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 011ecf5..2cb6460 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1160,7 +1160,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
 	return 0;
 }
 
-static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
+static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
 {
 	struct ip_tunnel *tunnel = netdev_priv(dev);
 	struct iphdr *iph = &tunnel->parms.iph;
@@ -1175,8 +1175,12 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev)
 	iph->ihl		= 5;
 	iph->ttl		= 64;
 
+	dev->tstats = alloc_percpu(struct pcpu_tstats);
+	if (!dev->tstats)
+		return -ENOMEM;
 	dev_hold(dev);
 	sitn->tunnels_wc[0]	= tunnel;
+	return 0;
 }
 
 static struct xfrm_tunnel sit_handler __read_mostly = {
@@ -1220,7 +1224,10 @@ static int __net_init sit_init_net(struct net *net)
 	}
 	dev_net_set(sitn->fb_tunnel_dev, net);
 
-	ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+	err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+	if (err)
+		goto err_dev_free;
+
 	ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
 
 	if ((err = register_netdev(sitn->fb_tunnel_dev)))
@@ -1230,7 +1237,8 @@ static int __net_init sit_init_net(struct net *net)
 
 err_reg_dev:
 	dev_put(sitn->fb_tunnel_dev);
-	free_netdev(sitn->fb_tunnel_dev);
+err_dev_free:
+	ipip6_dev_free(sitn->fb_tunnel_dev);
 err_alloc_dev:
 	return err;
 }



^ permalink raw reply related

* [PATCH net-next-2.6] sit: enable lockless xmits
From: Eric Dumazet @ 2010-09-28 12:53 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

SIT tunnels can benefit from lockless xmits, using NETIF_F_LLTX

Bench on a 16 cpus machine (dual E5540 cpus), 16 threads sending
10000000 UDP frames via one sit tunnel (size:220 bytes per frame)

Before patch : 

real	3m15.399s
user	0m9.185s
sys	51m55.403s

75029.00 87.5% _raw_spin_lock            vmlinux                                                             
 1090.00  1.3% dst_release               vmlinux                                                             
  902.00  1.1% dev_queue_xmit            vmlinux                                                             
  627.00  0.7% sock_wfree                vmlinux                                                             
  613.00  0.7% ip6_push_pending_frames   ipv6.ko
  505.00  0.6% __ip_route_output_key     vmlinux                                            

After patch:

real	1m1.387s
user	0m12.489s
sys	15m58.868s

28239.00 23.3% dst_release               vmlinux                                                             
13570.00 11.2% ip6_push_pending_frames   ipv6.ko
13118.00 10.8% ip6_append_data           ipv6.ko
 7995.00  6.6% __ip_route_output_key     vmlinux                                                             
 7924.00  6.5% sk_dst_check              vmlinux                                                             
 5015.00  4.1% udpv6_sendmsg             ipv6.ko
 3594.00  3.0% sock_alloc_send_pskb      vmlinux                                                             
 3135.00  2.6% sock_wfree                vmlinux                                                             
 3055.00  2.5% ip6_sk_dst_lookup         ipv6.ko
 2473.00  2.0% ip_finish_output          vmlinux               

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/sit.c |    1 +
 1 files changed, 1 insertion(+)

diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 011ecf5..d770178 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1140,6 +1140,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
 	dev->iflink		= 0;
 	dev->addr_len		= 4;
 	dev->features		|= NETIF_F_NETNS_LOCAL;
+	dev->features		|= NETIF_F_LLTX;
 }
 
 static int ipip6_tunnel_init(struct net_device *dev)



^ permalink raw reply related

* RE: [PATCH net-next-2.6 04/17] bnx2x: Use netif_set_real_num_{rx,tx}_queues()
From: Vladislav Zolotarov @ 2010-09-28 12:59 UTC (permalink / raw)
  To: Vladislav Zolotarov, Ben Hutchings, David Miller
  Cc: netdev@vger.kernel.org, linux-net-drivers@solarflare.com,
	Eilon Greenstein
In-Reply-To: <8628FE4E7912BF47A96AE7DD7BAC0AADDDEDAE6E96@SJEXCHCCR02.corp.ad.broadcom.com>



> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Vladislav Zolotarov
> Sent: Tuesday, September 28, 2010 11:26 AM
> To: Ben Hutchings; David Miller
> Cc: netdev@vger.kernel.org; linux-net-drivers@solarflare.com; Eilon
> Greenstein
> Subject: RE: [PATCH net-next-2.6 04/17] bnx2x: Use
> netif_set_real_num_{rx,tx}_queues()
> 
> 
> 
> > -----Original Message-----
> > From: netdev-owner@vger.kernel.org [mailto:netdev-
> > owner@vger.kernel.org] On Behalf Of Ben Hutchings
> > Sent: Monday, September 27, 2010 8:25 PM
> > To: David Miller
> > Cc: netdev@vger.kernel.org; linux-net-drivers@solarflare.com; Eilon
> > Greenstein
> > Subject: [PATCH net-next-2.6 04/17] bnx2x: Use
> > netif_set_real_num_{rx,tx}_queues()
> >
> > Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
> > ---
> >  drivers/net/bnx2x/bnx2x_cmn.c |    6 ++++--
> >  1 files changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/bnx2x/bnx2x_cmn.c
> > b/drivers/net/bnx2x/bnx2x_cmn.c
> > index efc7be4..05c05a4 100644
> > --- a/drivers/net/bnx2x/bnx2x_cmn.c
> > +++ b/drivers/net/bnx2x/bnx2x_cmn.c
> > @@ -1207,8 +1207,8 @@ static int bnx2x_set_num_queues(struct bnx2x
> *bp)
> >  			bp->num_queues = 1;
> >  		break;
> >  	}
> > -	bp->dev->real_num_tx_queues = bp->num_queues;
> > -	return rc;
> > +	netif_set_real_num_tx_queues(bp->dev, bp->num_queues);
> > +	return netif_set_real_num_rx_queues(bp->dev, bp->num_queues);
> >  }
> >
> >  static void bnx2x_release_firmware(struct bnx2x *bp)
> > @@ -1240,6 +1240,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int
> > load_mode)
> >  	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
> >
> >  	rc = bnx2x_set_num_queues(bp);
> > +	if (rc)
> > +		return rc;
> >
> >  	if (bnx2x_alloc_mem(bp)) {
> >  		bnx2x_free_irq(bp, true);
> > --
> > 1.7.2.1
> >
> 
> This patch breaks our interrupt enablement flow. I'll send the new one
> that incorporates the netif_set_real_num_rx_queues() shortly.

Ben, I'm going to fix the bnx2x the way your patch would apply. I suspect this would probably require u to respin the bnx2x patch.
Sorry for the inconvenience.

Thanks,
vlad

> 
> Thanks,
> vlad
> 
> >
> >
> > --
> > Ben Hutchings, Senior Software Engineer, Solarflare Communications
> > Not speaking for my employer; that's the marketing department's job.
> > They asked us to note that Solarflare product names are trademarked.
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe netdev" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> \x13��칻\x1c�&�~�&�\x18��+-��ݶ\x17��w��˛���m�޵ׯ�{ay�\x1dʇڙ�,j\r��f���h���z�\x1e�w���
> 
> ���j:+v���w�j�m����\r����zZ+�����ݢj"��!�i

^ permalink raw reply

* Re: [PATCH v11 13/17] Add mp(mediate passthru) device.
From: Michael S. Tsirkin @ 2010-09-28 13:06 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: xiaohui.xin, netdev, kvm, linux-kernel, mingo, davem, herbert,
	jdike, arnd
In-Reply-To: <1285622613.2263.550.camel@achroite.uk.solarflarecom.com>

On Mon, Sep 27, 2010 at 10:23:33PM +0100, Ben Hutchings wrote:
> > +/* The main function to transform the guest user space address
> > + * to host kernel address via get_user_pages(). Thus the hardware
> > + * can do DMA directly to the external buffer address.
> > + */
> > +static struct page_info *alloc_page_info(struct page_ctor *ctor,
> > +		struct kiocb *iocb, struct iovec *iov,
> > +		int count, struct frag *frags,
> > +		int npages, int total)
> > +{
> > +	int rc;
> > +	int i, j, n = 0;
> > +	int len;
> > +	unsigned long base, lock_limit;
> > +	struct page_info *info = NULL;
> > +
> > +	lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
> > +	lock_limit >>= PAGE_SHIFT;
> > +
> > +	if (ctor->lock_pages + count > lock_limit && npages) {
> > +		printk(KERN_INFO "exceed the locked memory rlimit.");
> > +		return NULL;
> > +	}
> 
> What if the process is locking pages with mlock() as well?  Doesn't this
> allow it to lock twice as many pages as it should be able to?

No, since locked_vm is incremented by both mp and mlock.
Or at least, that's the idea :)
In any case, twice as many would not be a big deal: admin can control
which processes can do this by controlling access to the device.

> > +	info = kmem_cache_alloc(ext_page_info_cache, GFP_KERNEL);
> > +	
> > +	if (!info)
> > +		return NULL;
> > +	info->skb = NULL;
> > +	info->next = info->prev = NULL;
> > +
> > +	for (i = j = 0; i < count; i++) {
> > +		base = (unsigned long)iov[i].iov_base;
> > +		len = iov[i].iov_len;
> > +
> > +		if (!len)
> > +			continue;
> > +		n = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT;
> > +
> > +		rc = get_user_pages_fast(base, n, npages ? 1 : 0,
> > +				&info->pages[j]);
> > +		if (rc != n)
> > +			goto failed;
> > +
> > +		while (n--) {
> > +			frags[j].offset = base & ~PAGE_MASK;
> > +			frags[j].size = min_t(int, len,
> > +					PAGE_SIZE - frags[j].offset);
> > +			len -= frags[j].size;
> > +			base += frags[j].size;
> > +			j++;
> > +		}
> > +	}
> > +
> > +#ifdef CONFIG_HIGHMEM
> > +	if (npages && !(dev->features & NETIF_F_HIGHDMA)) {
> > +		for (i = 0; i < j; i++) {
> > +			if (PageHighMem(info->pages[i]))
> > +				goto failed;
> > +		}
> > +	}
> > +#endif
> 
> Shouldn't you try to allocate lowmem pages explicitly, rather than
> failing at this point?

We don't allocate pages, we lock given pages. Once this is
integrated in macvtap presumably we'll fall back on data copy
for such devices.

...

> > +	skb_reserve(skb, NET_IP_ALIGN);
> > +	skb_put(skb, len);
> > +
> > +	if (skb_copy_datagram_from_iovec(skb, 0, iov, 0, len)) {
> > +		kfree_skb(skb);
> > +		return -EAGAIN;
> > +	}
> > +
> > +	skb->protocol = eth_type_trans(skb, mp->dev);
> 
> Why are you calling eth_type_trans() on transmit?

So that GSO can work.  BTW macvtap does:

        skb_set_network_header(skb, ETH_HLEN);
        skb_reset_mac_header(skb);
        skb->protocol = eth_hdr(skb)->h_proto;

and I think this is broken for vlans. Arnd?

-- 
MST

^ permalink raw reply

* Re: [PATCH v11 17/17]add two new ioctls for mp device.
From: Michael S. Tsirkin @ 2010-09-28 13:09 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: xiaohui.xin, netdev, kvm, linux-kernel, mingo, davem, herbert,
	jdike
In-Reply-To: <1285623375.2263.552.camel@achroite.uk.solarflarecom.com>

On Mon, Sep 27, 2010 at 10:36:15PM +0100, Ben Hutchings wrote:
> On Sat, 2010-09-25 at 12:27 +0800, xiaohui.xin@intel.com wrote:
> > From: Xin Xiaohui <xiaohui.xin@intel.com>
> > 
> > The patch add two ioctls for mp device.
> > One is for userspace to query how much memory locked to make mp device
> > run smoothly. Another one is for userspace to set how much meory locked
> > it really wants.
> [...]
> > diff --git a/include/linux/mpassthru.h b/include/linux/mpassthru.h
> > index ba8f320..083e9f7 100644
> > --- a/include/linux/mpassthru.h
> > +++ b/include/linux/mpassthru.h
> > @@ -7,6 +7,8 @@
> >  /* ioctl defines */
> >  #define MPASSTHRU_BINDDEV      _IOW('M', 213, int)
> >  #define MPASSTHRU_UNBINDDEV    _IO('M', 214)
> > +#define MPASSTHRU_SET_MEM_LOCKED	_IOW('M', 215, unsigned long)
> > +#define MPASSTHRU_GET_MEM_LOCKED_NEED	_IOR('M', 216, unsigned long)
> [...]
> 
> These will need compat handling.  You can avoid that by defining them to
> use a parameter type of u32 or u64.
> 
> Ben.

No need to introduce compat mess unless we have to.  I guess int is
sufficient: locking >= 2G just for guest networking is insane.

-- 
MST

^ permalink raw reply

* [PATCH net-next-2.6] ip6tnl: percpu stats accounting
From: Eric Dumazet @ 2010-09-28 13:23 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

Maintain per_cpu tx_bytes, tx_packets, rx_bytes, rx_packets.

Other seldom used fields are kept in netdev->stats structure, possibly
unsafe.

This is a preliminary work to support lockless transmit path, and
correct RX stats, that are already unsafe.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/ipv6/ip6_tunnel.c |   93 +++++++++++++++++++++++++++++++++-------
 1 files changed, 77 insertions(+), 16 deletions(-)

diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index f6d9f68..8be3c45 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL");
 		     (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
 		    (HASH_SIZE - 1))
 
-static void ip6_tnl_dev_init(struct net_device *dev);
+static int ip6_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_setup(struct net_device *dev);
 
 static int ip6_tnl_net_id __read_mostly;
@@ -88,6 +88,34 @@ struct ip6_tnl_net {
 	struct ip6_tnl __rcu **tnls[2];
 };
 
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+	unsigned long	rx_packets;
+	unsigned long	rx_bytes;
+	unsigned long	tx_packets;
+	unsigned long	tx_bytes;
+};
+
+static struct net_device_stats *ip6_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;
+}
+
 /*
  * Locking : hash tables are protected by RCU and RTNL
  */
@@ -216,6 +244,12 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t)
 	}
 }
 
+static void ip6_dev_free(struct net_device *dev)
+{
+	free_percpu(dev->tstats);
+	free_netdev(dev);
+}
+
 /**
  * ip6_tnl_create() - create a new tunnel
  *   @p: tunnel parameters
@@ -254,7 +288,9 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
 
 	t = netdev_priv(dev);
 	t->parms = *p;
-	ip6_tnl_dev_init(dev);
+	err = ip6_tnl_dev_init(dev);
+	if (err < 0)
+		goto failed_free;
 
 	if ((err = register_netdevice(dev)) < 0)
 		goto failed_free;
@@ -264,7 +300,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
 	return t;
 
 failed_free:
-	free_netdev(dev);
+	ip6_dev_free(dev);
 failed:
 	return NULL;
 }
@@ -700,6 +736,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
 
 	if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
 					&ipv6h->daddr)) != NULL) {
+		struct pcpu_tstats *tstats;
+
 		if (t->parms.proto != ipproto && t->parms.proto != 0) {
 			rcu_read_unlock();
 			goto discard;
@@ -722,7 +760,11 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
 		skb->pkt_type = PACKET_HOST;
 		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
 
-		skb_tunnel_rx(skb, t->dev);
+		tstats = this_cpu_ptr(t->dev->tstats);
+		tstats->rx_packets++;
+		tstats->rx_bytes += skb->len;
+
+		__skb_tunnel_rx(skb, t->dev);
 
 		dscp_ecn_decapsulate(t, ipv6h, skb);
 
@@ -935,8 +977,10 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 	err = ip6_local_out(skb);
 
 	if (net_xmit_eval(err) == 0) {
-		stats->tx_bytes += pkt_len;
-		stats->tx_packets++;
+		struct pcpu_tstats *tstats = this_cpu_ptr(t->dev->tstats);
+
+		tstats->tx_bytes += pkt_len;
+		tstats->tx_packets++;
 	} else {
 		stats->tx_errors++;
 		stats->tx_aborted_errors++;
@@ -1301,12 +1345,14 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
 
 
 static const struct net_device_ops ip6_tnl_netdev_ops = {
-	.ndo_uninit = ip6_tnl_dev_uninit,
+	.ndo_uninit	= ip6_tnl_dev_uninit,
 	.ndo_start_xmit = ip6_tnl_xmit,
-	.ndo_do_ioctl = ip6_tnl_ioctl,
+	.ndo_do_ioctl	= ip6_tnl_ioctl,
 	.ndo_change_mtu = ip6_tnl_change_mtu,
+	.ndo_get_stats	= ip6_get_stats,
 };
 
+
 /**
  * ip6_tnl_dev_setup - setup virtual tunnel device
  *   @dev: virtual device associated with tunnel
@@ -1318,7 +1364,7 @@ static const struct net_device_ops ip6_tnl_netdev_ops = {
 static void ip6_tnl_dev_setup(struct net_device *dev)
 {
 	dev->netdev_ops = &ip6_tnl_netdev_ops;
-	dev->destructor = free_netdev;
+	dev->destructor = ip6_dev_free;
 
 	dev->type = ARPHRD_TUNNEL6;
 	dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
@@ -1334,12 +1380,17 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
  *   @dev: virtual device associated with tunnel
  **/
 
-static inline void
+static inline int
 ip6_tnl_dev_init_gen(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
+
 	t->dev = dev;
 	strcpy(t->parms.name, dev->name);
+	dev->tstats = alloc_percpu(struct pcpu_tstats);
+	if (!dev->tstats)
+		return -ENOMEM;
+	return 0;
 }
 
 /**
@@ -1347,11 +1398,15 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
  *   @dev: virtual device associated with tunnel
  **/
 
-static void ip6_tnl_dev_init(struct net_device *dev)
+static int ip6_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
-	ip6_tnl_dev_init_gen(dev);
+	int err = ip6_tnl_dev_init_gen(dev);
+
+	if (err)
+		return err;
 	ip6_tnl_link_config(t);
+	return 0;
 }
 
 /**
@@ -1361,16 +1416,20 @@ static void ip6_tnl_dev_init(struct net_device *dev)
  * Return: 0
  **/
 
-static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
+static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev)
 {
 	struct ip6_tnl *t = netdev_priv(dev);
 	struct net *net = dev_net(dev);
 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+	int err = ip6_tnl_dev_init_gen(dev);
+
+	if (err)
+		return err;
 
-	ip6_tnl_dev_init_gen(dev);
 	t->parms.proto = IPPROTO_IPV6;
 	dev_hold(dev);
 	rcu_assign_pointer(ip6n->tnls_wc[0], t);
+	return 0;
 }
 
 static struct xfrm6_tunnel ip4ip6_handler __read_mostly = {
@@ -1420,7 +1479,9 @@ static int __net_init ip6_tnl_init_net(struct net *net)
 		goto err_alloc_dev;
 	dev_net_set(ip6n->fb_tnl_dev, net);
 
-	ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+	err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev);
+	if (err < 0)
+		goto err_register;
 
 	err = register_netdev(ip6n->fb_tnl_dev);
 	if (err < 0)
@@ -1428,7 +1489,7 @@ static int __net_init ip6_tnl_init_net(struct net *net)
 	return 0;
 
 err_register:
-	free_netdev(ip6n->fb_tnl_dev);
+	ip6_dev_free(ip6n->fb_tnl_dev);
 err_alloc_dev:
 	return err;
 }



^ permalink raw reply related

* Re: [PATCH v4 1/2] HID: Add Support for Setting and Getting Feature Reports from hidraw
From: Antonio Ospite @ 2010-09-28 13:30 UTC (permalink / raw)
  To: Alan Ott
  Cc: Jiri Kosina, Stefan Achatz, Alexey Dobriyan, Tejun Heo,
	Alan Stern, Greg Kroah-Hartman, Marcel Holtmann, Stephane Chatty,
	Michael Poole, David S. Miller, Bastien Nocera, Eric Dumazet,
	linux-input, linux-kernel, linux-usb, linux-bluetooth, netdev
In-Reply-To: <1281990059-3562-2-git-send-email-alan@signal11.us>


[-- Attachment #1.1: Type: text/plain, Size: 2624 bytes --]

On Mon, 16 Aug 2010 16:20:58 -0400
Alan Ott <alan@signal11.us> wrote:

> Per the HID Specification, Feature reports must be sent and received on
> the Configuration endpoint (EP 0) through the Set_Report/Get_Report
> interfaces.  This patch adds two ioctls to hidraw to set and get feature
> reports to and from the device.  Modifications were made to hidraw and
> usbhid.
> 
> New hidraw ioctls:
>   HIDIOCSFEATURE - Perform a Set_Report transfer of a Feature report.
>   HIDIOCGFEATURE - Perform a Get_Report transfer of a Feature report.
> 
> Signed-off-by: Alan Ott <alan@signal11.us>

Hi Alan, I am doing some stress testing on hidraw, if I have a loop with
HIDIOCGFEATURE on a given report and I disconnect the device while the
loop is running I get this:

BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]

Full log attached along with the test program, the device is a Sony PS3
Controller (sixaxis).

If my objdump analysis is right, hidraw_ioctl+0xfc should be around line
361 in hidraw.c (with your patch applied):

struct hid_device *hid = dev->hid;

It looks like 'dev' (which is hidraw_table[minor]) can be NULL
sometimes, can't it?
This is not introduced by your changes tho.

Just as a side note, the bug does not show up if the userspace program
handles return values properly and exits as soon as it gets an error
from the HID layer, see the XXX comment in test_hidraw_feature.c.

This fixes it, if it looks ok I will resend the patch rebased on
mainline code:

diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 7df1310..3c040c6 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -322,6 +322,10 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,

        mutex_lock(&minors_lock);
        dev = hidraw_table[minor];
+       if (!dev) {
+               ret = -ENODEV;
+               goto out;
+       }

        switch (cmd) {
                case HIDIOCGRDESCSIZE:
@@ -412,6 +416,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,

                ret = -ENOTTY;
        }
+out:
        mutex_unlock(&minors_lock);
        return ret;
 }


this change covers also the other uses of hidraw_table[minor] in
hidraw_send_report/hidraw_get_report.

Regards,
   Antonio

-- 
Antonio Ospite
http://ao2.it

PGP public key ID: 0x4553B001

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

[-- Attachment #1.2: dmesg_hidraw_feature_bug.log --]
[-- Type: application/octet-stream, Size: 3914 bytes --]

[  111.645836] usb 4-1: USB disconnect, address 2
[  111.669466] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[  111.669484] IP: [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]
[  111.669529] PGD 5a953067 PUD 6d741067 PMD 0 
[  111.669539] Oops: 0000 [#1] SMP 
[  111.669545] last sysfs file: /sys/devices/pci0000:00/0000:00:04.0/usb4/idVendor
[  111.669556] CPU 0 
[  111.669559] Modules linked in: hidp powernow_k8 mperf cpufreq_powersave cpufreq_conservative cpufreq_stats cpufreq_userspace lirc_serial(C) lirc_dev ipt_MASQUERADE bridge stp ppdev lp sco bnep rfcomm l2cap crc16 tun sit tunnel4 kvm_amd kvm binfmt_misc uinput fuse nfsd ip6table_raw ip6table_mangle ip6t_REJECT exportfs nfs ip6t_LOG lockd fscache nf_conntrack_ipv6 nfs_acl auth_rpcgss ip6table_filter sunrpc ip6_tables xt_tcpudp ipt_REJECT ipt_ULOG xt_limit xt_state xt_multiport iptable_filter iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 iptable_mangle iptable_raw ip_tables x_tables hwmon_vid loop snd_hda_codec_nvhdmi snd_hda_codec_via snd_hda_intel snd_hda_codec snd_hwdep snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_midi snd_rawmidi nvidia(P) snd_seq_midi_event snd_seq parport_pc btusb snd_timer snd_seq_device asus_atk0110 joydev video snd bluetooth rfkill hid_sony output wmi parport edac_core i2c_nforce2 tpm_tis shpchp pci_hotplug k8temp edac_mce_amd pcspkr tpm tpm_bios evdev soundcore snd_page_alloc i2c_core button processor ext3 jbd mbcache dm_mod sg sr_mod sd_mod crc_t10dif cdrom ata_generic usbhid hid ahci libahci pata_amd ohci_hcd libata ehci_hcd scsi_mod usbcore thermal forcedeth nls_base thermal_sys floppy [last unloaded: scsi_wait_scan]
[  111.669736] 
[  111.669746] Pid: 2969, comm: test_hidraw_fea Tainted: P         C  2.6.36-rc5-ao2+ #1 M3N78-VM/System Product Name
[  111.669753] RIP: 0010:[<ffffffffa02c66b4>]  [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]
[  111.669771] RSP: 0018:ffff880056831e78  EFLAGS: 00010206
[  111.669776] RAX: 0000000000000048 RBX: 00000000c02d4807 RCX: 00000000022c7e50
[  111.669783] RDX: 0000000100000000 RSI: ffffffff810377e0 RDI: ffffffffa02ceaa0
[  111.669789] RBP: 00000000022c7e50 R08: 00007f983f1cbec8 R09: 0000000000400aca
[  111.669795] R10: ffffffff8100769f R11: ffff880037a78dd8 R12: ffff88005a85c300
[  111.669801] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[  111.669808] FS:  00007f983f3cc700(0000) GS:ffff880001a00000(0000) knlGS:0000000000000000
[  111.669815] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  111.669821] CR2: 0000000000000028 CR3: 000000005aba9000 CR4: 00000000000006f0
[  111.669827] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  111.669833] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[  111.669840] Process test_hidraw_fea (pid: 2969, threadinfo ffff880056830000, task ffff88005ab93680)
[  111.669844] Stack:
[  111.669848]  00000000010aad14 ffff88005ab936b8 ffff88005a85c300 ffff880037fc6700
[  111.669857] <0> 00000000022c7e50 00000000022c7e50 0000000000000000 ffffffff810f64a5
[  111.669865] <0> ffff880001a14880 ffff88005ab93680 ffffffff81302776 0000000000000000
[  111.669875] Call Trace:
[  111.669898]  [<ffffffff810f64a5>] ? do_vfs_ioctl+0x4a2/0x4ef
[  111.669915]  [<ffffffff81302776>] ? schedule+0x573/0x5b7
[  111.669923]  [<ffffffff810f653d>] ? sys_ioctl+0x4b/0x72
[  111.669933]  [<ffffffff810ea002>] ? sys_write+0x5f/0x6b
[  111.669947]  [<ffffffff81008a02>] ? system_call_fastpath+0x16/0x1b
[  111.669952] Code: 2c 66 89 44 24 06 e8 1a c2 03 e1 48 89 e6 ba 08 00 00 00 48 89 ef e8 cc 79 ec e0 85 c0 0f 84 18 02 00 00 e9 01 02 00 00 0f b6 c7 <49> 8b 7d 28 83 f8 48 0f 85 fa 01 00 00 0f b6 c3 83 f8 06 75 24 
[  111.670011] RIP  [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]
[  111.670025]  RSP <ffff880056831e78>
[  111.670029] CR2: 0000000000000028
[  111.670036] ---[ end trace 9c7530cfc7009202 ]---

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: test_hidraw_feature.c --]
[-- Type: text/x-csrc; name="test_hidraw_feature.c", Size: 1265 bytes --]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

/*
#include <linux/hidraw.h>
*/
#include "/home/ao2/Proj/linux/linux-2.6/include/linux/hidraw.h"

void dump_hex_string(unsigned char *buf, unsigned int len)
{
	unsigned int i;

	for (i = 0; i < len; i++)
		printf("%02x%c", buf[i], i < len - 1 ? ' ' : 0);
}

void dump_feature_report(int fd, uint8_t report_number, unsigned int len)
{
	unsigned char *buf;
	int ret;

	buf = calloc(len, sizeof(*buf));

	buf[0] = report_number;

	ret = ioctl(fd, HIDIOCGFEATURE(len), buf);
	if (ret < 0) {
		fprintf(stderr, "report: 0x%02x ret: %d\n", report_number, ret);
		/* XXX: if I put exit(1) here the bug is masked */
		return;
	}

	dump_hex_string(buf, len);
	printf("\r");
	fflush(stdout);

	free(buf);
}

int main(int argc, char *argv[])
{
	int fd = -1;

	if (argc != 2) {
		fprintf(stderr, "usage: %s </dev/hidrawX>\n", argv[0]);
		exit(1);
	}

	fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		perror("hidraw open");
		exit(1);
	}

	while (1)
		dump_feature_report(fd, 0x01, 45);
	printf("\n");

	close(fd);
	exit(0);
}

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply related

* [PATCH net-next 2.6] myri10ge: DCA update
From: Andrew Gallatin @ 2010-09-28 13:41 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Loic Prylli

[-- Attachment #1: Type: text/plain, Size: 758 bytes --]

This patch contains the following DCA improvements to myri10ge:

1) Finally move myri10ge to use dca3 API

2) Disable PCIe relaxed ordering when enabling DCA on
     myri10ge.  This provides a performance boost on Nehalem
     based Xeons

3) Make sure to properly initialize NIC's DCA state when it is enabled,
     rather than giving the NIC a bogus tag (0) and waiting for
     the first received packet to trigger an update.  Not using a
     real tag can cause hardware exceptions on some motherboards
     when a CPU socket is empty.

3) Always update the cached CPU when our interrupt affinity changes
     so as to avoid excessive calls to dca3_get_tag()

Signed-off-by: Andrew Gallatin <gallatin@myri.com>
Signed-off-by: Loic Prylli <loic@myri.com>

[-- Attachment #2: myri10ge_dca.diff --]
[-- Type: text/x-diff, Size: 2222 bytes --]

diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 4f3a3c0..545d481 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -225,6 +225,7 @@ struct myri10ge_priv {
 	struct msix_entry *msix_vectors;
 #ifdef CONFIG_MYRI10GE_DCA
 	int dca_enabled;
+	int relaxed_order;
 #endif
 	u32 link_state;
 	unsigned int rdma_tags_available;
@@ -1074,10 +1075,29 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
 }
 
 #ifdef CONFIG_MYRI10GE_DCA
+static int
+myri10ge_toggle_relaxed(struct pci_dev *pdev, int on)
+{
+	int ret, cap, err;
+	u16 ctl;
+
+	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (!cap)
+		return (0);
+
+	err = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+	ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4;
+	if (ret != on) {
+		ctl &= ~PCI_EXP_DEVCTL_RELAX_EN;
+		ctl |= (on << 4);
+		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+	}
+	return (ret);	
+}
+
 static void
 myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
 {
-	ss->cpu = cpu;
 	ss->cached_dca_tag = tag;
 	put_be32(htonl(tag), ss->dca_tag);
 }
@@ -1088,9 +1108,10 @@ static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss)
 	int tag;
 
 	if (cpu != ss->cpu) {
-		tag = dca_get_tag(cpu);
+		tag = dca3_get_tag(&ss->mgp->pdev->dev, cpu);
 		if (ss->cached_dca_tag != tag)
 			myri10ge_write_dca(ss, cpu, tag);
+		ss->cpu = cpu;
 	}
 	put_cpu();
 }
@@ -1113,9 +1134,13 @@ static void myri10ge_setup_dca(struct myri10ge_priv *mgp)
 				"dca_add_requester() failed, err=%d\n", err);
 		return;
 	}
+	mgp->relaxed_order = myri10ge_toggle_relaxed(pdev, 0);
 	mgp->dca_enabled = 1;
-	for (i = 0; i < mgp->num_slices; i++)
-		myri10ge_write_dca(&mgp->ss[i], -1, 0);
+	for (i = 0; i < mgp->num_slices; i++) {
+		mgp->ss[i].cpu = -1;
+		mgp->ss[i].cached_dca_tag = -1;
+		myri10ge_update_dca(&mgp->ss[i]);
+	 }
 }
 
 static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
@@ -1126,6 +1151,8 @@ static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
 	if (!mgp->dca_enabled)
 		return;
 	mgp->dca_enabled = 0;
+	if (mgp->relaxed_order)
+		myri10ge_toggle_relaxed(pdev, 1);
 	err = dca_remove_requester(&pdev->dev);
 }
 

^ permalink raw reply related

* Re: [PATCH net-next 2.6] myri10ge: DCA update
From: Eric Dumazet @ 2010-09-28 14:21 UTC (permalink / raw)
  To: Andrew Gallatin; +Cc: David Miller, netdev, Loic Prylli
In-Reply-To: <4CA1F06E.3070109@myri.com>

Le mardi 28 septembre 2010 à 09:41 -0400, Andrew Gallatin a écrit :
> This patch contains the following DCA improvements to myri10ge:
> 
> 1) Finally move myri10ge to use dca3 API
> 
> 2) Disable PCIe relaxed ordering when enabling DCA on
>      myri10ge.  This provides a performance boost on Nehalem
>      based Xeons
> 
> 3) Make sure to properly initialize NIC's DCA state when it is enabled,
>      rather than giving the NIC a bogus tag (0) and waiting for
>      the first received packet to trigger an update.  Not using a
>      real tag can cause hardware exceptions on some motherboards
>      when a CPU socket is empty.
> 
> 3) Always update the cached CPU when our interrupt affinity changes
>      so as to avoid excessive calls to dca3_get_tag()
> 
> Signed-off-by: Andrew Gallatin <gallatin@myri.com>
> Signed-off-by: Loic Prylli <loic@myri.com>

ERROR: return is not a function, parentheses are not required
#99: FILE: drivers/net/myri10ge/myri10ge.c:1086:
+		return (0);

ERROR: trailing whitespace
#108: FILE: drivers/net/myri10ge/myri10ge.c:1095:
+^Ireturn (ret);^I$

ERROR: return is not a function, parentheses are not required
#108: FILE: drivers/net/myri10ge/myri10ge.c:1095:
+	return (ret);	

total: 3 errors, 0 warnings, 71 lines checked



^ permalink raw reply

* [PATCH] net: pxa168_etc.c  recognize additional contributors
From: Philip Rakity @ 2010-09-28 14:26 UTC (permalink / raw)
  To: netdev@vger.kernel.org; +Cc: Mark Brown, Sachin Sanap

Signed-off-by: Philip Rakity <prakity@marvell.com>
Signed-off-by: Sachin Sanap <ssanap@marvell.com>
Signed-off-by: Mark Brown <markb@marvell.com>
---
 drivers/net/pxa168_eth.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c
index c6eeb38..0f2d41b 100644
--- a/drivers/net/pxa168_eth.c
+++ b/drivers/net/pxa168_eth.c
@@ -4,8 +4,10 @@
  *
  * Copyright (C) 2010 Marvell International Ltd.
  *		Sachin Sanap <ssanap@marvell.com>
+ *		Zhangfei Gao <zgao6@marvell.com>
  *		Philip Rakity <prakity@marvell.com>
  *		Mark Brown <markb@marvell.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH v11 13/17] Add mp(mediate passthru) device.
From: Arnd Bergmann @ 2010-09-28 14:39 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Ben Hutchings, xiaohui.xin, netdev, kvm, linux-kernel, mingo,
	davem, herbert, jdike, Sridhar Samudrala
In-Reply-To: <20100928130654.GD14385@redhat.com>

On Tuesday 28 September 2010, Michael S. Tsirkin wrote:
> > > +   skb_reserve(skb, NET_IP_ALIGN);
> > > +   skb_put(skb, len);
> > > +
> > > +   if (skb_copy_datagram_from_iovec(skb, 0, iov, 0, len)) {
> > > +           kfree_skb(skb);
> > > +           return -EAGAIN;
> > > +   }
> > > +
> > > +   skb->protocol = eth_type_trans(skb, mp->dev);
> > 
> > Why are you calling eth_type_trans() on transmit?
> 
> So that GSO can work.  BTW macvtap does:
> 
>         skb_set_network_header(skb, ETH_HLEN);
>         skb_reset_mac_header(skb);
>         skb->protocol = eth_hdr(skb)->h_proto;
> 
> and I think this is broken for vlans. Arnd?

Hmm, that code (besides set_network_header) was added by Sridhar
for GSO support. I believe I originally did eth_type_trans but
had to change it before that time because it broke something.
Unfortunately, my memory on that is not very good any more.

Can you be more specific what the problem is? Do you think
it breaks when a guest sends VLAN tagged frames or when macvtap
is connected to a VLAN interface that adds another tag (or
only the combination)?

	Arnd

^ permalink raw reply

* [PATCH net-next-2.6] bnx2x: Moved enabling of MSI to the bnx2x_set_num_queues()
From: Vladislav Zolotarov @ 2010-09-28 14:42 UTC (permalink / raw)
  To: Dave Miller; +Cc: Eilon Greenstein, netdev list

Moved enabling of MSI to the bnx2x_set_num_queues() - the same functions that
handles the initialization of the MSI-X.

Signed-off-by: Vladislav Zolotarov <vladz@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---

This patch is required for the integration of Ben Hutchings bnx2x patch from
the "netif_set_real_num_{rx,tx}_queues" patch series.

 drivers/net/bnx2x/bnx2x_cmn.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index efc7be4..453d3b6 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -1185,8 +1185,10 @@ static int bnx2x_set_num_queues(struct bnx2x *bp)
 	int rc = 0;
 
 	switch (bp->int_mode) {
-	case INT_MODE_INTx:
 	case INT_MODE_MSI:
+		bnx2x_enable_msi(bp);
+		/* falling through... */
+	case INT_MODE_INTx:
 		bp->num_queues = 1;
 		DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
 		break;
@@ -1202,9 +1204,16 @@ static int bnx2x_set_num_queues(struct bnx2x *bp)
 		 * and fallback to MSI or legacy INTx with one fp
 		 */
 		rc = bnx2x_enable_msix(bp);
-		if (rc)
+		if (rc) {
 			/* failed to enable MSI-X */
 			bp->num_queues = 1;
+
+			/* Fall to INTx if failed to enable MSI-X due to lack of
+			 * memory (in bnx2x_set_num_queues()) */
+			if ((rc != -ENOMEM) && (bp->int_mode != INT_MODE_INTx))
+				bnx2x_enable_msi(bp);
+		}
+
 		break;
 	}
 	bp->dev->real_num_tx_queues = bp->num_queues;
@@ -1263,10 +1272,6 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 			goto load_error1;
 		}
 	} else {
-		/* Fall to INTx if failed to enable MSI-X due to lack of
-		   memory (in bnx2x_set_num_queues()) */
-		if ((rc != -ENOMEM) && (bp->int_mode != INT_MODE_INTx))
-			bnx2x_enable_msi(bp);
 		bnx2x_ack_int(bp);
 		rc = bnx2x_req_irq(bp);
 		if (rc) {
-- 
1.7.0.4





^ permalink raw reply related

* Re: [PATCH v11 13/17] Add mp(mediate passthru) device.
From: Michael S. Tsirkin @ 2010-09-28 14:43 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Ben Hutchings, xiaohui.xin, netdev, kvm, linux-kernel, mingo,
	davem, herbert, jdike, Sridhar Samudrala
In-Reply-To: <201009281639.59417.arnd@arndb.de>

On Tue, Sep 28, 2010 at 04:39:59PM +0200, Arnd Bergmann wrote:
> On Tuesday 28 September 2010, Michael S. Tsirkin wrote:
> > > > +   skb_reserve(skb, NET_IP_ALIGN);
> > > > +   skb_put(skb, len);
> > > > +
> > > > +   if (skb_copy_datagram_from_iovec(skb, 0, iov, 0, len)) {
> > > > +           kfree_skb(skb);
> > > > +           return -EAGAIN;
> > > > +   }
> > > > +
> > > > +   skb->protocol = eth_type_trans(skb, mp->dev);
> > > 
> > > Why are you calling eth_type_trans() on transmit?
> > 
> > So that GSO can work.  BTW macvtap does:
> > 
> >         skb_set_network_header(skb, ETH_HLEN);
> >         skb_reset_mac_header(skb);
> >         skb->protocol = eth_hdr(skb)->h_proto;
> > 
> > and I think this is broken for vlans. Arnd?
> 
> Hmm, that code (besides set_network_header) was added by Sridhar
> for GSO support. I believe I originally did eth_type_trans but
> had to change it before that time because it broke something.
> Unfortunately, my memory on that is not very good any more.
> 
> Can you be more specific what the problem is? Do you think
> it breaks when a guest sends VLAN tagged frames or when macvtap
> is connected to a VLAN interface that adds another tag (or
> only the combination)?
> 
> 	Arnd

I expect the protocol value to be wrong when guest sends vlan tagged
frames as 802.1q frames have a different format.

-- 
MST

^ permalink raw reply

* Re: [PATCH net-next 2.6] myri10ge: DCA update
From: Andrew Gallatin @ 2010-09-28 15:00 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev, Loic Prylli
In-Reply-To: <1285683683.3154.66.camel@edumazet-laptop>

[-- Attachment #1: Type: text/plain, Size: 780 bytes --]


> total: 3 errors, 0 warnings, 71 lines checked

Sorry! From googling, this seems to be checkpatch.pl output,
which I now know that I'm supposed to run before submitting
a patch.

Please accept my apologies.  Brice is no longer maintaining the
in-kernel version of myri10ge, and I'm trying to get some improvements
and fixes we've done for our vendor driver merged, so the in-kernel
version does not lag too far behind.  I'm pretty new to dealing
directly with the linux kernel lists, so I apologize for my
mistakes.

I've corrected the style problems pointed out by checkpatch, and
I've attached a new diff.  Is that sufficient, or do I start a
new thread, or..?

Thank you,

Drew

Signed-off-by: Andrew Gallatin <gallatin@myri.com>
Signed-off-by: Loic Prylli <loic@myri.com>



[-- Attachment #2: myri10ge_dca_2.diff --]
[-- Type: text/x-diff, Size: 2216 bytes --]

diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 4f3a3c0..02dd92e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -225,6 +225,7 @@ struct myri10ge_priv {
 	struct msix_entry *msix_vectors;
 #ifdef CONFIG_MYRI10GE_DCA
 	int dca_enabled;
+	int relaxed_order;
 #endif
 	u32 link_state;
 	unsigned int rdma_tags_available;
@@ -1074,10 +1075,28 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
 }
 
 #ifdef CONFIG_MYRI10GE_DCA
+static int myri10ge_toggle_relaxed(struct pci_dev *pdev, int on)
+{
+	int ret, cap, err;
+	u16 ctl;
+
+	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (!cap)
+		return 0;
+
+	err = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+	ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4;
+	if (ret != on) {
+		ctl &= ~PCI_EXP_DEVCTL_RELAX_EN;
+		ctl |= (on << 4);
+		pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+	}
+	return ret;
+}
+
 static void
 myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
 {
-	ss->cpu = cpu;
 	ss->cached_dca_tag = tag;
 	put_be32(htonl(tag), ss->dca_tag);
 }
@@ -1088,9 +1107,10 @@ static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss)
 	int tag;
 
 	if (cpu != ss->cpu) {
-		tag = dca_get_tag(cpu);
+		tag = dca3_get_tag(&ss->mgp->pdev->dev, cpu);
 		if (ss->cached_dca_tag != tag)
 			myri10ge_write_dca(ss, cpu, tag);
+		ss->cpu = cpu;
 	}
 	put_cpu();
 }
@@ -1113,9 +1133,13 @@ static void myri10ge_setup_dca(struct myri10ge_priv *mgp)
 				"dca_add_requester() failed, err=%d\n", err);
 		return;
 	}
+	mgp->relaxed_order = myri10ge_toggle_relaxed(pdev, 0);
 	mgp->dca_enabled = 1;
-	for (i = 0; i < mgp->num_slices; i++)
-		myri10ge_write_dca(&mgp->ss[i], -1, 0);
+	for (i = 0; i < mgp->num_slices; i++) {
+		mgp->ss[i].cpu = -1;
+		mgp->ss[i].cached_dca_tag = -1;
+		myri10ge_update_dca(&mgp->ss[i]);
+	 }
 }
 
 static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
@@ -1126,6 +1150,8 @@ static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
 	if (!mgp->dca_enabled)
 		return;
 	mgp->dca_enabled = 0;
+	if (mgp->relaxed_order)
+		myri10ge_toggle_relaxed(pdev, 1);
 	err = dca_remove_requester(&pdev->dev);
 }
 

^ permalink raw reply related

* Re: [PATCH v11 13/17] Add mp(mediate passthru) device.
From: Arnd Bergmann @ 2010-09-28 15:18 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Ben Hutchings, xiaohui.xin, netdev, kvm, linux-kernel, mingo,
	davem, herbert, jdike, Sridhar Samudrala
In-Reply-To: <20100928144311.GB15294@redhat.com>

On Tuesday 28 September 2010, Michael S. Tsirkin wrote:
> On Tue, Sep 28, 2010 at 04:39:59PM +0200, Arnd Bergmann wrote:
> > Can you be more specific what the problem is? Do you think
> > it breaks when a guest sends VLAN tagged frames or when macvtap
> > is connected to a VLAN interface that adds another tag (or
> > only the combination)?
>
> I expect the protocol value to be wrong when guest sends vlan tagged
> frames as 802.1q frames have a different format.

Ok, I see. Would that be fixed by using eth_type_trans()? I don't
see any code in there that tries to deal with the VLAN tag, so
do we have the same problem in the tun/tap driver?

Also, I wonder how we handle the case where both the guest and
the host do VLAN tagging. Does the host transparently override
the guest tag, or does it add a nested tag? More importantly,
what should it do?

	Arnd

^ permalink raw reply

* [PATCH] ipv4: remove all rt cache entries on UNREGISTER event
From: Nicolas Dichtel @ 2010-09-28 15:24 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]

Hi,

I face a problem when I try to remove an interface, 
netdev_wait_allrefs() complains about refcount.

Here is a trivial scenario to reproduce the problem:
# ip tunnel add mode ipip remote 10.16.0.164 local 10.16.0.72 dev eth0
# ./a.out tunl1
# ip tunnel del tunl1

Note: a.out binary create an IPv4 raw socket, attach it to tunl1 
(SO_BINDTODEVICE), set it as multicast (IP_MULTICAST_LOOP), set the 
multicast interface to tunl1 (IP_MULTICAST_IF), build the IP header 
(IP_HDRINCL) and then send a single packet (192.168.6.1 -> 224.0.0.18).

Note2: when a.out is executed, tunl1 has no ip address and is down.

Then, I got a serie of "kernel:[1206699.728010] unregister_netdevice: 
waiting for tunl1 to become free. Usage count = 3" and after some time, 
interface is removed.

The problem is that route cache entries are only invalidate on 
UNREGISTER event, and not removed (introduced by commit 
e2ce146848c81af2f6d42e67990191c284bf0c33). We must wait that 
rt_check_expire() remove the remaining route cache entries.

To fix the problem, I propose to remove a part of the previous commit.

Regards,
Nicolas

[-- Attachment #2: 0001-ipv4-remove-all-rt-cache-entries-on-UNREGISTER-even.patch --]
[-- Type: text/x-diff, Size: 2258 bytes --]

>From 3344e2e0431fe803c4dac8757a8746908357d780 Mon Sep 17 00:00:00 2001
From: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Date: Tue, 28 Sep 2010 16:38:19 +0200
Subject: [PATCH] ipv4: remove all rt cache entries on UNREGISTER event

Commit e2ce146848c81af2f6d42e67990191c284bf0c33 (ipv4: factorize cache clearing
for batched unregister operations) add a new parameter to fib_disable_ip() to
only invalidate route cache entries on unregister event.
This is wrong, we should ensure that all cache entries are removed on
unregister event, else netdev_wait_allrefs() may complain. A cache entry
can be created between event DOWN and UNREGISTER.

So, I revert a part of the patch.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
 net/ipv4/fib_frontend.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 7d02a9f..377e815 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -917,11 +917,11 @@ static void nl_fib_lookup_exit(struct net *net)
 	net->ipv4.fibnl = NULL;
 }
 
-static void fib_disable_ip(struct net_device *dev, int force, int delay)
+static void fib_disable_ip(struct net_device *dev, int force)
 {
 	if (fib_sync_down_dev(dev, force))
 		fib_flush(dev_net(dev));
-	rt_cache_flush(dev_net(dev), delay);
+	rt_cache_flush(dev_net(dev), 0);
 	arp_ifdown(dev);
 }
 
@@ -944,7 +944,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
 			/* Last address was deleted from this interface.
 			   Disable IP.
 			 */
-			fib_disable_ip(dev, 1, 0);
+			fib_disable_ip(dev, 1);
 		} else {
 			rt_cache_flush(dev_net(dev), -1);
 		}
@@ -959,7 +959,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
 	if (event == NETDEV_UNREGISTER) {
-		fib_disable_ip(dev, 2, -1);
+		fib_disable_ip(dev, 2);
 		return NOTIFY_DONE;
 	}
 
@@ -977,7 +977,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
 		rt_cache_flush(dev_net(dev), -1);
 		break;
 	case NETDEV_DOWN:
-		fib_disable_ip(dev, 0, 0);
+		fib_disable_ip(dev, 0);
 		break;
 	case NETDEV_CHANGEMTU:
 	case NETDEV_CHANGE:
-- 
1.5.6.5


^ permalink raw reply related

* Re:
From: Christoph Lameter @ 2010-09-28 15:49 UTC (permalink / raw)
  To: David Stevens
  Cc: Jason Gunthorpe, linux-rdma, netdev, David Miller, Bob Arendt
In-Reply-To: <OF980F8B87.D755A28E-ON882577AB.00779881-882577AB.0077F27A@us.ibm.com>

On Mon, 27 Sep 2010, David Stevens wrote:

>         No. I'm not talking about the force_igmp_tunable here, I'm talking
> about the per-interface robustness and interval settings which come from
> the querier (whatever version you are using).

The igmp subsystem currently does not keep state on the interface layer
about robustness etc. An interval setting is only kept for IGMP v3 and
used only for general query timeouts with igmp V3. The interval is
different one from the one used for the host membership reports.

Looking at the spec I get the impression that these variables seems to be
mainly of interest to router to router communications?




^ permalink raw reply

* Re: [PATCH net-next-2.6 0/5] XFRM,IPv6: Removal of RH2/HAO from IPsec-protected MIPv6 traffic
From: Arnaud Ebalard @ 2010-09-28 15:53 UTC (permalink / raw)
  To: David Miller; +Cc: eric.dumazet, herbert, yoshfuji, netdev
In-Reply-To: <20100927.212541.183056184.davem@davemloft.net>

Hi David,

David Miller <davem@davemloft.net> writes:

> Please resubmit this after you've done some more exhaustive
> build testing:

I spent some time on it today. An updated version follows. 

^ permalink raw reply

* [PATCHv2 net-next-2.6 0/5] XFRM,IPv6: Removal of RH2/HAO from IPsec-protected MIPv6 traffic
From: Arnaud Ebalard @ 2010-09-28 15:53 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev

Hi,

This an updated version of the patches. For reference, introduction of
the feature is here http://thread.gmane.org/gmane.linux.network/172941
Just tell me if you prefer I resend the full intro each time.

Compared to initial version, this v2 is

 - against net-next-2.6
 - fixed and more exhaustively build tested for various kernel
   configuration (w/ and w/o IPv6, IPv4, MIPv6, XFRM*, RO, ...).
   It adds some #ifdef but I did not found good ways to spare those.
 - built and tested on both current linux-2.6 and net-next-2.6 (*)

Comments welcome.

Cheers,

a+

(*): stripped from latest stats patches from Eric (crash at boot) until
     associated fixes get included tomorrow


^ permalink raw reply

* [PATCHv2 net-next-2.6 1/5] XFRM,IPv6: Remove xfrm_spi_hash() dependency on destination address
From: Arnaud Ebalard @ 2010-09-28 15:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <cover.1285687738.git.arno@natisbad.org>


In the new IPsec architecture [RFC4301], "for an SA used to carry
unicast traffic, the Security Parameters Index (SPI) by itself
suffices to specify an SA".  Section 4.1 of [RFC4301] provides
additional guidance on the topic.

In the old IPsec architecture [RFC2401], a SA "is uniquely identified
by a triple consisting of a Security Parameter Index (SPI), an IP
Destination Address and a security protocol (AH or ESP) identifier".

If an IPsec stack only supports the behavior mandated by the old
IPsec architecture, SAD lookup on inbound packets require the use of
both the SPI and the destination address of the SA.

For inbound IPsec traffic, IRO remapping rules may exist on the MN to
remap the destination address (CoA) into the HoA.  In that case, by
design, the address found in the destination address field of the
packet (CoA) does not match the one in the SA (HoA).

At the moment, Linux XFRM stack includes the address when computing
the hash to perform state lookup by SPI. This patch changes XFRM
state hash computation to prevent destination address to be
used. This will later allow finding states for packets w/ mangled
destination addresses.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 net/xfrm/xfrm_hash.h  |   21 +--------------------
 net/xfrm/xfrm_state.c |   20 ++++++++------------
 2 files changed, 9 insertions(+), 32 deletions(-)

diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 8e69533..19eeee7 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -4,16 +4,6 @@
 #include <linux/xfrm.h>
 #include <linux/socket.h>
 
-static inline unsigned int __xfrm4_addr_hash(xfrm_address_t *addr)
-{
-	return ntohl(addr->a4);
-}
-
-static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
-{
-	return ntohl(addr->a6[2] ^ addr->a6[3]);
-}
-
 static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
 {
 	u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4;
@@ -60,18 +50,9 @@ static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
 }
 
 static inline unsigned int
-__xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
-		unsigned int hmask)
+__xfrm_spi_hash(__be32 spi, u8 proto, unsigned int hmask)
 {
 	unsigned int h = (__force u32)spi ^ proto;
-	switch (family) {
-	case AF_INET:
-		h ^= __xfrm4_addr_hash(daddr);
-		break;
-	case AF_INET6:
-		h ^= __xfrm6_addr_hash(daddr);
-		break;
-	}
 	return (h ^ (h >> 10) ^ (h >> 20)) & hmask;
 }
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index eb96ce5..b6a4d8d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -30,7 +30,7 @@
 
 /* Each xfrm_state may be linked to two tables:
 
-   1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
+   1. Hash table by (spi,ah/esp) to find SA by SPI. (input,ctl)
    2. Hash table by (daddr,family,reqid) to find what SAs exist for given
       destination/tunnel endpoint. (output)
  */
@@ -67,9 +67,9 @@ static inline unsigned int xfrm_src_hash(struct net *net,
 }
 
 static inline unsigned int
-xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
+xfrm_spi_hash(struct net *net, __be32 spi, u8 proto)
 {
-	return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
+	return __xfrm_spi_hash(spi, proto, net->xfrm.state_hmask);
 }
 
 static void xfrm_hash_transfer(struct hlist_head *list,
@@ -95,9 +95,7 @@ static void xfrm_hash_transfer(struct hlist_head *list,
 		hlist_add_head(&x->bysrc, nsrctable+h);
 
 		if (x->id.spi) {
-			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
-					    x->id.proto, x->props.family,
-					    nhashmask);
+			h = __xfrm_spi_hash(x->id.spi, x->id.proto, nhashmask);
 			hlist_add_head(&x->byspi, nspitable+h);
 		}
 	}
@@ -679,7 +677,7 @@ xfrm_init_tempstate(struct xfrm_state *x, struct flowi *fl,
 
 static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
 {
-	unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
+	unsigned int h = xfrm_spi_hash(net, spi, proto);
 	struct xfrm_state *x;
 	struct hlist_node *entry;
 
@@ -868,7 +866,7 @@ found:
 			h = xfrm_src_hash(net, daddr, saddr, encap_family);
 			hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
 			if (x->id.spi) {
-				h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
+				h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
 				hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 			}
 			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
@@ -942,9 +940,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 	hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h);
 
 	if (x->id.spi) {
-		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
-				  x->props.family);
-
+		h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
 		hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 	}
 
@@ -1535,7 +1531,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
 	}
 	if (x->id.spi) {
 		spin_lock_bh(&xfrm_state_lock);
-		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
+		h = xfrm_spi_hash(net, x->id.spi, x->id.proto);
 		hlist_add_head(&x->byspi, net->xfrm.state_byspi+h);
 		spin_unlock_bh(&xfrm_state_lock);
 
-- 
1.7.1



^ permalink raw reply related

* [PATCHv2 net-next-2.6 2/5] XFRM,IPv6: Introduce receive sockopts to access IRO remapped src/dst addresses
From: Arnaud Ebalard @ 2010-09-28 15:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <cover.1285687738.git.arno@natisbad.org>


This patch introduces IRO recv sockopts, in order for userland processes
(e.g. UMIP) to access on-wire source or destination addresses found in
incoming (IPsec-protected) packets as they were before remapping by IRO.
The socket options are respectively IPV6_RECVIROSRC and IPV6_RECVIRODST.

Basically, the two recv socket options are similar in their purpose to
their generic RH2/HAO counterparts defined in RFC 3542 (IPV6_RECVIROSRC
<->  IPV6_RECVDSTOPTS, IPV6_RECVIRODST <-> IPV6_RECVRTHDR). They differ
on the following aspects:

 - IRO reporting sockopts only work on incoming IPsec-protected packets
   Userspace will never get IRO remapped address report for common
   (non protected) packets.
 - The receiver gets the original source/desination address (IRO
   remapping) from its IPsec stack.
 - as IRO sockopts only deal with addresses, no specific structure is
   defined, i.e. struct in6_addr is used to pass info.

As we only interact with IPsec protected packets, struct sec_path is
used to carry information (addresses) for incoming packets that have
undergone remapping process.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 include/linux/in6.h      |    7 +++++++
 include/linux/ipv6.h     |    4 +++-
 include/net/xfrm.h       |    5 +++++
 net/ipv6/datagram.c      |   18 ++++++++++++++++++
 net/ipv6/ipv6_sockglue.c |   26 ++++++++++++++++++++++++++
 5 files changed, 59 insertions(+), 1 deletions(-)

diff --git a/include/linux/in6.h b/include/linux/in6.h
index c4bf46f..52a98ab 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -283,4 +283,11 @@ struct in6_flowlabel_req {
  * MRT6_PIM			208
  * (reserved)			209
  */
+
+/* IRO (IPsec Route Optimization) sockopts */
+#define IPV6_RECVIROSRC         74
+#define IPV6_IROSRC		75
+#define IPV6_RECVIRODST         76
+#define IPV6_IRODST		77
+
 #endif
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index e62683b..55289ee 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -341,7 +341,9 @@ struct ipv6_pinfo {
 				odstopts:1,
                                 rxflow:1,
 				rxtclass:1,
-				rxpmtu:1;
+				rxpmtu:1,
+				irosrc:1,
+				irodst:1;
 		} bits;
 		__u16		all;
 	} rxopt;
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4f53532..e6a753c 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -909,6 +909,11 @@ struct sec_path {
 	atomic_t		refcnt;
 	int			len;
 	struct xfrm_state	*xvec[XFRM_MAX_DEPTH];
+
+#ifdef CONFIG_XFRM_SUB_POLICY
+	struct in6_addr         irosrc;
+	struct in6_addr         irodst;
+#endif
 };
 
 static inline struct sec_path *
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index ef371aa..2952c9e 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -29,6 +29,7 @@
 #include <net/transp_v6.h>
 #include <net/ip6_route.h>
 #include <net/tcp_states.h>
+#include <net/xfrm.h>
 
 #include <linux/errqueue.h>
 #include <asm/uaccess.h>
@@ -504,6 +505,23 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);
 	}
 
+#ifdef CONFIG_XFRM_SUB_POLICY
+	/* If access to IRO-remapped source or destination address has been
+	 * requested and it has indeed been remapped, provide the on-wire
+	 * address to userland */
+	if (skb_sec_path(skb)) {
+		struct sec_path *sp = skb_sec_path(skb);
+
+		if (np->rxopt.bits.irosrc && !ipv6_addr_any(&sp->irosrc))
+			put_cmsg(msg, SOL_IPV6, IPV6_IROSRC,
+				 sizeof(sp->irosrc), &sp->irosrc);
+
+		if (np->rxopt.bits.irodst && !ipv6_addr_any(&sp->irodst))
+			put_cmsg(msg, SOL_IPV6, IPV6_IRODST,
+				 sizeof(sp->irodst), &sp->irodst);
+	}
+#endif
+
 	if (opt->lastopt &&
 	    (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) {
 		/*
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index a7f66bc..722a49f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -302,6 +302,22 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		retv = 0;
 		break;
 
+#ifdef CONFIG_XFRM_SUB_POLICY
+	case IPV6_RECVIROSRC:
+		if (optlen < sizeof(int))
+			goto e_inval;
+		np->rxopt.bits.irosrc = valbool;
+		retv = 0;
+		break;
+
+	case IPV6_RECVIRODST:
+		if (optlen < sizeof(int))
+			goto e_inval;
+		np->rxopt.bits.irodst = valbool;
+		retv = 0;
+		break;
+#endif
+
 	case IPV6_2292DSTOPTS:
 		if (optlen < sizeof(int))
 			goto e_inval;
@@ -1056,6 +1072,16 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 		val = np->rxopt.bits.dstopts;
 		break;
 
+#ifdef CONFIG_XFRM_SUB_POLICY
+	case IPV6_RECVIROSRC:
+		val = np->rxopt.bits.irosrc;
+		break;
+
+	case IPV6_RECVIRODST:
+		val = np->rxopt.bits.irodst;
+		break;
+#endif
+
 	case IPV6_2292DSTOPTS:
 		val = np->rxopt.bits.odstopts;
 		break;
-- 
1.7.1



^ permalink raw reply related

* [PATCHv2 net-next-2.6 3/5] XFRM,IPv6: Add IRO src/dst address remapping XFRM types and i/o handlers
From: Arnaud Ebalard @ 2010-09-28 15:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <cover.1285687738.git.arno@natisbad.org>


Add IRO source and destination remapping XFRM types and associated
input/output handlers. This allows userland to install such states
in order to support remapping of source or destination address
of packet. They basically work like existing RH2 and HAO ones; the
main difference is that output handlers do not expand the packet by
adding an extension header: they simply change the source or
destination in place. Input handlers are almost the same as RH2/HAO
version in their behavior, but they are triggered differently. RH2
and HAO handlers are triggered based on structures found in the
packet. On input, IRO states (and associated handlers) are looked
up when processing an IPsec-protected packet, when there is an
address mismatch.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 include/net/xfrm.h       |    2 +
 net/ipv6/mip6.c          |  153 ++++++++++++++++++++++++++++++++++++++++++++++
 net/ipv6/xfrm6_mode_ro.c |   11 +++-
 net/xfrm/xfrm_user.c     |    4 +
 4 files changed, 169 insertions(+), 1 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e6a753c..05b2b1f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -35,6 +35,8 @@
 #define XFRM_PROTO_IPV6		41
 #define XFRM_PROTO_ROUTING	IPPROTO_ROUTING
 #define XFRM_PROTO_DSTOPTS	IPPROTO_DSTOPTS
+#define XFRM_PROTO_IRO_SRC      127
+#define XFRM_PROTO_IRO_DST      128
 
 #define XFRM_ALIGN8(len)	(((len) + 7) & ~7)
 #define MODULE_ALIAS_XFRM_MODE(family, encap) \
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index d6e9599..04b9e1d 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -477,6 +477,131 @@ static const struct xfrm_type mip6_rthdr_type =
 	.hdr_offset	= mip6_rthdr_offset,
 };
 
+#ifdef CONFIG_XFRM_SUB_POLICY
+/* IRO equivalent of mip6_destopt_input(): handles incoming packet with a
+ * source address different from the one expected in the SA: check that
+ * received source address is indeed the CoA we expected (or any address
+ * if the state references the unspecified address '::') */
+static int mip6_iro_src_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	int err = 1;
+
+	spin_lock(&x->lock);
+	if (!ipv6_addr_equal(&iph->saddr, (struct in6_addr *)x->coaddr) &&
+	    !ipv6_addr_any((struct in6_addr *)x->coaddr))
+		err = -ENOENT;
+	spin_unlock(&x->lock);
+
+	return err;
+}
+
+/* IRO equivalent of mip6_destopt_output(): replaces current source address
+ * of outgoing packet by state's CoA. */
+static int mip6_iro_src_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+
+	spin_lock_bh(&x->lock);
+	memcpy(&iph->saddr, x->coaddr, sizeof(iph->saddr));
+	spin_unlock_bh(&x->lock);
+
+	return 0;
+}
+
+static int mip6_iro_src_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl)
+{
+	int err = 0;
+
+	/* XXX We may need some reject handler at some point but it is not
+	 * critical yet: see xfrm_secpath_reject() in net/xfrm/xfrm_policy.c
+	 * and aslo what mip6_destopt_reject() implements */
+
+	printk("XXX FIXME: mip6_iro_src_reject() called\n");
+
+	return err;
+}
+
+/* This is the IRO equivalent of mip6_rthdr_input(): handles incoming packet
+ * with a destination address different from the one expected in the SA:
+ * check that received destination address is indeed the CoA we expected
+ * (or any address if the state references the unspecified address '::') */
+static int mip6_iro_dst_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	int err = 1;
+
+	spin_lock(&x->lock);
+	if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
+	    !ipv6_addr_any((struct in6_addr *)x->coaddr))
+		err = -ENOENT;
+	spin_unlock(&x->lock);
+
+	return err;
+}
+
+/* IRO equivalent of mip6_rthdr_output(): replaces current destination
+ * address of outgoing packet with state's CoA */
+static int mip6_iro_dst_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+
+	spin_lock_bh(&x->lock);
+	memcpy(&iph->daddr, x->coaddr, sizeof(iph->daddr));
+	spin_unlock_bh(&x->lock);
+
+	return 0;
+}
+
+/* Common to iro src and dst remapping states. */
+static int mip6_iro_init_state(struct xfrm_state *x)
+{
+	if (x->id.spi) {
+		printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
+		       x->id.spi);
+		return -EINVAL;
+	}
+	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
+		printk(KERN_INFO "%s: state's mode is not %u: %u\n",
+		       __func__, XFRM_MODE_ROUTEOPTIMIZATION,
+		       x->props.mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Unlike common IPsec protocols, nothing to do when destroying */
+static void mip6_iro_destroy(struct xfrm_state *x)
+{
+}
+
+static const struct xfrm_type mip6_iro_src_type =
+{
+	.description	= "MIP6_IRO_SRC",
+	.owner		= THIS_MODULE,
+	.proto	     	= XFRM_PROTO_IRO_SRC,
+	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
+	.init_state	= mip6_iro_init_state,
+	.destructor	= mip6_iro_destroy,
+	.input		= mip6_iro_src_input,
+	.output		= mip6_iro_src_output,
+	.reject         = mip6_iro_src_reject,
+};
+
+static const struct xfrm_type mip6_iro_dst_type =
+{
+	.description	= "MIP6_IRO_DST",
+	.owner		= THIS_MODULE,
+	.proto	     	= XFRM_PROTO_IRO_DST,
+	.flags		= XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
+	.init_state	= mip6_iro_init_state,
+	.destructor	= mip6_iro_destroy,
+	.input		= mip6_iro_dst_input,
+	.output		= mip6_iro_dst_output,
+};
+#endif /* CONFIG_XFRM_SUB_POLICY */
+
 static int __init mip6_init(void)
 {
 	printk(KERN_INFO "Mobile IPv6\n");
@@ -489,6 +614,20 @@ static int __init mip6_init(void)
 		printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __func__);
 		goto mip6_rthdr_xfrm_fail;
 	}
+
+#ifdef CONFIG_XFRM_SUB_POLICY
+	if (xfrm_register_type(&mip6_iro_src_type, AF_INET6) < 0) {
+		printk(KERN_INFO "%s: can't add xfrm type(IRO src remap)\n",
+		       __func__);
+		goto mip6_iro_src_remap_xfrm_fail;
+	}
+	if (xfrm_register_type(&mip6_iro_dst_type, AF_INET6) < 0) {
+		printk(KERN_INFO "%s: can't add xfrm type(IRO dst remap)\n",
+		       __func__);
+		goto mip6_iro_dst_remap_xfrm_fail;
+	}
+#endif
+
 	if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
 		printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __func__);
 		goto mip6_rawv6_mh_fail;
@@ -498,6 +637,12 @@ static int __init mip6_init(void)
 	return 0;
 
  mip6_rawv6_mh_fail:
+#ifdef CONFIG_XFRM_SUB_POLICY
+	xfrm_unregister_type(&mip6_iro_dst_type, AF_INET6);
+ mip6_iro_dst_remap_xfrm_fail:
+	xfrm_unregister_type(&mip6_iro_src_type, AF_INET6);
+ mip6_iro_src_remap_xfrm_fail:
+#endif
 	xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
  mip6_rthdr_xfrm_fail:
 	xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
@@ -509,6 +654,14 @@ static void __exit mip6_fini(void)
 {
 	if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
 		printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __func__);
+#ifdef CONFIG_XFRM_SUB_POLICY
+	if (xfrm_unregister_type(&mip6_iro_dst_type, AF_INET6) < 0)
+		printk(KERN_INFO "%s: can't remove xfrm type(IRO dst remap)\n",
+		       __func__);
+	if (xfrm_unregister_type(&mip6_iro_src_type, AF_INET6) < 0)
+		printk(KERN_INFO "%s: can't remove xfrm type(IRO src remap)\n",
+		       __func__);
+#endif
 	if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
 		printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __func__);
 	if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c
index 63d5d49..ea33178 100644
--- a/net/ipv6/xfrm6_mode_ro.c
+++ b/net/ipv6/xfrm6_mode_ro.c
@@ -45,6 +45,15 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
 	u8 *prevhdr;
 	int hdr_len;
 
+	/* Unlike RH2 (IPPROTO_ROUTING) and HAO in DstOpt
+	 * (IPPROTO_DSTOPTS), IRO remapping states do not
+	 * add extension header to the packet. Source
+	 * and/or destination addresses are simply modified
+	 * in place. */
+	if (x->id.proto == XFRM_PROTO_IRO_SRC ||
+	    x->id.proto == XFRM_PROTO_IRO_DST)
+		goto out;
+
 	iph = ipv6_hdr(skb);
 
 	hdr_len = x->type->hdr_offset(x, skb, &prevhdr);
@@ -54,8 +63,8 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb)
 	__skb_pull(skb, hdr_len);
 	memmove(ipv6_hdr(skb), iph, hdr_len);
 
+ out:
 	x->lastused = get_seconds();
-
 	return 0;
 }
 
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8bae6b2..2aecd40 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -179,6 +179,10 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	case IPPROTO_DSTOPTS:
 	case IPPROTO_ROUTING:
+#ifdef CONFIG_XFRM_SUB_POLICY
+	case XFRM_PROTO_IRO_SRC:
+	case XFRM_PROTO_IRO_DST:
+#endif
 		if (attrs[XFRMA_ALG_COMP]	||
 		    attrs[XFRMA_ALG_AUTH]	||
 		    attrs[XFRMA_ALG_AUTH_TRUNC]	||
-- 
1.7.1



^ permalink raw reply related

* [PATCHv2 net-next-2.6 4/5] XFRM,IPv6: Add IRO remapping hook in xfrm_input()
From: Arnaud Ebalard @ 2010-09-28 15:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <cover.1285687738.git.arno@natisbad.org>


Add a hook in xfrm_input() to allow IRO remapping to occur when
an incoming packet matching an existing SA (based on SPI) with
an unexpected destination or source address is received.
Because IRO does not consume additional bits in a packet (that's
the point), there is no way to demultiplex based on something
like nh or spi. Instead, IRO input handlers (for source and
destination address remapping) are called upon address mismatch
during IPsec processing.
For that to work, we rely on the fact that SPI values generated
locally are no more linked to destination address (first patch
of the set) and we postpone a bit the expected address check in
xfrm_input() (inside xfrm_state_lookup() against daddr param) by
introducing xfrm_input_addr_check() helper.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 include/net/xfrm.h     |    3 ++
 net/ipv4/xfrm4_input.c |   12 ++++++++
 net/ipv6/xfrm6_input.c |   70 +++++++++++++++++++++++++++++++++++++++++++++++-
 net/xfrm/xfrm_input.c  |   21 +++++++++++++-
 net/xfrm/xfrm_state.c  |    2 +-
 5 files changed, 104 insertions(+), 4 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 05b2b1f..f536b2f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -623,6 +623,7 @@ struct xfrm_spi_skb_cb {
 		struct inet6_skb_parm h6;
 	} header;
 
+	unsigned int saddroff;
 	unsigned int daddroff;
 	unsigned int family;
 };
@@ -1405,6 +1406,7 @@ extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
 			   int encap_type);
 extern int xfrm4_transport_finish(struct sk_buff *skb, int async);
 extern int xfrm4_rcv(struct sk_buff *skb);
+extern int xfrm4_input_addr_check(struct sk_buff *skb, struct xfrm_state *x);
 
 static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 {
@@ -1423,6 +1425,7 @@ extern int xfrm6_transport_finish(struct sk_buff *skb, int async);
 extern int xfrm6_rcv(struct sk_buff *skb);
 extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 			    xfrm_address_t *saddr, u8 proto);
+extern int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x);
 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
 extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 06814b6..82e23ec 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -41,6 +41,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
 		    int encap_type)
 {
 	XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+	XFRM_SPI_SKB_CB(skb)->saddroff = offsetof(struct iphdr, saddr);
 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
 	return xfrm_input(skb, nexthdr, spi, encap_type);
 }
@@ -164,3 +165,14 @@ int xfrm4_rcv(struct sk_buff *skb)
 	return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0);
 }
 EXPORT_SYMBOL(xfrm4_rcv);
+
+int xfrm4_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+	xfrm_address_t *daddr;
+
+	daddr = (xfrm_address_t *)(skb_network_header(skb) +
+				   XFRM_SPI_SKB_CB(skb)->daddroff);
+
+	return xfrm_addr_cmp(&x->id.daddr, daddr, AF_INET);
+}
+EXPORT_SYMBOL(xfrm4_input_addr_check);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index f8c3cf8..754ecf7 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -15,6 +15,7 @@
 #include <linux/netfilter_ipv6.h>
 #include <net/ipv6.h>
 #include <net/xfrm.h>
+#include <net/ip6_route.h> /* XXX for ip6_route_input() */
 
 int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
 {
@@ -24,6 +25,7 @@ int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb)
 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 {
 	XFRM_SPI_SKB_CB(skb)->family = AF_INET6;
+	XFRM_SPI_SKB_CB(skb)->saddroff = offsetof(struct ipv6hdr, saddr);
 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
 	return xfrm_input(skb, nexthdr, spi, 0);
 }
@@ -142,5 +144,71 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 drop:
 	return -1;
 }
-
 EXPORT_SYMBOL(xfrm6_input_addr);
+
+#if defined(CONFIG_XFRM_SUB_POLICY)
+/* Perform check on source and destination addresses and possibly IRO
+ * address remapping upon mismatch and if matching IRO state exists. */
+int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+	xfrm_address_t *saddr, *exp_saddr, *daddr, *exp_daddr;
+
+	saddr = (xfrm_address_t *)(skb_network_header(skb) +
+				   XFRM_SPI_SKB_CB(skb)->saddroff);
+	daddr = (xfrm_address_t *)(skb_network_header(skb) +
+				   XFRM_SPI_SKB_CB(skb)->daddroff);
+
+	exp_daddr = &x->id.daddr;
+	if (xfrm_addr_cmp(exp_daddr, daddr, AF_INET6)) {
+		/* Destination address mismatch: check if we have an IRO
+		 * destination remapping state to explain that.
+		 *
+		 * Note: saddr is provided as a hint. If source address
+		 * is also a remapped one, xfrm6_input_addr() will manage
+		 * to find IRO destination remapping state */
+		if (xfrm6_input_addr(skb, exp_daddr, saddr,
+				     XFRM_PROTO_IRO_DST) < 0)
+			return -1;
+
+		/* Copy destination address to sec_path for sock opts and
+		 * replace packet destination address with expected HoA */
+		ipv6_addr_copy(&skb->sp->irodst, (struct in6_addr *)daddr);
+		ipv6_addr_copy((struct in6_addr *)daddr,
+			       (struct in6_addr *)exp_daddr);
+
+		skb_dst_drop(skb);
+		ip6_route_input(skb);
+		if (skb_dst(skb)->error)
+			return -1;
+	}
+
+	exp_saddr = &x->props.saddr;
+	if (xfrm_addr_cmp(exp_saddr, saddr, AF_INET6)) {
+		/* Source address mismatch: check if we have an IRO
+		 * source remapping state to explain that.
+		 *
+		 * Note: unlike for destination addresses above, a
+		 * source mismatch is not considered fatal */
+		if (xfrm6_input_addr(skb, daddr, exp_saddr,
+				     XFRM_PROTO_IRO_SRC) < 0)
+			return 0;
+
+		/* Copy destination address to sec_path for sock opts and
+		 * then replace source address with expected peer's HoA */
+		ipv6_addr_copy(&skb->sp->irosrc, (struct in6_addr *)saddr);
+		ipv6_addr_copy((struct in6_addr *)saddr,
+			       (struct in6_addr *)exp_saddr);
+	}
+
+	return 0;
+}
+#else
+int xfrm6_input_addr_check(struct sk_buff *skb, struct xfrm_state *x)
+{
+	xfrm_address_t *daddr;
+	daddr = (xfrm_address_t *)(skb_network_header(skb) +
+				   XFRM_SPI_SKB_CB(skb)->daddroff);
+	return xfrm_addr_cmp(&x->id.daddr, daddr, AF_INET6);
+}
+#endif
+EXPORT_SYMBOL(xfrm6_input_addr_check);
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 45f1c98..7927af7 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -102,6 +102,23 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm_prepare_input);
 
+static inline int xfrm_input_addr_check(struct sk_buff *skb, struct xfrm_state *x,
+					unsigned int family)
+{
+	switch (family) {
+#ifdef CONFIG_INET
+	case AF_INET:
+		return xfrm4_input_addr_check(skb, x);
+#endif
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		return xfrm6_input_addr_check(skb, x);
+#endif
+	default:
+		return 0;
+	}
+}
+
 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 {
 	struct net *net = dev_net(skb->dev);
@@ -152,8 +169,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 			goto drop;
 		}
 
-		x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family);
-		if (x == NULL) {
+		x = xfrm_state_lookup(net, skb->mark, NULL, spi, nexthdr, family);
+		if (x == NULL || xfrm_input_addr_check(skb, x, family)) {
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
 			xfrm_audit_state_notfound(skb, family, spi, seq);
 			goto drop;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index b6a4d8d..b8f7c08 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -685,7 +685,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_ad
 		if (x->props.family != family ||
 		    x->id.spi       != spi ||
 		    x->id.proto     != proto ||
-		    xfrm_addr_cmp(&x->id.daddr, daddr, family))
+		    (daddr && xfrm_addr_cmp(&x->id.daddr, daddr, family)))
 			continue;
 
 		if ((mark & x->mark.m) != x->mark.v)
-- 
1.7.1



^ permalink raw reply related

* [PATCHv2 net-next-2.6 5/5] XFRM,IPv6: Add IRO remapping capability via socket ancillary data path
From: Arnaud Ebalard @ 2010-09-28 15:54 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Herbert Xu, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <cover.1285687738.git.arno@natisbad.org>


This provides the ability to remap src/dst address using IRO
via ancillary data passed to sockets. This is the IRO equivalent
of what is done for RH2/HAO (i.e. IPV6_RTHDR/IPV6_DSTOPTS).
This is used by UMIP during BA emission when acting as a Home
Agent.

Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
 include/net/ipv6.h       |    4 ++++
 net/ipv6/datagram.c      |   20 ++++++++++++++++++++
 net/ipv6/exthdrs.c       |   19 +++++++++++++------
 net/ipv6/ip6_flowlabel.c |    7 +++++++
 net/ipv6/ip6_output.c    |   22 ++++++++++++++++++++++
 net/ipv6/raw.c           |    3 ++-
 6 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 4a3cd2c..2ba96d8 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -188,6 +188,10 @@ struct ipv6_txoptions {
 	struct ipv6_rt_hdr	*srcrt;	/* Routing Header */
 	struct ipv6_opt_hdr	*dst1opt;
 
+	/* XXX protect those via some ifdef e.g. CONFIG_XFRM_SUB_POLICY ? */
+	struct in6_addr         *iro_src;
+	struct in6_addr         *iro_dst;
+
 	/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
 };
 
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 2952c9e..0ac7adf 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -757,6 +757,26 @@ int datagram_send_ctl(struct net *net,
 			}
 			break;
 
+#ifdef CONFIG_XFRM_SUB_POLICY
+		case IPV6_IROSRC:
+		case IPV6_IRODST:
+			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_addr))) {
+				err = -EINVAL;
+				goto exit_f;
+			}
+
+			if (!capable(CAP_NET_RAW)) {
+				err = -EPERM;
+				goto exit_f;
+			}
+
+			if (cmsg->cmsg_type == IPV6_IROSRC)
+				opt->iro_src = (struct in6_addr *)CMSG_DATA(cmsg);
+			else
+				opt->iro_dst = (struct in6_addr *)CMSG_DATA(cmsg);
+			break;
+#endif
+
 		case IPV6_2292RTHDR:
 		case IPV6_RTHDR:
 			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 262f105..e480b06 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -750,6 +750,10 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
 			*((char**)&opt2->dst1opt) += dif;
 		if (opt2->srcrt)
 			*((char**)&opt2->srcrt) += dif;
+		if (opt2->iro_src)
+			*((char**)&opt2->iro_src) += dif;
+		if (opt2->iro_dst)
+			*((char**)&opt2->iro_dst) += dif;
 	}
 	return opt2;
 }
@@ -874,24 +878,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
 
 /**
  * fl6_update_dst - update flowi destination address with info given
- *                  by srcrt option, if any.
+ *                  by srcrt/iro_dst option, if any.
  *
  * @fl: flowi for which fl6_dst is to be updated
- * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @opt: struct ipv6_txoptions in which to look for srcrt/iro_dst opt
  * @orig: copy of original fl6_dst address if modified
  *
- * Returns NULL if no txoptions or no srcrt, otherwise returns orig
- * and initial value of fl->fl6_dst set in orig
+ * Returns NULL if no txoptions or no options to change flowi destination
+ * (srcrt or IRO destination remapping rule), otherwise returns orig and
+ * initial value of fl->fl6_dst set in orig
  */
 struct in6_addr *fl6_update_dst(struct flowi *fl,
 				const struct ipv6_txoptions *opt,
 				struct in6_addr *orig)
 {
-	if (!opt || !opt->srcrt)
+	if (!opt || (!opt->srcrt && !opt->iro_dst))
 		return NULL;
 
 	ipv6_addr_copy(orig, &fl->fl6_dst);
-	ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+	ipv6_addr_copy(&fl->fl6_dst,
+		       opt->iro_dst ?: ((struct rt0_hdr *)opt->srcrt)->addr);
+
 	return orig;
 }
 
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 1365468..dbf9c29 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -280,6 +280,9 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
 		opt_space->hopopt = fl_opt->hopopt;
 		opt_space->dst0opt = fl_opt->dst0opt;
 		opt_space->srcrt = fl_opt->srcrt;
+		/* XXX protect those via some ifdef - see net/ipv6.h */
+		opt_space->iro_src = fl_opt->iro_src;
+		opt_space->iro_dst = fl_opt->iro_dst;
 		opt_space->opt_nflen = fl_opt->opt_nflen;
 	} else {
 		if (fopt->opt_nflen == 0)
@@ -287,6 +290,9 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
 		opt_space->hopopt = NULL;
 		opt_space->dst0opt = NULL;
 		opt_space->srcrt = NULL;
+		/* XXX protect those via some ifdef - see net/ipv6.h */
+		opt_space->iro_src = NULL;
+		opt_space->iro_dst = NULL;
 		opt_space->opt_nflen = 0;
 	}
 	opt_space->dst1opt = fopt->dst1opt;
@@ -456,6 +462,7 @@ static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2)
 		return 1;
 	if (ipv6_hdr_cmp((struct ipv6_opt_hdr *)o1->srcrt, (struct ipv6_opt_hdr *)o2->srcrt))
 		return 1;
+
 	return 0;
 }
 
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 99157b4..210f269 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -222,6 +222,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 			ipv6_push_frag_opts(skb, opt, &proto);
 		if (opt->opt_nflen)
 			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
+		if (opt->iro_dst)
+			first_hop = opt->iro_dst;
 	}
 
 	skb_push(skb, sizeof(struct ipv6hdr));
@@ -1106,6 +1108,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src,
 	return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL;
 }
 
+static inline struct in6_addr *ip6_iro_addr_dup(struct in6_addr *addr,
+						gfp_t gfp)
+{
+	return addr ? kmemdup(addr, sizeof(struct in6_addr), gfp) : NULL;
+}
+
 int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
 	int offset, int len, int odd, struct sk_buff *skb),
 	void *from, int length, int transhdrlen,
@@ -1162,6 +1170,16 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
 			if (opt->srcrt && !np->cork.opt->srcrt)
 				return -ENOBUFS;
 
+			np->cork.opt->iro_src = ip6_iro_addr_dup(opt->iro_src,
+								 sk->sk_allocation);
+			if (opt->iro_src && !np->cork.opt->iro_src)
+				return -ENOBUFS;
+
+			np->cork.opt->iro_dst = ip6_iro_addr_dup(opt->iro_dst,
+								 sk->sk_allocation);
+			if (opt->iro_dst && !np->cork.opt->iro_dst)
+				return -ENOBUFS;
+
 			/* need source address above miyazawa*/
 		}
 		dst_hold(&rt->dst);
@@ -1440,6 +1458,8 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
 		kfree(np->cork.opt->dst1opt);
 		kfree(np->cork.opt->hopopt);
 		kfree(np->cork.opt->srcrt);
+		kfree(np->cork.opt->iro_src);
+		kfree(np->cork.opt->iro_dst);
 		kfree(np->cork.opt);
 		np->cork.opt = NULL;
 	}
@@ -1495,6 +1515,8 @@ int ip6_push_pending_frames(struct sock *sk)
 		ipv6_push_frag_opts(skb, opt, &proto);
 	if (opt && opt->opt_nflen)
 		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
+	if (opt && opt->iro_dst)
+		final_dst = opt->iro_dst;
 
 	skb_push(skb, sizeof(struct ipv6hdr));
 	skb_reset_network_header(skb);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 45e6efb..1a11bd5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -828,7 +828,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 			if (flowlabel == NULL)
 				return -EINVAL;
 		}
-		if (!(opt->opt_nflen|opt->opt_flen))
+		if (!(opt->opt_nflen|opt->opt_flen) &&
+		    (!opt->iro_src && !opt->iro_dst))
 			opt = NULL;
 	}
 	if (opt == NULL)
-- 
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