Skip to content

Commit 7b0b67d

Browse files
chejianjlijinxia
authored andcommitted
dm: virtio-net: add vhost net support
One additional command parameter is added for virtio-net to support vhost net. The command line for vhost net is as follows: -s n,virtio-net,tap_xxx,vhost Tracked-On: #1329 Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
1 parent 3fdfaa3 commit 7b0b67d

File tree

1 file changed

+205
-16
lines changed

1 file changed

+205
-16
lines changed

devicemodel/hw/pci/virtio/virtio_net.c

Lines changed: 205 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "pci_core.h"
4646
#include "mevent.h"
4747
#include "virtio.h"
48+
#include "vhost.h"
4849

4950
#define VIRTIO_NET_RINGSZ 1024
5051
#define VIRTIO_NET_MAXSEGS 256
@@ -71,11 +72,18 @@
7172
#define VIRTIO_NET_F_CTRL_VLAN (1 << 19) /* control channel VLAN filtering */
7273
#define VIRTIO_NET_F_GUEST_ANNOUNCE \
7374
(1 << 21) /* guest can send gratuitous pkts */
75+
#define VHOST_NET_F_VIRTIO_NET_HDR \
76+
(1 << 27) /* vhost provides virtio_net_hdr */
7477

7578
#define VIRTIO_NET_S_HOSTCAPS \
7679
(VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \
7780
ACRN_VIRTIO_F_NOTIFY_ON_EMPTY | ACRN_VIRTIO_RING_F_INDIRECT_DESC)
7881

82+
#define VIRTIO_NET_S_VHOSTCAPS \
83+
(ACRN_VIRTIO_F_NOTIFY_ON_EMPTY | ACRN_VIRTIO_RING_F_INDIRECT_DESC | \
84+
ACRN_VIRTIO_RING_F_EVENT_IDX | VIRTIO_NET_F_MRG_RXBUF | \
85+
ACRN_VIRTIO_F_VERSION_1)
86+
7987
/* is address mcast/bcast? */
8088
#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01)
8189

@@ -116,6 +124,16 @@ static int virtio_net_debug;
116124
#define DPRINTF(params) do { if (virtio_net_debug) printf params; } while (0)
117125
#define WPRINTF(params) (printf params)
118126

127+
/*
128+
* vhost device struct
129+
*/
130+
struct vhost_net {
131+
struct vhost_dev vdev;
132+
struct vhost_vq vqs[VIRTIO_NET_MAXQ - 1];
133+
int tapfd;
134+
bool vhost_started;
135+
};
136+
119137
/*
120138
* Per-device struct
121139
*/
@@ -148,13 +166,24 @@ struct virtio_net {
148166
void (*virtio_net_rx)(struct virtio_net *net);
149167
void (*virtio_net_tx)(struct virtio_net *net, struct iovec *iov,
150168
int iovcnt, int len);
169+
170+
struct vhost_net *vhost_net;
171+
bool use_vhost;
151172
};
152173

153174
static void virtio_net_reset(void *vdev);
154175
static void virtio_net_tx_stop(struct virtio_net *net);
155-
static int virtio_net_cfgread(void *vdev, int offset, int size, uint32_t *retval);
156-
static int virtio_net_cfgwrite(void *vdev, int offset, int size, uint32_t value);
176+
static int virtio_net_cfgread(void *vdev, int offset, int size,
177+
uint32_t *retval);
178+
static int virtio_net_cfgwrite(void *vdev, int offset, int size,
179+
uint32_t value);
157180
static void virtio_net_neg_features(void *vdev, uint64_t negotiated_features);
181+
static void virtio_net_set_status(void *vdev, uint64_t status);
182+
static struct vhost_net *vhost_net_init(struct virtio_base *base, int vhostfd,
183+
int tapfd, int vq_idx);
184+
static int vhost_net_deinit(struct vhost_net *vhost_net);
185+
static int vhost_net_start(struct vhost_net *vhost_net);
186+
static int vhost_net_stop(struct vhost_net *vhost_net);
158187

