Skip to contentSkip to conversation

virtual-bus

RFC PATCH Superseded Gregory Haskins 2 participants 20 messages Apr 21, 2009 – May 11, 2009

Subsystems (13)
lore
Share & tools
lore
#0 lore raw

v3 cover virtual-bus

RFC: Virtual-Bus (applies to v2.6.30-rc2)
----------------------

Virtual-Bus is a Linux-kernel based virtual IO resource container technology. It allows you to declare virtualized device models directly within a host kernel that can be uniformly accessed from a variety of environments, such as KVM, userspace, lguest, Xen, etc. The goal is to reduce overhead while still preserving proper isolation to achieve maximum throughput and latency from your IO subsystem. It is installed on the host and configured using simple filesystem operations like "mkdir" to create a new container, "ln -s" to associate a device with a container, and "echo" to configure the device thanks to integration with configfs/sysfs. Therefore, managing a virtual-bus does not require special userspace tools.

Why would we want this?
----------------------

We believe that a combination of in-kernel models, coupled with optimizations in various areas such as reducing the number of context switches and executing the algorithms in parallel on modern multicore CPUs will result in the best possible IO performance for technologies such as virtualization. This facility aims to provide the framework for building such constructs in in software in the most efficient way we believe is possible.

Preliminary Results:
-----------------------

As a test, we wrote a virtual-ethernet backend and a Linux driver (called venet) and tested the setup with v2.6.29 on two 8-core x86_64 boxes with Chelsio T3 10GE connected back to back via cross over. We measured bare-metal performance, as well as a kvm guest (running the same kernel) connected to the T3 via a linux-bridge+tap configuration with a 1500 MTU. The results are as follows:

Bare metal : tput = 4078Mb/s, round-trip = 25593pps (39us rtt)
Virtio-net (PCI) : tput = 4003Mb/s, round-trip = 320pps (3125us rtt)
Venet (VBUS): tput = 4050Mb/s, round-trip = 15255 (65us rtt)

When we jump to 9000 byte MTU, the situation looks similar

Bare metal : tput = 9717Mb/s, round-trip = 30396pps (33us rtt)
Virtio-net (PCI) : tput = 4578Mb/s, round-trip = 249pps (4016us rtt)
Venet (VBUS): tput = 5802Mb/s, round-trip = 15127 (66us rtt)

Note that to be fair, part of the latency response from virtio-pci is due to the way that the driver/backend coalesces packets, and not a true limitation of the userspace path as the results may imply. Anthony Liguori is already looking into improving this based on the results we presented here, and is making good headway.

Also note that as of v2, we support a virtio-vbus transport, and therefore will soon be able to compare "Virtio-net (VBUS)" as an additional target in the near future once we have developed a virtio-net backend for the host. This virtio-net(pci) to virtio-net(vbus) comparison is probably more interesting than comparing to Venet as it would be more apples to apples. Also it would be nice to only need one PV driver per IO subsystem in the long term.

Changes v2->v3:
------------------

*) VBUS now renders as a PCI/MSI device instead of via cpuid/dynirq *) Dropped dynirq (replaced with MSI facility)
*) Dropped "reset" patch in favor of more reliably detecting reset via BUSOPEN *) Incorporated more review feedback from Stephen Hemminger on vbus-enet
driver
*) Added support for setting the guests MAC during host config (Pat Mullaney) *) Cleaned up documentation per feedback from Ben Hutchings
*) Numerous small tweaks to clean up things like warnings, comments, etc.
(Alex Tsariounov, Greg Haskins)
*) Fixed Kconfig dependency problem with virtio-vbus with feedback from
Peter Morreale.

Changes v1->v2:

*) Incorporated review feedback from Stephen Hemminger on vbus-enet driver *) Added support for connecting to vbus devices from userspace *) Added support for a virtio-vbus transport to allow virtio drivers to
work with vbus (needs testing and backend models).

Todo:
*) Beef up the userspace event channel ABI to support different event types *) Add memory-registration support
*) Develop some virtio backend devices.
*) Support ethtool_ops for venet.
*) Convert from MSI to MSIX to truely support multiple vectors

---------------------------------------

For more details, please see our Wiki at

http://developer.novell.com/wiki/index.php/Virtual-bus

---

Gregory Haskins (16):
virtio: add a vbus transport
vbus: add a userspace connector
kvm: Add guest-side support for VBUS
kvm: Add VBUS support to the host
venettap: add scatter-gather support
venet: add scatter-gather support
venet-tap: Adds a "venet" compatible "tap" device to VBUS
net: Add vbus_enet driver
venet: add the ABI definitions for an 802.x packet interface
ioq: add vbus helpers
ioq: Add basic definitions for a shared-memory, lockless queue
vbus: add a "vbus-proxy" bus model for vbus_driver objects
vbus: add bus-registration notifiers
vbus: add connection-client helper infrastructure
vbus: add virtual-bus definitions
shm-signal: shared-memory signals

Patrick Mullaney (1):
venet-tap: add the ability to set the client's mac address via sysfs

 Documentation/vbus.txt           |  385 +++++++++
 arch/x86/Kconfig                 |   11 
 arch/x86/include/asm/kvm_para.h  |    1 
 arch/x86/kvm/Kconfig             |    9 
 arch/x86/kvm/Makefile            |    3 
 arch/x86/kvm/x86.c               |    6 
 arch/x86/kvm/x86.h               |   12 
 drivers/Makefile                 |    2 
 drivers/net/Kconfig              |   13 
 drivers/net/Makefile             |    1 
 drivers/net/vbus-enet.c          |  898 +++++++++++++++++++++
 drivers/vbus/devices/Kconfig     |   17 
 drivers/vbus/devices/Makefile    |    1 
 drivers/vbus/devices/venet-tap.c | 1641 ++++++++++++++++++++++++++++++++++++++
 drivers/vbus/proxy/Makefile      |    2 
 drivers/vbus/proxy/kvm.c         |  751 +++++++++++++++++
 drivers/virtio/Kconfig           |   15 
 drivers/virtio/Makefile          |    1 
 drivers/virtio/virtio_vbus.c     |  496 +++++++++++
 fs/proc/base.c                   |   96 ++
 include/linux/ioq.h              |  410 +++++++++
 include/linux/kvm.h              |    7 
 include/linux/kvm_host.h         |   26 +
 include/linux/kvm_para.h         |   58 +
 include/linux/sched.h            |    4 
 include/linux/shm_signal.h       |  188 ++++
 include/linux/vbus.h             |  166 ++++
 include/linux/vbus_client.h      |  115 +++
 include/linux/vbus_device.h      |  424 ++++++++++
 include/linux/vbus_driver.h      |   80 ++
 include/linux/vbus_userspace.h   |   48 +
 include/linux/venet.h            |   82 ++
 include/linux/virtio_vbus.h      |  163 ++++
 kernel/Makefile                  |    1 
 kernel/exit.c                    |    2 
 kernel/fork.c                    |    2 
 kernel/vbus/Kconfig              |   56 +
 kernel/vbus/Makefile             |   11 
 kernel/vbus/attribute.c          |   52 +
 kernel/vbus/client.c             |  543 +++++++++++++
 kernel/vbus/config.c             |  275 ++++++
 kernel/vbus/core.c               |  626 ++++++++++++++
 kernel/vbus/devclass.c           |  124 +++
 kernel/vbus/map.c                |   72 ++
 kernel/vbus/map.h                |   41 +
 kernel/vbus/proxy.c              |  216 +++++
 kernel/vbus/shm-ioq.c            |   89 ++
 kernel/vbus/userspace-client.c   |  485 +++++++++++
 kernel/vbus/vbus.h               |  117 +++
 kernel/vbus/virtio.c             |  627 +++++++++++++++
 lib/Kconfig                      |   21 
 lib/Makefile                     |    2 
 lib/ioq.c                        |  298 +++++++
 lib/shm_signal.c                 |  186 ++++
 virt/kvm/kvm_main.c              |   10 
 virt/kvm/vbus.c                  | 1392 ++++++++++++++++++++++++++++++++
 56 files changed, 11380 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/vbus.txt
 create mode 100644 drivers/net/vbus-enet.c
 create mode 100644 drivers/vbus/devices/Kconfig
 create mode 100644 drivers/vbus/devices/Makefile
 create mode 100644 drivers/vbus/devices/venet-tap.c
 create mode 100644 drivers/vbus/proxy/Makefile
 create mode 100644 drivers/vbus/proxy/kvm.c
 create mode 100644 drivers/virtio/virtio_vbus.c
 create mode 100644 include/linux/ioq.h
 create mode 100644 include/linux/shm_signal.h
 create mode 100644 include/linux/vbus.h
 create mode 100644 include/linux/vbus_client.h
 create mode 100644 include/linux/vbus_device.h
 create mode 100644 include/linux/vbus_driver.h
 create mode 100644 include/linux/vbus_userspace.h
 create mode 100644 include/linux/venet.h
 create mode 100644 include/linux/virtio_vbus.h
 create mode 100644 kernel/vbus/Kconfig
 create mode 100644 kernel/vbus/Makefile
 create mode 100644 kernel/vbus/attribute.c
 create mode 100644 kernel/vbus/client.c
 create mode 100644 kernel/vbus/config.c
 create mode 100644 kernel/vbus/core.c
 create mode 100644 kernel/vbus/devclass.c
 create mode 100644 kernel/vbus/map.c
 create mode 100644 kernel/vbus/map.h
 create mode 100644 kernel/vbus/proxy.c
 create mode 100644 kernel/vbus/shm-ioq.c
 create mode 100644 kernel/vbus/userspace-client.c
 create mode 100644 kernel/vbus/vbus.h
 create mode 100644 kernel/vbus/virtio.c
 create mode 100644 lib/ioq.c
 create mode 100644 lib/shm_signal.c
 create mode 100644 virt/kvm/vbus.c
#1 lore raw

RFC PATCH v3 1/17 shm-signal: shared-memory signals

This interface provides a bidirectional shared-memory based signaling mechanism. It can be used by any entities which desire efficient communication via shared memory. The implementation details of the signaling are abstracted so that they may transcend a wide variety of locale boundaries (e.g. userspace/kernel, guest/host, etc).

The shm_signal mechanism supports event masking as well as spurious event delivery mitigation.

---

 include/linux/shm_signal.h |  188 ++++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig                |    9 ++
 lib/Makefile               |    1 
 lib/shm_signal.c           |  186 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 384 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/shm_signal.h
 create mode 100644 lib/shm_signal.c
