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 <linux/vhost.h>
22 #include <sys/ioctl.h>
24 #include "standard-headers/linux/virtio_net.h"
25 #include "monitor/monitor.h"
26 #include "hw/virtio/vhost.h"
28 /* Todo:need to add the multiqueue support here */
29 typedef struct VhostVDPAState
{
31 struct vhost_vdpa vhost_vdpa
;
32 VHostNetState
*vhost_net
;
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
,
56 VIRTIO_NET_F_CTRL_RX_EXTRA
,
57 VIRTIO_NET_F_CTRL_VLAN
,
58 VIRTIO_NET_F_GUEST_ANNOUNCE
,
59 VIRTIO_NET_F_CTRL_MAC_ADDR
,
63 VIRTIO_F_IOMMU_PLATFORM
,
66 VIRTIO_NET_F_HASH_REPORT
,
67 VIRTIO_NET_F_GUEST_ANNOUNCE
,
69 VHOST_INVALID_FEATURE_BIT
72 VHostNetState
*vhost_vdpa_get_vhost_net(NetClientState
*nc
)
74 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
75 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
79 static int vhost_vdpa_net_check_device_id(struct vhost_net
*net
)
83 struct vhost_dev
*hdev
;
85 hdev
= (struct vhost_dev
*)&net
->dev
;
86 ret
= hdev
->vhost_ops
->vhost_get_device_id(hdev
, &device_id
);
87 if (device_id
!= VIRTIO_ID_NET
) {
93 static int vhost_vdpa_add(NetClientState
*ncs
, void *be
,
94 int queue_pair_index
, int nvqs
)
96 VhostNetOptions options
;
97 struct vhost_net
*net
= NULL
;
101 options
.backend_type
= VHOST_BACKEND_TYPE_VDPA
;
102 assert(ncs
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
103 s
= DO_UPCAST(VhostVDPAState
, nc
, ncs
);
104 options
.net_backend
= ncs
;
106 options
.busyloop_timeout
= 0;
109 net
= vhost_net_init(&options
);
111 error_report("failed to init vhost_net for queue");
115 ret
= vhost_vdpa_net_check_device_id(net
);
121 vhost_net_cleanup(net
);
127 static void vhost_vdpa_cleanup(NetClientState
*nc
)
129 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
132 vhost_net_cleanup(s
->vhost_net
);
133 g_free(s
->vhost_net
);
136 if (s
->vhost_vdpa
.device_fd
>= 0) {
137 qemu_close(s
->vhost_vdpa
.device_fd
);
138 s
->vhost_vdpa
.device_fd
= -1;
142 static bool vhost_vdpa_has_vnet_hdr(NetClientState
*nc
)
144 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
149 static bool vhost_vdpa_has_ufo(NetClientState
*nc
)
151 assert(nc
->info
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
152 VhostVDPAState
*s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
153 uint64_t features
= 0;
154 features
|= (1ULL << VIRTIO_NET_F_HOST_UFO
);
155 features
= vhost_net_get_features(s
->vhost_net
, features
);
156 return !!(features
& (1ULL << VIRTIO_NET_F_HOST_UFO
));
160 static bool vhost_vdpa_check_peer_type(NetClientState
*nc
, ObjectClass
*oc
,
163 const char *driver
= object_class_get_name(oc
);
165 if (!g_str_has_prefix(driver
, "virtio-net-")) {
166 error_setg(errp
, "vhost-vdpa requires frontend driver virtio-net-*");
173 /** Dummy receive in case qemu falls back to userland tap networking */
174 static ssize_t
vhost_vdpa_receive(NetClientState
*nc
, const uint8_t *buf
,
180 static NetClientInfo net_vhost_vdpa_info
= {
181 .type
= NET_CLIENT_DRIVER_VHOST_VDPA
,
182 .size
= sizeof(VhostVDPAState
),
183 .receive
= vhost_vdpa_receive
,
184 .cleanup
= vhost_vdpa_cleanup
,
185 .has_vnet_hdr
= vhost_vdpa_has_vnet_hdr
,
186 .has_ufo
= vhost_vdpa_has_ufo
,
187 .check_peer_type
= vhost_vdpa_check_peer_type
,
190 static NetClientState
*net_vhost_vdpa_init(NetClientState
*peer
,
194 int queue_pair_index
,
198 NetClientState
*nc
= NULL
;
203 nc
= qemu_new_net_client(&net_vhost_vdpa_info
, peer
, device
,
206 nc
= qemu_new_net_control_client(&net_vhost_vdpa_info
, peer
,
209 snprintf(nc
->info_str
, sizeof(nc
->info_str
), TYPE_VHOST_VDPA
);
210 s
= DO_UPCAST(VhostVDPAState
, nc
, nc
);
212 s
->vhost_vdpa
.device_fd
= vdpa_device_fd
;
213 s
->vhost_vdpa
.index
= queue_pair_index
;
214 ret
= vhost_vdpa_add(nc
, (void *)&s
->vhost_vdpa
, queue_pair_index
, nvqs
);
216 qemu_del_net_client(nc
);
222 static int vhost_vdpa_get_max_queue_pairs(int fd
, int *has_cvq
, Error
**errp
)
224 unsigned long config_size
= offsetof(struct vhost_vdpa_config
, buf
);
225 g_autofree
struct vhost_vdpa_config
*config
= NULL
;
226 __virtio16
*max_queue_pairs
;
230 ret
= ioctl(fd
, VHOST_GET_FEATURES
, &features
);
232 error_setg(errp
, "Fail to query features from vhost-vDPA device");
236 if (features
& (1 << VIRTIO_NET_F_CTRL_VQ
)) {
242 if (features
& (1 << VIRTIO_NET_F_MQ
)) {
243 config
= g_malloc0(config_size
+ sizeof(*max_queue_pairs
));
244 config
->off
= offsetof(struct virtio_net_config
, max_virtqueue_pairs
);
245 config
->len
= sizeof(*max_queue_pairs
);
247 ret
= ioctl(fd
, VHOST_VDPA_GET_CONFIG
, config
);
249 error_setg(errp
, "Fail to get config from vhost-vDPA device");
253 max_queue_pairs
= (__virtio16
*)&config
->buf
;
255 return lduw_le_p(max_queue_pairs
);
261 int net_init_vhost_vdpa(const Netdev
*netdev
, const char *name
,
262 NetClientState
*peer
, Error
**errp
)
264 const NetdevVhostVDPAOptions
*opts
;
266 g_autofree NetClientState
**ncs
= NULL
;
268 int queue_pairs
, i
, has_cvq
= 0;
270 assert(netdev
->type
== NET_CLIENT_DRIVER_VHOST_VDPA
);
271 opts
= &netdev
->u
.vhost_vdpa
;
272 if (!opts
->vhostdev
) {
273 error_setg(errp
, "vdpa character device not specified with vhostdev");
277 vdpa_device_fd
= qemu_open(opts
->vhostdev
, O_RDWR
, errp
);
278 if (vdpa_device_fd
== -1) {
282 queue_pairs
= vhost_vdpa_get_max_queue_pairs(vdpa_device_fd
,
284 if (queue_pairs
< 0) {
285 qemu_close(vdpa_device_fd
);
289 ncs
= g_malloc0(sizeof(*ncs
) * queue_pairs
);
291 for (i
= 0; i
< queue_pairs
; i
++) {
292 ncs
[i
] = net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
,
293 vdpa_device_fd
, i
, 2, true);
299 nc
= net_vhost_vdpa_init(peer
, TYPE_VHOST_VDPA
, name
,
300 vdpa_device_fd
, i
, 1, false);
309 for (i
--; i
>= 0; i
--) {
310 qemu_del_net_client(ncs
[i
]);
313 qemu_close(vdpa_device_fd
);