159188
static struct virtio_ops virtio_net_ops = {
160189
"vtnet", /* our name */
@@ -165,7 +194,7 @@ static struct virtio_ops virtio_net_ops = {
165194
virtio_net_cfgread, /* read PCI config */
166195
virtio_net_cfgwrite, /* write PCI config */
167196
virtio_net_neg_features, /* apply negotiated features */
168-
NULL, /* called on guest set status */
197+
virtio_net_set_status, /* called on guest set status */
169198
};
170199

171200
static struct ether_addr *
@@ -603,7 +632,8 @@ virtio_net_tap_open(char *devname)
603632

604633
rc = ioctl(tunfd, TUNSETIFF, (void *)&ifr);
605634
if (rc < 0) {
606-
WPRINTF(("open of tap device %s failed\n", devname));
635+
WPRINTF(("open of tap device %s failed: %d\n",
636+
devname, errno));
607637
close(tunfd);
608638
return -1;
609639
}
@@ -617,6 +647,7 @@ virtio_net_tap_setup(struct virtio_net *net, char *devname)
617647
{
618648
char tbuf[80 + 5]; /* room for "acrn_" prefix */
619649
char *tbuf_ptr;
650+
int vhost_fd = -1;
620651

621652
tbuf_ptr = tbuf;
622653

@@ -648,12 +679,30 @@ virtio_net_tap_setup(struct virtio_net *net, char *devname)
648679
net->tapfd = -1;
649680
}
650681

651-
net->mevp = mevent_add(net->tapfd, EVF_READ,
652-
virtio_net_rx_callback, net);
653-
if (net->mevp == NULL) {
654-
WPRINTF(("Could not register event\n"));
655-
close(net->tapfd);
656-
net->tapfd = -1;
682+
if (net->use_vhost) {
683+
vhost_fd = open("/dev/vhost-net", O_RDWR);
684+
if (vhost_fd < 0)
685+
WPRINTF(("open of vhost-net failed\n"));
686+
else {
687+
net->vhost_net = vhost_net_init(&net->base, vhost_fd,
688+
net->tapfd, 0);
689+
if (!net->vhost_net) {
690+
WPRINTF(("vhost_net_init failed, fallback "
691+
"to userspace virtio\n"));
692+
close(vhost_fd);
693+
vhost_fd = -1;
694+
}
695+
}
696+
}
697+
698+
if (vhost_fd < 0) {
699+
net->mevp = mevent_add(net->tapfd, EVF_READ,
700+
virtio_net_rx_callback, net);
701+
if (net->mevp == NULL) {
702+
WPRINTF(("Could not register event\n"));
703+
close(net->tapfd);
704+
net->tapfd = -1;
705+
}
657706
}
658707
}
659708

@@ -667,6 +716,7 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
667716
struct virtio_net *net;
668717
char *devname;
669718
char *vtopts;
719+
char *opt;
670720
int mac_provided;
671721
pthread_mutexattr_t attr;
672722
int rc;
@@ -710,6 +760,7 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
710760
*/
711761
mac_provided = 0;
712762
net->tapfd = -1;
763+
net->vhost_net = NULL;
713764
if (opts != NULL) {
714765
int err;
715766

@@ -721,13 +772,18 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
721772

722773
(void) strsep(&vtopts, ",");
723774

724-
if (vtopts != NULL) {
725-
err = virtio_net_parsemac(vtopts, net->config.mac);
726-
if (err != 0) {
727-
free(devname);
728-
return err;
775+
while ((opt = strsep(&vtopts, ",")) != NULL) {
776+
if (strcmp("vhost", opt) == 0)
777+
net->use_vhost = true;
778+
else {
779+
err = virtio_net_parsemac(opt,
780+
net->config.mac);
781+
if (err != 0) {
782+
free(devname);
783+
return err;
784+
}
785+
mac_provided = 1;
729786
}
730-
mac_provided = 1;
731787
}
732788

733789
if (strncmp(devname, "tap", 3) == 0 ||
@@ -848,6 +904,35 @@ virtio_net_neg_features(void *vdev, uint64_t negotiated_features)
848904
}
849905
}
850906

907+
static void
908+
virtio_net_set_status(void *vdev, uint64_t status)
909+
{
910+
struct virtio_net *net = vdev;
911+
int rc;
912+
913+
if (!net->vhost_net)
914+
return;
915+
916+
if (!net->vhost_net->vhost_started &&
917+
(status & VIRTIO_CR_STATUS_DRIVER_OK)) {
918+
if (net->mevp) {
919+
mevent_delete(net->mevp);
920+
net->mevp = NULL;
921+
}
922+
923+
rc = vhost_net_start(net->vhost_net);
924+
if (rc < 0) {
925+
WPRINTF(("vhost_net_start failed\n"));
926+
return;
927+
}
928+
} else if (net->vhost_net->vhost_started &&
929+
((status & VIRTIO_CR_STATUS_DRIVER_OK) == 0)) {
930+
rc = vhost_net_stop(net->vhost_net);
931+
if (rc < 0)
932+
WPRINTF(("vhost_net_stop failed\n"));
933+
}
934+
}
935+
851936
static void
852937
virtio_net_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
853938
{
@@ -858,6 +943,13 @@ virtio_net_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
858943

859944
virtio_net_tx_stop(net);
860945

946+
if (net->vhost_net) {
947+
vhost_net_stop(net->vhost_net);
948+
vhost_net_deinit(net->vhost_net);
949+
free(net->vhost_net);
950+
net->vhost_net = NULL;
951+
}
952+
861953
if (net->tapfd >= 0) {
862954
close(net->tapfd);
863955
net->tapfd = -1;
@@ -874,6 +966,103 @@ virtio_net_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
874966
fprintf(stderr, "%s: NULL!\n", __func__);
875967
}
876968

969+
static struct vhost_net *
970+
vhost_net_init(struct virtio_base *base, int vhostfd, int tapfd, int vq_idx)
971+
{
972+
struct vhost_net *vhost_net = NULL;
973+
uint64_t vhost_features = VIRTIO_NET_S_VHOSTCAPS;
974+
uint64_t vhost_ext_features = VHOST_NET_F_VIRTIO_NET_HDR;
975+
uint32_t busyloop_timeout = 0;
976+
int rc;
977+
978+
vhost_net = calloc(1, sizeof(struct vhost_net));
979+
if (!vhost_net) {
980+
WPRINTF(("vhost init out of memory\n"));
981+
goto fail;
982+
}
983+
984+
/* pre-init before calling vhost_dev_init */
985+
vhost_net->vdev.nvqs = ARRAY_SIZE(vhost_net->vqs);
986+
vhost_net->vdev.vqs = vhost_net->vqs;
987+
vhost_net->tapfd = tapfd;
988+
989+
rc = vhost_dev_init(&vhost_net->vdev, base, vhostfd, vq_idx,
990+
vhost_features, vhost_ext_features, busyloop_timeout);
991+
if (rc < 0) {
992+
WPRINTF(("vhost_dev_init failed\n"));
993+
goto fail;
994+
}
995+
996+
return vhost_net;
997+
fail:
998+
if (vhost_net)
999+
free(vhost_net);
1000+
return NULL;
1001+
}
1002+
1003+
static int
1004+
vhost_net_deinit(struct vhost_net *vhost_net)
1005+
{
1006+
return vhost_dev_deinit(&vhost_net->vdev);
1007+
}
1008+
1009+
static int
1010+
vhost_net_start(struct vhost_net *vhost_net)
1011+
{
1012+
int rc;
1013+
1014+
if (vhost_net->vhost_started) {
1015+
WPRINTF(("vhost net already started\n"));
1016+
return 0;
1017+
}
1018+
1019+
rc = vhost_dev_start(&vhost_net->vdev);
1020+
if (rc < 0) {
1021+
WPRINTF(("vhost_dev_start failed\n"));
1022+
goto fail;
1023+
}
1024+
1025+
/* if the backend is the TAP */
1026+
if (vhost_net->tapfd > 0) {
1027+
rc = vhost_net_set_backend(&vhost_net->vdev,
1028+
vhost_net->tapfd);
1029+
if (rc < 0) {
1030+
WPRINTF(("vhost_net_set_backend failed\n"));
1031+
goto fail_set_backend;
1032+
}
1033+
}
1034+
1035+
vhost_net->vhost_started = true;
1036+
return 0;
1037+
1038+
fail_set_backend:
1039+
vhost_dev_stop(&vhost_net->vdev);
1040+
fail:
1041+
return -1;
1042+
}
1043+
1044+
static int
1045+
vhost_net_stop(struct vhost_net *vhost_net)
1046+
{
1047+
int rc;
1048+
1049+
if (!vhost_net->vhost_started) {
1050+
WPRINTF(("vhost net already stopped\n"));
1051+
return 0;
1052+
}
1053+
1054+
/* if the backend is the TAP */
1055+
if (vhost_net->tapfd > 0)
1056+
vhost_net_set_backend(&vhost_net->vdev, -1);
1057+
1058+
rc = vhost_dev_stop(&vhost_net->vdev);
1059+
if (rc < 0)
1060+
WPRINTF(("vhost_dev_stop failed\n"));
1061+
1062+
vhost_net->vhost_started = false;
1063+
return rc;
1064+
}
1065+
8771066
struct pci_vdev_ops pci_ops_virtio_net = {
8781067
.class_name = "virtio-net",
8791068
.vdev_init = virtio_net_init,

0 commit comments

Comments
 (0)