diff mbox

net: tun: convert to hw_features

Message ID 20110419161310.7508513909@rere.qmqm.pl
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Michał Mirosław April 19, 2011, 4:13 p.m. UTC
This changes offload setting behaviour to what I think is correct:
 - offloads set via ethtool mean what admin wants to use (by default
   he wants 'em all)
 - offloads set via ioctl() mean what userspace is expecting to get
   (this limits which admin wishes are granted)
 - TUN_NOCHECKSUM is ignored, as it might cause broken packets when
   forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum
   was verified, not that it can be ignored)

If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and
skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others
be verified by kernel when necessary.

TUN_NOCHECKSUM handling was introduced by commit
f43798c27684ab925adde7d8acc34c78c6e50df8:

    tun: Allow GSO using virtio_net_hdr
    
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/net/tun.c |   63 +++++++++++++++++++++--------------------------------
 1 files changed, 25 insertions(+), 38 deletions(-)

Comments

Rusty Russell April 20, 2011, 3:22 a.m. UTC | #1
On Tue, 19 Apr 2011 18:13:10 +0200 (CEST), Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:
> This changes offload setting behaviour to what I think is correct:
>  - offloads set via ethtool mean what admin wants to use (by default
>    he wants 'em all)
>  - offloads set via ioctl() mean what userspace is expecting to get
>    (this limits which admin wishes are granted)
>  - TUN_NOCHECKSUM is ignored, as it might cause broken packets when
>    forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum
>    was verified, not that it can be ignored)
> 
> If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and
> skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others
> be verified by kernel when necessary.
> 
> TUN_NOCHECKSUM handling was introduced by commit
> f43798c27684ab925adde7d8acc34c78c6e50df8:
> 
>     tun: Allow GSO using virtio_net_hdr

Err, not in my git tree!  It predates git in fact.

Since tap requires privs, I wouldn't worry about invalid packets too
much.

Thanks,
Rusty.
--
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
David Miller April 20, 2011, 8:32 a.m. UTC | #2
From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Date: Tue, 19 Apr 2011 18:13:10 +0200 (CEST)

> This changes offload setting behaviour to what I think is correct:
>  - offloads set via ethtool mean what admin wants to use (by default
>    he wants 'em all)
>  - offloads set via ioctl() mean what userspace is expecting to get
>    (this limits which admin wishes are granted)
>  - TUN_NOCHECKSUM is ignored, as it might cause broken packets when
>    forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum
>    was verified, not that it can be ignored)
> 
> If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and
> skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others
> be verified by kernel when necessary.
> 
> TUN_NOCHECKSUM handling was introduced by commit
> f43798c27684ab925adde7d8acc34c78c6e50df8:
> 
>     tun: Allow GSO using virtio_net_hdr
>     
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Applied.
--
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
Michał Mirosław April 20, 2011, 11:15 p.m. UTC | #3
On Wed, Apr 20, 2011 at 12:52:24PM +0930, Rusty Russell wrote:
> On Tue, 19 Apr 2011 18:13:10 +0200 (CEST), Michał Mirosław <mirq-linux@rere.qmqm.pl> wrote:
> > This changes offload setting behaviour to what I think is correct:
> >  - offloads set via ethtool mean what admin wants to use (by default
> >    he wants 'em all)
> >  - offloads set via ioctl() mean what userspace is expecting to get
> >    (this limits which admin wishes are granted)
> >  - TUN_NOCHECKSUM is ignored, as it might cause broken packets when
> >    forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum
> >    was verified, not that it can be ignored)
> > 
> > If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and
> > skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others
> > be verified by kernel when necessary.
> > 
> > TUN_NOCHECKSUM handling was introduced by commit
> > f43798c27684ab925adde7d8acc34c78c6e50df8:
> > 
> >     tun: Allow GSO using virtio_net_hdr
> Err, not in my git tree!  It predates git in fact.

Ah! Sorry! Your patch just moved the buggy line around.

> Since tap requires privs, I wouldn't worry about invalid packets too
> much.

I prefer correctness over uncertainty. ;)

Best Regards,
Michał Mirosław
--
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
Rusty Russell April 27, 2011, 4:59 a.m. UTC | #4
On Wed, 20 Apr 2011 01:32:16 -0700 (PDT), David Miller <davem@davemloft.net> wrote:
> From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> Date: Tue, 19 Apr 2011 18:13:10 +0200 (CEST)
> 
> > This changes offload setting behaviour to what I think is correct:
> >  - offloads set via ethtool mean what admin wants to use (by default
> >    he wants 'em all)
> >  - offloads set via ioctl() mean what userspace is expecting to get
> >    (this limits which admin wishes are granted)
> >  - TUN_NOCHECKSUM is ignored, as it might cause broken packets when
> >    forwarded (ip_summed == CHECKSUM_UNNECESSARY means that checksum
> >    was verified, not that it can be ignored)
> > 
> > If TUN_NOCHECKSUM is implemented, it should set skb->csum_* and
> > skb->ip_summed (= CHECKSUM_PARTIAL) for known protocols and let others
> > be verified by kernel when necessary.
> > 
> > TUN_NOCHECKSUM handling was introduced by commit
> > f43798c27684ab925adde7d8acc34c78c6e50df8:
> > 
> >     tun: Allow GSO using virtio_net_hdr
> >     
> > Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> 
> Applied.

Dave, you just removed a feature that has been in Linux since before
git.  It *probably* just means we go slower in cases we don't really
care about.  But does removing it break qemu?  Has anyone tested?

Thanks,
Rusty.

--
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
diff mbox

Patch

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f5e9ac0..ade3cf9 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -123,6 +123,9 @@  struct tun_struct {
 	gid_t			group;
 
 	struct net_device	*dev;
+	u32			set_features;
+#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
+			  NETIF_F_TSO6|NETIF_F_UFO)
 	struct fasync_struct	*fasync;
 
 	struct tap_filter       txflt;
@@ -451,12 +454,20 @@  tun_net_change_mtu(struct net_device *dev, int new_mtu)
 	return 0;
 }
 
