Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2016 Intel Corporation.
3 : : * Copyright(c) 2014 6WIND S.A.
4 : : * All rights reserved.
5 : : */
6 : :
7 : : #include <stdlib.h>
8 : : #include <time.h>
9 : :
10 : : #include <pcap.h>
11 : :
12 : : #include <rte_cycles.h>
13 : : #include <ethdev_driver.h>
14 : : #include <ethdev_vdev.h>
15 : : #include <rte_kvargs.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_mbuf.h>
18 : : #include <rte_mbuf_dyn.h>
19 : : #include <bus_vdev_driver.h>
20 : : #include <rte_os_shim.h>
21 : :
22 : : #include "pcap_osdep.h"
23 : :
24 : : #define RTE_ETH_PCAP_SNAPSHOT_LEN 65535
25 : : #define RTE_ETH_PCAP_SNAPLEN RTE_ETHER_MAX_JUMBO_FRAME_LEN
26 : : #define RTE_ETH_PCAP_PROMISC 1
27 : : #define RTE_ETH_PCAP_TIMEOUT -1
28 : :
29 : : #define ETH_PCAP_RX_PCAP_ARG "rx_pcap"
30 : : #define ETH_PCAP_TX_PCAP_ARG "tx_pcap"
31 : : #define ETH_PCAP_RX_IFACE_ARG "rx_iface"
32 : : #define ETH_PCAP_RX_IFACE_IN_ARG "rx_iface_in"
33 : : #define ETH_PCAP_TX_IFACE_ARG "tx_iface"
34 : : #define ETH_PCAP_IFACE_ARG "iface"
35 : : #define ETH_PCAP_PHY_MAC_ARG "phy_mac"
36 : : #define ETH_PCAP_INFINITE_RX_ARG "infinite_rx"
37 : :
38 : : #define ETH_PCAP_ARG_MAXLEN 64
39 : :
40 : : #define RTE_PMD_PCAP_MAX_QUEUES 16
41 : :
42 : : static char errbuf[PCAP_ERRBUF_SIZE];
43 : : static struct timespec start_time;
44 : : static uint64_t start_cycles;
45 : : static uint64_t hz;
46 : : static uint8_t iface_idx;
47 : :
48 : : static uint64_t timestamp_rx_dynflag;
49 : : static int timestamp_dynfield_offset = -1;
50 : :
51 : : struct queue_stat {
52 : : volatile unsigned long pkts;
53 : : volatile unsigned long bytes;
54 : : volatile unsigned long err_pkts;
55 : : volatile unsigned long rx_nombuf;
56 : : };
57 : :
58 : : struct queue_missed_stat {
59 : : /* last value retrieved from pcap */
60 : : unsigned int pcap;
61 : : /* stores values lost by pcap stop or rollover */
62 : : unsigned long mnemonic;
63 : : /* value on last reset */
64 : : unsigned long reset;
65 : : };
66 : :
67 : : struct pcap_rx_queue {
68 : : uint16_t port_id;
69 : : uint16_t queue_id;
70 : : struct rte_mempool *mb_pool;
71 : : struct queue_stat rx_stat;
72 : : struct queue_missed_stat missed_stat;
73 : : char name[PATH_MAX];
74 : : char type[ETH_PCAP_ARG_MAXLEN];
75 : :
76 : : /* Contains pre-generated packets to be looped through */
77 : : struct rte_ring *pkts;
78 : : };
79 : :
80 : : struct pcap_tx_queue {
81 : : uint16_t port_id;
82 : : uint16_t queue_id;
83 : : struct queue_stat tx_stat;
84 : : char name[PATH_MAX];
85 : : char type[ETH_PCAP_ARG_MAXLEN];
86 : : };
87 : :
88 : : struct pmd_internals {
89 : : struct pcap_rx_queue rx_queue[RTE_PMD_PCAP_MAX_QUEUES];
90 : : struct pcap_tx_queue tx_queue[RTE_PMD_PCAP_MAX_QUEUES];
91 : : char devargs[ETH_PCAP_ARG_MAXLEN];
92 : : struct rte_ether_addr eth_addr;
93 : : int if_index;
94 : : int single_iface;
95 : : int phy_mac;
96 : : unsigned int infinite_rx;
97 : : };
98 : :
99 : : struct pmd_process_private {
100 : : pcap_t *rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
101 : : pcap_t *tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
102 : : pcap_dumper_t *tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
103 : : };
104 : :
105 : : struct pmd_devargs {
106 : : unsigned int num_of_queue;
107 : : struct devargs_queue {
108 : : pcap_dumper_t *dumper;
109 : : pcap_t *pcap;
110 : : const char *name;
111 : : const char *type;
112 : : } queue[RTE_PMD_PCAP_MAX_QUEUES];
113 : : int phy_mac;
114 : : };
115 : :
116 : : struct pmd_devargs_all {
117 : : struct pmd_devargs rx_queues;
118 : : struct pmd_devargs tx_queues;
119 : : int single_iface;
120 : : unsigned int is_tx_pcap;
121 : : unsigned int is_tx_iface;
122 : : unsigned int is_rx_pcap;
123 : : unsigned int is_rx_iface;
124 : : unsigned int infinite_rx;
125 : : };
126 : :
127 : : static const char *valid_arguments[] = {
128 : : ETH_PCAP_RX_PCAP_ARG,
129 : : ETH_PCAP_TX_PCAP_ARG,
130 : : ETH_PCAP_RX_IFACE_ARG,
131 : : ETH_PCAP_RX_IFACE_IN_ARG,
132 : : ETH_PCAP_TX_IFACE_ARG,
133 : : ETH_PCAP_IFACE_ARG,
134 : : ETH_PCAP_PHY_MAC_ARG,
135 : : ETH_PCAP_INFINITE_RX_ARG,
136 : : NULL
137 : : };
138 : :
139 : : static struct rte_eth_link pmd_link = {
140 : : .link_speed = RTE_ETH_SPEED_NUM_10G,
141 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
142 : : .link_status = RTE_ETH_LINK_DOWN,
143 : : .link_autoneg = RTE_ETH_LINK_FIXED,
144 : : };
145 : :
146 [ - + ]: 251 : RTE_LOG_REGISTER_DEFAULT(eth_pcap_logtype, NOTICE);
147 : :
148 : : static struct queue_missed_stat*
149 : 0 : queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
150 : : {
151 : 0 : struct pmd_internals *internals = dev->data->dev_private;
152 : 0 : struct queue_missed_stat *missed_stat =
153 : : &internals->rx_queue[qid].missed_stat;
154 : 0 : const struct pmd_process_private *pp = dev->process_private;
155 : 0 : pcap_t *pcap = pp->rx_pcap[qid];
156 : : struct pcap_stat stat;
157 : :
158 [ # # # # ]: 0 : if (!pcap || (pcap_stats(pcap, &stat) != 0))
159 : 0 : return missed_stat;
160 : :
161 : : /* rollover check - best effort fixup assuming single rollover */
162 [ # # ]: 0 : if (stat.ps_drop < missed_stat->pcap)
163 : 0 : missed_stat->mnemonic += UINT_MAX;
164 : 0 : missed_stat->pcap = stat.ps_drop;
165 : :
166 : 0 : return missed_stat;
167 : : }
168 : :
169 : : static void
170 : : queue_missed_stat_on_stop_update(struct rte_eth_dev *dev, unsigned int qid)
171 : : {
172 : : struct queue_missed_stat *missed_stat =
173 : 0 : queue_missed_stat_update(dev, qid);
174 : :
175 : 0 : missed_stat->mnemonic += missed_stat->pcap;
176 : 0 : missed_stat->pcap = 0;
177 : : }
178 : :
179 : : static void
180 : : queue_missed_stat_reset(struct rte_eth_dev *dev, unsigned int qid)
181 : : {
182 : : struct queue_missed_stat *missed_stat =
183 : 0 : queue_missed_stat_update(dev, qid);
184 : :
185 : 0 : missed_stat->reset = missed_stat->pcap;
186 : 0 : missed_stat->mnemonic = 0;
187 : : }
188 : :
189 : : static unsigned long
190 : : queue_missed_stat_get(struct rte_eth_dev *dev, unsigned int qid)
191 : : {
192 : : const struct queue_missed_stat *missed_stat =
193 : 0 : queue_missed_stat_update(dev, qid);
194 : :
195 : 0 : return missed_stat->pcap + missed_stat->mnemonic - missed_stat->reset;
196 : : }
197 : :
198 : : static int
199 : 0 : eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
200 : : const u_char *data, uint16_t data_len)
201 : : {
202 : : /* Copy the first segment. */
203 : : uint16_t len = rte_pktmbuf_tailroom(mbuf);
204 : : struct rte_mbuf *m = mbuf;
205 : :
206 : 0 : rte_memcpy(rte_pktmbuf_append(mbuf, len), data, len);
207 : 0 : data_len -= len;
208 : 0 : data += len;
209 : :
210 [ # # ]: 0 : while (data_len > 0) {
211 : : /* Allocate next mbuf and point to that. */
212 : 0 : m->next = rte_pktmbuf_alloc(mb_pool);
213 : :
214 [ # # ]: 0 : if (unlikely(!m->next))
215 : : return -1;
216 : :
217 : : m = m->next;
218 : :
219 : : /* Headroom is not needed in chained mbufs. */
220 : : rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
221 : 0 : m->pkt_len = 0;
222 : 0 : m->data_len = 0;
223 : :
224 : : /* Copy next segment. */
225 : 0 : len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len);
226 : 0 : rte_memcpy(rte_pktmbuf_append(m, len), data, len);
227 : :
228 : 0 : mbuf->nb_segs++;
229 : 0 : data_len -= len;
230 : 0 : data += len;
231 : : }
232 : :
233 : 0 : return mbuf->nb_segs;
234 : : }
235 : :
236 : : static uint16_t
237 : 0 : eth_pcap_rx_infinite(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
238 : : {
239 : : int i;
240 : : struct pcap_rx_queue *pcap_q = queue;
241 : : uint32_t rx_bytes = 0;
242 : :
243 [ # # ]: 0 : if (unlikely(nb_pkts == 0))
244 : : return 0;
245 : :
246 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(pcap_q->mb_pool, bufs, nb_pkts) != 0)
247 : : return 0;
248 : :
249 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
250 : : struct rte_mbuf *pcap_buf;
251 [ # # # # : 0 : int err = rte_ring_dequeue(pcap_q->pkts, (void **)&pcap_buf);
# ]
252 : : if (err)
253 : 0 : return i;
254 : :
255 : 0 : rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *),
256 : 0 : rte_pktmbuf_mtod(pcap_buf, void *),
257 [ # # ]: 0 : pcap_buf->data_len);
258 : 0 : bufs[i]->data_len = pcap_buf->data_len;
259 : 0 : bufs[i]->pkt_len = pcap_buf->pkt_len;
260 : 0 : bufs[i]->port = pcap_q->port_id;
261 : 0 : rx_bytes += pcap_buf->data_len;
262 : :
263 : : /* Enqueue packet back on ring to allow infinite rx. */
264 [ # # # # : 0 : rte_ring_enqueue(pcap_q->pkts, pcap_buf);
# ]
265 : : }
266 : :
267 : 0 : pcap_q->rx_stat.pkts += i;
268 : 0 : pcap_q->rx_stat.bytes += rx_bytes;
269 : :
270 : 0 : return i;
271 : : }
272 : :
273 : : static uint16_t
274 : 0 : eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
275 : : {
276 : : unsigned int i;
277 : : struct pcap_pkthdr *header;
278 : : struct pmd_process_private *pp;
279 : : const u_char *packet;
280 : : struct rte_mbuf *mbuf;
281 : : struct pcap_rx_queue *pcap_q = queue;
282 : : uint16_t num_rx = 0;
283 : : uint32_t rx_bytes = 0;
284 : : pcap_t *pcap;
285 : :
286 : 0 : pp = rte_eth_devices[pcap_q->port_id].process_private;
287 : 0 : pcap = pp->rx_pcap[pcap_q->queue_id];
288 : :
289 [ # # ]: 0 : if (unlikely(pcap == NULL || nb_pkts == 0))
290 : : return 0;
291 : :
292 : : /* Reads the given number of packets from the pcap file one by one
293 : : * and copies the packet data into a newly allocated mbuf to return.
294 : : */
295 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
296 : : /* Get the next PCAP packet */
297 : 0 : int ret = pcap_next_ex(pcap, &header, &packet);
298 [ # # ]: 0 : if (ret != 1) {
299 [ # # ]: 0 : if (ret == PCAP_ERROR)
300 : 0 : pcap_q->rx_stat.err_pkts++;
301 : :
302 : : break;
303 : : }
304 : :
305 : 0 : mbuf = rte_pktmbuf_alloc(pcap_q->mb_pool);
306 [ # # ]: 0 : if (unlikely(mbuf == NULL)) {
307 : 0 : pcap_q->rx_stat.rx_nombuf++;
308 : 0 : break;
309 : : }
310 : :
311 [ # # ]: 0 : uint32_t len = header->caplen;
312 [ # # ]: 0 : if (len <= rte_pktmbuf_tailroom(mbuf)) {
313 : : /* pcap packet will fit in the mbuf, can copy it */
314 [ # # ]: 0 : rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packet, len);
315 : 0 : mbuf->data_len = len;
316 : : } else {
317 : : /* Try read jumbo frame into multi mbufs. */
318 [ # # ]: 0 : if (unlikely(eth_pcap_rx_jumbo(pcap_q->mb_pool,
319 : : mbuf, packet, len) == -1)) {
320 : 0 : pcap_q->rx_stat.err_pkts++;
321 : 0 : rte_pktmbuf_free(mbuf);
322 : 0 : break;
323 : : }
324 : : }
325 : :
326 : 0 : mbuf->pkt_len = len;
327 : 0 : uint64_t us = (uint64_t)header->ts.tv_sec * US_PER_S + header->ts.tv_usec;
328 : :
329 : 0 : *RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset, rte_mbuf_timestamp_t *) = us;
330 : 0 : mbuf->ol_flags |= timestamp_rx_dynflag;
331 : 0 : mbuf->port = pcap_q->port_id;
332 : 0 : bufs[num_rx] = mbuf;
333 : 0 : num_rx++;
334 : 0 : rx_bytes += len;
335 : : }
336 : 0 : pcap_q->rx_stat.pkts += num_rx;
337 : 0 : pcap_q->rx_stat.bytes += rx_bytes;
338 : :
339 : 0 : return num_rx;
340 : : }
341 : :
342 : : static uint16_t
343 : 0 : eth_null_rx(void *queue __rte_unused,
344 : : struct rte_mbuf **bufs __rte_unused,
345 : : uint16_t nb_pkts __rte_unused)
346 : : {
347 : 0 : return 0;
348 : : }
349 : :
350 : : #define NSEC_PER_SEC 1000000000L
351 : :
352 : : /*
353 : : * This function stores nanoseconds in `tv_usec` field of `struct timeval`,
354 : : * because `ts` goes directly to nanosecond-precision dump.
355 : : */
356 : : static inline void
357 : 0 : calculate_timestamp(struct timeval *ts) {
358 : : uint64_t cycles;
359 : : struct timespec cur_time;
360 : :
361 : 0 : cycles = rte_get_timer_cycles() - start_cycles;
362 : 0 : cur_time.tv_sec = cycles / hz;
363 : 0 : cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
364 : :
365 : 0 : ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
366 : 0 : ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
367 [ # # ]: 0 : if (ts->tv_usec >= NSEC_PER_SEC) {
368 : 0 : ts->tv_usec -= NSEC_PER_SEC;
369 : 0 : ts->tv_sec += 1;
370 : : }
371 : 0 : }
372 : :
373 : : /*
374 : : * Callback to handle writing packets to a pcap file.
375 : : */
376 : : static uint16_t
377 : 0 : eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
378 : : {
379 : : unsigned int i;
380 : : struct rte_mbuf *mbuf;
381 : : struct pmd_process_private *pp;
382 : : struct pcap_tx_queue *dumper_q = queue;
383 : : uint16_t num_tx = 0;
384 : : uint32_t tx_bytes = 0;
385 : : struct pcap_pkthdr header;
386 : : pcap_dumper_t *dumper;
387 : : unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
388 : : size_t len, caplen;
389 : :
390 : 0 : pp = rte_eth_devices[dumper_q->port_id].process_private;
391 : 0 : dumper = pp->tx_dumper[dumper_q->queue_id];
392 : :
393 [ # # ]: 0 : if (dumper == NULL || nb_pkts == 0)
394 : : return 0;
395 : :
396 : : /* writes the nb_pkts packets to the previously opened pcap file
397 : : * dumper */
398 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
399 : 0 : mbuf = bufs[i];
400 [ # # ]: 0 : len = caplen = rte_pktmbuf_pkt_len(mbuf);
401 [ # # # # ]: 0 : if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) &&
402 : : len > sizeof(temp_data))) {
403 : : caplen = sizeof(temp_data);
404 : : }
405 : :
406 : 0 : calculate_timestamp(&header.ts);
407 : 0 : header.len = len;
408 [ # # ]: 0 : header.caplen = caplen;
409 : : /* rte_pktmbuf_read() returns a pointer to the data directly
410 : : * in the mbuf (when the mbuf is contiguous) or, otherwise,
411 : : * a pointer to temp_data after copying into it.
412 : : */
413 : 0 : pcap_dump((u_char *)dumper, &header,
414 : : rte_pktmbuf_read(mbuf, 0, caplen, temp_data));
415 : :
416 : 0 : num_tx++;
417 : 0 : tx_bytes += caplen;
418 : 0 : rte_pktmbuf_free(mbuf);
419 : : }
420 : :
421 : : /*
422 : : * Since there's no place to hook a callback when the forwarding
423 : : * process stops and to make sure the pcap file is actually written,
424 : : * we flush the pcap dumper within each burst.
425 : : */
426 : 0 : pcap_dump_flush(dumper);
427 : 0 : dumper_q->tx_stat.pkts += num_tx;
428 : 0 : dumper_q->tx_stat.bytes += tx_bytes;
429 : 0 : dumper_q->tx_stat.err_pkts += nb_pkts - num_tx;
430 : :
431 : 0 : return nb_pkts;
432 : : }
433 : :
434 : : /*
435 : : * Callback to handle dropping packets in the infinite rx case.
436 : : */
437 : : static uint16_t
438 : 0 : eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
439 : : {
440 : : unsigned int i;
441 : : uint32_t tx_bytes = 0;
442 : : struct pcap_tx_queue *tx_queue = queue;
443 : :
444 [ # # ]: 0 : if (unlikely(nb_pkts == 0))
445 : : return 0;
446 : :
447 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
448 : 0 : tx_bytes += bufs[i]->pkt_len;
449 : 0 : rte_pktmbuf_free(bufs[i]);
450 : : }
451 : :
452 : 0 : tx_queue->tx_stat.pkts += nb_pkts;
453 : 0 : tx_queue->tx_stat.bytes += tx_bytes;
454 : :
455 : 0 : return i;
456 : : }
457 : :
458 : : /*
459 : : * Callback to handle sending packets through a real NIC.
460 : : */
461 : : static uint16_t
462 : 0 : eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
463 : : {
464 : : unsigned int i;
465 : : int ret;
466 : : struct rte_mbuf *mbuf;
467 : : struct pmd_process_private *pp;
468 : : struct pcap_tx_queue *tx_queue = queue;
469 : : uint16_t num_tx = 0;
470 : : uint32_t tx_bytes = 0;
471 : : pcap_t *pcap;
472 : : unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN];
473 : : size_t len;
474 : :
475 : 0 : pp = rte_eth_devices[tx_queue->port_id].process_private;
476 : 0 : pcap = pp->tx_pcap[tx_queue->queue_id];
477 : :
478 [ # # ]: 0 : if (unlikely(nb_pkts == 0 || pcap == NULL))
479 : : return 0;
480 : :
481 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
482 : 0 : mbuf = bufs[i];
483 [ # # ]: 0 : len = rte_pktmbuf_pkt_len(mbuf);
484 [ # # # # ]: 0 : if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) &&
485 : : len > sizeof(temp_data))) {
486 : 0 : PMD_LOG(ERR,
487 : : "Dropping multi segment PCAP packet. Size (%zd) > max size (%zd).",
488 : : len, sizeof(temp_data));
489 : 0 : rte_pktmbuf_free(mbuf);
490 : 0 : continue;
491 : : }
492 : :
493 : : /* rte_pktmbuf_read() returns a pointer to the data directly
494 : : * in the mbuf (when the mbuf is contiguous) or, otherwise,
495 : : * a pointer to temp_data after copying into it.
496 : : */
497 [ # # ]: 0 : ret = pcap_sendpacket(pcap,
498 : : rte_pktmbuf_read(mbuf, 0, len, temp_data), len);
499 [ # # ]: 0 : if (unlikely(ret != 0))
500 : : break;
501 : 0 : num_tx++;
502 : 0 : tx_bytes += len;
503 : 0 : rte_pktmbuf_free(mbuf);
504 : : }
505 : :
506 : 0 : tx_queue->tx_stat.pkts += num_tx;
507 : 0 : tx_queue->tx_stat.bytes += tx_bytes;
508 : 0 : tx_queue->tx_stat.err_pkts += i - num_tx;
509 : :
510 : 0 : return i;
511 : : }
512 : :
513 : : /*
514 : : * pcap_open_live wrapper function
515 : : */
516 : : static inline int
517 : 0 : open_iface_live(const char *iface, pcap_t **pcap) {
518 : 0 : *pcap = pcap_open_live(iface, RTE_ETH_PCAP_SNAPLEN,
519 : : RTE_ETH_PCAP_PROMISC, RTE_ETH_PCAP_TIMEOUT, errbuf);
520 : :
521 [ # # ]: 0 : if (*pcap == NULL) {
522 : 0 : PMD_LOG(ERR, "Couldn't open %s: %s", iface, errbuf);
523 : 0 : return -1;
524 : : }
525 : :
526 [ # # ]: 0 : if (pcap_setnonblock(*pcap, 1, errbuf)) {
527 : 0 : PMD_LOG(ERR, "Couldn't set non-blocking on %s: %s", iface, errbuf);
528 : 0 : pcap_close(*pcap);
529 : 0 : return -1;
530 : : }
531 : :
532 : : return 0;
533 : : }
534 : :
535 : : static int
536 : 0 : open_single_iface(const char *iface, pcap_t **pcap)
537 : : {
538 [ # # ]: 0 : if (open_iface_live(iface, pcap) < 0) {
539 : 0 : PMD_LOG(ERR, "Couldn't open interface %s", iface);
540 : 0 : return -1;
541 : : }
542 : :
543 : : return 0;
544 : : }
545 : :
546 : : static int
547 : 0 : open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper)
548 : : {
549 : : pcap_t *tx_pcap;
550 : :
551 : : /*
552 : : * We need to create a dummy empty pcap_t to use it
553 : : * with pcap_dump_open(). We create big enough an Ethernet
554 : : * pcap holder.
555 : : */
556 : 0 : tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
557 : : RTE_ETH_PCAP_SNAPSHOT_LEN, PCAP_TSTAMP_PRECISION_NANO);
558 [ # # ]: 0 : if (tx_pcap == NULL) {
559 : 0 : PMD_LOG(ERR, "Couldn't create dead pcap");
560 : 0 : return -1;
561 : : }
562 : :
563 : : /* The dumper is created using the previous pcap_t reference */
564 : 0 : *dumper = pcap_dump_open(tx_pcap, pcap_filename);
565 [ # # ]: 0 : if (*dumper == NULL) {
566 : 0 : pcap_close(tx_pcap);
567 : 0 : PMD_LOG(ERR, "Couldn't open %s for writing.",
568 : : pcap_filename);
569 : 0 : return -1;
570 : : }
571 : :
572 : 0 : pcap_close(tx_pcap);
573 : 0 : return 0;
574 : : }
575 : :
576 : : static int
577 : 0 : open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
578 : : {
579 : 0 : *pcap = pcap_open_offline(pcap_filename, errbuf);
580 [ # # ]: 0 : if (*pcap == NULL) {
581 : 0 : PMD_LOG(ERR, "Couldn't open %s: %s", pcap_filename,
582 : : errbuf);
583 : 0 : return -1;
584 : : }
585 : :
586 : : return 0;
587 : : }
588 : :
589 : : static uint64_t
590 : 0 : count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue *pcap_q)
591 : : {
592 : : const u_char *packet;
593 : : struct pcap_pkthdr header;
594 : : uint64_t pcap_pkt_count = 0;
595 : :
596 [ # # ]: 0 : while ((packet = pcap_next(*pcap, &header)))
597 : 0 : pcap_pkt_count++;
598 : :
599 : : /* The pcap is reopened so it can be used as normal later. */
600 : 0 : pcap_close(*pcap);
601 : 0 : *pcap = NULL;
602 : 0 : open_single_rx_pcap(pcap_q->name, pcap);
603 : :
604 : 0 : return pcap_pkt_count;
605 : : }
606 : :
607 : : static int
608 : 0 : eth_dev_start(struct rte_eth_dev *dev)
609 : : {
610 : : unsigned int i;
611 : 0 : struct pmd_internals *internals = dev->data->dev_private;
612 : 0 : struct pmd_process_private *pp = dev->process_private;
613 : : struct pcap_tx_queue *tx;
614 : : struct pcap_rx_queue *rx;
615 : :
616 : : /* Special iface case. Single pcap is open and shared between tx/rx. */
617 [ # # ]: 0 : if (internals->single_iface) {
618 : : tx = &internals->tx_queue[0];
619 : : rx = &internals->rx_queue[0];
620 : :
621 [ # # ]: 0 : if (!pp->tx_pcap[0] &&
622 [ # # ]: 0 : strcmp(tx->type, ETH_PCAP_IFACE_ARG) == 0) {
623 [ # # ]: 0 : if (open_single_iface(tx->name, &pp->tx_pcap[0]) < 0)
624 : : return -1;
625 : 0 : pp->rx_pcap[0] = pp->tx_pcap[0];
626 : : }
627 : :
628 : 0 : goto status_up;
629 : : }
630 : :
631 : : /* If not open already, open tx pcaps/dumpers */
632 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
633 : : tx = &internals->tx_queue[i];
634 : :
635 [ # # ]: 0 : if (!pp->tx_dumper[i] &&
636 [ # # ]: 0 : strcmp(tx->type, ETH_PCAP_TX_PCAP_ARG) == 0) {
637 [ # # ]: 0 : if (open_single_tx_pcap(tx->name,
638 : : &pp->tx_dumper[i]) < 0)
639 : : return -1;
640 [ # # ]: 0 : } else if (!pp->tx_pcap[i] &&
641 [ # # ]: 0 : strcmp(tx->type, ETH_PCAP_TX_IFACE_ARG) == 0) {
642 [ # # ]: 0 : if (open_single_iface(tx->name, &pp->tx_pcap[i]) < 0)
643 : : return -1;
644 : : }
645 : : }
646 : :
647 : : /* If not open already, open rx pcaps */
648 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
649 : : rx = &internals->rx_queue[i];
650 : :
651 [ # # ]: 0 : if (pp->rx_pcap[i] != NULL)
652 : 0 : continue;
653 : :
654 [ # # ]: 0 : if (strcmp(rx->type, ETH_PCAP_RX_PCAP_ARG) == 0) {
655 [ # # ]: 0 : if (open_single_rx_pcap(rx->name, &pp->rx_pcap[i]) < 0)
656 : : return -1;
657 [ # # ]: 0 : } else if (strcmp(rx->type, ETH_PCAP_RX_IFACE_ARG) == 0) {
658 [ # # ]: 0 : if (open_single_iface(rx->name, &pp->rx_pcap[i]) < 0)
659 : : return -1;
660 : : }
661 : : }
662 : :
663 : 0 : status_up:
664 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
665 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
666 : :
667 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
668 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
669 : :
670 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
671 : :
672 : 0 : return 0;
673 : : }
674 : :
675 : : /*
676 : : * This function gets called when the current port gets stopped.
677 : : * Is the only place for us to close all the tx streams dumpers.
678 : : * If not called the dumpers will be flushed within each tx burst.
679 : : */
680 : : static int
681 : 0 : eth_dev_stop(struct rte_eth_dev *dev)
682 : : {
683 : : unsigned int i;
684 : 0 : struct pmd_internals *internals = dev->data->dev_private;
685 : 0 : struct pmd_process_private *pp = dev->process_private;
686 : :
687 : : /* Special iface case. Single pcap is open and shared between tx/rx. */
688 [ # # ]: 0 : if (internals->single_iface) {
689 : : queue_missed_stat_on_stop_update(dev, 0);
690 [ # # ]: 0 : if (pp->tx_pcap[0] != NULL) {
691 : 0 : pcap_close(pp->tx_pcap[0]);
692 : 0 : pp->tx_pcap[0] = NULL;
693 : 0 : pp->rx_pcap[0] = NULL;
694 : : }
695 : 0 : goto status_down;
696 : : }
697 : :
698 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
699 [ # # ]: 0 : if (pp->tx_dumper[i] != NULL) {
700 : 0 : pcap_dump_close(pp->tx_dumper[i]);
701 : 0 : pp->tx_dumper[i] = NULL;
702 : : }
703 : :
704 [ # # ]: 0 : if (pp->tx_pcap[i] != NULL) {
705 : 0 : pcap_close(pp->tx_pcap[i]);
706 : 0 : pp->tx_pcap[i] = NULL;
707 : : }
708 : : }
709 : :
710 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
711 [ # # ]: 0 : if (pp->rx_pcap[i] != NULL) {
712 : : queue_missed_stat_on_stop_update(dev, i);
713 : 0 : pcap_close(pp->rx_pcap[i]);
714 : 0 : pp->rx_pcap[i] = NULL;
715 : : }
716 : : }
717 : :
718 : 0 : status_down:
719 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
720 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
721 : :
722 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++)
723 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
724 : :
725 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
726 : :
727 : 0 : return 0;
728 : : }
729 : :
730 : : static int
731 : 0 : eth_dev_configure(struct rte_eth_dev *dev __rte_unused)
732 : : {
733 : 0 : return 0;
734 : : }
735 : :
736 : : static int
737 : 0 : eth_dev_info(struct rte_eth_dev *dev,
738 : : struct rte_eth_dev_info *dev_info)
739 : : {
740 : 0 : struct pmd_internals *internals = dev->data->dev_private;
741 : :
742 : 0 : dev_info->if_index = internals->if_index;
743 : 0 : dev_info->max_mac_addrs = 1;
744 : 0 : dev_info->max_rx_pktlen = (uint32_t) -1;
745 : 0 : dev_info->max_rx_queues = dev->data->nb_rx_queues;
746 : 0 : dev_info->max_tx_queues = dev->data->nb_tx_queues;
747 : 0 : dev_info->min_rx_bufsize = 0;
748 : :
749 : 0 : return 0;
750 : : }
751 : :
752 : : static int
753 : 0 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
754 : : {
755 : : unsigned int i;
756 : : unsigned long rx_packets_total = 0, rx_bytes_total = 0;
757 : : unsigned long rx_missed_total = 0;
758 : : unsigned long rx_nombuf_total = 0, rx_err_total = 0;
759 : : unsigned long tx_packets_total = 0, tx_bytes_total = 0;
760 : : unsigned long tx_packets_err_total = 0;
761 : 0 : const struct pmd_internals *internal = dev->data->dev_private;
762 : :
763 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
764 [ # # ]: 0 : i < dev->data->nb_rx_queues; i++) {
765 : 0 : stats->q_ipackets[i] = internal->rx_queue[i].rx_stat.pkts;
766 : 0 : stats->q_ibytes[i] = internal->rx_queue[i].rx_stat.bytes;
767 : 0 : rx_nombuf_total += internal->rx_queue[i].rx_stat.rx_nombuf;
768 : 0 : rx_err_total += internal->rx_queue[i].rx_stat.err_pkts;
769 : 0 : rx_packets_total += stats->q_ipackets[i];
770 : 0 : rx_bytes_total += stats->q_ibytes[i];
771 : 0 : rx_missed_total += queue_missed_stat_get(dev, i);
772 : : }
773 : :
774 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
775 [ # # ]: 0 : i < dev->data->nb_tx_queues; i++) {
776 : 0 : stats->q_opackets[i] = internal->tx_queue[i].tx_stat.pkts;
777 : 0 : stats->q_obytes[i] = internal->tx_queue[i].tx_stat.bytes;
778 : 0 : tx_packets_total += stats->q_opackets[i];
779 : 0 : tx_bytes_total += stats->q_obytes[i];
780 : 0 : tx_packets_err_total += internal->tx_queue[i].tx_stat.err_pkts;
781 : : }
782 : :
783 : 0 : stats->ipackets = rx_packets_total;
784 : 0 : stats->ibytes = rx_bytes_total;
785 : 0 : stats->imissed = rx_missed_total;
786 : 0 : stats->ierrors = rx_err_total;
787 : 0 : stats->rx_nombuf = rx_nombuf_total;
788 : 0 : stats->opackets = tx_packets_total;
789 : 0 : stats->obytes = tx_bytes_total;
790 : 0 : stats->oerrors = tx_packets_err_total;
791 : :
792 : 0 : return 0;
793 : : }
794 : :
795 : : static int
796 : 0 : eth_stats_reset(struct rte_eth_dev *dev)
797 : : {
798 : : unsigned int i;
799 : 0 : struct pmd_internals *internal = dev->data->dev_private;
800 : :
801 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
802 : 0 : internal->rx_queue[i].rx_stat.pkts = 0;
803 : 0 : internal->rx_queue[i].rx_stat.bytes = 0;
804 : 0 : internal->rx_queue[i].rx_stat.err_pkts = 0;
805 : 0 : internal->rx_queue[i].rx_stat.rx_nombuf = 0;
806 : : queue_missed_stat_reset(dev, i);
807 : : }
808 : :
809 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
810 : 0 : internal->tx_queue[i].tx_stat.pkts = 0;
811 : 0 : internal->tx_queue[i].tx_stat.bytes = 0;
812 : 0 : internal->tx_queue[i].tx_stat.err_pkts = 0;
813 : : }
814 : :
815 : 0 : return 0;
816 : : }
817 : :
818 : : static inline void
819 : 0 : infinite_rx_ring_free(struct rte_ring *pkts)
820 : : {
821 : : struct rte_mbuf *bufs;
822 : :
823 : 0 : while (!rte_ring_dequeue(pkts, (void **)&bufs))
824 : 0 : rte_pktmbuf_free(bufs);
825 : :
826 : 0 : rte_ring_free(pkts);
827 : 0 : }
828 : :
829 : : static int
830 : 0 : eth_dev_close(struct rte_eth_dev *dev)
831 : : {
832 : : unsigned int i;
833 : 0 : struct pmd_internals *internals = dev->data->dev_private;
834 : :
835 : 0 : PMD_LOG(INFO, "Closing pcap ethdev on NUMA socket %d",
836 : : rte_socket_id());
837 : :
838 : 0 : eth_dev_stop(dev);
839 : :
840 : 0 : rte_free(dev->process_private);
841 : :
842 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
843 : : return 0;
844 : :
845 : : /* Device wide flag, but cleanup must be performed per queue. */
846 [ # # ]: 0 : if (internals->infinite_rx) {
847 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
848 : : struct pcap_rx_queue *pcap_q = &internals->rx_queue[i];
849 : :
850 : : /*
851 : : * 'pcap_q->pkts' can be NULL if 'eth_dev_close()'
852 : : * called before 'eth_rx_queue_setup()' has been called
853 : : */
854 [ # # ]: 0 : if (pcap_q->pkts == NULL)
855 : 0 : continue;
856 : :
857 : 0 : infinite_rx_ring_free(pcap_q->pkts);
858 : : }
859 : : }
860 : :
861 [ # # ]: 0 : if (internals->phy_mac == 0)
862 : : /* not dynamically allocated, must not be freed */
863 : 0 : dev->data->mac_addrs = NULL;
864 : :
865 : : return 0;
866 : : }
867 : :
868 : : static int
869 : 0 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
870 : : int wait_to_complete __rte_unused)
871 : : {
872 : 0 : return 0;
873 : : }
874 : :
875 : : static int
876 : 0 : eth_rx_queue_setup(struct rte_eth_dev *dev,
877 : : uint16_t rx_queue_id,
878 : : uint16_t nb_rx_desc __rte_unused,
879 : : unsigned int socket_id __rte_unused,
880 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
881 : : struct rte_mempool *mb_pool)
882 : : {
883 : 0 : struct pmd_internals *internals = dev->data->dev_private;
884 : 0 : struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
885 : :
886 : 0 : pcap_q->mb_pool = mb_pool;
887 : 0 : pcap_q->port_id = dev->data->port_id;
888 : 0 : pcap_q->queue_id = rx_queue_id;
889 : 0 : dev->data->rx_queues[rx_queue_id] = pcap_q;
890 : :
891 [ # # ]: 0 : if (internals->infinite_rx) {
892 : : struct pmd_process_private *pp;
893 : : char ring_name[RTE_RING_NAMESIZE];
894 : : static uint32_t ring_number;
895 : : uint64_t pcap_pkt_count = 0;
896 : : struct rte_mbuf *bufs[1];
897 : : pcap_t **pcap;
898 : :
899 : 0 : pp = rte_eth_devices[pcap_q->port_id].process_private;
900 : 0 : pcap = &pp->rx_pcap[pcap_q->queue_id];
901 : :
902 [ # # ]: 0 : if (unlikely(*pcap == NULL))
903 : 0 : return -ENOENT;
904 : :
905 : 0 : pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
906 : :
907 : 0 : snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
908 : : ring_number);
909 : :
910 : 0 : pcap_q->pkts = rte_ring_create(ring_name,
911 : : rte_align64pow2(pcap_pkt_count + 1), 0,
912 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
913 : 0 : ring_number++;
914 [ # # ]: 0 : if (!pcap_q->pkts)
915 : : return -ENOENT;
916 : :
917 : : /* Fill ring with packets from PCAP file one by one. */
918 [ # # ]: 0 : while (eth_pcap_rx(pcap_q, bufs, 1)) {
919 : : /* Check for multiseg mbufs. */
920 [ # # ]: 0 : if (bufs[0]->nb_segs != 1) {
921 : 0 : infinite_rx_ring_free(pcap_q->pkts);
922 : 0 : PMD_LOG(ERR,
923 : : "Multiseg mbufs are not supported in infinite_rx mode.");
924 : 0 : return -EINVAL;
925 : : }
926 : :
927 [ # # # # : 0 : rte_ring_enqueue_bulk(pcap_q->pkts,
# ]
928 : : (void * const *)bufs, 1, NULL);
929 : : }
930 : :
931 [ # # ]: 0 : if (rte_ring_count(pcap_q->pkts) < pcap_pkt_count) {
932 : 0 : infinite_rx_ring_free(pcap_q->pkts);
933 : 0 : PMD_LOG(ERR,
934 : : "Not enough mbufs to accommodate packets in pcap file. "
935 : : "At least %" PRIu64 " mbufs per queue is required.",
936 : : pcap_pkt_count);
937 : 0 : return -EINVAL;
938 : : }
939 : :
940 : : /*
941 : : * Reset the stats for this queue since eth_pcap_rx calls above
942 : : * didn't result in the application receiving packets.
943 : : */
944 : 0 : pcap_q->rx_stat.pkts = 0;
945 : 0 : pcap_q->rx_stat.bytes = 0;
946 : : }
947 : :
948 : : return 0;
949 : : }
950 : :
951 : : static int
952 : 0 : eth_tx_queue_setup(struct rte_eth_dev *dev,
953 : : uint16_t tx_queue_id,
954 : : uint16_t nb_tx_desc __rte_unused,
955 : : unsigned int socket_id __rte_unused,
956 : : const struct rte_eth_txconf *tx_conf __rte_unused)
957 : : {
958 : 0 : struct pmd_internals *internals = dev->data->dev_private;
959 : 0 : struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
960 : :
961 : 0 : pcap_q->port_id = dev->data->port_id;
962 : 0 : pcap_q->queue_id = tx_queue_id;
963 : 0 : dev->data->tx_queues[tx_queue_id] = pcap_q;
964 : :
965 : 0 : return 0;
966 : : }
967 : :
968 : : static int
969 : 0 : eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
970 : : {
971 : 0 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
972 : :
973 : 0 : return 0;
974 : : }
975 : :
976 : : static int
977 : 0 : eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
978 : : {
979 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
980 : :
981 : 0 : return 0;
982 : : }
983 : :
984 : : static int
985 : 0 : eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
986 : : {
987 : 0 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
988 : :
989 : 0 : return 0;
990 : : }
991 : :
992 : : static int
993 : 0 : eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
994 : : {
995 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
996 : :
997 : 0 : return 0;
998 : : }
999 : :
1000 : : static const struct eth_dev_ops ops = {
1001 : : .dev_start = eth_dev_start,
1002 : : .dev_stop = eth_dev_stop,
1003 : : .dev_close = eth_dev_close,
1004 : : .dev_configure = eth_dev_configure,
1005 : : .dev_infos_get = eth_dev_info,
1006 : : .rx_queue_setup = eth_rx_queue_setup,
1007 : : .tx_queue_setup = eth_tx_queue_setup,
1008 : : .rx_queue_start = eth_rx_queue_start,
1009 : : .tx_queue_start = eth_tx_queue_start,
1010 : : .rx_queue_stop = eth_rx_queue_stop,
1011 : : .tx_queue_stop = eth_tx_queue_stop,
1012 : : .link_update = eth_link_update,
1013 : : .stats_get = eth_stats_get,
1014 : : .stats_reset = eth_stats_reset,
1015 : : };
1016 : :
1017 : : static int
1018 : : add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
1019 : : pcap_t *pcap, pcap_dumper_t *dumper)
1020 : : {
1021 [ # # # # ]: 0 : if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
1022 : : return -1;
1023 [ # # # # ]: 0 : if (pcap)
1024 : 0 : pmd->queue[pmd->num_of_queue].pcap = pcap;
1025 [ # # ]: 0 : if (dumper)
1026 : 0 : pmd->queue[pmd->num_of_queue].dumper = dumper;
1027 : 0 : pmd->queue[pmd->num_of_queue].name = name;
1028 : 0 : pmd->queue[pmd->num_of_queue].type = type;
1029 : 0 : pmd->num_of_queue++;
1030 : 0 : return 0;
1031 : : }
1032 : :
1033 : : /*
1034 : : * Function handler that opens the pcap file for reading a stores a
1035 : : * reference of it for use it later on.
1036 : : */
1037 : : static int
1038 : 0 : open_rx_pcap(const char *key, const char *value, void *extra_args)
1039 : : {
1040 : : const char *pcap_filename = value;
1041 : : struct pmd_devargs *rx = extra_args;
1042 : 0 : pcap_t *pcap = NULL;
1043 : :
1044 [ # # ]: 0 : if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
1045 : : return -1;
1046 : :
1047 [ # # ]: 0 : if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
1048 : 0 : pcap_close(pcap);
1049 : 0 : return -1;
1050 : : }
1051 : :
1052 : : return 0;
1053 : : }
1054 : :
1055 : : /*
1056 : : * Opens a pcap file for writing and stores a reference to it
1057 : : * for use it later on.
1058 : : */
1059 : : static int
1060 : 0 : open_tx_pcap(const char *key, const char *value, void *extra_args)
1061 : : {
1062 : : const char *pcap_filename = value;
1063 : : struct pmd_devargs *dumpers = extra_args;
1064 : : pcap_dumper_t *dumper;
1065 : :
1066 [ # # ]: 0 : if (open_single_tx_pcap(pcap_filename, &dumper) < 0)
1067 : : return -1;
1068 : :
1069 [ # # ]: 0 : if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
1070 : 0 : pcap_dump_close(dumper);
1071 : 0 : return -1;
1072 : : }
1073 : :
1074 : : return 0;
1075 : : }
1076 : :
1077 : : /*
1078 : : * Opens an interface for reading and writing
1079 : : */
1080 : : static inline int
1081 : 0 : open_rx_tx_iface(const char *key, const char *value, void *extra_args)
1082 : : {
1083 : : const char *iface = value;
1084 : : struct pmd_devargs *tx = extra_args;
1085 : 0 : pcap_t *pcap = NULL;
1086 : :
1087 [ # # ]: 0 : if (open_single_iface(iface, &pcap) < 0)
1088 : : return -1;
1089 : :
1090 : 0 : tx->queue[0].pcap = pcap;
1091 : 0 : tx->queue[0].name = iface;
1092 : 0 : tx->queue[0].type = key;
1093 : :
1094 : 0 : return 0;
1095 : : }
1096 : :
1097 : : static inline int
1098 : 0 : set_iface_direction(const char *iface, pcap_t *pcap,
1099 : : pcap_direction_t direction)
1100 : : {
1101 [ # # ]: 0 : const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
1102 [ # # ]: 0 : if (pcap_setdirection(pcap, direction) < 0) {
1103 : 0 : PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s",
1104 : : iface, direction_str, pcap_geterr(pcap));
1105 : 0 : return -1;
1106 : : }
1107 : 0 : PMD_LOG(INFO, "Setting %s pcap direction %s",
1108 : : iface, direction_str);
1109 : 0 : return 0;
1110 : : }
1111 : :
1112 : : static inline int
1113 : 0 : open_iface(const char *key, const char *value, void *extra_args)
1114 : : {
1115 : : const char *iface = value;
1116 : : struct pmd_devargs *pmd = extra_args;
1117 : 0 : pcap_t *pcap = NULL;
1118 : :
1119 [ # # ]: 0 : if (open_single_iface(iface, &pcap) < 0)
1120 : : return -1;
1121 [ # # ]: 0 : if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
1122 : 0 : pcap_close(pcap);
1123 : 0 : return -1;
1124 : : }
1125 : :
1126 : : return 0;
1127 : : }
1128 : :
1129 : : /*
1130 : : * Opens a NIC for reading packets from it
1131 : : */
1132 : : static inline int
1133 : 0 : open_rx_iface(const char *key, const char *value, void *extra_args)
1134 : : {
1135 : 0 : int ret = open_iface(key, value, extra_args);
1136 [ # # ]: 0 : if (ret < 0)
1137 : : return ret;
1138 [ # # ]: 0 : if (strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
1139 : : struct pmd_devargs *pmd = extra_args;
1140 : 0 : unsigned int qid = pmd->num_of_queue - 1;
1141 : :
1142 : 0 : set_iface_direction(pmd->queue[qid].name,
1143 : : pmd->queue[qid].pcap,
1144 : : PCAP_D_IN);
1145 : : }
1146 : :
1147 : : return 0;
1148 : : }
1149 : :
1150 : : static inline int
1151 : 0 : rx_iface_args_process(const char *key, const char *value, void *extra_args)
1152 : : {
1153 [ # # ]: 0 : if (strcmp(key, ETH_PCAP_RX_IFACE_ARG) == 0 ||
1154 [ # # ]: 0 : strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
1155 : 0 : return open_rx_iface(key, value, extra_args);
1156 : :
1157 : : return 0;
1158 : : }
1159 : :
1160 : : /*
1161 : : * Opens a NIC for writing packets to it
1162 : : */
1163 : : static int
1164 : 0 : open_tx_iface(const char *key, const char *value, void *extra_args)
1165 : : {
1166 : 0 : return open_iface(key, value, extra_args);
1167 : : }
1168 : :
1169 : : static int
1170 : 0 : select_phy_mac(const char *key __rte_unused, const char *value,
1171 : : void *extra_args)
1172 : : {
1173 [ # # ]: 0 : if (extra_args) {
1174 : : const int phy_mac = atoi(value);
1175 : : int *enable_phy_mac = extra_args;
1176 : :
1177 [ # # ]: 0 : if (phy_mac)
1178 : 0 : *enable_phy_mac = 1;
1179 : : }
1180 : 0 : return 0;
1181 : : }
1182 : :
1183 : : static int
1184 : 0 : get_infinite_rx_arg(const char *key __rte_unused,
1185 : : const char *value, void *extra_args)
1186 : : {
1187 [ # # ]: 0 : if (extra_args) {
1188 : : const int infinite_rx = atoi(value);
1189 : : int *enable_infinite_rx = extra_args;
1190 : :
1191 [ # # ]: 0 : if (infinite_rx > 0)
1192 : 0 : *enable_infinite_rx = 1;
1193 : : }
1194 : 0 : return 0;
1195 : : }
1196 : :
1197 : : static int
1198 : 0 : pmd_init_internals(struct rte_vdev_device *vdev,
1199 : : const unsigned int nb_rx_queues,
1200 : : const unsigned int nb_tx_queues,
1201 : : struct pmd_internals **internals,
1202 : : struct rte_eth_dev **eth_dev)
1203 : : {
1204 : : struct rte_eth_dev_data *data;
1205 : : struct pmd_process_private *pp;
1206 : 0 : unsigned int numa_node = vdev->device.numa_node;
1207 : :
1208 : 0 : PMD_LOG(INFO, "Creating pcap-backed ethdev on numa socket %d",
1209 : : numa_node);
1210 : :
1211 : : pp = (struct pmd_process_private *)
1212 : 0 : rte_zmalloc(NULL, sizeof(struct pmd_process_private),
1213 : : RTE_CACHE_LINE_SIZE);
1214 : :
1215 [ # # ]: 0 : if (pp == NULL) {
1216 : 0 : PMD_LOG(ERR,
1217 : : "Failed to allocate memory for process private");
1218 : 0 : return -1;
1219 : : }
1220 : :
1221 : : /* reserve an ethdev entry */
1222 : 0 : *eth_dev = rte_eth_vdev_allocate(vdev, sizeof(**internals));
1223 [ # # ]: 0 : if (!(*eth_dev)) {
1224 : 0 : rte_free(pp);
1225 : 0 : return -1;
1226 : : }
1227 : 0 : (*eth_dev)->process_private = pp;
1228 : : /* now put it all together
1229 : : * - store queue data in internals,
1230 : : * - store numa_node info in eth_dev
1231 : : * - point eth_dev_data to internals
1232 : : * - and point eth_dev structure to new eth_dev_data structure
1233 : : */
1234 : 0 : *internals = (*eth_dev)->data->dev_private;
1235 : : /*
1236 : : * Interface MAC = 02:70:63:61:70:<iface_idx>
1237 : : * derived from: 'locally administered':'p':'c':'a':'p':'iface_idx'
1238 : : * where the middle 4 characters are converted to hex.
1239 : : */
1240 : 0 : (*internals)->eth_addr = (struct rte_ether_addr) {
1241 : 0 : .addr_bytes = { 0x02, 0x70, 0x63, 0x61, 0x70, iface_idx++ }
1242 : : };
1243 : 0 : (*internals)->phy_mac = 0;
1244 : : data = (*eth_dev)->data;
1245 : 0 : data->nb_rx_queues = (uint16_t)nb_rx_queues;
1246 : 0 : data->nb_tx_queues = (uint16_t)nb_tx_queues;
1247 : 0 : data->dev_link = pmd_link;
1248 : 0 : data->mac_addrs = &(*internals)->eth_addr;
1249 : 0 : data->promiscuous = 1;
1250 : 0 : data->all_multicast = 1;
1251 : 0 : data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1252 : :
1253 : : /*
1254 : : * NOTE: we'll replace the data element, of originally allocated
1255 : : * eth_dev so the rings are local per-process
1256 : : */
1257 [ # # ]: 0 : (*eth_dev)->dev_ops = &ops;
1258 : :
1259 : 0 : strlcpy((*internals)->devargs, rte_vdev_device_args(vdev),
1260 : : ETH_PCAP_ARG_MAXLEN);
1261 : :
1262 : 0 : return 0;
1263 : : }
1264 : :
1265 : : static int
1266 : 0 : eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
1267 : : const unsigned int numa_node)
1268 : : {
1269 : : void *mac_addrs;
1270 : : struct rte_ether_addr mac;
1271 : :
1272 [ # # ]: 0 : if (osdep_iface_mac_get(if_name, &mac) < 0)
1273 : : return -1;
1274 : :
1275 : 0 : mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
1276 [ # # ]: 0 : if (mac_addrs == NULL)
1277 : : return -1;
1278 : :
1279 : 0 : PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
1280 : : rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
1281 : 0 : eth_dev->data->mac_addrs = mac_addrs;
1282 : 0 : return 0;
1283 : : }
1284 : :
1285 : : static int
1286 : 0 : eth_from_pcaps_common(struct rte_vdev_device *vdev,
1287 : : struct pmd_devargs_all *devargs_all,
1288 : : struct pmd_internals **internals, struct rte_eth_dev **eth_dev)
1289 : : {
1290 : : struct pmd_process_private *pp;
1291 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1292 : : struct pmd_devargs *tx_queues = &devargs_all->tx_queues;
1293 : 0 : const unsigned int nb_rx_queues = rx_queues->num_of_queue;
1294 : 0 : const unsigned int nb_tx_queues = tx_queues->num_of_queue;
1295 : : unsigned int i;
1296 : :
1297 [ # # ]: 0 : if (pmd_init_internals(vdev, nb_rx_queues, nb_tx_queues, internals,
1298 : : eth_dev) < 0)
1299 : : return -1;
1300 : :
1301 : 0 : pp = (*eth_dev)->process_private;
1302 [ # # ]: 0 : for (i = 0; i < nb_rx_queues; i++) {
1303 : 0 : struct pcap_rx_queue *rx = &(*internals)->rx_queue[i];
1304 : : struct devargs_queue *queue = &rx_queues->queue[i];
1305 : :
1306 : 0 : pp->rx_pcap[i] = queue->pcap;
1307 : 0 : strlcpy(rx->name, queue->name, sizeof(rx->name));
1308 : 0 : strlcpy(rx->type, queue->type, sizeof(rx->type));
1309 : : }
1310 : :
1311 [ # # ]: 0 : for (i = 0; i < nb_tx_queues; i++) {
1312 : 0 : struct pcap_tx_queue *tx = &(*internals)->tx_queue[i];
1313 : : struct devargs_queue *queue = &tx_queues->queue[i];
1314 : :
1315 : 0 : pp->tx_dumper[i] = queue->dumper;
1316 : 0 : pp->tx_pcap[i] = queue->pcap;
1317 : 0 : strlcpy(tx->name, queue->name, sizeof(tx->name));
1318 : 0 : strlcpy(tx->type, queue->type, sizeof(tx->type));
1319 : : }
1320 : :
1321 : : return 0;
1322 : : }
1323 : :
1324 : : static int
1325 : 0 : eth_from_pcaps(struct rte_vdev_device *vdev,
1326 : : struct pmd_devargs_all *devargs_all)
1327 : : {
1328 : 0 : struct pmd_internals *internals = NULL;
1329 : 0 : struct rte_eth_dev *eth_dev = NULL;
1330 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1331 : 0 : int single_iface = devargs_all->single_iface;
1332 : 0 : unsigned int infinite_rx = devargs_all->infinite_rx;
1333 : : int ret;
1334 : :
1335 : 0 : ret = eth_from_pcaps_common(vdev, devargs_all, &internals, ð_dev);
1336 : :
1337 [ # # ]: 0 : if (ret < 0)
1338 : : return ret;
1339 : :
1340 : : /* store weather we are using a single interface for rx/tx or not */
1341 : 0 : internals->single_iface = single_iface;
1342 : :
1343 [ # # ]: 0 : if (single_iface) {
1344 : 0 : internals->if_index =
1345 : 0 : osdep_iface_index_get(rx_queues->queue[0].name);
1346 : :
1347 : : /* phy_mac arg is applied only if "iface" devarg is provided */
1348 [ # # ]: 0 : if (rx_queues->phy_mac) {
1349 [ # # ]: 0 : if (eth_pcap_update_mac(rx_queues->queue[0].name,
1350 : 0 : eth_dev, vdev->device.numa_node) == 0)
1351 : 0 : internals->phy_mac = 1;
1352 : : }
1353 : : }
1354 : :
1355 : 0 : internals->infinite_rx = infinite_rx;
1356 : : /* Assign rx ops. */
1357 [ # # ]: 0 : if (infinite_rx)
1358 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx_infinite;
1359 [ # # # # : 0 : else if (devargs_all->is_rx_pcap || devargs_all->is_rx_iface ||
# # ]
1360 : : single_iface)
1361 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx;
1362 : : else
1363 : 0 : eth_dev->rx_pkt_burst = eth_null_rx;
1364 : :
1365 : : /* Assign tx ops. */
1366 [ # # ]: 0 : if (devargs_all->is_tx_pcap)
1367 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
1368 [ # # # # ]: 0 : else if (devargs_all->is_tx_iface || single_iface)
1369 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx;
1370 : : else
1371 : 0 : eth_dev->tx_pkt_burst = eth_tx_drop;
1372 : :
1373 : 0 : rte_eth_dev_probing_finish(eth_dev);
1374 : 0 : return 0;
1375 : : }
1376 : :
1377 : : static void
1378 : 0 : eth_release_pcaps(struct pmd_devargs *pcaps,
1379 : : struct pmd_devargs *dumpers,
1380 : : int single_iface)
1381 : : {
1382 : : unsigned int i;
1383 : :
1384 [ # # ]: 0 : if (single_iface) {
1385 [ # # ]: 0 : if (pcaps->queue[0].pcap)
1386 : 0 : pcap_close(pcaps->queue[0].pcap);
1387 : 0 : return;
1388 : : }
1389 : :
1390 [ # # ]: 0 : for (i = 0; i < dumpers->num_of_queue; i++) {
1391 [ # # ]: 0 : if (dumpers->queue[i].dumper)
1392 : 0 : pcap_dump_close(dumpers->queue[i].dumper);
1393 : :
1394 [ # # ]: 0 : if (dumpers->queue[i].pcap)
1395 : 0 : pcap_close(dumpers->queue[i].pcap);
1396 : : }
1397 : :
1398 [ # # ]: 0 : for (i = 0; i < pcaps->num_of_queue; i++) {
1399 [ # # ]: 0 : if (pcaps->queue[i].pcap)
1400 : 0 : pcap_close(pcaps->queue[i].pcap);
1401 : : }
1402 : : }
1403 : :
1404 : : static int
1405 : 0 : pmd_pcap_probe(struct rte_vdev_device *dev)
1406 : : {
1407 : : const char *name;
1408 : : struct rte_kvargs *kvlist;
1409 : 0 : struct pmd_devargs pcaps = {0};
1410 : 0 : struct pmd_devargs dumpers = {0};
1411 : : struct rte_eth_dev *eth_dev = NULL;
1412 : : struct pmd_internals *internal;
1413 : : int ret = 0;
1414 : :
1415 [ # # ]: 0 : struct pmd_devargs_all devargs_all = {
1416 : : .single_iface = 0,
1417 : : .is_tx_pcap = 0,
1418 : : .is_tx_iface = 0,
1419 : : .infinite_rx = 0,
1420 : : };
1421 : :
1422 : : name = rte_vdev_device_name(dev);
1423 : 0 : PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
1424 : :
1425 : 0 : timespec_get(&start_time, TIME_UTC);
1426 : 0 : start_cycles = rte_get_timer_cycles();
1427 : 0 : hz = rte_get_timer_hz();
1428 : :
1429 : 0 : ret = rte_mbuf_dyn_rx_timestamp_register(×tamp_dynfield_offset,
1430 : : ×tamp_rx_dynflag);
1431 [ # # ]: 0 : if (ret != 0) {
1432 : 0 : PMD_LOG(ERR, "Failed to register Rx timestamp field/flag");
1433 : 0 : return -1;
1434 : : }
1435 : :
1436 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1437 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
1438 [ # # ]: 0 : if (!eth_dev) {
1439 : 0 : PMD_LOG(ERR, "Failed to probe %s", name);
1440 : 0 : return -1;
1441 : : }
1442 : :
1443 : 0 : internal = eth_dev->data->dev_private;
1444 : :
1445 : 0 : kvlist = rte_kvargs_parse(internal->devargs, valid_arguments);
1446 [ # # ]: 0 : if (kvlist == NULL)
1447 : : return -1;
1448 : : } else {
1449 : 0 : kvlist = rte_kvargs_parse(rte_vdev_device_args(dev),
1450 : : valid_arguments);
1451 [ # # ]: 0 : if (kvlist == NULL)
1452 : : return -1;
1453 : : }
1454 : :
1455 : : /*
1456 : : * If iface argument is passed we open the NICs and use them for
1457 : : * reading / writing
1458 : : */
1459 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_PCAP_IFACE_ARG) == 1) {
1460 : :
1461 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_IFACE_ARG,
1462 : : &open_rx_tx_iface, &pcaps);
1463 [ # # ]: 0 : if (ret < 0)
1464 : 0 : goto free_kvlist;
1465 : :
1466 : 0 : dumpers.queue[0] = pcaps.queue[0];
1467 : :
1468 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_PHY_MAC_ARG,
1469 : : &select_phy_mac, &pcaps.phy_mac);
1470 [ # # ]: 0 : if (ret < 0)
1471 : 0 : goto free_kvlist;
1472 : :
1473 : 0 : dumpers.phy_mac = pcaps.phy_mac;
1474 : :
1475 : 0 : devargs_all.single_iface = 1;
1476 : 0 : pcaps.num_of_queue = 1;
1477 : 0 : dumpers.num_of_queue = 1;
1478 : :
1479 : 0 : goto create_eth;
1480 : : }
1481 : :
1482 : : /*
1483 : : * We check whether we want to open a RX stream from a real NIC, a
1484 : : * pcap file or open a dummy RX stream
1485 : : */
1486 : 0 : devargs_all.is_rx_pcap =
1487 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_RX_PCAP_ARG) ? 1 : 0;
1488 : 0 : devargs_all.is_rx_iface =
1489 : 0 : (rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_ARG) +
1490 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_IN_ARG)) ? 1 : 0;
1491 : 0 : pcaps.num_of_queue = 0;
1492 : :
1493 : 0 : devargs_all.is_tx_pcap =
1494 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) ? 1 : 0;
1495 : 0 : devargs_all.is_tx_iface =
1496 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG) ? 1 : 0;
1497 : 0 : dumpers.num_of_queue = 0;
1498 : :
1499 [ # # ]: 0 : if (devargs_all.is_rx_pcap) {
1500 : : /*
1501 : : * We check whether we want to infinitely rx the pcap file.
1502 : : */
1503 : 0 : unsigned int infinite_rx_arg_cnt = rte_kvargs_count(kvlist,
1504 : : ETH_PCAP_INFINITE_RX_ARG);
1505 : :
1506 [ # # ]: 0 : if (infinite_rx_arg_cnt == 1) {
1507 : 0 : ret = rte_kvargs_process(kvlist,
1508 : : ETH_PCAP_INFINITE_RX_ARG,
1509 : : &get_infinite_rx_arg,
1510 : : &devargs_all.infinite_rx);
1511 [ # # ]: 0 : if (ret < 0)
1512 : 0 : goto free_kvlist;
1513 [ # # ]: 0 : PMD_LOG(INFO, "infinite_rx has been %s for %s",
1514 : : devargs_all.infinite_rx ? "enabled" : "disabled",
1515 : : name);
1516 : :
1517 [ # # ]: 0 : } else if (infinite_rx_arg_cnt > 1) {
1518 : 0 : PMD_LOG(WARNING, "infinite_rx has not been enabled since the "
1519 : : "argument has been provided more than once "
1520 : : "for %s", name);
1521 : : }
1522 : :
1523 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_PCAP_ARG,
1524 : : &open_rx_pcap, &pcaps);
1525 [ # # ]: 0 : } else if (devargs_all.is_rx_iface) {
1526 : 0 : ret = rte_kvargs_process(kvlist, NULL,
1527 : : &rx_iface_args_process, &pcaps);
1528 [ # # # # ]: 0 : } else if (devargs_all.is_tx_iface || devargs_all.is_tx_pcap) {
1529 : : unsigned int i;
1530 : :
1531 : : /* Count number of tx queue args passed before dummy rx queue
1532 : : * creation so a dummy rx queue can be created for each tx queue
1533 : : */
1534 : 0 : unsigned int num_tx_queues =
1535 : 0 : (rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) +
1536 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG));
1537 : :
1538 : 0 : PMD_LOG(INFO, "Creating null rx queue since no rx queues were provided.");
1539 : :
1540 : : /* Creating a dummy rx queue for each tx queue passed */
1541 [ # # ]: 0 : for (i = 0; i < num_tx_queues; i++)
1542 : : ret = add_queue(&pcaps, "dummy_rx", "rx_null", NULL,
1543 : : NULL);
1544 : : } else {
1545 : 0 : PMD_LOG(ERR, "Error - No rx or tx queues provided");
1546 : : ret = -ENOENT;
1547 : : }
1548 [ # # ]: 0 : if (ret < 0)
1549 : 0 : goto free_kvlist;
1550 : :
1551 : : /*
1552 : : * We check whether we want to open a TX stream to a real NIC,
1553 : : * a pcap file, or drop packets on tx
1554 : : */
1555 [ # # ]: 0 : if (devargs_all.is_tx_pcap) {
1556 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_PCAP_ARG,
1557 : : &open_tx_pcap, &dumpers);
1558 [ # # ]: 0 : } else if (devargs_all.is_tx_iface) {
1559 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_IFACE_ARG,
1560 : : &open_tx_iface, &dumpers);
1561 : : } else {
1562 : : unsigned int i;
1563 : :
1564 : 0 : PMD_LOG(INFO, "Dropping packets on tx since no tx queues were provided.");
1565 : :
1566 : : /* Add 1 dummy queue per rxq which counts and drops packets. */
1567 [ # # ]: 0 : for (i = 0; i < pcaps.num_of_queue; i++)
1568 : : ret = add_queue(&dumpers, "dummy_tx", "tx_drop", NULL,
1569 : : NULL);
1570 : : }
1571 : :
1572 [ # # ]: 0 : if (ret < 0)
1573 : 0 : goto free_kvlist;
1574 : :
1575 : 0 : create_eth:
1576 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1577 : : struct pmd_process_private *pp;
1578 : : unsigned int i;
1579 : :
1580 : : internal = eth_dev->data->dev_private;
1581 : : pp = (struct pmd_process_private *)
1582 : 0 : rte_zmalloc(NULL,
1583 : : sizeof(struct pmd_process_private),
1584 : : RTE_CACHE_LINE_SIZE);
1585 : :
1586 [ # # ]: 0 : if (pp == NULL) {
1587 : 0 : PMD_LOG(ERR,
1588 : : "Failed to allocate memory for process private");
1589 : : ret = -1;
1590 : 0 : goto free_kvlist;
1591 : : }
1592 : :
1593 : 0 : eth_dev->dev_ops = &ops;
1594 : 0 : eth_dev->device = &dev->device;
1595 : :
1596 : : /* setup process private */
1597 [ # # ]: 0 : for (i = 0; i < pcaps.num_of_queue; i++)
1598 : 0 : pp->rx_pcap[i] = pcaps.queue[i].pcap;
1599 : :
1600 [ # # ]: 0 : for (i = 0; i < dumpers.num_of_queue; i++) {
1601 : 0 : pp->tx_dumper[i] = dumpers.queue[i].dumper;
1602 : 0 : pp->tx_pcap[i] = dumpers.queue[i].pcap;
1603 : : }
1604 : :
1605 : 0 : eth_dev->process_private = pp;
1606 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx;
1607 [ # # ]: 0 : if (devargs_all.is_tx_pcap)
1608 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
1609 : : else
1610 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx;
1611 : :
1612 : 0 : rte_eth_dev_probing_finish(eth_dev);
1613 : 0 : goto free_kvlist;
1614 : : }
1615 : :
1616 : 0 : devargs_all.rx_queues = pcaps;
1617 : 0 : devargs_all.tx_queues = dumpers;
1618 : :
1619 : 0 : ret = eth_from_pcaps(dev, &devargs_all);
1620 : :
1621 : 0 : free_kvlist:
1622 : 0 : rte_kvargs_free(kvlist);
1623 : :
1624 [ # # ]: 0 : if (ret < 0)
1625 : 0 : eth_release_pcaps(&pcaps, &dumpers, devargs_all.single_iface);
1626 : :
1627 : : return ret;
1628 : : }
1629 : :
1630 : : static int
1631 : 0 : pmd_pcap_remove(struct rte_vdev_device *dev)
1632 : : {
1633 : : struct rte_eth_dev *eth_dev = NULL;
1634 : :
1635 [ # # ]: 0 : if (!dev)
1636 : : return -1;
1637 : :
1638 : 0 : eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
1639 [ # # ]: 0 : if (eth_dev == NULL)
1640 : : return 0; /* port already released */
1641 : :
1642 : 0 : eth_dev_close(eth_dev);
1643 : 0 : rte_eth_dev_release_port(eth_dev);
1644 : :
1645 : 0 : return 0;
1646 : : }
1647 : :
1648 : : static struct rte_vdev_driver pmd_pcap_drv = {
1649 : : .probe = pmd_pcap_probe,
1650 : : .remove = pmd_pcap_remove,
1651 : : };
1652 : :
1653 : 251 : RTE_PMD_REGISTER_VDEV(net_pcap, pmd_pcap_drv);
1654 : : RTE_PMD_REGISTER_ALIAS(net_pcap, eth_pcap);
1655 : : RTE_PMD_REGISTER_PARAM_STRING(net_pcap,
1656 : : ETH_PCAP_RX_PCAP_ARG "=<string> "
1657 : : ETH_PCAP_TX_PCAP_ARG "=<string> "
1658 : : ETH_PCAP_RX_IFACE_ARG "=<ifc> "
1659 : : ETH_PCAP_RX_IFACE_IN_ARG "=<ifc> "
1660 : : ETH_PCAP_TX_IFACE_ARG "=<ifc> "
1661 : : ETH_PCAP_IFACE_ARG "=<ifc> "
1662 : : ETH_PCAP_PHY_MAC_ARG "=<int>"
1663 : : ETH_PCAP_INFINITE_RX_ARG "=<0|1>");
|