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
,
58 VHOST_INVALID_FEATURE_BIT
61 VHostNetState
*vhost_vdpa_get_vhost_net(NetClientState
*nc
)
63 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
64 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
68 uint64_t vhost_vdpa_get_acked_features(NetClientState
*nc
)
70 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
71 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
72 s
->acked_features
= vhost_net_get_acked_features(s
->vhost_net
);
74 return s
->acked_features
;
77 static int vhost_vdpa_net_check_device_id(struct vhost_net
*net
)
81 struct vhost_dev
*hdev
;
83 hdev
= (struct vhost_dev
*)&net
->dev
;
84 ret
= hdev
->vhost_ops
->vhost_get_device_id(hdev
, &device_id
);
85 if (device_id
!= VIRTIO_ID_NET
) {
91 static void vhost_vdpa_del(NetClientState
*ncs
)
94 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
95 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
97 vhost_net_cleanup(s
->vhost_net
);
101 static int vhost_vdpa_add(NetClientState
*ncs
, void *be
)
103 VhostNetOptions options
;
104 struct vhost_net
*net
= NULL
;
108 options
.backend_type
= VHOST_BACKEND_TYPE_VDPA
;
109 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
110 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
111 options
.net_backend
= ncs
;
113 options
.busyloop_timeout
= 0;
115 net
= vhost_net_init(&options
);
117 error_report("failed to init vhost_net for queue");
121 vhost_net_cleanup(s
->vhost_net
);
122 g_free(s
->vhost_net
);
125 ret
= vhost_vdpa_net_check_device_id(net
);
132 vhost_net_cleanup(net
);
138 static void vhost_vdpa_cleanup(NetClientState
*nc
)
140 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
143 vhost_net_cleanup(s
->vhost_net
);
144 g_free(s
->vhost_net
);
149 static bool vhost_vdpa_has_vnet_hdr(NetClientState
*nc
)
151 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
156 static bool vhost_vdpa_has_ufo(NetClientState
*nc
)
158 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
159 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
160 uint64_t features
= 0;
161 features
|= (1ULL << VIRTIO_NET_F_HOST_UFO
);
162 features
= vhost_net_get_features(s
->vhost_net
, features
);
163 return !!(features
& (1ULL << VIRTIO_NET_F_HOST_UFO
));
167 static NetClientInfo net_vhost_vdpa_info
= {
168 .type
= NET_CLIENT_DRIVER_VHOST_VDPA
,
169 .size
= sizeof(VhostVDPAState
),
170 .cleanup
= vhost_vdpa_cleanup
,
171 .has_vnet_hdr
= vhost_vdpa_has_vnet_hdr
,
172 .has_ufo
= vhost_vdpa_has_ufo
,
175 static int net_vhost_vdpa_init(NetClientState
*peer
, const char *device
,
176 const char *name
, const char *vhostdev
)
178 NetClientState
*nc
= NULL
;
180 int vdpa_device_fd
= -1;
183 nc
= qemu_new_net_client(&net_vhost_vdpa_info
, peer
, device
, name
);
184 snprintf(nc
->info_str
, sizeof(nc
->info_str
), TYPE_VHOST_VDPA
);
186 s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
187 vdpa_device_fd
= qemu_open_old(vhostdev
, O_RDWR
);
188 if (vdpa_device_fd
== -1) {
191 s
->vhost_vdpa
.device_fd
= vdpa_device_fd
;
192 ret
= vhost_vdpa_add(nc
, (void *)&s
->vhost_vdpa
);
193 assert(s
->vhost_net
);
197 static int net_vhost_check_net(void *opaque
, QemuOpts
*opts
, Error
**errp
)
199 const char *name
= opaque
;
200 const char *driver
, *netdev
;
202 driver
= qemu_opt_get(opts
, "driver");
203 netdev
= qemu_opt_get(opts
, "netdev");
204 if (!driver
|| !netdev
) {
207 if (strcmp(netdev
, name
) == 0 &&
208 !g_str_has_prefix(driver
, "virtio-net-")) {
209 error_setg(errp
, "vhost-vdpa requires frontend driver virtio-net-*");
215 int net_init_vhost_vdpa(const Netdev
*netdev
, const char *name
,
216 NetClientState
*peer
, Error
**errp
)
218 const NetdevVhostVDPAOptions
*opts
;
220 assert(netdev
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
221 opts
= &netdev
->u
.vhost_vdpa
;
222 /* verify net frontend */
223 if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net
,
224 (char *)name
, errp
)) {
227 return net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
, opts
->vhostdev
);