Skip to content

Commit 5228ddc

Browse files
rustyrusselldavem330
authored andcommitted
tun: TUNSETFEATURES to set gso features.
ethtool is useful for setting (some) device fields, but it's root-only. Finer feature control is available through a tun-specific ioctl. (Includes Mark McLoughlin <markmc@redhat.com>'s fix to hold rtnl sem). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Acked-by: Max Krasnyansky <maxk@qualcomm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 07240fd commit 5228ddc

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

drivers/net/tun.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,46 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
611611
return err;
612612
}
613613

614+
/* This is like a cut-down ethtool ops, except done via tun fd so no
615+
* privs required. */
616+
static int set_offload(struct net_device *dev, unsigned long arg)
617+
{
618+
unsigned int old_features, features;
619+
620+
old_features = dev->features;
621+
/* Unset features, set them as we chew on the arg. */
622+
features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
623+
|NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6));
624+
625+
if (arg & TUN_F_CSUM) {
626+
features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
627+
arg &= ~TUN_F_CSUM;
628+
629+
if (arg & (TUN_F_TSO4|TUN_F_TSO6)) {
630+
if (arg & TUN_F_TSO_ECN) {
631+
features |= NETIF_F_TSO_ECN;
632+
arg &= ~TUN_F_TSO_ECN;
633+
}
634+
if (arg & TUN_F_TSO4)
635+
features |= NETIF_F_TSO;
636+
if (arg & TUN_F_TSO6)
637+
features |= NETIF_F_TSO6;
638+
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
639+
}
640+
}
641+
642+
/* This gives the user a way to test for new features in future by
643+
* trying to set them. */
644+
if (arg)
645+
return -EINVAL;
646+
647+
dev->features = features;
648+
if (old_features != dev->features)
649+
netdev_features_change(dev);
650+
651+
return 0;
652+
}
653+
614654
static int tun_chr_ioctl(struct inode *inode, struct file *file,
615655
unsigned int cmd, unsigned long arg)
616656
{
@@ -715,6 +755,15 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
715755
break;
716756
#endif
717757

758+
case TUNSETOFFLOAD:
759+
{
760+
int ret;
761+
rtnl_lock();
762+
ret = set_offload(tun->dev, arg);
763+
rtnl_unlock();
764+
return ret;
765+
}
766+
718767
case SIOCGIFFLAGS:
719768
ifr.ifr_flags = tun->if_flags;
720769
if (copy_to_user( argp, &ifr, sizeof ifr))

include/linux/if_tun.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,20 @@
4141
#define TUNSETLINK _IOW('T', 205, int)
4242
#define TUNSETGROUP _IOW('T', 206, int)
4343
#define TUNGETFEATURES _IOR('T', 207, unsigned int)
44+
#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)
4445

4546
/* TUNSETIFF ifr flags */
4647
#define IFF_TUN 0x0001
4748
#define IFF_TAP 0x0002
4849
#define IFF_NO_PI 0x1000
4950
#define IFF_ONE_QUEUE 0x2000
5051

52+
/* Features for GSO (TUNSETOFFLOAD). */
53+
#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */
54+
#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */
55+
#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */
56+
#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
57+
5158
struct tun_pi {
5259
unsigned short flags;
5360
__be16 proto;

0 commit comments

Comments
 (0)