vhost: mergeable buffer support
cover vhost: mergeable buffer support
This adds support for mergeable buffers with vhost. The tun ioctl this relies on is already in 2.6.34, the vhost support for the feature has been submitted for 2.6.36.
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 | 24 +++++++++++++++++++++++- 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, 135 insertions(+), 15 deletions(-)
Signature · 1 line
MST
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.
Signed-off-by Michael S. Tsirkin <[email protected]>
--- 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
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.
Signed-off-by Michael S. Tsirkin <[email protected]>
--- 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
@@ -127,6 +127,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 (struct virtio_net_hdr_mrg_rxbuf ) || + len ==sizeof (struct 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
PATCH 3/3 vhost_net: mergeable buffers support
In reply to Michael S. Tsirkinuse the new tap APIs to set header length
Signed-off-by Michael S. Tsirkin <[email protected]>
--- hw/vhost_net.c | 24 +++++++++++++++++++++++- 1 files changed, 23 insertions(+), 1 deletions(-)
hw/vhost_net.c +23 -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,10 @@ int vhost_net_start(struct vhost_net *net, {struct vhost_vring_file file = { };int r; +if (net->dev.acked_features & (1 <<VIRTIO_NET_F_MRG_RXBUF )) { +tap_set_vnet_hdr_len (net->vc, +sizeof (struct virtio_net_hdr_mrg_rxbuf )); + } net->dev.nvqs =2 ; net->dev.vqs = net->vqs;
@@ -145,6 +158,9 @@ fail: } net->vc->info->poll (net->vc, true);vhost_dev_stop (&net->dev, dev); +if (net->dev.acked_features & (1 <<VIRTIO_NET_F_MRG_RXBUF )) { +tap_set_vnet_hdr_len (net->vc,sizeof (struct virtio_net_hdr )); + }return r; }
@@ -159,11 +175,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 & (1 <<VIRTIO_NET_F_MRG_RXBUF )) { +tap_set_vnet_hdr_len (net->vc,sizeof (struct virtio_net_hdr )); + } }void vhost_net_cleanup (struct vhost_net *net) {vhost_dev_cleanup (&net->dev); +if (net->dev.acked_features & (1 <<VIRTIO_NET_F_MRG_RXBUF )) { +tap_set_vnet_hdr_len (net->vc,sizeof (struct virtio_net_hdr )); + }qemu_free (net); }#else
Signature · 1 line
1.7.2.rc0.14.g41c1c