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