+static u32 tun_net_fix_features(struct net_device *dev, u32 features)
+{
+	struct tun_struct *tun = netdev_priv(dev);
+
+	return (features & tun->set_features) | (features & ~TUN_USER_FEATURES);
+}
+
 static const struct net_device_ops tun_netdev_ops = {
 	.ndo_uninit		= tun_net_uninit,
 	.ndo_open		= tun_net_open,
 	.ndo_stop		= tun_net_close,
 	.ndo_start_xmit		= tun_net_xmit,
 	.ndo_change_mtu		= tun_net_change_mtu,
+	.ndo_fix_features	= tun_net_fix_features,
 };
 
 static const struct net_device_ops tap_netdev_ops = {
@@ -465,6 +476,7 @@  static const struct net_device_ops tap_netdev_ops = {
 	.ndo_stop		= tun_net_close,
 	.ndo_start_xmit		= tun_net_xmit,
 	.ndo_change_mtu		= tun_net_change_mtu,
+	.ndo_fix_features	= tun_net_fix_features,
 	.ndo_set_multicast_list	= tun_net_mclist,
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -628,8 +640,7 @@  static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
 			kfree_skb(skb);
 			return -EINVAL;
 		}
-	} else if (tun->flags & TUN_NOCHECKSUM)
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	}
 
 	switch (tun->flags & TUN_TYPE_MASK) {
 	case TUN_TUN_DEV:
@@ -1094,6 +1105,10 @@  static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 				goto err_free_sk;
 		}
 
+		dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
+			TUN_USER_FEATURES;
+		dev->features = dev->hw_features;
+
 		err = register_netdevice(tun->dev);
 		if (err < 0)
 			goto err_free_sk;
@@ -1158,18 +1173,12 @@  static int tun_get_iff(struct net *net, struct tun_struct *tun,
 
 /* This is like a cut-down ethtool ops, except done via tun fd so no
  * privs required. */
-static int set_offload(struct net_device *dev, unsigned long arg)
+static int set_offload(struct tun_struct *tun, unsigned long arg)
 {
-	u32 old_features, features;
-
-	old_features = dev->features;
-	/* Unset features, set them as we chew on the arg. */
-	features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
-				    |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
-				    |NETIF_F_UFO));
+	u32 features = 0;
 
 	if (arg & TUN_F_CSUM) {
-		features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+		features |= NETIF_F_HW_CSUM;
 		arg &= ~TUN_F_CSUM;
 
 		if (arg & (TUN_F_TSO4|TUN_F_TSO6)) {
@@ -1195,9 +1204,8 @@  static int set_offload(struct net_device *dev, unsigned long arg)
 	if (arg)
 		return -EINVAL;
 
-	dev->features = features;
-	if (old_features != dev->features)
-		netdev_features_change(dev);
+	tun->set_features = features;
+	netdev_update_features(tun->dev);
 
 	return 0;
 }
@@ -1262,12 +1270,9 @@  static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 
 	case TUNSETNOCSUM:
 		/* Disable/Enable checksum */
-		if (arg)
-			tun->flags |= TUN_NOCHECKSUM;
-		else
-			tun->flags &= ~TUN_NOCHECKSUM;
 
-		tun_debug(KERN_INFO, tun, "checksum %s\n",
+		/* [unimplemented] */
+		tun_debug(KERN_INFO, tun, "ignored: set checksum %s\n",
 			  arg ? "disabled" : "enabled");
 		break;
 
@@ -1316,7 +1321,7 @@  static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
 		break;
 #endif
 	case TUNSETOFFLOAD:
-		ret = set_offload(tun->dev, arg);
+		ret = set_offload(tun, arg);
 		break;
 
 	case TUNSETTXFILTER:
@@ -1595,30 +1600,12 @@  static void tun_set_msglevel(struct net_device *dev, u32 value)
 #endif
 }
 
-static u32 tun_get_rx_csum(struct net_device *dev)
-{
-	struct tun_struct *tun = netdev_priv(dev);
-	return (tun->flags & TUN_NOCHECKSUM) == 0;
-}
-
-static int tun_set_rx_csum(struct net_device *dev, u32 data)
-{
-	struct tun_struct *tun = netdev_priv(dev);
-	if (data)
-		tun->flags &= ~TUN_NOCHECKSUM;
-	else
-		tun->flags |= TUN_NOCHECKSUM;
-	return 0;
-}
-
 static const struct ethtool_ops tun_ethtool_ops = {
 	.get_settings	= tun_get_settings,
 	.get_drvinfo	= tun_get_drvinfo,
 	.get_msglevel	= tun_get_msglevel,
 	.set_msglevel	= tun_set_msglevel,
 	.get_link	= ethtool_op_get_link,
-	.get_rx_csum	= tun_get_rx_csum,
-	.set_rx_csum	= tun_set_rx_csum
 };