]>
Commit | Line | Data |
---|---|---|
1e0a84ea CL |
1 | /* |
2 | * vhost-vdpa.c | |
3 | * | |
4 | * Copyright(c) 2017-2018 Intel Corporation. | |
5 | * Copyright(c) 2020 Red Hat, Inc. | |
6 | * | |
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. | |
9 | * | |
10 | */ | |
11 | ||
12 | #include "qemu/osdep.h" | |
13 | #include "clients.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> | |
22 | #include <err.h> | |
23 | #include "standard-headers/linux/virtio_net.h" | |
24 | #include "monitor/monitor.h" | |
25 | #include "hw/virtio/vhost.h" | |
26 | ||
27 | /* Todo:need to add the multiqueue support here */ | |
28 | typedef struct VhostVDPAState { | |
29 | NetClientState nc; | |
30 | struct vhost_vdpa vhost_vdpa; | |
31 | VHostNetState *vhost_net; | |
1e0a84ea CL |
32 | bool started; |
33 | } VhostVDPAState; | |
34 | ||
35 | const int vdpa_feature_bits[] = { | |
36 | VIRTIO_F_NOTIFY_ON_EMPTY, | |
37 | VIRTIO_RING_F_INDIRECT_DESC, | |
38 | VIRTIO_RING_F_EVENT_IDX, | |
39 | VIRTIO_F_ANY_LAYOUT, | |
40 | VIRTIO_F_VERSION_1, | |
41 | VIRTIO_NET_F_CSUM, | |
42 | VIRTIO_NET_F_GUEST_CSUM, | |
43 | VIRTIO_NET_F_GSO, | |
44 | VIRTIO_NET_F_GUEST_TSO4, | |
45 | VIRTIO_NET_F_GUEST_TSO6, | |
46 | VIRTIO_NET_F_GUEST_ECN, | |
47 | VIRTIO_NET_F_GUEST_UFO, | |
48 | VIRTIO_NET_F_HOST_TSO4, | |
49 | VIRTIO_NET_F_HOST_TSO6, | |
50 | VIRTIO_NET_F_HOST_ECN, | |
51 | VIRTIO_NET_F_HOST_UFO, | |
52 | VIRTIO_NET_F_MRG_RXBUF, | |
53 | VIRTIO_NET_F_MTU, | |
54 | VIRTIO_F_IOMMU_PLATFORM, | |
55 | VIRTIO_F_RING_PACKED, | |
0145c393 AM |
56 | VIRTIO_NET_F_RSS, |
57 | VIRTIO_NET_F_HASH_REPORT, | |
1e0a84ea | 58 | VIRTIO_NET_F_GUEST_ANNOUNCE, |
9aa47edd | 59 | VIRTIO_NET_F_STATUS, |
1e0a84ea CL |
60 | VHOST_INVALID_FEATURE_BIT |
61 | }; | |
62 | ||
63 | VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) | |
64 | { | |
65 | VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | |
66 | assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | |
67 | return s->vhost_net; | |
68 | } | |
69 | ||
1e0a84ea CL |
70 | static int vhost_vdpa_net_check_device_id(struct vhost_net *net) |
71 | { | |
72 | uint32_t device_id; | |
73 | int ret; | |
74 | struct vhost_dev *hdev; | |
75 | ||
76 | hdev = (struct vhost_dev *)&net->dev; | |
77 | ret = hdev->vhost_ops->vhost_get_device_id(hdev, &device_id); | |
78 | if (device_id != VIRTIO_ID_NET) { | |
79 | return -ENOTSUP; | |
80 | } | |
81 | return ret; | |
82 | } | |
83 | ||
1e0a84ea CL |
84 | static int vhost_vdpa_add(NetClientState *ncs, void *be) |
85 | { | |
86 | VhostNetOptions options; | |
87 | struct vhost_net *net = NULL; | |
88 | VhostVDPAState *s; | |
89 | int ret; | |
90 | ||
91 | options.backend_type = VHOST_BACKEND_TYPE_VDPA; | |
92 | assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | |
93 | s = DO_UPCAST(VhostVDPAState, nc, ncs); | |
94 | options.net_backend = ncs; | |
95 | options.opaque = be; | |
96 | options.busyloop_timeout = 0; | |
6a756d14 | 97 | options.nvqs = 2; |
1e0a84ea CL |
98 | |
99 | net = vhost_net_init(&options); | |
100 | if (!net) { | |
101 | error_report("failed to init vhost_net for queue"); | |
a97ef87a | 102 | goto err_init; |
1e0a84ea | 103 | } |
1e0a84ea CL |
104 | s->vhost_net = net; |
105 | ret = vhost_vdpa_net_check_device_id(net); | |
106 | if (ret) { | |
a97ef87a | 107 | goto err_check; |
1e0a84ea CL |
108 | } |
109 | return 0; | |
a97ef87a JW |
110 | err_check: |
111 | vhost_net_cleanup(net); | |
112 | g_free(net); | |
113 | err_init: | |
1e0a84ea CL |
114 | return -1; |
115 | } | |
116 | ||
117 | static void vhost_vdpa_cleanup(NetClientState *nc) | |
118 | { | |
119 | VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | |
120 | ||
121 | if (s->vhost_net) { | |
122 | vhost_net_cleanup(s->vhost_net); | |
123 | g_free(s->vhost_net); | |
124 | s->vhost_net = NULL; | |
125 | } | |
57b3a7d8 CL |
126 | if (s->vhost_vdpa.device_fd >= 0) { |
127 | qemu_close(s->vhost_vdpa.device_fd); | |
128 | s->vhost_vdpa.device_fd = -1; | |
129 | } | |
1e0a84ea CL |
130 | } |
131 | ||
132 | static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc) | |
133 | { | |
134 | assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | |
135 | ||
136 | return true; | |
137 | } | |
138 | ||
139 | static bool vhost_vdpa_has_ufo(NetClientState *nc) | |
140 | { | |
141 | assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); | |
142 | VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); | |
143 | uint64_t features = 0; | |
144 | features |= (1ULL << VIRTIO_NET_F_HOST_UFO); | |
145 | features = vhost_net_get_features(s->vhost_net, features); | |
146 | return !!(features & (1ULL << VIRTIO_NET_F_HOST_UFO)); | |
147 | ||
148 | } | |
149 | ||
ee8a1c63 KW |
150 | static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc, |
151 | Error **errp) | |
152 | { | |
153 | const char *driver = object_class_get_name(oc); | |
154 | ||
155 | if (!g_str_has_prefix(driver, "virtio-net-")) { | |
156 | error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*"); | |
157 | return false; | |
158 | } | |
159 | ||
160 | return true; | |
161 | } | |
162 | ||
1e0a84ea CL |
163 | static NetClientInfo net_vhost_vdpa_info = { |
164 | .type = NET_CLIENT_DRIVER_VHOST_VDPA, | |
165 | .size = sizeof(VhostVDPAState), | |
166 | .cleanup = vhost_vdpa_cleanup, | |
167 | .has_vnet_hdr = vhost_vdpa_has_vnet_hdr, | |
168 | .has_ufo = vhost_vdpa_has_ufo, | |
ee8a1c63 | 169 | .check_peer_type = vhost_vdpa_check_peer_type, |
1e0a84ea CL |
170 | }; |
171 | ||
172 | static int net_vhost_vdpa_init(NetClientState *peer, const char *device, | |
7327813d | 173 | const char *name, int vdpa_device_fd) |
1e0a84ea CL |
174 | { |
175 | NetClientState *nc = NULL; | |
176 | VhostVDPAState *s; | |
1e0a84ea CL |
177 | int ret = 0; |
178 | assert(name); | |
179 | nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); | |
56e6f594 | 180 | snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); |
1e0a84ea | 181 | s = DO_UPCAST(VhostVDPAState, nc, nc); |
7327813d | 182 | |
1e0a84ea CL |
183 | s->vhost_vdpa.device_fd = vdpa_device_fd; |
184 | ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa); | |
74af5eec | 185 | if (ret) { |
74af5eec JW |
186 | qemu_del_net_client(nc); |
187 | } | |
1e0a84ea CL |
188 | return ret; |
189 | } | |
190 | ||
1e0a84ea CL |
191 | int net_init_vhost_vdpa(const Netdev *netdev, const char *name, |
192 | NetClientState *peer, Error **errp) | |
193 | { | |
194 | const NetdevVhostVDPAOptions *opts; | |
7327813d | 195 | int vdpa_device_fd, ret; |
1e0a84ea CL |
196 | |
197 | assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA); | |
198 | opts = &netdev->u.vhost_vdpa; | |
7327813d JW |
199 | |
200 | vdpa_device_fd = qemu_open_old(opts->vhostdev, O_RDWR); | |
201 | if (vdpa_device_fd == -1) { | |
202 | return -errno; | |
203 | } | |
204 | ||
205 | ret = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, vdpa_device_fd); | |
206 | if (ret) { | |
207 | qemu_close(vdpa_device_fd); | |
208 | } | |
209 | ||
210 | return ret; | |
1e0a84ea | 211 | } |