RE: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-16 Thread Thanos Makatos


> -Original Message-
> From: John Johnson 
> Sent: 16 February 2022 02:10
> To: Thanos Makatos 
> Cc: qemu-devel@nongnu.org
> Subject: Re: [RFC v4 08/21] vfio-user: define socket receive functions
> 
> 
> 
> > On Feb 15, 2022, at 6:50 AM, Thanos Makatos
>  wrote:
> >
> >>>
> >
> > On second thought, should we dump the entire header in case of such errors?
> If not by default then at least in debug builds?
> 
> 
>   I was thinking of adding qemu tracepoints in the recv and send paths
> for your other debug rfe.  Maybe I’ll add one set for the normal path that
> prints an abbreviated header, and another set for the error case that prints
> the whole header.  Would that work?

Yes that would be great.


Re: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-15 Thread John Johnson


> On Feb 15, 2022, at 6:50 AM, Thanos Makatos  
> wrote:
> 
>>> 
> 
> On second thought, should we dump the entire header in case of such errors? 
> If not by default then at least in debug builds?


I was thinking of adding qemu tracepoints in the recv and send paths
for your other debug rfe.  Maybe I’ll add one set for the normal path that
prints an abbreviated header, and another set for the error case that prints
the whole header.  Would that work?

JJ




