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