vhost-user: add multi queue support
PATCH v2 1/1 vhost-user: add multi queue support
Vhost-user will implement the multiqueueu support in a similar way to what vhost already has - a separate thread for each queue.
To enable the multiqueue funcionality - a new command line parameter "queues" is introduced for the vhost-user netdev.
Changes since v1:
- use s->nc.info_str when bringing up/down the backend
--- docs/specs/vhost-user.txt | 5 +++++ hw/virtio/vhost-user.c | 6 +++++- net/vhost-user.c | 39 +++++++++++++++++++++++++-------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 5 files changed, 43 insertions(+), 18 deletions(-)
docs/specs/vhost-user.txt +5 -0
@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. +Multi queue suport +--------------------- +The protocol supports multiple queues by setting all index fields in the sent +messages to a properly calculated value. + Message types -------------
hw/virtio/vhost-user.c +5 -1
@@ -253,17 +253,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_NUM :case VHOST_SET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state);break ;case VHOST_GET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state); need_reply =1 ;break ;case VHOST_SET_VRING_ADDR :memcpy (&msg.addr, arg,sizeof (struct vhost_vring_addr )); + msg.addr.index += dev->vq_index; msg.size =sizeof (m.addr);break ;
@@ -271,7 +274,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_CALL :case VHOST_SET_VRING_ERR : file = arg; - msg.u64 = file->index &VHOST_USER_VRING_IDX_MASK ; + msg.u64 = (file->index + dev->vq_index) &VHOST_USER_VRING_IDX_MASK ; msg.size =sizeof (m.u64);if (ioeventfd_enabled () && file->fd >0 ) { fds[fd_num++] = file->fd;
@@ -313,6 +316,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,error_report ("Received bad msg size.\n" );return -1 ; } + msg.state.index -= dev->vq_index;memcpy (arg, &msg.state,sizeof (struct vhost_vring_state ));break ;default :
net/vhost-user.c +25 -14
@@ -122,37 +122,39 @@ static void net_vhost_user_event(void *opaque, int event)case CHR_EVENT_OPENED :vhost_user_start (s);net_vhost_link_down (s, false); -error_report ("chardev \"%s\" went up\n" , s->chr->label); +error_report ("chardev \"%s\" went up\n" , s->nc.info_str);break ;case CHR_EVENT_CLOSED :net_vhost_link_down (s, true);vhost_user_stop (s); -error_report ("chardev \"%s\" went down\n" , s->chr->label); +error_report ("chardev \"%s\" went down\n" , s->nc.info_str);break ; } }static int net_vhost_user_init (NetClientState *peer,const char *device,const char *name,CharDriverState *chr, -bool vhostforce) +bool vhostforce,uint32_t queues) {NetClientState *nc;VhostUserState *s; +int i; - nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); +for (i =0 ; i < queues; i++) { + nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); -snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user to %s" , - chr->label); +snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user%d to %s" , + i, chr->label); - s =DO_UPCAST (VhostUserState, nc, nc); + s =DO_UPCAST (VhostUserState, nc, nc); -/* We don't provide a receive callback */ - s->nc.receive_disabled =1 ; - s->chr = chr; - s->vhostforce = vhostforce; - -qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); +/* We don't provide a receive callback */ + s->nc.receive_disabled =1 ; + s->chr = chr; + s->vhostforce = vhostforce; +qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); + }return 0 ; }
@@ -228,6 +230,7 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque)int net_init_vhost_user (const NetClientOptions *opts,const char *name,NetClientState *peer) { +uint32_t queues;const NetdevVhostUserOptions *vhost_user_opts;CharDriverState *chr;bool vhostforce;
@@ -254,5 +257,13 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name, vhostforce = false; } -return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce); +/* number of queues for multiqueue */ +if (vhost_user_opts->has_queues) { + queues = vhost_user_opts->queues; + }else { + queues =1 ; + } + +return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce, + queues); }
qapi-schema.json +5 -1
@@ -2287,12 +2287,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user +# (Since 2.3) +# # Since 2.1 ## { 'type': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } } ## # @NetClientOptions
qemu-options.hx +3 -2
@@ -1894,13 +1894,14 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the required hub automatically. -@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off] +@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n] Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should be a unix domain socket backed one. The vhost-user uses a specifically defined protocol to pass vhost ioctl replacement messages to an application on the other end of the socket. On non-MSIX guests, the feature can be forced with -@var{vhostforce}. +@var{vhostforce}. Use 'queues=@var{n}' to specify the number of queues to +be created for multiqueue vhost-user. Example: @example
Quoted 1 line · Nikolay Nikolaev
Vhost-user will implement the multiqueueu support in a similar way to what
s/multiqueueu/multiqueue/
Also, you probably want to be consistent - is it two words (subject line) or one word (this sentence)? I could go either way.
Quoted 3 lines
vhost already has - a separate thread for each queue.
To enable the multiqueue funcionality - a new command line parameter
s/funcionality/functionality/
Quoted 4 lines
"queues" is introduced for the vhost-user netdev.
Changes since v1:
- uses->nc.info_strwhen bringing up/down the backend
This paragraph about path versioning belongs...
Quoted 3 lines
Signed-off-by Nikolay Nikolaev <[email protected]>---
...here, after the --- separator. It is useful to reviewers, but makes no sense in the final qemu.git repository (a year from now, we only care about the one version that got committed, not how many tries it took to get to that one version).
Quoted 12 lines
docs/specs/vhost-user.txt | 5 +++++ hw/virtio/vhost-user.c | 6 +++++- net/vhost-user.c | 39 +++++++++++++++++++++++++-------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 5 files changed, 43 insertions(+), 18 deletions(-)docs/specs/vhost-user.txt +0
-0
docs/specs/vhost-user.txt in the ancillary data: · line 130
Quoted 4 lines
docs/specs/vhost-user.txt +1
-0@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. +Multi queue suport
s/suport/support/
docs/specs/vhost-user.txt in the ancillary data: · line 131
Quoted 1 line
docs/specs/vhost-user.txt +1
-0+---------------------
Make the length of this separator match the text it is underlining (too long, even after the typo fix)
docs/specs/vhost-user.txt line 2291
Quoted 7 lines
docs/specs/vhost-user.txt +3
-0+++ b/qapi-schema.json@@ -2287,12 +2287,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user +# (Since 2.3)
Might be worth mentioning that the default is 1.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Quoted 1 line · Nikolay Nikolaev
Vhost-user will implement the multiqueueu support in a similar way to what
multiqueue
docs/specs/vhost-user.txt
Quoted 21 lines
vhost already has - a separate thread for each queue.
To enable the multiqueue funcionality - a new command line parameter "queues" is introduced for the vhost-user netdev.
Changes since v1:
- uses->nc.info_strwhen bringing up/down the backendSigned-off-by Nikolay Nikolaev <[email protected]>--- docs/specs/vhost-user.txt | 5 +++++ hw/virtio/vhost-user.c | 6 +++++- net/vhost-user.c | 39 +++++++++++++++++++++++++-------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 5 files changed, 43 insertions(+), 18 deletions(-)docs/specs/vhost-user.txt +0
-0
I've been thinking that the protocol might be a useful addition to the virtio spec. For this, as a minimum you would have to submit this document as a comment to virtio TC with a proposal to include it in the virtio spec.
See
https://www.oasis-open.org/committees/comments/index.php?wg_abbrev=virtio
Can you do this?
We can take it from there, though I would encourage your company to join as a contributor.
docs/specs/vhost-user.txt in the ancillary data: · line 134
Quoted 9 lines
docs/specs/vhost-user.txt +5
-0@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. +Multi queue suport +--------------------- +The protocol supports multiple queues by setting all index fields in the sent +messages to a properly calculated value. +
Something that's not clear from this document is what happens with control VQ. Can you clarify please?
Quoted 168 lines
docs/specs/vhost-user.txt +0
-0Message types -------------hw/virtio/vhost-user.c +5
-1@@ -253,17 +253,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_NUM :case VHOST_SET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state);break ;case VHOST_GET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state); need_reply =1 ;break ;case VHOST_SET_VRING_ADDR :memcpy (&msg.addr, arg,sizeof (struct vhost_vring_addr )); + msg.addr.index += dev->vq_index; msg.size =sizeof (m.addr);break ;@@ -271,7 +274,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_CALL :case VHOST_SET_VRING_ERR : file = arg; - msg.u64 = file->index &VHOST_USER_VRING_IDX_MASK ; + msg.u64 = (file->index + dev->vq_index) &VHOST_USER_VRING_IDX_MASK ; msg.size =sizeof (m.u64);if (ioeventfd_enabled () && file->fd >0 ) { fds[fd_num++] = file->fd;@@ -313,6 +316,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,error_report ("Received bad msg size.\n" );return -1 ; } + msg.state.index -= dev->vq_index;memcpy (arg, &msg.state,sizeof (struct vhost_vring_state ));break ;default :net/vhost-user.c +25
-14@@ -122,37 +122,39 @@ static void net_vhost_user_event(void *opaque, int event)case CHR_EVENT_OPENED :vhost_user_start (s);net_vhost_link_down (s, false); -error_report ("chardev \"%s\" went up\n" , s->chr->label); +error_report ("chardev \"%s\" went up\n" , s->nc.info_str);break ;case CHR_EVENT_CLOSED :net_vhost_link_down (s, true);vhost_user_stop (s); -error_report ("chardev \"%s\" went down\n" , s->chr->label); +error_report ("chardev \"%s\" went down\n" , s->nc.info_str);break ; } }static int net_vhost_user_init (NetClientState *peer,const char *device,const char *name,CharDriverState *chr, -bool vhostforce) +bool vhostforce,uint32_t queues) {NetClientState *nc;VhostUserState *s; +int i; - nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); +for (i =0 ; i < queues; i++) { + nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); -snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user to %s" , - chr->label); +snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user%d to %s" , + i, chr->label); - s =DO_UPCAST (VhostUserState, nc, nc); + s =DO_UPCAST (VhostUserState, nc, nc); -/* We don't provide a receive callback */ - s->nc.receive_disabled =1 ; - s->chr = chr; - s->vhostforce = vhostforce; - -qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); +/* We don't provide a receive callback */ + s->nc.receive_disabled =1 ; + s->chr = chr; + s->vhostforce = vhostforce; +qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); + }return 0 ; }@@ -228,6 +230,7 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque)int net_init_vhost_user (const NetClientOptions *opts,const char *name,NetClientState *peer) { +uint32_t queues;const NetdevVhostUserOptions *vhost_user_opts;CharDriverState *chr;bool vhostforce;@@ -254,5 +257,13 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name, vhostforce = false; } -return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce); +/* number of queues for multiqueue */ +if (vhost_user_opts->has_queues) { + queues = vhost_user_opts->queues; + }else { + queues =1 ; + } + +return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce, + queues); }qapi-schema.json +5
-1@@ -2287,12 +2287,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user +# (Since 2.3) +# # Since 2.1 ## { 'type': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } } ## # @NetClientOptionsqemu-options.hx +3
-2@@ -1894,13 +1894,14 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the required hub automatically. -@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off] +@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n] Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should be a unix domain socket backed one. The vhost-user uses a specifically defined protocol to pass vhost ioctl replacement messages to an application on the other end of the socket. On non-MSIX guests, the feature can be forced with -@var{vhostforce}. +@var{vhostforce}. Use 'queues=@var{n}' to specify the number of queues to +be created for multiqueue vhost-user. Example: @example
Quoted 35 lines · Michael S. Tsirkin
Quoted 1 line · Nikolay Nikolaev
Vhost-user will implement the multiqueueu support in a similar way to what
multiqueue
docs/specs/vhost-user.txt
Quoted 21 lines
vhost already has - a separate thread for each queue.
To enable the multiqueue funcionality - a new command line parameter "queues" is introduced for the vhost-user netdev.
Changes since v1:
- uses->nc.info_strwhen bringing up/down the backendSigned-off-by Nikolay Nikolaev <[email protected]>--- docs/specs/vhost-user.txt | 5 +++++ hw/virtio/vhost-user.c | 6 +++++- net/vhost-user.c | 39 +++++++++++++++++++++++++-------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 5 files changed, 43 insertions(+), 18 deletions(-)docs/specs/vhost-user.txt +0
-0I've been thinking that the protocol might be a useful addition to the virtio spec. For this, as a minimum you would have to submit this document as a comment to virtio TC with a proposal to include it in the virtio spec.
See
https://www.oasis-open.org/committees/comments/index.php?wg_abbrev=virtio
Quoted 1 line
Can you do this?
This is actually a great idea. I'll post the document to the comment's list. Do you prefer the upstream version or this one with the MQ additions?
I believe we have to go for the feature negotiation you're proposing and then add MQ,
reconnections etc. as negotiable features on top. So for the first version in virtio spec
we can go with this v1.0 of the vhost-user protocol.
Quoted 3 lines
We can take it from there, though I would encourage your company to join as a contributor.
We'll refrain from joining the TC for the time being, but we may consider it in the future.
Quoted 6 lines
Quoted 6 lines
docs/specs/vhost-user.txt +0
-0@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented.
Quoted 8 lines
docs/specs/vhost-user.txt in the ancillary data: · line 134
Quoted 5 lines
docs/specs/vhost-user.txt +5
-0+Multi queue suport +--------------------- +The protocol supports multiple queues by setting all index fields in the sent +messages to a properly calculated value. +Something that's not clear from this document is what happens with control VQ. Can you clarify please?
Well, the control VQ is a property of the virtio net device. The vhost-user protocol operates
at the generic virtio level. It has not defined specifics for the different device types.
It is true that the current implementation handles the control VQ in QEMU itself. This is
because vhost-user was modeled over the 'tap' backend which exposes only the Rx/Tx queues to the
vhost-net kernel module.
I believe this doc should stay as generic as possible, but still we can add a note about the
current implementation. Something like:
NOTE: the current vhost-user implementation has no virtio device specifics. In that sense
the net device handles the cotrolq in QEMU and this it is not exposed to the slave.
regards,
Nikolay Nikolaev
Quoted 176 lines
Quoted 160 lines
docs/specs/vhost-user.txt +0
-0Message types -------------hw/virtio/vhost-user.c +5
-1@@ -253,17 +253,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_NUM :case VHOST_SET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state);break ;case VHOST_GET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state); need_reply =1 ;break ;case VHOST_SET_VRING_ADDR :memcpy (&msg.addr, arg,sizeof (struct vhost_vring_addr )); + msg.addr.index += dev->vq_index; msg.size =sizeof (m.addr);break ;@@ -271,7 +274,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_CALL :case VHOST_SET_VRING_ERR : file = arg; - msg.u64 = file->index &VHOST_USER_VRING_IDX_MASK ; + msg.u64 = (file->index + dev->vq_index) &VHOST_USER_VRING_IDX_MASK ; msg.size =sizeof (m.u64);if (ioeventfd_enabled () && file->fd >0 ) { fds[fd_num++] = file->fd;@@ -313,6 +316,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,error_report ("Received bad msg size.\n" );return -1 ; } + msg.state.index -= dev->vq_index;memcpy (arg, &msg.state,sizeof (struct vhost_vring_state ));break ;default :net/vhost-user.c +25
-14@@ -122,37 +122,39 @@ static void net_vhost_user_event(void *opaque, int event)case CHR_EVENT_OPENED :vhost_user_start (s);net_vhost_link_down (s, false); -error_report ("chardev \"%s\" went up\n" , s->chr->label); +error_report ("chardev \"%s\" went up\n" , s->nc.info_str);break ;case CHR_EVENT_CLOSED :net_vhost_link_down (s, true);vhost_user_stop (s); -error_report ("chardev \"%s\" went down\n" , s->chr->label); +error_report ("chardev \"%s\" went down\n" , s->nc.info_str);break ; } }static int net_vhost_user_init (NetClientState *peer,const char *device,const char *name,CharDriverState *chr, -bool vhostforce) +bool vhostforce,uint32_t queues) {NetClientState *nc;VhostUserState *s; +int i; - nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); +for (i =0 ; i < queues; i++) { + nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); -snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user to %s" , - chr->label); +snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user%d to %s" , + i, chr->label); - s =DO_UPCAST (VhostUserState, nc, nc); + s =DO_UPCAST (VhostUserState, nc, nc); -/* We don't provide a receive callback */ - s->nc.receive_disabled =1 ; - s->chr = chr; - s->vhostforce = vhostforce; - -qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); +/* We don't provide a receive callback */ + s->nc.receive_disabled =1 ; + s->chr = chr; + s->vhostforce = vhostforce; +qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); + }return 0 ; }@@ -228,6 +230,7 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque)int net_init_vhost_user (const NetClientOptions *opts,const char *name,NetClientState *peer) { +uint32_t queues;const NetdevVhostUserOptions *vhost_user_opts;CharDriverState *chr;bool vhostforce;@@ -254,5 +257,13 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name, vhostforce = false; } -return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce); +/* number of queues for multiqueue */ +if (vhost_user_opts->has_queues) { + queues = vhost_user_opts->queues; + }else { + queues =1 ; + } + +return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce, + queues); }qapi-schema.json +5
-1@@ -2287,12 +2287,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user +# (Since 2.3) +# # Since 2.1 ## { 'type': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } } ## # @NetClientOptionsqemu-options.hx +1
-1@@ -1894,13 +1894,14 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the required hub automatically. -@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off] +@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n]qemu-options.hx The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single · line 1907
Quoted 10 lines
qemu-options.hx +2
-1Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should be a unix domain socket backed one. The vhost-user uses a specifically defined protocol to pass vhost ioctl replacement messages to an application on the other end of the socket. On non-MSIX guests, the feature can be forced with -@var{vhostforce}. +@var{vhostforce}. Use 'queues=@var{n}' to specify the number of queues to +be created for multiqueue vhost-user. Example: @example--
You received this message because you are subscribed to the Google Groups "Snabb Switch development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send an email to [email protected].
Visit this group at http://groups.google.com/group/snabb-devel.
Hi guys,
Quoted 89 lines
-----Original Message-----
From: [email protected] [mailto:snabb- [email protected]] On Behalf Of Michael S. Tsirkin
Sent: Monday, April 6, 2015 11:07 PM
To: Nikolay Nikolaev
Cc: Long, Thomas; [email protected]; [email protected]; [email protected]; [email protected]
Subject: [snabb-devel] Re: [PATCH v2] vhost-user: add multi queue supportQuoted 2 lines · Nikolay Nikolaev
Vhost-user will implement the multiqueueu support in a similar way to what
multiqueue
docs/specs/vhost-user.txt
Quoted 21 lines
vhost already has - a separate thread for each queue.
To enable the multiqueue funcionality - a new command line parameter "queues" is introduced for the vhost-user netdev.
Changes since v1:
- uses->nc.info_strwhen bringing up/down the backendSigned-off-by Nikolay Nikolaev <[email protected]>--- docs/specs/vhost-user.txt | 5 +++++ hw/virtio/vhost-user.c | 6 +++++- net/vhost-user.c | 39 +++++++++++++++++++++++++-------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 5 files changed, 43 insertions(+), 18 deletions(-)docs/specs/vhost-user.txt +0
-0I've been thinking that the protocol might be a useful addition to the virtio spec. For this, as a minimum you would have to submit this document as a comment to virtio TC with a proposal to include it in the virtio spec. See
https://www.oasis-
open.org/committees/comments/index.php?wg_abbrev=virtioCan you do this?
We can take it from there, though I would encourage your company to join as a contributor.
Quoted 3 lines
docs/specs/vhost-user.txt +0
-0@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrongreply it will close the connection. An optional reconnection mechanism can
be implemented.
docs/specs/vhost-user.txt
Quoted 6 lines
docs/specs/vhost-user.txt +5
-0+Multi queue suport +--------------------- +The protocol supports multiple queues by setting all index fields in +the sent messages to a properly calculated value. +Something that's not clear from this document is what happens with control VQ.
Can you clarify please?hw/virtio/vhost-user.c static int vhost_user_call(struct vhost_dev *dev,
Quoted 8 lines
Message types
-------------hw/virtio/vhost-user.c index renamed from hw/virtio/vhost-user.c +0
-0aefe0bb..83ebcaa 100644
hw/virtio/vhost-user.c +0
-0@@ -253,17 +253,20 @@ static int vhost_user_call(struct vhost_dev *dev,unsigned long int request,
Quoted 14 lines
hw/virtio/vhost-user.c +2
-0case VHOST_SET_VRING_NUM :case VHOST_SET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state);break ;case VHOST_GET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state); need_reply =1 ;break ;
Quoted 14 lines
hw/virtio/vhost-user.c static int vhost_user_call(struct vhost_dev *dev,
Quoted 7 lines
hw/virtio/vhost-user.c +1
-0case VHOST_SET_VRING_ADDR :memcpy (&msg.addr, arg,sizeof (struct vhost_vring_addr )); + msg.addr.index += dev->vq_index; msg.size =sizeof (m.addr);break ;@@ -271,7 +274,7 @@ static int vhost_user_call(struct vhost_dev *dev,unsigned long int request,
Quoted 6 lines
hw/virtio/vhost-user.c +2
-1case VHOST_SET_VRING_CALL :case VHOST_SET_VRING_ERR : file = arg; - msg.u64 = file->index &VHOST_USER_VRING_IDX_MASK ; + msg.u64 = (file->index + dev->vq_index) & +VHOST_USER_VRING_IDX_MASK ;
I identify one vq_index issue here when it is the case of VHOST_SET_VRING_CALL,
The vq_index is not initialized before it is used here, so it could be a random value.
It leads to error in vhost, when this random value is passed to vhost and vhost use this random value to set the vring call.
I have a quick fix for this, code changes as the following:
hw/net/vhost_net.c +1 -0
@@ -157,6 +157,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) net->dev.nvqs =2 ; net->dev.vqs = net->vqs; + net->dev.vq_index = net->nc->queue_index; r =vhost_dev_init (&net->dev, options->opaque, options->backend_type, options->force);
net/vhost-user.c +1 -0
@@ -152,6 +152,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, s->nc.receive_disabled =1 ; s->chr = chr; s->vhostforce = vhostforce; + s->nc.queue_index = i;qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); }
Would you guys have a look at this issue?
And I also met other issues when I try to run with 2 virtio ports, each one has 2 queues But not root cause yet, need further investigate,
So I think it may have more issues in qemu for vhost user multiple queues enabling.
Quoted 144 lines
net/vhost-user.c static void net_vhost_user_event(void *opaque,
Quoted 16 lines
hw/virtio/vhost-user.c +0
-0msg.size =sizeof (m.u64);if (ioeventfd_enabled () && file->fd >0 ) { fds[fd_num++] = file->fd; @@ -313,6 +316,7 @@ static intvhost_user_call(struct
vhost_dev*dev, unsigned long int request,error_report("Received bad msg size.\n"); return -1; }hw/virtio/vhost-user.c +1
-0+ msg.state.index -= dev->vq_index;memcpy (arg, &msg.state,sizeof (struct vhost_vring_state ));break ;default :net/vhost-user.c index renamed from net/vhost-user.c +0
-024e050c..a0b4af2 100644
net/vhost-user.c +0
-0@@ -122,37 +122,39 @@ static void net_vhost_user_event(void *opaque,int event)
Quoted 15 lines
net/vhost-user.c +2
-2case CHR_EVENT_OPENED :vhost_user_start (s);net_vhost_link_down (s, false); -error_report ("chardev \"%s\" went up\n" , s->chr->label); +error_report ("chardev \"%s\" went up\n" , s->nc.info_str);break ;case CHR_EVENT_CLOSED :net_vhost_link_down (s, true);vhost_user_stop (s); -error_report ("chardev \"%s\" went down\n" , s->chr->label); +error_report ("chardev \"%s\" went down\n" , s->nc.info_str);break ; } }net/vhost-user.c static void net_vhost_user_event(void *opaque, · line 142
Quoted 10 lines
net/vhost-user.c +2
-2static int net_vhost_user_init (NetClientState *peer,const char *device,const char *name,CharDriverState *chr, -bool vhostforce) +bool vhostforce,uint32_t queues) {NetClientState *nc;VhostUserState *s; +int i; - nc = qemu_new_net_client(&net_vhost_user_info, peer, device,name);
Quoted 8 lines
net/vhost-user.c +5
-2+for (i =0 ; i < queues; i++) { + nc =qemu_new_net_client (&net_vhost_user_info, peer, device, + name); -snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user to %s" , - chr->label); +snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user%d to %s" , + i, chr->label);net/vhost-user.c static void net_vhost_user_event(void *opaque, · line 154
Quoted 10 lines
net/vhost-user.c +1
-7- s =DO_UPCAST (VhostUserState, nc, nc); + s =DO_UPCAST (VhostUserState, nc, nc); -/* We don't provide a receive callback */ - s->nc.receive_disabled =1 ; - s->chr = chr; - s->vhostforce = vhostforce; - - qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event,s);
net/vhost-user.c static void net_vhost_user_event(void *opaque, · line 157
Quoted 6 lines
net/vhost-user.c +5
-0+/* We don't provide a receive callback */ + s->nc.receive_disabled =1 ; + s->chr = chr; + s->vhostforce = vhostforce; + qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event,s);
net/vhost-user.c static int net_vhost_check_net(QemuOpts *opts, · line 230
Quoted 6 lines
net/vhost-user.c +1
-0+ }return 0 ; }@@ -228,6 +230,7 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque) int net_init_vhost_user(const NetClientOptions *opts,const char *name,
net/vhost-user.c int net_init_vhost_user(const NetClientOptions
Quoted 6 lines
net/vhost-user.c +1
-0NetClientState *peer) { +uint32_t queues;const NetdevVhostUserOptions *vhost_user_opts;CharDriverState *chr;bool vhostforce;@@ -254,5 +257,13 @@ int net_init_vhost_user(const NetClientOptions*opts, const char *name,
Quoted 19 lines
net/vhost-user.c +9
-1vhostforce = false; } -return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce); +/* number of queues for multiqueue */ +if (vhost_user_opts->has_queues) { + queues = vhost_user_opts->queues; + }else { + queues =1 ; + } + +return net_vhost_user_init (peer,"vhost_user" , name, chr, vhostforce, + queues); }qapi-schema.json index renamed from qapi-schema.json +0
-0e16f8eb..c2cead0 100644
qapi-schema.json line 2288
Quoted 2 lines
qapi-schema.json +0
-0@@ -2287,12 +2287,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default:false).
qapi-schema.json line 2290
Quoted 2 lines
qapi-schema.json +1
-0# +# @queues: #optional number of queues to be created for multiqueuevhost-user
Quoted 18 lines
qapi-schema.json +4
-1+# (Since 2.3) +# # Since 2.1 ## { 'type': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } } ## # @NetClientOptionsqemu-options.hx index 85ca3ad..b5fa61f renamed from qemu-options.hx +0
-0100644
qemu-options.hx +0
-0@@ -1894,13 +1894,14 @@ The hubport netdev lets you connect a NIC to aQuoted 2 lines
QEMU "vlan" instead of a single netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the required hub
automatically.
Quoted 15 lines
-@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off] +@item -netdev +vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n]
Establish a vhost-user netdev, backed by a chardev @var{id}. The
chardev should be a unix domain socket backed one. The vhost-user uses a specifically defined protocol to pass vhost ioctl replacement messages to an application on the other end of the socket. On non-MSIX guests, the feature can be forced with -@var{vhostforce}. +@var{vhostforce}. Use 'queues=@var{n}' to specify the number of +queues to be created for multiqueue vhost-user.Example:
@example
PATCH v3 1/1 vhost-user: add multi queue support
In reply to Nikolay NikolaevFrom: Changchun Ouyang <[email protected]>
Based on patch by Nikolay Nikolaev:
Vhost-user will implement the multi queue support in a similar way to what vhost already has - a separate thread for each queue. To enable the multi queue funcionality - a new command line parameter "queues" is introduced for the vhost-user netdev.
---
Changes since v2:
- fix vq index issue for set_vring_call
When it is the case of VHOST_SET_VRING_CALL, The vq_index is not initialized before it is used, thus it could be a random value. The random value lead to crash in vhost after passing down to vhost, as vhost use this random value to index an array index.
- fix the typo in the doc and description
- address vq index for reset_owner
Changes since v1:
- use s->nc.info_str when bringing up/down the backend
docs/specs/vhost-user.txt | 5 +++++ hw/net/vhost_net.c | 3 ++- hw/virtio/vhost-user.c | 11 ++++++++++- net/vhost-user.c | 37 ++++++++++++++++++++++++------------- qapi-schema.json | 6 +++++- qemu-options.hx | 5 +++-- 6 files changed, 49 insertions(+), 18 deletions(-)
docs/specs/vhost-user.txt +5 -0
@@ -127,6 +127,11 @@ in the ancillary data: If Master is unable to send the full message or receives a wrong reply it will close the connection. An optional reconnection mechanism can be implemented. +Multi queue support +------------------- +The protocol supports multiple queues by setting all index fields in the sent +messages to a properly calculated value. + Message types -------------
hw/net/vhost_net.c +2 -1
@@ -157,6 +157,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) net->dev.nvqs =2 ; net->dev.vqs = net->vqs; + net->dev.vq_index = net->nc->queue_index; r =vhost_dev_init (&net->dev, options->opaque, options->backend_type, options->force);
@@ -267,7 +268,7 @@ static void vhost_net_stop_one(struct vhost_net *net,for (file.index =0 ; file.index < net->dev.nvqs; ++file.index) {const VhostOps *vhost_ops = net->dev.vhost_ops;int r = vhost_ops->vhost_call (&net->dev,VHOST_RESET_OWNER , -NULL ); + &file);assert (r >=0 ); } }
hw/virtio/vhost-user.c +10 -1
@@ -210,7 +210,12 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,break ;case VHOST_SET_OWNER : +break ; +case VHOST_RESET_OWNER : +memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; + msg.size =sizeof (m.state);break ;case VHOST_SET_MEM_TABLE :
@@ -253,17 +258,20 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_NUM :case VHOST_SET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state);break ;case VHOST_GET_VRING_BASE :memcpy (&msg.state, arg,sizeof (struct vhost_vring_state )); + msg.state.index += dev->vq_index; msg.size =sizeof (m.state); need_reply =1 ;break ;case VHOST_SET_VRING_ADDR :memcpy (&msg.addr, arg,sizeof (struct vhost_vring_addr )); + msg.addr.index += dev->vq_index; msg.size =sizeof (m.addr);break ;
@@ -271,7 +279,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,case VHOST_SET_VRING_CALL :case VHOST_SET_VRING_ERR : file = arg; - msg.u64 = file->index &VHOST_USER_VRING_IDX_MASK ; + msg.u64 = (file->index + dev->vq_index) &VHOST_USER_VRING_IDX_MASK ; msg.size =sizeof (m.u64);if (ioeventfd_enabled () && file->fd >0 ) { fds[fd_num++] = file->fd;
@@ -313,6 +321,7 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,error_report ("Received bad msg size." );return -1 ; } + msg.state.index -= dev->vq_index;memcpy (arg, &msg.state,sizeof (struct vhost_vring_state ));break ;default :
net/vhost-user.c +24 -13
@@ -121,35 +121,39 @@ static void net_vhost_user_event(void *opaque, int event)case CHR_EVENT_OPENED :vhost_user_start (s);net_vhost_link_down (s, false); -error_report ("chardev \"%s\" went up" , s->chr->label); +error_report ("chardev \"%s\" went up\n" , s->nc.info_str);break ;case CHR_EVENT_CLOSED :net_vhost_link_down (s, true);vhost_user_stop (s); -error_report ("chardev \"%s\" went down" , s->chr->label); +error_report ("chardev \"%s\" went down\n" , s->nc.info_str);break ; } }static int net_vhost_user_init (NetClientState *peer,const char *device, -const char *name,CharDriverState *chr) +const char *name,CharDriverState *chr, +uint32_t queues) {NetClientState *nc;VhostUserState *s; +int i; - nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); +for (i =0 ; i < queues; i++) { + nc =qemu_new_net_client (&net_vhost_user_info, peer, device, name); -snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user to %s" , - chr->label); +snprintf (nc->info_str,sizeof (nc->info_str),"vhost-user%d to %s" , + i, chr->label); - s =DO_UPCAST (VhostUserState, nc, nc); + s =DO_UPCAST (VhostUserState, nc, nc); -/* We don't provide a receive callback */ - s->nc.receive_disabled =1 ; - s->chr = chr; - -qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); +/* We don't provide a receive callback */ + s->nc.receive_disabled =1 ; + s->chr = chr; + s->nc.queue_index = i; +qemu_chr_add_handlers (s->chr,NULL ,NULL , net_vhost_user_event, s); + }return 0 ; }
@@ -225,6 +229,7 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque)int net_init_vhost_user (const NetClientOptions *opts,const char *name,NetClientState *peer) { +uint32_t queues;const NetdevVhostUserOptions *vhost_user_opts;CharDriverState *chr;
@@ -243,6 +248,12 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,return -1 ; } +/* number of queues for multiqueue */ +if (vhost_user_opts->has_queues) { + queues = vhost_user_opts->queues; + }else { + queues =1 ; + } -return net_vhost_user_init (peer,"vhost_user" , name, chr); +return net_vhost_user_init (peer,"vhost_user" , name, chr, queues); }
qapi-schema.json +5 -1
@@ -2444,12 +2444,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user (default: 1). +# (Since 2.4) +# # Since 2.1 ## { 'struct': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } } ## # @NetClientOptions
qemu-options.hx +3 -2
@@ -1942,13 +1942,14 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the required hub automatically. -@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off] +@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n] Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should be a unix domain socket backed one. The vhost-user uses a specifically defined protocol to pass vhost ioctl replacement messages to an application on the other end of the socket. On non-MSIX guests, the feature can be forced with -@var{vhostforce}. +@var{vhostforce}. Use 'queues=@var{n}' to specify the number of queues to +be created for multiqueue vhost-user. Example: @example
Signature · 1 line
1.8.4.2
Quoted 2 lines · Ouyang Changchun
From: Changchun Ouyang <[email protected]>
It's better to post a v3 patch as a new top-level thread, rather than in-reply-to an existing thread.
Quoted 4 lines
Based on patch by Nikolay Nikolaev:
Vhost-user will implement the multi queue support in a similar way to what vhost already has - a separate thread for each queue. To enable the multi queue funcionality - a new command line parameter
s/funcionality/functionality/
Quoted 15 lines
"queues" is introduced for the vhost-user netdev.
Signed-off-by Nikolay Nikolaev <[email protected]>Signed-off-by Changchun Ouyang <[email protected]>---
Changes since v2:
- fix vq index issue forset_vring_call
When it is the case ofVHOST_SET_VRING_CALL, Thevq_indexis not initialized before it is used, thus it could be a random value. The random value lead to crash in vhost after passing down to vhost, as vhost use this random value to index an array index.
- fix the typo in the doc and description
- address vq index forreset_owner+++
b/qapi-schema.json
qapi-schema.json line 2447
Quoted 4 lines
qapi-schema.json +1
-0@@ -2444,12 +2444,16 @@ # # @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false). # +# @queues: #optional number of queues to be created for multiqueue vhost-user (default: 1).
Long line; please wrap to fit under 80 columns.
Quoted 10 lines
qapi-schema.json +4
-1+# (Since 2.4) +# # Since 2.1 ## { 'struct': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', - '*vhostforce': 'bool' } } + '*vhostforce': 'bool', + '*queues': 'uint32' } }
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org