diff mbox

[5/5] Add vhost-user calls implementation

Message ID 1385754746-21172-6-git-send-email-a.motakis@virtualopensystems.com
State New
Headers show

Commit Message

Antonios Motakis Nov. 29, 2013, 7:52 p.m. UTC
Each ioctl request of vhost-kernel has a vhost-user message equivalent,
which is sent it over the control socket.

The general approach is to copy the data from the supplied argument
pointer to a designated field in the message. If a file descriptor is
to be passed it should be placed also in the fds array for inclusion in
the sendmsd control header.

VHOST_SET_MEM_TABLE ignores the supplied vhost_memory structure and scans
the global ram_list for ram blocks wiht a valid fd field set. This would
be set when -mem-path and -mem-prealloc command line options are used.

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com>
---
 hw/virtio/vhost-backend.c | 105 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 100 insertions(+), 5 deletions(-)

Comments

Michael S. Tsirkin Dec. 4, 2013, 8 p.m. UTC | #1
On Fri, Nov 29, 2013 at 08:52:26PM +0100, Antonios Motakis wrote:
> Each ioctl request of vhost-kernel has a vhost-user message equivalent,
> which is sent it over the control socket.
> 
> The general approach is to copy the data from the supplied argument
> pointer to a designated field in the message. If a file descriptor is
> to be passed it should be placed also in the fds array for inclusion in
> the sendmsd control header.

What does this code talk to? What's on the other side of the domain socket?

> VHOST_SET_MEM_TABLE ignores the supplied vhost_memory structure and scans
> the global ram_list for ram blocks wiht a valid fd field set. This would
> be set when -mem-path and -mem-prealloc command line options are used.

I don't get this.
AFAIK -mem-path is used for huge tlb fs.
So vhost-user requires huge tlb fs then?

> Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com>


