2336 lines · 54.5 KB · C
RawDownload
/* *  TUN - Universal TUN/TAP device driver. *  Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *  GNU General Public License for more details. * *  $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $ */ /* *  Changes: * *  Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14 *    Add TUNSETLINK ioctl to set the link encapsulation * *  Mark Smith <markzzzsmith@yahoo.com.au> *    Use eth_random_addr() for tap MAC address. * *  Harald Roelle <harald.roelle@ifi.lmu.de>  2004/04/20 *    Fixes in packet dropping, queue length setting and queue wakeup. *    Increased default tx queue length. *    Added ethtool API. *    Minor cleanups * *  Daniel Podlejski <underley@underley.eu.org> *    Modifications for 2.3.99-pre5 kernel. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define DRV_NAME	"tun"#define DRV_VERSION	"1.6"#define DRV_DESCRIPTION	"Universal TUN/TAP device driver"#define DRV_COPYRIGHT	"(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>" #include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/miscdevice.h>#include <linux/ethtool.h>#include <linux/rtnetlink.h>#include <linux/compat.h>#include <linux/if.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/if_tun.h>#include <linux/if_vlan.h>#include <linux/crc32.h>#include <linux/nsproxy.h>#include <linux/virtio_net.h>#include <linux/rcupdate.h>#include <net/net_namespace.h>#include <net/netns/generic.h>#include <net/rtnetlink.h>#include <net/sock.h> #include <asm/uaccess.h> /* Uncomment to enable debugging *//* #define TUN_DEBUG 1 */ #ifdef TUN_DEBUGstatic int debug; #define tun_debug(level, tun, fmt, args...)			\do {								\	if (tun->debug)						\		netdev_printk(level, tun->dev, fmt, ##args);	\} while (0)#define DBG1(level, fmt, args...)				\do {								\	if (debug == 2)						\		printk(level fmt, ##args);			\} while (0)#else#define tun_debug(level, tun, fmt, args...)			\do {								\	if (0)							\		netdev_printk(level, tun->dev, fmt, ##args);	\} while (0)#define DBG1(level, fmt, args...)				\do {								\	if (0)							\		printk(level fmt, ##args);			\} while (0)#endif #define GOODCOPY_LEN 128 #define FLT_EXACT_COUNT 8struct tap_filter {	unsigned int    count;    /* Number of addrs. Zero means disabled */	u32             mask[2];  /* Mask of the hashed addrs */	unsigned char	addr[FLT_EXACT_COUNT][ETH_ALEN];}; /* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for * the netdevice to be fit in one page. So we can make sure the success of * memory allocation. TODO: increase the limit. */#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES#define MAX_TAP_FLOWS  4096 #define TUN_FLOW_EXPIRE (3 * HZ) /* A tun_file connects an open character device to a tuntap netdevice. It * also contains all socket related strctures (except sock_fprog and tap_filter) * to serve as one transmit queue for tuntap device. The sock_fprog and * tap_filter were kept in tun_struct since they were used for filtering for the * netdevice not for a specific queue (at least I didn't see the requirement for * this). * * RCU usage: * The tun_file and tun_struct are loosely coupled, the pointer from one to the * other can only be read while rcu_read_lock or rtnl_lock is held. */struct tun_file {	struct sock sk;	struct socket socket;	struct socket_wq wq;	struct tun_struct __rcu *tun;	struct net *net;	struct fasync_struct *fasync;	/* only used for fasnyc */	unsigned int flags;	union {		u16 queue_index;		unsigned int ifindex;	};	struct list_head next;	struct tun_struct *detached;}; struct tun_flow_entry {	struct hlist_node hash_link;	struct rcu_head rcu;	struct tun_struct *tun; 	u32 rxhash;	int queue_index;	unsigned long updated;}; #define TUN_NUM_FLOW_ENTRIES 1024 /* Since the socket were moved to tun_file, to preserve the behavior of persist * device, socket filter, sndbuf and vnet header size were restore when the * file were attached to a persist device. */struct tun_struct {	struct tun_file __rcu	*tfiles[MAX_TAP_QUEUES];	unsigned int            numqueues;	unsigned int 		flags;	kuid_t			owner;	kgid_t			group; 	struct net_device	*dev;	netdev_features_t	set_features;#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \			  NETIF_F_TSO6|NETIF_F_UFO) 	int			vnet_hdr_sz;	int			sndbuf;	struct tap_filter	txflt;	struct sock_fprog	fprog;	/* protected by rtnl lock */	bool			filter_attached;#ifdef TUN_DEBUG	int debug;#endif	spinlock_t lock;	struct hlist_head flows[TUN_NUM_FLOW_ENTRIES];	struct timer_list flow_gc_timer;	unsigned long ageing_time;	unsigned int numdisabled;	struct list_head disabled;	void *security;	u32 flow_count;}; static inline u32 tun_hashfn(u32 rxhash){	return rxhash & 0x3ff;} static struct tun_flow_entry *tun_flow_find(struct hlist_head *head, u32 rxhash){	struct tun_flow_entry *e; 	hlist_for_each_entry_rcu(e, head, hash_link) {		if (e->rxhash == rxhash)			return e;	}	return NULL;} static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun,					      struct hlist_head *head,					      u32 rxhash, u16 queue_index){	struct tun_flow_entry *e = kmalloc(sizeof(*e), GFP_ATOMIC); 	if (e) {		tun_debug(KERN_INFO, tun, "create flow: hash %u index %u\n",			  rxhash, queue_index);		e->updated = jiffies;		e->rxhash = rxhash;		e->queue_index = queue_index;		e->tun = tun;		hlist_add_head_rcu(&e->hash_link, head);		++tun->flow_count;	}	return e;} static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e){	tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n",		  e->rxhash, e->queue_index);	hlist_del_rcu(&e->hash_link);	kfree_rcu(e, rcu);	--tun->flow_count;} static void tun_flow_flush(struct tun_struct *tun){	int i; 	spin_lock_bh(&tun->lock);	for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) {		struct tun_flow_entry *e;		struct hlist_node *n; 		hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link)			tun_flow_delete(tun, e);	}	spin_unlock_bh(&tun->lock);} static void tun_flow_delete_by_queue(struct tun_struct *tun, u16 queue_index){	int i; 	spin_lock_bh(&tun->lock);	for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) {		struct tun_flow_entry *e;		struct hlist_node *n; 		hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) {			if (e->queue_index == queue_index)				tun_flow_delete(tun, e);		}	}	spin_unlock_bh(&tun->lock);} static void tun_flow_cleanup(unsigned long data){	struct tun_struct *tun = (struct tun_struct *)data;	unsigned long delay = tun->ageing_time;	unsigned long next_timer = jiffies + delay;	unsigned long count = 0;	int i; 	tun_debug(KERN_INFO, tun, "tun_flow_cleanup\n"); 	spin_lock_bh(&tun->lock);	for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++) {		struct tun_flow_entry *e;		struct hlist_node *n; 		hlist_for_each_entry_safe(e, n, &tun->flows[i], hash_link) {			unsigned long this_timer;			count++;			this_timer = e->updated + delay;			if (time_before_eq(this_timer, jiffies))				tun_flow_delete(tun, e);			else if (time_before(this_timer, next_timer))				next_timer = this_timer;		}	} 	if (count)		mod_timer(&tun->flow_gc_timer, round_jiffies_up(next_timer));	spin_unlock_bh(&tun->lock);} static void tun_flow_update(struct tun_struct *tun, u32 rxhash,			    struct tun_file *tfile){	struct hlist_head *head;	struct tun_flow_entry *e;	unsigned long delay = tun->ageing_time;	u16 queue_index = tfile->queue_index; 	if (!rxhash)		return;	else		head = &tun->flows[tun_hashfn(rxhash)]; 	rcu_read_lock(); 	/* We may get a very small possibility of OOO during switching, not	 * worth to optimize.*/	if (tun->numqueues == 1 || tfile->detached)		goto unlock; 	e = tun_flow_find(head, rxhash);	if (likely(e)) {		/* TODO: keep queueing to old queue until it's empty? */		e->queue_index = queue_index;		e->updated = jiffies;	} else {		spin_lock_bh(&tun->lock);		if (!tun_flow_find(head, rxhash) &&		    tun->flow_count < MAX_TAP_FLOWS)			tun_flow_create(tun, head, rxhash, queue_index); 		if (!timer_pending(&tun->flow_gc_timer))			mod_timer(&tun->flow_gc_timer,				  round_jiffies_up(jiffies + delay));		spin_unlock_bh(&tun->lock);	} unlock:	rcu_read_unlock();} /* We try to identify a flow through its rxhash first. The reason that * we do not check rxq no. is becuase some cards(e.g 82599), chooses * the rxq based on the txq where the last packet of the flow comes. As * the userspace application move between processors, we may get a * different rxq no. here. If we could not get rxhash, then we would * hope the rxq no. may help here. */static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,			    void *accel_priv){	struct tun_struct *tun = netdev_priv(dev);	struct tun_flow_entry *e;	u32 txq = 0;	u32 numqueues = 0; 	rcu_read_lock();	numqueues = ACCESS_ONCE(tun->numqueues); 	txq = skb_get_rxhash(skb);	if (txq) {		e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq);		if (e)			txq = e->queue_index;		else			/* use multiply and shift instead of expensive divide */			txq = ((u64)txq * numqueues) >> 32;	} else if (likely(skb_rx_queue_recorded(skb))) {		txq = skb_get_rx_queue(skb);		while (unlikely(txq >= numqueues))			txq -= numqueues;	} 	rcu_read_unlock();	return txq;} static inline bool tun_not_capable(struct tun_struct *tun){	const struct cred *cred = current_cred();	struct net *net = dev_net(tun->dev); 	return ((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) ||		  (gid_valid(tun->group) && !in_egroup_p(tun->group))) &&		!ns_capable(net->user_ns, CAP_NET_ADMIN);} static void tun_set_real_num_queues(struct tun_struct *tun){	netif_set_real_num_tx_queues(tun->dev, tun->numqueues);	netif_set_real_num_rx_queues(tun->dev, tun->numqueues);} static void tun_disable_queue(struct tun_struct *tun, struct tun_file *tfile){	tfile->detached = tun;	list_add_tail(&tfile->next, &tun->disabled);	++tun->numdisabled;} static struct tun_struct *tun_enable_queue(struct tun_file *tfile){	struct tun_struct *tun = tfile->detached; 	tfile->detached = NULL;	list_del_init(&tfile->next);	--tun->numdisabled;	return tun;} static void tun_queue_purge(struct tun_file *tfile){	skb_queue_purge(&tfile->sk.sk_receive_queue);	skb_queue_purge(&tfile->sk.sk_error_queue);} static void __tun_detach(struct tun_file *tfile, bool clean){	struct tun_file *ntfile;	struct tun_struct *tun; 	tun = rtnl_dereference(tfile->tun); 	if (tun && !tfile->detached) {		u16 index = tfile->queue_index;		BUG_ON(index >= tun->numqueues); 		rcu_assign_pointer(tun->tfiles[index],				   tun->tfiles[tun->numqueues - 1]);		ntfile = rtnl_dereference(tun->tfiles[index]);		ntfile->queue_index = index; 		--tun->numqueues;		if (clean) {			rcu_assign_pointer(tfile->tun, NULL);			sock_put(&tfile->sk);		} else			tun_disable_queue(tun, tfile); 		synchronize_net();		tun_flow_delete_by_queue(tun, tun->numqueues + 1);		/* Drop read queue */		tun_queue_purge(tfile);		tun_set_real_num_queues(tun);	} else if (tfile->detached && clean) {		tun = tun_enable_queue(tfile);		sock_put(&tfile->sk);	} 	if (clean) {		if (tun && tun->numqueues == 0 && tun->numdisabled == 0) {			netif_carrier_off(tun->dev); 			if (!(tun->flags & TUN_PERSIST) &&			    tun->dev->reg_state == NETREG_REGISTERED)				unregister_netdevice(tun->dev);		} 		BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,				 &tfile->socket.flags));		sk_release_kernel(&tfile->sk);	}} static void tun_detach(struct tun_file *tfile, bool clean){	rtnl_lock();	__tun_detach(tfile, clean);	rtnl_unlock();} static void tun_detach_all(struct net_device *dev){	struct tun_struct *tun = netdev_priv(dev);	struct tun_file *tfile, *tmp;	int i, n = tun->numqueues; 	for (i = 0; i < n; i++) {		tfile = rtnl_dereference(tun->tfiles[i]);		BUG_ON(!tfile);		wake_up_all(&tfile->wq.wait);		rcu_assign_pointer(tfile->tun, NULL);		--tun->numqueues;	}	list_for_each_entry(tfile, &tun->disabled, next) {		wake_up_all(&tfile->wq.wait);		rcu_assign_pointer(tfile->tun, NULL);	}	BUG_ON(tun->numqueues != 0); 	synchronize_net();	for (i = 0; i < n; i++) {		tfile = rtnl_dereference(tun->tfiles[i]);		/* Drop read queue */		tun_queue_purge(tfile);		sock_put(&tfile->sk);	}	list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {

Lines 1–500 of 2336.