4 * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5 * Copyright(c) 2014 6WIND S.A.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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.
41 #include <rte_cycles.h>
42 #include <rte_ethdev.h>
43 #include <rte_kvargs.h>
44 #include <rte_malloc.h>
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
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"
59 #define ETH_PCAP_ARG_MAXLEN 64
61 #define RTE_PMD_PCAP_MAX_QUEUES 16
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
;
70 volatile unsigned long pkts
;
71 volatile unsigned long bytes
;
72 volatile unsigned long err_pkts
;
75 struct pcap_rx_queue
{
78 struct rte_mempool
*mb_pool
;
79 struct queue_stat rx_stat
;
81 char type
[ETH_PCAP_ARG_MAXLEN
];
84 struct pcap_tx_queue
{
85 pcap_dumper_t
*dumper
;
87 struct queue_stat tx_stat
;
89 char type
[ETH_PCAP_ARG_MAXLEN
];
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
];
100 unsigned int num_of_queue
;
101 struct devargs_queue
{
102 pcap_dumper_t
*dumper
;
106 } queue
[RTE_PMD_PCAP_MAX_QUEUES
];
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
,
118 static struct ether_addr eth_addr
= {
119 .addr_bytes
= { 0, 0, 0, 0x1, 0x2, 0x3 }
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
,
131 eth_pcap_rx_jumbo(struct rte_mempool
*mb_pool
, struct rte_mbuf
*mbuf
,
132 const u_char
*data
, uint16_t data_len
)
134 /* Copy the first segment. */
135 uint16_t len
= rte_pktmbuf_tailroom(mbuf
);
136 struct rte_mbuf
*m
= mbuf
;
138 rte_memcpy(rte_pktmbuf_append(mbuf
, len
), data
, len
);
142 while (data_len
> 0) {
143 /* Allocate next mbuf and point to that. */
144 m
->next
= rte_pktmbuf_alloc(mb_pool
);
146 if (unlikely(!m
->next
))
151 /* Headroom is not needed in chained mbufs. */
152 rte_pktmbuf_prepend(m
, rte_pktmbuf_headroom(m
));
156 /* Copy next segment. */
157 len
= RTE_MIN(rte_pktmbuf_tailroom(m
), data_len
);
158 rte_memcpy(rte_pktmbuf_append(m
, len
), data
, len
);
165 return mbuf
->nb_segs
;
168 /* Copy data from mbuf chain to a buffer suitable for writing to a PCAP file. */
170 eth_pcap_gather_data(unsigned char *data
, struct rte_mbuf
*mbuf
)
172 uint16_t data_len
= 0;
175 rte_memcpy(data
+ data_len
, rte_pktmbuf_mtod(mbuf
, void *),
178 data_len
+= mbuf
->data_len
;
184 eth_pcap_rx(void *queue
, struct rte_mbuf
**bufs
, uint16_t nb_pkts
)
187 struct pcap_pkthdr header
;
188 const u_char
*packet
;
189 struct rte_mbuf
*mbuf
;
190 struct pcap_rx_queue
*pcap_q
= queue
;
193 uint32_t rx_bytes
= 0;
195 if (unlikely(pcap_q
->pcap
== NULL
|| nb_pkts
== 0))
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.
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
))
207 mbuf
= rte_pktmbuf_alloc(pcap_q
->mb_pool
);
208 if (unlikely(mbuf
== NULL
))
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
;
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
,
219 mbuf
->data_len
= (uint16_t)header
.caplen
;
221 /* Try read jumbo frame into multi mbufs. */
222 if (unlikely(eth_pcap_rx_jumbo(pcap_q
->mb_pool
,
225 header
.caplen
) == -1)) {
226 rte_pktmbuf_free(mbuf
);
231 mbuf
->pkt_len
= (uint16_t)header
.caplen
;
232 mbuf
->port
= pcap_q
->in_port
;
235 rx_bytes
+= header
.caplen
;
237 pcap_q
->rx_stat
.pkts
+= num_rx
;
238 pcap_q
->rx_stat
.bytes
+= rx_bytes
;
244 calculate_timestamp(struct timeval
*ts
) {
246 struct timeval cur_time
;
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
);
255 * Callback to handle writing packets to a pcap file.
258 eth_pcap_tx_dumper(void *queue
, struct rte_mbuf
**bufs
, uint16_t nb_pkts
)
261 struct rte_mbuf
*mbuf
;
262 struct pcap_tx_queue
*dumper_q
= queue
;
264 uint32_t tx_bytes
= 0;
265 struct pcap_pkthdr header
;
267 if (dumper_q
->dumper
== NULL
|| nb_pkts
== 0)
270 /* writes the nb_pkts packets to the previously opened pcap file
272 for (i
= 0; i
< nb_pkts
; i
++) {
274 calculate_timestamp(&header
.ts
);
275 header
.len
= mbuf
->pkt_len
;
276 header
.caplen
= header
.len
;
278 if (likely(mbuf
->nb_segs
== 1)) {
279 pcap_dump((u_char
*)dumper_q
->dumper
, &header
,
280 rte_pktmbuf_mtod(mbuf
, void*));
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
,
288 "Dropping PCAP packet. Size (%d) > max jumbo size (%d).\n",
290 ETHER_MAX_JUMBO_FRAME_LEN
);
292 rte_pktmbuf_free(mbuf
);
297 rte_pktmbuf_free(mbuf
);
299 tx_bytes
+= mbuf
->pkt_len
;
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.
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
;
316 * Callback to handle sending packets through a real NIC.
319 eth_pcap_tx(void *queue
, struct rte_mbuf
**bufs
, uint16_t nb_pkts
)
323 struct rte_mbuf
*mbuf
;
324 struct pcap_tx_queue
*tx_queue
= queue
;
326 uint32_t tx_bytes
= 0;
328 if (unlikely(nb_pkts
== 0 || tx_queue
->pcap
== NULL
))
331 for (i
= 0; i
< nb_pkts
; i
++) {
334 if (likely(mbuf
->nb_segs
== 1)) {
335 ret
= pcap_sendpacket(tx_queue
->pcap
,
336 rte_pktmbuf_mtod(mbuf
, u_char
*),
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
);
345 "Dropping PCAP packet. Size (%d) > max jumbo size (%d).\n",
347 ETHER_MAX_JUMBO_FRAME_LEN
);
349 rte_pktmbuf_free(mbuf
);
354 if (unlikely(ret
!= 0))
357 tx_bytes
+= mbuf
->pkt_len
;
358 rte_pktmbuf_free(mbuf
);
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
;
369 * pcap_open_live wrapper function
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
);
377 RTE_LOG(ERR
, PMD
, "Couldn't open %s: %s\n", iface
, errbuf
);
385 open_single_iface(const char *iface
, pcap_t
**pcap
)
387 if (open_iface_live(iface
, pcap
) < 0) {
388 RTE_LOG(ERR
, PMD
, "Couldn't open interface %s\n", iface
);
396 open_single_tx_pcap(const char *pcap_filename
, pcap_dumper_t
**dumper
)
401 * We need to create a dummy empty pcap_t to use it
402 * with pcap_dump_open(). We create big enough an Ethernet
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");
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",
423 open_single_rx_pcap(const char *pcap_filename
, pcap_t
**pcap
)
425 *pcap
= pcap_open_offline(pcap_filename
, errbuf
);
427 RTE_LOG(ERR
, PMD
, "Couldn't open %s: %s\n", pcap_filename
,
436 eth_dev_start(struct rte_eth_dev
*dev
)
439 struct pmd_internals
*internals
= dev
->data
->dev_private
;
440 struct pcap_tx_queue
*tx
;
441 struct pcap_rx_queue
*rx
;
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];
448 if (!tx
->pcap
&& strcmp(tx
->type
, ETH_PCAP_IFACE_ARG
) == 0) {
449 if (open_single_iface(tx
->name
, &tx
->pcap
) < 0)
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
];
461 strcmp(tx
->type
, ETH_PCAP_TX_PCAP_ARG
) == 0) {
462 if (open_single_tx_pcap(tx
->name
, &tx
->dumper
) < 0)
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)
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
];
475 if (rx
->pcap
!= NULL
)
478 if (strcmp(rx
->type
, ETH_PCAP_RX_PCAP_ARG
) == 0) {
479 if (open_single_rx_pcap(rx
->name
, &rx
->pcap
) < 0)
481 } else if (strcmp(rx
->type
, ETH_PCAP_RX_IFACE_ARG
) == 0) {
482 if (open_single_iface(rx
->name
, &rx
->pcap
) < 0)
488 dev
->data
->dev_link
.link_status
= ETH_LINK_UP
;
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.
499 eth_dev_stop(struct rte_eth_dev
*dev
)
502 struct pmd_internals
*internals
= dev
->data
->dev_private
;
503 struct pcap_tx_queue
*tx
;
504 struct pcap_rx_queue
*rx
;
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
);
516 for (i
= 0; i
< dev
->data
->nb_tx_queues
; i
++) {
517 tx
= &internals
->tx_queue
[i
];
519 if (tx
->dumper
!= NULL
) {
520 pcap_dump_close(tx
->dumper
);
524 if (tx
->pcap
!= NULL
) {
525 pcap_close(tx
->pcap
);
530 for (i
= 0; i
< dev
->data
->nb_rx_queues
; i
++) {
531 rx
= &internals
->rx_queue
[i
];
533 if (rx
->pcap
!= NULL
) {
534 pcap_close(rx
->pcap
);
540 dev
->data
->dev_link
.link_status
= ETH_LINK_DOWN
;
544 eth_dev_configure(struct rte_eth_dev
*dev __rte_unused
)
550 eth_dev_info(struct rte_eth_dev
*dev
,
551 struct rte_eth_dev_info
*dev_info
)
553 struct pmd_internals
*internals
= dev
->data
->dev_private
;
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
;
566 eth_stats_get(struct rte_eth_dev
*dev
, struct rte_eth_stats
*stats
)
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
;
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
];
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
];
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
;
600 eth_stats_reset(struct rte_eth_dev
*dev
)
603 struct pmd_internals
*internal
= dev
->data
->dev_private
;
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;
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;
618 eth_dev_close(struct rte_eth_dev
*dev __rte_unused
)
623 eth_queue_release(void *q __rte_unused
)
628 eth_link_update(struct rte_eth_dev
*dev __rte_unused
,
629 int wait_to_complete __rte_unused
)
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
)
642 struct pmd_internals
*internals
= dev
->data
->dev_private
;
643 struct pcap_rx_queue
*pcap_q
= &internals
->rx_queue
[rx_queue_id
];
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
;
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
)
659 struct pmd_internals
*internals
= dev
->data
->dev_private
;
661 dev
->data
->tx_queues
[tx_queue_id
] = &internals
->tx_queue
[tx_queue_id
];
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
,
682 * Function handler that opens the pcap file for reading a stores a
683 * reference of it for use it later on.
686 open_rx_pcap(const char *key
, const char *value
, void *extra_args
)
689 const char *pcap_filename
= value
;
690 struct pmd_devargs
*rx
= extra_args
;
693 for (i
= 0; i
< rx
->num_of_queue
; i
++) {
694 if (open_single_rx_pcap(pcap_filename
, &pcap
) < 0)
697 rx
->queue
[i
].pcap
= pcap
;
698 rx
->queue
[i
].name
= pcap_filename
;
699 rx
->queue
[i
].type
= key
;
706 * Opens a pcap file for writing and stores a reference to it
707 * for use it later on.
710 open_tx_pcap(const char *key
, const char *value
, void *extra_args
)
713 const char *pcap_filename
= value
;
714 struct pmd_devargs
*dumpers
= extra_args
;
715 pcap_dumper_t
*dumper
;
717 for (i
= 0; i
< dumpers
->num_of_queue
; i
++) {
718 if (open_single_tx_pcap(pcap_filename
, &dumper
) < 0)
721 dumpers
->queue
[i
].dumper
= dumper
;
722 dumpers
->queue
[i
].name
= pcap_filename
;
723 dumpers
->queue
[i
].type
= key
;
730 * Opens an interface for reading and writing
733 open_rx_tx_iface(const char *key
, const char *value
, void *extra_args
)
735 const char *iface
= value
;
736 struct pmd_devargs
*tx
= extra_args
;
739 if (open_single_iface(iface
, &pcap
) < 0)
742 tx
->queue
[0].pcap
= pcap
;
743 tx
->queue
[0].name
= iface
;
744 tx
->queue
[0].type
= key
;
750 * Opens a NIC for reading packets from it
753 open_rx_iface(const char *key
, const char *value
, void *extra_args
)
756 const char *iface
= value
;
757 struct pmd_devargs
*rx
= extra_args
;
760 for (i
= 0; i
< rx
->num_of_queue
; i
++) {
761 if (open_single_iface(iface
, &pcap
) < 0)
763 rx
->queue
[i
].pcap
= pcap
;
764 rx
->queue
[i
].name
= iface
;
765 rx
->queue
[i
].type
= key
;
772 * Opens a NIC for writing packets to it
775 open_tx_iface(const char *key
, const char *value
, void *extra_args
)
778 const char *iface
= value
;
779 struct pmd_devargs
*tx
= extra_args
;
782 for (i
= 0; i
< tx
->num_of_queue
; i
++) {
783 if (open_single_iface(iface
, &pcap
) < 0)
785 tx
->queue
[i
].pcap
= pcap
;
786 tx
->queue
[i
].name
= iface
;
787 tx
->queue
[i
].type
= key
;
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
)
799 struct rte_eth_dev_data
*data
= NULL
;
800 unsigned int numa_node
= rte_socket_id();
802 RTE_LOG(INFO
, PMD
, "Creating pcap-backed ethdev on numa socket %u\n",
805 /* now do all data allocation - for eth_dev structure
806 * and internal (private) data
808 data
= rte_zmalloc_socket(name
, sizeof(*data
), 0, numa_node
);
812 *internals
= rte_zmalloc_socket(name
, sizeof(**internals
), 0,
814 if (*internals
== NULL
)
817 /* reserve an ethdev entry */
818 *eth_dev
= rte_eth_dev_allocate(name
);
819 if (*eth_dev
== NULL
)
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
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
= ð_addr
;
837 * NOTE: we'll replace the data element, of originally allocated
838 * eth_dev so the rings are local per-process
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
;
852 rte_free(*internals
);
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
)
863 struct rte_kvargs_pair
*pair
= NULL
;
867 /* do some parameter checking */
868 if (rx_queues
== NULL
&& nb_rx_queues
> 0)
870 if (tx_queues
== NULL
&& nb_tx_queues
> 0)
873 if (pmd_init_internals(name
, nb_rx_queues
, nb_tx_queues
, internals
,
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
];
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
);
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
];
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
);
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
)
903 (*internals
)->if_index
= 0;
905 (*internals
)->if_index
= if_nametoindex(pair
->value
);
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
)
916 struct pmd_internals
*internals
= NULL
;
917 struct rte_eth_dev
*eth_dev
= NULL
;
920 ret
= eth_from_pcaps_common(name
, rx_queues
, nb_rx_queues
,
921 tx_queues
, nb_tx_queues
, kvlist
, &internals
, ð_dev
);
926 /* store weather we are using a single interface for rx/tx or not */
927 internals
->single_iface
= single_iface
;
929 eth_dev
->rx_pkt_burst
= eth_pcap_rx
;
932 eth_dev
->tx_pkt_burst
= eth_pcap_tx_dumper
;
934 eth_dev
->tx_pkt_burst
= eth_pcap_tx
;
940 pmd_pcap_probe(const char *name
, const char *params
)
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;
949 RTE_LOG(INFO
, PMD
, "Initializing pmd_pcap for %s\n", name
);
951 gettimeofday(&start_time
, NULL
);
952 start_cycles
= rte_get_timer_cycles();
953 hz
= rte_get_timer_hz();
955 kvlist
= rte_kvargs_parse(params
, valid_arguments
);
960 * If iface argument is passed we open the NICs and use them for
963 if (rte_kvargs_count(kvlist
, ETH_PCAP_IFACE_ARG
) == 1) {
965 ret
= rte_kvargs_process(kvlist
, ETH_PCAP_IFACE_ARG
,
966 &open_rx_tx_iface
, &pcaps
);
971 dumpers
.queue
[0] = pcaps
.queue
[0];
974 pcaps
.num_of_queue
= 1;
975 dumpers
.num_of_queue
= 1;
981 * We check whether we want to open a RX stream from a real NIC or a
984 pcaps
.num_of_queue
= rte_kvargs_count(kvlist
, ETH_PCAP_RX_PCAP_ARG
);
985 if (pcaps
.num_of_queue
)
988 pcaps
.num_of_queue
= rte_kvargs_count(kvlist
,
989 ETH_PCAP_RX_IFACE_ARG
);
991 if (pcaps
.num_of_queue
> RTE_PMD_PCAP_MAX_QUEUES
)
992 pcaps
.num_of_queue
= RTE_PMD_PCAP_MAX_QUEUES
;
995 ret
= rte_kvargs_process(kvlist
, ETH_PCAP_RX_PCAP_ARG
,
996 &open_rx_pcap
, &pcaps
);
998 ret
= rte_kvargs_process(kvlist
, ETH_PCAP_RX_IFACE_ARG
,
999 &open_rx_iface
, &pcaps
);
1005 * We check whether we want to open a TX stream to a real NIC or a
1008 dumpers
.num_of_queue
= rte_kvargs_count(kvlist
, ETH_PCAP_TX_PCAP_ARG
);
1009 if (dumpers
.num_of_queue
)
1012 dumpers
.num_of_queue
= rte_kvargs_count(kvlist
,
1013 ETH_PCAP_TX_IFACE_ARG
);
1015 if (dumpers
.num_of_queue
> RTE_PMD_PCAP_MAX_QUEUES
)
1016 dumpers
.num_of_queue
= RTE_PMD_PCAP_MAX_QUEUES
;
1019 ret
= rte_kvargs_process(kvlist
, ETH_PCAP_TX_PCAP_ARG
,
1020 &open_tx_pcap
, &dumpers
);
1022 ret
= rte_kvargs_process(kvlist
, ETH_PCAP_TX_IFACE_ARG
,
1023 &open_tx_iface
, &dumpers
);
1029 ret
= eth_from_pcaps(name
, &pcaps
, pcaps
.num_of_queue
, &dumpers
,
1030 dumpers
.num_of_queue
, kvlist
, single_iface
, is_tx_pcap
);
1033 rte_kvargs_free(kvlist
);
1039 pmd_pcap_remove(const char *name
)
1041 struct rte_eth_dev
*eth_dev
= NULL
;
1043 RTE_LOG(INFO
, PMD
, "Closing pcap ethdev on numa socket %u\n",
1049 /* reserve an ethdev entry */
1050 eth_dev
= rte_eth_dev_allocated(name
);
1051 if (eth_dev
== NULL
)
1054 rte_free(eth_dev
->data
->dev_private
);
1055 rte_free(eth_dev
->data
);
1057 rte_eth_dev_release_port(eth_dev
);
1062 static struct rte_vdev_driver pmd_pcap_drv
= {
1063 .probe
= pmd_pcap_probe
,
1064 .remove
= pmd_pcap_remove
,
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>");