tun: export underlying socket
Subsystems (12)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Michael S. Tsirkin
maintainerPATCH 1/3 tun: export underlying socket
Tun device looks similar to a packet socket in that both pass complete frames from/to userspace.
This patch fills in enough fields in the socket underlying tun driver to support sendmsg/recvmsg operations, and message flags MSG_TRUNC and MSG_DONTWAIT, and exports access to this socket to modules. Regular read/write behaviour is unchanged.
This way, code using raw sockets to inject packets into a physical device, can support injecting packets into host network stack almost without modification.
First user of this interface will be vhost virtualization accelerator.
--- drivers/net/tun.c | 101 +++++++++++++++++++++++++++++++++++++++--------- include/linux/if_tun.h | 14 +++++++ 2 files changed, 96 insertions(+), 19 deletions(-)
drivers/net/tun.c +82 -19
@@ -144,6 +144,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file) err =0 ; tfile->tun = tun; tun->tfile = tfile; + tun->socket.file = file;dev_hold (tun->dev);sock_hold (tun->socket.sk);atomic_inc (&tfile->count);
@@ -158,6 +159,7 @@ static void __tun_detach(struct tun_struct *tun)/* Detach from net device */ netif_tx_lock_bh (tun->dev); tun->tfile =NULL ; + tun->socket.file =NULL ;netif_tx_unlock_bh (tun->dev);/* Drop read queue */
@@ -387,7 +389,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)/* Notify and wake up reader process */ if (tun->flags &TUN_FASYNC )kill_fasync (&tun->fasync,SIGIO ,POLL_IN ); -wake_up_interruptible (&tun->socket.wait); +wake_up_interruptible_poll (&tun->socket.wait,POLLIN | +POLLRDNORM |POLLRDBAND );return NETDEV_TX_OK ; drop:
@@ -743,7 +746,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, len =min_t (int, skb->len, len);skb_copy_datagram_const_iovec (skb,0 , iv, total, len); - total += len; + total += skb->len; tun->dev->stats.tx_packets++; tun->dev->stats.tx_bytes += len;
@@ -751,34 +754,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,return total; } -static ssize_t tun_chr_aio_read (struct kiocb *iocb,const struct iovec *iv, -unsigned long count,loff_t pos) +static ssize_t tun_do_read (struct tun_struct *tun, +struct kiocb *iocb,const struct iovec *iv, +ssize_t len,int noblock) { -struct file *file = iocb->ki_filp; -struct tun_file *tfile = file->private_data; -struct tun_struct *tun =__tun_get (tfile);DECLARE_WAITQUEUE (wait, current);struct sk_buff *skb; -ssize_t len, ret =0 ; - -if (!tun) -return -EBADFD ; +ssize_t ret =0 ;DBG (KERN_INFO "%s: tun_chr_read\n" , tun->dev->name); - len =iov_length (iv, count); -if (len <0 ) { - ret = -EINVAL ; - goto out; - } -add_wait_queue (&tun->socket.wait, &wait);while (len) { current->state =TASK_INTERRUPTIBLE ;/* Read frames from the queue */ if (!(skb=skb_dequeue (&tun->socket.sk->sk_receive_queue))) { -if (file->f_flags &O_NONBLOCK ) { +if (noblock) { ret = -EAGAIN ;break ; }
@@ -805,6 +797,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, current->state =TASK_RUNNING ;remove_wait_queue (&tun->socket.wait, &wait); +return ret; +} + +static ssize_t tun_chr_aio_read (struct kiocb *iocb,const struct iovec *iv, +unsigned long count,loff_t pos) +{ +struct file *file = iocb->ki_filp; +struct tun_file *tfile = file->private_data; +struct tun_struct *tun =__tun_get (tfile); +ssize_t len, ret; + +if (!tun) +return -EBADFD ; + len =iov_length (iv, count); +if (len <0 ) { + ret = -EINVAL ; + goto out; + } + + ret =tun_do_read (tun, iocb, iv, len, file->f_flags &O_NONBLOCK ); + ret =min_t (ssize_t, ret, len); out:tun_put (tun);return ret;
@@ -847,7 +860,8 @@ static void tun_sock_write_space(struct sock *sk)return ;if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep)) -wake_up_interruptible_sync (sk->sk_sleep); +wake_up_interruptible_sync_poll (sk->sk_sleep,POLLOUT | +POLLWRNORM |POLLWRBAND ); tun =tun_sk (sk)->tun;kill_fasync (&tun->fasync,SIGIO ,POLL_OUT );
@@ -858,6 +872,37 @@ static void tun_sock_destruct(struct sock *sk)free_netdev (tun_sk (sk)->tun->dev); } +static int tun_sendmsg (struct kiocb *iocb,struct socket *sock, +struct msghdr *m,size_t total_len) +{ + struct tun_struct *tun = container_of(sock, struct tun_struct, socket); +return tun_get_user (tun, m->msg_iov, total_len, + m->msg_flags &MSG_DONTWAIT ); +} + +static int tun_recvmsg (struct kiocb *iocb,struct socket *sock, +struct msghdr *m,size_t total_len, +int flags) +{ + struct tun_struct *tun = container_of(sock, struct tun_struct, socket); +int ret; +if (flags & ~(MSG_DONTWAIT |MSG_TRUNC )) +return -EINVAL ; + ret =tun_do_read (tun, iocb, m->msg_iov, total_len, + flags &MSG_DONTWAIT ); +if (ret > total_len) { + m->msg_flags |=MSG_TRUNC ; + ret = flags &MSG_TRUNC ? ret : total_len; + } +return ret; +} + +/* Ops structure to mimic raw sockets with tun */ +static const struct proto_ops tun_socket_ops = { + .sendmsg = tun_sendmsg, + .recvmsg = tun_recvmsg, +}; +static struct proto tun_proto = { .name ="tun" , .owner =THIS_MODULE ,
@@ -986,6 +1031,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) goto err_free_dev;init_waitqueue_head (&tun->socket.wait); + tun->socket.ops = &tun_socket_ops;sock_init_data (&tun->socket, sk); sk->sk_write_space = tun_sock_write_space; sk->sk_sndbuf =INT_MAX ;
@@ -1525,6 +1571,23 @@ static void tun_cleanup(void)rtnl_link_unregister (&tun_link_ops); } +/* Get an underlying socket object from tun file. Returns error unless file is +* attached to a device. The returned object works like a packet socket, it +* can be used for sock_sendmsg/sock_recvmsg. The caller is responsible for +* holding a reference to the file for as long as the socket is in use. */ +struct socket *tun_get_socket (struct file *file) +{ +struct tun_struct *tun; +if (file->f_op != &tun_fops) +return ERR_PTR (-EINVAL ); + tun =tun_get (file); +if (!tun) +return ERR_PTR (-EBADFD ); +tun_put (tun); +return &tun->socket; +} +EXPORT_SYMBOL_GPL (tun_get_socket); +module_init (tun_init);module_exit (tun_cleanup);MODULE_DESCRIPTION (DRV_DESCRIPTION );
include/linux/if_tun.h +14 -0
@@ -86,4 +86,18 @@ struct tun_filter { __u8 addr[0][ETH_ALEN]; }; +#ifdef __KERNEL__ +#if defined(CONFIG_TUN ) || defined(CONFIG_TUN_MODULE ) +struct socket *tun_get_socket (struct file *); +#else +#include <linux/err.h> +#include <linux/errno.h> +struct file ; +struct socket ; +static inline struct socket *tun_get_socket (struct file *f) +{ +return ERR_PTR (-EINVAL ); +} +#endif /* CONFIG_TUN */ +#endif /* __KERNEL__ */ #endif /* __IF_TUN_H */
Signature · 1 line
1.6.6.144.g5c3af
Michael S. Tsirkin
maintainerPATCH 2/3 mm: export use_mm/unuse_mm to modules
In reply to a message not in the archivevhost net module wants to do copy to/from user from a kernel thread, which needs use_mm. Export it to modules.
--- mm/mmu_context.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
mm/mmu_context.c +3 -0
@@ -5,6 +5,7 @@#include <linux/mm.h> #include <linux/mmu_context.h> +#include <linux/module.h> #include <linux/sched.h> #include <asm/mmu_context.h>
@@ -37,6 +38,7 @@ void use_mm(struct mm_struct *mm)if (active_mm != mm)mmdrop (active_mm); } +EXPORT_SYMBOL_GPL (use_mm);/* * unuse_mm
@@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm)enter_lazy_tlb (mm, tsk);task_unlock (tsk); } +EXPORT_SYMBOL_GPL (unuse_mm);
Signature · 1 line
1.6.6.144.g5c3af
Michael S. Tsirkin
maintainerPATCH 3/3 vhost_net: a kernel-level virtio server
In reply to a message not in the archiveWhat it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.
There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration, bug work-arounds in userspace)
- write logging is supported (good for migration)
- support memory table and not just an offset (needed for kvm)
common virtio related code has been put in a separate file vhost.c and can be made into a separate module if/when more backends appear. I used Rusty's lguest.c as the source for developing this part : this supplied me with witty comments I wouldn't be able to write myself.
What it is not: vhost net is not a bus, and not a generic new system call. No assumptions are made on how guest performs hypercalls. Userspace hypervisors are supported as well as kvm.
How it works: Basically, we connect virtio frontend (configured by userspace) to a backend. The backend could be a network device, or a tap device. Backend is also configured by userspace, including vlan/mac etc.
Status: This works for me, and I haven't see any crashes. Compared to userspace, people reported improved latency (as I save up to 4 system calls per packet), as well as better bandwidth and CPU utilization.
Features that I plan to look at in the future:
- mergeable buffers
- zero copy
- scalability tuning: figure out the best threading model to use
Note on RCU usage (this is also documented in vhost.h, near private_pointer which is the value protected by this variant of RCU):
what is happening is that the rcu_dereference() is being used in a workqueue item. The role of rcu_read_lock() is taken on by the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue()/flush_work(). In the future we might need to apply some gcc attribute or sparse annotation to the function passed to INIT_WORK(). Paul's ack below is for this RCU usage.
(Includes fixes by Alan Cox <[email protected]>, David L Stevens <[email protected]>, Chris Wright <[email protected]>)
--- MAINTAINERS | 9 + arch/ia64/kvm/Kconfig | 1 + arch/powerpc/kvm/Kconfig | 1 + arch/s390/kvm/Kconfig | 1 + arch/x86/kvm/Kconfig | 1 + drivers/Makefile | 1 + drivers/vhost/Kconfig | 11 + drivers/vhost/Makefile | 2 + drivers/vhost/net.c | 661 ++++++++++++++++++++++++++ drivers/vhost/vhost.c | 1098 ++++++++++++++++++++++++++++++++++++++++++++ drivers/vhost/vhost.h | 161 +++++++ include/linux/Kbuild | 1 + include/linux/miscdevice.h | 1 + include/linux/vhost.h | 130 ++++++ 14 files changed, 2079 insertions(+), 0 deletions(-) create mode 100644 drivers/vhost/Kconfig create mode 100644 drivers/vhost/Makefile create mode 100644 drivers/vhost/net.c create mode 100644 drivers/vhost/vhost.c create mode 100644 drivers/vhost/vhost.h create mode 100644 include/linux/vhost.h
MAINTAINERS +9 -0
@@ -5803,6 +5803,15 @@ S: Maintained F: Documentation/filesystems/vfat.txt F: fs/fat/ +VIRTIO HOST (VHOST) +M: "Michael S. Tsirkin" <[email protected]> +L: [email protected] +L: [email protected] +L: [email protected] +S: Maintained +F: drivers/vhost/ +F: include/linux/vhost.h + VIA RHINE NETWORK DRIVER M: Roger Luethi <[email protected]> S: Maintained
arch/ia64/kvm/Kconfig +1 -0
@@ -47,6 +47,7 @@ config KVM_INTEL Provides support for KVM on Itanium 2 processors equipped with the VT extensions. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION
arch/powerpc/kvm/Kconfig +1 -0
@@ -75,6 +75,7 @@ config KVM_E500 If unsure, say N. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION
arch/s390/kvm/Kconfig +1 -0
@@ -35,6 +35,7 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION
arch/x86/kvm/Kconfig +1 -0
@@ -65,6 +65,7 @@ config KVM_AMD # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/lguest/Kconfig source drivers/virtio/Kconfig
drivers/Makefile +1 -0
@@ -106,6 +106,7 @@ obj-$(CONFIG_HID) += hid/ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ +obj-$(CONFIG_VHOST_NET) += vhost/ obj-$(CONFIG_VIRTIO) += virtio/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/
drivers/vhost/Kconfig new file +11 -0
@@ -0,0 +1,11 @@ +config VHOST_NET + tristate "Host kernel accelerator for virtio net (EXPERIMENTAL)" + depends on NET && EVENTFD && EXPERIMENTAL + ---help--- + This kernel module can be loaded in host kernel to accelerate + guest networking with virtio_net. Not to be confused with virtio_net + module itself which needs to be loaded in guest kernel. + + To compile this driver as a module, choose M here: the module will + be called vhost_net. +
drivers/vhost/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +obj-$(CONFIG_VHOST_NET) += vhost_net.o +vhost_net-y := vhost.o net.o
drivers/vhost/net.c new file +661 -0
661 lines not on this page · raw message
drivers/vhost/vhost.c new file +1098 -0
1,098 lines not on this page · raw message
drivers/vhost/vhost.h new file +161 -0
161 lines not on this page · raw message
include/linux/Kbuild +1 -0
@@ -362,6 +362,7 @@ unifdef-y += uio.h unifdef-y += unistd.h unifdef-y += usbdevice_fs.h unifdef-y += utsname.h +unifdef-y += vhost.h unifdef-y += videodev2.h unifdef-y += videodev.h unifdef-y += virtio_config.h
include/linux/miscdevice.h +1 -0
@@ -30,6 +30,7 @@#define HPET_MINOR 228#define FUSE_MINOR 229#define KVM_MINOR 232 +#define VHOST_NET_MINOR 233#define MISC_DYNAMIC_MINOR 255struct device ;
include/linux/vhost.h new file +130 -0
130 lines not on this page · raw message
Signature · 1 line
1.6.6.144.g5c3af