qemu/vhost-net: mergeable buffers support
Subsystems (2)
cover qemu/vhost-net: mergeable buffers support
This adds mergeable buffers support in vhost-net in qemu. With this patch, sending raw packets while vhost-net is active should work as well: important for migration. Compile-tested only for now. David, could you please review and maybe try this out?
The kernel side is in vhost-net-next. I intend for it to got into net-next and then into 2.6.36.
TODO: basic test. migration test, send pull request.
Michael S. Tsirkin (3):
tap: generalize code for different vnet header len
tap: add APIs for vnet header length
vhost_net: mergeable buffers support
hw/vhost_net.c | 23 ++++++++++++++++++++++- net/tap-aix.c | 9 +++++++++ net/tap-bsd.c | 9 +++++++++ net/tap-linux.c | 29 +++++++++++++++++++++++++++++ net/tap-linux.h | 8 ++++++++ net/tap-solaris.c | 9 +++++++++ net/tap-win32.c | 9 +++++++++ net/tap.c | 49 +++++++++++++++++++++++++++++++++++-------------- net/tap.h | 4 ++++ 9 files changed, 134 insertions(+), 15 deletions(-)
Signature · 1 line
MST
RFC PATCH 1/3 tap: generalize code for different vnet header len
Make host vnet header length a structure field in preparation for using this support in linux kernel.
--- net/tap-linux.h | 6 ++++++ net/tap.c | 28 ++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-)
net/tap-linux.h +6 -0
@@ -52,4 +52,10 @@ struct virtio_net_hdr uint16_t csum_offset; }; +struct virtio_net_hdr_mrg_rxbuf +{ +struct virtio_net_hdr hdr; +uint16_t num_buffers;/* Number of merged rx buffers */ +}; +#endif /* QEMU_TAP_H */
net/tap.c +14 -14
@@ -57,10 +57,10 @@ typedef struct TAPState {uint8_t buf[TAP_BUFSIZE ]; unsigned int read_poll : 1; unsigned int write_poll : 1; - unsigned int has_vnet_hdr : 1; unsigned int using_vnet_hdr : 1; unsigned int has_ufo: 1;VHostNetState *vhost_net; +unsigned host_vnet_hdr_len; } TAPState;static int launch_script (const char *setup_script,const char *ifname,int fd);
@@ -121,11 +121,11 @@ static ssize_t tap_receive_iov(VLANClientState *nc, const struct iovec *iov,TAPState *s =DO_UPCAST (TAPState, nc, nc);const struct iovec *iovp = iov;struct iovec iov_copy[iovcnt +1 ]; -struct virtio_net_hdr hdr = {0 , }; +struct virtio_net_hdr_mrg_rxbuf hdr = { }; -if (s->has_vnet_hdr && !s->using_vnet_hdr) { +if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { iov_copy[0 ].iov_base = &hdr; - iov_copy[0 ].iov_len =sizeof (hdr); + iov_copy[0 ].iov_len = s->host_vnet_hdr_len;memcpy (&iov_copy[1 ], iov, iovcnt *sizeof (*iov)); iovp = iov_copy; iovcnt++;
@@ -139,11 +139,11 @@ static ssize_t tap_receive_raw(VLANClientState *nc, const uint8_t *buf, size_t sTAPState *s =DO_UPCAST (TAPState, nc, nc);struct iovec iov[2 ];int iovcnt =0 ; -struct virtio_net_hdr hdr = {0 , }; +struct virtio_net_hdr_mrg_rxbuf hdr = { }; -if (s->has_vnet_hdr) { +if (s->host_vnet_hdr_len) { iov[iovcnt].iov_base = &hdr; - iov[iovcnt].iov_len =sizeof (hdr); + iov[iovcnt].iov_len = s->host_vnet_hdr_len; iovcnt++; }
@@ -159,7 +159,7 @@ static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)TAPState *s =DO_UPCAST (TAPState, nc, nc);struct iovec iov[1 ]; -if (s->has_vnet_hdr && !s->using_vnet_hdr) { +if (s->host_vnet_hdr_len && !s->using_vnet_hdr) {return tap_receive_raw (nc, buf, size); }
@@ -202,9 +202,9 @@ static void tap_send(void *opaque)break ; } -if (s->has_vnet_hdr && !s->using_vnet_hdr) { - buf +=sizeof (struct virtio_net_hdr ); - size -=sizeof (struct virtio_net_hdr ); +if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { + buf += s->host_vnet_hdr_len; + size -= s->host_vnet_hdr_len; } size =qemu_send_packet_async (&s->nc, buf, size, tap_send_completed);
@@ -229,7 +229,7 @@ int tap_has_vnet_hdr(VLANClientState *nc)assert (nc->info->type ==NET_CLIENT_TYPE_TAP ); -return s->has_vnet_hdr; +return !!s->host_vnet_hdr_len; }void tap_using_vnet_hdr (VLANClientState *nc,int using_vnet_hdr)
@@ -239,7 +239,7 @@ void tap_using_vnet_hdr(VLANClientState *nc, int using_vnet_hdr) using_vnet_hdr = using_vnet_hdr !=0 ;assert (nc->info->type ==NET_CLIENT_TYPE_TAP ); -assert (s->has_vnet_hdr == using_vnet_hdr); +assert (!!s->host_vnet_hdr_len == using_vnet_hdr); s->using_vnet_hdr = using_vnet_hdr; }
@@ -310,7 +310,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, s =DO_UPCAST (TAPState, nc, nc); s->fd = fd; - s->has_vnet_hdr = vnet_hdr !=0 ; + s->host_vnet_hdr_len = vnet_hdr ?sizeof (struct virtio_net_hdr ) :0 ; s->using_vnet_hdr =0 ; s->has_ufo =tap_probe_has_ufo (s->fd);tap_set_offload (&s->nc,0 ,0 ,0 ,0 ,0 );
Signature · 1 line
1.7.2.rc0.14.g41c1c
RFC PATCH 2/3 tap: add APIs for vnet header length
In reply to Michael S. TsirkinAdd APIs to control host header length. First user will be vhost-net.
--- net/tap-aix.c | 9 +++++++++ net/tap-bsd.c | 9 +++++++++ net/tap-linux.c | 29 +++++++++++++++++++++++++++++ net/tap-linux.h | 2 ++ net/tap-solaris.c | 9 +++++++++ net/tap-win32.c | 9 +++++++++ net/tap.c | 21 +++++++++++++++++++++ net/tap.h | 4 ++++ 8 files changed, 92 insertions(+), 0 deletions(-)
net/tap-aix.c +9 -0
@@ -46,6 +46,15 @@ int tap_probe_has_ufo(int fd)return 0 ; } +int tap_probe_vnet_hdr_len (int fd,int len) +{ +return 0 ; +} + +void tap_fd_set_vnet_hdr_len (int fd,int len) +{ +} +void tap_fd_set_offload (int fd,int csum,int tso4,int tso6,int ecn,int ufo) {
net/tap-bsd.c +9 -0
@@ -116,6 +116,15 @@ int tap_probe_has_ufo(int fd)return 0 ; } +int tap_probe_vnet_hdr_len (int fd,int len) +{ +return 0 ; +} + +void tap_fd_set_vnet_hdr_len (int fd,int len) +{ +} +void tap_fd_set_offload (int fd,int csum,int tso4,int tso6,int ecn,int ufo) {
net/tap-linux.c +29 -0
@@ -129,6 +129,35 @@ int tap_probe_has_ufo(int fd)return 1 ; } +/* Verify that we can assign given length */ +int tap_probe_vnet_hdr_len (int fd,int len) +{ +int orig; +if (ioctl (fd,TUNGETVNETHDRSZ , &orig) ==-1 ) { +return 0 ; + } +if (ioctl (fd,TUNSETVNETHDRSZ , &len) ==-1 ) { +return 0 ; + } +/* Restore original length: we can't handle failure. */ +if (ioctl (fd,TUNSETVNETHDRSZ , &orig) ==-1 ) { +fprintf (stderr,"TUNGETVNETHDRSZ ioctl() failed: %s. Exiting.\n" , +strerror (errno)); +assert (0 ); +return -errno; + } +return 1 ; +} + +void tap_fd_set_vnet_hdr_len (int fd,int len) +{ +if (ioctl (fd,TUNSETVNETHDRSZ , &len) ==-1 ) { +fprintf (stderr,"TUNSETVNETHDRSZ ioctl() failed: %s. Exiting.\n" , +strerror (errno)); +assert (0 ); + } +} +void tap_fd_set_offload (int fd,int csum,int tso4,int tso6,int ecn,int ufo) {
net/tap-linux.h +2 -0
@@ -27,6 +27,8 @@#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)#define TUNGETIFF _IOR('T', 210, unsigned int)#define TUNSETSNDBUF _IOW('T', 212, int) +#define TUNGETVNETHDRSZ _IOR('T', 215, int) +#define TUNSETVNETHDRSZ _IOW('T', 216, int)#endif
net/tap-solaris.c +9 -0
@@ -211,6 +211,15 @@ int tap_probe_has_ufo(int fd)return 0 ; } +int tap_probe_vnet_hdr_len (int fd,int len) +{ +return 0 ; +} + +void tap_fd_set_vnet_hdr_len (int fd,int len) +{ +} +void tap_fd_set_offload (int fd,int csum,int tso4,int tso6,int ecn,int ufo) {
net/tap-win32.c +9 -0
@@ -728,6 +728,15 @@ int tap_has_vnet_hdr(VLANClientState *vc)return 0 ; } +int tap_probe_vnet_hdr_len (int fd,int len) +{ +return 0 ; +} + +void tap_fd_set_vnet_hdr_len (int fd,int len) +{ +} +void tap_using_vnet_hdr (VLANClientState *vc,int using_vnet_hdr) { }
net/tap.c +21 -0
@@ -232,6 +232,27 @@ int tap_has_vnet_hdr(VLANClientState *nc)return !!s->host_vnet_hdr_len; } +int tap_has_vnet_hdr_len (VLANClientState *nc,int len) +{ +TAPState *s =DO_UPCAST (TAPState, nc, nc); + +assert (nc->info->type ==NET_CLIENT_TYPE_TAP ); + +return tap_probe_vnet_hdr_len (s->fd, len); +} + +void tap_set_vnet_hdr_len (VLANClientState *nc,int len) +{ +TAPState *s =DO_UPCAST (TAPState, nc, nc); + +assert (nc->info->type ==NET_CLIENT_TYPE_TAP ); +assert (len ==sizeof (virtio_net_hdr_mrg) || + len ==sizeof (virtio_net_hdr)); + +tap_fd_set_vnet_hdr_len (s->fd, len); + s->host_vnet_hdr_len = len; +} +void tap_using_vnet_hdr (VLANClientState *nc,int using_vnet_hdr) {TAPState *s =DO_UPCAST (TAPState, nc, nc);
net/tap.h +4 -0
@@ -40,13 +40,17 @@ ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen);int tap_has_ufo (VLANClientState *vc);int tap_has_vnet_hdr (VLANClientState *vc); +int tap_has_vnet_hdr_len (VLANClientState *vc,int len);void tap_using_vnet_hdr (VLANClientState *vc,int using_vnet_hdr);void tap_set_offload (VLANClientState *vc,int csum,int tso4,int tso6,int ecn,int ufo); +void tap_set_vnet_hdr_len (VLANClientState *vc,int len);int tap_set_sndbuf (int fd,QemuOpts *opts);int tap_probe_vnet_hdr (int fd); +int tap_probe_vnet_hdr_len (int fd,int len);int tap_probe_has_ufo (int fd);void tap_fd_set_offload (int fd,int csum,int tso4,int tso6,int ecn,int ufo); +void tap_fd_set_vnet_hdr_len (int fd,int len);int tap_get_fd (VLANClientState *vc);
Signature · 1 line
1.7.2.rc0.14.g41c1c
RFC PATCH 3/3 vhost_net: mergeable buffers support
In reply to Michael S. Tsirkinuse the new tap APIs to set header length
--- hw/vhost_net.c | 23 ++++++++++++++++++++++- 1 files changed, 22 insertions(+), 1 deletions(-)
hw/vhost_net.c +22 -1
@@ -51,7 +51,9 @@ unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)if (!(net->dev.features & (1 <<VIRTIO_RING_F_INDIRECT_DESC ))) { features &= ~(1 <<VIRTIO_RING_F_INDIRECT_DESC ); } - features &= ~(1 <<VIRTIO_NET_F_MRG_RXBUF ); +if (!(net->dev.features & (1 <<VIRTIO_NET_F_MRG_RXBUF ))) { + features &= ~(1 <<VIRTIO_NET_F_MRG_RXBUF ); + }return features; }
@@ -64,6 +66,9 @@ void vhost_net_ack_features(struct vhost_net *net, unsigned features)if (features & (1 <<VIRTIO_RING_F_INDIRECT_DESC )) { net->dev.acked_features |= (1 <<VIRTIO_RING_F_INDIRECT_DESC ); } +if (features & (1 <<VIRTIO_NET_F_MRG_RXBUF )) { + net->dev.acked_features |= (1 <<VIRTIO_NET_F_MRG_RXBUF ); + } }static int vhost_net_get_fd (VLANClientState *backend)
@@ -98,6 +103,10 @@ struct vhost_net *vhost_net_init(VLANClientState *backend, int devfd)if (r <0 ) { goto fail; } +if (!tap_has_vnet_hdr_len (backend, +sizeof (struct virtio_net_hdr_mrg_rxbuf ))) { + net->dev.features &= ~(1 <<VIRTIO_NET_F_MRG_RXBUF ); + }if (~net->dev.features & net->dev.backend_features) {fprintf (stderr,"vhost lacks feature mask %" PRIu64" for backend\n" , (uint64_t )(~net->dev.features & net->dev.backend_features));
@@ -118,6 +127,9 @@ int vhost_net_start(struct vhost_net *net, {struct vhost_vring_file file = { };int r; +if (net->dev.acked_features &VIRTIO_NET_F_MRG_RXBUF ) { +tap_set_vnet_hdr_len (net->backend,sizeof (virtio_net_hdr_mrg_rxbuf)); + } net->dev.nvqs =2 ; net->dev.vqs = net->vqs;
@@ -145,6 +157,9 @@ fail: } net->vc->info->poll (net->vc, true);vhost_dev_stop (&net->dev, dev); +if (net->dev.acked_features &VIRTIO_NET_F_MRG_RXBUF ) { +tap_set_vnet_hdr_len (net->backend,sizeof (virtio_net_hdr)); + }return r; }
@@ -159,11 +174,17 @@ void vhost_net_stop(struct vhost_net *net, } net->vc->info->poll (net->vc, true);vhost_dev_stop (&net->dev, dev); +if (net->dev.acked_features &VIRTIO_NET_F_MRG_RXBUF ) { +tap_set_vnet_hdr_len (net->backend,sizeof (virtio_net_hdr)); + } }void vhost_net_cleanup (struct vhost_net *net) {vhost_dev_cleanup (&net->dev); +if (net->dev.acked_features &VIRTIO_NET_F_MRG_RXBUF ) { +tap_set_vnet_hdr_len (net->backend,sizeof (virtio_net_hdr)); + }qemu_free (net); }#else
Signature · 1 line
1.7.2.rc0.14.g41c1c
Quoted 8 lines · Michael S. Tsirkin
This adds mergeable buffers support in vhost-net in qemu. With this patch, sending raw packets while vhost-net is active should work as well: important for migration. Compile-tested only for now. David, could you please review and maybe try this out?
The kernel side is in vhost-net-next. I intend for it to got into net-next and then into 2.6.36.TODO: basic test. migration test, send pull request.
This is on top of 46c85dab1c2ffa1363c07bf7c161921ff613c0b6 in qemu-kvm.
Quoted 20 lines
Michael S. Tsirkin (3):
tap: generalize code for different vnet header len
tap: add APIs for vnet header length
vhost_net: mergeable buffers supporthw/vhost_net.c | 23 ++++++++++++++++++++++- net/tap-aix.c | 9 +++++++++ net/tap-bsd.c | 9 +++++++++ net/tap-linux.c | 29 +++++++++++++++++++++++++++++ net/tap-linux.h | 8 ++++++++ net/tap-solaris.c | 9 +++++++++ net/tap-win32.c | 9 +++++++++ net/tap.c | 49 +++++++++++++++++++++++++++++++++++-------------- net/tap.h | 4 ++++ 9 files changed, 134 insertions(+), 15 deletions(-)Signature · 1 line
MST