include/linux/shm_signal.h new file +188 -0
new file mode 100644
index 0000000..a65e54e
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Author:
+ *      Gregory Haskins <[email protected]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_SHM_SIGNAL_H
+#define _LINUX_SHM_SIGNAL_H
+
+#include <asm/types.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc).  Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+
+#define SHM_SIGNAL_MAGIC 0x58fa39df
+#define SHM_SIGNAL_VER   1
+
+struct shm_signal_irq {
+	__u8                  enabled;
+	__u8                  pending;
+	__u8                  dirty;
+};
+
+enum shm_signal_locality {
+	shm_locality_north,
+	shm_locality_south,
+};
+
+struct shm_signal_desc {
+	__u32                 magic;
+	__u32                 ver;
+	struct shm_signal_irq irq[2];
+};
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/interrupt.h>
+
+struct shm_signal_notifier {
+	void (*signal)(struct shm_signal_notifier *);
+};
+
+struct shm_signal;
+
+struct shm_signal_ops {
+	int      (*inject)(struct shm_signal *s);
+	void     (*fault)(struct shm_signal *s, const char *fmt, ...);
+	void     (*release)(struct shm_signal *s);
+};
+
+enum {
+	shm_signal_in_wakeup,
+};
+
+struct shm_signal {
+	atomic_t                    refs;
+	spinlock_t                  lock;
+	enum shm_signal_locality    locale;
+	unsigned long               flags;
+	struct shm_signal_ops      *ops;
+	struct shm_signal_desc     *desc;
+	struct shm_signal_notifier *notifier;
+	struct tasklet_struct       deferred_notify;
+};
+
+#define SHM_SIGNAL_FAULT(s, fmt, args...)  \
+  ((s)->ops->fault ? (s)->ops->fault((s), fmt, ## args) : panic(fmt, ## args))
+
+ /*
+  * These functions should only be used internally
+  */
+void _shm_signal_release(struct shm_signal *s);
+void _shm_signal_wakeup(struct shm_signal *s);
+
+/**
+ * shm_signal_init() - initialize an SHM_SIGNAL
+ * @s:        SHM_SIGNAL context
+ *
+ * Initializes SHM_SIGNAL context before first use
+ *
+ **/
+void shm_signal_init(struct shm_signal *s);
+
+/**
+ * shm_signal_get() - acquire an SHM_SIGNAL context reference
+ * @s:        SHM_SIGNAL context
+ *
+ **/
+static inline struct shm_signal *shm_signal_get(struct shm_signal *s)
+{
+	atomic_inc(&s->refs);
+
+	return s;
+}
+
+/**
+ * shm_signal_put() - release an SHM_SIGNAL context reference
+ * @s:        SHM_SIGNAL context
+ *
+ **/
+static inline void shm_signal_put(struct shm_signal *s)
+{
+	if (atomic_dec_and_test(&s->refs))
+		_shm_signal_release(s);
+}
+
+/**
+ * shm_signal_enable() - enables local notifications on an SHM_SIGNAL
+ * @s:        SHM_SIGNAL context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered notifier (if applicable) to receive wakeups
+ * whenever the remote side performs an shm_signal() operation. A notification
+ * will be dispatched immediately if any pending signals have already been
+ * issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_enable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_disable() - disable local notifications on an SHM_SIGNAL
+ * @s:        SHM_SIGNAL context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Disables/masks the registered shm_signal_notifier (if applicable) from
+ * receiving any further notifications.  Any subsequent calls to shm_signal()
+ * by the remote side will update the shm as dirty, but will not traverse the
+ * locale boundary and will not invoke the notifier callback.  Signals
+ * delivered while masked will be deferred until shm_signal_enable() is
+ * invoked.
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_disable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_inject() - notify the remote side about shm changes
+ * @s:        SHM_SIGNAL context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Marks the shm state as "dirty" and, if enabled, will traverse
+ * a locale boundary to inject a remote notification.  The remote
+ * side controls whether the notification should be delivered via
+ * the shm_signal_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the shm_signal_ops->signal() interface and provided by a particular
+ * implementation.  However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_inject(struct shm_signal *s, int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SHM_SIGNAL_H */
lib/Kconfig +9 -0
index 8ade0a7..1b249a3 100644
@@ -191,4 +191,13 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
 config NLATTR
 	bool
 
+config SHM_SIGNAL
+	boolean "SHM Signal - Generic shared-memory signaling mechanism"
+	default n
+	help
+	 Provides a shared-memory based signaling mechansim to indicate
+         memory-dirty notifications between two end-points.
+
+	 If unsure, say N
+
 endmenu
lib/Makefile +1 -0
index d6edd67..1ef4156 100644
@@ -75,6 +75,7 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
 obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 obj-$(CONFIG_SMP) += percpu_counter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
+obj-$(CONFIG_SHM_SIGNAL) += shm_signal.o
 
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
lib/shm_signal.c new file +186 -0

186 lines not on this page · raw message

#2 lore raw

RFC PATCH v3 2/17 vbus: add virtual-bus definitions

In reply to Gregory Haskins

See Documentation/vbus.txt for details

---

 Documentation/vbus.txt      |  385 +++++++++++++++++++++++++++++
 arch/x86/Kconfig            |    2 
 fs/proc/base.c              |   96 +++++++
 include/linux/sched.h       |    4 
 include/linux/vbus.h        |  147 +++++++++++
 include/linux/vbus_device.h |  417 ++++++++++++++++++++++++++++++++
 kernel/Makefile             |    1 
 kernel/exit.c               |    2 
 kernel/fork.c               |    2 
 kernel/vbus/Kconfig         |   14 +
 kernel/vbus/Makefile        |    1 
 kernel/vbus/attribute.c     |   52 ++++
 kernel/vbus/config.c        |  275 +++++++++++++++++++++
 kernel/vbus/core.c          |  567 +++++++++++++++++++++++++++++++++++++++++++
 kernel/vbus/devclass.c      |  124 +++++++++
 kernel/vbus/map.c           |   72 +++++
 kernel/vbus/map.h           |   41 +++
 kernel/vbus/vbus.h          |  116 +++++++++
 18 files changed, 2318 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/vbus.txt
 create mode 100644 include/linux/vbus.h
 create mode 100644 include/linux/vbus_device.h
 create mode 100644 kernel/vbus/Kconfig
 create mode 100644 kernel/vbus/Makefile
 create mode 100644 kernel/vbus/attribute.c
 create mode 100644 kernel/vbus/config.c
 create mode 100644 kernel/vbus/core.c
 create mode 100644 kernel/vbus/devclass.c
 create mode 100644 kernel/vbus/map.c
 create mode 100644 kernel/vbus/map.h
 create mode 100644 kernel/vbus/vbus.h
Documentation/vbus.txt new file +385 -0
new file mode 100644
index 0000000..7e96758
@@ -0,0 +1,385 @@
+
+Virtual-Bus:
+======================
+Author: Gregory Haskins <[email protected]>
+
+
+
+
+What is it?
+--------------------
+
+Virtual-Bus is a kernel based IO resource container technology.  It is modeled
+on a concept similar to the Linux Device-Model (LDM), where we have buses,
+devices, and drivers as the primary actors.  However, VBUS has several
+distinctions when contrasted with LDM:
+
+  1) "Busses" in LDM are relatively static and global to the kernel (e.g.
+     "PCI", "USB", etc).  VBUS buses are arbitrarily created and destroyed
+     dynamically, and are not globally visible.  Instead they are defined as
+     visible only to a specific subset of the system (the contained context).
+  2) "Devices" in LDM are typically tangible physical (or sometimes logical)
+     devices.  VBUS devices are purely software abstractions (which may or
+     may not have one or more physical devices behind them).  Devices may
+     also be arbitrarily created or destroyed by software/administrative action
+     as opposed to by a hardware discovery mechanism.
+  3) "Drivers" in LDM sit within the same kernel context as the busses and
+     devices they interact with.  VBUS drivers live in a foreign
+     context (such as userspace, or a virtual-machine guest).
+
+The idea is that a vbus is created to contain access to some IO services.
+Virtual devices are then instantiated and linked to a bus to grant access to
+drivers actively present on the bus.  Drivers will only have visibility to
+devices present on their respective bus, and nothing else.
+
+Virtual devices are defined by modules which register a deviceclass with the
+system.  A deviceclass simply represents a type of device that _may_ be
+instantiated into a device, should an administrator wish to do so.  Once
+this has happened, the device may be associated with one or more buses where
+it will become visible to all clients of those respective buses.
+
+Why do we need this?
+----------------------
+
+There are various reasons why such a construct may be useful.  One of the
+most interesting use cases is for virtualization, such as KVM.  Hypervisors
+today provide virtualized IO resources to a guest, but this is often at a cost
+in both latency and throughput compared to bare metal performance.  Utilizing
+para-virtual resources instead of emulated devices helps to mitigate this
+penalty, but even these techniques to date have not fully realized the
+potential of the underlying bare-metal hardware.
+
+Some of the performance differential is unavoidable just given the extra
+processing that occurs due to the deeper stack (guest+host).  However, some of
+this overhead is a direct result of the rather indirect path most hypervisors
+use to route IO.  For instance, KVM uses PIO faults from the guest to trigger
+a guest->host-kernel->host-userspace->host-kernel sequence of events.
+Contrast this to a typical userspace application on the host which must only
+traverse app->kernel for most IO.
+
+The fact is that the linux kernel is already great at managing access to IO
+resources.  Therefore, if you have a hypervisor that is based on the linux
+kernel, is there some way that we can allow the hypervisor to manage IO
+directly instead of forcing this convoluted path?
+
+The short answer is: "not yet" ;)
+
+In order to use such a concept, we need some new facilties.  For one, we
+need to be able to define containers with their corresponding access-control so
+that guests do not have unmitigated access to anything they wish.  Second,
+we also need to define some forms of memory access that is uniform in the face
+of various clients (e.g. "copy_to_user()" cannot be assumed to work for, say,
+a KVM vcpu context).  Lastly, we need to provide access to these resources in
+a way that makes sense for the application, such as asynchronous communication
+paths and minimizing context switches.
+
+So we introduce VBUS as a framework to provide such facilities.  The net
+result is a *substantial* reduction in IO overhead, even when compared to
+state of the art para-virtualization techniques (such as virtio-net).
+
+How do I use it?
+------------------------
+
+There are two components to utilizing a virtual-bus.  One is the
+administrative function (creating and configuring a bus and its devices).  The
+other is the consumption of the resources on the bus by a client (e.g. a
+virtual machine, or a userspace application).  The former occurs on the host
+kernel by means of interacting with various special filesystems (e.g. sysfs,
+configfs, etc).  The latter occurs by means of a "vbus connector" which must
+be developed specifically to bridge a particular environment.  To date, we
+have developed such connectors for host-userspace and kvm-guests.  Conceivably
+we could develop other connectors as needs arise (e.g. lguest, xen,
+guest-userspace, etc).  This document deals with the administrative interface.
+Details about developing a connector are out of scope for this document.
+
+Interacting with vbus
+------------------------
+
+The first step is to enable virtual-bus support (CONFIG_VBUS) as well as any
+desired vbus-device modules (e.g. CONFIG_VBUS_VENETTAP), and ensure that your
+environment mounts both sysfs and configfs somewhere in the filesystem.  This
+document will assume they are mounted to /sys and /config, respectively.
+
+VBUS will create a top-level directory "vbus" in each of the two respective
+filesystems.  At boot-up, they will look like the following:
+
+/sys/vbus/
+|-- deviceclass
+|-- devices
+|-- instances
+`-- version
+
+/config/vbus/
+|-- devices
+`-- instances
+
+Following their respective roles, /config/vbus is for userspace to manage the
+lifetime of some number of objects/attributes.  This is in contrast to
+/sys/vbus which is a reflection of objects managed by the kernel.  It is
+assumed the reader is already familiar with these two facilities, so we will
+not go into depth about their general operation.  Suffice to say that vbus
+consists of objects that are managed both by userspace and the kernel.
+Modification of objects via /config/vbus will typically be reflected in the
+/sys/vbus area.
+
+It all starts with a deviceclass
+--------------------------------
+
+Before you can do anything useful with vbus, you need some registered
+deviceclasses.  A deviceclass provides the implementation of a specific type
+of virtual device.  A deviceclass will typically be registered by loading a
+kernel-module.  Once loaded, the available device types are enumerated under
+/sys/vbus/deviceclass.  For example, we will load our "venet-tap" module,
+which provides network services:
+
+# modprobe venet-tap
+# tree /sys/vbus
+/sys/vbus
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|-- instances
+`-- version
+
+An administrative agent should be able to enumerate /sys/vbus/deviceclass to
+determine what services are available on a given platform.
+
+Create the container
+-------------------
+
+The next step is to create a new container.  In vbus, this comes in the form
+of a vbus-instance and it is created by a simple "mkdir" in the
+/config/vbus/instances area.  The only requirement is that the instance is
+given a host-wide unique name.  This may be some kind of association to the
+application (e.g. the unique VM GUID) or it can be arbitrary.  For the
+purposes of example, we will let $(uuidgen) generate a random UUID for us.
+
+# mkdir /config/vbus/instances/$(uuidgen)
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+So we can see that we have now created a vbus called
+
+               "beb4df8f-7483-4028-b3f7-767512e2a18c"
+
+in the /config area, and it was immediately reflected in the
+/sys/vbus/instances area as well (with a few subobjects of its own: "devices"
+and "members").  The "devices" object denotes any devices that are present on
+the bus (in this case: none).  Likewise, "members" denotes the pids of any
+tasks that are members of the bus (in this case: none).  We will come back to
+this later.  For now, we move on to the next step
+
+Create a device instance
+------------------------
+
+Devices are instantiated by again utilizing the /config/vbus configfs area.
+They are represented as root-level objects under /config/vbus/devices as
+opposed to bus subordinate objects specifically to allow greater flexibility
+in the association of a device.  For instance, it may be desirable to have
+a single device that spans multiple VMs (consider an ethernet switch, or
+a shared disk for a cluster).  Therefore, device lifecycles are managed by
+creating/deleting objects in /config/vbus/devices.
+
+Note: Creating a device instance is actually a two step process:  We need to
+give the device instance a unique name, and we also need to give it a specific
+device type.  It is hard to express both parameters using standard filesystem
+operations like mkdir, so the design decision was made to require performing
+the operation in two steps.
+
+Our first step is to create a unique instance.  We will again utilize
+$(uuidgen) to yield an arbitrary name.  Any name will suffice as long as it is
+unqie on this particular host.
+
+# mkdir /config/vbus/devices/$(uuidgen)
+# tree /sys/vbus
+/sys/vbus
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       `-- interfaces
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+At this point we have created a partial instance, since we have not yet
+assigned a type to the device.  Even so, we can see that some state has
+changed under /sys/vbus/devices.  We now have an instance named
+
+	      	 6a1aff24-5dc0-4aea-9c35-435daef90e55
+
+and it has a single subordinate object: "interfaces".  This object in
+particular is provided by the infrastructure, though do note that a
+deviceclass may also provide its own attributes/objects once it is created.
+
+We will go ahead and give this device a type to complete its construction.  We
+do this by setting the /config/vbus/devices/$devname/type attribute with a
+valid deviceclass type:
+
+# echo foo > /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/type
+bash: echo: write error: No such file or directory
+
+Oops!  What happened?  "foo" is not a valid deviceclass.  We need to consult
+the /sys/vbus/deviceclass area to find out what our options are:
+
+# tree /sys/vbus/deviceclass/
+/sys/vbus/deviceclass/
+`-- venet-tap
+
+Lets try again:
+
+# echo venet-tap > /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/type
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       `-- members
+`-- version
+
+Ok, that looks better.  And note that /sys/vbus/devices now has some more
+subordinate objects.  Most of those were registered when the venet-tap
+deviceclass was given a chance to create an instance of itself.  Those
+attributes are a property of the venet-tap and therefore are out of scope
+for this document.  Please see the documentation that accompanies a particular
+module for more details.
+
+Put the device on the bus
+-------------------------
+
+The next administrative step is to associate our new device with our bus.
+This is accomplished using a symbolic link from the bus instance to our device
+instance.
+
+ln -s /config/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/ /config/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|           `-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       |   `-- 0
+|       |       |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |       `-- type
+|       `-- members
+`-- version
+
+We can now see that the device indicates that it has an interface registered
+to a bus:
+
+/sys/vbus/devices/6a1aff24-5dc0-4aea-9c35-435daef90e55/interfaces/
+`-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+
+Likewise, we can see that the bus has a device listed (id = "0"):
+
+/sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/
+`-- 0
+    |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+    `-- type
+
+At this point, our container is ready for use.  However, it currently has 0
+members, so lets fix that
+
+Add some members
+--------------------
+
+Membership is controlled by an attribute: /proc/$pid/vbus.  A pid can only be
+a member of one (or zero) busses at a time.  To establish membership, we set
+the name of the bus, like so:
+
+# echo beb4df8f-7483-4028-b3f7-767512e2a18c > /proc/self/vbus
+# tree /sys/vbus/
+/sys/vbus/
+|-- deviceclass
+|   `-- venet-tap
+|-- devices
+|   `-- 6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |-- class -> ../../deviceclass/venet-tap
+|       |-- client_mac
+|       |-- enabled
+|       |-- host_mac
+|       |-- ifname
+|       `-- interfaces
+|           `-- 0 -> ../../../instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0
+|-- instances
+|   `-- beb4df8f-7483-4028-b3f7-767512e2a18c
+|       |-- devices
+|       |   `-- 0
+|       |       |-- device -> ../../../../devices/6a1aff24-5dc0-4aea-9c35-435daef90e55
+|       |       `-- type
+|       `-- members
+|           |-- 4382
+|           `-- 4588
+`-- version
+
+Woah!  Why are there two members?  VBUS membership is inherited by forked
+tasks.  Therefore 4382 is the pid of our shell (which we set via /proc/self),
+and 4588 is the pid of the forked/exec'ed "tree" process.  This property can
+be useful for having things like qemu set up the bus and then forking each
+vcpu which will inherit access.
+
+At this point, we are ready to roll.  Pid 4382 has access to a virtual-bus
+namespace with one device, id=0.  Its type is:
+
+# cat /sys/vbus/instances/beb4df8f-7483-4028-b3f7-767512e2a18c/devices/0/type
+virtual-ethernet
+
+"virtual-ethernet"?  Why is it not "venet-tap"?  Device-classes are allowed to
+register their interfaces under an id that is not required to be the same as
+their deviceclass.  This supports device polymorphism.   For instance,
+consider that an interface "virtual-ethernet" may provide basic 802.x packet
+exchange.  However, we could have various implementations of a device that
+supports the 802.x interface, while having various implementations behind
+them.
+
+For instance, "venet-tap" might act like a tuntap module, while
+"venet-loopback" would loop packets back and "venet-switch" would form a
+layer-2 domain among the participating guests.  All three modules would
+presumably support the same basic 802.x interface, yet all three have
+completely different implementations.
+
+Drivers on this particular bus would see this instance id=0 as a type
+"virtual-ethernet" even though the underlying implementation happens to be a
+tap device.  This means a single driver that supports the protocol advertised
+by the "virtual-ethernet" type would be able to support the plethera of
+available device types that we may wish to create.
+
+Teardown:
+---------------
+
+We can descontruct a vbus container doing pretty much the opposite of what we
+did to create it.  Echo "0" into /proc/self/vbus, rm the symlink between the
+bus and device, and rmdir the bus and device objects.  Once that is done, we
+can even rmmod the venet-tap module.  Note that the infrastructure will
+maintain a module-ref while it is configured in a container, so be sure to
+completely tear down the vbus/device before trying this.
arch/x86/Kconfig +2 -0
index bc25b9f..e222395 100644
@@ -1978,6 +1978,8 @@ source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
 
+source "kernel/vbus/Kconfig"
+
 endmenu
 
 
fs/proc/base.c +96 -0

114 lines not on this page · raw message

include/linux/sched.h +4 -0
index b4c38bc..5e3ff74 100644
@@ -98,6 +98,7 @@ struct robust_list_head;
 struct bio;
 struct bts_tracer;
 struct fs_struct;
+struct vbus;
 
 /*
  * List of flags we want to share for kernel threads,
@@ -1339,6 +1340,9 @@ struct task_struct {
 	struct held_lock held_locks[MAX_LOCK_DEPTH];
 	gfp_t lockdep_reclaim_gfp;
 #endif
+#ifdef CONFIG_VBUS
+	struct vbus *vbus;
+#endif
 
 /* journalling filesystem info */
 	void *journal_info;
include/linux/vbus.h new file +147 -0

147 lines not on this page · raw message

include/linux/vbus_device.h new file +417 -0

417 lines not on this page · raw message

kernel/Makefile +1 -0
index 4242366..cc06c63 100644
@@ -95,6 +95,7 @@ obj-$(CONFIG_FUNCTION_TRACER) += trace/
 obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
 obj-$(CONFIG_SLOW_WORK) += slow-work.o
+obj-$(CONFIG_VBUS) += vbus/
 
 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/exit.c +2 -0
index abf9cf3..c86875d 100644
@@ -49,6 +49,7 @@
 #include <linux/fs_struct.h>
 #include <linux/init_task.h>
 #include <trace/sched.h>
+#include <linux/vbus.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -966,6 +967,7 @@ NORET_TYPE void do_exit(long code)
 	check_stack_usage();
 	exit_thread();
 	cgroup_exit(tsk, 1);
+	task_vbus_disassociate(tsk);
 
 	if (group_dead && tsk->signal->leader)
 		disassociate_ctty(1);
kernel/fork.c +2 -0
index b9e2edd..5954d6c 100644
@@ -63,6 +63,7 @@
 #include <linux/fs_struct.h>
 #include <trace/sched.h>
 #include <linux/magic.h>
+#include <linux/vbus.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -1266,6 +1267,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	write_unlock_irq(&tasklist_lock);
 	proc_fork_connector(p);
 	cgroup_post_fork(p);
+	fork_vbus(p);
 	return p;
 
 bad_fork_free_graph:
kernel/vbus/Kconfig new file +14 -0
new file mode 100644
index 0000000..f2b92f5
@@ -0,0 +1,14 @@
+#
+# Virtual-Bus (VBus) configuration
+#
+
+config VBUS
+       bool "Virtual Bus"
+       select CONFIGFS_FS
+       select SHM_SIGNAL
+       default n
+       help
+        Provides a mechansism for declaring virtual-bus objects and binding
+	various tasks and devices which reside on the bus.
+
+	If unsure, say N
kernel/vbus/Makefile new file +1 -0
new file mode 100644
index 0000000..367f65b
@@ -0,0 +1 @@
+obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o
kernel/vbus/attribute.c new file +52 -0

52 lines not on this page · raw message

kernel/vbus/config.c new file +275 -0

275 lines not on this page · raw message

kernel/vbus/core.c new file +567 -0

567 lines not on this page · raw message

kernel/vbus/devclass.c new file +124 -0

124 lines not on this page · raw message

kernel/vbus/map.c new file +72 -0

72 lines not on this page · raw message

kernel/vbus/map.h new file +41 -0

41 lines not on this page · raw message

kernel/vbus/vbus.h new file +116 -0

116 lines not on this page · raw message

#3 lore raw

RFC PATCH v3 3/17 vbus: add connection-client helper infrastructure

In reply to Gregory Haskins

We expect to have various types of connection-clients (e.g. userspace, kvm, etc), each of which is likely to have common access patterns and marshalling duties. Therefore we create a "client" API to simplify client development by helping with mundane tasks such as handle-2-pointer translation, etc.

Special thanks to Pat Mullaney for suggesting the optimization to pass a cookie object down during DEVICESHM operations to save lookup overhead on the event channel.

---

 include/linux/vbus_client.h |  115 +++++++++
 kernel/vbus/Makefile        |    2 
 kernel/vbus/client.c        |  543 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 659 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/vbus_client.h
 create mode 100644 kernel/vbus/client.c
include/linux/vbus_client.h new file +115 -0
new file mode 100644
index 0000000..62dab78
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Virtual-Bus - Client interface
+ *
+ * We expect to have various types of connection-clients (e.g. userspace,
+ * kvm, etc).  Each client will be connecting from some environment outside
+ * of the kernel, and therefore will not have direct access to the API as
+ * presented in ./linux/vbus.h.  There will undoubtedly be some parameter
+ * marshalling that must occur, as well as common patterns for the handling
+ * of those marshalled parameters (e.g. translating a handle into a pointer,
+ * etc).
+ *
+ * Therefore this "client" API is provided to simplify the development
+ * of any clients.  Of course, a client is free to bypass this API entirely
+ * and communicate with the direct VBUS API if desired.
+ *
+ * Author:
+ *      Gregory Haskins <[email protected]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_CLIENT_H
+#define _LINUX_VBUS_CLIENT_H
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+struct vbus_deviceopen {
+	__u32 devid;
+	__u32 version; /* device ABI version */
+	__u64 handle; /* return value for devh */
+};
+
+struct vbus_devicecall {
+	__u64 devh;   /* device-handle (returned from DEVICEOPEN */
+	__u32 func;
+	__u32 len;
+	__u32 flags;
+	__u64 datap;
+};
+
+struct vbus_deviceshm {
+	__u64 devh;   /* device-handle (returned from DEVICEOPEN */
+	__u32 id;
+	__u32 len;
+	__u32 flags;
+	struct {
+		__u32 offset;
+		__u32 prio;
+		__u64 cookie; /* token to pass back when signaling client */
+	} signal;
+	__u64 datap;
+	__u64 handle; /* return value for signaling from client to kernel */
+};
+
+#ifdef __KERNEL__
+
+#include <linux/ioq.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+struct vbus_client;
+
+struct vbus_client_ops {
+	int (*deviceopen)(struct vbus_client *client,  struct vbus_memctx *ctx,
+			  __u32 devid, __u32 version, __u64 *devh);
+	int (*deviceclose)(struct vbus_client *client, __u64 devh);
+	int (*devicecall)(struct vbus_client *client,
+			  __u64 devh, __u32 func,
+			  void *data, __u32 len, __u32 flags);
+	int (*deviceshm)(struct vbus_client *client,
+			 __u64 devh, __u32 id,
+			 struct vbus_shm *shm, struct shm_signal *signal,
+			 __u32 flags, __u64 *handle);
+	int (*shmsignal)(struct vbus_client *client, __u64 handle);
+	void (*release)(struct vbus_client *client);
+};
+
+struct vbus_client {
+	atomic_t refs;
+	struct vbus_client_ops *ops;
+};
+
+static inline void vbus_client_get(struct vbus_client *client)
+{
+	atomic_inc(&client->refs);
+}
+
+static inline void vbus_client_put(struct vbus_client *client)
+{
+	if (atomic_dec_and_test(&client->refs))
+		client->ops->release(client);
+}
+
+struct vbus_client *vbus_client_attach(struct vbus *bus);
+
+extern struct vbus_memctx *current_memctx;
+struct vbus_memctx *task_memctx_alloc(struct task_struct *task);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_VBUS_CLIENT_H */
kernel/vbus/Makefile +1 -1
index 367f65b..4d440e5 100644
@@ -1 +1 @@
-obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o
+obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o client.o
kernel/vbus/client.c new file +543 -0

543 lines not on this page · raw message

#4 lore raw

RFC PATCH v3 4/17 vbus: add bus-registration notifiers

In reply to Gregory Haskins

We need to get hotswap events in environments which cannot use existing facilities (e.g. inotify). So we add a notifier-chain to allow client callbacks whenever an interface is {un}registered.

---

 include/linux/vbus.h |   15 +++++++++++++
 kernel/vbus/core.c   |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/vbus/vbus.h   |    1 +
 3 files changed, 75 insertions(+), 0 deletions(-)
include/linux/vbus.h +15 -0
index 5f0566c..04db4ff 100644
@@ -29,6 +29,7 @@
 #include <linux/sched.h>
 #include <linux/rcupdate.h>
 #include <linux/vbus_device.h>
+#include <linux/notifier.h>
 
 struct vbus;
 struct task_struct;
@@ -137,6 +138,20 @@ static inline void task_vbus_disassociate(struct task_struct *p)
 	}
 }
 
+enum {
+	VBUS_EVENT_DEVADD,
+	VBUS_EVENT_DEVDROP,
+};
+
+struct vbus_event_devadd {
+	const char   *type;
+	unsigned long id;
+};
+
+int vbus_notifier_register(struct vbus *vbus, struct notifier_block *nb);
+int vbus_notifier_unregister(struct vbus *vbus, struct notifier_block *nb);
+
+
 #else /* CONFIG_VBUS */
 
 #define fork_vbus(p) do { } while (0)
kernel/vbus/core.c +59 -0

89 lines not on this page · raw message

kernel/vbus/vbus.h +1 -0
index 1266d69..cd2676b 100644
@@ -51,6 +51,7 @@ struct vbus {
 	struct vbus_subdir members;
 	unsigned long next_id;
 	struct rb_node node;
+	struct raw_notifier_head notifier;
 };
 
 struct vbus_member {
#5 lore raw

RFC PATCH v3 5/17 vbus: add a "vbus-proxy" bus model for vbus_driver objects

In reply to Gregory Haskins

This will generally be used for hypervisors to publish any host-side virtual devices up to a guest. The guest will have the opportunity to consume any devices present on the vbus-proxy as if they were platform devices, similar to existing buses like PCI.

---

 include/linux/vbus_driver.h |   73 +++++++++++++++++++++
 kernel/vbus/Kconfig         |    9 +++
 kernel/vbus/Makefile        |    4 +
 kernel/vbus/proxy.c         |  152 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 238 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/vbus_driver.h
 create mode 100644 kernel/vbus/proxy.c
include/linux/vbus_driver.h new file +73 -0
new file mode 100644
index 0000000..c53e13f
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * Mediates access to a host VBUS from a guest kernel by providing a
+ * global view of all VBUS devices
+ *
+ * Author:
+ *      Gregory Haskins <[email protected]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_DRIVER_H
+#define _LINUX_VBUS_DRIVER_H
+
+#include <linux/device.h>
+#include <linux/shm_signal.h>
+
+struct vbus_device_proxy;
+struct vbus_driver;
+
+struct vbus_device_proxy_ops {
+	int (*open)(struct vbus_device_proxy *dev, int version, int flags);
+	int (*close)(struct vbus_device_proxy *dev, int flags);
+	int (*shm)(struct vbus_device_proxy *dev, int id, int prio,
+		   void *ptr, size_t len,
+		   struct shm_signal_desc *sigdesc, struct shm_signal **signal,
+		   int flags);
+	int (*call)(struct vbus_device_proxy *dev, u32 func,
+		    void *data, size_t len, int flags);
+	void (*release)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_device_proxy {
+	char                          *type;
+	u64                            id;
+	void                          *priv; /* Used by drivers */
+	struct vbus_device_proxy_ops  *ops;
+	struct device                  dev;
+};
+
+int vbus_device_proxy_register(struct vbus_device_proxy *dev);
+void vbus_device_proxy_unregister(struct vbus_device_proxy *dev);
+
+struct vbus_device_proxy *vbus_device_proxy_find(u64 id);
+
+struct vbus_driver_ops {
+	int (*probe)(struct vbus_device_proxy *dev);
+	int (*remove)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_driver {
+	char                          *type;
+	struct module                 *owner;
+	struct vbus_driver_ops        *ops;
+	struct device_driver           drv;
+};
+
+int vbus_driver_register(struct vbus_driver *drv);
+void vbus_driver_unregister(struct vbus_driver *drv);
+
+#endif /* _LINUX_VBUS_DRIVER_H */
kernel/vbus/Kconfig +9 -0
index f2b92f5..3aaa085 100644
@@ -12,3 +12,12 @@ config VBUS
 	various tasks and devices which reside on the bus.
 
 	If unsure, say N
+
+config VBUS_DRIVERS
+       tristate "VBUS Driver support"
+       default n
+       help
+        Adds support for a virtual bus model for proxying drivers.
+
+	If unsure, say N
+
kernel/vbus/Makefile +4 -0
index 4d440e5..d028ece 100644
@@ -1 +1,5 @@
 obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o client.o
+
+vbus-proxy-objs += proxy.o
+obj-$(CONFIG_VBUS_DRIVERS) += vbus-proxy.o
+
kernel/vbus/proxy.c new file +152 -0

152 lines not on this page · raw message

#6 lore raw

RFC PATCH v3 6/17 ioq: Add basic definitions for a shared-memory, lockless queue

In reply to Gregory Haskins

We can map these over VBUS shared memory (or really any shared-memory architecture if it supports shm-signals) to allow asynchronous communication between two end-points. Memory is synchronized using pure barriers (i.e. lockless), so IOQs are friendly in many contexts, even if the memory is remote.

---

 include/linux/ioq.h |  410 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig         |   12 +
 lib/Makefile        |    1 
 lib/ioq.c           |  298 +++++++++++++++++++++++++++++++++++++
 4 files changed, 721 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/ioq.h
 create mode 100644 lib/ioq.c
include/linux/ioq.h new file +410 -0
new file mode 100644
index 0000000..d450d9a
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2009 Novell.  All Rights Reserved.
+ *
+ * IOQ is a generic shared-memory, lockless queue mechanism. It can be used
+ * in a variety of ways, though its intended purpose is to become the
+ * asynchronous communication path for virtual-bus drivers.
+ *
+ * The following are a list of key design points:
+ *
+ * #) All shared-memory is always allocated on explicitly one side of the
+ *    link.  This typically would be the guest side in a VM/VMM scenario.
+ * #) Each IOQ has the concept of "north" and "south" locales, where
+ *    north denotes the memory-owner side (e.g. guest).
+ * #) An IOQ is manipulated using an iterator idiom.
+ * #) Provides a bi-directional signaling/notification infrastructure on
+ *    a per-queue basis, which includes an event mitigation strategy
+ *    to reduce boundary switching.
+ * #) The signaling path is abstracted so that various technologies and
+ *    topologies can define their own specific implementation while sharing
+ *    the basic structures and code.
+ *
+ * Author:
+ *      Gregory Haskins <[email protected]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_IOQ_H
+#define _LINUX_IOQ_H
+
+#include <asm/types.h>
+#include <linux/shm_signal.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc).  Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+struct ioq_ring_desc {
+	__u64                 cookie; /* for arbitrary use by north-side */
+	__u64                 ptr;
+	__u64                 len;
+	__u8                  valid;
+	__u8                  sown; /* South owned = 1, North owned = 0 */
+};
+
+#define IOQ_RING_MAGIC 0x47fa2fe4
+#define IOQ_RING_VER   4
+
+struct ioq_ring_idx {
+	__u32                 head;    /* 0 based index to head of ptr array */
+	__u32                 tail;    /* 0 based index to tail of ptr array */
+	__u8                  full;
+};
+
+enum ioq_locality {
+	ioq_locality_north,
+	ioq_locality_south,
+};
+
+struct ioq_ring_head {
+	__u32                  magic;
+	__u32                  ver;
+	struct shm_signal_desc signal;
+	struct ioq_ring_idx    idx[2];
+	__u32                  count;
+	struct ioq_ring_desc   ring[1]; /* "count" elements will be allocated */
+};
+
+#define IOQ_HEAD_DESC_SIZE(count) \
+    (sizeof(struct ioq_ring_head) + sizeof(struct ioq_ring_desc) * (count - 1))
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/shm_signal.h>
+#include <asm/atomic.h>
+
+enum ioq_idx_type {
+	ioq_idxtype_valid,
+	ioq_idxtype_inuse,
+	ioq_idxtype_both,
+	ioq_idxtype_invalid,
+};
+
+enum ioq_seek_type {
+	ioq_seek_tail,
+	ioq_seek_next,
+	ioq_seek_head,
+	ioq_seek_set
+};
+
+struct ioq_iterator {
+	struct ioq            *ioq;
+	struct ioq_ring_idx   *idx;
+	u32                    pos;
+	struct ioq_ring_desc  *desc;
+	int                    update:1;
+	int                    dualidx:1;
+	int                    flipowner:1;
+};
+
+struct ioq_notifier {
+	void (*signal)(struct ioq_notifier *);
+};
+
+struct ioq_ops {
+	void     (*release)(struct ioq *ioq);
+};
+
+struct ioq {
+	struct ioq_ops *ops;
+
+	atomic_t               refs;
+	enum ioq_locality      locale;
+	struct ioq_ring_head  *head_desc;
+	struct ioq_ring_desc  *ring;
+	struct shm_signal     *signal;
+	wait_queue_head_t      wq;
+	struct ioq_notifier   *notifier;
+	size_t                 count;
+	struct shm_signal_notifier shm_notifier;
+};
+
+#define IOQ_ITER_AUTOUPDATE  (1 << 0)
+#define IOQ_ITER_NOFLIPOWNER (1 << 1)
+
+/**
+ * ioq_init() - initialize an IOQ
+ * @ioq:        IOQ context
+ *
+ * Initializes IOQ context before first use
+ *
+ **/
+void ioq_init(struct ioq *ioq,
+	      struct ioq_ops *ops,
+	      enum ioq_locality locale,
+	      struct ioq_ring_head *head,
+	      struct shm_signal *signal,
+	      size_t count);
+
+/**
+ * ioq_get() - acquire an IOQ context reference
+ * @ioq:        IOQ context
+ *
+ **/
+static inline struct ioq *ioq_get(struct ioq *ioq)
+{
+	atomic_inc(&ioq->refs);
+
+	return ioq;
+}
+
+/**
+ * ioq_put() - release an IOQ context reference
+ * @ioq:        IOQ context
+ *
+ **/
+static inline void ioq_put(struct ioq *ioq)
+{
+	if (atomic_dec_and_test(&ioq->refs)) {
+		shm_signal_put(ioq->signal);
+		ioq->ops->release(ioq);
+	}
+}
+
+/**
+ * ioq_notify_enable() - enables local notifications on an IOQ
+ * @ioq:        IOQ context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered ioq_notifier (if applicable) and waitq to
+ * receive wakeups whenever the remote side performs an ioq_signal() operation.
+ * A notification will be dispatched immediately if any pending signals have
+ * already been issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_enable(struct ioq *ioq, int flags)
+{
+	return shm_signal_enable(ioq->signal, 0);
+}
+
+/**
+ * ioq_notify_disable() - disable local notifications on an IOQ
+ * @ioq:        IOQ context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Disables/masks the registered ioq_notifier (if applicable) and waitq
+ * from receiving any further notifications.  Any subsequent calls to
+ * ioq_signal() by the remote side will update the ring as dirty, but
+ * will not traverse the locale boundary and will not invoke the notifier
+ * callback or wakeup the waitq.  Signals delivered while masked will
+ * be deferred until ioq_notify_enable() is invoked
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_disable(struct ioq *ioq, int flags)
+{
+	return shm_signal_disable(ioq->signal, 0);
+}
+
+/**
+ * ioq_signal() - notify the remote side about ring changes
+ * @ioq:        IOQ context
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Marks the ring state as "dirty" and, if enabled, will traverse
+ * a locale boundary to invoke a remote notification.  The remote
+ * side controls whether the notification should be delivered via
+ * the ioq_notify_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the ioq_ops->signal() interface and provided by a particular
+ * implementation.  However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_signal(struct ioq *ioq, int flags)
+{
+	return shm_signal_inject(ioq->signal, 0);
+}
+
+/**
+ * ioq_count() - counts the number of outstanding descriptors in an index
+ * @ioq:        IOQ context
+ * @type:	Specifies the index type
+ *                 (*) valid: the descriptor is valid.  This is usually
+ *                     used to keep track of descriptors that may not
+ *                     be carrying a useful payload, but still need to
+ *                     be tracked carefully.
+ *                 (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ *  (*) >=0: # of descriptors outstanding in the index
+ *  (*) <0 = ERRNO
+ *
+ **/
+int ioq_count(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_remain() - counts the number of remaining descriptors in an index
+ * @ioq:        IOQ context
+ * @type:	Specifies the index type
+ *                 (*) valid: the descriptor is valid.  This is usually
+ *                     used to keep track of descriptors that may not
+ *                     be carrying a useful payload, but still need to
+ *                     be tracked carefully.
+ *                 (*) inuse: Descriptors that carry useful payload
+ *
+ * This is the converse of ioq_count().  This function returns the number
+ * of "free" descriptors left in a particular index
+ *
+ * Returns:
+ *  (*) >=0: # of descriptors remaining in the index
+ *  (*) <0 = ERRNO
+ *
+ **/
+int ioq_remain(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_size() - counts the maximum number of descriptors in an ring
+ * @ioq:        IOQ context
+ *
+ * This function returns the maximum number of descriptors supported in
+ * a ring, regardless of their current state (free or inuse).
+ *
+ * Returns:
+ *  (*) >=0: total # of descriptors in the ring
+ *  (*) <0 = ERRNO
+ *
+ **/
+int ioq_size(struct ioq *ioq);
+
+/**
+ * ioq_full() - determines if a specific index is "full"
+ * @ioq:        IOQ context
+ * @type:	Specifies the index type
+ *                 (*) valid: the descriptor is valid.  This is usually
+ *                     used to keep track of descriptors that may not
+ *                     be carrying a useful payload, but still need to
+ *                     be tracked carefully.
+ *                 (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ *  (*) 0: index is not full
+ *  (*) 1: index is full
+ *  (*) <0 = ERRNO
+ *
+ **/
+int ioq_full(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_empty() - determines if a specific index is "empty"
+ * @ioq:        IOQ context
+ * @type:	Specifies the index type
+ *                 (*) valid: the descriptor is valid.  This is usually
+ *                     used to keep track of descriptors that may not
+ *                     be carrying a useful payload, but still need to
+ *                     be tracked carefully.
+ *                 (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ *  (*) 0: index is not empty
+ *  (*) 1: index is empty
+ *  (*) <0 = ERRNO
+ *
+ **/
+static inline int ioq_empty(struct ioq *ioq, enum ioq_idx_type type)
+{
+    return !ioq_count(ioq, type);
+}
+
+/**
+ * ioq_iter_init() - initialize an iterator for IOQ descriptor traversal
+ * @ioq:        IOQ context to iterate on
+ * @iter:	Iterator context to init (usually from stack)
+ * @type:	Specifies the index type to iterate against
+ *                 (*) valid: iterate against the "valid" index
+ *                 (*) inuse: iterate against the "inuse" index
+ *                 (*) both: iterate against both indexes simultaneously
+ * @flags:      Bitfield with 0 or more bits set to alter behavior
+ *                 (*) autoupdate: automatically signal the remote side
+ *                     whenever the iterator pushes/pops to a new desc
+ *                 (*) noflipowner: do not flip the ownership bit during
+ *                     a push/pop operation
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
+		  enum ioq_idx_type type, int flags);
+
+/**
+ * ioq_iter_seek() - seek to a specific location in the IOQ ring
+ * @iter:	Iterator context (must be initialized with ioq_iter_init)
+ * @type:	Specifies the type of seek operation
+ *                 (*) tail: seek to the absolute tail, offset is ignored
+ *                 (*) next: seek to the relative next, offset is ignored
+ *                 (*) head: seek to the absolute head, offset is ignored
+ *                 (*) set: seek to the absolute offset
+ * @offset:     Offset for ioq_seek_set operations
+ * @flags:      Reserved for future use, must be 0
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int  ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
+		   long offset, int flags);
+
+/**
+ * ioq_iter_push() - push the tail pointer forward
+ * @iter:	Iterator context (must be initialized with ioq_iter_init)
+ * @flags:      Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the tail ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation.  This effectively "pushes" a new pointer
+ * onto the tail of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int  ioq_iter_push(struct ioq_iterator *iter, int flags);
+
+/**
+ * ioq_iter_pop() - pop the head pointer from the ring
+ * @iter:	Iterator context (must be initialized with ioq_iter_init)
+ * @flags:      Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the head ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation.  This effectively "pops" a pointer
+ * from the head of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int  ioq_iter_pop(struct ioq_iterator *iter,  int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_IOQ_H */
lib/Kconfig +12 -0
index 1b249a3..8fb4939 100644
@@ -200,4 +200,16 @@ config SHM_SIGNAL
 
 	 If unsure, say N
 
+config IOQ
+	boolean "IO-Queue library - Generic shared-memory queue"
+	select SHM_SIGNAL
+	default n
+	help
+	 IOQ is a generic shared-memory-queue mechanism that happens to be
+	 friendly to virtualization boundaries. It can be used in a variety
+	 of ways, though its intended purpose is to become the low-level
+	 communication path for paravirtualized drivers.
+
+	 If unsure, say N
+
 endmenu
lib/Makefile +1 -0
index 1ef4156..68f2dc9 100644
@@ -76,6 +76,7 @@ obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
 obj-$(CONFIG_SMP) += percpu_counter.o
 obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 obj-$(CONFIG_SHM_SIGNAL) += shm_signal.o
+obj-$(CONFIG_IOQ) += ioq.o
 
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
lib/ioq.c new file +298 -0

298 lines not on this page · raw message

#7 lore raw

RFC PATCH v3 7/17 ioq: add vbus helpers

In reply to Gregory Haskins

It will be common to map an IOQ over the VBUS shared-memory interfaces, so lets generalize their setup so we can reuse the pattern.

---

 include/linux/vbus_device.h |    7 +++
 include/linux/vbus_driver.h |    7 +++
 kernel/vbus/Kconfig         |    2 +
 kernel/vbus/Makefile        |    1 
 kernel/vbus/proxy.c         |   64 +++++++++++++++++++++++++++++++
 kernel/vbus/shm-ioq.c       |   89 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 170 insertions(+), 0 deletions(-)
 create mode 100644 kernel/vbus/shm-ioq.c
include/linux/vbus_device.h +7 -0
index f73cd86..c91bce4 100644
@@ -102,6 +102,7 @@
 #include <linux/configfs.h>
 #include <linux/rbtree.h>
 #include <linux/shm_signal.h>
+#include <linux/ioq.h>
 #include <linux/vbus.h>
 #include <asm/atomic.h>
 
@@ -414,4 +415,10 @@ static inline void vbus_connection_put(struct vbus_connection *conn)
 		conn->ops->release(conn);
 }
 
+/*
+ * device-side IOQ helper - dereferences device-shm as an IOQ
+ */
+int vbus_shm_ioq_attach(struct vbus_shm *shm, struct shm_signal *signal,
+			int maxcount, struct ioq **ioq);
+
 #endif /* _LINUX_VBUS_DEVICE_H */
include/linux/vbus_driver.h +7 -0
index c53e13f..9cfbf60 100644
@@ -26,6 +26,7 @@
 
 #include <linux/device.h>
 #include <linux/shm_signal.h>
+#include <linux/ioq.h>
 
 struct vbus_device_proxy;
 struct vbus_driver;
@@ -70,4 +71,10 @@ struct vbus_driver {
 int vbus_driver_register(struct vbus_driver *drv);
 void vbus_driver_unregister(struct vbus_driver *drv);
 
+/*
+ * driver-side IOQ helper - allocates device-shm and maps an IOQ on it
+ */
+int vbus_driver_ioq_alloc(struct vbus_device_proxy *dev, int id, int prio,
+			  size_t ringsize, struct ioq **ioq);
+
 #endif /* _LINUX_VBUS_DRIVER_H */
kernel/vbus/Kconfig +2 -0
index 3aaa085..71acd6f 100644
@@ -6,6 +6,7 @@ config VBUS
        bool "Virtual Bus"
        select CONFIGFS_FS
        select SHM_SIGNAL
+       select IOQ
        default n
        help
         Provides a mechansism for declaring virtual-bus objects and binding
@@ -15,6 +16,7 @@ config VBUS
 
 config VBUS_DRIVERS
        tristate "VBUS Driver support"
+       select IOQ
        default n
        help
         Adds support for a virtual bus model for proxying drivers.
kernel/vbus/Makefile +1 -0
index d028ece..45f6503 100644
@@ -1,4 +1,5 @@
 obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o client.o
+obj-$(CONFIG_VBUS) += shm-ioq.o
 
 vbus-proxy-objs += proxy.o
 obj-$(CONFIG_VBUS_DRIVERS) += vbus-proxy.o
kernel/vbus/proxy.c +64 -0

67 lines not on this page · raw message

kernel/vbus/shm-ioq.c new file +89 -0

89 lines not on this page · raw message

#8 lore raw

RFC PATCH v3 8/17 venet: add the ABI definitions for an 802.x packet interface

In reply to Gregory Haskins

---

 include/linux/venet.h |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 47 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/venet.h
include/linux/venet.h new file +47 -0
new file mode 100644
index 0000000..ef6b199
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 Novell.  All Rights Reserved.
+ *
+ * Virtual-Ethernet adapter
+ *
+ * Author:
+ *      Gregory Haskins <[email protected]>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VENET_H
+#define _LINUX_VENET_H
+
+#define VENET_VERSION 1
+
+#define VENET_TYPE "virtual-ethernet"
+
+#define VENET_QUEUE_RX 0
+#define VENET_QUEUE_TX 1
+
+struct venet_capabilities {
+	__u32 gid;
+	__u32 bits;
+};
+
+/* CAPABILITIES-GROUP 0 */
+/* #define VENET_CAP_FOO    0   (No capabilities defined yet, for now) */
+
+#define VENET_FUNC_LINKUP   0
+#define VENET_FUNC_LINKDOWN 1
+#define VENET_FUNC_MACQUERY 2
+#define VENET_FUNC_NEGCAP   3 /* negotiate capabilities */
+#define VENET_FUNC_FLUSHRX  4
+
+#endif /* _LINUX_VENET_H */
#9 lore raw

RFC PATCH v3 9/17 net: Add vbus_enet driver

In reply to Gregory Haskins

---

 drivers/net/Kconfig     |   13 +
 drivers/net/Makefile    |    1 
 drivers/net/vbus-enet.c |  672 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 686 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/vbus-enet.c
drivers/net/Kconfig +13 -0
index 9e92154..f46239b 100644
@@ -3155,4 +3155,17 @@ config VIRTIO_NET
 	  This is the virtual network driver for virtio.  It can be used with
           lguest or QEMU based VMMs (like KVM or Xen).  Say Y or M.
 
+config VBUS_ENET
+	tristate "Virtual Ethernet Driver"
+	depends on VBUS_DRIVERS
+	help
+	   A virtualized 802.x network device based on the VBUS interface.
+	   It can be used with any hypervisor/kernel that supports the
+	   vbus protocol.
+
+config VBUS_ENET_DEBUG
+        bool "Enable Debugging"
+	depends on VBUS_ENET
+	default n
+
 endif # NETDEVICES
drivers/net/Makefile +1 -0
index 1fc4602..ee76236 100644
@@ -268,6 +268,7 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
 obj-$(CONFIG_NETXEN_NIC) += netxen/
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_VBUS_ENET) += vbus-enet.o
 obj-$(CONFIG_SFC) += sfc/
 
 obj-$(CONFIG_WIMAX) += wimax/
drivers/net/vbus-enet.c new file +672 -0

672 lines not on this page · raw message

#10 lore raw

RFC PATCH v3 10/17 venet-tap: Adds a "venet" compatible "tap" device to VBUS

In reply to Gregory Haskins

This module is similar in concept to a "tuntap". A tuntap module provides a netif() interface on one side, and a char-dev interface on the other. Packets that ingress on one interface, egress on the other (and vice versa).

This module offers a similar concept, except that it substitues the char-dev for a VBUS/IOQ interface. This allows a VBUS compatible entity (e.g. userspace or a guest) to directly inject and receive packets from the host/kernel stack.

Thanks to Pat Mullaney for contributing the maxcount modification

---

 drivers/Makefile                 |    1 
 drivers/vbus/devices/Kconfig     |   17 
 drivers/vbus/devices/Makefile    |    1 
 drivers/vbus/devices/venet-tap.c | 1387 ++++++++++++++++++++++++++++++++++++++
 kernel/vbus/Kconfig              |   13 
 5 files changed, 1419 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vbus/devices/Kconfig
 create mode 100644 drivers/vbus/devices/Makefile
 create mode 100644 drivers/vbus/devices/venet-tap.c
drivers/Makefile +1 -0
index 2618a61..4c66912 100644
@@ -107,3 +107,4 @@ obj-$(CONFIG_SSB)		+= ssb/
 obj-$(CONFIG_VIRTIO)		+= virtio/
 obj-$(CONFIG_STAGING)		+= staging/
 obj-y				+= platform/
+obj-$(CONFIG_VBUS_DEVICES)	+= vbus/devices/
drivers/vbus/devices/Kconfig new file +17 -0
new file mode 100644
index 0000000..64e4731
@@ -0,0 +1,17 @@
+#
+# Virtual-Bus (VBus) configuration
+#
+
+config VBUS_VENETTAP
+       tristate "Virtual-Bus Ethernet Tap Device"
+       depends on VBUS_DEVICES
+       default n
+       help
+        Provides a virtual ethernet adapter to a vbus, which in turn
+        manifests itself as a standard netif based adapter to the
+	kernel.  It can be used similarly to a "tuntap" device,
+        except that the char-dev transport is replaced with a vbus/ioq
+        interface.
+
+	If unsure, say N
+
drivers/vbus/devices/Makefile new file +1 -0
new file mode 100644
index 0000000..2ea7d2a
@@ -0,0 +1 @@
+obj-$(CONFIG_VBUS_VENETTAP) += venet-tap.o
drivers/vbus/devices/venet-tap.c new file +1387 -0

1,387 lines not on this page · raw message

kernel/vbus/Kconfig +13 -0
index 71acd6f..3ce0adc 100644
@@ -14,6 +14,17 @@ config VBUS
 
 	If unsure, say N
 
+config VBUS_DEVICES
+       bool "Virtual-Bus Devices"
+       depends on VBUS
+       default n
+       help
+         Provides device-class modules for instantiation on a virtual-bus
+
+	 If unsure, say N
+
+source "drivers/vbus/devices/Kconfig"
+
 config VBUS_DRIVERS
        tristate "VBUS Driver support"
        select IOQ
@@ -23,3 +34,5 @@ config VBUS_DRIVERS
 
 	If unsure, say N
 
+
+
#11 lore raw

RFC PATCH v3 11/17 venet-tap: add the ability to set the client's mac address via sysfs

In reply to Gregory Haskins

From: Patrick Mullaney <[email protected]>

---

 drivers/vbus/devices/venet-tap.c |   35 ++++++++++++++++++++++++++++++++++-
 1 files changed, 34 insertions(+), 1 deletions(-)
drivers/vbus/devices/venet-tap.c +34 -1
index 5e093a0..33ede4c 100644
@@ -1214,6 +1214,39 @@ host_mac_show(struct vbus_device *dev, struct vbus_device_attribute *attr,
 static struct vbus_device_attribute attr_hmac =
 	__ATTR_RO(host_mac);
 
+
+static ssize_t
+cmac_store(struct vbus_device *dev, struct vbus_device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct venettap *priv = vdev_to_priv(dev);
+	const char *pbuf = buf;
+	unsigned int uc;
+	int i;
+
+	/*
+	 * Format 00:11:22:33:44:55
+	 */
+	if (count != 18)
+		return -EINVAL;
+
+	for (i = 2; i < 17; i += 3) {
+		if (pbuf[i] != ':')
+			return -EINVAL;
+	}
+
+	if (priv->vbus.opened)
+		return -EINVAL;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		sscanf(pbuf, "%x", &uc);
+		pbuf = pbuf + 3;
+		priv->cmac[i] = (u8)uc;
+	}
+
+	return count;
+}
+
 static ssize_t
 client_mac_show(struct vbus_device *dev, struct vbus_device_attribute *attr,
 	 char *buf)
@@ -1224,7 +1257,7 @@ client_mac_show(struct vbus_device *dev, struct vbus_device_attribute *attr,
 }
 
 static struct vbus_device_attribute attr_cmac =
-	__ATTR_RO(client_mac);
+	__ATTR(client_mac, S_IRUGO | S_IWUSR, client_mac_show, cmac_store);
 
 static ssize_t
 enabled_show(struct vbus_device *dev, struct vbus_device_attribute *attr,
#12 lore raw

RFC PATCH v3 12/17 venet: add scatter-gather support

In reply to Gregory Haskins

---

 drivers/net/vbus-enet.c |  248 +++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/venet.h   |   39 +++++++
 2 files changed, 274 insertions(+), 13 deletions(-)
drivers/net/vbus-enet.c +237 -11
index 8fcc2d6..7220f43 100644
@@ -42,6 +42,8 @@ static int rx_ringlen = 256;
 module_param(rx_ringlen, int, 0444);
 static int tx_ringlen = 256;
 module_param(tx_ringlen, int, 0444);
+static int sg_enabled = 1;
+module_param(sg_enabled, int, 0444);
 
 #define PDEBUG(_dev, fmt, args...) dev_dbg(&(_dev)->dev, fmt, ## args)
 
@@ -58,8 +60,17 @@ struct vbus_enet_priv {
 	struct vbus_enet_queue     rxq;
 	struct vbus_enet_queue     txq;
 	struct tasklet_struct      txtask;
+	struct {
+		int                sg:1;
+		int                tso:1;
+		int                ufo:1;
+		int                tso6:1;
+		int                ecn:1;
+	} flags;
 };
 
+static void vbus_enet_tx_reap(struct vbus_enet_priv *priv, int force);
+
 static struct vbus_enet_priv *
 napi_to_priv(struct napi_struct *napi)
 {
@@ -193,6 +204,93 @@ rx_teardown(struct vbus_enet_priv *priv)
 	}
 }
 
+static int
+tx_setup(struct vbus_enet_priv *priv)
+{
+	struct ioq *ioq = priv->txq.queue;
+	struct ioq_iterator iter;
+	int i;
+	int ret;
+
+	if (!priv->flags.sg)
+		/*
+		 * There is nothing to do for a ring that is not using
+		 * scatter-gather
+		 */
+		return 0;
+
+	ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+	BUG_ON(ret < 0);
+
+	ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+	BUG_ON(ret < 0);
+
+	/*
+	 * Now populate each descriptor with an empty SG descriptor
+	 */
+	for (i = 0; i < tx_ringlen; i++) {
+		struct venet_sg *vsg;
+		size_t iovlen = sizeof(struct venet_iov) * (MAX_SKB_FRAGS-1);
+		size_t len = sizeof(*vsg) + iovlen;
+
+		vsg = kzalloc(len, GFP_KERNEL);
+		if (!vsg)
+			return -ENOMEM;
+
+		iter.desc->cookie = (u64)vsg;
+		iter.desc->len    = len;
+		iter.desc->ptr    = (u64)__pa(vsg);
+
+		ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+		BUG_ON(ret < 0);
+	}
+
+	return 0;
+}
+
+static void
+tx_teardown(struct vbus_enet_priv *priv)
+{
+	struct ioq *ioq = priv->txq.queue;
+	struct ioq_iterator iter;
+	int ret;
+
+	/* forcefully free all outstanding transmissions */
+	vbus_enet_tx_reap(priv, 1);
+
+	if (!priv->flags.sg)
+		/*
+		 * There is nothing else to do for a ring that is not using
+		 * scatter-gather
+		 */
+		return;
+
+	ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+	BUG_ON(ret < 0);
+
+	/* seek to position 0 */
+	ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+	BUG_ON(ret < 0);
+
+	/*
+	 * free each valid descriptor
+	 */
+	while (iter.desc->cookie) {
+		struct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;
+
+		iter.desc->valid = 0;
+		wmb();
+
+		iter.desc->ptr = 0;
+		iter.desc->cookie = 0;
+
+		ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+		BUG_ON(ret < 0);
+
+		kfree(vsg);
+	}
+}
+
 /*
  * Open and close
  */
@@ -396,14 +494,67 @@ vbus_enet_tx_start(struct sk_buff *skb, struct net_device *dev)
 	BUG_ON(ret < 0);
 	BUG_ON(iter.desc->sown);
 
-	/*
-	 * We simply put the skb right onto the ring.  We will get an interrupt
-	 * later when the data has been consumed and we can reap the pointers
-	 * at that time
-	 */
-	iter.desc->cookie = (u64)skb;
-	iter.desc->len = (u64)skb->len;
-	iter.desc->ptr = (u64)__pa(skb->data);
+	if (priv->flags.sg) {
+		struct venet_sg *vsg = (struct venet_sg *)iter.desc->cookie;
+		struct scatterlist sgl[MAX_SKB_FRAGS+1];
+		struct scatterlist *sg;
+		int count, maxcount = ARRAY_SIZE(sgl);
+
+		sg_init_table(sgl, maxcount);
+
+		memset(vsg, 0, sizeof(*vsg));
+
+		vsg->cookie = (u64)skb;
+		vsg->len    = skb->len;
+
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			vsg->flags      |= VENET_SG_FLAG_NEEDS_CSUM;
+			vsg->csum.start  = skb->csum_start - skb_headroom(skb);
+			vsg->csum.offset = skb->csum_offset;
+		}
+
+		if (skb_is_gso(skb)) {
+			struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+			vsg->flags |= VENET_SG_FLAG_GSO;
+
+			vsg->gso.hdrlen = skb_transport_header(skb) - skb->data;
+			vsg->gso.size = sinfo->gso_size;
+			if (sinfo->gso_type & SKB_GSO_TCPV4)
+				vsg->gso.type = VENET_GSO_TYPE_TCPV4;
+			else if (sinfo->gso_type & SKB_GSO_TCPV6)
+				vsg->gso.type = VENET_GSO_TYPE_TCPV6;
+			else if (sinfo->gso_type & SKB_GSO_UDP)
+				vsg->gso.type = VENET_GSO_TYPE_UDP;
+			else
+				panic("Virtual-Ethernet: unknown GSO type " \
+				      "0x%x\n", sinfo->gso_type);
+
+			if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+				vsg->flags |= VENET_SG_FLAG_ECN;
+		}
+
+		count = skb_to_sgvec(skb, sgl, 0, skb->len);
+
+		BUG_ON(count > maxcount);
+
+		for (sg = &sgl[0]; sg; sg = sg_next(sg)) {
+			struct venet_iov *iov = &vsg->iov[vsg->count++];
+
+			iov->len = sg->length;
+			iov->ptr = (u64)sg_phys(sg);
+		}
+
+	} else {
+		/*
+		 * non scatter-gather mode: simply put the skb right onto the
+		 * ring.
+		 */
+		iter.desc->cookie = (u64)skb;
+		iter.desc->len = (u64)skb->len;
+		iter.desc->ptr = (u64)__pa(skb->data);
+	}
+
 	iter.desc->valid  = 1;
 
 	priv->dev->stats.tx_packets++;
@@ -459,7 +610,17 @@ vbus_enet_tx_reap(struct vbus_enet_priv *priv, int force)
 	 * owned by the south-side
 	 */
 	while (iter.desc->valid && (!iter.desc->sown || force)) {
-		struct sk_buff *skb = (struct sk_buff *)iter.desc->cookie;
+		struct sk_buff *skb;
+
+		if (priv->flags.sg) {
+			struct venet_sg *vsg;
+
+			vsg = (struct venet_sg *)iter.desc->cookie;
+			skb = (struct sk_buff *)vsg->cookie;
+
+		} else {
+			skb = (struct sk_buff *)iter.desc->cookie;
+		}
 
 		PDEBUG(priv->dev, "completed sending %d bytes\n", skb->len);
 
@@ -538,6 +699,46 @@ tx_isr(struct ioq_notifier *notifier)
        tasklet_schedule(&priv->txtask);
 }
 
+static int
+vbus_enet_negcap(struct vbus_enet_priv *priv)
+{
+	int ret;
+	struct venet_capabilities caps;
+
+	memset(&caps, 0, sizeof(caps));
+
+	if (sg_enabled) {
+		caps.gid = VENET_CAP_GROUP_SG;
+		caps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+			      |VENET_CAP_ECN|VENET_CAP_UFO);
+	}
+
+	ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+	if (ret < 0)
+		return ret;
+
+	if (caps.bits & VENET_CAP_SG) {
+		priv->flags.sg = true;
+
+		if (caps.bits & VENET_CAP_TSO4)
+			priv->flags.tso = true;
+		if (caps.bits & VENET_CAP_TSO6)
+			priv->flags.tso6 = true;
+		if (caps.bits & VENET_CAP_UFO)
+			priv->flags.ufo = true;
+		if (caps.bits & VENET_CAP_ECN)
+			priv->flags.ecn = true;
+
+		dev_info(&priv->dev->dev, "Detected GSO features %s%s%s%s\n",
+			 priv->flags.tso  ? "t" : "-",
+			 priv->flags.tso6 ? "T" : "-",
+			 priv->flags.ufo  ? "u" : "-",
+			 priv->flags.ecn  ? "e" : "-");
+	}
+
+	return 0;
+}
+
 static const struct net_device_ops vbus_enet_netdev_ops = {
 	.ndo_open          = vbus_enet_open,
 	.ndo_stop          = vbus_enet_stop,
@@ -574,12 +775,21 @@ vbus_enet_probe(struct vbus_device_proxy *vdev)
 	priv->dev  = dev;
 	priv->vdev = vdev;
 
+	ret = vbus_enet_negcap(priv);
+	if (ret < 0) {
+		printk(KERN_INFO "VENET: Error negotiating capabilities for " \
+		       "%lld\n",
+		       priv->vdev->id);
+		goto out_free;
+	}
+
 	tasklet_init(&priv->txtask, deferred_tx_isr, (unsigned long)priv);
 
 	queue_init(priv, &priv->rxq, VENET_QUEUE_RX, rx_ringlen, rx_isr);
 	queue_init(priv, &priv->txq, VENET_QUEUE_TX, tx_ringlen, tx_isr);
 
 	rx_setup(priv);
+	tx_setup(priv);
 
 	ioq_notify_enable(priv->rxq.queue, 0);  /* enable interrupts */
 	ioq_notify_enable(priv->txq.queue, 0);
@@ -599,6 +809,22 @@ vbus_enet_probe(struct vbus_device_proxy *vdev)
 
 	dev->features |= NETIF_F_HIGHDMA;
 
+	if (priv->flags.sg) {
+		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_FRAGLIST;
+
+		if (priv->flags.tso)
+			dev->features |= NETIF_F_TSO;
+
+		if (priv->flags.ufo)
+			dev->features |= NETIF_F_UFO;
+
+		if (priv->flags.tso6)
+			dev->features |= NETIF_F_TSO6;
+
+		if (priv->flags.ecn)
+			dev->features |= NETIF_F_TSO_ECN;
+	}
+
 	ret = register_netdev(dev);
 	if (ret < 0) {
 		printk(KERN_INFO "VENET: error %i registering device \"%s\"\n",
@@ -626,9 +852,9 @@ vbus_enet_remove(struct vbus_device_proxy *vdev)
 	napi_disable(&priv->napi);
 
 	rx_teardown(priv);
-	vbus_enet_tx_reap(priv, 1);
-
 	ioq_put(priv->rxq.queue);
+
+	tx_teardown(priv);
 	ioq_put(priv->txq.queue);
 
 	dev->ops->close(dev, 0);
include/linux/venet.h +37 -2
index ef6b199..1c96b90 100644
@@ -35,8 +35,43 @@ struct venet_capabilities {
 	__u32 bits;
 };
 
-/* CAPABILITIES-GROUP 0 */
-/* #define VENET_CAP_FOO    0   (No capabilities defined yet, for now) */
+#define VENET_CAP_GROUP_SG 0
+
+/* CAPABILITIES-GROUP SG */
+#define VENET_CAP_SG     (1 << 0)
+#define VENET_CAP_TSO4   (1 << 1)
+#define VENET_CAP_TSO6   (1 << 2)
+#define VENET_CAP_ECN    (1 << 3)
+#define VENET_CAP_UFO    (1 << 4)
+
+struct venet_iov {
+	__u32 len;
+	__u64 ptr;
+};
+
+#define VENET_SG_FLAG_NEEDS_CSUM (1 << 0)
+#define VENET_SG_FLAG_GSO        (1 << 1)
+#define VENET_SG_FLAG_ECN        (1 << 2)
+
+struct venet_sg {
+	__u64            cookie;
+	__u32            flags;
+	__u32            len;     /* total length of all iovs */
+	struct {
+		__u16    start;	  /* csum starting position */
+		__u16    offset;  /* offset to place csum */
+	} csum;
+	struct {
+#define VENET_GSO_TYPE_TCPV4	0	/* IPv4 TCP (TSO) */
+#define VENET_GSO_TYPE_UDP	1	/* IPv4 UDP (UFO) */
+#define VENET_GSO_TYPE_TCPV6	2	/* IPv6 TCP */
+		__u8     type;
+		__u16    hdrlen;
+		__u16    size;
+	} gso;
+	__u32            count;   /* nr of iovs */
+	struct venet_iov iov[1];
+};
 
 #define VENET_FUNC_LINKUP   0
 #define VENET_FUNC_LINKDOWN 1
#13 lore raw

RFC PATCH v3 13/17 venettap: add scatter-gather support

In reply to Gregory Haskins

---

 drivers/vbus/devices/venet-tap.c |  235 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 228 insertions(+), 7 deletions(-)
drivers/vbus/devices/venet-tap.c +228 -7
index 33ede4c..8788c05 100644
@@ -81,6 +81,13 @@ enum {
 	TX_IOQ_CONGESTED,
 };
 
+struct venettap;
+
+struct venettap_rx_ops {
+	int (*decode)(struct venettap *priv, void *ptr, int len);
+	int (*import)(struct venettap *, struct sk_buff *, void *, int);
+};
+
 struct venettap {
 	spinlock_t                   lock;
 	unsigned char                hmac[ETH_ALEN]; /* host-mac */
@@ -108,7 +115,13 @@ struct venettap {
 		struct vbus_memctx          *ctx;
 		struct venettap_queue        rxq;
 		struct venettap_queue        txq;
+		struct venettap_rx_ops      *rx_ops;
 		wait_queue_head_t            rx_empty;
+		struct {
+			struct venet_sg     *desc;
+			size_t               len;
+			int                  enabled:1;
+		} sg;
 		int                          connected:1;
 		int                          opened:1;
 		int                          link:1;
@@ -289,6 +302,183 @@ venettap_change_mtu(struct net_device *dev, int new_mtu)
 }
 
 /*
+ * ---------------------------
+ * Scatter-Gather support
+ * ---------------------------
+ */
+
+/* assumes reference to priv->vbus.conn held */
+static int
+venettap_sg_decode(struct venettap *priv, void *ptr, int len)
+{
+	struct venet_sg *vsg;
+	struct vbus_memctx *ctx;
+	int ret;
+
+	/*
+	 * SG is enabled, so we need to pull in the venet_sg
+	 * header before we can interpret the rest of the
+	 * packet
+	 *
+	 * FIXME: Make sure this is not too big
+	 */
+	if (unlikely(len > priv->vbus.sg.len)) {
+		kfree(priv->vbus.sg.desc);
+		priv->vbus.sg.desc = kzalloc(len, GFP_KERNEL);
+	}
+
+	vsg = priv->vbus.sg.desc;
+	ctx = priv->vbus.ctx;
+
+	ret = ctx->ops->copy_from(ctx, vsg, ptr, len);
+	BUG_ON(ret);
+
+	/*
+	 * Non GSO type packets should be constrained by the MTU setting
+	 * on the host
+	 */
+	if (!(vsg->flags & VENET_SG_FLAG_GSO)
+	    && (vsg->len > (priv->netif.dev->mtu + ETH_HLEN)))
+		return -1;
+
+	return vsg->len;
+}
+
+/*
+ * venettap_sg_import - import an skb in scatter-gather mode
+ *
+ * assumes reference to priv->vbus.conn held
+ */
+static int
+venettap_sg_import(struct venettap *priv, struct sk_buff *skb,
+		   void *ptr, int len)
+{
+	struct venet_sg *vsg = priv->vbus.sg.desc;
+	struct vbus_memctx *ctx = priv->vbus.ctx;
+	int remain = len;
+	int ret;
+	int i;
+
+	PDEBUG("Importing %d bytes in %d segments\n", len, vsg->count);
+
+	for (i = 0; i < vsg->count; i++) {
+		struct venet_iov *iov = &vsg->iov[i];
+
+		if (remain < iov->len)
+			return -EINVAL;
+
+		PDEBUG("Segment %d: %p/%d\n", i, iov->ptr, iov->len);
+
+		ret = ctx->ops->copy_from(ctx, skb_tail_pointer(skb),
+					 (void *)iov->ptr,
+					 iov->len);
+		if (ret)
+			return -EFAULT;
+
+		skb_put(skb, iov->len);
+		remain -= iov->len;
+	}
+
+	if (vsg->flags & VENET_SG_FLAG_NEEDS_CSUM
+	    && !skb_partial_csum_set(skb, vsg->csum.start, vsg->csum.offset))
+		return -EINVAL;
+
+	if (vsg->flags & VENET_SG_FLAG_GSO) {
+		struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+		PDEBUG("GSO packet detected\n");
+
+		switch (vsg->gso.type) {
+		case VENET_GSO_TYPE_TCPV4:
+			sinfo->gso_type = SKB_GSO_TCPV4;
+			break;
+		case VENET_GSO_TYPE_TCPV6:
+			sinfo->gso_type = SKB_GSO_TCPV6;
+			break;
+		case VENET_GSO_TYPE_UDP:
+			sinfo->gso_type = SKB_GSO_UDP;
+			break;
+		default:
+			PDEBUG("Illegal GSO type: %d\n", vsg->gso.type);
+			priv->netif.stats.rx_frame_errors++;
+			kfree_skb(skb);
+			return -EINVAL;
+		}
+
+		if (vsg->flags & VENET_SG_FLAG_ECN)
+			sinfo->gso_type |= SKB_GSO_TCP_ECN;
+
+		sinfo->gso_size = vsg->gso.size;
+		if (skb_shinfo(skb)->gso_size == 0) {
+			PDEBUG("Illegal GSO size: %d\n", vsg->gso.size);
+			priv->netif.stats.rx_frame_errors++;
+			kfree_skb(skb);
+			return -EINVAL;
+		}
+
+		/* Header must be checked, and gso_segs computed. */
+		skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+		skb_shinfo(skb)->gso_segs = 0;
+	}
+
+	return 0;
+}
+
+static struct venettap_rx_ops venettap_sg_rx_ops = {
+	.decode = venettap_sg_decode,
+	.import = venettap_sg_import,
+};
+
+/*
+ * ---------------------------
+ * Flat (non Scatter-Gather) support
+ * ---------------------------
+ */
+
+/* assumes reference to priv->vbus.conn held */
+static int
+venettap_flat_decode(struct venettap *priv, void *ptr, int len)
+{
+	size_t maxlen = priv->netif.dev->mtu + ETH_HLEN;
+
+	if (len > maxlen)
+		return -1;
+
+	/*
+	 * If SG is *not* enabled, the length is simply the
+	 * descriptor length
+	 */
+
+	return len;
+}
+
+/*
+ * venettap_rx_flat - import an skb in non scatter-gather mode
+ *
+ * assumes reference to priv->vbus.conn held
+ */
+static int
+venettap_flat_import(struct venettap *priv, struct sk_buff *skb,
+		     void *ptr, int len)
+{
+	struct vbus_memctx *ctx = priv->vbus.ctx;
+	int ret;
+
+	ret = ctx->ops->copy_from(ctx, skb_tail_pointer(skb), ptr, len);
+	if (ret)
+		return -EFAULT;
+
+	skb_put(skb, len);
+
+	return 0;
+}
+
+static struct venettap_rx_ops venettap_flat_rx_ops = {
+	.decode = venettap_flat_decode,
+	.import = venettap_flat_import,
+};
+
+/*
  * The poll implementation.
  */
 static int
@@ -302,6 +492,7 @@ venettap_rx(struct venettap *priv)
 	int                         ret;
 	unsigned long               flags;
 	struct vbus_connection     *conn;
+	struct venettap_rx_ops     *rx_ops;
 
 	PDEBUG("polling...\n");
 
@@ -325,6 +516,8 @@ venettap_rx(struct venettap *priv)
 	ioq = priv->vbus.rxq.queue;
 	ctx = priv->vbus.ctx;
 
+	rx_ops = priv->vbus.rx_ops;
+
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* We want to iterate on the head of the in-use index */
@@ -339,11 +532,14 @@ venettap_rx(struct venettap *priv)
 	 * the north side
 	 */
 	while (iter.desc->sown) {
-		size_t len = iter.desc->len;
-		size_t maxlen = priv->netif.dev->mtu + ETH_HLEN;
 		struct sk_buff *skb = NULL;
+		size_t len;
 
-		if (unlikely(len > maxlen)) {
+		len = rx_ops->decode(priv,
+				     (void *)iter.desc->ptr,
+				     iter.desc->len);
+
+		if (unlikely(len < 0)) {
 			priv->netif.stats.rx_errors++;
 			priv->netif.stats.rx_length_errors++;
 			goto next;
@@ -361,10 +557,8 @@ venettap_rx(struct venettap *priv)
 		/* align IP on 16B boundary */
 		skb_reserve(skb, 2);
 
-		ret = ctx->ops->copy_from(ctx, skb->data,
-					 (void *)iter.desc->ptr,
-					 len);
-		if (unlikely(ret)) {
+		ret = rx_ops->import(priv, skb, (void *)iter.desc->ptr, len);
+		if (unlikely(ret < 0)) {
 			priv->netif.stats.rx_errors++;
 			goto next;
 		}
@@ -845,6 +1039,23 @@ venettap_macquery(struct venettap *priv, void *data, unsigned long len)
 	return 0;
 }
 
+static u32
+venettap_negcap_sg(struct venettap *priv, u32 requested)
+{
+	u32 available = VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+		|VENET_CAP_ECN;
+	u32 ret;
+
+	ret = available & requested;
+
+	if (ret & VENET_CAP_SG) {
+		priv->vbus.sg.enabled = true;
+		priv->vbus.rx_ops = &venettap_sg_rx_ops;
+	}
+
+	return ret;
+}
+
 /*
  * Negotiate Capabilities - This function is provided so that the
  * interface may be extended without breaking ABI compatability
@@ -872,6 +1083,9 @@ venettap_negcap(struct venettap *priv, void *data, unsigned long len)
 		return -EFAULT;
 
 	switch (caps.gid) {
+	case VENET_CAP_GROUP_SG:
+		caps.bits = venettap_negcap_sg(priv, caps.bits);
+		break;
 	default:
 		caps.bits = 0;
 		break;
@@ -1056,6 +1270,12 @@ venettap_vlink_release(struct vbus_connection *conn)
 	vbus_memctx_put(priv->vbus.ctx);
 
 	kobject_put(priv->vbus.dev.kobj);
+
+	priv->vbus.sg.enabled = false;
+	priv->vbus.rx_ops = &venettap_flat_rx_ops;
+	kfree(priv->vbus.sg.desc);
+	priv->vbus.sg.desc = NULL;
+	priv->vbus.sg.len = 0;
 }
 
 static struct vbus_connection_ops venettap_vbus_link_ops = {
@@ -1368,6 +1588,7 @@ venettap_device_create(struct vbus_devclass *dc,
 	_vdev->ops             = &venettap_device_ops;
 	_vdev->attrs           = &venettap_attr_group;
 
+	priv->vbus.rx_ops      = &venettap_flat_rx_ops;
 	init_waitqueue_head(&priv->vbus.rx_empty);
 
 	/*
#14 lore raw

RFC PATCH v3 14/17 kvm: Add VBUS support to the host

In reply to Gregory Haskins

This patch adds support for guest access to a VBUS assigned to the same context as the VM. It utilizes a IOQ+IRQ to move events from host->guest, and provides a hypercall interface to move events guest->host.

Special thanks to Alex Tsariounov for submitting patches for cleaning up some sloppy warnings I had left in the code.

---

 arch/x86/include/asm/kvm_para.h |    1 
 arch/x86/kvm/Kconfig            |    9 
 arch/x86/kvm/Makefile           |    3 
 arch/x86/kvm/x86.c              |    6 
 arch/x86/kvm/x86.h              |   12 
 include/linux/kvm.h             |    7 
 include/linux/kvm_host.h        |   26 +
 include/linux/kvm_para.h        |   58 ++
 virt/kvm/kvm_main.c             |   10 
 virt/kvm/vbus.c                 | 1392 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 1524 insertions(+), 0 deletions(-)
 create mode 100644 virt/kvm/vbus.c
arch/x86/include/asm/kvm_para.h +1 -0
index b8a3305..0a209b4 100644
@@ -13,6 +13,7 @@
 #define KVM_FEATURE_CLOCKSOURCE		0
 #define KVM_FEATURE_NOP_IO_DELAY	1
 #define KVM_FEATURE_MMU_OP		2
+#define KVM_FEATURE_VBUS                3
 
 #define MSR_KVM_WALL_CLOCK  0x11
 #define MSR_KVM_SYSTEM_TIME 0x12
arch/x86/kvm/Kconfig +9 -0
index a58504e..f2bcb4f 100644
@@ -69,6 +69,15 @@ config KVM_TRACE
 	  relayfs.  Note the ABI is not considered stable and will be
 	  modified in future updates.
 
+config KVM_HOST_VBUS
+       bool "KVM virtual-bus (VBUS) host-side support"
+       depends on KVM
+       select VBUS
+       default n
+       ---help---
+          This option enables host-side support for accessing virtual-bus
+	  devices.
+
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/lguest/Kconfig
arch/x86/kvm/Makefile +3 -0
index d3ec292..32ffe5b 100644
@@ -15,6 +15,9 @@ EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
 
 kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
 	i8254.o
+ifeq ($(CONFIG_KVM_HOST_VBUS),y)
+kvm-objs += $(addprefix ../../../virt/kvm/, vbus.o)
+endif
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
arch/x86/kvm/x86.c +6 -0
index 8ca100a..9f4895e 100644
@@ -1040,6 +1040,9 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_IOMMU:
 		r = iommu_found();
 		break;
+	case KVM_CAP_VBUS:
+		r = kvm_vbus_support();
+		break;
 	default:
 		r = 0;
 		break;
@@ -2830,6 +2833,9 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 	case KVM_HC_MMU_OP:
 		r = kvm_pv_mmu_op(vcpu, a0, hc_gpa(vcpu, a1, a2), &ret);
 		break;
+	case KVM_HC_VBUS:
+		ret = kvm_vbus_hc(vcpu, a0, a1, a2);
+		break;
 	default:
 		ret = -KVM_ENOSYS;
 		break;
arch/x86/kvm/x86.h +12 -0
index 6a4be78..b6c682b 100644
@@ -3,6 +3,18 @@
 
 #include <linux/kvm_host.h>
 
+#ifdef CONFIG_KVM_HOST_VBUS
+static inline int kvm_vbus_support(void)
+{
+    return 1;
+}
+#else
+static inline int kvm_vbus_support(void)
+{
+    return 0;
+}
+#endif
+
 static inline void kvm_clear_exception_queue(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.exception.pending = false;
include/linux/kvm.h +7 -0
index 311a073..9b83bbc 100644
@@ -409,6 +409,7 @@ struct kvm_trace_rec {
 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
 #define KVM_CAP_DEVICE_DEASSIGNMENT 27
 #endif
+#define KVM_CAP_VBUS 28
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -448,6 +449,11 @@ struct kvm_irq_routing {
 
 #endif
 
+struct kvm_vbus_gsi {
+	__u32 queue;
+	__u32 gsi;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -485,6 +491,7 @@ struct kvm_irq_routing {
 #define KVM_REINJECT_CONTROL      _IO(KVMIO, 0x71)
 #define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
 				     struct kvm_assigned_pci_dev)
+#define KVM_VBUS_ASSIGN_GSI       _IOW(KVMIO, 0x73, struct kvm_vbus_gsi)
 
 /*
  * ioctls for vcpu fds
include/linux/kvm_host.h +26 -0
index 894a56e..43c310c 100644
@@ -134,6 +134,9 @@ struct kvm {
 	struct list_head vm_list;
 	struct kvm_io_bus mmio_bus;
 	struct kvm_io_bus pio_bus;
+#ifdef CONFIG_KVM_HOST_VBUS
+	struct kvm_vbus *kvbus;
+#endif
 	struct kvm_vm_stat stat;
 	struct kvm_arch arch;
 	atomic_t users_count;
@@ -512,4 +515,27 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
 
 #endif
 
+#ifdef CONFIG_KVM_HOST_VBUS
+
+int kvm_vbus_hc(struct kvm_vcpu *vcpu, int nr, gpa_t gpa, size_t len);
+void kvm_vbus_release(struct kvm_vbus *kvbus);
+int kvm_vbus_assign_gsi(struct kvm *kvm, int queue, int gsi);
+
+#else /* CONFIG_KVM_HOST_VBUS */
+
+static inline int
+kvm_vbus_hc(struct kvm_vcpu *vcpu, int nr, gpa_t gpa, size_t len)
+{
+	return -EINVAL;
+}
+
+#define kvm_vbus_release(kvbus) do {} while (0)
+
+static inline int kvm_vbus_assign_gsi(struct kvm *kvm, int queue, int gsi)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_KVM_HOST_VBUS */
+
 #endif
include/linux/kvm_para.h +58 -0

64 lines not on this page · raw message

virt/kvm/kvm_main.c +10 -0
index 605697e..5373402 100644
@@ -901,6 +901,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
 {
 	struct kvm *kvm = filp->private_data;
 
+	kvm_vbus_release(kvm->kvbus);
 	kvm_put_kvm(kvm);
 	return 0;
 }
@@ -1920,6 +1921,15 @@ static long kvm_vm_ioctl(struct file *filp,
 		break;
 	}
 #endif
+	case KVM_VBUS_ASSIGN_GSI: {
+		struct kvm_vbus_gsi data;
+
+		r = -EFAULT;
+		if (copy_from_user(&data, argp, sizeof data))
+			goto out;
+		r = kvm_vbus_assign_gsi(kvm, data.queue, data.gsi);
+		break;
+	}
 	default:
 		r = kvm_arch_vm_ioctl(filp, ioctl, arg);
 	}
virt/kvm/vbus.c new file +1392 -0

1,392 lines not on this page · raw message

#15 lore raw

RFC PATCH v3 15/17 kvm: Add guest-side support for VBUS

In reply to Gregory Haskins

This adds a driver to interface between the host VBUS support, and the guest-vbus bus model.

---

 arch/x86/Kconfig            |    9 +
 drivers/Makefile            |    1 
 drivers/vbus/proxy/Makefile |    2 
 drivers/vbus/proxy/kvm.c    |  751 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 763 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vbus/proxy/Makefile
 create mode 100644 drivers/vbus/proxy/kvm.c
arch/x86/Kconfig +9 -0
index e222395..25bd822 100644
@@ -486,6 +486,15 @@ config KVM_GUEST
 	  This option enables various optimizations for running under the KVM
 	  hypervisor.
 
+config KVM_GUEST_VBUS
+       tristate "KVM virtual-bus (VBUS) guest-side support"
+       depends on KVM_GUEST
+       select VBUS_DRIVERS
+       default y
+       ---help---
+          This option enables guest-side support for accessing virtual-bus
+	  devices.
+
 source "arch/x86/lguest/Kconfig"
 
 config PARAVIRT
drivers/Makefile +1 -0
index 4c66912..df088cf 100644
@@ -108,3 +108,4 @@ obj-$(CONFIG_VIRTIO)		+= virtio/
 obj-$(CONFIG_STAGING)		+= staging/
 obj-y				+= platform/
 obj-$(CONFIG_VBUS_DEVICES)	+= vbus/devices/
+obj-$(CONFIG_VBUS_DRIVERS)	+= vbus/proxy/
drivers/vbus/proxy/Makefile new file +2 -0
new file mode 100644
index 0000000..c18d58d
@@ -0,0 +1,2 @@
+kvm-guest-vbus-objs += kvm.o
+obj-$(CONFIG_KVM_GUEST_VBUS) += kvm-guest-vbus.o
drivers/vbus/proxy/kvm.c new file +751 -0

751 lines not on this page · raw message

#16 lore raw

RFC PATCH v3 16/17 vbus: add a userspace connector

In reply to Gregory Haskins

This allows userspace applications to access vbus devices

---

 include/linux/vbus.h           |    4 
 include/linux/vbus_client.h    |    2 
 include/linux/vbus_userspace.h |   48 ++++
 kernel/vbus/Kconfig            |   10 +
 kernel/vbus/Makefile           |    2 
 kernel/vbus/userspace-client.c |  485 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 550 insertions(+), 1 deletions(-)
 create mode 100644 include/linux/vbus_userspace.h
 create mode 100644 kernel/vbus/userspace-client.c
include/linux/vbus.h +4 -0
index 04db4ff..f967e59 100644
@@ -23,6 +23,8 @@
 #ifndef _LINUX_VBUS_H
 #define _LINUX_VBUS_H
 
+#ifdef __KERNEL__
+
 #ifdef CONFIG_VBUS
 
 #include <linux/module.h>
@@ -159,4 +161,6 @@ int vbus_notifier_unregister(struct vbus *vbus, struct notifier_block *nb);
 
 #endif /* CONFIG_VBUS */
 
+#endif /* __KERNEL__ */
+
 #endif /* _LINUX_VBUS_H */
include/linux/vbus_client.h +1 -1
index 62dab78..4c82822 100644
@@ -35,7 +35,7 @@
 #ifndef _LINUX_VBUS_CLIENT_H
 #define _LINUX_VBUS_CLIENT_H
 
-#include <linux/types.h>
+#include <asm/types.h>
 #include <linux/compiler.h>
 
 struct vbus_deviceopen {
include/linux/vbus_userspace.h new file +48 -0

48 lines not on this page · raw message

kernel/vbus/Kconfig +10 -0
index 3ce0adc..b894dd1 100644
@@ -25,6 +25,16 @@ config VBUS_DEVICES
 
 source "drivers/vbus/devices/Kconfig"
 
+config VBUS_USERSPACE
+       tristate "Virtual-Bus userspace client support"
+       depends on VBUS
+       default y
+       help
+         Provides facilities for userspace applications to access virtual-
+	 bus objects.
+
+	 If unsure, say N
+
 config VBUS_DRIVERS
        tristate "VBUS Driver support"
        select IOQ
kernel/vbus/Makefile +2 -0
index 45f6503..61d0371 100644
@@ -4,3 +4,5 @@ obj-$(CONFIG_VBUS) += shm-ioq.o
 vbus-proxy-objs += proxy.o
 obj-$(CONFIG_VBUS_DRIVERS) += vbus-proxy.o
 
+vbus-userspace-objs += userspace-client.o
+obj-$(CONFIG_VBUS_USERSPACE) += vbus-userspace.o
kernel/vbus/userspace-client.c new file +485 -0

485 lines not on this page · raw message

#17 lore raw

RFC PATCH v3 17/17 virtio: add a vbus transport

In reply to Gregory Haskins

We add a new virtio transport for accessing backends located on vbus. This complements the existing transports for virtio-pci, virtio-s390, and virtio-lguest that already exist.

---

 drivers/virtio/Kconfig       |   15 +
 drivers/virtio/Makefile      |    1 
 drivers/virtio/virtio_vbus.c |  496 +++++++++++++++++++++++++++++++++
 include/linux/virtio_vbus.h  |  163 +++++++++++
 kernel/vbus/Kconfig          |    8 +
 kernel/vbus/Makefile         |    3 
 kernel/vbus/virtio.c         |  627 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 1313 insertions(+), 0 deletions(-)
 create mode 100644 drivers/virtio/virtio_vbus.c
 create mode 100644 include/linux/virtio_vbus.h
 create mode 100644 kernel/vbus/virtio.c
drivers/virtio/Kconfig +15 -0
index 3dd6294..e8562ee 100644
@@ -23,6 +23,21 @@ config VIRTIO_PCI
 
 	  If unsure, say M.
 
+config VIRTIO_VBUS
+	tristate "VBUS driver for virtio devices (EXPERIMENTAL)"
+	depends on VBUS_DRIVERS && EXPERIMENTAL
+	select VIRTIO
+	select VIRTIO_RING
+	---help---
+	  This drivers provides support for virtio based paravirtual device
+	  drivers over VBUS.  This requires that your VMM has appropriate VBUS
+	  virtio backends.
+
+	  Currently, the ABI is not considered stable so there is no guarantee
+	  that this version of the driver will work with your VMM.
+
+	  If unsure, say M.
+
 config VIRTIO_BALLOON
 	tristate "Virtio balloon driver (EXPERIMENTAL)"
 	select VIRTIO
drivers/virtio/Makefile +1 -0
index 6738c44..0342e42 100644
@@ -1,4 +1,5 @@
 obj-$(CONFIG_VIRTIO) += virtio.o
 obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
+obj-$(CONFIG_VIRTIO_VBUS) += virtio_vbus.o
 obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
drivers/virtio/virtio_vbus.c new file +496 -0

496 lines not on this page · raw message

include/linux/virtio_vbus.h new file +163 -0

163 lines not on this page · raw message

kernel/vbus/Kconfig +8 -0
index b894dd1..0a4813e 100644
@@ -14,6 +14,14 @@ config VBUS
 
 	If unsure, say N
 
+config VBUS_VIRTIO_BACKEND
+       tristate "Virtio VBUS Backend"
+       depends on VIRTIO_RING
+       depends on VBUS
+       default n
+       help
+        Provides backend support for virtio devices over vbus
+
 config VBUS_DEVICES
        bool "Virtual-Bus Devices"
        depends on VBUS
kernel/vbus/Makefile +3 -0
index 61d0371..c2bd140 100644
@@ -1,6 +1,9 @@
 obj-$(CONFIG_VBUS) += core.o devclass.o config.o attribute.o map.o client.o
 obj-$(CONFIG_VBUS) += shm-ioq.o
 
+virtio-backend-objs += virtio.o
+obj-$(CONFIG_VBUS_VIRTIO_BACKEND) += virtio-backend.o
+
 vbus-proxy-objs += proxy.o
 obj-$(CONFIG_VBUS_DRIVERS) += vbus-proxy.o
 
kernel/vbus/virtio.c new file +627 -0

627 lines not on this page · raw message

#18 lore raw
In reply to Gregory Haskins

Hi Gregory,

I'd like to try Your vbus patches, but compiling 2.6.30-rc2 (or 2.6.30-rc5) fails
with following error:
drivers/vbus/proxy/kvm-guest-vbus: struct pci_device_id is 32 bytes. The last of 1 is:
0xda 0x11 0x00 0x00 0x00 0x20 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
FATAL: drivers/vbus/proxy/kvm-guest-vbus: struct pci_device_id is not terminated with a NULL entry!

Do You have any idea on what might be wrong?
thanks a lot in advance...
BR
nik

Quoted 221 lines · Gregory Haskins

RFC: Virtual-Bus (applies to v2.6.30-rc2)
----------------------

Virtual-Bus is a Linux-kernel based virtual IO resource container technology. It allows you to declare virtualized device models directly within a host kernel that can be uniformly accessed from a variety of environments, such as KVM, userspace, lguest, Xen, etc. The goal is to reduce overhead while still preserving proper isolation to achieve maximum throughput and latency from your IO subsystem. It is installed on the host and configured using simple filesystem operations like "mkdir" to create a new container, "ln -s" to associate a device with a container, and "echo" to configure the device thanks to integration with configfs/sysfs. Therefore, managing a virtual-bus does not require special userspace tools.

Why would we want this?
----------------------

We believe that a combination of in-kernel models, coupled with optimizations in various areas such as reducing the number of context switches and executing the algorithms in parallel on modern multicore CPUs will result in the best possible IO performance for technologies such as virtualization. This facility aims to provide the framework for building such constructs in in software in the most efficient way we believe is possible.

Preliminary Results:
-----------------------

As a test, we wrote a virtual-ethernet backend and a Linux driver (called venet) and tested the setup with v2.6.29 on two 8-core x86_64 boxes with Chelsio T3 10GE connected back to back via cross over. We measured bare-metal performance, as well as a kvm guest (running the same kernel) connected to the T3 via a linux-bridge+tap configuration with a 1500 MTU. The results are as follows:

Bare metal : tput = 4078Mb/s, round-trip = 25593pps (39us rtt)
Virtio-net (PCI) : tput = 4003Mb/s, round-trip = 320pps (3125us rtt)
Venet (VBUS): tput = 4050Mb/s, round-trip = 15255 (65us rtt)

When we jump to 9000 byte MTU, the situation looks similar

Bare metal : tput = 9717Mb/s, round-trip = 30396pps (33us rtt)
Virtio-net (PCI) : tput = 4578Mb/s, round-trip = 249pps (4016us rtt)
Venet (VBUS): tput = 5802Mb/s, round-trip = 15127 (66us rtt)

Note that to be fair, part of the latency response from virtio-pci is due to the way that the driver/backend coalesces packets, and not a true limitation of the userspace path as the results may imply. Anthony Liguori is already looking into improving this based on the results we presented here, and is making good headway.

Also note that as of v2, we support a virtio-vbus transport, and therefore will soon be able to compare "Virtio-net (VBUS)" as an additional target in the near future once we have developed a virtio-net backend for the host. This virtio-net(pci) to virtio-net(vbus) comparison is probably more interesting than comparing to Venet as it would be more apples to apples. Also it would be nice to only need one PV driver per IO subsystem in the long term.

Changes v2->v3:
------------------

*) VBUS now renders as a PCI/MSI device instead of via cpuid/dynirq *) Dropped dynirq (replaced with MSI facility)
*) Dropped "reset" patch in favor of more reliably detecting reset via BUSOPEN *) Incorporated more review feedback from Stephen Hemminger on vbus-enet
driver
*) Added support for setting the guests MAC during host config (Pat Mullaney) *) Cleaned up documentation per feedback from Ben Hutchings
*) Numerous small tweaks to clean up things like warnings, comments, etc.
(Alex Tsariounov, Greg Haskins)
*) Fixed Kconfig dependency problem with virtio-vbus with feedback from
Peter Morreale.

Changes v1->v2:

*) Incorporated review feedback from Stephen Hemminger on vbus-enet driver *) Added support for connecting to vbus devices from userspace *) Added support for a virtio-vbus transport to allow virtio drivers to
work with vbus (needs testing and backend models).

Todo:
*) Beef up the userspace event channel ABI to support different event types *) Add memory-registration support
*) Develop some virtio backend devices.
*) Support ethtool_ops for venet.
*) Convert from MSI to MSIX to truely support multiple vectors

---------------------------------------

For more details, please see our Wiki at

http://developer.novell.com/wiki/index.php/Virtual-bus

---

Gregory Haskins (16):
virtio: add a vbus transport
vbus: add a userspace connector
kvm: Add guest-side support for VBUS
kvm: Add VBUS support to the host
venettap: add scatter-gather support
venet: add scatter-gather support
venet-tap: Adds a "venet" compatible "tap" device to VBUS
net: Add vbus_enet driver
venet: add the ABI definitions for an 802.x packet interface
ioq: add vbus helpers
ioq: Add basic definitions for a shared-memory, lockless queue
vbus: add a "vbus-proxy" bus model for vbus_driver objects
vbus: add bus-registration notifiers
vbus: add connection-client helper infrastructure
vbus: add virtual-bus definitions
shm-signal: shared-memory signals

Patrick Mullaney (1):
venet-tap: add the ability to set the client's mac address via sysfs

 Documentation/vbus.txt           |  385 +++++++++
 arch/x86/Kconfig                 |   11 
 arch/x86/include/asm/kvm_para.h  |    1 
 arch/x86/kvm/Kconfig             |    9 
 arch/x86/kvm/Makefile            |    3 
 arch/x86/kvm/x86.c               |    6 
 arch/x86/kvm/x86.h               |   12 
 drivers/Makefile                 |    2 
 drivers/net/Kconfig              |   13 
 drivers/net/Makefile             |    1 
 drivers/net/vbus-enet.c          |  898 +++++++++++++++++++++
 drivers/vbus/devices/Kconfig     |   17 
 drivers/vbus/devices/Makefile    |    1 
 drivers/vbus/devices/venet-tap.c | 1641 ++++++++++++++++++++++++++++++++++++++
 drivers/vbus/proxy/Makefile      |    2 
 drivers/vbus/proxy/kvm.c         |  751 +++++++++++++++++
 drivers/virtio/Kconfig           |   15 
 drivers/virtio/Makefile          |    1 
 drivers/virtio/virtio_vbus.c     |  496 +++++++++++
 fs/proc/base.c                   |   96 ++
 include/linux/ioq.h              |  410 +++++++++
 include/linux/kvm.h              |    7 
 include/linux/kvm_host.h         |   26 +
 include/linux/kvm_para.h         |   58 +
 include/linux/sched.h            |    4 
 include/linux/shm_signal.h       |  188 ++++
 include/linux/vbus.h             |  166 ++++
 include/linux/vbus_client.h      |  115 +++
 include/linux/vbus_device.h      |  424 ++++++++++
 include/linux/vbus_driver.h      |   80 ++
 include/linux/vbus_userspace.h   |   48 +
 include/linux/venet.h            |   82 ++
 include/linux/virtio_vbus.h      |  163 ++++
 kernel/Makefile                  |    1 
 kernel/exit.c                    |    2 
 kernel/fork.c                    |    2 
 kernel/vbus/Kconfig              |   56 +
 kernel/vbus/Makefile             |   11 
 kernel/vbus/attribute.c          |   52 +
 kernel/vbus/client.c             |  543 +++++++++++++
 kernel/vbus/config.c             |  275 ++++++
 kernel/vbus/core.c               |  626 ++++++++++++++
 kernel/vbus/devclass.c           |  124 +++
 kernel/vbus/map.c                |   72 ++
 kernel/vbus/map.h                |   41 +
 kernel/vbus/proxy.c              |  216 +++++
 kernel/vbus/shm-ioq.c            |   89 ++
 kernel/vbus/userspace-client.c   |  485 +++++++++++
 kernel/vbus/vbus.h               |  117 +++
 kernel/vbus/virtio.c             |  627 +++++++++++++++
 lib/Kconfig                      |   21 
 lib/Makefile                     |    2 
 lib/ioq.c                        |  298 +++++++
 lib/shm_signal.c                 |  186 ++++
 virt/kvm/kvm_main.c              |   10 
 virt/kvm/vbus.c                  | 1392 ++++++++++++++++++++++++++++++++
 56 files changed, 11380 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/vbus.txt
 create mode 100644 drivers/net/vbus-enet.c
 create mode 100644 drivers/vbus/devices/Kconfig
 create mode 100644 drivers/vbus/devices/Makefile
 create mode 100644 drivers/vbus/devices/venet-tap.c
 create mode 100644 drivers/vbus/proxy/Makefile
 create mode 100644 drivers/vbus/proxy/kvm.c
 create mode 100644 drivers/virtio/virtio_vbus.c
 create mode 100644 include/linux/ioq.h
 create mode 100644 include/linux/shm_signal.h
 create mode 100644 include/linux/vbus.h
 create mode 100644 include/linux/vbus_client.h
 create mode 100644 include/linux/vbus_device.h
 create mode 100644 include/linux/vbus_driver.h
 create mode 100644 include/linux/vbus_userspace.h
 create mode 100644 include/linux/venet.h
 create mode 100644 include/linux/virtio_vbus.h
 create mode 100644 kernel/vbus/Kconfig
 create mode 100644 kernel/vbus/Makefile
 create mode 100644 kernel/vbus/attribute.c
 create mode 100644 kernel/vbus/client.c
 create mode 100644 kernel/vbus/config.c
 create mode 100644 kernel/vbus/core.c
 create mode 100644 kernel/vbus/devclass.c
 create mode 100644 kernel/vbus/map.c
 create mode 100644 kernel/vbus/map.h
 create mode 100644 kernel/vbus/proxy.c
 create mode 100644 kernel/vbus/shm-ioq.c
 create mode 100644 kernel/vbus/userspace-client.c
 create mode 100644 kernel/vbus/vbus.h
 create mode 100644 kernel/vbus/virtio.c
 create mode 100644 lib/ioq.c
 create mode 100644 lib/shm_signal.c
 create mode 100644 virt/kvm/vbus.c
Signature · 5 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Signature · 14 lines
-------------------------------------
Nikola CIPRICH
LinuxBox.cz, s.r.o.
28. rijna 168, 709 01 Ostrava

tel.:   +420 596 603 142
fax:    +420 596 621 273
mobil:  +420 777 093 799

www.linuxbox.cz

mobil servis: +420 737 238 656
email servis: [email protected]
-------------------------------------
#19 lore raw
Quoted 11 lines · Nikola Ciprich

Hi Gregory,

I'd like to try Your vbus patches, but compiling 2.6.30-rc2 (or 2.6.30-rc5) fails
with following error:
drivers/vbus/proxy/kvm-guest-vbus: struct pci_device_id is 32 bytes. The last of 1 is:
0xda 0x11 0x00 0x00 0x00 0x20 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
FATAL: drivers/vbus/proxy/kvm-guest-vbus: struct pci_device_id is not terminated with a NULL entry!

Do You have any idea on what might be wrong?
thanks a lot in advance...

Hi Nik,
I haven't seen that error with vbus itself, but oddly enough I just
encountered something similar when I was working on a different series
(nullio). The fix there was trivial, and I suspect it will be here as
well. What I am more confused on is why this suddenly started happening.... I will get back to you with a fix.

Regards,
-Greg