45
45
#include "pci_core.h"
46
46
#include "mevent.h"
47
47
#include "virtio.h"
48
+ #include "vhost.h"
48
49
49
50
#define VIRTIO_NET_RINGSZ 1024
50
51
#define VIRTIO_NET_MAXSEGS 256
71
72
#define VIRTIO_NET_F_CTRL_VLAN (1 << 19) /* control channel VLAN filtering */
72
73
#define VIRTIO_NET_F_GUEST_ANNOUNCE \
73
74
(1 << 21) /* guest can send gratuitous pkts */
75
+ #define VHOST_NET_F_VIRTIO_NET_HDR \
76
+ (1 << 27) /* vhost provides virtio_net_hdr */
74
77
75
78
#define VIRTIO_NET_S_HOSTCAPS \
76
79
(VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \
77
80
ACRN_VIRTIO_F_NOTIFY_ON_EMPTY | ACRN_VIRTIO_RING_F_INDIRECT_DESC)
78
81
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
+
79
87
/* is address mcast/bcast? */
80
88
#define ETHER_IS_MULTICAST (addr ) (*(addr) & 0x01)
81
89
@@ -116,6 +124,16 @@ static int virtio_net_debug;
116
124
#define DPRINTF (params ) do { if (virtio_net_debug) printf params; } while (0)
117
125
#define WPRINTF (params ) (printf params)
118
126
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
+
119
137
/*
120
138
* Per-device struct
121
139
*/
@@ -148,13 +166,24 @@ struct virtio_net {
148
166
void (* virtio_net_rx )(struct virtio_net * net );
149
167
void (* virtio_net_tx )(struct virtio_net * net , struct iovec * iov ,
150
168
int iovcnt , int len );
169
+
170
+ struct vhost_net * vhost_net ;
171
+ bool use_vhost ;
151
172
};
152
173
153
174
static void virtio_net_reset (void * vdev );
154
175
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 );
157
180
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 );
158
187
159
188
static struct virtio_ops virtio_net_ops = {
160
189
"vtnet" , /* our name */
@@ -165,7 +194,7 @@ static struct virtio_ops virtio_net_ops = {
165
194
virtio_net_cfgread , /* read PCI config */
166
195
virtio_net_cfgwrite , /* write PCI config */
167
196
virtio_net_neg_features , /* apply negotiated features */
168
- NULL , /* called on guest set status */
197
+ virtio_net_set_status , /* called on guest set status */
169
198
};
170
199
171
200
static struct ether_addr *
@@ -603,7 +632,8 @@ virtio_net_tap_open(char *devname)
603
632
604
633
rc = ioctl (tunfd , TUNSETIFF , (void * )& ifr );
605
634
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 ));
607
637
close (tunfd );
608
638
return -1 ;
609
639
}
@@ -617,6 +647,7 @@ virtio_net_tap_setup(struct virtio_net *net, char *devname)
617
647
{
618
648
char tbuf [80 + 5 ]; /* room for "acrn_" prefix */
619
649
char * tbuf_ptr ;
650
+ int vhost_fd = -1 ;
620
651
621
652
tbuf_ptr = tbuf ;
622
653
@@ -648,12 +679,30 @@ virtio_net_tap_setup(struct virtio_net *net, char *devname)
648
679
net -> tapfd = -1 ;
649
680
}
650
681
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
+ }
657
706
}
658
707
}
659
708
@@ -667,6 +716,7 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
667
716
struct virtio_net * net ;
668
717
char * devname ;
669
718
char * vtopts ;
719
+ char * opt ;
670
720
int mac_provided ;
671
721
pthread_mutexattr_t attr ;
672
722
int rc ;
@@ -710,6 +760,7 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
710
760
*/
711
761
mac_provided = 0 ;
712
762
net -> tapfd = -1 ;
763
+ net -> vhost_net = NULL ;
713
764
if (opts != NULL ) {
714
765
int err ;
715
766
@@ -721,13 +772,18 @@ virtio_net_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
721
772
722
773
(void ) strsep (& vtopts , "," );
723
774
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 ;
729
786
}
730
- mac_provided = 1 ;
731
787
}
732
788
733
789
if (strncmp (devname , "tap" , 3 ) == 0 ||
@@ -848,6 +904,35 @@ virtio_net_neg_features(void *vdev, uint64_t negotiated_features)
848
904
}
849
905
}
850
906
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
+
851
936
static void
852
937
virtio_net_deinit (struct vmctx * ctx , struct pci_vdev * dev , char * opts )
853
938
{
@@ -858,6 +943,13 @@ virtio_net_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
858
943
859
944
virtio_net_tx_stop (net );
860
945
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
+
861
953
if (net -> tapfd >= 0 ) {
862
954
close (net -> tapfd );
863
955
net -> tapfd = -1 ;
@@ -874,6 +966,103 @@ virtio_net_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
874
966
fprintf (stderr , "%s: NULL!\n" , __func__ );
875
967
}
876
968
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
+
877
1066
struct pci_vdev_ops pci_ops_virtio_net = {
878
1067
.class_name = "virtio-net" ,
879
1068
.vdev_init = virtio_net_init ,
0 commit comments