Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) IGEL Co.,Ltd.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <stdlib.h>
7 : :
8 : : #include <rte_mbuf.h>
9 : : #include <ethdev_driver.h>
10 : : #include <ethdev_vdev.h>
11 : : #include <rte_malloc.h>
12 : : #include <rte_memcpy.h>
13 : : #include <bus_vdev_driver.h>
14 : : #include <rte_kvargs.h>
15 : : #include <rte_spinlock.h>
16 : :
17 : : #define ETH_NULL_PACKET_SIZE_ARG "size"
18 : : #define ETH_NULL_PACKET_COPY_ARG "copy"
19 : : #define ETH_NULL_PACKET_NO_RX_ARG "no-rx"
20 : :
21 : : static unsigned int default_packet_size = 64;
22 : : static unsigned int default_packet_copy;
23 : : static unsigned int default_no_rx;
24 : :
25 : : static const char *valid_arguments[] = {
26 : : ETH_NULL_PACKET_SIZE_ARG,
27 : : ETH_NULL_PACKET_COPY_ARG,
28 : : ETH_NULL_PACKET_NO_RX_ARG,
29 : : NULL
30 : : };
31 : :
32 : : struct pmd_internals;
33 : :
34 : : struct null_queue {
35 : : struct pmd_internals *internals;
36 : :
37 : : /**
38 : : * For RX queue:
39 : : * Mempool to allocate mbufs from.
40 : : *
41 : : * For TX queue:
42 : : * Mempool to free mbufs to, if fast release of mbufs is enabled.
43 : : * UINTPTR_MAX if the mempool for fast release of mbufs has not yet been detected.
44 : : * NULL if fast release of mbufs is not enabled.
45 : : *
46 : : * @see RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE
47 : : */
48 : : struct rte_mempool *mb_pool;
49 : : void *dummy_packet;
50 : :
51 : : uint64_t rx_pkts;
52 : : uint64_t rx_bytes;
53 : :
54 : : RTE_ATOMIC(uint64_t) tx_pkts;
55 : : RTE_ATOMIC(uint64_t) tx_bytes;
56 : : };
57 : :
58 : : struct pmd_options {
59 : : unsigned int packet_copy;
60 : : unsigned int packet_size;
61 : : unsigned int no_rx;
62 : : };
63 : :
64 : : struct pmd_internals {
65 : : unsigned int packet_size;
66 : : unsigned int packet_copy;
67 : : unsigned int no_rx;
68 : : uint16_t port_id;
69 : :
70 : : struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
71 : : struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
72 : :
73 : : struct rte_ether_addr eth_addr;
74 : : /** Bit mask of RSS offloads, the bit offset also means flow type */
75 : : uint64_t flow_type_rss_offloads;
76 : :
77 : : rte_spinlock_t rss_lock;
78 : :
79 : : uint16_t reta_size;
80 : : struct rte_eth_rss_reta_entry64 reta_conf[RTE_ETH_RSS_RETA_SIZE_128 /
81 : : RTE_ETH_RETA_GROUP_SIZE];
82 : :
83 : : uint8_t rss_key[40]; /**< 40-byte hash key. */
84 : : };
85 : : static struct rte_eth_link pmd_link = {
86 : : .link_speed = RTE_ETH_SPEED_NUM_10G,
87 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
88 : : .link_status = RTE_ETH_LINK_DOWN,
89 : : .link_autoneg = RTE_ETH_LINK_FIXED,
90 : : };
91 : :
92 [ - + ]: 253 : RTE_LOG_REGISTER_DEFAULT(eth_null_logtype, NOTICE);
93 : : #define RTE_LOGTYPE_ETH_NULL eth_null_logtype
94 : :
95 : : #define PMD_LOG(level, ...) \
96 : : RTE_LOG_LINE_PREFIX(level, ETH_NULL, "%s(): ", __func__, __VA_ARGS__)
97 : :
98 : : static uint16_t
99 : 0 : eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
100 : : {
101 : : unsigned int i;
102 : : struct null_queue *h = q;
103 : : unsigned int packet_size;
104 : : uint64_t bytes = 0;
105 : :
106 : 0 : packet_size = h->internals->packet_size;
107 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
108 : : return 0;
109 : :
110 [ # # ]: 0 : for (i = 0; i < nb_bufs; i++) {
111 : 0 : bufs[i]->data_len = (uint16_t)packet_size;
112 : 0 : bufs[i]->pkt_len = packet_size;
113 : 0 : bytes += packet_size;
114 : 0 : bufs[i]->port = h->internals->port_id;
115 : : }
116 : :
117 : 0 : h->rx_pkts += nb_bufs;
118 : 0 : h->rx_bytes += bytes;
119 : 0 : return nb_bufs;
120 : : }
121 : :
122 : : static uint16_t
123 : 0 : eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
124 : : {
125 : : unsigned int i;
126 : : struct null_queue *h = q;
127 : : unsigned int packet_size;
128 : : uint64_t bytes = 0;
129 : :
130 : 0 : packet_size = h->internals->packet_size;
131 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(h->mb_pool, bufs, nb_bufs) != 0)
132 : : return 0;
133 : :
134 [ # # ]: 0 : for (i = 0; i < nb_bufs; i++) {
135 [ # # ]: 0 : rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
136 : : packet_size);
137 : 0 : bufs[i]->data_len = (uint16_t)packet_size;
138 : 0 : bufs[i]->pkt_len = packet_size;
139 : 0 : bytes += packet_size;
140 : 0 : bufs[i]->port = h->internals->port_id;
141 : : }
142 : :
143 : 0 : h->rx_pkts += nb_bufs;
144 : 0 : h->rx_bytes += bytes;
145 : 0 : return nb_bufs;
146 : : }
147 : :
148 : : static uint16_t
149 : 0 : eth_null_no_rx(void *q __rte_unused, struct rte_mbuf **bufs __rte_unused,
150 : : uint16_t nb_bufs __rte_unused)
151 : : {
152 : 0 : return 0;
153 : : }
154 : :
155 : : enum eth_tx_free_mode {
156 : : ETH_TX_FREE_MODE_NO_MBUF_FAST_FREE, /* MBUF_FAST_FREE not possible. */
157 : : ETH_TX_FREE_MODE_MBUF_FAST_FREE, /* MBUF_FAST_FREE enabled for the device. */
158 : : ETH_TX_FREE_MODE_PER_QUEUE, /* Varies per TX queue. */
159 : : };
160 : :
161 : : static __rte_always_inline uint16_t
162 : : eth_null_tx_common(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs,
163 : : enum eth_tx_free_mode mode)
164 : : {
165 : : struct null_queue *h = q;
166 : : unsigned int i;
167 : : uint64_t bytes = 0;
168 : :
169 [ # # # # : 0 : for (i = 0; i < nb_bufs; i++)
# # ]
170 : 0 : bytes += rte_pktmbuf_pkt_len(bufs[i]);
171 : :
172 : : if (mode == ETH_TX_FREE_MODE_MBUF_FAST_FREE ||
173 [ # # ]: 0 : (mode == ETH_TX_FREE_MODE_PER_QUEUE && h->mb_pool != NULL)) {
174 : : /* RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE */
175 [ # # # # ]: 0 : if (unlikely(h->mb_pool == (void *)UINTPTR_MAX)) {
176 [ # # # # ]: 0 : if (unlikely(nb_bufs == 0))
177 : : return 0; /* Do not dereference uninitialized bufs[0]. */
178 : 0 : h->mb_pool = bufs[0]->pool;
179 : : }
180 [ # # # # ]: 0 : rte_mbuf_raw_free_bulk(h->mb_pool, bufs, nb_bufs);
181 : : } else {
182 : 0 : rte_pktmbuf_free_bulk(bufs, nb_bufs);
183 : : }
184 : 0 : rte_atomic_fetch_add_explicit(&h->tx_pkts, nb_bufs, rte_memory_order_relaxed);
185 : 0 : rte_atomic_fetch_add_explicit(&h->tx_bytes, bytes, rte_memory_order_relaxed);
186 : :
187 : 0 : return nb_bufs;
188 : : }
189 : :
190 : : static uint16_t
191 : 0 : eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
192 : : {
193 : 0 : return eth_null_tx_common(q, bufs, nb_bufs, ETH_TX_FREE_MODE_PER_QUEUE);
194 : : }
195 : :
196 : : static uint16_t
197 : 0 : eth_null_tx_no_mbuf_fast_free(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
198 : : {
199 : 0 : return eth_null_tx_common(q, bufs, nb_bufs, ETH_TX_FREE_MODE_NO_MBUF_FAST_FREE);
200 : : }
201 : :
202 : : static uint16_t
203 : 0 : eth_null_tx_mbuf_fast_free(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
204 : : {
205 : 0 : return eth_null_tx_common(q, bufs, nb_bufs, ETH_TX_FREE_MODE_MBUF_FAST_FREE);
206 : : }
207 : :
208 : : static uint16_t
209 : 0 : eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
210 : : {
211 : : struct null_queue *h = q;
212 : : unsigned int i;
213 : : uint64_t bytes = 0;
214 : :
215 [ # # ]: 0 : for (i = 0; i < nb_bufs; i++) {
216 : 0 : struct rte_mbuf *m = bufs[i];
217 : 0 : size_t len = RTE_MIN(h->internals->packet_size, m->data_len);
218 : :
219 [ # # ]: 0 : rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(m, void *), len);
220 : 0 : bytes += m->pkt_len;
221 : : }
222 : :
223 : 0 : rte_atomic_fetch_add_explicit(&h->tx_pkts, nb_bufs, rte_memory_order_relaxed);
224 : 0 : rte_atomic_fetch_add_explicit(&h->tx_bytes, bytes, rte_memory_order_relaxed);
225 : 0 : return nb_bufs;
226 : : }
227 : :
228 : : static void
229 : 8 : eth_dev_assign_rxtx_ops(struct rte_eth_dev *dev)
230 : : {
231 : 8 : struct pmd_internals *internals = dev->data->dev_private;
232 : :
233 [ - + ]: 8 : if (internals->packet_copy) {
234 : 0 : dev->rx_pkt_burst = eth_null_copy_rx;
235 : 0 : dev->tx_pkt_burst = eth_null_copy_tx;
236 : : } else {
237 [ - + ]: 8 : if (internals->no_rx)
238 : 0 : dev->rx_pkt_burst = eth_null_no_rx;
239 : : else
240 : 8 : dev->rx_pkt_burst = eth_null_rx;
241 : :
242 : 8 : dev->tx_pkt_burst = eth_null_tx;
243 [ - + ]: 8 : if (dev->data->dev_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS)
244 : 0 : dev->tx_pkt_burst = eth_null_tx_no_mbuf_fast_free;
245 [ - + ]: 8 : if (dev->data->dev_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
246 : 0 : dev->tx_pkt_burst = eth_null_tx_mbuf_fast_free;
247 : : }
248 : 8 : }
249 : :
250 : : static int
251 : 2 : eth_dev_configure(struct rte_eth_dev *dev)
252 : : {
253 : 2 : struct pmd_internals *internals = dev->data->dev_private;
254 : :
255 [ - + ]: 2 : if ((dev->data->dev_conf.txmode.offloads &
256 : : (RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) ==
257 : : (RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) {
258 : 0 : PMD_LOG(ERR,
259 : : "TX offloads MBUF_FAST_FREE and MULTI_SEGS are mutually exclusive");
260 : 0 : return -EINVAL;
261 : : }
262 [ - + ]: 2 : if (dev->data->dev_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE &&
263 [ # # ]: 0 : internals->packet_copy) {
264 : 0 : PMD_LOG(INFO,
265 : : "TX offload MBUF_FAST_FREE is ignored with %s argument",
266 : : ETH_NULL_PACKET_COPY_ARG);
267 : : }
268 : : /* Assign RX/TX ops depending on device TX offloads. */
269 : 2 : eth_dev_assign_rxtx_ops(dev);
270 : 2 : return 0;
271 : : }
272 : :
273 : : static int
274 : 0 : eth_dev_start(struct rte_eth_dev *dev)
275 : : {
276 : : uint16_t i;
277 : :
278 [ # # ]: 0 : if (dev == NULL)
279 : : return -EINVAL;
280 : :
281 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
282 : :
283 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
284 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
285 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
286 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
287 : :
288 : : return 0;
289 : : }
290 : :
291 : : static int
292 : 0 : eth_dev_stop(struct rte_eth_dev *dev)
293 : : {
294 : : uint16_t i;
295 : :
296 [ # # ]: 0 : if (dev == NULL)
297 : : return 0;
298 : :
299 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
300 : :
301 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
302 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
303 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
304 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
305 : :
306 : : return 0;
307 : : }
308 : :
309 : : static int
310 : 0 : eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
311 : : uint16_t nb_rx_desc __rte_unused,
312 : : unsigned int socket_id __rte_unused,
313 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
314 : : struct rte_mempool *mb_pool)
315 : : {
316 : : struct rte_mbuf *dummy_packet;
317 : : struct pmd_internals *internals;
318 : : unsigned int packet_size;
319 : :
320 [ # # ]: 0 : if ((dev == NULL) || (mb_pool == NULL))
321 : : return -EINVAL;
322 : :
323 : 0 : internals = dev->data->dev_private;
324 : :
325 [ # # ]: 0 : if (rx_queue_id >= dev->data->nb_rx_queues)
326 : : return -ENODEV;
327 : :
328 : 0 : packet_size = internals->packet_size;
329 : :
330 : 0 : internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
331 : 0 : dev->data->rx_queues[rx_queue_id] =
332 : 0 : &internals->rx_null_queues[rx_queue_id];
333 : 0 : dummy_packet = rte_zmalloc_socket(NULL,
334 : 0 : packet_size, 0, dev->data->numa_node);
335 [ # # ]: 0 : if (dummy_packet == NULL)
336 : : return -ENOMEM;
337 : :
338 : 0 : internals->rx_null_queues[rx_queue_id].internals = internals;
339 : 0 : internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
340 : :
341 : 0 : return 0;
342 : : }
343 : :
344 : : static int
345 : 0 : eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
346 : : uint16_t nb_tx_desc __rte_unused,
347 : : unsigned int socket_id __rte_unused,
348 : : const struct rte_eth_txconf *tx_conf)
349 : : {
350 : : struct rte_mbuf *dummy_packet;
351 : : struct pmd_internals *internals;
352 : : unsigned int packet_size;
353 : :
354 [ # # ]: 0 : if (dev == NULL)
355 : : return -EINVAL;
356 : :
357 : 0 : internals = dev->data->dev_private;
358 : :
359 [ # # ]: 0 : if (tx_queue_id >= dev->data->nb_tx_queues)
360 : : return -ENODEV;
361 : :
362 [ # # ]: 0 : if (((dev->data->dev_conf.txmode.offloads | tx_conf->offloads) &
363 : : (RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) ==
364 : : (RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) {
365 : 0 : PMD_LOG(ERR,
366 : : "TX offloads MBUF_FAST_FREE and MULTI_SEGS are mutually exclusive");
367 : 0 : return -EINVAL;
368 : : }
369 [ # # ]: 0 : if (tx_conf->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE &&
370 [ # # ]: 0 : internals->packet_copy) {
371 : 0 : PMD_LOG(INFO,
372 : : "TX offload MBUF_FAST_FREE is ignored with %s argument",
373 : : ETH_NULL_PACKET_COPY_ARG);
374 : : }
375 : :
376 : 0 : packet_size = internals->packet_size;
377 : :
378 : 0 : dev->data->tx_queues[tx_queue_id] =
379 : 0 : &internals->tx_null_queues[tx_queue_id];
380 : 0 : dummy_packet = rte_zmalloc_socket(NULL,
381 : 0 : packet_size, 0, dev->data->numa_node);
382 [ # # ]: 0 : if (dummy_packet == NULL)
383 : : return -ENOMEM;
384 : :
385 : 0 : internals->tx_null_queues[tx_queue_id].internals = internals;
386 : 0 : internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
387 : 0 : internals->tx_null_queues[tx_queue_id].mb_pool =
388 : 0 : (dev->data->dev_conf.txmode.offloads | tx_conf->offloads) &
389 : : RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE ?
390 [ # # ]: 0 : (void *)UINTPTR_MAX : NULL;
391 : :
392 : 0 : return 0;
393 : : }
394 : :
395 : : static int
396 : 0 : eth_mtu_set(struct rte_eth_dev *dev __rte_unused, uint16_t mtu __rte_unused)
397 : : {
398 : 0 : return 0;
399 : : }
400 : :
401 : : static int
402 : 9 : eth_dev_info(struct rte_eth_dev *dev,
403 : : struct rte_eth_dev_info *dev_info)
404 : : {
405 : : struct pmd_internals *internals;
406 : :
407 [ + - ]: 9 : if ((dev == NULL) || (dev_info == NULL))
408 : : return -EINVAL;
409 : :
410 : 9 : internals = dev->data->dev_private;
411 : 9 : dev_info->max_mac_addrs = 1;
412 : 9 : dev_info->max_rx_pktlen = (uint32_t)-1;
413 : 9 : dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
414 : 9 : dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
415 : 9 : dev_info->min_rx_bufsize = 0;
416 : 9 : dev_info->tx_queue_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
417 : : RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
418 : 9 : dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MT_LOCKFREE |
419 : : dev_info->tx_queue_offload_capa;
420 : :
421 : 9 : dev_info->reta_size = internals->reta_size;
422 : 9 : dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
423 : 9 : dev_info->hash_key_size = sizeof(internals->rss_key);
424 : :
425 : 9 : return 0;
426 : : }
427 : :
428 : : static int
429 : 2 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
430 : : struct eth_queue_stats *qstats)
431 : : {
432 : 2 : const struct pmd_internals *internal = dev->data->dev_private;
433 : : unsigned int i;
434 : :
435 [ + + ]: 4 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
436 : 2 : uint64_t pkts = internal->rx_null_queues[i].rx_pkts;
437 : 2 : uint64_t bytes = internal->rx_null_queues[i].rx_bytes;
438 : :
439 : 2 : stats->ipackets += pkts;
440 : 2 : stats->ibytes += bytes;
441 : :
442 [ + + ]: 2 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
443 : 1 : qstats->q_ipackets[i] = pkts;
444 : 1 : qstats->q_ibytes[i] = bytes;
445 : : }
446 : : }
447 : :
448 [ + + ]: 4 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
449 : : const struct null_queue *q = &internal->tx_null_queues[i];
450 : : uint64_t pkts, bytes;
451 : :
452 : 2 : pkts = rte_atomic_load_explicit(&q->tx_pkts, rte_memory_order_relaxed);
453 : 2 : bytes = rte_atomic_load_explicit(&q->tx_bytes, rte_memory_order_relaxed);
454 : :
455 : 2 : stats->opackets = pkts;
456 : 2 : stats->obytes = bytes;
457 : :
458 [ + + ]: 2 : if (qstats != NULL && i < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
459 : 1 : qstats->q_opackets[i] = pkts;
460 : 1 : qstats->q_obytes[i] = bytes;
461 : : }
462 : : }
463 : :
464 : 2 : return 0;
465 : : }
466 : :
467 : : static int
468 : 0 : eth_stats_reset(struct rte_eth_dev *dev)
469 : : {
470 : 0 : struct pmd_internals *internal = dev->data->dev_private;
471 : : unsigned int i;
472 : :
473 [ # # ]: 0 : for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++) {
474 : 0 : internal->rx_null_queues[i].rx_pkts = 0;
475 : 0 : internal->rx_null_queues[i].rx_bytes = 0;
476 : : }
477 : :
478 [ # # ]: 0 : for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) {
479 : : struct null_queue *q = &internal->tx_null_queues[i];
480 : :
481 : 0 : rte_atomic_store_explicit(&q->tx_pkts, 0, rte_memory_order_relaxed);
482 : 0 : rte_atomic_store_explicit(&q->tx_bytes, 0, rte_memory_order_relaxed);
483 : : }
484 : :
485 : 0 : return 0;
486 : : }
487 : :
488 : : static void
489 : 0 : eth_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
490 : : {
491 : 0 : struct null_queue *nq = dev->data->rx_queues[qid];
492 : :
493 [ # # ]: 0 : if (nq == NULL)
494 : : return;
495 : :
496 : 0 : rte_free(nq->dummy_packet);
497 : : }
498 : :
499 : : static void
500 : 0 : eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
501 : : {
502 : 0 : struct null_queue *nq = dev->data->tx_queues[qid];
503 : :
504 [ # # ]: 0 : if (nq == NULL)
505 : : return;
506 : :
507 : 0 : rte_free(nq->dummy_packet);
508 : : }
509 : :
510 : : static int
511 : 5 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
512 : 5 : int wait_to_complete __rte_unused) { return 0; }
513 : :
514 : : static int
515 : 0 : eth_rss_reta_update(struct rte_eth_dev *dev,
516 : : struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
517 : : {
518 : : int i, j;
519 : 0 : struct pmd_internals *internal = dev->data->dev_private;
520 : :
521 [ # # ]: 0 : if (reta_size != internal->reta_size)
522 : : return -EINVAL;
523 : :
524 : 0 : rte_spinlock_lock(&internal->rss_lock);
525 : :
526 : : /* Copy RETA table */
527 [ # # ]: 0 : for (i = 0; i < (internal->reta_size / RTE_ETH_RETA_GROUP_SIZE); i++) {
528 : 0 : internal->reta_conf[i].mask = reta_conf[i].mask;
529 [ # # ]: 0 : for (j = 0; j < RTE_ETH_RETA_GROUP_SIZE; j++)
530 [ # # ]: 0 : if ((reta_conf[i].mask >> j) & 0x01)
531 : 0 : internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
532 : : }
533 : :
534 : : rte_spinlock_unlock(&internal->rss_lock);
535 : :
536 : 0 : return 0;
537 : : }
538 : :
539 : : static int
540 : 0 : eth_rss_reta_query(struct rte_eth_dev *dev,
541 : : struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
542 : : {
543 : : int i, j;
544 : 0 : struct pmd_internals *internal = dev->data->dev_private;
545 : :
546 [ # # ]: 0 : if (reta_size != internal->reta_size)
547 : : return -EINVAL;
548 : :
549 : 0 : rte_spinlock_lock(&internal->rss_lock);
550 : :
551 : : /* Copy RETA table */
552 [ # # ]: 0 : for (i = 0; i < (internal->reta_size / RTE_ETH_RETA_GROUP_SIZE); i++) {
553 [ # # ]: 0 : for (j = 0; j < RTE_ETH_RETA_GROUP_SIZE; j++)
554 [ # # ]: 0 : if ((reta_conf[i].mask >> j) & 0x01)
555 : 0 : reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
556 : : }
557 : :
558 : : rte_spinlock_unlock(&internal->rss_lock);
559 : :
560 : 0 : return 0;
561 : : }
562 : :
563 : : static int
564 : 0 : eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
565 : : {
566 : 0 : struct pmd_internals *internal = dev->data->dev_private;
567 : :
568 : 0 : rte_spinlock_lock(&internal->rss_lock);
569 : :
570 [ # # ]: 0 : if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
571 : 0 : dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
572 : : rss_conf->rss_hf & internal->flow_type_rss_offloads;
573 : :
574 [ # # ]: 0 : if (rss_conf->rss_key)
575 [ # # ]: 0 : rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
576 : :
577 : : rte_spinlock_unlock(&internal->rss_lock);
578 : :
579 : 0 : return 0;
580 : : }
581 : :
582 : : static int
583 : 1 : eth_rss_hash_conf_get(struct rte_eth_dev *dev,
584 : : struct rte_eth_rss_conf *rss_conf)
585 : : {
586 : 1 : struct pmd_internals *internal = dev->data->dev_private;
587 : :
588 : 1 : rte_spinlock_lock(&internal->rss_lock);
589 : :
590 : 1 : rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
591 [ + - ]: 1 : if (rss_conf->rss_key)
592 [ - + ]: 1 : rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
593 : :
594 : : rte_spinlock_unlock(&internal->rss_lock);
595 : :
596 : 1 : return 0;
597 : : }
598 : :
599 : : static int
600 : 0 : eth_mac_address_set(__rte_unused struct rte_eth_dev *dev,
601 : : __rte_unused struct rte_ether_addr *addr)
602 : : {
603 : 0 : return 0;
604 : : }
605 : :
606 : : static int
607 : 6 : eth_dev_close(struct rte_eth_dev *dev)
608 : : {
609 : 6 : PMD_LOG(INFO, "Closing null ethdev on NUMA socket %u",
610 : : rte_socket_id());
611 : :
612 [ + - ]: 6 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
613 : : return 0;
614 : :
615 : : /* mac_addrs must not be freed alone because part of dev_private */
616 : 6 : dev->data->mac_addrs = NULL;
617 : :
618 : 6 : return 0;
619 : : }
620 : :
621 : : static const struct eth_dev_ops ops = {
622 : : .dev_close = eth_dev_close,
623 : : .dev_start = eth_dev_start,
624 : : .dev_stop = eth_dev_stop,
625 : : .dev_configure = eth_dev_configure,
626 : : .dev_infos_get = eth_dev_info,
627 : : .rx_queue_setup = eth_rx_queue_setup,
628 : : .tx_queue_setup = eth_tx_queue_setup,
629 : : .rx_queue_release = eth_rx_queue_release,
630 : : .tx_queue_release = eth_tx_queue_release,
631 : : .mtu_set = eth_mtu_set,
632 : : .link_update = eth_link_update,
633 : : .mac_addr_set = eth_mac_address_set,
634 : : .stats_get = eth_stats_get,
635 : : .stats_reset = eth_stats_reset,
636 : : .reta_update = eth_rss_reta_update,
637 : : .reta_query = eth_rss_reta_query,
638 : : .rss_hash_update = eth_rss_hash_update,
639 : : .rss_hash_conf_get = eth_rss_hash_conf_get
640 : : };
641 : :
642 : : static int
643 : 6 : eth_dev_null_create(struct rte_vdev_device *dev, struct pmd_options *args)
644 : : {
645 : : const unsigned int nb_rx_queues = 1;
646 : : const unsigned int nb_tx_queues = 1;
647 : : struct rte_eth_dev_data *data;
648 : : struct pmd_internals *internals = NULL;
649 : : struct rte_eth_dev *eth_dev = NULL;
650 : :
651 : : static const uint8_t default_rss_key[40] = {
652 : : 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
653 : : 0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
654 : : 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
655 : : 0xBE, 0xAC, 0x01, 0xFA
656 : : };
657 : :
658 [ + - ]: 6 : if (dev->device.numa_node == SOCKET_ID_ANY)
659 : 6 : dev->device.numa_node = rte_socket_id();
660 : :
661 : 6 : PMD_LOG(INFO, "Creating null ethdev on numa socket %u",
662 : : dev->device.numa_node);
663 : :
664 : 6 : eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
665 [ + - ]: 6 : if (!eth_dev)
666 : : return -ENOMEM;
667 : :
668 : : /* now put it all together
669 : : * - store queue data in internals,
670 : : * - store numa_node info in ethdev data
671 : : * - point eth_dev_data to internals
672 : : * - and point eth_dev structure to new eth_dev_data structure
673 : : */
674 : : /* NOTE: we'll replace the data element, of originally allocated eth_dev
675 : : * so the nulls are local per-process */
676 : :
677 : 6 : internals = eth_dev->data->dev_private;
678 : 6 : internals->packet_size = args->packet_size;
679 : 6 : internals->packet_copy = args->packet_copy;
680 : 6 : internals->no_rx = args->no_rx;
681 : 6 : internals->port_id = eth_dev->data->port_id;
682 : 6 : rte_eth_random_addr(internals->eth_addr.addr_bytes);
683 : :
684 : 6 : internals->flow_type_rss_offloads = RTE_ETH_RSS_PROTO_MASK;
685 : 6 : internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_ETH_RETA_GROUP_SIZE;
686 : :
687 [ - + ]: 6 : rte_memcpy(internals->rss_key, default_rss_key, 40);
688 : :
689 : 6 : data = eth_dev->data;
690 : 6 : data->nb_rx_queues = (uint16_t)nb_rx_queues;
691 : 6 : data->nb_tx_queues = (uint16_t)nb_tx_queues;
692 : 6 : data->dev_link = pmd_link;
693 : 6 : data->mac_addrs = &internals->eth_addr;
694 : 6 : data->promiscuous = 1;
695 : 6 : data->all_multicast = 1;
696 : 6 : data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
697 : :
698 : 6 : eth_dev->dev_ops = &ops;
699 : :
700 : : /* finally assign rx and tx ops */
701 : 6 : eth_dev_assign_rxtx_ops(eth_dev);
702 : :
703 : 6 : rte_eth_dev_probing_finish(eth_dev);
704 : 6 : return 0;
705 : : }
706 : :
707 : : static inline int
708 : 0 : get_packet_size_arg(const char *key __rte_unused,
709 : : const char *value, void *extra_args)
710 : : {
711 : : const char *a = value;
712 : : unsigned int *packet_size = extra_args;
713 : :
714 [ # # ]: 0 : if ((value == NULL) || (extra_args == NULL))
715 : : return -EINVAL;
716 : :
717 : 0 : *packet_size = (unsigned int)strtoul(a, NULL, 0);
718 [ # # ]: 0 : if (*packet_size == UINT_MAX)
719 : 0 : return -1;
720 : :
721 : : return 0;
722 : : }
723 : :
724 : : static inline int
725 : 0 : get_packet_copy_arg(const char *key __rte_unused,
726 : : const char *value, void *extra_args)
727 : : {
728 : : const char *a = value;
729 : : unsigned int *packet_copy = extra_args;
730 : :
731 [ # # ]: 0 : if ((value == NULL) || (extra_args == NULL))
732 : : return -EINVAL;
733 : :
734 : 0 : *packet_copy = (unsigned int)strtoul(a, NULL, 0);
735 [ # # ]: 0 : if (*packet_copy == UINT_MAX)
736 : 0 : return -1;
737 : :
738 : : return 0;
739 : : }
740 : :
741 : : static int
742 : 0 : get_packet_no_rx_arg(const char *key __rte_unused,
743 : : const char *value, void *extra_args)
744 : : {
745 : : const char *a = value;
746 : : unsigned int no_rx;
747 : :
748 [ # # ]: 0 : if (value == NULL || extra_args == NULL)
749 : : return -EINVAL;
750 : :
751 : 0 : no_rx = (unsigned int)strtoul(a, NULL, 0);
752 [ # # ]: 0 : if (no_rx != 0 && no_rx != 1)
753 : : return -1;
754 : :
755 : 0 : *(unsigned int *)extra_args = no_rx;
756 : 0 : return 0;
757 : : }
758 : :
759 : : static int
760 : 6 : rte_pmd_null_probe(struct rte_vdev_device *dev)
761 : : {
762 : : const char *name, *params;
763 : 6 : struct pmd_options args = {
764 : : .packet_copy = default_packet_copy,
765 : : .packet_size = default_packet_size,
766 : : .no_rx = default_no_rx,
767 : : };
768 : : struct rte_kvargs *kvlist = NULL;
769 : : struct rte_eth_dev *eth_dev;
770 : : int ret;
771 : :
772 [ + - ]: 6 : if (!dev)
773 : : return -EINVAL;
774 : :
775 : : name = rte_vdev_device_name(dev);
776 : : params = rte_vdev_device_args(dev);
777 : 6 : PMD_LOG(INFO, "Initializing pmd_null for %s", name);
778 : :
779 [ - + ]: 6 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
780 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
781 [ # # ]: 0 : if (!eth_dev) {
782 : 0 : PMD_LOG(ERR, "Failed to probe %s", name);
783 : 0 : return -1;
784 : : }
785 : : /* TODO: request info from primary to set up Rx and Tx */
786 : 0 : eth_dev->dev_ops = &ops;
787 : 0 : eth_dev->device = &dev->device;
788 : 0 : eth_dev_assign_rxtx_ops(eth_dev);
789 : 0 : rte_eth_dev_probing_finish(eth_dev);
790 : 0 : return 0;
791 : : }
792 : :
793 [ + - ]: 6 : if (params != NULL) {
794 : 6 : kvlist = rte_kvargs_parse(params, valid_arguments);
795 [ + - ]: 6 : if (kvlist == NULL)
796 : : return -1;
797 : :
798 : 6 : ret = rte_kvargs_process(kvlist,
799 : : ETH_NULL_PACKET_SIZE_ARG,
800 : : &get_packet_size_arg, &args.packet_size);
801 [ - + ]: 6 : if (ret < 0)
802 : 0 : goto free_kvlist;
803 : :
804 : :
805 : 6 : ret = rte_kvargs_process(kvlist,
806 : : ETH_NULL_PACKET_COPY_ARG,
807 : : &get_packet_copy_arg, &args.packet_copy);
808 [ - + ]: 6 : if (ret < 0)
809 : 0 : goto free_kvlist;
810 : :
811 : 6 : ret = rte_kvargs_process(kvlist,
812 : : ETH_NULL_PACKET_NO_RX_ARG,
813 : : &get_packet_no_rx_arg, &args.no_rx);
814 [ - + ]: 6 : if (ret < 0)
815 : 0 : goto free_kvlist;
816 : :
817 [ - + - - ]: 6 : if (args.no_rx && args.packet_copy) {
818 : 0 : PMD_LOG(ERR,
819 : : "Both %s and %s arguments at the same time not supported",
820 : : ETH_NULL_PACKET_COPY_ARG,
821 : : ETH_NULL_PACKET_NO_RX_ARG);
822 : 0 : goto free_kvlist;
823 : : }
824 : : }
825 : :
826 [ + - ]: 12 : PMD_LOG(INFO, "Configure pmd_null: packet size is %d, "
827 : : "packet copy is %s", args.packet_size,
828 : : args.packet_copy ? "enabled" : "disabled");
829 : :
830 : 6 : ret = eth_dev_null_create(dev, &args);
831 : :
832 : 6 : free_kvlist:
833 : 6 : rte_kvargs_free(kvlist);
834 : 6 : return ret;
835 : : }
836 : :
837 : : static int
838 : 6 : rte_pmd_null_remove(struct rte_vdev_device *dev)
839 : : {
840 : : struct rte_eth_dev *eth_dev = NULL;
841 : :
842 [ + - ]: 6 : if (!dev)
843 : : return -EINVAL;
844 : :
845 : : /* find the ethdev entry */
846 : 6 : eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
847 [ + - ]: 6 : if (eth_dev == NULL)
848 : : return 0; /* port already released */
849 : :
850 : 6 : eth_dev_close(eth_dev);
851 : 6 : rte_eth_dev_release_port(eth_dev);
852 : :
853 : 6 : return 0;
854 : : }
855 : :
856 : : static struct rte_vdev_driver pmd_null_drv = {
857 : : .probe = rte_pmd_null_probe,
858 : : .remove = rte_pmd_null_remove,
859 : : };
860 : :
861 : 253 : RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
862 : : RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
863 : : RTE_PMD_REGISTER_PARAM_STRING(net_null,
864 : : "size=<int> "
865 : : "copy=<int> "
866 : : ETH_NULL_PACKET_NO_RX_ARG "=0|1");
|