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