xref: /dpdk/drivers/net/null/rte_eth_null.c (revision d5b0924ba6baae2cb6ac7c880db0977d4befedc6)
1b3b413f7SBruce Richardson /*-
2b3b413f7SBruce Richardson  *   BSD LICENSE
3b3b413f7SBruce Richardson  *
4b3b413f7SBruce Richardson  *   Copyright (C) IGEL Co.,Ltd.
5b3b413f7SBruce Richardson  *   All rights reserved.
6b3b413f7SBruce Richardson  *
7b3b413f7SBruce Richardson  *   Redistribution and use in source and binary forms, with or without
8b3b413f7SBruce Richardson  *   modification, are permitted provided that the following conditions
9b3b413f7SBruce Richardson  *   are met:
10b3b413f7SBruce Richardson  *
11b3b413f7SBruce Richardson  *     * Redistributions of source code must retain the above copyright
12b3b413f7SBruce Richardson  *       notice, this list of conditions and the following disclaimer.
13b3b413f7SBruce Richardson  *     * Redistributions in binary form must reproduce the above copyright
14b3b413f7SBruce Richardson  *       notice, this list of conditions and the following disclaimer in
15b3b413f7SBruce Richardson  *       the documentation and/or other materials provided with the
16b3b413f7SBruce Richardson  *       distribution.
17b3b413f7SBruce Richardson  *     * Neither the name of IGEL Co.,Ltd. nor the names of its
18b3b413f7SBruce Richardson  *       contributors may be used to endorse or promote products derived
19b3b413f7SBruce Richardson  *       from this software without specific prior written permission.
20b3b413f7SBruce Richardson  *
21b3b413f7SBruce Richardson  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22b3b413f7SBruce Richardson  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23b3b413f7SBruce Richardson  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24b3b413f7SBruce Richardson  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25b3b413f7SBruce Richardson  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26b3b413f7SBruce Richardson  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27b3b413f7SBruce Richardson  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28b3b413f7SBruce Richardson  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29b3b413f7SBruce Richardson  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30b3b413f7SBruce Richardson  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31b3b413f7SBruce Richardson  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32b3b413f7SBruce Richardson  */
33b3b413f7SBruce Richardson 
34b3b413f7SBruce Richardson #include <rte_mbuf.h>
35b3b413f7SBruce Richardson #include <rte_ethdev.h>
36050fe6e9SJan Blunck #include <rte_ethdev_vdev.h>
37b3b413f7SBruce Richardson #include <rte_malloc.h>
38b3b413f7SBruce Richardson #include <rte_memcpy.h>
39fe363dd4SJan Viktorin #include <rte_vdev.h>
40b3b413f7SBruce Richardson #include <rte_kvargs.h>
411ccec0a8STomasz Kulasek #include <rte_spinlock.h>
42b3b413f7SBruce Richardson 
43b3b413f7SBruce Richardson #define ETH_NULL_PACKET_SIZE_ARG	"size"
44b3b413f7SBruce Richardson #define ETH_NULL_PACKET_COPY_ARG	"copy"
45b3b413f7SBruce Richardson 
46b3b413f7SBruce Richardson static unsigned default_packet_size = 64;
47b3b413f7SBruce Richardson static unsigned default_packet_copy;
48b3b413f7SBruce Richardson 
49b3b413f7SBruce Richardson static const char *valid_arguments[] = {
50b3b413f7SBruce Richardson 	ETH_NULL_PACKET_SIZE_ARG,
51b3b413f7SBruce Richardson 	ETH_NULL_PACKET_COPY_ARG,
52b3b413f7SBruce Richardson 	NULL
53b3b413f7SBruce Richardson };
54b3b413f7SBruce Richardson 
55b3b413f7SBruce Richardson struct pmd_internals;
56b3b413f7SBruce Richardson 
57b3b413f7SBruce Richardson struct null_queue {
58b3b413f7SBruce Richardson 	struct pmd_internals *internals;
59b3b413f7SBruce Richardson 
60b3b413f7SBruce Richardson 	struct rte_mempool *mb_pool;
61b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
62b3b413f7SBruce Richardson 
63b3b413f7SBruce Richardson 	rte_atomic64_t rx_pkts;
64b3b413f7SBruce Richardson 	rte_atomic64_t tx_pkts;
65b3b413f7SBruce Richardson 	rte_atomic64_t err_pkts;
66b3b413f7SBruce Richardson };
67b3b413f7SBruce Richardson 
68b3b413f7SBruce Richardson struct pmd_internals {
69b3b413f7SBruce Richardson 	unsigned packet_size;
70b3b413f7SBruce Richardson 	unsigned packet_copy;
71f8244c63SZhiyong Yang 	uint16_t port_id;
72b3b413f7SBruce Richardson 
73dd7c54a6STomasz Kulasek 	struct null_queue rx_null_queues[RTE_MAX_QUEUES_PER_PORT];
74dd7c54a6STomasz Kulasek 	struct null_queue tx_null_queues[RTE_MAX_QUEUES_PER_PORT];
751ccec0a8STomasz Kulasek 
761ccec0a8STomasz Kulasek 	/** Bit mask of RSS offloads, the bit offset also means flow type */
771ccec0a8STomasz Kulasek 	uint64_t flow_type_rss_offloads;
781ccec0a8STomasz Kulasek 
791ccec0a8STomasz Kulasek 	rte_spinlock_t rss_lock;
801ccec0a8STomasz Kulasek 
811ccec0a8STomasz Kulasek 	uint16_t reta_size;
821ccec0a8STomasz Kulasek 	struct rte_eth_rss_reta_entry64 reta_conf[ETH_RSS_RETA_SIZE_128 /
831ccec0a8STomasz Kulasek 			RTE_RETA_GROUP_SIZE];
841ccec0a8STomasz Kulasek 
851ccec0a8STomasz Kulasek 	uint8_t rss_key[40];                /**< 40-byte hash key. */
86b3b413f7SBruce Richardson };
87b3b413f7SBruce Richardson 
88b3b413f7SBruce Richardson 
89b3b413f7SBruce Richardson static struct ether_addr eth_addr = { .addr_bytes = {0} };
90b3b413f7SBruce Richardson static struct rte_eth_link pmd_link = {
9139fd068aSMarc Sune 	.link_speed = ETH_SPEED_NUM_10G,
92b3b413f7SBruce Richardson 	.link_duplex = ETH_LINK_FULL_DUPLEX,
9309419f23SThomas Monjalon 	.link_status = ETH_LINK_DOWN,
9482113036SMarc Sune 	.link_autoneg = ETH_LINK_SPEED_AUTONEG,
95b3b413f7SBruce Richardson };
96b3b413f7SBruce Richardson 
97b3b413f7SBruce Richardson static uint16_t
98b3b413f7SBruce Richardson eth_null_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
99b3b413f7SBruce Richardson {
100b3b413f7SBruce Richardson 	int i;
101b3b413f7SBruce Richardson 	struct null_queue *h = q;
102b3b413f7SBruce Richardson 	unsigned packet_size;
103b3b413f7SBruce Richardson 
104b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
105b3b413f7SBruce Richardson 		return 0;
106b3b413f7SBruce Richardson 
107b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
108b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
109b3b413f7SBruce Richardson 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
110b3b413f7SBruce Richardson 		if (!bufs[i])
111b3b413f7SBruce Richardson 			break;
112b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
113b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
1145cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
115b3b413f7SBruce Richardson 	}
116b3b413f7SBruce Richardson 
117b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
118b3b413f7SBruce Richardson 
119b3b413f7SBruce Richardson 	return i;
120b3b413f7SBruce Richardson }
121b3b413f7SBruce Richardson 
122b3b413f7SBruce Richardson static uint16_t
123b3b413f7SBruce Richardson eth_null_copy_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
124b3b413f7SBruce Richardson {
125b3b413f7SBruce Richardson 	int i;
126b3b413f7SBruce Richardson 	struct null_queue *h = q;
127b3b413f7SBruce Richardson 	unsigned packet_size;
128b3b413f7SBruce Richardson 
129b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
130b3b413f7SBruce Richardson 		return 0;
131b3b413f7SBruce Richardson 
132b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
133b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
134b3b413f7SBruce Richardson 		bufs[i] = rte_pktmbuf_alloc(h->mb_pool);
135b3b413f7SBruce Richardson 		if (!bufs[i])
136b3b413f7SBruce Richardson 			break;
137b3b413f7SBruce Richardson 		rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *), h->dummy_packet,
138b3b413f7SBruce Richardson 					packet_size);
139b3b413f7SBruce Richardson 		bufs[i]->data_len = (uint16_t)packet_size;
140b3b413f7SBruce Richardson 		bufs[i]->pkt_len = packet_size;
1415cf86418SSean Harte 		bufs[i]->port = h->internals->port_id;
142b3b413f7SBruce Richardson 	}
143b3b413f7SBruce Richardson 
144b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->rx_pkts), i);
145b3b413f7SBruce Richardson 
146b3b413f7SBruce Richardson 	return i;
147b3b413f7SBruce Richardson }
148b3b413f7SBruce Richardson 
149b3b413f7SBruce Richardson static uint16_t
150b3b413f7SBruce Richardson eth_null_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
151b3b413f7SBruce Richardson {
152b3b413f7SBruce Richardson 	int i;
153b3b413f7SBruce Richardson 	struct null_queue *h = q;
154b3b413f7SBruce Richardson 
155b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
156b3b413f7SBruce Richardson 		return 0;
157b3b413f7SBruce Richardson 
158b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++)
159b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
160b3b413f7SBruce Richardson 
161b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
162b3b413f7SBruce Richardson 
163b3b413f7SBruce Richardson 	return i;
164b3b413f7SBruce Richardson }
165b3b413f7SBruce Richardson 
166b3b413f7SBruce Richardson static uint16_t
167b3b413f7SBruce Richardson eth_null_copy_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
168b3b413f7SBruce Richardson {
169b3b413f7SBruce Richardson 	int i;
170b3b413f7SBruce Richardson 	struct null_queue *h = q;
171b3b413f7SBruce Richardson 	unsigned packet_size;
172b3b413f7SBruce Richardson 
173b3b413f7SBruce Richardson 	if ((q == NULL) || (bufs == NULL))
174b3b413f7SBruce Richardson 		return 0;
175b3b413f7SBruce Richardson 
176b3b413f7SBruce Richardson 	packet_size = h->internals->packet_size;
177b3b413f7SBruce Richardson 	for (i = 0; i < nb_bufs; i++) {
178b3b413f7SBruce Richardson 		rte_memcpy(h->dummy_packet, rte_pktmbuf_mtod(bufs[i], void *),
179b3b413f7SBruce Richardson 					packet_size);
180b3b413f7SBruce Richardson 		rte_pktmbuf_free(bufs[i]);
181b3b413f7SBruce Richardson 	}
182b3b413f7SBruce Richardson 
183b3b413f7SBruce Richardson 	rte_atomic64_add(&(h->tx_pkts), i);
184b3b413f7SBruce Richardson 
185b3b413f7SBruce Richardson 	return i;
186b3b413f7SBruce Richardson }
187b3b413f7SBruce Richardson 
188b3b413f7SBruce Richardson static int
189c9634e44SFerruh Yigit eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
190c9634e44SFerruh Yigit {
191dd7c54a6STomasz Kulasek 	return 0;
192dd7c54a6STomasz Kulasek }
193b3b413f7SBruce Richardson 
194b3b413f7SBruce Richardson static int
195b3b413f7SBruce Richardson eth_dev_start(struct rte_eth_dev *dev)
196b3b413f7SBruce Richardson {
197b3b413f7SBruce Richardson 	if (dev == NULL)
198b3b413f7SBruce Richardson 		return -EINVAL;
199b3b413f7SBruce Richardson 
20009419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_UP;
201b3b413f7SBruce Richardson 	return 0;
202b3b413f7SBruce Richardson }
203b3b413f7SBruce Richardson 
204b3b413f7SBruce Richardson static void
205b3b413f7SBruce Richardson eth_dev_stop(struct rte_eth_dev *dev)
206b3b413f7SBruce Richardson {
207b3b413f7SBruce Richardson 	if (dev == NULL)
208b3b413f7SBruce Richardson 		return;
209b3b413f7SBruce Richardson 
21009419f23SThomas Monjalon 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
211b3b413f7SBruce Richardson }
212b3b413f7SBruce Richardson 
213b3b413f7SBruce Richardson static int
214b3b413f7SBruce Richardson eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
215b3b413f7SBruce Richardson 		uint16_t nb_rx_desc __rte_unused,
216b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
217b3b413f7SBruce Richardson 		const struct rte_eth_rxconf *rx_conf __rte_unused,
218b3b413f7SBruce Richardson 		struct rte_mempool *mb_pool)
219b3b413f7SBruce Richardson {
220b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
221b3b413f7SBruce Richardson 	struct pmd_internals *internals;
222b3b413f7SBruce Richardson 	unsigned packet_size;
223b3b413f7SBruce Richardson 
224b3b413f7SBruce Richardson 	if ((dev == NULL) || (mb_pool == NULL))
225b3b413f7SBruce Richardson 		return -EINVAL;
226b3b413f7SBruce Richardson 
227dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
228dd7c54a6STomasz Kulasek 
229c9634e44SFerruh Yigit 	if (rx_queue_id >= dev->data->nb_rx_queues)
230b3b413f7SBruce Richardson 		return -ENODEV;
231b3b413f7SBruce Richardson 
232b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
233b3b413f7SBruce Richardson 
234b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].mb_pool = mb_pool;
235b3b413f7SBruce Richardson 	dev->data->rx_queues[rx_queue_id] =
236b3b413f7SBruce Richardson 		&internals->rx_null_queues[rx_queue_id];
237b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
238c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
239b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
240b3b413f7SBruce Richardson 		return -ENOMEM;
241b3b413f7SBruce Richardson 
242b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].internals = internals;
243b3b413f7SBruce Richardson 	internals->rx_null_queues[rx_queue_id].dummy_packet = dummy_packet;
244b3b413f7SBruce Richardson 
245b3b413f7SBruce Richardson 	return 0;
246b3b413f7SBruce Richardson }
247b3b413f7SBruce Richardson 
248b3b413f7SBruce Richardson static int
249b3b413f7SBruce Richardson eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
250b3b413f7SBruce Richardson 		uint16_t nb_tx_desc __rte_unused,
251b3b413f7SBruce Richardson 		unsigned int socket_id __rte_unused,
252b3b413f7SBruce Richardson 		const struct rte_eth_txconf *tx_conf __rte_unused)
253b3b413f7SBruce Richardson {
254b3b413f7SBruce Richardson 	struct rte_mbuf *dummy_packet;
255b3b413f7SBruce Richardson 	struct pmd_internals *internals;
256b3b413f7SBruce Richardson 	unsigned packet_size;
257b3b413f7SBruce Richardson 
258b3b413f7SBruce Richardson 	if (dev == NULL)
259b3b413f7SBruce Richardson 		return -EINVAL;
260b3b413f7SBruce Richardson 
261dd7c54a6STomasz Kulasek 	internals = dev->data->dev_private;
262dd7c54a6STomasz Kulasek 
263c9634e44SFerruh Yigit 	if (tx_queue_id >= dev->data->nb_tx_queues)
264b3b413f7SBruce Richardson 		return -ENODEV;
265b3b413f7SBruce Richardson 
266b3b413f7SBruce Richardson 	packet_size = internals->packet_size;
267b3b413f7SBruce Richardson 
268b3b413f7SBruce Richardson 	dev->data->tx_queues[tx_queue_id] =
269b3b413f7SBruce Richardson 		&internals->tx_null_queues[tx_queue_id];
270b3b413f7SBruce Richardson 	dummy_packet = rte_zmalloc_socket(NULL,
271c9634e44SFerruh Yigit 			packet_size, 0, dev->data->numa_node);
272b3b413f7SBruce Richardson 	if (dummy_packet == NULL)
273b3b413f7SBruce Richardson 		return -ENOMEM;
274b3b413f7SBruce Richardson 
275b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].internals = internals;
276b3b413f7SBruce Richardson 	internals->tx_null_queues[tx_queue_id].dummy_packet = dummy_packet;
277b3b413f7SBruce Richardson 
278b3b413f7SBruce Richardson 	return 0;
279b3b413f7SBruce Richardson }
280b3b413f7SBruce Richardson 
281b3b413f7SBruce Richardson 
282b3b413f7SBruce Richardson static void
283b3b413f7SBruce Richardson eth_dev_info(struct rte_eth_dev *dev,
284b3b413f7SBruce Richardson 		struct rte_eth_dev_info *dev_info)
285b3b413f7SBruce Richardson {
286b3b413f7SBruce Richardson 	struct pmd_internals *internals;
287b3b413f7SBruce Richardson 
288b3b413f7SBruce Richardson 	if ((dev == NULL) || (dev_info == NULL))
289b3b413f7SBruce Richardson 		return;
290b3b413f7SBruce Richardson 
291b3b413f7SBruce Richardson 	internals = dev->data->dev_private;
292b3b413f7SBruce Richardson 	dev_info->max_mac_addrs = 1;
293b3b413f7SBruce Richardson 	dev_info->max_rx_pktlen = (uint32_t)-1;
294dd7c54a6STomasz Kulasek 	dev_info->max_rx_queues = RTE_DIM(internals->rx_null_queues);
295dd7c54a6STomasz Kulasek 	dev_info->max_tx_queues = RTE_DIM(internals->tx_null_queues);
296b3b413f7SBruce Richardson 	dev_info->min_rx_bufsize = 0;
2971ccec0a8STomasz Kulasek 	dev_info->reta_size = internals->reta_size;
2981ccec0a8STomasz Kulasek 	dev_info->flow_type_rss_offloads = internals->flow_type_rss_offloads;
299b3b413f7SBruce Richardson }
300b3b413f7SBruce Richardson 
301*d5b0924bSMatan Azrad static int
302b3b413f7SBruce Richardson eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *igb_stats)
303b3b413f7SBruce Richardson {
304b3b413f7SBruce Richardson 	unsigned i, num_stats;
305b3b413f7SBruce Richardson 	unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
306b3b413f7SBruce Richardson 	const struct pmd_internals *internal;
307b3b413f7SBruce Richardson 
308b3b413f7SBruce Richardson 	if ((dev == NULL) || (igb_stats == NULL))
309*d5b0924bSMatan Azrad 		return -EINVAL;
310b3b413f7SBruce Richardson 
311b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
312b3b413f7SBruce Richardson 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
313c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_rx_queues,
314b34141b2SBruce Richardson 				RTE_DIM(internal->rx_null_queues)));
315b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
316b3b413f7SBruce Richardson 		igb_stats->q_ipackets[i] =
317b3b413f7SBruce Richardson 			internal->rx_null_queues[i].rx_pkts.cnt;
318b3b413f7SBruce Richardson 		rx_total += igb_stats->q_ipackets[i];
319b3b413f7SBruce Richardson 	}
320b3b413f7SBruce Richardson 
321b3b413f7SBruce Richardson 	num_stats = RTE_MIN((unsigned)RTE_ETHDEV_QUEUE_STAT_CNTRS,
322c9634e44SFerruh Yigit 			RTE_MIN(dev->data->nb_tx_queues,
323b34141b2SBruce Richardson 				RTE_DIM(internal->tx_null_queues)));
324b3b413f7SBruce Richardson 	for (i = 0; i < num_stats; i++) {
325b3b413f7SBruce Richardson 		igb_stats->q_opackets[i] =
326b3b413f7SBruce Richardson 			internal->tx_null_queues[i].tx_pkts.cnt;
327b3b413f7SBruce Richardson 		igb_stats->q_errors[i] =
328b3b413f7SBruce Richardson 			internal->tx_null_queues[i].err_pkts.cnt;
329b3b413f7SBruce Richardson 		tx_total += igb_stats->q_opackets[i];
330b3b413f7SBruce Richardson 		tx_err_total += igb_stats->q_errors[i];
331b3b413f7SBruce Richardson 	}
332b3b413f7SBruce Richardson 
333b3b413f7SBruce Richardson 	igb_stats->ipackets = rx_total;
334b3b413f7SBruce Richardson 	igb_stats->opackets = tx_total;
335b3b413f7SBruce Richardson 	igb_stats->oerrors = tx_err_total;
336*d5b0924bSMatan Azrad 
337*d5b0924bSMatan Azrad 	return 0;
338b3b413f7SBruce Richardson }
339b3b413f7SBruce Richardson 
340b3b413f7SBruce Richardson static void
341b3b413f7SBruce Richardson eth_stats_reset(struct rte_eth_dev *dev)
342b3b413f7SBruce Richardson {
343b3b413f7SBruce Richardson 	unsigned i;
344b3b413f7SBruce Richardson 	struct pmd_internals *internal;
345b3b413f7SBruce Richardson 
346b3b413f7SBruce Richardson 	if (dev == NULL)
347b3b413f7SBruce Richardson 		return;
348b3b413f7SBruce Richardson 
349b3b413f7SBruce Richardson 	internal = dev->data->dev_private;
350b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->rx_null_queues); i++)
351b3b413f7SBruce Richardson 		internal->rx_null_queues[i].rx_pkts.cnt = 0;
352b34141b2SBruce Richardson 	for (i = 0; i < RTE_DIM(internal->tx_null_queues); i++) {
353b3b413f7SBruce Richardson 		internal->tx_null_queues[i].tx_pkts.cnt = 0;
354b3b413f7SBruce Richardson 		internal->tx_null_queues[i].err_pkts.cnt = 0;
355b3b413f7SBruce Richardson 	}
356b3b413f7SBruce Richardson }
357b3b413f7SBruce Richardson 
358b3b413f7SBruce Richardson static void
359b3b413f7SBruce Richardson eth_queue_release(void *q)
360b3b413f7SBruce Richardson {
361b3b413f7SBruce Richardson 	struct null_queue *nq;
362b3b413f7SBruce Richardson 
363b3b413f7SBruce Richardson 	if (q == NULL)
364b3b413f7SBruce Richardson 		return;
365b3b413f7SBruce Richardson 
366b3b413f7SBruce Richardson 	nq = q;
367b3b413f7SBruce Richardson 	rte_free(nq->dummy_packet);
368b3b413f7SBruce Richardson }
369b3b413f7SBruce Richardson 
370b3b413f7SBruce Richardson static int
371b3b413f7SBruce Richardson eth_link_update(struct rte_eth_dev *dev __rte_unused,
372b3b413f7SBruce Richardson 		int wait_to_complete __rte_unused) { return 0; }
373b3b413f7SBruce Richardson 
3741ccec0a8STomasz Kulasek static int
3751ccec0a8STomasz Kulasek eth_rss_reta_update(struct rte_eth_dev *dev,
3761ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
3771ccec0a8STomasz Kulasek {
3781ccec0a8STomasz Kulasek 	int i, j;
3791ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
3801ccec0a8STomasz Kulasek 
3811ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
3821ccec0a8STomasz Kulasek 		return -EINVAL;
3831ccec0a8STomasz Kulasek 
3841ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
3851ccec0a8STomasz Kulasek 
3861ccec0a8STomasz Kulasek 	/* Copy RETA table */
3871ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
3881ccec0a8STomasz Kulasek 		internal->reta_conf[i].mask = reta_conf[i].mask;
3891ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
3901ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
3911ccec0a8STomasz Kulasek 				internal->reta_conf[i].reta[j] = reta_conf[i].reta[j];
3921ccec0a8STomasz Kulasek 	}
3931ccec0a8STomasz Kulasek 
3941ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
3951ccec0a8STomasz Kulasek 
3961ccec0a8STomasz Kulasek 	return 0;
3971ccec0a8STomasz Kulasek }
3981ccec0a8STomasz Kulasek 
3991ccec0a8STomasz Kulasek static int
4001ccec0a8STomasz Kulasek eth_rss_reta_query(struct rte_eth_dev *dev,
4011ccec0a8STomasz Kulasek 		struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size)
4021ccec0a8STomasz Kulasek {
4031ccec0a8STomasz Kulasek 	int i, j;
4041ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4051ccec0a8STomasz Kulasek 
4061ccec0a8STomasz Kulasek 	if (reta_size != internal->reta_size)
4071ccec0a8STomasz Kulasek 		return -EINVAL;
4081ccec0a8STomasz Kulasek 
4091ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4101ccec0a8STomasz Kulasek 
4111ccec0a8STomasz Kulasek 	/* Copy RETA table */
4121ccec0a8STomasz Kulasek 	for (i = 0; i < (internal->reta_size / RTE_RETA_GROUP_SIZE); i++) {
4131ccec0a8STomasz Kulasek 		for (j = 0; j < RTE_RETA_GROUP_SIZE; j++)
4141ccec0a8STomasz Kulasek 			if ((reta_conf[i].mask >> j) & 0x01)
4151ccec0a8STomasz Kulasek 				reta_conf[i].reta[j] = internal->reta_conf[i].reta[j];
4161ccec0a8STomasz Kulasek 	}
4171ccec0a8STomasz Kulasek 
4181ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4191ccec0a8STomasz Kulasek 
4201ccec0a8STomasz Kulasek 	return 0;
4211ccec0a8STomasz Kulasek }
4221ccec0a8STomasz Kulasek 
4231ccec0a8STomasz Kulasek static int
4241ccec0a8STomasz Kulasek eth_rss_hash_update(struct rte_eth_dev *dev, struct rte_eth_rss_conf *rss_conf)
4251ccec0a8STomasz Kulasek {
4261ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4271ccec0a8STomasz Kulasek 
4281ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4291ccec0a8STomasz Kulasek 
4301ccec0a8STomasz Kulasek 	if ((rss_conf->rss_hf & internal->flow_type_rss_offloads) != 0)
4311ccec0a8STomasz Kulasek 		dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf =
4321ccec0a8STomasz Kulasek 				rss_conf->rss_hf & internal->flow_type_rss_offloads;
4331ccec0a8STomasz Kulasek 
4341ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4351ccec0a8STomasz Kulasek 		rte_memcpy(internal->rss_key, rss_conf->rss_key, 40);
4361ccec0a8STomasz Kulasek 
4371ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4381ccec0a8STomasz Kulasek 
4391ccec0a8STomasz Kulasek 	return 0;
4401ccec0a8STomasz Kulasek }
4411ccec0a8STomasz Kulasek 
4421ccec0a8STomasz Kulasek static int
4431ccec0a8STomasz Kulasek eth_rss_hash_conf_get(struct rte_eth_dev *dev,
4441ccec0a8STomasz Kulasek 		struct rte_eth_rss_conf *rss_conf)
4451ccec0a8STomasz Kulasek {
4461ccec0a8STomasz Kulasek 	struct pmd_internals *internal = dev->data->dev_private;
4471ccec0a8STomasz Kulasek 
4481ccec0a8STomasz Kulasek 	rte_spinlock_lock(&internal->rss_lock);
4491ccec0a8STomasz Kulasek 
4501ccec0a8STomasz Kulasek 	rss_conf->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
4511ccec0a8STomasz Kulasek 	if (rss_conf->rss_key)
4521ccec0a8STomasz Kulasek 		rte_memcpy(rss_conf->rss_key, internal->rss_key, 40);
4531ccec0a8STomasz Kulasek 
4541ccec0a8STomasz Kulasek 	rte_spinlock_unlock(&internal->rss_lock);
4551ccec0a8STomasz Kulasek 
4561ccec0a8STomasz Kulasek 	return 0;
4571ccec0a8STomasz Kulasek }
4581ccec0a8STomasz Kulasek 
459b3b413f7SBruce Richardson static const struct eth_dev_ops ops = {
460b3b413f7SBruce Richardson 	.dev_start = eth_dev_start,
461b3b413f7SBruce Richardson 	.dev_stop = eth_dev_stop,
462b3b413f7SBruce Richardson 	.dev_configure = eth_dev_configure,
463b3b413f7SBruce Richardson 	.dev_infos_get = eth_dev_info,
464b3b413f7SBruce Richardson 	.rx_queue_setup = eth_rx_queue_setup,
465b3b413f7SBruce Richardson 	.tx_queue_setup = eth_tx_queue_setup,
466b3b413f7SBruce Richardson 	.rx_queue_release = eth_queue_release,
467b3b413f7SBruce Richardson 	.tx_queue_release = eth_queue_release,
468b3b413f7SBruce Richardson 	.link_update = eth_link_update,
469b3b413f7SBruce Richardson 	.stats_get = eth_stats_get,
470b3b413f7SBruce Richardson 	.stats_reset = eth_stats_reset,
4711ccec0a8STomasz Kulasek 	.reta_update = eth_rss_reta_update,
4721ccec0a8STomasz Kulasek 	.reta_query = eth_rss_reta_query,
4731ccec0a8STomasz Kulasek 	.rss_hash_update = eth_rss_hash_update,
4741ccec0a8STomasz Kulasek 	.rss_hash_conf_get = eth_rss_hash_conf_get
475b3b413f7SBruce Richardson };
476b3b413f7SBruce Richardson 
47773db5badSDavid Marchand static struct rte_vdev_driver pmd_null_drv;
47873db5badSDavid Marchand 
479c3b047beSJan Blunck static int
480050fe6e9SJan Blunck eth_dev_null_create(struct rte_vdev_device *dev,
481b3b413f7SBruce Richardson 		unsigned packet_size,
482b3b413f7SBruce Richardson 		unsigned packet_copy)
483b3b413f7SBruce Richardson {
484b3b413f7SBruce Richardson 	const unsigned nb_rx_queues = 1;
485b3b413f7SBruce Richardson 	const unsigned nb_tx_queues = 1;
486b3b413f7SBruce Richardson 	struct rte_eth_dev_data *data = NULL;
487b3b413f7SBruce Richardson 	struct pmd_internals *internals = NULL;
488b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
489b3b413f7SBruce Richardson 
4901ccec0a8STomasz Kulasek 	static const uint8_t default_rss_key[40] = {
4911ccec0a8STomasz Kulasek 		0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2, 0x41, 0x67, 0x25, 0x3D,
4921ccec0a8STomasz Kulasek 		0x43, 0xA3, 0x8F, 0xB0, 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
4931ccec0a8STomasz Kulasek 		0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C, 0x6A, 0x42, 0xB7, 0x3B,
4941ccec0a8STomasz Kulasek 		0xBE, 0xAC, 0x01, 0xFA
4951ccec0a8STomasz Kulasek 	};
4961ccec0a8STomasz Kulasek 
497050fe6e9SJan Blunck 	if (dev->device.numa_node == SOCKET_ID_ANY)
498050fe6e9SJan Blunck 		dev->device.numa_node = rte_socket_id();
499b3b413f7SBruce Richardson 
500b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Creating null ethdev on numa socket %u\n",
501050fe6e9SJan Blunck 		dev->device.numa_node);
502b3b413f7SBruce Richardson 
503b3b413f7SBruce Richardson 	/* now do all data allocation - for eth_dev structure, dummy pci driver
504b3b413f7SBruce Richardson 	 * and internal (private) data
505b3b413f7SBruce Richardson 	 */
506050fe6e9SJan Blunck 	data = rte_zmalloc_socket(rte_vdev_device_name(dev), sizeof(*data), 0,
507050fe6e9SJan Blunck 		dev->device.numa_node);
508050fe6e9SJan Blunck 	if (!data)
509050fe6e9SJan Blunck 		return -ENOMEM;
510b3b413f7SBruce Richardson 
511050fe6e9SJan Blunck 	eth_dev = rte_eth_vdev_allocate(dev, sizeof(*internals));
512050fe6e9SJan Blunck 	if (!eth_dev) {
513050fe6e9SJan Blunck 		rte_free(data);
514050fe6e9SJan Blunck 		return -ENOMEM;
515050fe6e9SJan Blunck 	}
516b3b413f7SBruce Richardson 
517b3b413f7SBruce Richardson 	/* now put it all together
518b3b413f7SBruce Richardson 	 * - store queue data in internals,
5198fb9e2bbSBernard Iremonger 	 * - store numa_node info in ethdev data
5208fb9e2bbSBernard Iremonger 	 * - point eth_dev_data to internals
521b3b413f7SBruce Richardson 	 * - and point eth_dev structure to new eth_dev_data structure
522b3b413f7SBruce Richardson 	 */
523b3b413f7SBruce Richardson 	/* NOTE: we'll replace the data element, of originally allocated eth_dev
524b3b413f7SBruce Richardson 	 * so the nulls are local per-process */
525b3b413f7SBruce Richardson 
526050fe6e9SJan Blunck 	internals = eth_dev->data->dev_private;
527b3b413f7SBruce Richardson 	internals->packet_size = packet_size;
528b3b413f7SBruce Richardson 	internals->packet_copy = packet_copy;
5295cf86418SSean Harte 	internals->port_id = eth_dev->data->port_id;
530b3b413f7SBruce Richardson 
5311ccec0a8STomasz Kulasek 	internals->flow_type_rss_offloads =  ETH_RSS_PROTO_MASK;
5321ccec0a8STomasz Kulasek 	internals->reta_size = RTE_DIM(internals->reta_conf) * RTE_RETA_GROUP_SIZE;
5331ccec0a8STomasz Kulasek 
5341ccec0a8STomasz Kulasek 	rte_memcpy(internals->rss_key, default_rss_key, 40);
5351ccec0a8STomasz Kulasek 
536050fe6e9SJan Blunck 	rte_memcpy(data, eth_dev->data, sizeof(*data));
537b3b413f7SBruce Richardson 	data->nb_rx_queues = (uint16_t)nb_rx_queues;
538b3b413f7SBruce Richardson 	data->nb_tx_queues = (uint16_t)nb_tx_queues;
539b3b413f7SBruce Richardson 	data->dev_link = pmd_link;
540b3b413f7SBruce Richardson 	data->mac_addrs = &eth_addr;
541b3b413f7SBruce Richardson 
542b3b413f7SBruce Richardson 	eth_dev->data = data;
543b3b413f7SBruce Richardson 	eth_dev->dev_ops = &ops;
5446799cfe4SBernard Iremonger 
545c9634e44SFerruh Yigit 	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
5468fb9e2bbSBernard Iremonger 
547b3b413f7SBruce Richardson 	/* finally assign rx and tx ops */
548b3b413f7SBruce Richardson 	if (packet_copy) {
549b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_copy_rx;
550b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_copy_tx;
551b3b413f7SBruce Richardson 	} else {
552b3b413f7SBruce Richardson 		eth_dev->rx_pkt_burst = eth_null_rx;
553b3b413f7SBruce Richardson 		eth_dev->tx_pkt_burst = eth_null_tx;
554b3b413f7SBruce Richardson 	}
555b3b413f7SBruce Richardson 
556b3b413f7SBruce Richardson 	return 0;
557b3b413f7SBruce Richardson }
558b3b413f7SBruce Richardson 
559b3b413f7SBruce Richardson static inline int
560b3b413f7SBruce Richardson get_packet_size_arg(const char *key __rte_unused,
561b3b413f7SBruce Richardson 		const char *value, void *extra_args)
562b3b413f7SBruce Richardson {
563b3b413f7SBruce Richardson 	const char *a = value;
564b3b413f7SBruce Richardson 	unsigned *packet_size = extra_args;
565b3b413f7SBruce Richardson 
566b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
567b3b413f7SBruce Richardson 		return -EINVAL;
568b3b413f7SBruce Richardson 
569b3b413f7SBruce Richardson 	*packet_size = (unsigned)strtoul(a, NULL, 0);
570b3b413f7SBruce Richardson 	if (*packet_size == UINT_MAX)
571b3b413f7SBruce Richardson 		return -1;
572b3b413f7SBruce Richardson 
573b3b413f7SBruce Richardson 	return 0;
574b3b413f7SBruce Richardson }
575b3b413f7SBruce Richardson 
576b3b413f7SBruce Richardson static inline int
577b3b413f7SBruce Richardson get_packet_copy_arg(const char *key __rte_unused,
578b3b413f7SBruce Richardson 		const char *value, void *extra_args)
579b3b413f7SBruce Richardson {
580b3b413f7SBruce Richardson 	const char *a = value;
581b3b413f7SBruce Richardson 	unsigned *packet_copy = extra_args;
582b3b413f7SBruce Richardson 
583b3b413f7SBruce Richardson 	if ((value == NULL) || (extra_args == NULL))
584b3b413f7SBruce Richardson 		return -EINVAL;
585b3b413f7SBruce Richardson 
586b3b413f7SBruce Richardson 	*packet_copy = (unsigned)strtoul(a, NULL, 0);
587b3b413f7SBruce Richardson 	if (*packet_copy == UINT_MAX)
588b3b413f7SBruce Richardson 		return -1;
589b3b413f7SBruce Richardson 
590b3b413f7SBruce Richardson 	return 0;
591b3b413f7SBruce Richardson }
592b3b413f7SBruce Richardson 
593b3b413f7SBruce Richardson static int
5945d2aa461SJan Blunck rte_pmd_null_probe(struct rte_vdev_device *dev)
595b3b413f7SBruce Richardson {
5965d2aa461SJan Blunck 	const char *name, *params;
597b3b413f7SBruce Richardson 	unsigned packet_size = default_packet_size;
598b3b413f7SBruce Richardson 	unsigned packet_copy = default_packet_copy;
599b3b413f7SBruce Richardson 	struct rte_kvargs *kvlist = NULL;
600b3b413f7SBruce Richardson 	int ret;
601b3b413f7SBruce Richardson 
6025d2aa461SJan Blunck 	if (!dev)
603b3b413f7SBruce Richardson 		return -EINVAL;
604b3b413f7SBruce Richardson 
6055d2aa461SJan Blunck 	name = rte_vdev_device_name(dev);
6065d2aa461SJan Blunck 	params = rte_vdev_device_args(dev);
607b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Initializing pmd_null for %s\n", name);
608b3b413f7SBruce Richardson 
609b3b413f7SBruce Richardson 	if (params != NULL) {
610b3b413f7SBruce Richardson 		kvlist = rte_kvargs_parse(params, valid_arguments);
611b3b413f7SBruce Richardson 		if (kvlist == NULL)
612b3b413f7SBruce Richardson 			return -1;
613b3b413f7SBruce Richardson 
614b3b413f7SBruce Richardson 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_SIZE_ARG) == 1) {
615b3b413f7SBruce Richardson 
616b3b413f7SBruce Richardson 			ret = rte_kvargs_process(kvlist,
617b3b413f7SBruce Richardson 					ETH_NULL_PACKET_SIZE_ARG,
618b3b413f7SBruce Richardson 					&get_packet_size_arg, &packet_size);
619b3b413f7SBruce Richardson 			if (ret < 0)
620b3b413f7SBruce Richardson 				goto free_kvlist;
621b3b413f7SBruce Richardson 		}
622b3b413f7SBruce Richardson 
623b3b413f7SBruce Richardson 		if (rte_kvargs_count(kvlist, ETH_NULL_PACKET_COPY_ARG) == 1) {
624b3b413f7SBruce Richardson 
625b3b413f7SBruce Richardson 			ret = rte_kvargs_process(kvlist,
626b3b413f7SBruce Richardson 					ETH_NULL_PACKET_COPY_ARG,
627b3b413f7SBruce Richardson 					&get_packet_copy_arg, &packet_copy);
628b3b413f7SBruce Richardson 			if (ret < 0)
629b3b413f7SBruce Richardson 				goto free_kvlist;
630b3b413f7SBruce Richardson 		}
631b3b413f7SBruce Richardson 	}
632b3b413f7SBruce Richardson 
633b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Configure pmd_null: packet size is %d, "
634b3b413f7SBruce Richardson 			"packet copy is %s\n", packet_size,
635b3b413f7SBruce Richardson 			packet_copy ? "enabled" : "disabled");
636b3b413f7SBruce Richardson 
637050fe6e9SJan Blunck 	ret = eth_dev_null_create(dev, packet_size, packet_copy);
638b3b413f7SBruce Richardson 
639b3b413f7SBruce Richardson free_kvlist:
640b3b413f7SBruce Richardson 	if (kvlist)
641b3b413f7SBruce Richardson 		rte_kvargs_free(kvlist);
642b3b413f7SBruce Richardson 	return ret;
643b3b413f7SBruce Richardson }
644b3b413f7SBruce Richardson 
645b3b413f7SBruce Richardson static int
6465d2aa461SJan Blunck rte_pmd_null_remove(struct rte_vdev_device *dev)
647b3b413f7SBruce Richardson {
648b3b413f7SBruce Richardson 	struct rte_eth_dev *eth_dev = NULL;
649b3b413f7SBruce Richardson 
6505d2aa461SJan Blunck 	if (!dev)
651b3b413f7SBruce Richardson 		return -EINVAL;
652b3b413f7SBruce Richardson 
653b3b413f7SBruce Richardson 	RTE_LOG(INFO, PMD, "Closing null ethdev on numa socket %u\n",
654b3b413f7SBruce Richardson 			rte_socket_id());
655b3b413f7SBruce Richardson 
6566799cfe4SBernard Iremonger 	/* find the ethdev entry */
6575d2aa461SJan Blunck 	eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
658b3b413f7SBruce Richardson 	if (eth_dev == NULL)
659b3b413f7SBruce Richardson 		return -1;
660b3b413f7SBruce Richardson 
661b3b413f7SBruce Richardson 	rte_free(eth_dev->data->dev_private);
662b3b413f7SBruce Richardson 	rte_free(eth_dev->data);
663b3b413f7SBruce Richardson 
664b3b413f7SBruce Richardson 	rte_eth_dev_release_port(eth_dev);
665b3b413f7SBruce Richardson 
666b3b413f7SBruce Richardson 	return 0;
667b3b413f7SBruce Richardson }
668b3b413f7SBruce Richardson 
669fe363dd4SJan Viktorin static struct rte_vdev_driver pmd_null_drv = {
67050a3345fSShreyansh Jain 	.probe = rte_pmd_null_probe,
67150a3345fSShreyansh Jain 	.remove = rte_pmd_null_remove,
672b3b413f7SBruce Richardson };
673b3b413f7SBruce Richardson 
67401f19227SShreyansh Jain RTE_PMD_REGISTER_VDEV(net_null, pmd_null_drv);
6759fa80cb2SJan Blunck RTE_PMD_REGISTER_ALIAS(net_null, eth_null);
67601f19227SShreyansh Jain RTE_PMD_REGISTER_PARAM_STRING(net_null,
67765eca099SPablo de Lara 	"size=<int> "
67865eca099SPablo de Lara 	"copy=<int>");
679