4 * Copyright(c) 2017-2018 Intel Corporation.
5 * Copyright(c) 2020 Red Hat, Inc.
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
14 #include "net/vhost_net.h"
15 #include "net/vhost-vdpa.h"
16 #include "hw/virtio/vhost-vdpa.h"
17 #include "qemu/config-file.h"
18 #include "qemu/error-report.h"
19 #include "qemu/option.h"
20 #include "qapi/error.h"
21 #include <sys/ioctl.h>
23 #include "standard-headers/linux/virtio_net.h"
24 #include "monitor/monitor.h"
25 #include "hw/virtio/vhost.h"
27 /* Todo:need to add the multiqueue support here */
28 typedef struct VhostVDPAState
{
30 struct vhost_vdpa vhost_vdpa
;
31 VHostNetState
*vhost_net
;
32 uint64_t acked_features
;
36 const int vdpa_feature_bits
[] = {
37 VIRTIO_F_NOTIFY_ON_EMPTY
,
38 VIRTIO_RING_F_INDIRECT_DESC
,
39 VIRTIO_RING_F_EVENT_IDX
,
43 VIRTIO_NET_F_GUEST_CSUM
,
45 VIRTIO_NET_F_GUEST_TSO4
,
46 VIRTIO_NET_F_GUEST_TSO6
,
47 VIRTIO_NET_F_GUEST_ECN
,
48 VIRTIO_NET_F_GUEST_UFO
,
49 VIRTIO_NET_F_HOST_TSO4
,
50 VIRTIO_NET_F_HOST_TSO6
,
51 VIRTIO_NET_F_HOST_ECN
,
52 VIRTIO_NET_F_HOST_UFO
,
53 VIRTIO_NET_F_MRG_RXBUF
,
55 VIRTIO_F_IOMMU_PLATFORM
,
58 VIRTIO_NET_F_HASH_REPORT
,
59 VIRTIO_NET_F_GUEST_ANNOUNCE
,
61 VHOST_INVALID_FEATURE_BIT
64 VHostNetState
*vhost_vdpa_get_vhost_net(NetClientState
*nc
)
66 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
67 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
71 static int vhost_vdpa_net_check_device_id(struct vhost_net
*net
)
75 struct vhost_dev
*hdev
;
77 hdev
= (struct vhost_dev
*)&net
->dev
;
78 ret
= hdev
->vhost_ops
->vhost_get_device_id(hdev
, &device_id
);
79 if (device_id
!= VIRTIO_ID_NET
) {
85 static void vhost_vdpa_del(NetClientState
*ncs
)
88 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
89 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
91 vhost_net_cleanup(s
->vhost_net
);
95 static int vhost_vdpa_add(NetClientState
*ncs
, void *be
)
97 VhostNetOptions options
;
98 struct vhost_net
*net
= NULL
;
102 options
.backend_type
= VHOST_BACKEND_TYPE_VDPA
;
103 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
104 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
105 options
.net_backend
= ncs
;
107 options
.busyloop_timeout
= 0;
109 net
= vhost_net_init(&options
);
111 error_report("failed to init vhost_net for queue");
115 vhost_net_cleanup(s
->vhost_net
);
116 g_free(s
->vhost_net
);
119 ret
= vhost_vdpa_net_check_device_id(net
);
126 vhost_net_cleanup(net
);
132 static void vhost_vdpa_cleanup(NetClientState
*nc
)
134 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
137 vhost_net_cleanup(s
->vhost_net
);
138 g_free(s
->vhost_net
);
141 if (s
->vhost_vdpa
.device_fd
>= 0) {
142 qemu_close(s
->vhost_vdpa
.device_fd
);
143 s
->vhost_vdpa
.device_fd
= -1;
147 static bool vhost_vdpa_has_vnet_hdr(NetClientState
*nc
)
149 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
154 static bool vhost_vdpa_has_ufo(NetClientState
*nc
)
156 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
157 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
158 uint64_t features
= 0;
159 features
|= (1ULL << VIRTIO_NET_F_HOST_UFO
);
160 features
= vhost_net_get_features(s
->vhost_net
, features
);
161 return !!(features
& (1ULL << VIRTIO_NET_F_HOST_UFO
));
165 static NetClientInfo net_vhost_vdpa_info
= {
166 .type
= NET_CLIENT_DRIVER_VHOST_VDPA
,
167 .size
= sizeof(VhostVDPAState
),
168 .cleanup
= vhost_vdpa_cleanup
,
169 .has_vnet_hdr
= vhost_vdpa_has_vnet_hdr
,
170 .has_ufo
= vhost_vdpa_has_ufo
,
173 static int net_vhost_vdpa_init(NetClientState
*peer
, const char *device
,
174 const char *name
, const char *vhostdev
)
176 NetClientState
*nc
= NULL
;
178 int vdpa_device_fd
= -1;
181 nc
= qemu_new_net_client(&net_vhost_vdpa_info
, peer
, device
, name
);
182 snprintf(nc
->info_str
, sizeof(nc
->info_str
), TYPE_VHOST_VDPA
);
184 s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
185 vdpa_device_fd
= qemu_open_old(vhostdev
, O_RDWR
);
186 if (vdpa_device_fd
== -1) {
189 s
->vhost_vdpa
.device_fd
= vdpa_device_fd
;
190 ret
= vhost_vdpa_add(nc
, (void *)&s
->vhost_vdpa
);
191 assert(s
->vhost_net
);
195 static int net_vhost_check_net(void *opaque
, QemuOpts
*opts
, Error
**errp
)
197 const char *name
= opaque
;
198 const char *driver
, *netdev
;
200 driver
= qemu_opt_get(opts
, "driver");
201 netdev
= qemu_opt_get(opts
, "netdev");
202 if (!driver
|| !netdev
) {
205 if (strcmp(netdev
, name
) == 0 &&
206 !g_str_has_prefix(driver
, "virtio-net-")) {
207 error_setg(errp
, "vhost-vdpa requires frontend driver virtio-net-*");
213 int net_init_vhost_vdpa(const Netdev
*netdev
, const char *name
,
214 NetClientState
*peer
, Error
**errp
)
216 const NetdevVhostVDPAOptions
*opts
;
218 assert(netdev
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
219 opts
= &netdev
->u
.vhost_vdpa
;
220 /* verify net frontend */
221 if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net
,
222 (char *)name
, errp
)) {
225 return net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
, opts
->vhostdev
);