1 // SPDX-License-Identifier: GPL-2.0
7 #include <sys/eventfd.h>
11 #include <sys/ioctl.h>
13 #include <sys/types.h>
16 #include <linux/vhost.h>
18 #include <linux/if_tun.h>
20 #include <linux/if_packet.h>
21 #include <linux/virtio_net.h>
22 #include <netinet/ether.h>
24 #define HDR_LEN sizeof(struct virtio_net_hdr_mrg_rxbuf)
25 #define TEST_BUF_LEN 256
26 #define TEST_PTYPE ETH_P_LOOPBACK
29 /* Used by implementation of kmalloc() in tools/virtio/linux/kernel.h */
30 void *__kmalloc_fake
, *__kfree_ignore_start
, *__kfree_ignore_end
;
40 /* copy used for control */
46 struct virtio_device vdev
;
48 struct vq_info vqs
[2];
54 struct vhost_memory
*mem
;
57 unsigned char mac
[ETHER_ADDR_LEN
];
60 static int tun_alloc(struct vdev_info
*dev
, char *tun_name
)
66 fd
= open("/dev/net/tun", O_RDWR
);
68 perror("Cannot open /dev/net/tun");
72 memset(&ifr
, 0, sizeof(ifr
));
74 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
| IFF_VNET_HDR
;
75 strncpy(ifr
.ifr_name
, tun_name
, IFNAMSIZ
);
77 e
= ioctl(fd
, TUNSETIFF
, &ifr
);
79 perror("ioctl[TUNSETIFF]");
84 e
= ioctl(fd
, TUNSETVNETHDRSZ
, &len
);
86 perror("ioctl[TUNSETVNETHDRSZ]");
91 e
= ioctl(fd
, SIOCGIFHWADDR
, &ifr
);
93 perror("ioctl[SIOCGIFHWADDR]");
98 memcpy(dev
->mac
, &ifr
.ifr_hwaddr
.sa_data
, ETHER_ADDR_LEN
);
102 static void vdev_create_socket(struct vdev_info
*dev
, char *tun_name
)
106 dev
->sock
= socket(AF_PACKET
, SOCK_RAW
, htons(TEST_PTYPE
));
107 assert(dev
->sock
!= -1);
109 strncpy(ifr
.ifr_name
, tun_name
, IFNAMSIZ
);
110 assert(ioctl(dev
->sock
, SIOCGIFINDEX
, &ifr
) >= 0);
112 dev
->ifindex
= ifr
.ifr_ifindex
;
114 /* Set the flags that bring the device up */
115 assert(ioctl(dev
->sock
, SIOCGIFFLAGS
, &ifr
) >= 0);
116 ifr
.ifr_flags
|= (IFF_UP
| IFF_RUNNING
);
117 assert(ioctl(dev
->sock
, SIOCSIFFLAGS
, &ifr
) >= 0);
120 static void vdev_send_packet(struct vdev_info
*dev
)
122 char *sendbuf
= dev
->test_buf
+ HDR_LEN
;
123 struct sockaddr_ll saddrll
= {0};
124 int sockfd
= dev
->sock
;
127 saddrll
.sll_family
= PF_PACKET
;
128 saddrll
.sll_ifindex
= dev
->ifindex
;
129 saddrll
.sll_halen
= ETH_ALEN
;
130 saddrll
.sll_protocol
= htons(TEST_PTYPE
);
132 ret
= sendto(sockfd
, sendbuf
, TEST_BUF_LEN
, 0,
133 (struct sockaddr
*)&saddrll
,
134 sizeof(struct sockaddr_ll
));
138 static bool vq_notify(struct virtqueue
*vq
)
140 struct vq_info
*info
= vq
->priv
;
141 unsigned long long v
= 1;
144 r
= write(info
->kick
, &v
, sizeof(v
));
145 assert(r
== sizeof(v
));
150 static void vhost_vq_setup(struct vdev_info
*dev
, struct vq_info
*info
)
152 struct vhost_vring_addr addr
= {
154 .desc_user_addr
= (uint64_t)(unsigned long)info
->vring
.desc
,
155 .avail_user_addr
= (uint64_t)(unsigned long)info
->vring
.avail
,
156 .used_user_addr
= (uint64_t)(unsigned long)info
->vring
.used
,
158 struct vhost_vring_state state
= { .index
= info
->idx
};
159 struct vhost_vring_file file
= { .index
= info
->idx
};
162 state
.num
= info
->vring
.num
;
163 r
= ioctl(dev
->control
, VHOST_SET_VRING_NUM
, &state
);
167 r
= ioctl(dev
->control
, VHOST_SET_VRING_BASE
, &state
);
170 r
= ioctl(dev
->control
, VHOST_SET_VRING_ADDR
, &addr
);
173 file
.fd
= info
->kick
;
174 r
= ioctl(dev
->control
, VHOST_SET_VRING_KICK
, &file
);
178 static void vq_reset(struct vq_info
*info
, int num
, struct virtio_device
*vdev
)
181 vring_del_virtqueue(info
->vq
);
183 memset(info
->ring
, 0, vring_size(num
, 4096));
184 vring_init(&info
->vring
, num
, info
->ring
, 4096);
185 info
->vq
= vring_new_virtqueue(info
->idx
, num
, 4096, vdev
, true, false,
186 info
->ring
, vq_notify
, NULL
, "test");
188 info
->vq
->priv
= info
;
191 static void vq_info_add(struct vdev_info
*dev
, int idx
, int num
, int fd
)
193 struct vhost_vring_file backend
= { .index
= idx
, .fd
= fd
};
194 struct vq_info
*info
= &dev
->vqs
[idx
];
198 info
->kick
= eventfd(0, EFD_NONBLOCK
);
199 r
= posix_memalign(&info
->ring
, 4096, vring_size(num
, 4096));
201 vq_reset(info
, num
, &dev
->vdev
);
202 vhost_vq_setup(dev
, info
);
204 r
= ioctl(dev
->control
, VHOST_NET_SET_BACKEND
, &backend
);
208 static void vdev_info_init(struct vdev_info
*dev
, unsigned long long features
)
210 struct ether_header
*eh
;
213 dev
->vdev
.features
= features
;
214 INIT_LIST_HEAD(&dev
->vdev
.vqs
);
215 spin_lock_init(&dev
->vdev
.vqs_list_lock
);
217 dev
->buf_size
= (HDR_LEN
+ TEST_BUF_LEN
) * 2;
218 dev
->buf
= malloc(dev
->buf_size
);
220 dev
->test_buf
= dev
->buf
;
221 dev
->res_buf
= dev
->test_buf
+ HDR_LEN
+ TEST_BUF_LEN
;
223 memset(dev
->test_buf
, 0, HDR_LEN
+ TEST_BUF_LEN
);
224 eh
= (struct ether_header
*)(dev
->test_buf
+ HDR_LEN
);
225 eh
->ether_type
= htons(TEST_PTYPE
);
226 memcpy(eh
->ether_dhost
, dev
->mac
, ETHER_ADDR_LEN
);
227 memcpy(eh
->ether_shost
, dev
->mac
, ETHER_ADDR_LEN
);
229 for (i
= sizeof(*eh
); i
< TEST_BUF_LEN
; i
++)
230 dev
->test_buf
[i
+ HDR_LEN
] = (char)i
;
232 dev
->control
= open("/dev/vhost-net", O_RDWR
);
233 assert(dev
->control
>= 0);
235 r
= ioctl(dev
->control
, VHOST_SET_OWNER
, NULL
);
238 dev
->mem
= malloc(offsetof(struct vhost_memory
, regions
) +
239 sizeof(dev
->mem
->regions
[0]));
241 memset(dev
->mem
, 0, offsetof(struct vhost_memory
, regions
) +
242 sizeof(dev
->mem
->regions
[0]));
243 dev
->mem
->nregions
= 1;
244 dev
->mem
->regions
[0].guest_phys_addr
= (long)dev
->buf
;
245 dev
->mem
->regions
[0].userspace_addr
= (long)dev
->buf
;
246 dev
->mem
->regions
[0].memory_size
= dev
->buf_size
;
248 r
= ioctl(dev
->control
, VHOST_SET_MEM_TABLE
, dev
->mem
);
251 r
= ioctl(dev
->control
, VHOST_SET_FEATURES
, &features
);
257 static void wait_for_interrupt(struct vq_info
*vq
)
259 unsigned long long val
;
261 poll(&vq
->fds
, 1, 100);
263 if (vq
->fds
.revents
& POLLIN
)
264 read(vq
->fds
.fd
, &val
, sizeof(val
));
267 static void verify_res_buf(char *res_buf
)
271 for (i
= ETHER_HDR_LEN
; i
< TEST_BUF_LEN
; i
++)
272 assert(res_buf
[i
] == (char)i
);
275 static void run_tx_test(struct vdev_info
*dev
, struct vq_info
*vq
,
276 bool delayed
, int bufs
)
278 long long spurious
= 0;
279 struct scatterlist sl
;
284 long started_before
= vq
->started
;
285 long completed_before
= vq
->completed
;
287 virtqueue_disable_cb(vq
->vq
);
289 while (vq
->started
< bufs
&&
290 (vq
->started
- vq
->completed
) < 1) {
291 sg_init_one(&sl
, dev
->test_buf
, HDR_LEN
+ TEST_BUF_LEN
);
292 r
= virtqueue_add_outbuf(vq
->vq
, &sl
, 1,
293 dev
->test_buf
+ vq
->started
,
295 if (unlikely(r
!= 0))
300 if (unlikely(!virtqueue_kick(vq
->vq
))) {
306 if (vq
->started
>= bufs
)
309 /* Flush out completed bufs if any */
310 while (virtqueue_get_buf(vq
->vq
, &len
)) {
313 n
= recvfrom(dev
->sock
, dev
->res_buf
, TEST_BUF_LEN
, 0, NULL
, NULL
);
314 assert(n
== TEST_BUF_LEN
);
315 verify_res_buf(dev
->res_buf
);
322 if (vq
->completed
== completed_before
&& vq
->started
== started_before
)
325 assert(vq
->completed
<= bufs
);
326 assert(vq
->started
<= bufs
);
327 if (vq
->completed
== bufs
)
331 if (virtqueue_enable_cb_delayed(vq
->vq
))
332 wait_for_interrupt(vq
);
334 if (virtqueue_enable_cb(vq
->vq
))
335 wait_for_interrupt(vq
);
338 printf("TX spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
339 spurious
, vq
->started
, vq
->completed
);
342 static void run_rx_test(struct vdev_info
*dev
, struct vq_info
*vq
,
343 bool delayed
, int bufs
)
345 long long spurious
= 0;
346 struct scatterlist sl
;
351 long started_before
= vq
->started
;
352 long completed_before
= vq
->completed
;
355 while (vq
->started
< bufs
&&
356 (vq
->started
- vq
->completed
) < 1) {
357 sg_init_one(&sl
, dev
->res_buf
, HDR_LEN
+ TEST_BUF_LEN
);
359 r
= virtqueue_add_inbuf(vq
->vq
, &sl
, 1,
360 dev
->res_buf
+ vq
->started
,
362 if (unlikely(r
!= 0))
367 vdev_send_packet(dev
);
369 if (unlikely(!virtqueue_kick(vq
->vq
))) {
375 if (vq
->started
>= bufs
)
378 /* Flush out completed bufs if any */
379 while (virtqueue_get_buf(vq
->vq
, &len
)) {
380 struct ether_header
*eh
;
382 eh
= (struct ether_header
*)(dev
->res_buf
+ HDR_LEN
);
384 /* tun netdev is up and running, only handle the
387 if (eh
->ether_type
== htons(TEST_PTYPE
)) {
388 assert(len
== TEST_BUF_LEN
+ HDR_LEN
);
389 verify_res_buf(dev
->res_buf
+ HDR_LEN
);
397 if (vq
->completed
== completed_before
&& vq
->started
== started_before
)
400 assert(vq
->completed
<= bufs
);
401 assert(vq
->started
<= bufs
);
402 if (vq
->completed
== bufs
)
406 printf("RX spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
407 spurious
, vq
->started
, vq
->completed
);
410 static const char optstring
[] = "h";
411 static const struct option longopts
[] = {
421 .name
= "no-event-idx",
429 .name
= "no-indirect",
437 .name
= "no-virtio-1",
441 .name
= "delayed-interrupt",
445 .name
= "no-delayed-interrupt",
451 .has_arg
= required_argument
,
456 .has_arg
= required_argument
,
462 static void help(int status
)
464 fprintf(stderr
, "Usage: vhost_net_test [--help]"
468 " [--delayed-interrupt]"
475 int main(int argc
, char **argv
)
477 unsigned long long features
= (1ULL << VIRTIO_RING_F_INDIRECT_DESC
) |
478 (1ULL << VIRTIO_RING_F_EVENT_IDX
) | (1ULL << VIRTIO_F_VERSION_1
);
479 char tun_name
[IFNAMSIZ
];
480 long nbufs
= 0x100000;
481 struct vdev_info dev
;
482 bool delayed
= false;
486 o
= getopt_long(argc
, argv
, optstring
, longopts
, NULL
);
493 features
&= ~(1ULL << VIRTIO_RING_F_EVENT_IDX
);
498 features
&= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC
);
501 features
&= ~(1ULL << VIRTIO_F_VERSION_1
);
507 nbufs
= strtol(optarg
, NULL
, 10);
517 memset(&dev
, 0, sizeof(dev
));
518 snprintf(tun_name
, IFNAMSIZ
, "tun_%d", getpid());
520 fd
= tun_alloc(&dev
, tun_name
);
523 vdev_info_init(&dev
, features
);
524 vq_info_add(&dev
, 0, DESC_NUM
, fd
);
525 vq_info_add(&dev
, 1, DESC_NUM
, fd
);
526 vdev_create_socket(&dev
, tun_name
);
528 run_rx_test(&dev
, &dev
.vqs
[0], delayed
, nbufs
);
529 run_tx_test(&dev
, &dev
.vqs
[1], delayed
, nbufs
);