vhost: refactor code structure
[dpdk.git] / lib / librte_vhost / vhost.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <linux/vhost.h>
35 #include <linux/virtio_net.h>
36 #include <stddef.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #ifdef RTE_LIBRTE_VHOST_NUMA
40 #include <numaif.h>
41 #endif
42
43 #include <rte_ethdev.h>
44 #include <rte_log.h>
45 #include <rte_string_fns.h>
46 #include <rte_memory.h>
47 #include <rte_malloc.h>
48 #include <rte_virtio_net.h>
49
50 #include "vhost.h"
51
52 #define VHOST_USER_F_PROTOCOL_FEATURES  30
53
54 /* Features supported by this lib. */
55 #define VHOST_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \
56                                 (1ULL << VIRTIO_NET_F_CTRL_VQ) | \
57                                 (1ULL << VIRTIO_NET_F_CTRL_RX) | \
58                                 (1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | \
59                                 (VHOST_SUPPORTS_MQ)            | \
60                                 (1ULL << VIRTIO_F_VERSION_1)   | \
61                                 (1ULL << VHOST_F_LOG_ALL)      | \
62                                 (1ULL << VHOST_USER_F_PROTOCOL_FEATURES) | \
63                                 (1ULL << VIRTIO_NET_F_HOST_TSO4) | \
64                                 (1ULL << VIRTIO_NET_F_HOST_TSO6) | \
65                                 (1ULL << VIRTIO_NET_F_CSUM)    | \
66                                 (1ULL << VIRTIO_NET_F_GUEST_CSUM) | \
67                                 (1ULL << VIRTIO_NET_F_GUEST_TSO4) | \
68                                 (1ULL << VIRTIO_NET_F_GUEST_TSO6))
69
70 uint64_t VHOST_FEATURES = VHOST_SUPPORTED_FEATURES;
71
72 struct virtio_net *vhost_devices[MAX_VHOST_DEVICE];
73
74 /* device ops to add/remove device to/from data core. */
75 struct virtio_net_device_ops const *notify_ops;
76
77 struct virtio_net *
78 get_device(int vid)
79 {
80         struct virtio_net *dev = vhost_devices[vid];
81
82         if (unlikely(!dev)) {
83                 RTE_LOG(ERR, VHOST_CONFIG,
84                         "(%d) device not found.\n", vid);
85         }
86
87         return dev;
88 }
89
90 static void
91 cleanup_vq(struct vhost_virtqueue *vq, int destroy)
92 {
93         if ((vq->callfd >= 0) && (destroy != 0))
94                 close(vq->callfd);
95         if (vq->kickfd >= 0)
96                 close(vq->kickfd);
97 }
98
99 /*
100  * Unmap any memory, close any file descriptors and
101  * free any memory owned by a device.
102  */
103 void
104 cleanup_device(struct virtio_net *dev, int destroy)
105 {
106         uint32_t i;
107
108         vhost_backend_cleanup(dev);
109
110         for (i = 0; i < dev->virt_qp_nb; i++) {
111                 cleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_RXQ], destroy);
112                 cleanup_vq(dev->virtqueue[i * VIRTIO_QNUM + VIRTIO_TXQ], destroy);
113         }
114 }
115
116 /*
117  * Release virtqueues and device memory.
118  */
119 static void
120 free_device(struct virtio_net *dev)
121 {
122         uint32_t i;
123
124         for (i = 0; i < dev->virt_qp_nb; i++)
125                 rte_free(dev->virtqueue[i * VIRTIO_QNUM]);
126
127         rte_free(dev);
128 }
129
130 static void
131 init_vring_queue(struct vhost_virtqueue *vq, int qp_idx)
132 {
133         memset(vq, 0, sizeof(struct vhost_virtqueue));
134
135         vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
136         vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;
137
138         /* Backends are set to -1 indicating an inactive device. */
139         vq->backend = -1;
140
141         /* always set the default vq pair to enabled */
142         if (qp_idx == 0)
143                 vq->enabled = 1;
144 }
145
146 static void
147 init_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)
148 {
149         uint32_t base_idx = qp_idx * VIRTIO_QNUM;
150
151         init_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);
152         init_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);
153 }
154
155 static void
156 reset_vring_queue(struct vhost_virtqueue *vq, int qp_idx)
157 {
158         int callfd;
159
160         callfd = vq->callfd;
161         init_vring_queue(vq, qp_idx);
162         vq->callfd = callfd;
163 }
164
165 static void
166 reset_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)
167 {
168         uint32_t base_idx = qp_idx * VIRTIO_QNUM;
169
170         reset_vring_queue(dev->virtqueue[base_idx + VIRTIO_RXQ], qp_idx);
171         reset_vring_queue(dev->virtqueue[base_idx + VIRTIO_TXQ], qp_idx);
172 }
173
174 int
175 alloc_vring_queue_pair(struct virtio_net *dev, uint32_t qp_idx)
176 {
177         struct vhost_virtqueue *virtqueue = NULL;
178         uint32_t virt_rx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_RXQ;
179         uint32_t virt_tx_q_idx = qp_idx * VIRTIO_QNUM + VIRTIO_TXQ;
180
181         virtqueue = rte_malloc(NULL,
182                                sizeof(struct vhost_virtqueue) * VIRTIO_QNUM, 0);
183         if (virtqueue == NULL) {
184                 RTE_LOG(ERR, VHOST_CONFIG,
185                         "Failed to allocate memory for virt qp:%d.\n", qp_idx);
186                 return -1;
187         }
188
189         dev->virtqueue[virt_rx_q_idx] = virtqueue;
190         dev->virtqueue[virt_tx_q_idx] = virtqueue + VIRTIO_TXQ;
191
192         init_vring_queue_pair(dev, qp_idx);
193
194         dev->virt_qp_nb += 1;
195
196         return 0;
197 }
198
199 /*
200  * Reset some variables in device structure, while keeping few
201  * others untouched, such as vid, ifname, virt_qp_nb: they
202  * should be same unless the device is removed.
203  */
204 void
205 reset_device(struct virtio_net *dev)
206 {
207         uint32_t i;
208
209         dev->features = 0;
210         dev->protocol_features = 0;
211         dev->flags = 0;
212
213         for (i = 0; i < dev->virt_qp_nb; i++)
214                 reset_vring_queue_pair(dev, i);
215 }
216
217 /*
218  * Function is called from the CUSE open function. The device structure is
219  * initialised and a new entry is added to the device configuration linked
220  * list.
221  */
222 int
223 vhost_new_device(void)
224 {
225         struct virtio_net *dev;
226         int i;
227
228         dev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0);
229         if (dev == NULL) {
230                 RTE_LOG(ERR, VHOST_CONFIG,
231                         "Failed to allocate memory for new dev.\n");
232                 return -1;
233         }
234
235         for (i = 0; i < MAX_VHOST_DEVICE; i++) {
236                 if (vhost_devices[i] == NULL)
237                         break;
238         }
239         if (i == MAX_VHOST_DEVICE) {
240                 RTE_LOG(ERR, VHOST_CONFIG,
241                         "Failed to find a free slot for new device.\n");
242                 return -1;
243         }
244
245         vhost_devices[i] = dev;
246         dev->vid = i;
247
248         return i;
249 }
250
251 /*
252  * Function is called from the CUSE release function. This function will
253  * cleanup the device and remove it from device configuration linked list.
254  */
255 void
256 vhost_destroy_device(int vid)
257 {
258         struct virtio_net *dev = get_device(vid);
259
260         if (dev == NULL)
261                 return;
262
263         if (dev->flags & VIRTIO_DEV_RUNNING) {
264                 dev->flags &= ~VIRTIO_DEV_RUNNING;
265                 notify_ops->destroy_device(vid);
266         }
267
268         cleanup_device(dev, 1);
269         free_device(dev);
270
271         vhost_devices[vid] = NULL;
272 }
273
274 void
275 vhost_set_ifname(int vid, const char *if_name, unsigned int if_len)
276 {
277         struct virtio_net *dev;
278         unsigned int len;
279
280         dev = get_device(vid);
281         if (dev == NULL)
282                 return;
283
284         len = if_len > sizeof(dev->ifname) ?
285                 sizeof(dev->ifname) : if_len;
286
287         strncpy(dev->ifname, if_name, len);
288         dev->ifname[sizeof(dev->ifname) - 1] = '\0';
289 }
290
291
292 int
293 rte_vhost_get_numa_node(int vid)
294 {
295 #ifdef RTE_LIBRTE_VHOST_NUMA
296         struct virtio_net *dev = get_device(vid);
297         int numa_node;
298         int ret;
299
300         if (dev == NULL)
301                 return -1;
302
303         ret = get_mempolicy(&numa_node, NULL, 0, dev,
304                             MPOL_F_NODE | MPOL_F_ADDR);
305         if (ret < 0) {
306                 RTE_LOG(ERR, VHOST_CONFIG,
307                         "(%d) failed to query numa node: %d\n", vid, ret);
308                 return -1;
309         }
310
311         return numa_node;
312 #else
313         RTE_SET_USED(vid);
314         return -1;
315 #endif
316 }
317
318 uint32_t
319 rte_vhost_get_queue_num(int vid)
320 {
321         struct virtio_net *dev = get_device(vid);
322
323         if (dev == NULL)
324                 return 0;
325
326         return dev->virt_qp_nb;
327 }
328
329 int
330 rte_vhost_get_ifname(int vid, char *buf, size_t len)
331 {
332         struct virtio_net *dev = get_device(vid);
333
334         if (dev == NULL)
335                 return -1;
336
337         len = RTE_MIN(len, sizeof(dev->ifname));
338
339         strncpy(buf, dev->ifname, len);
340         buf[len - 1] = '\0';
341
342         return 0;
343 }
344
345 uint16_t
346 rte_vhost_avail_entries(int vid, uint16_t queue_id)
347 {
348         struct virtio_net *dev;
349         struct vhost_virtqueue *vq;
350
351         dev = get_device(vid);
352         if (!dev)
353                 return 0;
354
355         vq = dev->virtqueue[queue_id];
356         if (!vq->enabled)
357                 return 0;
358
359         return *(volatile uint16_t *)&vq->avail->idx - vq->last_used_idx;
360 }
361
362 int
363 rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable)
364 {
365         struct virtio_net *dev = get_device(vid);
366
367         if (dev == NULL)
368                 return -1;
369
370         if (enable) {
371                 RTE_LOG(ERR, VHOST_CONFIG,
372                         "guest notification isn't supported.\n");
373                 return -1;
374         }
375
376         dev->virtqueue[queue_id]->used->flags = VRING_USED_F_NO_NOTIFY;
377         return 0;
378 }
379
380 uint64_t rte_vhost_feature_get(void)
381 {
382         return VHOST_FEATURES;
383 }
384
385 int rte_vhost_feature_disable(uint64_t feature_mask)
386 {
387         VHOST_FEATURES = VHOST_FEATURES & ~feature_mask;
388         return 0;
389 }
390
391 int rte_vhost_feature_enable(uint64_t feature_mask)
392 {
393         if ((feature_mask & VHOST_SUPPORTED_FEATURES) == feature_mask) {
394                 VHOST_FEATURES = VHOST_FEATURES | feature_mask;
395                 return 0;
396         }
397         return -1;
398 }
399
400 /*
401  * Register ops so that we can add/remove device to data core.
402  */
403 int
404 rte_vhost_driver_callback_register(struct virtio_net_device_ops const * const ops)
405 {
406         notify_ops = ops;
407
408         return 0;
409 }