> ---
>  hw/virtio/vhost-backend.c | 105 +++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 100 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
> index 264a0a1..1bc2928 100644
> --- a/hw/virtio/vhost-backend.c
> +++ b/hw/virtio/vhost-backend.c
> @@ -67,6 +67,38 @@ typedef struct VhostUserMsg {
>      };
>  } VhostUserMsg;
>  
> +static unsigned long int ioctl_to_vhost_user_request[VHOST_USER_MAX] = {
> +    -1, /* VHOST_USER_NONE */
> +    VHOST_GET_FEATURES, /* VHOST_USER_GET_FEATURES */
> +    VHOST_SET_FEATURES, /* VHOST_USER_SET_FEATURES */
> +    VHOST_SET_OWNER, /* VHOST_USER_SET_OWNER */
> +    VHOST_RESET_OWNER, /* VHOST_USER_RESET_OWNER */
> +    VHOST_SET_MEM_TABLE, /* VHOST_USER_SET_MEM_TABLE */
> +    VHOST_SET_LOG_BASE, /* VHOST_USER_SET_LOG_BASE */
> +    VHOST_SET_LOG_FD, /* VHOST_USER_SET_LOG_FD */
> +    VHOST_SET_VRING_NUM, /* VHOST_USER_SET_VRING_NUM */
> +    VHOST_SET_VRING_ADDR, /* VHOST_USER_SET_VRING_ADDR */
> +    VHOST_SET_VRING_BASE, /* VHOST_USER_SET_VRING_BASE */
> +    VHOST_GET_VRING_BASE, /* VHOST_USER_GET_VRING_BASE */
> +    VHOST_SET_VRING_KICK, /* VHOST_USER_SET_VRING_KICK */
> +    VHOST_SET_VRING_CALL, /* VHOST_USER_SET_VRING_CALL */
> +    VHOST_SET_VRING_ERR, /* VHOST_USER_SET_VRING_ERR */
> +    VHOST_NET_SET_BACKEND /* VHOST_USER_NET_SET_BACKEND */
> +};
> +
> +static VhostUserRequest vhost_user_request_translate(unsigned long int request)
> +{
> +    VhostUserRequest idx;
> +
> +    for (idx = 0; idx < VHOST_USER_MAX; idx++) {
> +        if (ioctl_to_vhost_user_request[idx] == request) {
> +            break;
> +        }
> +    }
> +
> +    return (idx == VHOST_USER_MAX) ? VHOST_USER_NONE : idx;
> +}
> +
>  static int vhost_user_recv(int fd, VhostUserMsg *msg)
>  {
>      ssize_t r = read(fd, msg, sizeof(VhostUserMsg));
> @@ -137,13 +169,72 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
>  {
>      int fd = dev->control;
>      VhostUserMsg msg;
> -    int result = 0;
> +    RAMBlock *block = 0;
> +    int result = 0, need_reply = 0;
>      int fds[VHOST_MEMORY_MAX_NREGIONS];
>      size_t fd_num = 0;
>  
> -    memset(&msg, 0, sizeof(VhostUserMsg));
> +    msg.request = vhost_user_request_translate(request);
> +    msg.flags = 0;
>  
>      switch (request) {
> +    case VHOST_GET_FEATURES:
> +    case VHOST_GET_VRING_BASE:
> +        need_reply = 1;
> +        break;
> +
> +    case VHOST_SET_FEATURES:
> +    case VHOST_SET_LOG_BASE:
> +        msg.u64 = *((uint64_t *) arg);
> +        break;
> +
> +    case VHOST_SET_OWNER:
> +    case VHOST_RESET_OWNER:
> +        break;
> +
> +    case VHOST_SET_MEM_TABLE:
> +        QTAILQ_FOREACH(block, &ram_list.blocks, next)
> +        {
> +            if (block->fd > 0) {
> +                msg.memory.regions[fd_num].userspace_addr = (__u64) block->host;
> +                msg.memory.regions[fd_num].memory_size = block->length;
> +                msg.memory.regions[fd_num].guest_phys_addr = block->offset;
> +                fds[fd_num++] = block->fd;
> +            }
> +        }
> +
> +        msg.memory.nregions = fd_num;
> +
> +        if (!fd_num) {
> +            fprintf(stderr, "Failed initializing vhost-user memory map\n"
> +                    "consider -mem-path and -mem-prealloc options\n");
> +            return -1;
> +        }
> +        break;
> +
> +    case VHOST_SET_LOG_FD:
> +        msg.fd = *((int *) arg);
> +        break;
> +
> +    case VHOST_SET_VRING_NUM:
> +    case VHOST_SET_VRING_BASE:
> +        memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
> +        break;
> +
> +    case VHOST_SET_VRING_ADDR:
> +        memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
> +        break;
> +
> +    case VHOST_SET_VRING_KICK:
> +    case VHOST_SET_VRING_CALL:
> +    case VHOST_SET_VRING_ERR:
> +    case VHOST_NET_SET_BACKEND:
> +        memcpy(&msg.file, arg, sizeof(struct vhost_vring_file));
> +        if (msg.file.fd > 0) {
> +            fds[0] = msg.file.fd;
> +            fd_num = 1;
> +        }
> +        break;
>      default:
>          fprintf(stderr, "vhost-user trying to send unhandled ioctl\n");
>          return -1;
> @@ -152,12 +243,16 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
>  
>      result = vhost_user_send_fds(fd, &msg, fds, fd_num);
>  
> -    if (!result) {
> +    if (!result && need_reply) {
>          result = vhost_user_recv(fd, &msg);
>          if (!result) {
>              switch (request) {
> -            default:
> -                fprintf(stderr, "vhost-user received unhandled message\n");
> +            case VHOST_GET_FEATURES:
> +                *((uint64_t *) arg) = msg.u64;
> +                break;
> +            case VHOST_GET_VRING_BASE:
> +                memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
> +                break;
>              }
>          }
>      }
> -- 
> 1.8.3.2
>
Antonios Motakis Dec. 10, 2013, 12:05 p.m. UTC | #2
Hello,

On Wed, Dec 4, 2013 at 9:00 PM, Michael S. Tsirkin <mst@redhat.com> wrote:

> On Fri, Nov 29, 2013 at 08:52:26PM +0100, Antonios Motakis wrote:
> > Each ioctl request of vhost-kernel has a vhost-user message equivalent,
> > which is sent it over the control socket.
> >
> > The general approach is to copy the data from the supplied argument
> > pointer to a designated field in the message. If a file descriptor is
> > to be passed it should be placed also in the fds array for inclusion in
> > the sendmsd control header.
>
> What does this code talk to? What's on the other side of the domain socket?
>

Our intention is to have on the other side of the socket the Snabbswitch
userspace ethernet switch. Of course the interface we are aiming at is not
limited to Snabbswitch, so other use cases could be considered as well.


>
> > VHOST_SET_MEM_TABLE ignores the supplied vhost_memory structure and scans
> > the global ram_list for ram blocks wiht a valid fd field set. This would
> > be set when -mem-path and -mem-prealloc command line options are used.
>
> I don't get this.
> AFAIK -mem-path is used for huge tlb fs.
> So vhost-user requires huge tlb fs then?
>

We need a mechanism to share the guest memory with the remote process. Huge
tlb fs is one way to do it, however we posted a new version of the patch
series that introduces another mechanism (-mem-share), so it is no longer
mandatory to use huge tlb fs. I think should address any concern. For more
details you can refer to the new vhost-user series we posted today.

Best regards,
Antonios


> > Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
> > Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com>
>
>
> > ---
> >  hw/virtio/vhost-backend.c | 105
> +++++++++++++++++++++++++++++++++++++++++++---
> >  1 file changed, 100 insertions(+), 5 deletions(-)
> >
> > diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
> > index 264a0a1..1bc2928 100644
> > --- a/hw/virtio/vhost-backend.c
> > +++ b/hw/virtio/vhost-backend.c
> > @@ -67,6 +67,38 @@ typedef struct VhostUserMsg {
> >      };
> >  } VhostUserMsg;
> >
> > +static unsigned long int ioctl_to_vhost_user_request[VHOST_USER_MAX] = {
> > +    -1, /* VHOST_USER_NONE */
> > +    VHOST_GET_FEATURES, /* VHOST_USER_GET_FEATURES */
> > +    VHOST_SET_FEATURES, /* VHOST_USER_SET_FEATURES */
> > +    VHOST_SET_OWNER, /* VHOST_USER_SET_OWNER */
> > +    VHOST_RESET_OWNER, /* VHOST_USER_RESET_OWNER */
> > +    VHOST_SET_MEM_TABLE, /* VHOST_USER_SET_MEM_TABLE */
> > +    VHOST_SET_LOG_BASE, /* VHOST_USER_SET_LOG_BASE */
> > +    VHOST_SET_LOG_FD, /* VHOST_USER_SET_LOG_FD */
> > +    VHOST_SET_VRING_NUM, /* VHOST_USER_SET_VRING_NUM */
> > +    VHOST_SET_VRING_ADDR, /* VHOST_USER_SET_VRING_ADDR */
> > +    VHOST_SET_VRING_BASE, /* VHOST_USER_SET_VRING_BASE */
> > +    VHOST_GET_VRING_BASE, /* VHOST_USER_GET_VRING_BASE */
> > +    VHOST_SET_VRING_KICK, /* VHOST_USER_SET_VRING_KICK */
> > +    VHOST_SET_VRING_CALL, /* VHOST_USER_SET_VRING_CALL */
> > +    VHOST_SET_VRING_ERR, /* VHOST_USER_SET_VRING_ERR */
> > +    VHOST_NET_SET_BACKEND /* VHOST_USER_NET_SET_BACKEND */
> > +};
> > +
> > +static VhostUserRequest vhost_user_request_translate(unsigned long int
> request)
> > +{
> > +    VhostUserRequest idx;
> > +
> > +    for (idx = 0; idx < VHOST_USER_MAX; idx++) {
> > +        if (ioctl_to_vhost_user_request[idx] == request) {
> > +            break;
> > +        }
> > +    }
> > +
> > +    return (idx == VHOST_USER_MAX) ? VHOST_USER_NONE : idx;
> > +}
> > +
> >  static int vhost_user_recv(int fd, VhostUserMsg *msg)
> >  {
> >      ssize_t r = read(fd, msg, sizeof(VhostUserMsg));
> > @@ -137,13 +169,72 @@ static int vhost_user_call(struct vhost_dev *dev,
> unsigned long int request,
> >  {
> >      int fd = dev->control;
> >      VhostUserMsg msg;
> > -    int result = 0;
> > +    RAMBlock *block = 0;
> > +    int result = 0, need_reply = 0;
> >      int fds[VHOST_MEMORY_MAX_NREGIONS];
> >      size_t fd_num = 0;
> >
> > -    memset(&msg, 0, sizeof(VhostUserMsg));
> > +    msg.request = vhost_user_request_translate(request);
> > +    msg.flags = 0;
> >
> >      switch (request) {
> > +    case VHOST_GET_FEATURES:
> > +    case VHOST_GET_VRING_BASE:
> > +        need_reply = 1;
> > +        break;
> > +
> > +    case VHOST_SET_FEATURES:
> > +    case VHOST_SET_LOG_BASE:
> > +        msg.u64 = *((uint64_t *) arg);
> > +        break;
> > +
> > +    case VHOST_SET_OWNER:
> > +    case VHOST_RESET_OWNER:
> > +        break;
> > +
> > +    case VHOST_SET_MEM_TABLE:
> > +        QTAILQ_FOREACH(block, &ram_list.blocks, next)
> > +        {
> > +            if (block->fd > 0) {
> > +                msg.memory.regions[fd_num].userspace_addr = (__u64)
> block->host;
> > +                msg.memory.regions[fd_num].memory_size = block->length;
> > +                msg.memory.regions[fd_num].guest_phys_addr =
> block->offset;
> > +                fds[fd_num++] = block->fd;
> > +            }
> > +        }
> > +
> > +        msg.memory.nregions = fd_num;
> > +
> > +        if (!fd_num) {
> > +            fprintf(stderr, "Failed initializing vhost-user memory
> map\n"
> > +                    "consider -mem-path and -mem-prealloc options\n");
> > +            return -1;
> > +        }
> > +        break;
> > +
> > +    case VHOST_SET_LOG_FD:
> > +        msg.fd = *((int *) arg);
> > +        break;
> > +
> > +    case VHOST_SET_VRING_NUM:
> > +    case VHOST_SET_VRING_BASE:
> > +        memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
> > +        break;
> > +
> > +    case VHOST_SET_VRING_ADDR:
> > +        memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
> > +        break;
> > +
> > +    case VHOST_SET_VRING_KICK:
> > +    case VHOST_SET_VRING_CALL:
> > +    case VHOST_SET_VRING_ERR:
> > +    case VHOST_NET_SET_BACKEND:
> > +        memcpy(&msg.file, arg, sizeof(struct vhost_vring_file));
> > +        if (msg.file.fd > 0) {
> > +            fds[0] = msg.file.fd;
> > +            fd_num = 1;
> > +        }
> > +        break;
> >      default:
> >          fprintf(stderr, "vhost-user trying to send unhandled ioctl\n");
> >          return -1;
> > @@ -152,12 +243,16 @@ static int vhost_user_call(struct vhost_dev *dev,
> unsigned long int request,
> >
> >      result = vhost_user_send_fds(fd, &msg, fds, fd_num);
> >
> > -    if (!result) {
> > +    if (!result && need_reply) {
> >          result = vhost_user_recv(fd, &msg);
> >          if (!result) {
> >              switch (request) {
> > -            default:
> > -                fprintf(stderr, "vhost-user received unhandled
> message\n");
> > +            case VHOST_GET_FEATURES:
> > +                *((uint64_t *) arg) = msg.u64;
> > +                break;
> > +            case VHOST_GET_VRING_BASE:
> > +                memcpy(arg, &msg.state, sizeof(struct
> vhost_vring_state));
> > +                break;
> >              }
> >          }
> >      }
> > --
> > 1.8.3.2
> >
>
diff mbox

Patch

diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 264a0a1..1bc2928 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -67,6 +67,38 @@  typedef struct VhostUserMsg {
     };
 } VhostUserMsg;
 
+static unsigned long int ioctl_to_vhost_user_request[VHOST_USER_MAX] = {
+    -1, /* VHOST_USER_NONE */
+    VHOST_GET_FEATURES, /* VHOST_USER_GET_FEATURES */
+    VHOST_SET_FEATURES, /* VHOST_USER_SET_FEATURES */
+    VHOST_SET_OWNER, /* VHOST_USER_SET_OWNER */
+    VHOST_RESET_OWNER, /* VHOST_USER_RESET_OWNER */
+    VHOST_SET_MEM_TABLE, /* VHOST_USER_SET_MEM_TABLE */
+    VHOST_SET_LOG_BASE, /* VHOST_USER_SET_LOG_BASE */
+    VHOST_SET_LOG_FD, /* VHOST_USER_SET_LOG_FD */
+    VHOST_SET_VRING_NUM, /* VHOST_USER_SET_VRING_NUM */
+    VHOST_SET_VRING_ADDR, /* VHOST_USER_SET_VRING_ADDR */
+    VHOST_SET_VRING_BASE, /* VHOST_USER_SET_VRING_BASE */
+    VHOST_GET_VRING_BASE, /* VHOST_USER_GET_VRING_BASE */
+    VHOST_SET_VRING_KICK, /* VHOST_USER_SET_VRING_KICK */
+    VHOST_SET_VRING_CALL, /* VHOST_USER_SET_VRING_CALL */
+    VHOST_SET_VRING_ERR, /* VHOST_USER_SET_VRING_ERR */
+    VHOST_NET_SET_BACKEND /* VHOST_USER_NET_SET_BACKEND */
+};
+
+static VhostUserRequest vhost_user_request_translate(unsigned long int request)
+{
+    VhostUserRequest idx;
+
+    for (idx = 0; idx < VHOST_USER_MAX; idx++) {
+        if (ioctl_to_vhost_user_request[idx] == request) {
+            break;
+        }
+    }
+
+    return (idx == VHOST_USER_MAX) ? VHOST_USER_NONE : idx;
+}
+
 static int vhost_user_recv(int fd, VhostUserMsg *msg)
 {
     ssize_t r = read(fd, msg, sizeof(VhostUserMsg));
@@ -137,13 +169,72 @@  static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
 {
     int fd = dev->control;
     VhostUserMsg msg;
-    int result = 0;
+    RAMBlock *block = 0;
+    int result = 0, need_reply = 0;
     int fds[VHOST_MEMORY_MAX_NREGIONS];
     size_t fd_num = 0;
 
-    memset(&msg, 0, sizeof(VhostUserMsg));
+    msg.request = vhost_user_request_translate(request);
+    msg.flags = 0;
 
     switch (request) {
+    case VHOST_GET_FEATURES:
+    case VHOST_GET_VRING_BASE:
+        need_reply = 1;
+        break;
+
+    case VHOST_SET_FEATURES:
+    case VHOST_SET_LOG_BASE:
+        msg.u64 = *((uint64_t *) arg);
+        break;
+
+    case VHOST_SET_OWNER:
+    case VHOST_RESET_OWNER:
+        break;
+
+    case VHOST_SET_MEM_TABLE:
+        QTAILQ_FOREACH(block, &ram_list.blocks, next)
+        {
+            if (block->fd > 0) {
+                msg.memory.regions[fd_num].userspace_addr = (__u64) block->host;
+                msg.memory.regions[fd_num].memory_size = block->length;
+                msg.memory.regions[fd_num].guest_phys_addr = block->offset;
+                fds[fd_num++] = block->fd;
+            }
+        }
+
+        msg.memory.nregions = fd_num;
+
+        if (!fd_num) {
+            fprintf(stderr, "Failed initializing vhost-user memory map\n"
+                    "consider -mem-path and -mem-prealloc options\n");
+            return -1;
+        }
+        break;
+
+    case VHOST_SET_LOG_FD:
+        msg.fd = *((int *) arg);
+        break;
+
+    case VHOST_SET_VRING_NUM:
+    case VHOST_SET_VRING_BASE:
+        memcpy(&msg.state, arg, sizeof(struct vhost_vring_state));
+        break;
+
+    case VHOST_SET_VRING_ADDR:
+        memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr));
+        break;
+
+    case VHOST_SET_VRING_KICK:
+    case VHOST_SET_VRING_CALL:
+    case VHOST_SET_VRING_ERR:
+    case VHOST_NET_SET_BACKEND:
+        memcpy(&msg.file, arg, sizeof(struct vhost_vring_file));
+        if (msg.file.fd > 0) {
+            fds[0] = msg.file.fd;
+            fd_num = 1;
+        }
+        break;
     default:
         fprintf(stderr, "vhost-user trying to send unhandled ioctl\n");
         return -1;
@@ -152,12 +243,16 @@  static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
 
     result = vhost_user_send_fds(fd, &msg, fds, fd_num);
 
-    if (!result) {
+    if (!result && need_reply) {
         result = vhost_user_recv(fd, &msg);
         if (!result) {
             switch (request) {
-            default:
-                fprintf(stderr, "vhost-user received unhandled message\n");
+            case VHOST_GET_FEATURES:
+                *((uint64_t *) arg) = msg.u64;
+                break;
+            case VHOST_GET_VRING_BASE:
+                memcpy(arg, &msg.state, sizeof(struct vhost_vring_state));
+                break;
             }
         }
     }