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
,
57 VIRTIO_NET_F_GUEST_ANNOUNCE
,
59 VHOST_INVALID_FEATURE_BIT
62 VHostNetState
*vhost_vdpa_get_vhost_net(NetClientState
*nc
)
64 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
65 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
69 uint64_t vhost_vdpa_get_acked_features(NetClientState
*nc
)
71 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
72 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
73 s
->acked_features
= vhost_net_get_acked_features(s
->vhost_net
);
75 return s
->acked_features
;
78 static int vhost_vdpa_net_check_device_id(struct vhost_net
*net
)
82 struct vhost_dev
*hdev
;
84 hdev
= (struct vhost_dev
*)&net
->dev
;
85 ret
= hdev
->vhost_ops
->vhost_get_device_id(hdev
, &device_id
);
86 if (device_id
!= VIRTIO_ID_NET
) {
92 static void vhost_vdpa_del(NetClientState
*ncs
)
95 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
96 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
98 vhost_net_cleanup(s
->vhost_net
);
102 static int vhost_vdpa_add(NetClientState
*ncs
, void *be
)
104 VhostNetOptions options
;
105 struct vhost_net
*net
= NULL
;
109 options
.backend_type
= VHOST_BACKEND_TYPE_VDPA
;
110 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
111 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
112 options
.net_backend
= ncs
;
114 options
.busyloop_timeout
= 0;
116 net
= vhost_net_init(&options
);
118 error_report("failed to init vhost_net for queue");
122 vhost_net_cleanup(s
->vhost_net
);
123 g_free(s
->vhost_net
);
126 ret
= vhost_vdpa_net_check_device_id(net
);
133 vhost_net_cleanup(net
);
139 static void vhost_vdpa_cleanup(NetClientState
*nc
)
141 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
144 vhost_net_cleanup(s
->vhost_net
);
145 g_free(s
->vhost_net
);
148 if (s
->vhost_vdpa
.device_fd
>= 0) {
149 qemu_close(s
->vhost_vdpa
.device_fd
);
150 s
->vhost_vdpa
.device_fd
= -1;
154 static bool vhost_vdpa_has_vnet_hdr(NetClientState
*nc
)
156 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
161 static bool vhost_vdpa_has_ufo(NetClientState
*nc
)
163 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
164 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
165 uint64_t features
= 0;
166 features
|= (1ULL << VIRTIO_NET_F_HOST_UFO
);
167 features
= vhost_net_get_features(s
->vhost_net
, features
);
168 return !!(features
& (1ULL << VIRTIO_NET_F_HOST_UFO
));
172 static NetClientInfo net_vhost_vdpa_info
= {
173 .type
= NET_CLIENT_DRIVER_VHOST_VDPA
,
174 .size
= sizeof(VhostVDPAState
),
175 .cleanup
= vhost_vdpa_cleanup
,
176 .has_vnet_hdr
= vhost_vdpa_has_vnet_hdr
,
177 .has_ufo
= vhost_vdpa_has_ufo
,
180 static int net_vhost_vdpa_init(NetClientState
*peer
, const char *device
,
181 const char *name
, const char *vhostdev
)
183 NetClientState
*nc
= NULL
;
185 int vdpa_device_fd
= -1;
188 nc
= qemu_new_net_client(&net_vhost_vdpa_info
, peer
, device
, name
);
189 snprintf(nc
->info_str
, sizeof(nc
->info_str
), TYPE_VHOST_VDPA
);
191 s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
192 vdpa_device_fd
= qemu_open_old(vhostdev
, O_RDWR
);
193 if (vdpa_device_fd
== -1) {
196 s
->vhost_vdpa
.device_fd
= vdpa_device_fd
;
197 ret
= vhost_vdpa_add(nc
, (void *)&s
->vhost_vdpa
);
198 assert(s
->vhost_net
);
202 static int net_vhost_check_net(void *opaque
, QemuOpts
*opts
, Error
**errp
)
204 const char *name
= opaque
;
205 const char *driver
, *netdev
;
207 driver
= qemu_opt_get(opts
, "driver");
208 netdev
= qemu_opt_get(opts
, "netdev");
209 if (!driver
|| !netdev
) {
212 if (strcmp(netdev
, name
) == 0 &&
213 !g_str_has_prefix(driver
, "virtio-net-")) {
214 error_setg(errp
, "vhost-vdpa requires frontend driver virtio-net-*");
220 int net_init_vhost_vdpa(const Netdev
*netdev
, const char *name
,
221 NetClientState
*peer
, Error
**errp
)
223 const NetdevVhostVDPAOptions
*opts
;
225 assert(netdev
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
226 opts
= &netdev
->u
.vhost_vdpa
;
227 /* verify net frontend */
228 if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net
,
229 (char *)name
, errp
)) {
232 return net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
, opts
->vhostdev
);