]> git.proxmox.com Git - ceph.git/blob - ceph/src/dpdk/drivers/net/pcap/rte_eth_pcap.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / dpdk / drivers / net / pcap / rte_eth_pcap.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5 * Copyright(c) 2014 6WIND S.A.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <time.h>
36
37 #include <net/if.h>
38
39 #include <pcap.h>
40
41 #include <rte_cycles.h>
42 #include <rte_ethdev.h>
43 #include <rte_kvargs.h>
44 #include <rte_malloc.h>
45 #include <rte_mbuf.h>
46 #include <rte_vdev.h>
47
48 #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
49 #define RTE_ETH_PCAP_SNAPLEN ETHER_MAX_JUMBO_FRAME_LEN
50 #define RTE_ETH_PCAP_PROMISC 1
51 #define RTE_ETH_PCAP_TIMEOUT -1
52
53 #define ETH_PCAP_RX_PCAP_ARG "rx_pcap"
54 #define ETH_PCAP_TX_PCAP_ARG "tx_pcap"
55 #define ETH_PCAP_RX_IFACE_ARG "rx_iface"
56 #define ETH_PCAP_TX_IFACE_ARG "tx_iface"
57 #define ETH_PCAP_IFACE_ARG "iface"
58
59 #define ETH_PCAP_ARG_MAXLEN 64
60
61 #define RTE_PMD_PCAP_MAX_QUEUES 16
62
63 static char errbuf[PCAP_ERRBUF_SIZE];
64 static unsigned char tx_pcap_data[RTE_ETH_PCAP_SNAPLEN];
65 static struct timeval start_time;
66 static uint64_t start_cycles;
67 static uint64_t hz;
68
69 struct queue_stat {
70 volatile unsigned long pkts;
71 volatile unsigned long bytes;
72 volatile unsigned long err_pkts;
73 };
74
75 struct pcap_rx_queue {
76 pcap_t *pcap;
77 uint8_t in_port;
78 struct rte_mempool *mb_pool;
79 struct queue_stat rx_stat;
80 char name[PATH_MAX];
81 char type[ETH_PCAP_ARG_MAXLEN];
82 };
83
84 struct pcap_tx_queue {
85 pcap_dumper_t *dumper;
86 pcap_t *pcap;
87 struct queue_stat tx_stat;
88 char name[PATH_MAX];
89 char type[ETH_PCAP_ARG_MAXLEN];
90 };
91
92 struct pmd_internals {
93 struct pcap_rx_queue rx_queue[RTE_PMD_PCAP_MAX_QUEUES];
94 struct pcap_tx_queue tx_queue[RTE_PMD_PCAP_MAX_QUEUES];
95 int if_index;
96 int single_iface;
97 };
98
99 struct pmd_devargs {
100 unsigned int num_of_queue;
101 struct devargs_queue {
102 pcap_dumper_t *dumper;
103 pcap_t *pcap;
104 const char *name;
105 const char *type;
106 } queue[RTE_PMD_PCAP_MAX_QUEUES];
107 };
108
109 static const char *valid_arguments[] = {
110 ETH_PCAP_RX_PCAP_ARG,
111 ETH_PCAP_TX_PCAP_ARG,
112 ETH_PCAP_RX_IFACE_ARG,
113 ETH_PCAP_TX_IFACE_ARG,
114 ETH_PCAP_IFACE_ARG,
115 NULL
116 };
117
118 static struct ether_addr eth_addr = {
119 .addr_bytes = { 0, 0, 0, 0x1, 0x2, 0x3 }
120 };
121
122 static const char *drivername = "Pcap PMD";
123 static struct rte_eth_link pmd_link = {
124 .link_speed = ETH_SPEED_NUM_10G,
125 .link_duplex = ETH_LINK_FULL_DUPLEX,
126 .link_status = ETH_LINK_DOWN,
127 .link_autoneg = ETH_LINK_SPEED_FIXED,
128 };
129
130 static int
131 eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
132 const u_char *data, uint16_t data_len)
133 {
134 /* Copy the first segment. */
135 uint16_t len = rte_pktmbuf_tailroom(mbuf);
136 struct rte_mbuf *m = mbuf;
137
138 rte_memcpy(rte_pktmbuf_append(mbuf, len), data, len);
139 data_len -= len;
140 data += len;
141
142 while (data_len > 0) {
143 /* Allocate next mbuf and point to that. */
144 m->next = rte_pktmbuf_alloc(mb_pool);
145
146 if (unlikely(!m->next))
147 return -1;
148
149 m = m->next;
150
151 /* Headroom is not needed in chained mbufs. */
152 rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
153 m->pkt_len = 0;
154 m->data_len = 0;
155
156 /* Copy next segment. */
157 len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len);
158 rte_memcpy(rte_pktmbuf_append(m, len), data, len);
159
160 mbuf->nb_segs++;
161 data_len -= len;
162 data += len;
163 }
164
165 return mbuf->nb_segs;
166 }
167
168 /* Copy data from mbuf chain to a buffer suitable for writing to a PCAP file. */
169 static void
170 eth_pcap_gather_data(unsigned char *data, struct rte_mbuf *mbuf)
171 {
172 uint16_t data_len = 0;
173
174 while (mbuf) {
175 rte_memcpy(data + data_len, rte_pktmbuf_mtod(mbuf, void *),
176 mbuf->data_len);
177
178 data_len += mbuf->data_len;
179 mbuf = mbuf->next;
180 }
181 }
182
183 static uint16_t
184 eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
185 {
186 unsigned int i;
187 struct pcap_pkthdr header;
188 const u_char *packet;
189 struct rte_mbuf *mbuf;
190 struct pcap_rx_queue *pcap_q = queue;
191 uint16_t num_rx = 0;
192 uint16_t buf_size;
193 uint32_t rx_bytes = 0;
194
195 if (unlikely(pcap_q->pcap == NULL || nb_pkts == 0))
196 return 0;
197
198 /* Reads the given number of packets from the pcap file one by one
199 * and copies the packet data into a newly allocated mbuf to return.
200 */
201 for (i = 0; i < nb_pkts; i++) {
202 /* Get the next PCAP packet */
203 packet = pcap_next(pcap_q->pcap, &header);
204 if (unlikely(packet == NULL))
205 break;
206
207 mbuf = rte_pktmbuf_alloc(pcap_q->mb_pool);
208 if (unlikely(mbuf == NULL))
209 break;
210
211 /* Now get the space available for data in the mbuf */
212 buf_size = rte_pktmbuf_data_room_size(pcap_q->mb_pool) -
213 RTE_PKTMBUF_HEADROOM;
214
215 if (header.caplen <= buf_size) {
216 /* pcap packet will fit in the mbuf, can copy it */
217 rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packet,
218 header.caplen);
219 mbuf->data_len = (uint16_t)header.caplen;
220 } else {
221 /* Try read jumbo frame into multi mbufs. */
222 if (unlikely(eth_pcap_rx_jumbo(pcap_q->mb_pool,
223 mbuf,
224 packet,
225 header.caplen) == -1)) {
226 rte_pktmbuf_free(mbuf);
227 break;
228 }
229 }
230
231 mbuf->pkt_len = (uint16_t)header.caplen;
232 mbuf->port = pcap_q->in_port;
233 bufs[num_rx] = mbuf;
234 num_rx++;
235 rx_bytes += header.caplen;
236 }
237 pcap_q->rx_stat.pkts += num_rx;
238 pcap_q->rx_stat.bytes += rx_bytes;
239
240 return num_rx;
241 }
242
243 static inline void
244 calculate_timestamp(struct timeval *ts) {
245 uint64_t cycles;
246 struct timeval cur_time;
247
248 cycles = rte_get_timer_cycles() - start_cycles;
249 cur_time.tv_sec = cycles / hz;
250 cur_time.tv_usec = (cycles % hz) * 10e6 / hz;
251 timeradd(&start_time, &cur_time, ts);
252 }
253
254 /*
255 * Callback to handle writing packets to a pcap file.
256 */
257 static uint16_t
258 eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
259 {
260 unsigned int i;
261 struct rte_mbuf *mbuf;
262 struct pcap_tx_queue *dumper_q = queue;
263 uint16_t num_tx = 0;
264 uint32_t tx_bytes = 0;
265 struct pcap_pkthdr header;
266
267 if (dumper_q->dumper == NULL || nb_pkts == 0)
268 return 0;
269
270 /* writes the nb_pkts packets to the previously opened pcap file
271 * dumper */
272 for (i = 0; i < nb_pkts; i++) {
273 mbuf = bufs[i];
274 calculate_timestamp(&header.ts);
275 header.len = mbuf->pkt_len;
276 header.caplen = header.len;
277
278 if (likely(mbuf->nb_segs == 1)) {
279 pcap_dump((u_char *)dumper_q->dumper, &header,
280 rte_pktmbuf_mtod(mbuf, void*));
281 } else {
282 if (mbuf->pkt_len <= ETHER_MAX_JUMBO_FRAME_LEN) {
283 eth_pcap_gather_data(tx_pcap_data, mbuf);
284 pcap_dump((u_char *)dumper_q->dumper, &header,
285 tx_pcap_data);
286 } else {
287 RTE_LOG(ERR, PMD,
288 "Dropping PCAP packet. Size (%d) > max jumbo size (%d).\n",
289 mbuf->pkt_len,
290 ETHER_MAX_JUMBO_FRAME_LEN);
291
292 rte_pktmbuf_free(mbuf);
293 break;
294 }
295 }
296
297 rte_pktmbuf_free(mbuf);
298 num_tx++;
299 tx_bytes += mbuf->pkt_len;
300 }
301
302 /*
303 * Since there's no place to hook a callback when the forwarding
304 * process stops and to make sure the pcap file is actually written,
305 * we flush the pcap dumper within each burst.
306 */
307 pcap_dump_flush(dumper_q->dumper);
308 dumper_q->tx_stat.pkts += num_tx;
309 dumper_q->tx_stat.bytes += tx_bytes;
310 dumper_q->tx_stat.err_pkts += nb_pkts - num_tx;
311
312 return num_tx;
313 }
314
315 /*
316 * Callback to handle sending packets through a real NIC.
317 */
318 static uint16_t
319 eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
320 {
321 unsigned int i;
322 int ret;
323 struct rte_mbuf *mbuf;
324 struct pcap_tx_queue *tx_queue = queue;
325 uint16_t num_tx = 0;
326 uint32_t tx_bytes = 0;
327
328 if (unlikely(nb_pkts == 0 || tx_queue->pcap == NULL))
329 return 0;
330
331 for (i = 0; i < nb_pkts; i++) {
332 mbuf = bufs[i];
333
334 if (likely(mbuf->nb_segs == 1)) {
335 ret = pcap_sendpacket(tx_queue->pcap,
336 rte_pktmbuf_mtod(mbuf, u_char *),
337 mbuf->pkt_len);
338 } else {
339 if (mbuf->pkt_len <= ETHER_MAX_JUMBO_FRAME_LEN) {
340 eth_pcap_gather_data(tx_pcap_data, mbuf);
341 ret = pcap_sendpacket(tx_queue->pcap,
342 tx_pcap_data, mbuf->pkt_len);
343 } else {
344 RTE_LOG(ERR, PMD,
345 "Dropping PCAP packet. Size (%d) > max jumbo size (%d).\n",
346 mbuf->pkt_len,
347 ETHER_MAX_JUMBO_FRAME_LEN);
348
349 rte_pktmbuf_free(mbuf);
350 break;
351 }
352 }
353
354 if (unlikely(ret != 0))
355 break;
356 num_tx++;
357 tx_bytes += mbuf->pkt_len;
358 rte_pktmbuf_free(mbuf);
359 }
360
361 tx_queue->tx_stat.pkts += num_tx;
362 tx_queue->tx_stat.bytes += tx_bytes;
363 tx_queue->tx_stat.err_pkts += nb_pkts - num_tx;
364
365 return num_tx;
366 }
367
368 /*
369 * pcap_open_live wrapper function
370 */
371 static inline int
372 open_iface_live(const char *iface, pcap_t **pcap) {
373 *pcap = pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
374 RTE_ETH_PCAP_PROMISC, RTE_ETH_PCAP_TIMEOUT, errbuf);
375
376 if (*pcap == NULL) {
377 RTE_LOG(ERR, PMD, "Couldn't open %s: %s\n", iface, errbuf);
378 return -1;
379 }
380
381 return 0;
382 }
383
384 static int
385 open_single_iface(const char *iface, pcap_t **pcap)
386 {
387 if (open_iface_live(iface, pcap) < 0) {
388 RTE_LOG(ERR, PMD, "Couldn't open interface %s\n", iface);
389 return -1;
390 }
391
392 return 0;
393 }
394
395 static int
396 open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper)
397 {
398 pcap_t *tx_pcap;
399
400 /*
401 * We need to create a dummy empty pcap_t to use it
402 * with pcap_dump_open(). We create big enough an Ethernet
403 * pcap holder.
404 */
405 tx_pcap = pcap_open_dead(DLT_EN10MB, RTE_ETH_PCAP_SNAPSHOT_LEN);
406 if (tx_pcap == NULL) {
407 RTE_LOG(ERR, PMD, "Couldn't create dead pcap\n");
408 return -1;
409 }
410
411 /* The dumper is created using the previous pcap_t reference */
412 *dumper = pcap_dump_open(tx_pcap, pcap_filename);
413 if (*dumper == NULL) {
414 RTE_LOG(ERR, PMD, "Couldn't open %s for writing.\n",
415 pcap_filename);
416 return -1;
417 }
418
419 return 0;
420 }
421
422 static int
423 open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
424 {
425 *pcap = pcap_open_offline(pcap_filename, errbuf);
426 if (*pcap == NULL) {
427 RTE_LOG(ERR, PMD, "Couldn't open %s: %s\n", pcap_filename,
428 errbuf);
429 return -1;
430 }
431
432 return 0;
433 }
434
435 static int
436 eth_dev_start(struct rte_eth_dev *dev)
437 {
438 unsigned int i;
439 struct pmd_internals *internals = dev->data->dev_private;
440 struct pcap_tx_queue *tx;
441 struct pcap_rx_queue *rx;
442
443 /* Special iface case. Single pcap is open and shared between tx/rx. */
444 if (internals->single_iface) {
445 tx = &internals->tx_queue[0];
446 rx = &internals->rx_queue[0];
447
448 if (!tx->pcap && strcmp(tx->type, ETH_PCAP_IFACE_ARG) == 0) {
449 if (open_single_iface(tx->name, &tx->pcap) < 0)
450 return -1;
451 rx->pcap = tx->pcap;
452 }
453 goto status_up;
454 }
455
456 /* If not open already, open tx pcaps/dumpers */
457 for (i = 0; i < dev->data->nb_tx_queues; i++) {
458 tx = &internals->tx_queue[i];
459
460 if (!tx->dumper &&
461 strcmp(tx->type, ETH_PCAP_TX_PCAP_ARG) == 0) {
462 if (open_single_tx_pcap(tx->name, &tx->dumper) < 0)
463 return -1;
464 } else if (!tx->pcap &&
465 strcmp(tx->type, ETH_PCAP_TX_IFACE_ARG) == 0) {
466 if (open_single_iface(tx->name, &tx->pcap) < 0)
467 return -1;
468 }
469 }
470
471 /* If not open already, open rx pcaps */
472 for (i = 0; i < dev->data->nb_rx_queues; i++) {
473 rx = &internals->rx_queue[i];
474
475 if (rx->pcap != NULL)
476 continue;
477
478 if (strcmp(rx->type, ETH_PCAP_RX_PCAP_ARG) == 0) {
479 if (open_single_rx_pcap(rx->name, &rx->pcap) < 0)
480 return -1;
481 } else if (strcmp(rx->type, ETH_PCAP_RX_IFACE_ARG) == 0) {
482 if (open_single_iface(rx->name, &rx->pcap) < 0)
483 return -1;
484 }
485 }
486
487 status_up:
488 dev->data->dev_link.link_status = ETH_LINK_UP;
489
490 return 0;
491 }
492
493 /*
494 * This function gets called when the current port gets stopped.
495 * Is the only place for us to close all the tx streams dumpers.
496 * If not called the dumpers will be flushed within each tx burst.
497 */
498 static void
499 eth_dev_stop(struct rte_eth_dev *dev)
500 {
501 unsigned int i;
502 struct pmd_internals *internals = dev->data->dev_private;
503 struct pcap_tx_queue *tx;
504 struct pcap_rx_queue *rx;
505
506 /* Special iface case. Single pcap is open and shared between tx/rx. */
507 if (internals->single_iface) {
508 tx = &internals->tx_queue[0];
509 rx = &internals->rx_queue[0];
510 pcap_close(tx->pcap);
511 tx->pcap = NULL;
512 rx->pcap = NULL;
513 goto status_down;
514 }
515
516 for (i = 0; i < dev->data->nb_tx_queues; i++) {
517 tx = &internals->tx_queue[i];
518
519 if (tx->dumper != NULL) {
520 pcap_dump_close(tx->dumper);
521 tx->dumper = NULL;
522 }
523
524 if (tx->pcap != NULL) {
525 pcap_close(tx->pcap);
526 tx->pcap = NULL;
527 }
528 }
529
530 for (i = 0; i < dev->data->nb_rx_queues; i++) {
531 rx = &internals->rx_queue[i];
532
533 if (rx->pcap != NULL) {
534 pcap_close(rx->pcap);
535 rx->pcap = NULL;
536 }
537 }
538
539 status_down:
540 dev->data->dev_link.link_status = ETH_LINK_DOWN;
541 }
542
543 static int
544 eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
545 {
546 return 0;
547 }
548
549 static void
550 eth_dev_info(struct rte_eth_dev *dev,
551 struct rte_eth_dev_info *dev_info)
552 {
553 struct pmd_internals *internals = dev->data->dev_private;
554
555 dev_info->driver_name = drivername;
556 dev_info->if_index = internals->if_index;
557 dev_info->max_mac_addrs = 1;
558 dev_info->max_rx_pktlen = (uint32_t) -1;
559 dev_info->max_rx_queues = dev->data->nb_rx_queues;
560 dev_info->max_tx_queues = dev->data->nb_tx_queues;
561 dev_info->min_rx_bufsize = 0;
562 dev_info->pci_dev = NULL;
563 }
564
565 static void
566 eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
567 {
568 unsigned int i;
569 unsigned long rx_packets_total = 0, rx_bytes_total = 0;
570 unsigned long tx_packets_total = 0, tx_bytes_total = 0;
571 unsigned long tx_packets_err_total = 0;
572 const struct pmd_internals *internal = dev->data->dev_private;
573
574 for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
575 i < dev->data->nb_rx_queues; i++) {
576 stats->q_ipackets[i] = internal->rx_queue[i].rx_stat.pkts;
577 stats->q_ibytes[i] = internal->rx_queue[i].rx_stat.bytes;
578 rx_packets_total += stats->q_ipackets[i];
579 rx_bytes_total += stats->q_ibytes[i];
580 }
581
582 for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
583 i < dev->data->nb_tx_queues; i++) {
584 stats->q_opackets[i] = internal->tx_queue[i].tx_stat.pkts;
585 stats->q_obytes[i] = internal->tx_queue[i].tx_stat.bytes;
586 stats->q_errors[i] = internal->tx_queue[i].tx_stat.err_pkts;
587 tx_packets_total += stats->q_opackets[i];
588 tx_bytes_total += stats->q_obytes[i];
589 tx_packets_err_total += stats->q_errors[i];
590 }
591
592 stats->ipackets = rx_packets_total;
593 stats->ibytes = rx_bytes_total;
594 stats->opackets = tx_packets_total;
595 stats->obytes = tx_bytes_total;
596 stats->oerrors = tx_packets_err_total;
597 }
598
599 static void
600 eth_stats_reset(struct rte_eth_dev *dev)
601 {
602 unsigned int i;
603 struct pmd_internals *internal = dev->data->dev_private;
604
605 for (i = 0; i < dev->data->nb_rx_queues; i++) {
606 internal->rx_queue[i].rx_stat.pkts = 0;
607 internal->rx_queue[i].rx_stat.bytes = 0;
608 }
609
610 for (i = 0; i < dev->data->nb_tx_queues; i++) {
611 internal->tx_queue[i].tx_stat.pkts = 0;
612 internal->tx_queue[i].tx_stat.bytes = 0;
613 internal->tx_queue[i].tx_stat.err_pkts = 0;
614 }
615 }
616
617 static void
618 eth_dev_close(struct rte_eth_dev *dev __rte_unused)
619 {
620 }
621
622 static void
623 eth_queue_release(void *q __rte_unused)
624 {
625 }
626
627 static int
628 eth_link_update(struct rte_eth_dev *dev __rte_unused,
629 int wait_to_complete __rte_unused)
630 {
631 return 0;
632 }
633
634 static int
635 eth_rx_queue_setup(struct rte_eth_dev *dev,
636 uint16_t rx_queue_id,
637 uint16_t nb_rx_desc __rte_unused,
638 unsigned int socket_id __rte_unused,
639 const struct rte_eth_rxconf *rx_conf __rte_unused,
640 struct rte_mempool *mb_pool)
641 {
642 struct pmd_internals *internals = dev->data->dev_private;
643 struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
644
645 pcap_q->mb_pool = mb_pool;
646 dev->data->rx_queues[rx_queue_id] = pcap_q;
647 pcap_q->in_port = dev->data->port_id;
648
649 return 0;
650 }
651
652 static int
653 eth_tx_queue_setup(struct rte_eth_dev *dev,
654 uint16_t tx_queue_id,
655 uint16_t nb_tx_desc __rte_unused,
656 unsigned int socket_id __rte_unused,
657 const struct rte_eth_txconf *tx_conf __rte_unused)
658 {
659 struct pmd_internals *internals = dev->data->dev_private;
660
661 dev->data->tx_queues[tx_queue_id] = &internals->tx_queue[tx_queue_id];
662
663 return 0;
664 }
665
666 static const struct eth_dev_ops ops = {
667 .dev_start = eth_dev_start,
668 .dev_stop = eth_dev_stop,
669 .dev_close = eth_dev_close,
670 .dev_configure = eth_dev_configure,
671 .dev_infos_get = eth_dev_info,
672 .rx_queue_setup = eth_rx_queue_setup,
673 .tx_queue_setup = eth_tx_queue_setup,
674 .rx_queue_release = eth_queue_release,
675 .tx_queue_release = eth_queue_release,
676 .link_update = eth_link_update,
677 .stats_get = eth_stats_get,
678 .stats_reset = eth_stats_reset,
679 };
680
681 /*
682 * Function handler that opens the pcap file for reading a stores a
683 * reference of it for use it later on.
684 */
685 static int
686 open_rx_pcap(const char *key, const char *value, void *extra_args)
687 {
688 unsigned int i;
689 const char *pcap_filename = value;
690 struct pmd_devargs *rx = extra_args;
691 pcap_t *pcap = NULL;
692
693 for (i = 0; i < rx->num_of_queue; i++) {
694 if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
695 return -1;
696
697 rx->queue[i].pcap = pcap;
698 rx->queue[i].name = pcap_filename;
699 rx->queue[i].type = key;
700 }
701
702 return 0;
703 }
704
705 /*
706 * Opens a pcap file for writing and stores a reference to it
707 * for use it later on.
708 */
709 static int
710 open_tx_pcap(const char *key, const char *value, void *extra_args)
711 {
712 unsigned int i;
713 const char *pcap_filename = value;
714 struct pmd_devargs *dumpers = extra_args;
715 pcap_dumper_t *dumper;
716
717 for (i = 0; i < dumpers->num_of_queue; i++) {
718 if (open_single_tx_pcap(pcap_filename, &dumper) < 0)
719 return -1;
720
721 dumpers->queue[i].dumper = dumper;
722 dumpers->queue[i].name = pcap_filename;
723 dumpers->queue[i].type = key;
724 }
725
726 return 0;
727 }
728
729 /*
730 * Opens an interface for reading and writing
731 */
732 static inline int
733 open_rx_tx_iface(const char *key, const char *value, void *extra_args)
734 {
735 const char *iface = value;
736 struct pmd_devargs *tx = extra_args;
737 pcap_t *pcap = NULL;
738
739 if (open_single_iface(iface, &pcap) < 0)
740 return -1;
741
742 tx->queue[0].pcap = pcap;
743 tx->queue[0].name = iface;
744 tx->queue[0].type = key;
745
746 return 0;
747 }
748
749 /*
750 * Opens a NIC for reading packets from it
751 */
752 static inline int
753 open_rx_iface(const char *key, const char *value, void *extra_args)
754 {
755 unsigned int i;
756 const char *iface = value;
757 struct pmd_devargs *rx = extra_args;
758 pcap_t *pcap = NULL;
759
760 for (i = 0; i < rx->num_of_queue; i++) {
761 if (open_single_iface(iface, &pcap) < 0)
762 return -1;
763 rx->queue[i].pcap = pcap;
764 rx->queue[i].name = iface;
765 rx->queue[i].type = key;
766 }
767
768 return 0;
769 }
770
771 /*
772 * Opens a NIC for writing packets to it
773 */
774 static int
775 open_tx_iface(const char *key, const char *value, void *extra_args)
776 {
777 unsigned int i;
778 const char *iface = value;
779 struct pmd_devargs *tx = extra_args;
780 pcap_t *pcap;
781
782 for (i = 0; i < tx->num_of_queue; i++) {
783 if (open_single_iface(iface, &pcap) < 0)
784 return -1;
785 tx->queue[i].pcap = pcap;
786 tx->queue[i].name = iface;
787 tx->queue[i].type = key;
788 }
789
790 return 0;
791 }
792
793 static int
794 pmd_init_internals(const char *name, const unsigned int nb_rx_queues,
795 const unsigned int nb_tx_queues,
796 struct pmd_internals **internals,
797 struct rte_eth_dev **eth_dev)
798 {
799 struct rte_eth_dev_data *data = NULL;
800 unsigned int numa_node = rte_socket_id();
801
802 RTE_LOG(INFO, PMD, "Creating pcap-backed ethdev on numa socket %u\n",
803 numa_node);
804
805 /* now do all data allocation - for eth_dev structure
806 * and internal (private) data
807 */
808 data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
809 if (data == NULL)
810 goto error;
811
812 *internals = rte_zmalloc_socket(name, sizeof(**internals), 0,
813 numa_node);
814 if (*internals == NULL)
815 goto error;
816
817 /* reserve an ethdev entry */
818 *eth_dev = rte_eth_dev_allocate(name);
819 if (*eth_dev == NULL)
820 goto error;
821
822 /* now put it all together
823 * - store queue data in internals,
824 * - store numa_node info in eth_dev
825 * - point eth_dev_data to internals
826 * - and point eth_dev structure to new eth_dev_data structure
827 */
828 data->dev_private = *internals;
829 data->port_id = (*eth_dev)->data->port_id;
830 snprintf(data->name, sizeof(data->name), "%s", (*eth_dev)->data->name);
831 data->nb_rx_queues = (uint16_t)nb_rx_queues;
832 data->nb_tx_queues = (uint16_t)nb_tx_queues;
833 data->dev_link = pmd_link;
834 data->mac_addrs = &eth_addr;
835
836 /*
837 * NOTE: we'll replace the data element, of originally allocated
838 * eth_dev so the rings are local per-process
839 */
840 (*eth_dev)->data = data;
841 (*eth_dev)->dev_ops = &ops;
842 (*eth_dev)->driver = NULL;
843 data->dev_flags = RTE_ETH_DEV_DETACHABLE;
844 data->kdrv = RTE_KDRV_NONE;
845 data->drv_name = drivername;
846 data->numa_node = numa_node;
847
848 return 0;
849
850 error:
851 rte_free(data);
852 rte_free(*internals);
853
854 return -1;
855 }
856
857 static int
858 eth_from_pcaps_common(const char *name, struct pmd_devargs *rx_queues,
859 const unsigned int nb_rx_queues, struct pmd_devargs *tx_queues,
860 const unsigned int nb_tx_queues, struct rte_kvargs *kvlist,
861 struct pmd_internals **internals, struct rte_eth_dev **eth_dev)
862 {
863 struct rte_kvargs_pair *pair = NULL;
864 unsigned int k_idx;
865 unsigned int i;
866
867 /* do some parameter checking */
868 if (rx_queues == NULL && nb_rx_queues > 0)
869 return -1;
870 if (tx_queues == NULL && nb_tx_queues > 0)
871 return -1;
872
873 if (pmd_init_internals(name, nb_rx_queues, nb_tx_queues, internals,
874 eth_dev) < 0)
875 return -1;
876
877 for (i = 0; i < nb_rx_queues; i++) {
878 struct pcap_rx_queue *rx = &(*internals)->rx_queue[i];
879 struct devargs_queue *queue = &rx_queues->queue[i];
880
881 rx->pcap = queue->pcap;
882 snprintf(rx->name, sizeof(rx->name), "%s", queue->name);
883 snprintf(rx->type, sizeof(rx->type), "%s", queue->type);
884 }
885
886 for (i = 0; i < nb_tx_queues; i++) {
887 struct pcap_tx_queue *tx = &(*internals)->tx_queue[i];
888 struct devargs_queue *queue = &tx_queues->queue[i];
889
890 tx->dumper = queue->dumper;
891 tx->pcap = queue->pcap;
892 snprintf(tx->name, sizeof(tx->name), "%s", queue->name);
893 snprintf(tx->type, sizeof(tx->type), "%s", queue->type);
894 }
895
896 for (k_idx = 0; k_idx < kvlist->count; k_idx++) {
897 pair = &kvlist->pairs[k_idx];
898 if (strstr(pair->key, ETH_PCAP_IFACE_ARG) != NULL)
899 break;
900 }
901
902 if (pair == NULL)
903 (*internals)->if_index = 0;
904 else
905 (*internals)->if_index = if_nametoindex(pair->value);
906
907 return 0;
908 }
909
910 static int
911 eth_from_pcaps(const char *name, struct pmd_devargs *rx_queues,
912 const unsigned int nb_rx_queues, struct pmd_devargs *tx_queues,
913 const unsigned int nb_tx_queues, struct rte_kvargs *kvlist,
914 int single_iface, unsigned int using_dumpers)
915 {
916 struct pmd_internals *internals = NULL;
917 struct rte_eth_dev *eth_dev = NULL;
918 int ret;
919
920 ret = eth_from_pcaps_common(name, rx_queues, nb_rx_queues,
921 tx_queues, nb_tx_queues, kvlist, &internals, &eth_dev);
922
923 if (ret < 0)
924 return ret;
925
926 /* store weather we are using a single interface for rx/tx or not */
927 internals->single_iface = single_iface;
928
929 eth_dev->rx_pkt_burst = eth_pcap_rx;
930
931 if (using_dumpers)
932 eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
933 else
934 eth_dev->tx_pkt_burst = eth_pcap_tx;
935
936 return 0;
937 }
938
939 static int
940 pmd_pcap_probe(const char *name, const char *params)
941 {
942 unsigned int is_rx_pcap = 0, is_tx_pcap = 0;
943 struct rte_kvargs *kvlist;
944 struct pmd_devargs pcaps = {0};
945 struct pmd_devargs dumpers = {0};
946 int single_iface = 0;
947 int ret;
948
949 RTE_LOG(INFO, PMD, "Initializing pmd_pcap for %s\n", name);
950
951 gettimeofday(&start_time, NULL);
952 start_cycles = rte_get_timer_cycles();
953 hz = rte_get_timer_hz();
954
955 kvlist = rte_kvargs_parse(params, valid_arguments);
956 if (kvlist == NULL)
957 return -1;
958
959 /*
960 * If iface argument is passed we open the NICs and use them for
961 * reading / writing
962 */
963 if (rte_kvargs_count(kvlist, ETH_PCAP_IFACE_ARG) == 1) {
964
965 ret = rte_kvargs_process(kvlist, ETH_PCAP_IFACE_ARG,
966 &open_rx_tx_iface, &pcaps);
967
968 if (ret < 0)
969 goto free_kvlist;
970
971 dumpers.queue[0] = pcaps.queue[0];
972
973 single_iface = 1;
974 pcaps.num_of_queue = 1;
975 dumpers.num_of_queue = 1;
976
977 goto create_eth;
978 }
979
980 /*
981 * We check whether we want to open a RX stream from a real NIC or a
982 * pcap file
983 */
984 pcaps.num_of_queue = rte_kvargs_count(kvlist, ETH_PCAP_RX_PCAP_ARG);
985 if (pcaps.num_of_queue)
986 is_rx_pcap = 1;
987 else
988 pcaps.num_of_queue = rte_kvargs_count(kvlist,
989 ETH_PCAP_RX_IFACE_ARG);
990
991 if (pcaps.num_of_queue > RTE_PMD_PCAP_MAX_QUEUES)
992 pcaps.num_of_queue = RTE_PMD_PCAP_MAX_QUEUES;
993
994 if (is_rx_pcap)
995 ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_PCAP_ARG,
996 &open_rx_pcap, &pcaps);
997 else
998 ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_IFACE_ARG,
999 &open_rx_iface, &pcaps);
1000
1001 if (ret < 0)
1002 goto free_kvlist;
1003
1004 /*
1005 * We check whether we want to open a TX stream to a real NIC or a
1006 * pcap file
1007 */
1008 dumpers.num_of_queue = rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG);
1009 if (dumpers.num_of_queue)
1010 is_tx_pcap = 1;
1011 else
1012 dumpers.num_of_queue = rte_kvargs_count(kvlist,
1013 ETH_PCAP_TX_IFACE_ARG);
1014
1015 if (dumpers.num_of_queue > RTE_PMD_PCAP_MAX_QUEUES)
1016 dumpers.num_of_queue = RTE_PMD_PCAP_MAX_QUEUES;
1017
1018 if (is_tx_pcap)
1019 ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_PCAP_ARG,
1020 &open_tx_pcap, &dumpers);
1021 else
1022 ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_IFACE_ARG,
1023 &open_tx_iface, &dumpers);
1024
1025 if (ret < 0)
1026 goto free_kvlist;
1027
1028 create_eth:
1029 ret = eth_from_pcaps(name, &pcaps, pcaps.num_of_queue, &dumpers,
1030 dumpers.num_of_queue, kvlist, single_iface, is_tx_pcap);
1031
1032 free_kvlist:
1033 rte_kvargs_free(kvlist);
1034
1035 return ret;
1036 }
1037
1038 static int
1039 pmd_pcap_remove(const char *name)
1040 {
1041 struct rte_eth_dev *eth_dev = NULL;
1042
1043 RTE_LOG(INFO, PMD, "Closing pcap ethdev on numa socket %u\n",
1044 rte_socket_id());
1045
1046 if (name == NULL)
1047 return -1;
1048
1049 /* reserve an ethdev entry */
1050 eth_dev = rte_eth_dev_allocated(name);
1051 if (eth_dev == NULL)
1052 return -1;
1053
1054 rte_free(eth_dev->data->dev_private);
1055 rte_free(eth_dev->data);
1056
1057 rte_eth_dev_release_port(eth_dev);
1058
1059 return 0;
1060 }
1061
1062 static struct rte_vdev_driver pmd_pcap_drv = {
1063 .probe = pmd_pcap_probe,
1064 .remove = pmd_pcap_remove,
1065 };
1066
1067 RTE_PMD_REGISTER_VDEV(net_pcap, pmd_pcap_drv);
1068 RTE_PMD_REGISTER_ALIAS(net_pcap, eth_pcap);
1069 RTE_PMD_REGISTER_PARAM_STRING(net_pcap,
1070 ETH_PCAP_RX_PCAP_ARG "=<string> "
1071 ETH_PCAP_TX_PCAP_ARG "=<string> "
1072 ETH_PCAP_RX_IFACE_ARG "=<ifc> "
1073 ETH_PCAP_TX_IFACE_ARG "=<ifc> "
1074 ETH_PCAP_IFACE_ARG "=<ifc>");