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
);
150 static bool vhost_vdpa_has_vnet_hdr(NetClientState
*nc
)
152 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
157 static bool vhost_vdpa_has_ufo(NetClientState
*nc
)
159 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
160 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
161 uint64_t features
= 0;
162 features
|= (1ULL << VIRTIO_NET_F_HOST_UFO
);
163 features
= vhost_net_get_features(s
->vhost_net
, features
);
164 return !!(features
& (1ULL << VIRTIO_NET_F_HOST_UFO
));
168 static NetClientInfo net_vhost_vdpa_info
= {
169 .type
= NET_CLIENT_DRIVER_VHOST_VDPA
,
170 .size
= sizeof(VhostVDPAState
),
171 .cleanup
= vhost_vdpa_cleanup
,
172 .has_vnet_hdr
= vhost_vdpa_has_vnet_hdr
,
173 .has_ufo
= vhost_vdpa_has_ufo
,
176 static int net_vhost_vdpa_init(NetClientState
*peer
, const char *device
,
177 const char *name
, const char *vhostdev
)
179 NetClientState
*nc
= NULL
;
181 int vdpa_device_fd
= -1;
184 nc
= qemu_new_net_client(&net_vhost_vdpa_info
, peer
, device
, name
);
185 snprintf(nc
->info_str
, sizeof(nc
->info_str
), TYPE_VHOST_VDPA
);
187 s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
188 vdpa_device_fd
= qemu_open_old(vhostdev
, O_RDWR
);
189 if (vdpa_device_fd
== -1) {
192 s
->vhost_vdpa
.device_fd
= vdpa_device_fd
;
193 ret
= vhost_vdpa_add(nc
, (void *)&s
->vhost_vdpa
);
194 assert(s
->vhost_net
);
198 static int net_vhost_check_net(void *opaque
, QemuOpts
*opts
, Error
**errp
)
200 const char *name
= opaque
;
201 const char *driver
, *netdev
;
203 driver
= qemu_opt_get(opts
, "driver");
204 netdev
= qemu_opt_get(opts
, "netdev");
205 if (!driver
|| !netdev
) {
208 if (strcmp(netdev
, name
) == 0 &&
209 !g_str_has_prefix(driver
, "virtio-net-")) {
210 error_setg(errp
, "vhost-vdpa requires frontend driver virtio-net-*");
216 int net_init_vhost_vdpa(const Netdev
*netdev
, const char *name
,
217 NetClientState
*peer
, Error
**errp
)
219 const NetdevVhostVDPAOptions
*opts
;
221 assert(netdev
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
222 opts
= &netdev
->u
.vhost_vdpa
;
223 /* verify net frontend */
224 if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net
,
225 (char *)name
, errp
)) {
228 return net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
, opts
->vhostdev
);