ivshmem: update documentation, add client/server tools
v6 cover ivshmem: update documentation, add client/server tools
Here is a patchset containing an update on ivshmem specs documentation and importing ivshmem server and client tools.
These tools have been written from scratch and are not related to what is available in nahanni repository.
I put them in contrib/ directory as the qemu-doc.texi was already telling the server was supposed to be there.
Changes since v5:
- 1st patch
* fixed remaining coding style issues
* fixed checks on snprintf return code
* prefixed all symbols to avoid pollution
* fixed spelling mistakes in comments
* fixed function descriptions in headers
* added a signal handler on SIGTERM and only unlink server socket when server exits
* fixed fd leaks I identified in client when reconnecting to a server
- 3rd patch
* remove wrong debug message
* do not delay pci bar2 register
Changes since v4:
- squashed patches 3-13 from v4 into first patch
- reused reported error when parsing arguments in server
- fixed spelling mistakes in documentation in second patch
Changes since v3:
- first patch is untouched
- just restored the Reviewed-By Claudio in second patch
- following patches 3-8 take into account Stefan's comments
- patches 9-12 take into account Gonglei's comments
- patch 13 adjusts ivshmem-server default values
- last patch introduces a change in the ivshmem client-server protocol to check a protocol version at connect time
Changes since v2:
- fixed license issues in ivshmem client/server (I took hw/virtio/virtio-rng.c file as a reference).
Changes since v1:
- moved client/server import patch before doc update,
- tried to re-organise the ivshmem_device_spec.txt file based on Claudio comments (still not sure if the result is that great, comments welcome),
- incorporated comments from Claudio, Eric and Cam,
- added more details on the server <-> client messages exchange (but sorry, no ASCII art here).
By the way, there are still some functionnalities that need description (use of ioeventfd, the lack of irqfd support) and some parts of the ivshmem code clearly need cleanup. I will try to address this in future patches when these first patches are ok.
Signature · 30 lines
David Marchand David Marchand (3): contrib: add ivshmem client and server docs: update ivshmem device spec ivshmem: add check on protocol version in QEMU Makefile | 8 + configure | 3 + contrib/ivshmem-client/ivshmem-client.c | 440 +++++++++++++++++++++++++++++++ contrib/ivshmem-client/ivshmem-client.h | 213 +++++++++++++++ contrib/ivshmem-client/main.c | 239 +++++++++++++++++ contrib/ivshmem-server/ivshmem-server.c | 426 ++++++++++++++++++++++++++++++ contrib/ivshmem-server/ivshmem-server.h | 165 ++++++++++++ contrib/ivshmem-server/main.c | 264 +++++++++++++++++++ docs/specs/ivshmem_device_spec.txt | 127 ++++++--- hw/misc/ivshmem.c | 27 +- include/hw/misc/ivshmem.h | 17 ++ qemu-doc.texi | 10 +- 12 files changed, 1903 insertions(+), 36 deletions(-) create mode 100644 contrib/ivshmem-client/ivshmem-client.c create mode 100644 contrib/ivshmem-client/ivshmem-client.h create mode 100644 contrib/ivshmem-client/main.c create mode 100644 contrib/ivshmem-server/ivshmem-server.c create mode 100644 contrib/ivshmem-server/ivshmem-server.h create mode 100644 contrib/ivshmem-server/main.c create mode 100644 include/hw/misc/ivshmem.h -- 1.7.10.4
PATCH v6 1/3 contrib: add ivshmem client and server
When using ivshmem devices, notifications between guests can be sent as interrupts using a ivshmem-server (typical use described in documentation). The client is provided as a debug tool.
--- Makefile | 8 + configure | 3 + contrib/ivshmem-client/ivshmem-client.c | 433 +++++++++++++++++++++++++++++++ contrib/ivshmem-client/ivshmem-client.h | 212 +++++++++++++++ contrib/ivshmem-client/main.c | 239 +++++++++++++++++ contrib/ivshmem-server/ivshmem-server.c | 417 +++++++++++++++++++++++++++++ contrib/ivshmem-server/ivshmem-server.h | 164 ++++++++++++ contrib/ivshmem-server/main.c | 264 +++++++++++++++++++ qemu-doc.texi | 10 +- 9 files changed, 1747 insertions(+), 3 deletions(-) create mode 100644 contrib/ivshmem-client/ivshmem-client.c create mode 100644 contrib/ivshmem-client/ivshmem-client.h create mode 100644 contrib/ivshmem-client/main.c create mode 100644 contrib/ivshmem-server/ivshmem-server.c create mode 100644 contrib/ivshmem-server/ivshmem-server.h create mode 100644 contrib/ivshmem-server/main.c
Makefile +8 -0
@@ -283,6 +283,14 @@ $(qga-obj-y) qemu-ga.o: $(QGALIB_GEN) qemu-ga$(EXESUF): $(qga-obj-y) libqemuutil.a libqemustub.a $(call LINK, $^) +IVSHMEM_CLIENT_OBJS=$(addprefix $(SRC_PATH)/contrib/ivshmem-client/, ivshmem-client.o main.o) +ivshmem-client$(EXESUF): $(IVSHMEM_CLIENT_OBJS) + $(call LINK, $^) + +IVSHMEM_SERVER_OBJS=$(addprefix $(SRC_PATH)/contrib/ivshmem-server/, ivshmem-server.o main.o) +ivshmem-server$(EXESUF): $(IVSHMEM_SERVER_OBJS) libqemuutil.a libqemustub.a + $(call LINK, $^) + clean: # avoid old build problems by removing potentially incorrect old files rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
configure +3 -0
@@ -4125,6 +4125,9 @@ if test "$want_tools" = "yes" ; then if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then tools="qemu-nbd\$(EXESUF) $tools" fi + if [ "$kvm" = "yes" ] ; then + tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools" + fi fi if test "$softmmu" = yes ; then if test "$virtfs" != no ; then
contrib/ivshmem-client/ivshmem-client.c new file +433 -0
433 lines not on this page · raw message
contrib/ivshmem-client/ivshmem-client.h new file +212 -0
212 lines not on this page · raw message
contrib/ivshmem-client/main.c new file +239 -0
239 lines not on this page · raw message
contrib/ivshmem-server/ivshmem-server.c new file +417 -0
417 lines not on this page · raw message
contrib/ivshmem-server/ivshmem-server.h new file +164 -0
164 lines not on this page · raw message
contrib/ivshmem-server/main.c new file +264 -0
264 lines not on this page · raw message
qemu-doc.texi +7 -3
@@ -1250,9 +1250,13 @@ is qemu.git/contrib/ivshmem-server. An example syntax when using the shared memory server is: @example -qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,chardev=<id>] - [,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master] -qemu-system-i386 -chardev socket,path=<path>,id=<id> +# First start the ivshmem server once and for all +ivshmem-server -p <pidfile> -S <path> -m <shm name> -l <shm size> -n <vectors n> + +# Then start your qemu instances with matching arguments +qemu-system-i386 -device ivshmem,size=<shm size>,vectors=<vectors n>,chardev=<id> + [,msi=on][,ioeventfd=on][,role=peer|master] + -chardev socket,path=<path>,id=<id> @end example When using the server, the guest will be assigned a VM ID (>=0) that allows guests
Signature · 1 line
1.7.10.4
Re: [PATCH v6 1/3] contrib: add ivshmem client and server
On Mon, Sep 08, 2014 at 11:17:48AM +0200, David Marchand wrote:
...
configure if test "$want_tools" = "yes" ; then · line 4130
Quoted 11 lines
configure +3
-0@@ -4125,6 +4125,9 @@ if test "$want_tools" = "yes" ; then if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then tools="qemu-nbd\$(EXESUF) $tools" fi + if [ "$kvm" = "yes" ] ; then + tools="ivshmem-client\$(EXESUF) ivshmem-server\$(EXESUF) $tools" + fi
Why are you tying this to kvm btw?
Shouldn't be for any linux host?
Quoted 3 lines
configure +0
-0fi if test "$softmmu" = yes ; then if test "$virtfs" != no ; then
...
Quoted 40 lines
contrib/ivshmem-client/ivshmem-client.h new file +34
-0@@ -0,0 +1,212 @@ +/* +* Copyright 6WIND S.A., 2014 +* +* This work is licensed under the terms of the GNU GPL, version 2 or +* (at your option) any later version. See the COPYING file in the +* top-level directory. +*/ + +#ifndef _IVSHMEM_CLIENT_H_ +#define _IVSHMEM_CLIENT_H_ + +/** +* This file provides helper to implement an ivshmem client. It is used +* on the host to ask QEMU to send an interrupt to an ivshmem PCI device in a +* guest. QEMU also implements an ivshmem client similar to this one, they both +* connect to an ivshmem server. +* +* A standalone ivshmem client based on this file is provided for debug/test +* purposes. +*/ + +#include <limits.h> +#include <sys/select.h> + +#include "qemu/queue.h" + +/** +* Maximum number of notification vectors supported by the client +*/ +#define IVSHMEM_CLIENT_MAX_VECTORS 64 + +/** +* Structure storing a peer +*
contrib/ivshmem-client/ivshmem-client.h line 44
Quoted 10 lines
contrib/ivshmem-client/ivshmem-client.h new file +10
-0+* Each time a client connects to an ivshmem server, it is advertised to +* all connected clients through the unix socket. When our ivshmem +* client receives a notification, it creates a IvshmemClientPeer +* structure to store the infos of this peer. +* +* This structure is also used to store the information of our own +* client in (IvshmemClient)->local. +*/ +typedef struct IvshmemClientPeer { + QTAILQ_ENTRY(IvshmemClientPeer) next; /**< next in list*/
Needs space before */
contrib/ivshmem-client/ivshmem-client.h line 47
Quoted 3 lines
contrib/ivshmem-client/ivshmem-client.h new file +3
-0+long id;/**< the id of the peer */ +int vectors[IVSHMEM_CLIENT_MAX_VECTORS ];/**< one fd per vector */ +unsigned vectors_count;/**< number of vectors */
I would do just /* text */ here, otherewise people might think they have to copy this comment style.
contrib/ivshmem-client/ivshmem-client.h line 48
Quoted 1 line
contrib/ivshmem-client/ivshmem-client.h new file +1
-0+} IvshmemClientPeer;
an empty line wouldn't hurt here.
Quoted 5 lines
contrib/ivshmem-client/ivshmem-client.h new file +5
-0+QTAILQ_HEAD (IvshmemClientPeerList, IvshmemClientPeer); + +typedef struct IvshmemClientPeerList IvshmemClientPeerList ; +typedef struct IvshmemClient IvshmemClient ; +
PATCH v6 2/3 docs: update ivshmem device spec
In reply to David MarchandAdd some notes on the parts needed to use ivshmem devices: more specifically, explain the purpose of an ivshmem server and the basic concept to use the ivshmem devices in guests.
Move some parts of the documentation and re-organise it.
--- docs/specs/ivshmem_device_spec.txt | 124 +++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 31 deletions(-)
docs/specs/ivshmem_device_spec.txt +93 -31
@@ -2,30 +2,103 @@ Device Specification for Inter-VM shared memory device ------------------------------------------------------ -The Inter-VM shared memory device is designed to share a region of memory to -userspace in multiple virtual guests. The memory region does not belong to any -guest, but is a POSIX memory object on the host. Optionally, the device may -support sending interrupts to other guests sharing the same memory region. +The Inter-VM shared memory device is designed to share a memory region (created +on the host via the POSIX shared memory API) between multiple QEMU processes +running different guests. In order for all guests to be able to pick up the +shared memory area, it is modeled by QEMU as a PCI device exposing said memory +to the guest as a PCI BAR. +The memory region does not belong to any guest, but is a POSIX memory object on +the host. The host can access this shared memory if needed. + +The device also provides an optional communication mechanism between guests +sharing the same memory object. More details about that in the section 'Guest to +guest communication' section. The Inter-VM PCI device ----------------------- -*BARs* +From the VM point of view, the ivshmem PCI device supports three BARs. + +- BAR0 is a 1 Kbyte MMIO region to support registers and interrupts when MSI is + not used. +- BAR1 is used for MSI-X when it is enabled in the device. +- BAR2 is used to access the shared memory object. + +It is your choice how to use the device but you must choose between two +behaviors : + +- basically, if you only need the shared memory part, you will map BAR2. + This way, you have access to the shared memory in guest and can use it as you + see fit (memnic, for example, uses it in userland + http://dpdk.org/browse/memnic). + +- BAR0 and BAR1 are used to implement an optional communication mechanism + through interrupts in the guests. If you need an event mechanism between the + guests accessing the shared memory, you will most likely want to write a + kernel driver that will handle interrupts. See details in the section 'Guest + to guest communication' section. + +The behavior is chosen when starting your QEMU processes: +- no communication mechanism needed, the first QEMU to start creates the shared + memory on the host, subsequent QEMU processes will use it. + +- communication mechanism needed, an ivshmem server must be started before any + QEMU processes, then each QEMU process connects to the server unix socket. + +For more details on the QEMU ivshmem parameters, see qemu-doc documentation. + + +Guest to guest communication +---------------------------- + +This section details the communication mechanism between the guests accessing +the ivhsmem shared memory. -The device supports three BARs. BAR0 is a 1 Kbyte MMIO region to support -registers. BAR1 is used for MSI-X when it is enabled in the device. BAR2 is -used to map the shared memory object from the host. The size of BAR2 is -specified when the guest is started and must be a power of 2 in size. +*ivshmem server* -*Registers* +This server code is available in qemu.git/contrib/ivshmem-server. -The device currently supports 4 registers of 32-bits each. Registers -are used for synchronization between guests sharing the same memory object when -interrupts are supported (this requires using the shared memory server). +The server must be started on the host before any guest. +It creates a shared memory object then waits for clients to connect on a unix +socket. -The server assigns each VM an ID number and sends this ID number to the QEMU -process when the guest starts. +For each client (QEMU process) that connects to the server: +- the server assigns an ID for this client and sends this ID to him as the first + message, +- the server sends a fd to the shared memory object to this client, +- the server creates a new set of host eventfds associated to the new client and + sends this set to all already connected clients, +- finally, the server sends all the eventfds sets for all clients to the new + client. + +The server signals all clients when one of them disconnects. + +The client IDs are limited to 16 bits because of the current implementation (see +Doorbell register in 'PCI device registers' subsection). Hence only 65536 +clients are supported. + +All the file descriptors (fd to the shared memory, eventfds for each client) +are passed to clients using SCM_RIGHTS over the server unix socket. + +Apart from the current ivshmem implementation in QEMU, an ivshmem client has +been provided in qemu.git/contrib/ivshmem-client for debug. + +*QEMU as an ivshmem client* + +At initialisation, when creating the ivshmem device, QEMU gets its ID from the +server then makes it available through BAR0 IVPosition register for the VM to +use (see 'PCI device registers' subsection). +QEMU then uses the fd to the shared memory to map it to BAR2. +eventfds for all other clients received from the server are stored to implement +BAR0 Doorbell register (see 'PCI device registers' subsection). +Finally, eventfds assigned to this QEMU process are used to send interrupts in +this VM. + +*PCI device registers* + +From the VM point of view, the ivshmem PCI device supports 4 registers of +32-bits each. enum ivshmem_registers { IntrMask = 0,
@@ -49,8 +122,8 @@ bit to 0 and unmasked by setting the first bit to 1. IVPosition Register: The IVPosition register is read-only and reports the guest's ID number. The guest IDs are non-negative integers. When using the server, since the server is a separate process, the VM ID will only be set when -the device is ready (shared memory is received from the server and accessible via -the device). If the device is not ready, the IVPosition will return -1. +the device is ready (shared memory is received from the server and accessible +via the device). If the device is not ready, the IVPosition will return -1. Applications should ensure that they have a valid VM ID before accessing the shared memory.
@@ -59,8 +132,8 @@ Doorbell register. The doorbell register is 32-bits, logically divided into two 16-bit fields. The high 16-bits are the guest ID to interrupt and the low 16-bits are the interrupt vector to trigger. The semantics of the value written to the doorbell depends on whether the device is using MSI or a regular -pin-based interrupt. In short, MSI uses vectors while regular interrupts set the -status register. +pin-based interrupt. In short, MSI uses vectors while regular interrupts set +the status register. Regular Interrupts
@@ -71,7 +144,7 @@ interrupt in the destination guest. Message Signalled Interrupts -A ivshmem device may support multiple MSI vectors. If so, the lower 16-bits +An ivshmem device may support multiple MSI vectors. If so, the lower 16-bits written to the Doorbell register must be between 0 and the maximum number of vectors the guest supports. The lower 16 bits written to the doorbell is the MSI vector that will be raised in the destination guest. The number of MSI
@@ -83,14 +156,3 @@ interrupt itself should be communicated via the shared memory region. Devices supporting multiple MSI vectors can use different vectors to indicate different events have occurred. The semantics of interrupt vectors are left to the user's discretion. - - -Usage in the Guest ------------------- - -The shared memory device is intended to be used with the provided UIO driver. -Very little configuration is needed. The guest should map BAR0 to access the -registers (an array of 32-bit ints allows simple writing) and map BAR2 to -access the shared memory region itself. The size of the shared memory region -is specified when the guest (or shared memory server) is started. A guest may -map the whole shared memory region or only part of it.
Signature · 1 line
1.7.10.4
Re: [PATCH v6 2/3] docs: update ivshmem device spec
Quoted 38 lines · David Marchand
Add some notes on the parts needed to use ivshmem devices: more specifically, explain the purpose of an ivshmem server and the basic concept to use the ivshmem devices in guests.
Move some parts of the documentation and re-organise it.Signed-off-by David Marchand <[email protected]>Reviewed-by Claudio Fontana <[email protected]>Reviewed-by Stefan Hajnoczi <[email protected]>--- docs/specs/ivshmem_device_spec.txt | 124 +++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 31 deletions(-)docs/specs/ivshmem_device_spec.txt +11
-4@@ -2,30 +2,103 @@ Device Specification for Inter-VM shared memory device ------------------------------------------------------ -The Inter-VM shared memory device is designed to share a region of memory to -userspace in multiple virtual guests. The memory region does not belong to any -guest, but is a POSIX memory object on the host. Optionally, the device may -support sending interrupts to other guests sharing the same memory region. +The Inter-VM shared memory device is designed to share a memory region (created +on the host via the POSIX shared memory API) between multiple QEMU processes +running different guests. In order for all guests to be able to pick up the +shared memory area, it is modeled by QEMU as a PCI device exposing said memory +to the guest as a PCI BAR. +The memory region does not belong to any guest, but is a POSIX memory object on +the host. The host can access this shared memory if needed. + +The device also provides an optional communication mechanism between guests +sharing the same memory object. More details about that in the section 'Guest to +guest communication' section. The Inter-VM PCI device
docs/specs/ivshmem_device_spec.txt line 27
Quoted 10 lines
docs/specs/ivshmem_device_spec.txt +7
-1----------------------- -*BARs* +From the VM point of view, the ivshmem PCI device supports three BARs. + +- BAR0 is a 1 Kbyte MMIO region to support registers and interrupts when MSI is + not used. +- BAR1 is used for MSI-X when it is enabled in the device. +- BAR2 is used to access the shared memory object. +
BAR2 or resource 2?
Not the same if BAR1 is 64 bit.
Guests are using this already, right?
We can't change it?
Unfortunate since switching shared memory to BAR1 would have avoided the ambiguity.
Oh well, we don't want to break guests for such a minor gain.
And what happens if there's no MSI-X capability?
BAR1 unused?
docs/specs/ivshmem_device_spec.txt line 29
Quoted 2 lines
docs/specs/ivshmem_device_spec.txt +2
-0+It is your choice how to use the device but you must choose between two +behaviors :
Make this a separate chapter, this is not from VM POV anymore.
Quoted 12 lines
docs/specs/ivshmem_device_spec.txt +12
-0+ +- basically, if you only need the shared memory part, you will map BAR2. + This way, you have access to the shared memory in guest and can use it as you + see fit (memnic, for example, uses it in userland + http://dpdk.org/browse/memnic). + +- BAR0 and BAR1 are used to implement an optional communication mechanism + through interrupts in the guests. If you need an event mechanism between the + guests accessing the shared memory, you will most likely want to write a + kernel driver that will handle interrupts. See details in the section 'Guest + to guest communication' section. +
docs/specs/ivshmem_device_spec.txt line 51
Quoted 10 lines
docs/specs/ivshmem_device_spec.txt +10
-0+The behavior is chosen when starting your QEMU processes: +- no communication mechanism needed, the first QEMU to start creates the shared + memory on the host, subsequent QEMU processes will use it. + +- communication mechanism needed, an ivshmem server must be started before any + QEMU processes, then each QEMU process connects to the server unix socket. + +For more details on the QEMU ivshmem parameters, see qemu-doc documentation. + +
I know you did not start it but don't add more cases of two empty lines please.
docs/specs/ivshmem_device_spec.txt line 56
Quoted 5 lines
docs/specs/ivshmem_device_spec.txt +5
-0+Guest to guest communication +---------------------------- + +This section details the communication mechanism between the guests accessing +the ivhsmem shared memory.
In in fact, below text is QEMU to QEMU protocol.
There are 3 types of communication:
qemu to vm: e.g. pci registers
qemu to another ivshmem server/client: e.g. domain sockets vm to vm: using shared memory, interrupts (can be mediated by qemu)
Pls don't mix these up, seperate them in the documentation.
Quoted 106 lines
docs/specs/ivshmem_device_spec.txt +46
-26-The device supports three BARs. BAR0 is a 1 Kbyte MMIO region to support -registers. BAR1 is used for MSI-X when it is enabled in the device. BAR2 is -used to map the shared memory object from the host. The size of BAR2 is -specified when the guest is started and must be a power of 2 in size. +*ivshmem server* -*Registers* +This server code is available in qemu.git/contrib/ivshmem-server. -The device currently supports 4 registers of 32-bits each. Registers -are used for synchronization between guests sharing the same memory object when -interrupts are supported (this requires using the shared memory server). +The server must be started on the host before any guest. +It creates a shared memory object then waits for clients to connect on a unix +socket. -The server assigns each VM an ID number and sends this ID number to the QEMU -process when the guest starts. +For each client (QEMU process) that connects to the server: +- the server assigns an ID for this client and sends this ID to him as the first + message, +- the server sends a fd to the shared memory object to this client, +- the server creates a new set of host eventfds associated to the new client and + sends this set to all already connected clients, +- finally, the server sends all the eventfds sets for all clients to the new + client. + +The server signals all clients when one of them disconnects. + +The client IDs are limited to 16 bits because of the current implementation (see +Doorbell register in 'PCI device registers' subsection). Hence only 65536 +clients are supported. + +All the file descriptors (fd to the shared memory, eventfds for each client) +are passed to clients using SCM_RIGHTS over the server unix socket. + +Apart from the current ivshmem implementation in QEMU, an ivshmem client has +been provided in qemu.git/contrib/ivshmem-client for debug. + +*QEMU as an ivshmem client* + +At initialisation, when creating the ivshmem device, QEMU gets its ID from the +server then makes it available through BAR0 IVPosition register for the VM to +use (see 'PCI device registers' subsection). +QEMU then uses the fd to the shared memory to map it to BAR2. +eventfds for all other clients received from the server are stored to implement +BAR0 Doorbell register (see 'PCI device registers' subsection). +Finally, eventfds assigned to this QEMU process are used to send interrupts in +this VM. + +*PCI device registers* + +From the VM point of view, the ivshmem PCI device supports 4 registers of +32-bits each. enum ivshmem_registers { IntrMask = 0,@@ -49,8 +122,8 @@ bit to 0 and unmasked by setting the first bit to 1. IVPosition Register: The IVPosition register is read-only and reports the guest's ID number. The guest IDs are non-negative integers. When using the server, since the server is a separate process, the VM ID will only be set when -the device is ready (shared memory is received from the server and accessible via -the device). If the device is not ready, the IVPosition will return -1. +the device is ready (shared memory is received from the server and accessible +via the device). If the device is not ready, the IVPosition will return -1. Applications should ensure that they have a valid VM ID before accessing the shared memory.@@ -59,8 +132,8 @@ Doorbell register. The doorbell register is 32-bits, logically divided into two 16-bit fields. The high 16-bits are the guest ID to interrupt and the low 16-bits are the interrupt vector to trigger. The semantics of the value written to the doorbell depends on whether the device is using MSI or a regular -pin-based interrupt. In short, MSI uses vectors while regular interrupts set the -status register. +pin-based interrupt. In short, MSI uses vectors while regular interrupts set +the status register. Regular Interrupts@@ -71,7 +144,7 @@ interrupt in the destination guest. Message Signalled Interrupts -A ivshmem device may support multiple MSI vectors. If so, the lower 16-bits +An ivshmem device may support multiple MSI vectors. If so, the lower 16-bits written to the Doorbell register must be between 0 and the maximum number of vectors the guest supports. The lower 16 bits written to the doorbell is the MSI vector that will be raised in the destination guest. The number of MSI@@ -83,14 +156,3 @@ interrupt itself should be communicated via the shared memory region. Devices supporting multiple MSI vectors can use different vectors to indicate different events have occurred. The semantics of interrupt vectors are left to the user's discretion. - - -Usage in the Guest ------------------- - -The shared memory device is intended to be used with the provided UIO driver. -Very little configuration is needed. The guest should map BAR0 to access the -registers (an array of 32-bit ints allows simple writing) and map BAR2 to -access the shared memory region itself. The size of the shared memory region -is specified when the guest (or shared memory server) is started. A guest may -map the whole shared memory region or only part of it.Signature · 1 line
1.7.10.4
PATCH v6 3/3 ivshmem: add check on protocol version in QEMU
In reply to David MarchandSend a protocol version as the first message from server, clients must close communication if they don't support this protocol version.
Older QEMUs should be fine with this change in the protocol since they overrides their own vm_id on reception of an id associated to no eventfd.
--- contrib/ivshmem-client/ivshmem-client.c | 13 ++++++++++--- contrib/ivshmem-client/ivshmem-client.h | 1 + contrib/ivshmem-server/ivshmem-server.c | 9 +++++++++ contrib/ivshmem-server/ivshmem-server.h | 1 + docs/specs/ivshmem_device_spec.txt | 9 ++++++--- hw/misc/ivshmem.c | 27 +++++++++++++++++++++++++-- include/hw/misc/ivshmem.h | 17 +++++++++++++++++ 7 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 include/hw/misc/ivshmem.h
contrib/ivshmem-client/ivshmem-client.c +10 -3
@@ -201,10 +201,17 @@ ivshmem_client_connect(IvshmemClient *client) goto err_close; } -/* first, we expect our index + a fd == -1 */ +/* first, we expect a protocol version */ +if (ivshmem_client_read_one_msg (client, &tmp, &fd) <0 || + (tmp !=IVSHMEM_PROTOCOL_VERSION ) || fd !=-1 ) { +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server\n" ); + goto err_close; + } + +/* then, we expect our index + a fd == -1 */ if (ivshmem_client_read_one_msg (client, &client->local.id, &fd) <0 || client->local.id <0 || fd !=-1 ) { -IVSHMEM_CLIENT_DEBUG (client,"cannot read from server\n" ); +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (2)\n" ); goto err_close; }IVSHMEM_CLIENT_DEBUG (client,"our_id=%ld\n" , client->local.id);
@@ -216,7 +223,7 @@ ivshmem_client_connect(IvshmemClient *client)if (fd >=0 ) {close (fd); } -IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (2)\n" ); +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (3)\n" ); goto err_close; } client->shm_fd = fd;
contrib/ivshmem-client/ivshmem-client.h +1 -0
@@ -23,6 +23,7 @@#include <sys/select.h> #include "qemu/queue.h" +#include "hw/misc/ivshmem.h" /** * Maximum number of notification vectors supported by the client
contrib/ivshmem-server/ivshmem-server.c +9 -0
@@ -99,6 +99,15 @@ ivshmem_server_send_initial_info(IvshmemServer *server, IvshmemServerPeer *peer) {int ret; +/* send our protocol version first */ + ret =ivshmem_server_send_one_msg (peer->sock_fd,IVSHMEM_PROTOCOL_VERSION , +-1 ); +if (ret <0 ) { +IVSHMEM_SERVER_DEBUG (server,"cannot send version: %s\n" , +strerror (errno)); +return -1 ; + } +/* send the peer id to the client */ ret =ivshmem_server_send_one_msg (peer->sock_fd, peer->id,-1 );if (ret <0 ) {
contrib/ivshmem-server/ivshmem-server.h +1 -0
@@ -30,6 +30,7 @@#include <sys/select.h> #include "qemu/queue.h" +#include "hw/misc/ivshmem.h" /** * Maximum number of notification vectors supported by the server
docs/specs/ivshmem_device_spec.txt +6 -3
@@ -64,6 +64,8 @@ It creates a shared memory object then waits for clients to connect on a unix socket. For each client (QEMU process) that connects to the server: +- the server sends a protocol version, if client does not support it, the client + closes the communication, - the server assigns an ID for this client and sends this ID to him as the first message, - the server sends a fd to the shared memory object to this client,
@@ -86,9 +88,10 @@ been provided in qemu.git/contrib/ivshmem-client for debug. *QEMU as an ivshmem client* -At initialisation, when creating the ivshmem device, QEMU gets its ID from the -server then makes it available through BAR0 IVPosition register for the VM to -use (see 'PCI device registers' subsection). +At initialisation, when creating the ivshmem device, QEMU first receives a +protocol version and closes communication with server if it does not match. +Then, QEMU gets its ID from the server then makes it available through BAR0 +IVPosition register for the VM to use (see 'PCI device registers' subsection). QEMU then uses the fd to the shared memory to map it to BAR2. eventfds for all other clients received from the server are stored to implement BAR0 Doorbell register (see 'PCI device registers' subsection).
hw/misc/ivshmem.c +25 -2
@@ -26,6 +26,8 @@#include "qemu/event_notifier.h" #include "sysemu/char.h" +#include "hw/misc/ivshmem.h" +#include <sys/mman.h> #include <sys/types.h>
@@ -528,6 +530,27 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) } } +static void ivshmem_check_version (void *opaque,const uint8_t * buf,int flags) +{ +IVShmemState *s = opaque; +int tmp; +long version; + +memcpy (&version, buf,sizeof (long )); + tmp =qemu_chr_fe_get_msgfd (s->server_chr); +if (tmp !=-1 || version !=IVSHMEM_PROTOCOL_VERSION ) { +fprintf (stderr,"incompatible version, you are connecting to a ivshmem-" +"server using a different protocol please check your setup\n" ); +qemu_chr_delete (s->server_chr); + s->server_chr =NULL ; +return ; + } + +IVSHMEM_DPRINTF ("version check ok, switch to real chardev handler\n" ); +qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, ivshmem_read, + ivshmem_event, s); +} +/* Select the MSI-X vectors used by device. * ivshmem maps events to vectors statically, so * we just enable all vectors on init and after reset. */
@@ -742,8 +765,8 @@ static int pci_ivshmem_init(PCIDevice *dev) s->eventfd_chr =g_malloc0 (s->vectors *sizeof (CharDriverState *)); -qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, ivshmem_read, - ivshmem_event, s); +qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, + ivshmem_check_version, ivshmem_event, s); }else {/* just map the file immediately, we're not using a server */ int fd;
include/hw/misc/ivshmem.h new file +17 -0
@@ -0,0 +1,17 @@ +/* +* Copyright 6WIND S.A., 2014 +* +* This work is licensed under the terms of the GNU GPL, version 2 or +* (at your option) any later version. See the COPYING file in the +* top-level directory. +*/ + +#ifndef _IVSHMEM_H_ +#define _IVSHMEM_H_ + +/** +* Protocol version +*/ +#define IVSHMEM_PROTOCOL_VERSION 0x0 + +#endif
Signature · 1 line
1.7.10.4
Re: [PATCH v6 3/3] ivshmem: add check on protocol version in QEMU
Quoted 2 lines · David Marchand
Send a protocol version as the first message from server, clients must close communication if they don't support this protocol version.
What's the motivation here?
This is at best a way to break all clients if an incompatible change in the server is made.
Would not it be better to send a bitmap, or a list of supported versions, so it's possible to write servers compatible with multiple clients?
Quoted 1 line
Older QEMUs should be fine with this change in the protocol since they overrides
they override
Quoted 1 line
their own
vm_idon reception of an id associated to no eventfd.
associated with?
I don't understand how compatibility works exactly, a bit more explanation in code comments would be nice. In particular new client won't work with old server, will it?
Quoted 194 lines
Signed-off-by David Marchand <[email protected]>--- contrib/ivshmem-client/ivshmem-client.c | 13 ++++++++++--- contrib/ivshmem-client/ivshmem-client.h | 1 + contrib/ivshmem-server/ivshmem-server.c | 9 +++++++++ contrib/ivshmem-server/ivshmem-server.h | 1 + docs/specs/ivshmem_device_spec.txt | 9 ++++++--- hw/misc/ivshmem.c | 27 +++++++++++++++++++++++++-- include/hw/misc/ivshmem.h | 17 +++++++++++++++++ 7 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 include/hw/misc/ivshmem.hcontrib/ivshmem-client/ivshmem-client.c +10
-3@@ -201,10 +201,17 @@ ivshmem_client_connect(IvshmemClient *client) goto err_close; } -/* first, we expect our index + a fd == -1 */ +/* first, we expect a protocol version */ +if (ivshmem_client_read_one_msg (client, &tmp, &fd) <0 || + (tmp !=IVSHMEM_PROTOCOL_VERSION ) || fd !=-1 ) { +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server\n" ); + goto err_close; + } + +/* then, we expect our index + a fd == -1 */ if (ivshmem_client_read_one_msg (client, &client->local.id, &fd) <0 || client->local.id <0 || fd !=-1 ) { -IVSHMEM_CLIENT_DEBUG (client,"cannot read from server\n" ); +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (2)\n" ); goto err_close; }IVSHMEM_CLIENT_DEBUG (client,"our_id=%ld\n" , client->local.id);@@ -216,7 +223,7 @@ ivshmem_client_connect(IvshmemClient *client)if (fd >=0 ) {close (fd); } -IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (2)\n" ); +IVSHMEM_CLIENT_DEBUG (client,"cannot read from server (3)\n" ); goto err_close; } client->shm_fd = fd;contrib/ivshmem-client/ivshmem-client.h +1
-0@@ -23,6 +23,7 @@#include <sys/select.h> #include "qemu/queue.h" +#include "hw/misc/ivshmem.h" /** * Maximum number of notification vectors supported by the client contrib/ivshmem-server/ivshmem-server.c +9
-0@@ -99,6 +99,15 @@ ivshmem_server_send_initial_info(IvshmemServer *server, IvshmemServerPeer *peer) {int ret; +/* send our protocol version first */ + ret =ivshmem_server_send_one_msg (peer->sock_fd,IVSHMEM_PROTOCOL_VERSION , +-1 ); +if (ret <0 ) { +IVSHMEM_SERVER_DEBUG (server,"cannot send version: %s\n" , +strerror (errno)); +return -1 ; + } +/* send the peer id to the client */ ret =ivshmem_server_send_one_msg (peer->sock_fd, peer->id,-1 );if (ret <0 ) {contrib/ivshmem-server/ivshmem-server.h +1
-0@@ -30,6 +30,7 @@#include <sys/select.h> #include "qemu/queue.h" +#include "hw/misc/ivshmem.h" /** * Maximum number of notification vectors supported by the server docs/specs/ivshmem_device_spec.txt +6
-3@@ -64,6 +64,8 @@ It creates a shared memory object then waits for clients to connect on a unix socket. For each client (QEMU process) that connects to the server: +- the server sends a protocol version, if client does not support it, the client + closes the communication, - the server assigns an ID for this client and sends this ID to him as the first message, - the server sends a fd to the shared memory object to this client,@@ -86,9 +88,10 @@ been provided in qemu.git/contrib/ivshmem-client for debug. *QEMU as an ivshmem client* -At initialisation, when creating the ivshmem device, QEMU gets its ID from the -server then makes it available through BAR0 IVPosition register for the VM to -use (see 'PCI device registers' subsection). +At initialisation, when creating the ivshmem device, QEMU first receives a +protocol version and closes communication with server if it does not match. +Then, QEMU gets its ID from the server then makes it available through BAR0 +IVPosition register for the VM to use (see 'PCI device registers' subsection). QEMU then uses the fd to the shared memory to map it to BAR2. eventfds for all other clients received from the server are stored to implement BAR0 Doorbell register (see 'PCI device registers' subsection).hw/misc/ivshmem.c +25
-2@@ -26,6 +26,8 @@#include "qemu/event_notifier.h" #include "sysemu/char.h" +#include "hw/misc/ivshmem.h" +#include <sys/mman.h> #include <sys/types.h> @@ -528,6 +530,27 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags) } } +static void ivshmem_check_version (void *opaque,const uint8_t * buf,int flags) +{ +IVShmemState *s = opaque; +int tmp; +long version; + +memcpy (&version, buf,sizeof (long )); + tmp =qemu_chr_fe_get_msgfd (s->server_chr); +if (tmp !=-1 || version !=IVSHMEM_PROTOCOL_VERSION ) { +fprintf (stderr,"incompatible version, you are connecting to a ivshmem-" +"server using a different protocol please check your setup\n" ); +qemu_chr_delete (s->server_chr); + s->server_chr =NULL ; +return ; + } + +IVSHMEM_DPRINTF ("version check ok, switch to real chardev handler\n" ); +qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, ivshmem_read, + ivshmem_event, s); +} +/* Select the MSI-X vectors used by device. * ivshmem maps events to vectors statically, so * we just enable all vectors on init and after reset. */ @@ -742,8 +765,8 @@ static int pci_ivshmem_init(PCIDevice *dev) s->eventfd_chr =g_malloc0 (s->vectors *sizeof (CharDriverState *)); -qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, ivshmem_read, - ivshmem_event, s); +qemu_chr_add_handlers (s->server_chr, ivshmem_can_receive, + ivshmem_check_version, ivshmem_event, s); }else {/* just map the file immediately, we're not using a server */ int fd;include/hw/misc/ivshmem.h new file +17
-0@@ -0,0 +1,17 @@ +/* +* Copyright 6WIND S.A., 2014 +* +* This work is licensed under the terms of the GNU GPL, version 2 or +* (at your option) any later version. See the COPYING file in the +* top-level directory. +*/ + +#ifndef _IVSHMEM_H_ +#define _IVSHMEM_H_ + +/** +* Protocol version +*/ +#define IVSHMEM_PROTOCOL_VERSION 0x0 + +#endif Signature · 1 line
1.7.10.4
Re: [PATCH v6 3/3] ivshmem: add check on protocol version in QEMU
Quoted 10 lines · Michael S. Tsirkin
Quoted 2 lines · David Marchand
Send a protocol version as the first message from server, clients must close communication if they don't support this protocol version.
What's the motivation here?
This is at best a way to break all clients if an incompatible change in the server is made.
Would not it be better to send a bitmap, or a list of supported versions, so it's possible to write servers compatible with multiple clients?
I'm not sure a full-fledged feature negotiation system is needed. The ivshmem protocol is local to the host and all participants are under control of the administrator.
I suggested a protocol version to protect against misconfiguration. For example, building QEMU from source but talking to an outdated ivhsmem server that is still running from before.
Remember that ivshmem-server and QEMU are shipped together by the distro. So in 99% of the cases they will have the same version anyway. But we want to protect against rare misconfiguration that break things (user mixing and matching incompatible software).
The only reason I can see for fancy negotiation is to make life easier for proprietary third-party software, which I don't care about or like.
Stefan
Re: [PATCH v6 3/3] ivshmem: add check on protocol version in QEMU
Quoted 4 lines · Stefan Hajnoczi
I'm not sure a full-fledged feature negotiation system is needed. The ivshmem protocol is local to the host and all participants are under control of the administrator.
Quoted 8 lines
I suggested a protocol version to protect against misconfiguration. For example, building QEMU from source but talking to an outdated ivhsmem server that is still running from before.
Remember that ivshmem-server and QEMU are shipped together by the distro. So in 99% of the cases they will have the same version anyway. But we want to protect against rare misconfiguration that break things (user mixing and matching incompatible software).
Ok, so how about keeping with this simple mechanism at the moment ?
If this versionning system is too limited in the future, I think we will need a global rework on the protocol, anyway.
Signature · 1 line
David Marchand