Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2016 IGEL Co., Ltd.
3 : : * Copyright(c) 2016-2018 Intel Corporation
4 : : */
5 : : #include <stdlib.h>
6 : : #include <unistd.h>
7 : : #include <pthread.h>
8 : : #include <stdbool.h>
9 : : #include <sys/epoll.h>
10 : :
11 : : #include <rte_mbuf.h>
12 : : #include <ethdev_driver.h>
13 : : #include <ethdev_vdev.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_memcpy.h>
16 : : #include <rte_net.h>
17 : : #include <bus_vdev_driver.h>
18 : : #include <rte_kvargs.h>
19 : : #include <rte_vhost.h>
20 : : #include <rte_spinlock.h>
21 : :
22 : : #include "rte_eth_vhost.h"
23 : :
24 [ - + ]: 235 : RTE_LOG_REGISTER_DEFAULT(vhost_logtype, NOTICE);
25 : :
26 : : #define VHOST_LOG(level, ...) \
27 : : rte_log(RTE_LOG_ ## level, vhost_logtype, __VA_ARGS__)
28 : :
29 : : enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};
30 : :
31 : : #define ETH_VHOST_IFACE_ARG "iface"
32 : : #define ETH_VHOST_QUEUES_ARG "queues"
33 : : #define ETH_VHOST_CLIENT_ARG "client"
34 : : #define ETH_VHOST_IOMMU_SUPPORT "iommu-support"
35 : : #define ETH_VHOST_POSTCOPY_SUPPORT "postcopy-support"
36 : : #define ETH_VHOST_VIRTIO_NET_F_HOST_TSO "tso"
37 : : #define ETH_VHOST_LINEAR_BUF "linear-buffer"
38 : : #define ETH_VHOST_EXT_BUF "ext-buffer"
39 : : #define ETH_VHOST_LEGACY_OL_FLAGS "legacy-ol-flags"
40 : : #define VHOST_MAX_PKT_BURST 32
41 : :
42 : : static const char *valid_arguments[] = {
43 : : ETH_VHOST_IFACE_ARG,
44 : : ETH_VHOST_QUEUES_ARG,
45 : : ETH_VHOST_CLIENT_ARG,
46 : : ETH_VHOST_IOMMU_SUPPORT,
47 : : ETH_VHOST_POSTCOPY_SUPPORT,
48 : : ETH_VHOST_VIRTIO_NET_F_HOST_TSO,
49 : : ETH_VHOST_LINEAR_BUF,
50 : : ETH_VHOST_EXT_BUF,
51 : : ETH_VHOST_LEGACY_OL_FLAGS,
52 : : NULL
53 : : };
54 : :
55 : : static struct rte_ether_addr base_eth_addr = {
56 : : .addr_bytes = {
57 : : 0x56 /* V */,
58 : : 0x48 /* H */,
59 : : 0x4F /* O */,
60 : : 0x53 /* S */,
61 : : 0x54 /* T */,
62 : : 0x00
63 : : }
64 : : };
65 : :
66 : : struct vhost_stats {
67 : : uint64_t pkts;
68 : : uint64_t bytes;
69 : : uint64_t missed_pkts;
70 : : };
71 : :
72 : : struct vhost_queue {
73 : : int vid;
74 : : rte_atomic32_t allow_queuing;
75 : : rte_atomic32_t while_queuing;
76 : : struct pmd_internal *internal;
77 : : struct rte_mempool *mb_pool;
78 : : uint16_t port;
79 : : uint16_t virtqueue_id;
80 : : struct vhost_stats stats;
81 : : rte_spinlock_t intr_lock;
82 : : struct epoll_event ev;
83 : : int kickfd;
84 : : };
85 : :
86 : : struct pmd_internal {
87 : : rte_atomic32_t dev_attached;
88 : : char *iface_name;
89 : : uint64_t flags;
90 : : uint64_t disable_flags;
91 : : uint64_t features;
92 : : uint16_t max_queues;
93 : : int vid;
94 : : rte_atomic32_t started;
95 : : bool vlan_strip;
96 : : bool rx_sw_csum;
97 : : bool tx_sw_csum;
98 : : };
99 : :
100 : : struct internal_list {
101 : : TAILQ_ENTRY(internal_list) next;
102 : : struct rte_eth_dev *eth_dev;
103 : : };
104 : :
105 : : TAILQ_HEAD(internal_list_head, internal_list);
106 : : static struct internal_list_head internal_list =
107 : : TAILQ_HEAD_INITIALIZER(internal_list);
108 : :
109 : : static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
110 : :
111 : : static struct rte_eth_link pmd_link = {
112 : : .link_speed = 10000,
113 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
114 : : .link_status = RTE_ETH_LINK_DOWN
115 : : };
116 : :
117 : : struct rte_vhost_vring_state {
118 : : rte_spinlock_t lock;
119 : :
120 : : bool cur[RTE_MAX_QUEUES_PER_PORT * 2];
121 : : bool seen[RTE_MAX_QUEUES_PER_PORT * 2];
122 : : unsigned int index;
123 : : unsigned int max_vring;
124 : : };
125 : :
126 : : static struct rte_vhost_vring_state *vring_states[RTE_MAX_ETHPORTS];
127 : :
128 : : static int
129 : 0 : vhost_dev_xstats_reset(struct rte_eth_dev *dev)
130 : : {
131 : : struct vhost_queue *vq;
132 : : int ret, i;
133 : :
134 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
135 : 0 : vq = dev->data->rx_queues[i];
136 : 0 : ret = rte_vhost_vring_stats_reset(vq->vid, vq->virtqueue_id);
137 [ # # ]: 0 : if (ret < 0)
138 : 0 : return ret;
139 : : }
140 : :
141 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
142 : 0 : vq = dev->data->tx_queues[i];
143 : 0 : ret = rte_vhost_vring_stats_reset(vq->vid, vq->virtqueue_id);
144 [ # # ]: 0 : if (ret < 0)
145 : 0 : return ret;
146 : : }
147 : :
148 : : return 0;
149 : : }
150 : :
151 : : static int
152 : 0 : vhost_dev_xstats_get_names(struct rte_eth_dev *dev,
153 : : struct rte_eth_xstat_name *xstats_names,
154 : : unsigned int limit)
155 : : {
156 : : struct rte_vhost_stat_name *name;
157 : : struct vhost_queue *vq;
158 : : int ret, i, count = 0, nstats = 0;
159 : :
160 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
161 : 0 : vq = dev->data->rx_queues[i];
162 : 0 : ret = rte_vhost_vring_stats_get_names(vq->vid, vq->virtqueue_id, NULL, 0);
163 [ # # ]: 0 : if (ret < 0)
164 : 0 : return ret;
165 : :
166 : 0 : nstats += ret;
167 : : }
168 : :
169 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
170 : 0 : vq = dev->data->tx_queues[i];
171 : 0 : ret = rte_vhost_vring_stats_get_names(vq->vid, vq->virtqueue_id, NULL, 0);
172 [ # # ]: 0 : if (ret < 0)
173 : 0 : return ret;
174 : :
175 : 0 : nstats += ret;
176 : : }
177 : :
178 [ # # ]: 0 : if (!xstats_names || limit < (unsigned int)nstats)
179 : : return nstats;
180 : :
181 : 0 : name = calloc(nstats, sizeof(*name));
182 [ # # ]: 0 : if (!name)
183 : : return -1;
184 : :
185 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
186 : 0 : vq = dev->data->rx_queues[i];
187 : 0 : ret = rte_vhost_vring_stats_get_names(vq->vid, vq->virtqueue_id,
188 : 0 : name + count, nstats - count);
189 [ # # ]: 0 : if (ret < 0) {
190 : 0 : free(name);
191 : 0 : return ret;
192 : : }
193 : :
194 : 0 : count += ret;
195 : : }
196 : :
197 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
198 : 0 : vq = dev->data->tx_queues[i];
199 : 0 : ret = rte_vhost_vring_stats_get_names(vq->vid, vq->virtqueue_id,
200 : 0 : name + count, nstats - count);
201 [ # # ]: 0 : if (ret < 0) {
202 : 0 : free(name);
203 : 0 : return ret;
204 : : }
205 : :
206 : 0 : count += ret;
207 : : }
208 : :
209 [ # # ]: 0 : for (i = 0; i < count; i++)
210 : 0 : strncpy(xstats_names[i].name, name[i].name, RTE_ETH_XSTATS_NAME_SIZE);
211 : :
212 : 0 : free(name);
213 : :
214 : 0 : return count;
215 : : }
216 : :
217 : : static int
218 : 0 : vhost_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
219 : : unsigned int n)
220 : : {
221 : : struct rte_vhost_stat *stats;
222 : : struct vhost_queue *vq;
223 : : int ret, i, count = 0, nstats = 0;
224 : :
225 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
226 : 0 : vq = dev->data->rx_queues[i];
227 : 0 : ret = rte_vhost_vring_stats_get(vq->vid, vq->virtqueue_id, NULL, 0);
228 [ # # ]: 0 : if (ret < 0)
229 : 0 : return ret;
230 : :
231 : 0 : nstats += ret;
232 : : }
233 : :
234 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
235 : 0 : vq = dev->data->tx_queues[i];
236 : 0 : ret = rte_vhost_vring_stats_get(vq->vid, vq->virtqueue_id, NULL, 0);
237 [ # # ]: 0 : if (ret < 0)
238 : 0 : return ret;
239 : :
240 : 0 : nstats += ret;
241 : : }
242 : :
243 [ # # ]: 0 : if (!xstats || n < (unsigned int)nstats)
244 : : return nstats;
245 : :
246 : 0 : stats = calloc(nstats, sizeof(*stats));
247 [ # # ]: 0 : if (!stats)
248 : : return -1;
249 : :
250 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
251 : 0 : vq = dev->data->rx_queues[i];
252 : 0 : ret = rte_vhost_vring_stats_get(vq->vid, vq->virtqueue_id,
253 : 0 : stats + count, nstats - count);
254 [ # # ]: 0 : if (ret < 0) {
255 : 0 : free(stats);
256 : 0 : return ret;
257 : : }
258 : :
259 : 0 : count += ret;
260 : : }
261 : :
262 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
263 : 0 : vq = dev->data->tx_queues[i];
264 : 0 : ret = rte_vhost_vring_stats_get(vq->vid, vq->virtqueue_id,
265 : 0 : stats + count, nstats - count);
266 [ # # ]: 0 : if (ret < 0) {
267 : 0 : free(stats);
268 : 0 : return ret;
269 : : }
270 : :
271 : 0 : count += ret;
272 : : }
273 : :
274 [ # # ]: 0 : for (i = 0; i < count; i++) {
275 : 0 : xstats[i].id = stats[i].id;
276 : 0 : xstats[i].value = stats[i].value;
277 : : }
278 : :
279 : 0 : free(stats);
280 : :
281 : 0 : return nstats;
282 : : }
283 : :
284 : : static void
285 : 0 : vhost_dev_csum_configure(struct rte_eth_dev *eth_dev)
286 : : {
287 : 0 : struct pmd_internal *internal = eth_dev->data->dev_private;
288 : : const struct rte_eth_rxmode *rxmode = ð_dev->data->dev_conf.rxmode;
289 : : const struct rte_eth_txmode *txmode = ð_dev->data->dev_conf.txmode;
290 : :
291 : 0 : internal->rx_sw_csum = false;
292 : 0 : internal->tx_sw_csum = false;
293 : :
294 : : /* SW checksum is not compatible with legacy mode */
295 [ # # ]: 0 : if (!(internal->flags & RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS))
296 : : return;
297 : :
298 [ # # ]: 0 : if (internal->features & (1ULL << VIRTIO_NET_F_CSUM)) {
299 [ # # ]: 0 : if (!(rxmode->offloads &
300 : : (RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM))) {
301 : 0 : VHOST_LOG(NOTICE, "Rx csum will be done in SW, may impact performance.\n");
302 : 0 : internal->rx_sw_csum = true;
303 : : }
304 : : }
305 : :
306 [ # # ]: 0 : if (!(internal->features & (1ULL << VIRTIO_NET_F_GUEST_CSUM))) {
307 [ # # ]: 0 : if (txmode->offloads &
308 : : (RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM)) {
309 : 0 : VHOST_LOG(NOTICE, "Tx csum will be done in SW, may impact performance.\n");
310 : 0 : internal->tx_sw_csum = true;
311 : : }
312 : : }
313 : : }
314 : :
315 : : static void
316 : 0 : vhost_dev_tx_sw_csum(struct rte_mbuf *mbuf)
317 : : {
318 : : uint32_t hdr_len;
319 : 0 : uint16_t csum = 0, csum_offset;
320 : :
321 [ # # # ]: 0 : switch (mbuf->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
322 : : case RTE_MBUF_F_TX_L4_NO_CKSUM:
323 : 0 : return;
324 : : case RTE_MBUF_F_TX_TCP_CKSUM:
325 : : csum_offset = offsetof(struct rte_tcp_hdr, cksum);
326 : : break;
327 : 0 : case RTE_MBUF_F_TX_UDP_CKSUM:
328 : : csum_offset = offsetof(struct rte_udp_hdr, dgram_cksum);
329 : 0 : break;
330 : : default:
331 : : /* Unsupported packet type. */
332 : : return;
333 : : }
334 : :
335 : 0 : hdr_len = mbuf->l2_len + mbuf->l3_len;
336 : 0 : csum_offset += hdr_len;
337 : :
338 : : /* Prepare the pseudo-header checksum */
339 [ # # ]: 0 : if (rte_net_intel_cksum_prepare(mbuf) < 0)
340 : : return;
341 : :
342 [ # # ]: 0 : if (rte_raw_cksum_mbuf(mbuf, hdr_len, rte_pktmbuf_pkt_len(mbuf) - hdr_len, &csum) < 0)
343 : : return;
344 : :
345 : 0 : csum = ~csum;
346 : : /* See RFC768 */
347 [ # # # # ]: 0 : if (unlikely((mbuf->packet_type & RTE_PTYPE_L4_UDP) && csum == 0))
348 : 0 : csum = 0xffff;
349 : :
350 [ # # ]: 0 : if (rte_pktmbuf_data_len(mbuf) >= csum_offset + 1)
351 : 0 : *rte_pktmbuf_mtod_offset(mbuf, uint16_t *, csum_offset) = csum;
352 : :
353 : 0 : mbuf->ol_flags &= ~RTE_MBUF_F_TX_L4_MASK;
354 : : mbuf->ol_flags |= RTE_MBUF_F_TX_L4_NO_CKSUM;
355 : : }
356 : :
357 : : static void
358 : 0 : vhost_dev_rx_sw_csum(struct rte_mbuf *mbuf)
359 : : {
360 : : struct rte_net_hdr_lens hdr_lens;
361 : : uint32_t ptype, hdr_len;
362 : 0 : uint16_t csum = 0, csum_offset;
363 : :
364 : : /* Return early if the L4 checksum was not offloaded */
365 [ # # ]: 0 : if ((mbuf->ol_flags & RTE_MBUF_F_RX_L4_CKSUM_MASK) != RTE_MBUF_F_RX_L4_CKSUM_NONE)
366 : 0 : return;
367 : :
368 : 0 : ptype = rte_net_get_ptype(mbuf, &hdr_lens, RTE_PTYPE_ALL_MASK);
369 : :
370 : 0 : hdr_len = hdr_lens.l2_len + hdr_lens.l3_len;
371 : :
372 [ # # # ]: 0 : switch (ptype & RTE_PTYPE_L4_MASK) {
373 : 0 : case RTE_PTYPE_L4_TCP:
374 : 0 : csum_offset = offsetof(struct rte_tcp_hdr, cksum) + hdr_len;
375 : 0 : break;
376 : 0 : case RTE_PTYPE_L4_UDP:
377 : 0 : csum_offset = offsetof(struct rte_udp_hdr, dgram_cksum) + hdr_len;
378 : 0 : break;
379 : : default:
380 : : /* Unsupported packet type */
381 : : return;
382 : : }
383 : :
384 : : /* The pseudo-header checksum is already performed, as per Virtio spec */
385 [ # # ]: 0 : if (rte_raw_cksum_mbuf(mbuf, hdr_len, rte_pktmbuf_pkt_len(mbuf) - hdr_len, &csum) < 0)
386 : : return;
387 : :
388 : 0 : csum = ~csum;
389 : : /* See RFC768 */
390 [ # # # # ]: 0 : if (unlikely((ptype & RTE_PTYPE_L4_UDP) && csum == 0))
391 : 0 : csum = 0xffff;
392 : :
393 [ # # ]: 0 : if (rte_pktmbuf_data_len(mbuf) >= csum_offset + 1)
394 : 0 : *rte_pktmbuf_mtod_offset(mbuf, uint16_t *, csum_offset) = csum;
395 : :
396 : 0 : mbuf->ol_flags &= ~RTE_MBUF_F_RX_L4_CKSUM_MASK;
397 : 0 : mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
398 : : }
399 : :
400 : : static uint16_t
401 [ # # ]: 0 : eth_vhost_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
402 : : {
403 : : struct vhost_queue *r = q;
404 : : uint16_t i, nb_rx = 0;
405 : : uint16_t nb_receive = nb_bufs;
406 : :
407 [ # # ]: 0 : if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
408 : : return 0;
409 : :
410 : : rte_atomic32_set(&r->while_queuing, 1);
411 : :
412 [ # # ]: 0 : if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
413 : 0 : goto out;
414 : :
415 : : /* Dequeue packets from guest TX queue */
416 [ # # ]: 0 : while (nb_receive) {
417 : : uint16_t nb_pkts;
418 : 0 : uint16_t num = (uint16_t)RTE_MIN(nb_receive,
419 : : VHOST_MAX_PKT_BURST);
420 : :
421 : 0 : nb_pkts = rte_vhost_dequeue_burst(r->vid, r->virtqueue_id,
422 : 0 : r->mb_pool, &bufs[nb_rx],
423 : : num);
424 : :
425 : 0 : nb_rx += nb_pkts;
426 : 0 : nb_receive -= nb_pkts;
427 [ # # ]: 0 : if (nb_pkts < num)
428 : : break;
429 : : }
430 : :
431 : 0 : r->stats.pkts += nb_rx;
432 : :
433 [ # # ]: 0 : for (i = 0; likely(i < nb_rx); i++) {
434 : 0 : bufs[i]->port = r->port;
435 : 0 : bufs[i]->vlan_tci = 0;
436 : :
437 [ # # ]: 0 : if (r->internal->vlan_strip)
438 : 0 : rte_vlan_strip(bufs[i]);
439 : :
440 [ # # ]: 0 : if (r->internal->rx_sw_csum)
441 : 0 : vhost_dev_rx_sw_csum(bufs[i]);
442 : :
443 : 0 : r->stats.bytes += bufs[i]->pkt_len;
444 : : }
445 : :
446 : 0 : out:
447 : : rte_atomic32_set(&r->while_queuing, 0);
448 : :
449 : 0 : return nb_rx;
450 : : }
451 : :
452 : : static uint16_t
453 [ # # ]: 0 : eth_vhost_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
454 : : {
455 : : struct vhost_queue *r = q;
456 : : uint16_t i, nb_tx = 0;
457 : : uint16_t nb_send = 0;
458 : : uint64_t nb_bytes = 0;
459 : : uint64_t nb_missed = 0;
460 : :
461 [ # # ]: 0 : if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
462 : : return 0;
463 : :
464 : : rte_atomic32_set(&r->while_queuing, 1);
465 : :
466 [ # # ]: 0 : if (unlikely(rte_atomic32_read(&r->allow_queuing) == 0))
467 : 0 : goto out;
468 : :
469 [ # # ]: 0 : for (i = 0; i < nb_bufs; i++) {
470 : 0 : struct rte_mbuf *m = bufs[i];
471 : :
472 : : /* Do VLAN tag insertion */
473 [ # # ]: 0 : if (m->ol_flags & RTE_MBUF_F_TX_VLAN) {
474 : 0 : int error = rte_vlan_insert(&m);
475 [ # # ]: 0 : if (unlikely(error)) {
476 : 0 : rte_pktmbuf_free(m);
477 : 0 : continue;
478 : : }
479 : : }
480 : :
481 [ # # ]: 0 : if (r->internal->tx_sw_csum)
482 : 0 : vhost_dev_tx_sw_csum(m);
483 : :
484 : :
485 : 0 : bufs[nb_send] = m;
486 : 0 : ++nb_send;
487 : : }
488 : :
489 : : /* Enqueue packets to guest RX queue */
490 [ # # ]: 0 : while (nb_send) {
491 : : uint16_t nb_pkts;
492 : 0 : uint16_t num = (uint16_t)RTE_MIN(nb_send,
493 : : VHOST_MAX_PKT_BURST);
494 : :
495 : 0 : nb_pkts = rte_vhost_enqueue_burst(r->vid, r->virtqueue_id,
496 : 0 : &bufs[nb_tx], num);
497 : :
498 : 0 : nb_tx += nb_pkts;
499 : 0 : nb_send -= nb_pkts;
500 [ # # ]: 0 : if (nb_pkts < num)
501 : : break;
502 : : }
503 : :
504 [ # # ]: 0 : for (i = 0; likely(i < nb_tx); i++)
505 : 0 : nb_bytes += bufs[i]->pkt_len;
506 : :
507 : 0 : nb_missed = nb_bufs - nb_tx;
508 : :
509 : 0 : r->stats.pkts += nb_tx;
510 : 0 : r->stats.bytes += nb_bytes;
511 : 0 : r->stats.missed_pkts += nb_missed;
512 : :
513 [ # # ]: 0 : for (i = 0; likely(i < nb_tx); i++)
514 : 0 : rte_pktmbuf_free(bufs[i]);
515 : 0 : out:
516 : : rte_atomic32_set(&r->while_queuing, 0);
517 : :
518 : 0 : return nb_tx;
519 : : }
520 : :
521 : : static inline struct internal_list *
522 : 0 : find_internal_resource(char *ifname)
523 : : {
524 : : int found = 0;
525 : : struct internal_list *list;
526 : : struct pmd_internal *internal;
527 : :
528 [ # # ]: 0 : if (ifname == NULL)
529 : : return NULL;
530 : :
531 : 0 : pthread_mutex_lock(&internal_list_lock);
532 : :
533 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
534 : 0 : internal = list->eth_dev->data->dev_private;
535 [ # # ]: 0 : if (!strcmp(internal->iface_name, ifname)) {
536 : : found = 1;
537 : : break;
538 : : }
539 : : }
540 : :
541 : 0 : pthread_mutex_unlock(&internal_list_lock);
542 : :
543 [ # # ]: 0 : if (!found)
544 : 0 : return NULL;
545 : :
546 : : return list;
547 : : }
548 : :
549 : : static void
550 : 0 : eth_vhost_update_intr(struct rte_eth_dev *eth_dev, uint16_t rxq_idx)
551 : : {
552 : : struct rte_vhost_vring vring;
553 : : struct vhost_queue *vq;
554 : :
555 : 0 : vq = eth_dev->data->rx_queues[rxq_idx];
556 [ # # # # ]: 0 : if (vq == NULL || vq->vid < 0)
557 : 0 : return;
558 : :
559 [ # # ]: 0 : if (rte_vhost_get_vhost_vring(vq->vid, (rxq_idx << 1) + 1, &vring) < 0) {
560 : 0 : VHOST_LOG(DEBUG, "Failed to get rxq-%d's vring, skip!\n", rxq_idx);
561 : 0 : return;
562 : : }
563 : :
564 : 0 : rte_spinlock_lock(&vq->intr_lock);
565 : :
566 : : /* Remove previous kickfd from proxy epoll */
567 [ # # # # ]: 0 : if (vq->kickfd >= 0 && vq->kickfd != vring.kickfd) {
568 [ # # ]: 0 : if (epoll_ctl(vq->ev.data.fd, EPOLL_CTL_DEL, vq->kickfd, &vq->ev) < 0) {
569 : 0 : VHOST_LOG(DEBUG, "Failed to unregister %d from rxq-%d epoll: %s\n",
570 : : vq->kickfd, rxq_idx, strerror(errno));
571 : : } else {
572 : 0 : VHOST_LOG(DEBUG, "Unregistered %d from rxq-%d epoll\n",
573 : : vq->kickfd, rxq_idx);
574 : : }
575 : 0 : vq->kickfd = -1;
576 : : }
577 : :
578 : : /* Add new one, if valid */
579 [ # # # # ]: 0 : if (vq->kickfd != vring.kickfd && vring.kickfd >= 0) {
580 [ # # ]: 0 : if (epoll_ctl(vq->ev.data.fd, EPOLL_CTL_ADD, vring.kickfd, &vq->ev) < 0) {
581 : 0 : VHOST_LOG(ERR, "Failed to register %d in rxq-%d epoll: %s\n",
582 : : vring.kickfd, rxq_idx, strerror(errno));
583 : : } else {
584 : 0 : vq->kickfd = vring.kickfd;
585 : 0 : VHOST_LOG(DEBUG, "Registered %d in rxq-%d epoll\n",
586 : : vq->kickfd, rxq_idx);
587 : : }
588 : : }
589 : :
590 : : rte_spinlock_unlock(&vq->intr_lock);
591 : : }
592 : :
593 : : static int
594 : 0 : eth_rxq_intr_enable(struct rte_eth_dev *dev, uint16_t qid)
595 : : {
596 : 0 : struct vhost_queue *vq = dev->data->rx_queues[qid];
597 : :
598 [ # # ]: 0 : if (vq->vid >= 0)
599 : 0 : rte_vhost_enable_guest_notification(vq->vid, (qid << 1) + 1, 1);
600 : :
601 : 0 : return 0;
602 : : }
603 : :
604 : : static int
605 : 0 : eth_rxq_intr_disable(struct rte_eth_dev *dev, uint16_t qid)
606 : : {
607 : 0 : struct vhost_queue *vq = dev->data->rx_queues[qid];
608 : :
609 [ # # ]: 0 : if (vq->vid >= 0)
610 : 0 : rte_vhost_enable_guest_notification(vq->vid, (qid << 1) + 1, 0);
611 : :
612 : 0 : return 0;
613 : : }
614 : :
615 : : static void
616 : 0 : eth_vhost_uninstall_intr(struct rte_eth_dev *dev)
617 : : {
618 : 0 : struct rte_intr_handle *intr_handle = dev->intr_handle;
619 : :
620 [ # # ]: 0 : if (intr_handle != NULL) {
621 : : int i;
622 : :
623 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
624 : 0 : int epoll_fd = rte_intr_efds_index_get(dev->intr_handle, i);
625 : :
626 [ # # ]: 0 : if (epoll_fd >= 0)
627 : 0 : close(epoll_fd);
628 : : }
629 : 0 : rte_intr_vec_list_free(intr_handle);
630 : 0 : rte_intr_instance_free(intr_handle);
631 : : }
632 : 0 : dev->intr_handle = NULL;
633 : 0 : }
634 : :
635 : : static int
636 : 0 : eth_vhost_install_intr(struct rte_eth_dev *dev)
637 : : {
638 : 0 : int nb_rxq = dev->data->nb_rx_queues;
639 : : struct vhost_queue *vq;
640 : :
641 : : int ret;
642 : : int i;
643 : :
644 : 0 : dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
645 [ # # ]: 0 : if (dev->intr_handle == NULL) {
646 : 0 : VHOST_LOG(ERR, "Fail to allocate intr_handle\n");
647 : : ret = -ENOMEM;
648 : 0 : goto error;
649 : : }
650 [ # # ]: 0 : if (rte_intr_efd_counter_size_set(dev->intr_handle, 0)) {
651 : 0 : ret = -rte_errno;
652 : 0 : goto error;
653 : : }
654 : :
655 [ # # ]: 0 : if (rte_intr_vec_list_alloc(dev->intr_handle, NULL, nb_rxq)) {
656 : 0 : VHOST_LOG(ERR, "Failed to allocate memory for interrupt vector\n");
657 : : ret = -ENOMEM;
658 : 0 : goto error;
659 : : }
660 : :
661 : 0 : VHOST_LOG(DEBUG, "Prepare intr vec\n");
662 [ # # ]: 0 : for (i = 0; i < nb_rxq; i++) {
663 : 0 : int epoll_fd = epoll_create1(0);
664 : :
665 [ # # ]: 0 : if (epoll_fd < 0) {
666 : 0 : VHOST_LOG(ERR, "Failed to create proxy epoll fd for rxq-%d\n", i);
667 : 0 : ret = -errno;
668 : 0 : goto error;
669 : : }
670 : :
671 [ # # ]: 0 : if (rte_intr_vec_list_index_set(dev->intr_handle, i,
672 [ # # ]: 0 : RTE_INTR_VEC_RXTX_OFFSET + i) ||
673 : 0 : rte_intr_efds_index_set(dev->intr_handle, i, epoll_fd)) {
674 : 0 : ret = -rte_errno;
675 : 0 : close(epoll_fd);
676 : 0 : goto error;
677 : : }
678 : :
679 : 0 : vq = dev->data->rx_queues[i];
680 : 0 : memset(&vq->ev, 0, sizeof(vq->ev));
681 : 0 : vq->ev.events = EPOLLIN;
682 : 0 : vq->ev.data.fd = epoll_fd;
683 : : }
684 : :
685 [ # # ]: 0 : if (rte_intr_nb_efd_set(dev->intr_handle, nb_rxq)) {
686 : 0 : ret = -rte_errno;
687 : 0 : goto error;
688 : : }
689 [ # # ]: 0 : if (rte_intr_max_intr_set(dev->intr_handle, nb_rxq + 1)) {
690 : 0 : ret = -rte_errno;
691 : 0 : goto error;
692 : : }
693 [ # # ]: 0 : if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_VDEV)) {
694 : 0 : ret = -rte_errno;
695 : 0 : goto error;
696 : : }
697 : :
698 : : return 0;
699 : :
700 : 0 : error:
701 : 0 : eth_vhost_uninstall_intr(dev);
702 : 0 : return ret;
703 : : }
704 : :
705 : : static void
706 : 0 : eth_vhost_configure_intr(struct rte_eth_dev *dev)
707 : : {
708 : : int i;
709 : :
710 : 0 : VHOST_LOG(DEBUG, "Configure intr vec\n");
711 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
712 : 0 : eth_vhost_update_intr(dev, i);
713 : 0 : }
714 : :
715 : : static void
716 : 0 : eth_vhost_unconfigure_intr(struct rte_eth_dev *eth_dev)
717 : : {
718 : : struct vhost_queue *vq;
719 : : int i;
720 : :
721 : 0 : VHOST_LOG(DEBUG, "Unconfigure intr vec\n");
722 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
723 : 0 : vq = eth_dev->data->rx_queues[i];
724 [ # # # # ]: 0 : if (vq == NULL || vq->vid < 0)
725 : 0 : continue;
726 : :
727 : 0 : rte_spinlock_lock(&vq->intr_lock);
728 : :
729 : : /* Remove previous kickfd from proxy epoll */
730 [ # # ]: 0 : if (vq->kickfd >= 0) {
731 [ # # ]: 0 : if (epoll_ctl(vq->ev.data.fd, EPOLL_CTL_DEL, vq->kickfd, &vq->ev) < 0) {
732 : 0 : VHOST_LOG(DEBUG, "Failed to unregister %d from rxq-%d epoll: %s\n",
733 : : vq->kickfd, i, strerror(errno));
734 : : } else {
735 : 0 : VHOST_LOG(DEBUG, "Unregistered %d from rxq-%d epoll\n",
736 : : vq->kickfd, i);
737 : : }
738 : 0 : vq->kickfd = -1;
739 : : }
740 : :
741 : : rte_spinlock_unlock(&vq->intr_lock);
742 : : }
743 : 0 : }
744 : :
745 : : static void
746 : 0 : update_queuing_status(struct rte_eth_dev *dev, bool wait_queuing)
747 : : {
748 : 0 : struct pmd_internal *internal = dev->data->dev_private;
749 : : struct vhost_queue *vq;
750 : : struct rte_vhost_vring_state *state;
751 : : unsigned int i;
752 : : int allow_queuing = 1;
753 : :
754 [ # # # # ]: 0 : if (!dev->data->rx_queues || !dev->data->tx_queues)
755 : : return;
756 : :
757 [ # # # # ]: 0 : if (rte_atomic32_read(&internal->started) == 0 ||
758 : : rte_atomic32_read(&internal->dev_attached) == 0)
759 : : allow_queuing = 0;
760 : :
761 : 0 : state = vring_states[dev->data->port_id];
762 : :
763 : : /* Wait until rx/tx_pkt_burst stops accessing vhost device */
764 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
765 : 0 : vq = dev->data->rx_queues[i];
766 [ # # ]: 0 : if (vq == NULL)
767 : 0 : continue;
768 [ # # # # ]: 0 : if (allow_queuing && state->cur[vq->virtqueue_id])
769 : : rte_atomic32_set(&vq->allow_queuing, 1);
770 : : else
771 : : rte_atomic32_set(&vq->allow_queuing, 0);
772 [ # # # # ]: 0 : while (wait_queuing && rte_atomic32_read(&vq->while_queuing))
773 : : rte_pause();
774 : : }
775 : :
776 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
777 : 0 : vq = dev->data->tx_queues[i];
778 [ # # ]: 0 : if (vq == NULL)
779 : 0 : continue;
780 [ # # # # ]: 0 : if (allow_queuing && state->cur[vq->virtqueue_id])
781 : : rte_atomic32_set(&vq->allow_queuing, 1);
782 : : else
783 : : rte_atomic32_set(&vq->allow_queuing, 0);
784 [ # # # # ]: 0 : while (wait_queuing && rte_atomic32_read(&vq->while_queuing))
785 : : rte_pause();
786 : : }
787 : : }
788 : :
789 : : static void
790 : 0 : queue_setup(struct rte_eth_dev *eth_dev, struct pmd_internal *internal)
791 : : {
792 : : struct vhost_queue *vq;
793 : : int i;
794 : :
795 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
796 : 0 : vq = eth_dev->data->rx_queues[i];
797 [ # # ]: 0 : if (!vq)
798 : 0 : continue;
799 : 0 : vq->vid = internal->vid;
800 : 0 : vq->internal = internal;
801 : 0 : vq->port = eth_dev->data->port_id;
802 : : }
803 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
804 : 0 : vq = eth_dev->data->tx_queues[i];
805 [ # # ]: 0 : if (!vq)
806 : 0 : continue;
807 : 0 : vq->vid = internal->vid;
808 : 0 : vq->internal = internal;
809 : 0 : vq->port = eth_dev->data->port_id;
810 : : }
811 : 0 : }
812 : :
813 : : static int
814 : 0 : new_device(int vid)
815 : : {
816 : : struct rte_eth_dev *eth_dev;
817 : : struct internal_list *list;
818 : : struct pmd_internal *internal;
819 : : struct rte_eth_conf *dev_conf;
820 : : unsigned i;
821 : : char ifname[PATH_MAX];
822 : : #ifdef RTE_LIBRTE_VHOST_NUMA
823 : : int newnode;
824 : : #endif
825 : :
826 : 0 : rte_vhost_get_ifname(vid, ifname, sizeof(ifname));
827 : 0 : list = find_internal_resource(ifname);
828 [ # # ]: 0 : if (list == NULL) {
829 : 0 : VHOST_LOG(INFO, "Invalid device name: %s\n", ifname);
830 : 0 : return -1;
831 : : }
832 : :
833 : 0 : eth_dev = list->eth_dev;
834 : 0 : internal = eth_dev->data->dev_private;
835 : : dev_conf = ð_dev->data->dev_conf;
836 : :
837 : : #ifdef RTE_LIBRTE_VHOST_NUMA
838 : 0 : newnode = rte_vhost_get_numa_node(vid);
839 [ # # ]: 0 : if (newnode >= 0)
840 : 0 : eth_dev->data->numa_node = newnode;
841 : : #endif
842 : :
843 [ # # ]: 0 : if (rte_vhost_get_negotiated_features(vid, &internal->features)) {
844 : 0 : VHOST_LOG(ERR, "Failed to get device features\n");
845 : 0 : return -1;
846 : : }
847 : :
848 [ # # ]: 0 : internal->vid = vid;
849 [ # # ]: 0 : if (rte_atomic32_read(&internal->started) == 1) {
850 : 0 : queue_setup(eth_dev, internal);
851 [ # # ]: 0 : if (dev_conf->intr_conf.rxq)
852 : 0 : eth_vhost_configure_intr(eth_dev);
853 : : }
854 : :
855 [ # # ]: 0 : for (i = 0; i < rte_vhost_get_vring_num(vid); i++)
856 : 0 : rte_vhost_enable_guest_notification(vid, i, 0);
857 : :
858 : 0 : rte_vhost_get_mtu(vid, ð_dev->data->mtu);
859 : :
860 : 0 : eth_dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
861 : :
862 : 0 : vhost_dev_csum_configure(eth_dev);
863 : :
864 : : rte_atomic32_set(&internal->dev_attached, 1);
865 : 0 : update_queuing_status(eth_dev, false);
866 : :
867 : 0 : VHOST_LOG(INFO, "Vhost device %d created\n", vid);
868 : :
869 : 0 : rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
870 : :
871 : 0 : return 0;
872 : : }
873 : :
874 : : static void
875 : 0 : destroy_device(int vid)
876 : : {
877 : : struct rte_eth_dev *eth_dev;
878 : : struct pmd_internal *internal;
879 : : struct vhost_queue *vq;
880 : : struct internal_list *list;
881 : : char ifname[PATH_MAX];
882 : : unsigned i;
883 : : struct rte_vhost_vring_state *state;
884 : :
885 : 0 : rte_vhost_get_ifname(vid, ifname, sizeof(ifname));
886 : 0 : list = find_internal_resource(ifname);
887 [ # # ]: 0 : if (list == NULL) {
888 : 0 : VHOST_LOG(ERR, "Invalid interface name: %s\n", ifname);
889 : 0 : return;
890 : : }
891 : 0 : eth_dev = list->eth_dev;
892 : 0 : internal = eth_dev->data->dev_private;
893 : :
894 : : rte_atomic32_set(&internal->dev_attached, 0);
895 : 0 : update_queuing_status(eth_dev, true);
896 : 0 : eth_vhost_unconfigure_intr(eth_dev);
897 : :
898 : 0 : eth_dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
899 : :
900 [ # # # # ]: 0 : if (eth_dev->data->rx_queues && eth_dev->data->tx_queues) {
901 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
902 : 0 : vq = eth_dev->data->rx_queues[i];
903 [ # # ]: 0 : if (!vq)
904 : 0 : continue;
905 : 0 : vq->vid = -1;
906 : : }
907 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
908 : 0 : vq = eth_dev->data->tx_queues[i];
909 [ # # ]: 0 : if (!vq)
910 : 0 : continue;
911 : 0 : vq->vid = -1;
912 : : }
913 : : }
914 : :
915 : 0 : state = vring_states[eth_dev->data->port_id];
916 : 0 : rte_spinlock_lock(&state->lock);
917 [ # # ]: 0 : for (i = 0; i <= state->max_vring; i++) {
918 : 0 : state->cur[i] = false;
919 : 0 : state->seen[i] = false;
920 : : }
921 : 0 : state->max_vring = 0;
922 : : rte_spinlock_unlock(&state->lock);
923 : :
924 : 0 : VHOST_LOG(INFO, "Vhost device %d destroyed\n", vid);
925 : :
926 : 0 : rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
927 : : }
928 : :
929 : : static int
930 : 0 : vring_state_changed(int vid, uint16_t vring, int enable)
931 : : {
932 : : struct rte_vhost_vring_state *state;
933 : : struct rte_eth_dev *eth_dev;
934 : : struct internal_list *list;
935 : : char ifname[PATH_MAX];
936 : :
937 : 0 : rte_vhost_get_ifname(vid, ifname, sizeof(ifname));
938 : 0 : list = find_internal_resource(ifname);
939 [ # # ]: 0 : if (list == NULL) {
940 : 0 : VHOST_LOG(ERR, "Invalid interface name: %s\n", ifname);
941 : 0 : return -1;
942 : : }
943 : :
944 : 0 : eth_dev = list->eth_dev;
945 : : /* won't be NULL */
946 : 0 : state = vring_states[eth_dev->data->port_id];
947 : :
948 [ # # # # ]: 0 : if (eth_dev->data->dev_conf.intr_conf.rxq && vring % 2)
949 : 0 : eth_vhost_update_intr(eth_dev, (vring - 1) >> 1);
950 : :
951 : 0 : rte_spinlock_lock(&state->lock);
952 [ # # ]: 0 : if (state->cur[vring] == enable) {
953 : : rte_spinlock_unlock(&state->lock);
954 : 0 : return 0;
955 : : }
956 : 0 : state->cur[vring] = enable;
957 : 0 : state->max_vring = RTE_MAX(vring, state->max_vring);
958 : : rte_spinlock_unlock(&state->lock);
959 : :
960 : 0 : update_queuing_status(eth_dev, false);
961 : :
962 [ # # ]: 0 : VHOST_LOG(INFO, "vring%u is %s\n",
963 : : vring, enable ? "enabled" : "disabled");
964 : :
965 : 0 : rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_QUEUE_STATE, NULL);
966 : :
967 : 0 : return 0;
968 : : }
969 : :
970 : : static struct rte_vhost_device_ops vhost_ops = {
971 : : .new_device = new_device,
972 : : .destroy_device = destroy_device,
973 : : .vring_state_changed = vring_state_changed,
974 : : };
975 : :
976 : : static int
977 : 0 : vhost_driver_setup(struct rte_eth_dev *eth_dev)
978 : : {
979 : 0 : struct pmd_internal *internal = eth_dev->data->dev_private;
980 : : struct internal_list *list = NULL;
981 : : struct rte_vhost_vring_state *vring_state = NULL;
982 : 0 : unsigned int numa_node = eth_dev->device->numa_node;
983 : 0 : const char *name = eth_dev->device->name;
984 : :
985 : : /* Don't try to setup again if it has already been done. */
986 : 0 : list = find_internal_resource(internal->iface_name);
987 [ # # ]: 0 : if (list)
988 : : return 0;
989 : :
990 : 0 : list = rte_zmalloc_socket(name, sizeof(*list), 0, numa_node);
991 [ # # ]: 0 : if (list == NULL)
992 : : return -1;
993 : :
994 : 0 : vring_state = rte_zmalloc_socket(name, sizeof(*vring_state),
995 : : 0, numa_node);
996 [ # # ]: 0 : if (vring_state == NULL)
997 : 0 : goto free_list;
998 : :
999 : 0 : list->eth_dev = eth_dev;
1000 : 0 : pthread_mutex_lock(&internal_list_lock);
1001 : 0 : TAILQ_INSERT_TAIL(&internal_list, list, next);
1002 : 0 : pthread_mutex_unlock(&internal_list_lock);
1003 : :
1004 : : rte_spinlock_init(&vring_state->lock);
1005 : 0 : vring_states[eth_dev->data->port_id] = vring_state;
1006 : :
1007 [ # # ]: 0 : if (rte_vhost_driver_register(internal->iface_name, internal->flags))
1008 : 0 : goto list_remove;
1009 : :
1010 [ # # ]: 0 : if (internal->disable_flags) {
1011 [ # # ]: 0 : if (rte_vhost_driver_disable_features(internal->iface_name,
1012 : : internal->disable_flags))
1013 : 0 : goto drv_unreg;
1014 : : }
1015 : :
1016 [ # # ]: 0 : if (rte_vhost_driver_set_max_queue_num(internal->iface_name, internal->max_queues))
1017 : 0 : goto drv_unreg;
1018 : :
1019 [ # # ]: 0 : if (rte_vhost_driver_callback_register(internal->iface_name,
1020 : : &vhost_ops) < 0) {
1021 : 0 : VHOST_LOG(ERR, "Can't register callbacks\n");
1022 : 0 : goto drv_unreg;
1023 : : }
1024 : :
1025 [ # # ]: 0 : if (rte_vhost_driver_start(internal->iface_name) < 0) {
1026 : 0 : VHOST_LOG(ERR, "Failed to start driver for %s\n",
1027 : : internal->iface_name);
1028 : 0 : goto drv_unreg;
1029 : : }
1030 : :
1031 : : return 0;
1032 : :
1033 : 0 : drv_unreg:
1034 : 0 : rte_vhost_driver_unregister(internal->iface_name);
1035 : 0 : list_remove:
1036 : 0 : vring_states[eth_dev->data->port_id] = NULL;
1037 : 0 : pthread_mutex_lock(&internal_list_lock);
1038 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1039 : 0 : pthread_mutex_unlock(&internal_list_lock);
1040 : 0 : rte_free(vring_state);
1041 : 0 : free_list:
1042 : 0 : rte_free(list);
1043 : :
1044 : 0 : return -1;
1045 : : }
1046 : :
1047 : : int
1048 : 0 : rte_eth_vhost_get_queue_event(uint16_t port_id,
1049 : : struct rte_eth_vhost_queue_event *event)
1050 : : {
1051 : : struct rte_vhost_vring_state *state;
1052 : : unsigned int i;
1053 : : int idx;
1054 : :
1055 [ # # ]: 0 : if (port_id >= RTE_MAX_ETHPORTS) {
1056 : 0 : VHOST_LOG(ERR, "Invalid port id\n");
1057 : 0 : return -1;
1058 : : }
1059 : :
1060 : 0 : state = vring_states[port_id];
1061 [ # # ]: 0 : if (!state) {
1062 : 0 : VHOST_LOG(ERR, "Unused port\n");
1063 : 0 : return -1;
1064 : : }
1065 : :
1066 : 0 : rte_spinlock_lock(&state->lock);
1067 [ # # ]: 0 : for (i = 0; i <= state->max_vring; i++) {
1068 : 0 : idx = state->index++ % (state->max_vring + 1);
1069 : :
1070 [ # # ]: 0 : if (state->cur[idx] != state->seen[idx]) {
1071 : 0 : state->seen[idx] = state->cur[idx];
1072 : 0 : event->queue_id = idx / 2;
1073 : 0 : event->rx = idx & 1;
1074 : 0 : event->enable = state->cur[idx];
1075 : : rte_spinlock_unlock(&state->lock);
1076 : 0 : return 0;
1077 : : }
1078 : : }
1079 : : rte_spinlock_unlock(&state->lock);
1080 : :
1081 : 0 : return -1;
1082 : : }
1083 : :
1084 : : int
1085 : 0 : rte_eth_vhost_get_vid_from_port_id(uint16_t port_id)
1086 : : {
1087 : : struct internal_list *list;
1088 : : struct rte_eth_dev *eth_dev;
1089 : : struct vhost_queue *vq;
1090 : : int vid = -1;
1091 : :
1092 [ # # ]: 0 : if (!rte_eth_dev_is_valid_port(port_id))
1093 : : return -1;
1094 : :
1095 : 0 : pthread_mutex_lock(&internal_list_lock);
1096 : :
1097 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
1098 : 0 : eth_dev = list->eth_dev;
1099 [ # # ]: 0 : if (eth_dev->data->port_id == port_id) {
1100 : 0 : vq = eth_dev->data->rx_queues[0];
1101 [ # # ]: 0 : if (vq) {
1102 : 0 : vid = vq->vid;
1103 : : }
1104 : : break;
1105 : : }
1106 : : }
1107 : :
1108 : 0 : pthread_mutex_unlock(&internal_list_lock);
1109 : :
1110 : 0 : return vid;
1111 : : }
1112 : :
1113 : : static int
1114 : 0 : eth_dev_configure(struct rte_eth_dev *dev)
1115 : : {
1116 : 0 : struct pmd_internal *internal = dev->data->dev_private;
1117 : : const struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
1118 : :
1119 : : /* NOTE: the same process has to operate a vhost interface
1120 : : * from beginning to end (from eth_dev configure to eth_dev close).
1121 : : * It is user's responsibility at the moment.
1122 : : */
1123 [ # # ]: 0 : if (vhost_driver_setup(dev) < 0)
1124 : : return -1;
1125 : :
1126 : 0 : internal->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
1127 : :
1128 : 0 : vhost_dev_csum_configure(dev);
1129 : :
1130 : 0 : return 0;
1131 : : }
1132 : :
1133 : : static int
1134 : 0 : eth_dev_start(struct rte_eth_dev *eth_dev)
1135 : : {
1136 : 0 : struct pmd_internal *internal = eth_dev->data->dev_private;
1137 : : struct rte_eth_conf *dev_conf = ð_dev->data->dev_conf;
1138 : : uint16_t i;
1139 : :
1140 : 0 : eth_vhost_uninstall_intr(eth_dev);
1141 [ # # # # ]: 0 : if (dev_conf->intr_conf.rxq && eth_vhost_install_intr(eth_dev) < 0) {
1142 : 0 : VHOST_LOG(ERR, "Failed to install interrupt handler.\n");
1143 : 0 : return -1;
1144 : : }
1145 : :
1146 : 0 : queue_setup(eth_dev, internal);
1147 [ # # # # ]: 0 : if (rte_atomic32_read(&internal->dev_attached) == 1 &&
1148 : : dev_conf->intr_conf.rxq)
1149 : 0 : eth_vhost_configure_intr(eth_dev);
1150 : :
1151 : : rte_atomic32_set(&internal->started, 1);
1152 : 0 : update_queuing_status(eth_dev, false);
1153 : :
1154 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_rx_queues; i++)
1155 : 0 : eth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1156 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_tx_queues; i++)
1157 : 0 : eth_dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
1158 : :
1159 : : return 0;
1160 : : }
1161 : :
1162 : : static int
1163 : 0 : eth_dev_stop(struct rte_eth_dev *dev)
1164 : : {
1165 : 0 : struct pmd_internal *internal = dev->data->dev_private;
1166 : : uint16_t i;
1167 : :
1168 : 0 : dev->data->dev_started = 0;
1169 : : rte_atomic32_set(&internal->started, 0);
1170 : 0 : update_queuing_status(dev, true);
1171 : :
1172 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
1173 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1174 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
1175 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1176 : :
1177 : 0 : return 0;
1178 : : }
1179 : :
1180 : : static int
1181 : 0 : eth_dev_close(struct rte_eth_dev *dev)
1182 : : {
1183 : : struct pmd_internal *internal;
1184 : : struct internal_list *list;
1185 : : unsigned int i, ret;
1186 : :
1187 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1188 : : return 0;
1189 : :
1190 : 0 : internal = dev->data->dev_private;
1191 [ # # ]: 0 : if (!internal)
1192 : : return 0;
1193 : :
1194 : 0 : ret = eth_dev_stop(dev);
1195 : :
1196 : 0 : list = find_internal_resource(internal->iface_name);
1197 [ # # ]: 0 : if (list) {
1198 : 0 : rte_vhost_driver_unregister(internal->iface_name);
1199 : 0 : pthread_mutex_lock(&internal_list_lock);
1200 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1201 : 0 : pthread_mutex_unlock(&internal_list_lock);
1202 : 0 : rte_free(list);
1203 : : }
1204 : :
1205 [ # # ]: 0 : if (dev->data->rx_queues)
1206 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
1207 : 0 : rte_free(dev->data->rx_queues[i]);
1208 : :
1209 [ # # ]: 0 : if (dev->data->tx_queues)
1210 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
1211 : 0 : rte_free(dev->data->tx_queues[i]);
1212 : :
1213 : 0 : rte_free(internal->iface_name);
1214 : 0 : rte_free(internal);
1215 : :
1216 : 0 : eth_vhost_uninstall_intr(dev);
1217 : :
1218 : 0 : dev->data->dev_private = NULL;
1219 : :
1220 : 0 : rte_free(vring_states[dev->data->port_id]);
1221 : 0 : vring_states[dev->data->port_id] = NULL;
1222 : :
1223 : 0 : return ret;
1224 : : }
1225 : :
1226 : : static int
1227 : 0 : eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
1228 : : uint16_t nb_rx_desc __rte_unused,
1229 : : unsigned int socket_id,
1230 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
1231 : : struct rte_mempool *mb_pool)
1232 : : {
1233 : : struct vhost_queue *vq;
1234 : :
1235 : 0 : vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
1236 : : RTE_CACHE_LINE_SIZE, socket_id);
1237 [ # # ]: 0 : if (vq == NULL) {
1238 : 0 : VHOST_LOG(ERR, "Failed to allocate memory for rx queue\n");
1239 : 0 : return -ENOMEM;
1240 : : }
1241 : :
1242 : 0 : vq->mb_pool = mb_pool;
1243 : 0 : vq->virtqueue_id = rx_queue_id * VIRTIO_QNUM + VIRTIO_TXQ;
1244 : : rte_spinlock_init(&vq->intr_lock);
1245 : 0 : vq->kickfd = -1;
1246 : 0 : dev->data->rx_queues[rx_queue_id] = vq;
1247 : :
1248 : 0 : return 0;
1249 : : }
1250 : :
1251 : : static int
1252 : 0 : eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
1253 : : uint16_t nb_tx_desc __rte_unused,
1254 : : unsigned int socket_id,
1255 : : const struct rte_eth_txconf *tx_conf __rte_unused)
1256 : : {
1257 : : struct vhost_queue *vq;
1258 : :
1259 : 0 : vq = rte_zmalloc_socket(NULL, sizeof(struct vhost_queue),
1260 : : RTE_CACHE_LINE_SIZE, socket_id);
1261 [ # # ]: 0 : if (vq == NULL) {
1262 : 0 : VHOST_LOG(ERR, "Failed to allocate memory for tx queue\n");
1263 : 0 : return -ENOMEM;
1264 : : }
1265 : :
1266 : 0 : vq->virtqueue_id = tx_queue_id * VIRTIO_QNUM + VIRTIO_RXQ;
1267 : : rte_spinlock_init(&vq->intr_lock);
1268 : 0 : vq->kickfd = -1;
1269 : 0 : dev->data->tx_queues[tx_queue_id] = vq;
1270 : :
1271 : 0 : return 0;
1272 : : }
1273 : :
1274 : : static int
1275 : 0 : eth_dev_info(struct rte_eth_dev *dev,
1276 : : struct rte_eth_dev_info *dev_info)
1277 : : {
1278 : : struct pmd_internal *internal;
1279 : :
1280 : 0 : internal = dev->data->dev_private;
1281 [ # # ]: 0 : if (internal == NULL) {
1282 : 0 : VHOST_LOG(ERR, "Invalid device specified\n");
1283 : 0 : return -ENODEV;
1284 : : }
1285 : :
1286 : 0 : dev_info->max_mac_addrs = 1;
1287 : 0 : dev_info->max_rx_pktlen = (uint32_t)-1;
1288 : 0 : dev_info->max_rx_queues = internal->max_queues;
1289 : 0 : dev_info->max_tx_queues = internal->max_queues;
1290 : 0 : dev_info->min_rx_bufsize = 0;
1291 : :
1292 : 0 : dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
1293 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
1294 [ # # ]: 0 : if (internal->flags & RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS) {
1295 : 0 : dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
1296 : : RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
1297 : : }
1298 : :
1299 : 0 : dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP;
1300 [ # # ]: 0 : if (internal->flags & RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS) {
1301 : 0 : dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
1302 : : RTE_ETH_RX_OFFLOAD_TCP_CKSUM;
1303 : : }
1304 : :
1305 : : return 0;
1306 : : }
1307 : :
1308 : : static int
1309 : 0 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
1310 : : {
1311 : : unsigned i;
1312 : : unsigned long rx_total = 0, tx_total = 0;
1313 : : unsigned long rx_total_bytes = 0, tx_total_bytes = 0;
1314 : : unsigned long tx_total_errors = 0;
1315 : : struct vhost_queue *vq;
1316 : :
1317 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
1318 [ # # ]: 0 : i < dev->data->nb_rx_queues; i++) {
1319 [ # # ]: 0 : if (dev->data->rx_queues[i] == NULL)
1320 : 0 : continue;
1321 : : vq = dev->data->rx_queues[i];
1322 : 0 : stats->q_ipackets[i] = vq->stats.pkts;
1323 : 0 : rx_total += stats->q_ipackets[i];
1324 : :
1325 : 0 : stats->q_ibytes[i] = vq->stats.bytes;
1326 : 0 : rx_total_bytes += stats->q_ibytes[i];
1327 : : }
1328 : :
1329 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
1330 [ # # ]: 0 : i < dev->data->nb_tx_queues; i++) {
1331 [ # # ]: 0 : if (dev->data->tx_queues[i] == NULL)
1332 : 0 : continue;
1333 : : vq = dev->data->tx_queues[i];
1334 : 0 : stats->q_opackets[i] = vq->stats.pkts;
1335 : 0 : tx_total += stats->q_opackets[i];
1336 : :
1337 : 0 : stats->q_obytes[i] = vq->stats.bytes;
1338 : 0 : tx_total_bytes += stats->q_obytes[i];
1339 : :
1340 : 0 : tx_total_errors += vq->stats.missed_pkts;
1341 : : }
1342 : :
1343 : 0 : stats->ipackets = rx_total;
1344 : 0 : stats->opackets = tx_total;
1345 : 0 : stats->ibytes = rx_total_bytes;
1346 : 0 : stats->obytes = tx_total_bytes;
1347 : 0 : stats->oerrors = tx_total_errors;
1348 : :
1349 : 0 : return 0;
1350 : : }
1351 : :
1352 : : static int
1353 : 0 : eth_stats_reset(struct rte_eth_dev *dev)
1354 : : {
1355 : : struct vhost_queue *vq;
1356 : : unsigned i;
1357 : :
1358 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1359 [ # # ]: 0 : if (dev->data->rx_queues[i] == NULL)
1360 : 0 : continue;
1361 : : vq = dev->data->rx_queues[i];
1362 : 0 : vq->stats.pkts = 0;
1363 : 0 : vq->stats.bytes = 0;
1364 : : }
1365 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1366 [ # # ]: 0 : if (dev->data->tx_queues[i] == NULL)
1367 : 0 : continue;
1368 : : vq = dev->data->tx_queues[i];
1369 : 0 : vq->stats.pkts = 0;
1370 : 0 : vq->stats.bytes = 0;
1371 : 0 : vq->stats.missed_pkts = 0;
1372 : : }
1373 : :
1374 : 0 : return 0;
1375 : : }
1376 : :
1377 : : static void
1378 : 0 : eth_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
1379 : : {
1380 : 0 : rte_free(dev->data->rx_queues[qid]);
1381 : 0 : }
1382 : :
1383 : : static void
1384 : 0 : eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
1385 : : {
1386 : 0 : rte_free(dev->data->tx_queues[qid]);
1387 : 0 : }
1388 : :
1389 : : static int
1390 : 0 : eth_tx_done_cleanup(void *txq __rte_unused, uint32_t free_cnt __rte_unused)
1391 : : {
1392 : : /*
1393 : : * vHost does not hang onto mbuf. eth_vhost_tx() copies packet data
1394 : : * and releases mbuf, so nothing to cleanup.
1395 : : */
1396 : 0 : return 0;
1397 : : }
1398 : :
1399 : : static int
1400 : 0 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
1401 : : int wait_to_complete __rte_unused)
1402 : : {
1403 : 0 : return 0;
1404 : : }
1405 : :
1406 : : static uint32_t
1407 : 0 : eth_rx_queue_count(void *rx_queue)
1408 : : {
1409 : : struct vhost_queue *vq;
1410 : :
1411 : : vq = rx_queue;
1412 [ # # ]: 0 : if (vq == NULL)
1413 : : return 0;
1414 : :
1415 : 0 : return rte_vhost_rx_queue_count(vq->vid, vq->virtqueue_id);
1416 : : }
1417 : :
1418 : : #define CLB_VAL_IDX 0
1419 : : #define CLB_MSK_IDX 1
1420 : : #define CLB_MATCH_IDX 2
1421 : : static int
1422 : 0 : vhost_monitor_callback(const uint64_t value,
1423 : : const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
1424 : : {
1425 : 0 : const uint64_t m = opaque[CLB_MSK_IDX];
1426 : 0 : const uint64_t v = opaque[CLB_VAL_IDX];
1427 : 0 : const uint64_t c = opaque[CLB_MATCH_IDX];
1428 : :
1429 [ # # ]: 0 : if (c)
1430 [ # # ]: 0 : return (value & m) == v ? -1 : 0;
1431 : : else
1432 [ # # ]: 0 : return (value & m) == v ? 0 : -1;
1433 : : }
1434 : :
1435 : : static int
1436 : 0 : vhost_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
1437 : : {
1438 : : struct vhost_queue *vq = rx_queue;
1439 : : struct rte_vhost_power_monitor_cond vhost_pmc;
1440 : : int ret;
1441 [ # # ]: 0 : if (vq == NULL)
1442 : : return -EINVAL;
1443 : 0 : ret = rte_vhost_get_monitor_addr(vq->vid, vq->virtqueue_id,
1444 : : &vhost_pmc);
1445 [ # # ]: 0 : if (ret < 0)
1446 : : return -EINVAL;
1447 : 0 : pmc->addr = vhost_pmc.addr;
1448 : 0 : pmc->opaque[CLB_VAL_IDX] = vhost_pmc.val;
1449 : 0 : pmc->opaque[CLB_MSK_IDX] = vhost_pmc.mask;
1450 : 0 : pmc->opaque[CLB_MATCH_IDX] = vhost_pmc.match;
1451 : 0 : pmc->size = vhost_pmc.size;
1452 : 0 : pmc->fn = vhost_monitor_callback;
1453 : :
1454 : 0 : return 0;
1455 : : }
1456 : :
1457 : : static int
1458 : 0 : vhost_dev_priv_dump(struct rte_eth_dev *dev, FILE *f)
1459 : : {
1460 : 0 : struct pmd_internal *internal = dev->data->dev_private;
1461 : :
1462 : 0 : fprintf(f, "iface_name: %s\n", internal->iface_name);
1463 : 0 : fprintf(f, "flags: 0x%" PRIx64 "\n", internal->flags);
1464 : 0 : fprintf(f, "disable_flags: 0x%" PRIx64 "\n", internal->disable_flags);
1465 : 0 : fprintf(f, "features: 0x%" PRIx64 "\n", internal->features);
1466 : 0 : fprintf(f, "max_queues: %u\n", internal->max_queues);
1467 : 0 : fprintf(f, "vid: %d\n", internal->vid);
1468 : : fprintf(f, "started: %d\n", rte_atomic32_read(&internal->started));
1469 : : fprintf(f, "dev_attached: %d\n", rte_atomic32_read(&internal->dev_attached));
1470 : 0 : fprintf(f, "vlan_strip: %d\n", internal->vlan_strip);
1471 : 0 : fprintf(f, "rx_sw_csum: %d\n", internal->rx_sw_csum);
1472 : 0 : fprintf(f, "tx_sw_csum: %d\n", internal->tx_sw_csum);
1473 : :
1474 : 0 : return 0;
1475 : : }
1476 : :
1477 : : static const struct eth_dev_ops ops = {
1478 : : .dev_start = eth_dev_start,
1479 : : .dev_stop = eth_dev_stop,
1480 : : .dev_close = eth_dev_close,
1481 : : .dev_configure = eth_dev_configure,
1482 : : .dev_infos_get = eth_dev_info,
1483 : : .rx_queue_setup = eth_rx_queue_setup,
1484 : : .tx_queue_setup = eth_tx_queue_setup,
1485 : : .rx_queue_release = eth_rx_queue_release,
1486 : : .tx_queue_release = eth_tx_queue_release,
1487 : : .tx_done_cleanup = eth_tx_done_cleanup,
1488 : : .link_update = eth_link_update,
1489 : : .stats_get = eth_stats_get,
1490 : : .stats_reset = eth_stats_reset,
1491 : : .xstats_reset = vhost_dev_xstats_reset,
1492 : : .xstats_get = vhost_dev_xstats_get,
1493 : : .xstats_get_names = vhost_dev_xstats_get_names,
1494 : : .rx_queue_intr_enable = eth_rxq_intr_enable,
1495 : : .rx_queue_intr_disable = eth_rxq_intr_disable,
1496 : : .get_monitor_addr = vhost_get_monitor_addr,
1497 : : .eth_dev_priv_dump = vhost_dev_priv_dump,
1498 : : };
1499 : :
1500 : : static int
1501 [ # # ]: 0 : eth_dev_vhost_create(struct rte_vdev_device *dev, char *iface_name,
1502 : : int16_t queues, const unsigned int numa_node, uint64_t flags,
1503 : : uint64_t disable_flags)
1504 : : {
1505 : : const char *name = rte_vdev_device_name(dev);
1506 : : struct rte_eth_dev_data *data;
1507 : : struct pmd_internal *internal = NULL;
1508 : : struct rte_eth_dev *eth_dev = NULL;
1509 : : struct rte_ether_addr *eth_addr = NULL;
1510 : :
1511 : 0 : VHOST_LOG(INFO, "Creating VHOST-USER backend on numa socket %u\n",
1512 : : numa_node);
1513 : :
1514 : : /* reserve an ethdev entry */
1515 : 0 : eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internal));
1516 [ # # ]: 0 : if (eth_dev == NULL)
1517 : 0 : goto error;
1518 : 0 : data = eth_dev->data;
1519 : :
1520 : 0 : eth_addr = rte_zmalloc_socket(name, sizeof(*eth_addr), 0, numa_node);
1521 [ # # ]: 0 : if (eth_addr == NULL)
1522 : 0 : goto error;
1523 : 0 : data->mac_addrs = eth_addr;
1524 : 0 : *eth_addr = base_eth_addr;
1525 : 0 : eth_addr->addr_bytes[5] = eth_dev->data->port_id;
1526 : :
1527 : : /* now put it all together
1528 : : * - store queue data in internal,
1529 : : * - point eth_dev_data to internals
1530 : : * - and point eth_dev structure to new eth_dev_data structure
1531 : : */
1532 : 0 : internal = eth_dev->data->dev_private;
1533 : 0 : internal->iface_name = rte_malloc_socket(name, strlen(iface_name) + 1,
1534 : : 0, numa_node);
1535 [ # # ]: 0 : if (internal->iface_name == NULL)
1536 : 0 : goto error;
1537 : : strcpy(internal->iface_name, iface_name);
1538 : :
1539 : 0 : data->nb_rx_queues = queues;
1540 : 0 : data->nb_tx_queues = queues;
1541 : 0 : internal->max_queues = queues;
1542 : 0 : internal->vid = -1;
1543 : 0 : internal->flags = flags;
1544 : 0 : internal->disable_flags = disable_flags;
1545 : 0 : data->dev_link = pmd_link;
1546 : 0 : data->dev_flags = RTE_ETH_DEV_INTR_LSC |
1547 : : RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1548 : 0 : data->promiscuous = 1;
1549 : 0 : data->all_multicast = 1;
1550 : :
1551 : 0 : eth_dev->dev_ops = &ops;
1552 : 0 : eth_dev->rx_queue_count = eth_rx_queue_count;
1553 : :
1554 : : /* finally assign rx and tx ops */
1555 : 0 : eth_dev->rx_pkt_burst = eth_vhost_rx;
1556 : 0 : eth_dev->tx_pkt_burst = eth_vhost_tx;
1557 : :
1558 : 0 : rte_eth_dev_probing_finish(eth_dev);
1559 : 0 : return 0;
1560 : :
1561 : : error:
1562 : : if (internal)
1563 : 0 : rte_free(internal->iface_name);
1564 : 0 : rte_eth_dev_release_port(eth_dev);
1565 : :
1566 : 0 : return -1;
1567 : : }
1568 : :
1569 : : static inline int
1570 : 0 : open_iface(const char *key __rte_unused, const char *value, void *extra_args)
1571 : : {
1572 : : const char **iface_name = extra_args;
1573 : :
1574 [ # # ]: 0 : if (value == NULL)
1575 : : return -1;
1576 : :
1577 : 0 : *iface_name = value;
1578 : :
1579 : 0 : return 0;
1580 : : }
1581 : :
1582 : : static inline int
1583 : 0 : open_int(const char *key __rte_unused, const char *value, void *extra_args)
1584 : : {
1585 : : uint16_t *n = extra_args;
1586 : :
1587 [ # # ]: 0 : if (value == NULL || extra_args == NULL)
1588 : : return -EINVAL;
1589 : :
1590 : 0 : *n = (uint16_t)strtoul(value, NULL, 0);
1591 [ # # # # ]: 0 : if (*n == USHRT_MAX && errno == ERANGE)
1592 : 0 : return -1;
1593 : :
1594 : : return 0;
1595 : : }
1596 : :
1597 : : static int
1598 : 0 : rte_pmd_vhost_probe(struct rte_vdev_device *dev)
1599 : : {
1600 : : struct rte_kvargs *kvlist = NULL;
1601 : : int ret = 0;
1602 : : char *iface_name;
1603 : : uint16_t queues;
1604 : : uint64_t flags = RTE_VHOST_USER_NET_STATS_ENABLE;
1605 : : uint64_t disable_flags = 0;
1606 : 0 : int client_mode = 0;
1607 : 0 : int iommu_support = 0;
1608 : 0 : int postcopy_support = 0;
1609 : 0 : int tso = 0;
1610 : 0 : int linear_buf = 0;
1611 : 0 : int ext_buf = 0;
1612 [ # # ]: 0 : int legacy_ol_flags = 0;
1613 : : struct rte_eth_dev *eth_dev;
1614 : : const char *name = rte_vdev_device_name(dev);
1615 : :
1616 : 0 : VHOST_LOG(INFO, "Initializing pmd_vhost for %s\n", name);
1617 : :
1618 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1619 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
1620 [ # # ]: 0 : if (!eth_dev) {
1621 : 0 : VHOST_LOG(ERR, "Failed to probe %s\n", name);
1622 : 0 : return -1;
1623 : : }
1624 : 0 : eth_dev->rx_pkt_burst = eth_vhost_rx;
1625 : 0 : eth_dev->tx_pkt_burst = eth_vhost_tx;
1626 : 0 : eth_dev->dev_ops = &ops;
1627 [ # # ]: 0 : if (dev->device.numa_node == SOCKET_ID_ANY)
1628 : 0 : dev->device.numa_node = rte_socket_id();
1629 : 0 : eth_dev->device = &dev->device;
1630 : 0 : rte_eth_dev_probing_finish(eth_dev);
1631 : 0 : return 0;
1632 : : }
1633 : :
1634 : 0 : kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments);
1635 [ # # ]: 0 : if (kvlist == NULL)
1636 : : return -1;
1637 : :
1638 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_IFACE_ARG) == 1) {
1639 : 0 : ret = rte_kvargs_process(kvlist, ETH_VHOST_IFACE_ARG,
1640 : : &open_iface, &iface_name);
1641 [ # # ]: 0 : if (ret < 0)
1642 : 0 : goto out_free;
1643 : : } else {
1644 : : ret = -1;
1645 : 0 : goto out_free;
1646 : : }
1647 : :
1648 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_QUEUES_ARG) == 1) {
1649 : 0 : ret = rte_kvargs_process(kvlist, ETH_VHOST_QUEUES_ARG,
1650 : : &open_int, &queues);
1651 [ # # # # ]: 0 : if (ret < 0 || queues > RTE_MAX_QUEUES_PER_PORT)
1652 : 0 : goto out_free;
1653 : :
1654 : : } else
1655 : 0 : queues = 1;
1656 : :
1657 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_CLIENT_ARG) == 1) {
1658 : 0 : ret = rte_kvargs_process(kvlist, ETH_VHOST_CLIENT_ARG,
1659 : : &open_int, &client_mode);
1660 [ # # ]: 0 : if (ret < 0)
1661 : 0 : goto out_free;
1662 : :
1663 [ # # ]: 0 : if (client_mode)
1664 : : flags |= RTE_VHOST_USER_CLIENT;
1665 : : }
1666 : :
1667 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_IOMMU_SUPPORT) == 1) {
1668 : 0 : ret = rte_kvargs_process(kvlist, ETH_VHOST_IOMMU_SUPPORT,
1669 : : &open_int, &iommu_support);
1670 [ # # ]: 0 : if (ret < 0)
1671 : 0 : goto out_free;
1672 : :
1673 [ # # ]: 0 : if (iommu_support)
1674 : 0 : flags |= RTE_VHOST_USER_IOMMU_SUPPORT;
1675 : : }
1676 : :
1677 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_POSTCOPY_SUPPORT) == 1) {
1678 : 0 : ret = rte_kvargs_process(kvlist, ETH_VHOST_POSTCOPY_SUPPORT,
1679 : : &open_int, &postcopy_support);
1680 [ # # ]: 0 : if (ret < 0)
1681 : 0 : goto out_free;
1682 : :
1683 [ # # ]: 0 : if (postcopy_support)
1684 : 0 : flags |= RTE_VHOST_USER_POSTCOPY_SUPPORT;
1685 : : }
1686 : :
1687 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_VIRTIO_NET_F_HOST_TSO) == 1) {
1688 : 0 : ret = rte_kvargs_process(kvlist,
1689 : : ETH_VHOST_VIRTIO_NET_F_HOST_TSO,
1690 : : &open_int, &tso);
1691 [ # # ]: 0 : if (ret < 0)
1692 : 0 : goto out_free;
1693 : : }
1694 : :
1695 [ # # ]: 0 : if (tso == 0) {
1696 : : disable_flags |= (1ULL << VIRTIO_NET_F_HOST_TSO4);
1697 : : disable_flags |= (1ULL << VIRTIO_NET_F_HOST_TSO6);
1698 : : }
1699 : :
1700 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_LINEAR_BUF) == 1) {
1701 : 0 : ret = rte_kvargs_process(kvlist,
1702 : : ETH_VHOST_LINEAR_BUF,
1703 : : &open_int, &linear_buf);
1704 [ # # ]: 0 : if (ret < 0)
1705 : 0 : goto out_free;
1706 : :
1707 [ # # ]: 0 : if (linear_buf == 1)
1708 : 0 : flags |= RTE_VHOST_USER_LINEARBUF_SUPPORT;
1709 : : }
1710 : :
1711 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_EXT_BUF) == 1) {
1712 : 0 : ret = rte_kvargs_process(kvlist,
1713 : : ETH_VHOST_EXT_BUF,
1714 : : &open_int, &ext_buf);
1715 [ # # ]: 0 : if (ret < 0)
1716 : 0 : goto out_free;
1717 : :
1718 [ # # ]: 0 : if (ext_buf == 1)
1719 : 0 : flags |= RTE_VHOST_USER_EXTBUF_SUPPORT;
1720 : : }
1721 : :
1722 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_VHOST_LEGACY_OL_FLAGS) == 1) {
1723 : 0 : ret = rte_kvargs_process(kvlist,
1724 : : ETH_VHOST_LEGACY_OL_FLAGS,
1725 : : &open_int, &legacy_ol_flags);
1726 [ # # ]: 0 : if (ret < 0)
1727 : 0 : goto out_free;
1728 : : }
1729 : :
1730 [ # # ]: 0 : if (legacy_ol_flags == 0)
1731 : 0 : flags |= RTE_VHOST_USER_NET_COMPLIANT_OL_FLAGS;
1732 : :
1733 [ # # ]: 0 : if (dev->device.numa_node == SOCKET_ID_ANY)
1734 : 0 : dev->device.numa_node = rte_socket_id();
1735 : :
1736 : 0 : ret = eth_dev_vhost_create(dev, iface_name, queues,
1737 : 0 : dev->device.numa_node, flags, disable_flags);
1738 [ # # ]: 0 : if (ret == -1)
1739 : 0 : VHOST_LOG(ERR, "Failed to create %s\n", name);
1740 : :
1741 : 0 : out_free:
1742 : 0 : rte_kvargs_free(kvlist);
1743 : 0 : return ret;
1744 : : }
1745 : :
1746 : : static int
1747 [ # # ]: 0 : rte_pmd_vhost_remove(struct rte_vdev_device *dev)
1748 : : {
1749 : : const char *name;
1750 : : struct rte_eth_dev *eth_dev = NULL;
1751 : :
1752 : : name = rte_vdev_device_name(dev);
1753 : 0 : VHOST_LOG(INFO, "Un-Initializing pmd_vhost for %s\n", name);
1754 : :
1755 : : /* find an ethdev entry */
1756 : 0 : eth_dev = rte_eth_dev_allocated(name);
1757 [ # # ]: 0 : if (eth_dev == NULL)
1758 : : return 0;
1759 : :
1760 : 0 : eth_dev_close(eth_dev);
1761 : 0 : rte_eth_dev_release_port(eth_dev);
1762 : :
1763 : 0 : return 0;
1764 : : }
1765 : :
1766 : : static struct rte_vdev_driver pmd_vhost_drv = {
1767 : : .probe = rte_pmd_vhost_probe,
1768 : : .remove = rte_pmd_vhost_remove,
1769 : : };
1770 : :
1771 : 235 : RTE_PMD_REGISTER_VDEV(net_vhost, pmd_vhost_drv);
1772 : : RTE_PMD_REGISTER_ALIAS(net_vhost, eth_vhost);
1773 : : RTE_PMD_REGISTER_PARAM_STRING(net_vhost,
1774 : : "iface=<ifc> "
1775 : : "queues=<int> "
1776 : : "client=<0|1> "
1777 : : "iommu-support=<0|1> "
1778 : : "postcopy-support=<0|1> "
1779 : : "tso=<0|1> "
1780 : : "linear-buffer=<0|1> "
1781 : : "ext-buffer=<0|1>");
|