RE: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-15 Thread Thanos Makatos
> > +/*
> > + * Receive and process one incoming message.
> > + *
> > + * For replies, find matching outgoing request and wake any waiters.
> > + * For requests, queue in incoming list and run request BH.
> > + */
> > +static int vfio_user_recv_one(VFIOProxy *proxy)
> > +{
> > +VFIOUserMsg *msg = NULL;
> > +g_autofree int *fdp = NULL;
> > +VFIOUserFDs *reqfds;
> > +VFIOUserHdr hdr;
> > +struct iovec iov = {
> > +.iov_base = ,
> > +.iov_len = sizeof(hdr),
> > +};
> > +bool isreply = false;
> > +int i, ret;
> > +size_t msgleft, numfds = 0;
> > +char *data = NULL;
> > +char *buf = NULL;
> > +Error *local_err = NULL;
> > +
> > +/*
> > + * Read header
> > + */
> > +ret = qio_channel_readv_full(proxy->ioc, , 1, , ,
> > + _err);
> > +if (ret == QIO_CHANNEL_ERR_BLOCK) {
> > +return ret;
> > +}
> > +if (ret <= 0) {
> > +/* read error or other side closed connection */
> > +if (ret == 0) {
> > +error_setg(_err, "vfio_user_recv server closed socket");
> > +} else {
> > +error_prepend(_err, "vfio_user_recv");
> > +}
> > +goto fatal;
> > +}
> > +if (ret < sizeof(msg)) {
> > +error_setg(_err, "vfio_user_recv short read of header");
> > +goto fatal;
> > +}
> 
> Print received size for debug purposes?
> 
> > +
> > +/*
> > + * Validate header
> > + */
> > +if (hdr.size < sizeof(VFIOUserHdr)) {
> > +error_setg(_err, "vfio_user_recv bad header size");
> > +goto fatal;
> > +}
> 
> Print header size?
> 
> > +switch (hdr.flags & VFIO_USER_TYPE) {
> > +case VFIO_USER_REQUEST:
> > +isreply = false;
> > +break;
> > +case VFIO_USER_REPLY:
> > +isreply = true;
> > +break;
> > +default:
> > +error_setg(_err, "vfio_user_recv unknown message type");
> > +goto fatal;
> > +}
> 
> Print message type?
> 
> > +
> > +/*
> > + * For replies, find the matching pending request.
> > + * For requests, reap incoming FDs.
> > + */
> > +if (isreply) {
> > +QTAILQ_FOREACH(msg, >pending, next) {
> > +if (hdr.id == msg->id) {
> > +break;
> > +}
> > +}
> > +if (msg == NULL) {
> > +error_setg(_err, "vfio_user_recv unexpected reply");
> > +goto err;
> > +}
> > +QTAILQ_REMOVE(>pending, msg, next);
> > +
> > +/*
> > + * Process any received FDs
> > + */
> > +if (numfds != 0) {
> > +if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
> > +error_setg(_err, "vfio_user_recv unexpected FDs");
> > +goto err;
> > +}
> > +msg->fds->recv_fds = numfds;
> > +memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
> > +}
> > +} else {
> > +if (numfds != 0) {
> > +reqfds = vfio_user_getfds(numfds);
> > +memcpy(reqfds->fds, fdp, numfds * sizeof(int));
> > +} else {
> > +reqfds = NULL;
> > +}
> > +}
> > +
> > +/*
> > + * Put the whole message into a single buffer.
> > + */
> > +if (isreply) {
> > +if (hdr.size > msg->rsize) {
> > +error_setg(_err,
> > +   "vfio_user_recv reply larger than recv buffer");
> > +goto err;
> > +}
> 
> Print hdr.size and msg->rsize?
> 
> > +*msg->hdr = hdr;
> > +data = (char *)msg->hdr + sizeof(hdr);
> > +} else {
> > +if (hdr.size > max_xfer_size) {
> > +error_setg(_err, "vfio_user_recv request larger than 
> > max");
> > +goto err;
> > +}
> 
> Print hdr.size?

On second thought, should we dump the entire header in case of such errors? If 
not by default then at least in debug builds?


RE: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-15 Thread Thanos Makatos
> -Original Message-
> From: Qemu-devel  bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of John
> Johnson
> Sent: 12 January 2022 00:44
> To: qemu-devel@nongnu.org
> Subject: [RFC v4 08/21] vfio-user: define socket receive functions
> 
> Add infrastructure needed to receive incoming messages
> 
> Signed-off-by: John G Johnson 
> Signed-off-by: Elena Ufimtseva 
> Signed-off-by: Jagannathan Raman 
> ---
>  hw/vfio/user-protocol.h |  54 
>  hw/vfio/user.h  |   6 +
>  hw/vfio/pci.c   |   6 +
>  hw/vfio/user.c  | 327
> 
>  MAINTAINERS |   1 +
>  5 files changed, 394 insertions(+)
>  create mode 100644 hw/vfio/user-protocol.h
> 
> diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h
> new file mode 100644
> index 000..d23877c
> --- /dev/null
> +++ b/hw/vfio/user-protocol.h
> @@ -0,0 +1,54 @@
> +#ifndef VFIO_USER_PROTOCOL_H
> +#define VFIO_USER_PROTOCOL_H
> +
> +/*
> + * vfio protocol over a UNIX socket.
> + *
> + * Copyright © 2018, 2021 Oracle and/or its affiliates.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + * Each message has a standard header that describes the command
> + * being sent, which is almost always a VFIO ioctl().
> + *
> + * The header may be followed by command-specific data, such as the
> + * region and offset info for read and write commands.
> + */
> +
> +typedef struct {
> +uint16_t id;
> +uint16_t command;
> +uint32_t size;
> +uint32_t flags;
> +uint32_t error_reply;
> +} VFIOUserHdr;
> +
> +/* VFIOUserHdr commands */
> +enum vfio_user_command {
> +VFIO_USER_VERSION   = 1,
> +VFIO_USER_DMA_MAP   = 2,
> +VFIO_USER_DMA_UNMAP = 3,
> +VFIO_USER_DEVICE_GET_INFO   = 4,
> +VFIO_USER_DEVICE_GET_REGION_INFO= 5,
> +VFIO_USER_DEVICE_GET_REGION_IO_FDS  = 6,
> +VFIO_USER_DEVICE_GET_IRQ_INFO   = 7,
> +VFIO_USER_DEVICE_SET_IRQS   = 8,
> +VFIO_USER_REGION_READ   = 9,
> +VFIO_USER_REGION_WRITE  = 10,
> +VFIO_USER_DMA_READ  = 11,
> +VFIO_USER_DMA_WRITE = 12,
> +VFIO_USER_DEVICE_RESET  = 13,
> +VFIO_USER_DIRTY_PAGES   = 14,
> +VFIO_USER_MAX,
> +};
> +
> +/* VFIOUserHdr flags */
> +#define VFIO_USER_REQUEST   0x0
> +#define VFIO_USER_REPLY 0x1
> +#define VFIO_USER_TYPE  0xF
> +
> +#define VFIO_USER_NO_REPLY  0x10
> +#define VFIO_USER_ERROR 0x20
> +
> +#endif /* VFIO_USER_PROTOCOL_H */
> diff --git a/hw/vfio/user.h b/hw/vfio/user.h
> index da92862..72eefa7 100644
> --- a/hw/vfio/user.h
> +++ b/hw/vfio/user.h
> @@ -11,6 +11,8 @@
>   *
>   */
> 
> +#include "user-protocol.h"
> +
>  typedef struct {
>  int send_fds;
>  int recv_fds;
> @@ -27,6 +29,7 @@ enum msg_type {
> 
>  typedef struct VFIOUserMsg {
>  QTAILQ_ENTRY(VFIOUserMsg) next;
> +VFIOUserHdr *hdr;
>  VFIOUserFDs *fds;
>  uint32_t rsize;
>  uint32_t id;
> @@ -74,5 +77,8 @@ typedef struct VFIOProxy {
> 
>  VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
>  void vfio_user_disconnect(VFIOProxy *proxy);
> +void vfio_user_set_handler(VFIODevice *vbasedev,
> +   void (*handler)(void *opaque, VFIOUserMsg *msg),
> +   void *reqarg);
> 
>  #endif /* VFIO_USER_H */
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 9fd7c07..0de915d 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -3386,6 +3386,11 @@ type_init(register_vfio_pci_dev_type)
>   * vfio-user routines.
>   */
> 
> +static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg)
> +{
> +
> +}
> +
>  /*
>   * Emulated devices don't use host hot reset
>   */
> @@ -3432,6 +3437,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev,
> Error **errp)
>  return;
>  }
>  vbasedev->proxy = proxy;
> +vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
> 
>  vbasedev->name = g_strdup_printf("VFIO user <%s>", udev->sock_name);
>  vbasedev->dev = DEVICE(vdev);
> diff --git a/hw/vfio/user.c b/hw/vfio/user.c
> index c843f90..e1dfd5d 100644
> --- a/hw/vfio/user.c
> +++ b/hw/vfio/user.c
> @@ -25,10 +25,26 @@
>  #include "sysemu/iothread.h"
>  #include "user.h"
> 
> +static uint64_t max_xfer_s

Re: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-06 Thread John Johnson


> On Feb 4, 2022, at 4:42 AM, Thanos Makatos  wrote:
> 
>> -Original Message-
>> From: Qemu-devel > bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of Thanos
>> Makatos
>> Sent: 03 February 2022 21:54
>> To: John Johnson ; qemu-devel@nongnu.org
>> Subject: RE: [RFC v4 08/21] vfio-user: define socket receive functions
>> 
>> 
>> 
>>> -Original Message-
>>> From: Qemu-devel >> bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of John
>>> Johnson
>>> Sent: 12 January 2022 00:44
>>> To: qemu-devel@nongnu.org
>>> Subject: [RFC v4 08/21] vfio-user: define socket receive functions
>>> 
>>> +}
>>> +
>>> +msgleft = hdr.size - sizeof(hdr);
>>> +while (msgleft > 0) {
>>> +ret = qio_channel_read(proxy->ioc, data, msgleft, _err);
>>> +
>>> +/* error or would block */
>>> +if (ret < 0) {
>>> +goto fatal;
>>> +}
>> 
>> IIUC qio_channel_read() ends up calling qio_channel_socket_readv() which can
>> return QIO_CHANNEL_ERR_BLOCK (-2). The if will be taken so local_err is NULL
>> and that causes a segfault when error_report_err(local_err) is called before
>> returning from this function.
> 
> In fact, don't we need to continue if qio_channel_read() returns 
> QIO_CHANNEL_ERR_BLOCK and only fail if it returns -1?
> 
>> 
>>> +
>>> +msgleft -= ret;
>>> +data += ret;
>>> +}
>>> +


I can’t loop indefinitely, as a malicious server could cause the 
receiver to loop
continuously if it sends a packet with a header length greater than the packet 
length.

If large messages are being fragmented by the socket code, then I think 
I’ll need
to change the packet parser to able to reassemble them.

JJ



RE: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-04 Thread Thanos Makatos
> -Original Message-
> From: Qemu-devel  bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of Thanos
> Makatos
> Sent: 03 February 2022 21:54
> To: John Johnson ; qemu-devel@nongnu.org
> Subject: RE: [RFC v4 08/21] vfio-user: define socket receive functions
> 
> 
> 
> > -Original Message-
> > From: Qemu-devel  > bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of John
> > Johnson
> > Sent: 12 January 2022 00:44
> > To: qemu-devel@nongnu.org
> > Subject: [RFC v4 08/21] vfio-user: define socket receive functions
> >
> > Add infrastructure needed to receive incoming messages
> >
> > Signed-off-by: John G Johnson 
> > Signed-off-by: Elena Ufimtseva 
> > Signed-off-by: Jagannathan Raman 
> > ---
> >  hw/vfio/user-protocol.h |  54 
> >  hw/vfio/user.h  |   6 +
> >  hw/vfio/pci.c   |   6 +
> >  hw/vfio/user.c  | 327
> > 
> >  MAINTAINERS |   1 +
> >  5 files changed, 394 insertions(+)
> >  create mode 100644 hw/vfio/user-protocol.h
> >
> > diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h
> > new file mode 100644
> > index 000..d23877c
> > --- /dev/null
> > +++ b/hw/vfio/user-protocol.h
> > @@ -0,0 +1,54 @@
> > +#ifndef VFIO_USER_PROTOCOL_H
> > +#define VFIO_USER_PROTOCOL_H
> > +
> > +/*
> > + * vfio protocol over a UNIX socket.
> > + *
> > + * Copyright © 2018, 2021 Oracle and/or its affiliates.
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2.  See
> > + * the COPYING file in the top-level directory.
> > + *
> > + * Each message has a standard header that describes the command
> > + * being sent, which is almost always a VFIO ioctl().
> > + *
> > + * The header may be followed by command-specific data, such as the
> > + * region and offset info for read and write commands.
> > + */
> > +
> > +typedef struct {
> > +uint16_t id;
> > +uint16_t command;
> > +uint32_t size;
> > +uint32_t flags;
> > +uint32_t error_reply;
> > +} VFIOUserHdr;
> > +
> > +/* VFIOUserHdr commands */
> > +enum vfio_user_command {
> > +VFIO_USER_VERSION   = 1,
> > +VFIO_USER_DMA_MAP   = 2,
> > +VFIO_USER_DMA_UNMAP = 3,
> > +VFIO_USER_DEVICE_GET_INFO   = 4,
> > +VFIO_USER_DEVICE_GET_REGION_INFO= 5,
> > +VFIO_USER_DEVICE_GET_REGION_IO_FDS  = 6,
> > +VFIO_USER_DEVICE_GET_IRQ_INFO   = 7,
> > +VFIO_USER_DEVICE_SET_IRQS   = 8,
> > +VFIO_USER_REGION_READ   = 9,
> > +VFIO_USER_REGION_WRITE  = 10,
> > +VFIO_USER_DMA_READ  = 11,
> > +VFIO_USER_DMA_WRITE = 12,
> > +VFIO_USER_DEVICE_RESET  = 13,
> > +VFIO_USER_DIRTY_PAGES   = 14,
> > +VFIO_USER_MAX,
> > +};
> > +
> > +/* VFIOUserHdr flags */
> > +#define VFIO_USER_REQUEST   0x0
> > +#define VFIO_USER_REPLY 0x1
> > +#define VFIO_USER_TYPE  0xF
> > +
> > +#define VFIO_USER_NO_REPLY  0x10
> > +#define VFIO_USER_ERROR 0x20
> > +
> > +#endif /* VFIO_USER_PROTOCOL_H */
> > diff --git a/hw/vfio/user.h b/hw/vfio/user.h
> > index da92862..72eefa7 100644
> > --- a/hw/vfio/user.h
> > +++ b/hw/vfio/user.h
> > @@ -11,6 +11,8 @@
> >   *
> >   */
> >
> > +#include "user-protocol.h"
> > +
> >  typedef struct {
> >  int send_fds;
> >  int recv_fds;
> > @@ -27,6 +29,7 @@ enum msg_type {
> >
> >  typedef struct VFIOUserMsg {
> >  QTAILQ_ENTRY(VFIOUserMsg) next;
> > +VFIOUserHdr *hdr;
> >  VFIOUserFDs *fds;
> >  uint32_t rsize;
> >  uint32_t id;
> > @@ -74,5 +77,8 @@ typedef struct VFIOProxy {
> >
> >  VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
> >  void vfio_user_disconnect(VFIOProxy *proxy);
> > +void vfio_user_set_handler(VFIODevice *vbasedev,
> > +   void (*handler)(void *opaque, VFIOUserMsg *msg),
> > +   void *reqarg);
> >
> >  #endif /* VFIO_USER_H */
> > diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> > index 9fd7c07..0de915d 100644
> > --- a/hw/vfio/pci.c
> > +++ b/hw/vfio/pci.c
> > @@ -3386,6 +3386,11 @@ type_init(register_vfio_pci_dev_type)
> &g

RE: [RFC v4 08/21] vfio-user: define socket receive functions

2022-02-03 Thread Thanos Makatos


> -Original Message-
> From: Qemu-devel  bounces+thanos.makatos=nutanix@nongnu.org> On Behalf Of John
> Johnson
> Sent: 12 January 2022 00:44
> To: qemu-devel@nongnu.org
> Subject: [RFC v4 08/21] vfio-user: define socket receive functions
> 
> Add infrastructure needed to receive incoming messages
> 
> Signed-off-by: John G Johnson 
> Signed-off-by: Elena Ufimtseva 
> Signed-off-by: Jagannathan Raman 
> ---
>  hw/vfio/user-protocol.h |  54 
>  hw/vfio/user.h  |   6 +
>  hw/vfio/pci.c   |   6 +
>  hw/vfio/user.c  | 327
> 
>  MAINTAINERS |   1 +
>  5 files changed, 394 insertions(+)
>  create mode 100644 hw/vfio/user-protocol.h
> 
> diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h
> new file mode 100644
> index 000..d23877c
> --- /dev/null
> +++ b/hw/vfio/user-protocol.h
> @@ -0,0 +1,54 @@
> +#ifndef VFIO_USER_PROTOCOL_H
> +#define VFIO_USER_PROTOCOL_H
> +
> +/*
> + * vfio protocol over a UNIX socket.
> + *
> + * Copyright © 2018, 2021 Oracle and/or its affiliates.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + * Each message has a standard header that describes the command
> + * being sent, which is almost always a VFIO ioctl().
> + *
> + * The header may be followed by command-specific data, such as the
> + * region and offset info for read and write commands.
> + */
> +
> +typedef struct {
> +uint16_t id;
> +uint16_t command;
> +uint32_t size;
> +uint32_t flags;
> +uint32_t error_reply;
> +} VFIOUserHdr;
> +
> +/* VFIOUserHdr commands */
> +enum vfio_user_command {
> +VFIO_USER_VERSION   = 1,
> +VFIO_USER_DMA_MAP   = 2,
> +VFIO_USER_DMA_UNMAP = 3,
> +VFIO_USER_DEVICE_GET_INFO   = 4,
> +VFIO_USER_DEVICE_GET_REGION_INFO= 5,
> +VFIO_USER_DEVICE_GET_REGION_IO_FDS  = 6,
> +VFIO_USER_DEVICE_GET_IRQ_INFO   = 7,
> +VFIO_USER_DEVICE_SET_IRQS   = 8,
> +VFIO_USER_REGION_READ   = 9,
> +VFIO_USER_REGION_WRITE  = 10,
> +VFIO_USER_DMA_READ  = 11,
> +VFIO_USER_DMA_WRITE = 12,
> +VFIO_USER_DEVICE_RESET  = 13,
> +VFIO_USER_DIRTY_PAGES   = 14,
> +VFIO_USER_MAX,
> +};
> +
> +/* VFIOUserHdr flags */
> +#define VFIO_USER_REQUEST   0x0
> +#define VFIO_USER_REPLY 0x1
> +#define VFIO_USER_TYPE  0xF
> +
> +#define VFIO_USER_NO_REPLY  0x10
> +#define VFIO_USER_ERROR 0x20
> +
> +#endif /* VFIO_USER_PROTOCOL_H */
> diff --git a/hw/vfio/user.h b/hw/vfio/user.h
> index da92862..72eefa7 100644
> --- a/hw/vfio/user.h
> +++ b/hw/vfio/user.h
> @@ -11,6 +11,8 @@
>   *
>   */
> 
> +#include "user-protocol.h"
> +
>  typedef struct {
>  int send_fds;
>  int recv_fds;
> @@ -27,6 +29,7 @@ enum msg_type {
> 
>  typedef struct VFIOUserMsg {
>  QTAILQ_ENTRY(VFIOUserMsg) next;
> +VFIOUserHdr *hdr;
>  VFIOUserFDs *fds;
>  uint32_t rsize;
>  uint32_t id;
> @@ -74,5 +77,8 @@ typedef struct VFIOProxy {
> 
>  VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
>  void vfio_user_disconnect(VFIOProxy *proxy);
> +void vfio_user_set_handler(VFIODevice *vbasedev,
> +   void (*handler)(void *opaque, VFIOUserMsg *msg),
> +   void *reqarg);
> 
>  #endif /* VFIO_USER_H */
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 9fd7c07..0de915d 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -3386,6 +3386,11 @@ type_init(register_vfio_pci_dev_type)
>   * vfio-user routines.
>   */
> 
> +static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg)
> +{
> +
> +}
> +
>  /*
>   * Emulated devices don't use host hot reset
>   */
> @@ -3432,6 +3437,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev,
> Error **errp)
>  return;
>  }
>  vbasedev->proxy = proxy;
> +vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
> 
>  vbasedev->name = g_strdup_printf("VFIO user <%s>", udev->sock_name);
>  vbasedev->dev = DEVICE(vdev);
> diff --git a/hw/vfio/user.c b/hw/vfio/user.c
> index c843f90..e1dfd5d 100644
> --- a/hw/vfio/user.c
> +++ b/hw/vfio/user.c
> @@ -25,10 +25,26 @@
>  #include "sysemu/iothread.h"
>  #include "user.h"
> 
> +static uint64_t max_xfer_s

[RFC v4 08/21] vfio-user: define socket receive functions

2022-01-11 Thread John Johnson
Add infrastructure needed to receive incoming messages

Signed-off-by: John G Johnson 
Signed-off-by: Elena Ufimtseva 
Signed-off-by: Jagannathan Raman 
---
 hw/vfio/user-protocol.h |  54 
 hw/vfio/user.h  |   6 +
 hw/vfio/pci.c   |   6 +
 hw/vfio/user.c  | 327 
 MAINTAINERS |   1 +
 5 files changed, 394 insertions(+)
 create mode 100644 hw/vfio/user-protocol.h

diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h
new file mode 100644
index 000..d23877c
--- /dev/null
+++ b/hw/vfio/user-protocol.h
@@ -0,0 +1,54 @@
+#ifndef VFIO_USER_PROTOCOL_H
+#define VFIO_USER_PROTOCOL_H
+
+/*
+ * vfio protocol over a UNIX socket.
+ *
+ * Copyright © 2018, 2021 Oracle and/or its affiliates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Each message has a standard header that describes the command
+ * being sent, which is almost always a VFIO ioctl().
+ *
+ * The header may be followed by command-specific data, such as the
+ * region and offset info for read and write commands.
+ */
+
+typedef struct {
+uint16_t id;
+uint16_t command;
+uint32_t size;
+uint32_t flags;
+uint32_t error_reply;
+} VFIOUserHdr;
+
+/* VFIOUserHdr commands */
+enum vfio_user_command {
+VFIO_USER_VERSION   = 1,
+VFIO_USER_DMA_MAP   = 2,
+VFIO_USER_DMA_UNMAP = 3,
+VFIO_USER_DEVICE_GET_INFO   = 4,
+VFIO_USER_DEVICE_GET_REGION_INFO= 5,
+VFIO_USER_DEVICE_GET_REGION_IO_FDS  = 6,
+VFIO_USER_DEVICE_GET_IRQ_INFO   = 7,
+VFIO_USER_DEVICE_SET_IRQS   = 8,
+VFIO_USER_REGION_READ   = 9,
+VFIO_USER_REGION_WRITE  = 10,
+VFIO_USER_DMA_READ  = 11,
+VFIO_USER_DMA_WRITE = 12,
+VFIO_USER_DEVICE_RESET  = 13,
+VFIO_USER_DIRTY_PAGES   = 14,
+VFIO_USER_MAX,
+};
+
+/* VFIOUserHdr flags */
+#define VFIO_USER_REQUEST   0x0
+#define VFIO_USER_REPLY 0x1
+#define VFIO_USER_TYPE  0xF
+
+#define VFIO_USER_NO_REPLY  0x10
+#define VFIO_USER_ERROR 0x20
+
+#endif /* VFIO_USER_PROTOCOL_H */
diff --git a/hw/vfio/user.h b/hw/vfio/user.h
index da92862..72eefa7 100644
--- a/hw/vfio/user.h
+++ b/hw/vfio/user.h
@@ -11,6 +11,8 @@
  *
  */
 
+#include "user-protocol.h"
+
 typedef struct {
 int send_fds;
 int recv_fds;
@@ -27,6 +29,7 @@ enum msg_type {
 
 typedef struct VFIOUserMsg {
 QTAILQ_ENTRY(VFIOUserMsg) next;
+VFIOUserHdr *hdr;
 VFIOUserFDs *fds;
 uint32_t rsize;
 uint32_t id;
@@ -74,5 +77,8 @@ typedef struct VFIOProxy {
 
 VFIOProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
 void vfio_user_disconnect(VFIOProxy *proxy);
+void vfio_user_set_handler(VFIODevice *vbasedev,
+   void (*handler)(void *opaque, VFIOUserMsg *msg),
+   void *reqarg);
 
 #endif /* VFIO_USER_H */
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 9fd7c07..0de915d 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -3386,6 +3386,11 @@ type_init(register_vfio_pci_dev_type)
  * vfio-user routines.
  */
 
+static void vfio_user_pci_process_req(void *opaque, VFIOUserMsg *msg)
+{
+
+}
+
 /*
  * Emulated devices don't use host hot reset
  */
@@ -3432,6 +3437,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error 
**errp)
 return;
 }
 vbasedev->proxy = proxy;
+vfio_user_set_handler(vbasedev, vfio_user_pci_process_req, vdev);
 
 vbasedev->name = g_strdup_printf("VFIO user <%s>", udev->sock_name);
 vbasedev->dev = DEVICE(vdev);
diff --git a/hw/vfio/user.c b/hw/vfio/user.c
index c843f90..e1dfd5d 100644
--- a/hw/vfio/user.c
+++ b/hw/vfio/user.c
@@ -25,10 +25,26 @@
 #include "sysemu/iothread.h"
 #include "user.h"
 
+static uint64_t max_xfer_size;
 static IOThread *vfio_user_iothread;
 
 static void vfio_user_shutdown(VFIOProxy *proxy);
+static VFIOUserMsg *vfio_user_getmsg(VFIOProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds);
+static VFIOUserFDs *vfio_user_getfds(int numfds);
+static void vfio_user_recycle(VFIOProxy *proxy, VFIOUserMsg *msg);
 
+static void vfio_user_recv(void *opaque);
+static int vfio_user_recv_one(VFIOProxy *proxy);
+static void vfio_user_cb(void *opaque);
+
+static void vfio_user_request(void *opaque);
+
+static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
+{
+hdr->flags |= VFIO_USER_ERROR;
+hdr->error_reply = err;
+}
 
 /*
  * Functions called by main, CPU, or iothread threads
@@ -40,10 +56,261 @@ static void vfio_user_shutdown(VFIOProxy *proxy)
 qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL, NULL, NULL);
 }
 
+static VFIOUserMsg *vfio_user_getmsg(VFIOProxy *proxy, VFIOUserHdr *hdr,
+ VFIOUserFDs *fds)
+{
+