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 [ - + ]: 253 : 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 : : struct eth_queue_stats *qstats)
755 : : {
756 : : unsigned int i;
757 : : unsigned long rx_packets_total = 0, rx_bytes_total = 0;
758 : : unsigned long rx_missed_total = 0;
759 : : unsigned long rx_nombuf_total = 0, rx_err_total = 0;
760 : : unsigned long tx_packets_total = 0, tx_bytes_total = 0;
761 : : unsigned long tx_packets_err_total = 0;
762 : 0 : const struct pmd_internals *internal = dev->data->dev_private;
763 : :
764 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
765 [ # # ]: 0 : i < dev->data->nb_rx_queues; i++) {
766 [ # # ]: 0 : if (qstats != NULL) {
767 : 0 : qstats->q_ipackets[i] = internal->rx_queue[i].rx_stat.pkts;
768 : 0 : qstats->q_ibytes[i] = internal->rx_queue[i].rx_stat.bytes;
769 : : }
770 : 0 : rx_nombuf_total += internal->rx_queue[i].rx_stat.rx_nombuf;
771 : 0 : rx_err_total += internal->rx_queue[i].rx_stat.err_pkts;
772 : 0 : rx_packets_total += internal->rx_queue[i].rx_stat.pkts;
773 : 0 : rx_bytes_total += internal->rx_queue[i].rx_stat.bytes;
774 : 0 : rx_missed_total += queue_missed_stat_get(dev, i);
775 : : }
776 : :
777 [ # # ]: 0 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
778 [ # # ]: 0 : i < dev->data->nb_tx_queues; i++) {
779 [ # # ]: 0 : if (qstats != NULL) {
780 : 0 : qstats->q_opackets[i] = internal->tx_queue[i].tx_stat.pkts;
781 : 0 : qstats->q_obytes[i] = internal->tx_queue[i].tx_stat.bytes;
782 : : }
783 : 0 : tx_packets_total += internal->tx_queue[i].tx_stat.pkts;
784 : 0 : tx_bytes_total += internal->tx_queue[i].tx_stat.bytes;
785 : 0 : tx_packets_err_total += internal->tx_queue[i].tx_stat.err_pkts;
786 : : }
787 : :
788 : 0 : stats->ipackets = rx_packets_total;
789 : 0 : stats->ibytes = rx_bytes_total;
790 : 0 : stats->imissed = rx_missed_total;
791 : 0 : stats->ierrors = rx_err_total;
792 : 0 : stats->rx_nombuf = rx_nombuf_total;
793 : 0 : stats->opackets = tx_packets_total;
794 : 0 : stats->obytes = tx_bytes_total;
795 : 0 : stats->oerrors = tx_packets_err_total;
796 : :
797 : 0 : return 0;
798 : : }
799 : :
800 : : static int
801 : 0 : eth_stats_reset(struct rte_eth_dev *dev)
802 : : {
803 : : unsigned int i;
804 : 0 : struct pmd_internals *internal = dev->data->dev_private;
805 : :
806 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
807 : 0 : internal->rx_queue[i].rx_stat.pkts = 0;
808 : 0 : internal->rx_queue[i].rx_stat.bytes = 0;
809 : 0 : internal->rx_queue[i].rx_stat.err_pkts = 0;
810 : 0 : internal->rx_queue[i].rx_stat.rx_nombuf = 0;
811 : : queue_missed_stat_reset(dev, i);
812 : : }
813 : :
814 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
815 : 0 : internal->tx_queue[i].tx_stat.pkts = 0;
816 : 0 : internal->tx_queue[i].tx_stat.bytes = 0;
817 : 0 : internal->tx_queue[i].tx_stat.err_pkts = 0;
818 : : }
819 : :
820 : 0 : return 0;
821 : : }
822 : :
823 : : static inline void
824 : 0 : infinite_rx_ring_free(struct rte_ring *pkts)
825 : : {
826 : : struct rte_mbuf *bufs;
827 : :
828 : 0 : while (!rte_ring_dequeue(pkts, (void **)&bufs))
829 : 0 : rte_pktmbuf_free(bufs);
830 : :
831 : 0 : rte_ring_free(pkts);
832 : 0 : }
833 : :
834 : : static int
835 : 0 : eth_dev_close(struct rte_eth_dev *dev)
836 : : {
837 : : unsigned int i;
838 : 0 : struct pmd_internals *internals = dev->data->dev_private;
839 : :
840 : 0 : PMD_LOG(INFO, "Closing pcap ethdev on NUMA socket %d",
841 : : rte_socket_id());
842 : :
843 : 0 : eth_dev_stop(dev);
844 : :
845 : 0 : rte_free(dev->process_private);
846 : :
847 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
848 : : return 0;
849 : :
850 : : /* Device wide flag, but cleanup must be performed per queue. */
851 [ # # ]: 0 : if (internals->infinite_rx) {
852 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
853 : : struct pcap_rx_queue *pcap_q = &internals->rx_queue[i];
854 : :
855 : : /*
856 : : * 'pcap_q->pkts' can be NULL if 'eth_dev_close()'
857 : : * called before 'eth_rx_queue_setup()' has been called
858 : : */
859 [ # # ]: 0 : if (pcap_q->pkts == NULL)
860 : 0 : continue;
861 : :
862 : 0 : infinite_rx_ring_free(pcap_q->pkts);
863 : : }
864 : : }
865 : :
866 [ # # ]: 0 : if (internals->phy_mac == 0)
867 : : /* not dynamically allocated, must not be freed */
868 : 0 : dev->data->mac_addrs = NULL;
869 : :
870 : : return 0;
871 : : }
872 : :
873 : : static int
874 : 0 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
875 : : int wait_to_complete __rte_unused)
876 : : {
877 : 0 : return 0;
878 : : }
879 : :
880 : : static int
881 : 0 : eth_rx_queue_setup(struct rte_eth_dev *dev,
882 : : uint16_t rx_queue_id,
883 : : uint16_t nb_rx_desc __rte_unused,
884 : : unsigned int socket_id __rte_unused,
885 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
886 : : struct rte_mempool *mb_pool)
887 : : {
888 : 0 : struct pmd_internals *internals = dev->data->dev_private;
889 : 0 : struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
890 : :
891 : 0 : pcap_q->mb_pool = mb_pool;
892 : 0 : pcap_q->port_id = dev->data->port_id;
893 : 0 : pcap_q->queue_id = rx_queue_id;
894 : 0 : dev->data->rx_queues[rx_queue_id] = pcap_q;
895 : :
896 [ # # ]: 0 : if (internals->infinite_rx) {
897 : : struct pmd_process_private *pp;
898 : : char ring_name[RTE_RING_NAMESIZE];
899 : : static uint32_t ring_number;
900 : : uint64_t pcap_pkt_count = 0;
901 : : struct rte_mbuf *bufs[1];
902 : : pcap_t **pcap;
903 : :
904 : 0 : pp = rte_eth_devices[pcap_q->port_id].process_private;
905 : 0 : pcap = &pp->rx_pcap[pcap_q->queue_id];
906 : :
907 [ # # ]: 0 : if (unlikely(*pcap == NULL))
908 : 0 : return -ENOENT;
909 : :
910 : 0 : pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
911 : :
912 : 0 : snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
913 : : ring_number);
914 : :
915 : 0 : pcap_q->pkts = rte_ring_create(ring_name,
916 : : rte_align64pow2(pcap_pkt_count + 1), 0,
917 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
918 : 0 : ring_number++;
919 [ # # ]: 0 : if (!pcap_q->pkts)
920 : : return -ENOENT;
921 : :
922 : : /* Fill ring with packets from PCAP file one by one. */
923 [ # # ]: 0 : while (eth_pcap_rx(pcap_q, bufs, 1)) {
924 : : /* Check for multiseg mbufs. */
925 [ # # ]: 0 : if (bufs[0]->nb_segs != 1) {
926 : 0 : infinite_rx_ring_free(pcap_q->pkts);
927 : 0 : PMD_LOG(ERR,
928 : : "Multiseg mbufs are not supported in infinite_rx mode.");
929 : 0 : return -EINVAL;
930 : : }
931 : :
932 [ # # # # : 0 : rte_ring_enqueue_bulk(pcap_q->pkts,
# ]
933 : : (void * const *)bufs, 1, NULL);
934 : : }
935 : :
936 [ # # ]: 0 : if (rte_ring_count(pcap_q->pkts) < pcap_pkt_count) {
937 : 0 : infinite_rx_ring_free(pcap_q->pkts);
938 : 0 : PMD_LOG(ERR,
939 : : "Not enough mbufs to accommodate packets in pcap file. "
940 : : "At least %" PRIu64 " mbufs per queue is required.",
941 : : pcap_pkt_count);
942 : 0 : return -EINVAL;
943 : : }
944 : :
945 : : /*
946 : : * Reset the stats for this queue since eth_pcap_rx calls above
947 : : * didn't result in the application receiving packets.
948 : : */
949 : 0 : pcap_q->rx_stat.pkts = 0;
950 : 0 : pcap_q->rx_stat.bytes = 0;
951 : : }
952 : :
953 : : return 0;
954 : : }
955 : :
956 : : static int
957 : 0 : eth_tx_queue_setup(struct rte_eth_dev *dev,
958 : : uint16_t tx_queue_id,
959 : : uint16_t nb_tx_desc __rte_unused,
960 : : unsigned int socket_id __rte_unused,
961 : : const struct rte_eth_txconf *tx_conf __rte_unused)
962 : : {
963 : 0 : struct pmd_internals *internals = dev->data->dev_private;
964 : 0 : struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
965 : :
966 : 0 : pcap_q->port_id = dev->data->port_id;
967 : 0 : pcap_q->queue_id = tx_queue_id;
968 : 0 : dev->data->tx_queues[tx_queue_id] = pcap_q;
969 : :
970 : 0 : return 0;
971 : : }
972 : :
973 : : static int
974 : 0 : eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
975 : : {
976 : 0 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
977 : :
978 : 0 : return 0;
979 : : }
980 : :
981 : : static int
982 : 0 : eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
983 : : {
984 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
985 : :
986 : 0 : return 0;
987 : : }
988 : :
989 : : static int
990 : 0 : eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
991 : : {
992 : 0 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
993 : :
994 : 0 : return 0;
995 : : }
996 : :
997 : : static int
998 : 0 : eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
999 : : {
1000 : 0 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
1001 : :
1002 : 0 : return 0;
1003 : : }
1004 : :
1005 : : static const struct eth_dev_ops ops = {
1006 : : .dev_start = eth_dev_start,
1007 : : .dev_stop = eth_dev_stop,
1008 : : .dev_close = eth_dev_close,
1009 : : .dev_configure = eth_dev_configure,
1010 : : .dev_infos_get = eth_dev_info,
1011 : : .rx_queue_setup = eth_rx_queue_setup,
1012 : : .tx_queue_setup = eth_tx_queue_setup,
1013 : : .rx_queue_start = eth_rx_queue_start,
1014 : : .tx_queue_start = eth_tx_queue_start,
1015 : : .rx_queue_stop = eth_rx_queue_stop,
1016 : : .tx_queue_stop = eth_tx_queue_stop,
1017 : : .link_update = eth_link_update,
1018 : : .stats_get = eth_stats_get,
1019 : : .stats_reset = eth_stats_reset,
1020 : : };
1021 : :
1022 : : static int
1023 : : add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
1024 : : pcap_t *pcap, pcap_dumper_t *dumper)
1025 : : {
1026 [ # # # # ]: 0 : if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
1027 : : return -1;
1028 [ # # # # ]: 0 : if (pcap)
1029 : 0 : pmd->queue[pmd->num_of_queue].pcap = pcap;
1030 [ # # ]: 0 : if (dumper)
1031 : 0 : pmd->queue[pmd->num_of_queue].dumper = dumper;
1032 : 0 : pmd->queue[pmd->num_of_queue].name = name;
1033 : 0 : pmd->queue[pmd->num_of_queue].type = type;
1034 : 0 : pmd->num_of_queue++;
1035 : 0 : return 0;
1036 : : }
1037 : :
1038 : : /*
1039 : : * Function handler that opens the pcap file for reading a stores a
1040 : : * reference of it for use it later on.
1041 : : */
1042 : : static int
1043 : 0 : open_rx_pcap(const char *key, const char *value, void *extra_args)
1044 : : {
1045 : : const char *pcap_filename = value;
1046 : : struct pmd_devargs *rx = extra_args;
1047 : 0 : pcap_t *pcap = NULL;
1048 : :
1049 [ # # ]: 0 : if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
1050 : : return -1;
1051 : :
1052 [ # # ]: 0 : if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
1053 : 0 : pcap_close(pcap);
1054 : 0 : return -1;
1055 : : }
1056 : :
1057 : : return 0;
1058 : : }
1059 : :
1060 : : /*
1061 : : * Opens a pcap file for writing and stores a reference to it
1062 : : * for use it later on.
1063 : : */
1064 : : static int
1065 : 0 : open_tx_pcap(const char *key, const char *value, void *extra_args)
1066 : : {
1067 : : const char *pcap_filename = value;
1068 : : struct pmd_devargs *dumpers = extra_args;
1069 : : pcap_dumper_t *dumper;
1070 : :
1071 [ # # ]: 0 : if (open_single_tx_pcap(pcap_filename, &dumper) < 0)
1072 : : return -1;
1073 : :
1074 [ # # ]: 0 : if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
1075 : 0 : pcap_dump_close(dumper);
1076 : 0 : return -1;
1077 : : }
1078 : :
1079 : : return 0;
1080 : : }
1081 : :
1082 : : /*
1083 : : * Opens an interface for reading and writing
1084 : : */
1085 : : static inline int
1086 : 0 : open_rx_tx_iface(const char *key, const char *value, void *extra_args)
1087 : : {
1088 : : const char *iface = value;
1089 : : struct pmd_devargs *tx = extra_args;
1090 : 0 : pcap_t *pcap = NULL;
1091 : :
1092 [ # # ]: 0 : if (open_single_iface(iface, &pcap) < 0)
1093 : : return -1;
1094 : :
1095 : 0 : tx->queue[0].pcap = pcap;
1096 : 0 : tx->queue[0].name = iface;
1097 : 0 : tx->queue[0].type = key;
1098 : :
1099 : 0 : return 0;
1100 : : }
1101 : :
1102 : : static inline int
1103 : 0 : set_iface_direction(const char *iface, pcap_t *pcap,
1104 : : pcap_direction_t direction)
1105 : : {
1106 [ # # ]: 0 : const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
1107 [ # # ]: 0 : if (pcap_setdirection(pcap, direction) < 0) {
1108 : 0 : PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s",
1109 : : iface, direction_str, pcap_geterr(pcap));
1110 : 0 : return -1;
1111 : : }
1112 : 0 : PMD_LOG(INFO, "Setting %s pcap direction %s",
1113 : : iface, direction_str);
1114 : 0 : return 0;
1115 : : }
1116 : :
1117 : : static inline int
1118 : 0 : open_iface(const char *key, const char *value, void *extra_args)
1119 : : {
1120 : : const char *iface = value;
1121 : : struct pmd_devargs *pmd = extra_args;
1122 : 0 : pcap_t *pcap = NULL;
1123 : :
1124 [ # # ]: 0 : if (open_single_iface(iface, &pcap) < 0)
1125 : : return -1;
1126 [ # # ]: 0 : if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
1127 : 0 : pcap_close(pcap);
1128 : 0 : return -1;
1129 : : }
1130 : :
1131 : : return 0;
1132 : : }
1133 : :
1134 : : /*
1135 : : * Opens a NIC for reading packets from it
1136 : : */
1137 : : static inline int
1138 : 0 : open_rx_iface(const char *key, const char *value, void *extra_args)
1139 : : {
1140 : 0 : int ret = open_iface(key, value, extra_args);
1141 [ # # ]: 0 : if (ret < 0)
1142 : : return ret;
1143 [ # # ]: 0 : if (strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
1144 : : struct pmd_devargs *pmd = extra_args;
1145 : 0 : unsigned int qid = pmd->num_of_queue - 1;
1146 : :
1147 : 0 : set_iface_direction(pmd->queue[qid].name,
1148 : : pmd->queue[qid].pcap,
1149 : : PCAP_D_IN);
1150 : : }
1151 : :
1152 : : return 0;
1153 : : }
1154 : :
1155 : : static inline int
1156 : 0 : rx_iface_args_process(const char *key, const char *value, void *extra_args)
1157 : : {
1158 [ # # ]: 0 : if (strcmp(key, ETH_PCAP_RX_IFACE_ARG) == 0 ||
1159 [ # # ]: 0 : strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
1160 : 0 : return open_rx_iface(key, value, extra_args);
1161 : :
1162 : : return 0;
1163 : : }
1164 : :
1165 : : /*
1166 : : * Opens a NIC for writing packets to it
1167 : : */
1168 : : static int
1169 : 0 : open_tx_iface(const char *key, const char *value, void *extra_args)
1170 : : {
1171 : 0 : return open_iface(key, value, extra_args);
1172 : : }
1173 : :
1174 : : static int
1175 : 0 : select_phy_mac(const char *key __rte_unused, const char *value,
1176 : : void *extra_args)
1177 : : {
1178 [ # # ]: 0 : if (extra_args) {
1179 : : const int phy_mac = atoi(value);
1180 : : int *enable_phy_mac = extra_args;
1181 : :
1182 [ # # ]: 0 : if (phy_mac)
1183 : 0 : *enable_phy_mac = 1;
1184 : : }
1185 : 0 : return 0;
1186 : : }
1187 : :
1188 : : static int
1189 : 0 : get_infinite_rx_arg(const char *key __rte_unused,
1190 : : const char *value, void *extra_args)
1191 : : {
1192 [ # # ]: 0 : if (extra_args) {
1193 : : const int infinite_rx = atoi(value);
1194 : : int *enable_infinite_rx = extra_args;
1195 : :
1196 [ # # ]: 0 : if (infinite_rx > 0)
1197 : 0 : *enable_infinite_rx = 1;
1198 : : }
1199 : 0 : return 0;
1200 : : }
1201 : :
1202 : : static int
1203 : 0 : pmd_init_internals(struct rte_vdev_device *vdev,
1204 : : const unsigned int nb_rx_queues,
1205 : : const unsigned int nb_tx_queues,
1206 : : struct pmd_internals **internals,
1207 : : struct rte_eth_dev **eth_dev)
1208 : : {
1209 : : struct rte_eth_dev_data *data;
1210 : : struct pmd_process_private *pp;
1211 : 0 : unsigned int numa_node = vdev->device.numa_node;
1212 : :
1213 : 0 : PMD_LOG(INFO, "Creating pcap-backed ethdev on numa socket %d",
1214 : : numa_node);
1215 : :
1216 : : pp = (struct pmd_process_private *)
1217 : 0 : rte_zmalloc(NULL, sizeof(struct pmd_process_private),
1218 : : RTE_CACHE_LINE_SIZE);
1219 : :
1220 [ # # ]: 0 : if (pp == NULL) {
1221 : 0 : PMD_LOG(ERR,
1222 : : "Failed to allocate memory for process private");
1223 : 0 : return -1;
1224 : : }
1225 : :
1226 : : /* reserve an ethdev entry */
1227 : 0 : *eth_dev = rte_eth_vdev_allocate(vdev, sizeof(**internals));
1228 [ # # ]: 0 : if (!(*eth_dev)) {
1229 : 0 : rte_free(pp);
1230 : 0 : return -1;
1231 : : }
1232 : 0 : (*eth_dev)->process_private = pp;
1233 : : /* now put it all together
1234 : : * - store queue data in internals,
1235 : : * - store numa_node info in eth_dev
1236 : : * - point eth_dev_data to internals
1237 : : * - and point eth_dev structure to new eth_dev_data structure
1238 : : */
1239 : 0 : *internals = (*eth_dev)->data->dev_private;
1240 : : /*
1241 : : * Interface MAC = 02:70:63:61:70:<iface_idx>
1242 : : * derived from: 'locally administered':'p':'c':'a':'p':'iface_idx'
1243 : : * where the middle 4 characters are converted to hex.
1244 : : */
1245 : 0 : (*internals)->eth_addr = (struct rte_ether_addr) {
1246 : 0 : .addr_bytes = { 0x02, 0x70, 0x63, 0x61, 0x70, iface_idx++ }
1247 : : };
1248 : 0 : (*internals)->phy_mac = 0;
1249 : : data = (*eth_dev)->data;
1250 : 0 : data->nb_rx_queues = (uint16_t)nb_rx_queues;
1251 : 0 : data->nb_tx_queues = (uint16_t)nb_tx_queues;
1252 : 0 : data->dev_link = pmd_link;
1253 : 0 : data->mac_addrs = &(*internals)->eth_addr;
1254 : 0 : data->promiscuous = 1;
1255 : 0 : data->all_multicast = 1;
1256 : 0 : data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1257 : :
1258 : : /*
1259 : : * NOTE: we'll replace the data element, of originally allocated
1260 : : * eth_dev so the rings are local per-process
1261 : : */
1262 [ # # ]: 0 : (*eth_dev)->dev_ops = &ops;
1263 : :
1264 : 0 : strlcpy((*internals)->devargs, rte_vdev_device_args(vdev),
1265 : : ETH_PCAP_ARG_MAXLEN);
1266 : :
1267 : 0 : return 0;
1268 : : }
1269 : :
1270 : : static int
1271 : 0 : eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
1272 : : const unsigned int numa_node)
1273 : : {
1274 : : void *mac_addrs;
1275 : : struct rte_ether_addr mac;
1276 : :
1277 [ # # ]: 0 : if (osdep_iface_mac_get(if_name, &mac) < 0)
1278 : : return -1;
1279 : :
1280 : 0 : mac_addrs = rte_zmalloc_socket(NULL, RTE_ETHER_ADDR_LEN, 0, numa_node);
1281 [ # # ]: 0 : if (mac_addrs == NULL)
1282 : : return -1;
1283 : :
1284 : 0 : PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
1285 : : rte_memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
1286 : 0 : eth_dev->data->mac_addrs = mac_addrs;
1287 : 0 : return 0;
1288 : : }
1289 : :
1290 : : static int
1291 : 0 : eth_from_pcaps_common(struct rte_vdev_device *vdev,
1292 : : struct pmd_devargs_all *devargs_all,
1293 : : struct pmd_internals **internals, struct rte_eth_dev **eth_dev)
1294 : : {
1295 : : struct pmd_process_private *pp;
1296 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1297 : : struct pmd_devargs *tx_queues = &devargs_all->tx_queues;
1298 : 0 : const unsigned int nb_rx_queues = rx_queues->num_of_queue;
1299 : 0 : const unsigned int nb_tx_queues = tx_queues->num_of_queue;
1300 : : unsigned int i;
1301 : :
1302 [ # # ]: 0 : if (pmd_init_internals(vdev, nb_rx_queues, nb_tx_queues, internals,
1303 : : eth_dev) < 0)
1304 : : return -1;
1305 : :
1306 : 0 : pp = (*eth_dev)->process_private;
1307 [ # # ]: 0 : for (i = 0; i < nb_rx_queues; i++) {
1308 : 0 : struct pcap_rx_queue *rx = &(*internals)->rx_queue[i];
1309 : : struct devargs_queue *queue = &rx_queues->queue[i];
1310 : :
1311 : 0 : pp->rx_pcap[i] = queue->pcap;
1312 : 0 : strlcpy(rx->name, queue->name, sizeof(rx->name));
1313 : 0 : strlcpy(rx->type, queue->type, sizeof(rx->type));
1314 : : }
1315 : :
1316 [ # # ]: 0 : for (i = 0; i < nb_tx_queues; i++) {
1317 : 0 : struct pcap_tx_queue *tx = &(*internals)->tx_queue[i];
1318 : : struct devargs_queue *queue = &tx_queues->queue[i];
1319 : :
1320 : 0 : pp->tx_dumper[i] = queue->dumper;
1321 : 0 : pp->tx_pcap[i] = queue->pcap;
1322 : 0 : strlcpy(tx->name, queue->name, sizeof(tx->name));
1323 : 0 : strlcpy(tx->type, queue->type, sizeof(tx->type));
1324 : : }
1325 : :
1326 : : return 0;
1327 : : }
1328 : :
1329 : : static int
1330 : 0 : eth_from_pcaps(struct rte_vdev_device *vdev,
1331 : : struct pmd_devargs_all *devargs_all)
1332 : : {
1333 : 0 : struct pmd_internals *internals = NULL;
1334 : 0 : struct rte_eth_dev *eth_dev = NULL;
1335 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1336 : 0 : int single_iface = devargs_all->single_iface;
1337 : 0 : unsigned int infinite_rx = devargs_all->infinite_rx;
1338 : : int ret;
1339 : :
1340 : 0 : ret = eth_from_pcaps_common(vdev, devargs_all, &internals, ð_dev);
1341 : :
1342 [ # # ]: 0 : if (ret < 0)
1343 : : return ret;
1344 : :
1345 : : /* store weather we are using a single interface for rx/tx or not */
1346 : 0 : internals->single_iface = single_iface;
1347 : :
1348 [ # # ]: 0 : if (single_iface) {
1349 : 0 : internals->if_index =
1350 : 0 : osdep_iface_index_get(rx_queues->queue[0].name);
1351 : :
1352 : : /* phy_mac arg is applied only if "iface" devarg is provided */
1353 [ # # ]: 0 : if (rx_queues->phy_mac) {
1354 [ # # ]: 0 : if (eth_pcap_update_mac(rx_queues->queue[0].name,
1355 : 0 : eth_dev, vdev->device.numa_node) == 0)
1356 : 0 : internals->phy_mac = 1;
1357 : : }
1358 : : }
1359 : :
1360 : 0 : internals->infinite_rx = infinite_rx;
1361 : : /* Assign rx ops. */
1362 [ # # ]: 0 : if (infinite_rx)
1363 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx_infinite;
1364 [ # # # # : 0 : else if (devargs_all->is_rx_pcap || devargs_all->is_rx_iface ||
# # ]
1365 : : single_iface)
1366 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx;
1367 : : else
1368 : 0 : eth_dev->rx_pkt_burst = eth_null_rx;
1369 : :
1370 : : /* Assign tx ops. */
1371 [ # # ]: 0 : if (devargs_all->is_tx_pcap)
1372 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
1373 [ # # # # ]: 0 : else if (devargs_all->is_tx_iface || single_iface)
1374 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx;
1375 : : else
1376 : 0 : eth_dev->tx_pkt_burst = eth_tx_drop;
1377 : :
1378 : 0 : rte_eth_dev_probing_finish(eth_dev);
1379 : 0 : return 0;
1380 : : }
1381 : :
1382 : : static void
1383 : 0 : eth_release_pcaps(struct pmd_devargs *pcaps,
1384 : : struct pmd_devargs *dumpers,
1385 : : int single_iface)
1386 : : {
1387 : : unsigned int i;
1388 : :
1389 [ # # ]: 0 : if (single_iface) {
1390 [ # # ]: 0 : if (pcaps->queue[0].pcap)
1391 : 0 : pcap_close(pcaps->queue[0].pcap);
1392 : 0 : return;
1393 : : }
1394 : :
1395 [ # # ]: 0 : for (i = 0; i < dumpers->num_of_queue; i++) {
1396 [ # # ]: 0 : if (dumpers->queue[i].dumper)
1397 : 0 : pcap_dump_close(dumpers->queue[i].dumper);
1398 : :
1399 [ # # ]: 0 : if (dumpers->queue[i].pcap)
1400 : 0 : pcap_close(dumpers->queue[i].pcap);
1401 : : }
1402 : :
1403 [ # # ]: 0 : for (i = 0; i < pcaps->num_of_queue; i++) {
1404 [ # # ]: 0 : if (pcaps->queue[i].pcap)
1405 : 0 : pcap_close(pcaps->queue[i].pcap);
1406 : : }
1407 : : }
1408 : :
1409 : : static int
1410 : 0 : pmd_pcap_probe(struct rte_vdev_device *dev)
1411 : : {
1412 : : const char *name;
1413 : : struct rte_kvargs *kvlist;
1414 : 0 : struct pmd_devargs pcaps = {0};
1415 : 0 : struct pmd_devargs dumpers = {0};
1416 : : struct rte_eth_dev *eth_dev = NULL;
1417 : : struct pmd_internals *internal;
1418 : : int ret = 0;
1419 : :
1420 [ # # ]: 0 : struct pmd_devargs_all devargs_all = {
1421 : : .single_iface = 0,
1422 : : .is_tx_pcap = 0,
1423 : : .is_tx_iface = 0,
1424 : : .infinite_rx = 0,
1425 : : };
1426 : :
1427 : : name = rte_vdev_device_name(dev);
1428 : 0 : PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
1429 : :
1430 : 0 : timespec_get(&start_time, TIME_UTC);
1431 : 0 : start_cycles = rte_get_timer_cycles();
1432 : 0 : hz = rte_get_timer_hz();
1433 : :
1434 : 0 : ret = rte_mbuf_dyn_rx_timestamp_register(×tamp_dynfield_offset,
1435 : : ×tamp_rx_dynflag);
1436 [ # # ]: 0 : if (ret != 0) {
1437 : 0 : PMD_LOG(ERR, "Failed to register Rx timestamp field/flag");
1438 : 0 : return -1;
1439 : : }
1440 : :
1441 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1442 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
1443 [ # # ]: 0 : if (!eth_dev) {
1444 : 0 : PMD_LOG(ERR, "Failed to probe %s", name);
1445 : 0 : return -1;
1446 : : }
1447 : :
1448 : 0 : internal = eth_dev->data->dev_private;
1449 : :
1450 : 0 : kvlist = rte_kvargs_parse(internal->devargs, valid_arguments);
1451 [ # # ]: 0 : if (kvlist == NULL)
1452 : : return -1;
1453 : : } else {
1454 : 0 : kvlist = rte_kvargs_parse(rte_vdev_device_args(dev),
1455 : : valid_arguments);
1456 [ # # ]: 0 : if (kvlist == NULL)
1457 : : return -1;
1458 : : }
1459 : :
1460 : : /*
1461 : : * If iface argument is passed we open the NICs and use them for
1462 : : * reading / writing
1463 : : */
1464 [ # # ]: 0 : if (rte_kvargs_count(kvlist, ETH_PCAP_IFACE_ARG) == 1) {
1465 : :
1466 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_IFACE_ARG,
1467 : : &open_rx_tx_iface, &pcaps);
1468 [ # # ]: 0 : if (ret < 0)
1469 : 0 : goto free_kvlist;
1470 : :
1471 : 0 : dumpers.queue[0] = pcaps.queue[0];
1472 : :
1473 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_PHY_MAC_ARG,
1474 : : &select_phy_mac, &pcaps.phy_mac);
1475 [ # # ]: 0 : if (ret < 0)
1476 : 0 : goto free_kvlist;
1477 : :
1478 : 0 : dumpers.phy_mac = pcaps.phy_mac;
1479 : :
1480 : 0 : devargs_all.single_iface = 1;
1481 : 0 : pcaps.num_of_queue = 1;
1482 : 0 : dumpers.num_of_queue = 1;
1483 : :
1484 : 0 : goto create_eth;
1485 : : }
1486 : :
1487 : : /*
1488 : : * We check whether we want to open a RX stream from a real NIC, a
1489 : : * pcap file or open a dummy RX stream
1490 : : */
1491 : 0 : devargs_all.is_rx_pcap =
1492 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_RX_PCAP_ARG) ? 1 : 0;
1493 : 0 : devargs_all.is_rx_iface =
1494 : 0 : (rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_ARG) +
1495 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_IN_ARG)) ? 1 : 0;
1496 : 0 : pcaps.num_of_queue = 0;
1497 : :
1498 : 0 : devargs_all.is_tx_pcap =
1499 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) ? 1 : 0;
1500 : 0 : devargs_all.is_tx_iface =
1501 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG) ? 1 : 0;
1502 : 0 : dumpers.num_of_queue = 0;
1503 : :
1504 [ # # ]: 0 : if (devargs_all.is_rx_pcap) {
1505 : : /*
1506 : : * We check whether we want to infinitely rx the pcap file.
1507 : : */
1508 : 0 : unsigned int infinite_rx_arg_cnt = rte_kvargs_count(kvlist,
1509 : : ETH_PCAP_INFINITE_RX_ARG);
1510 : :
1511 [ # # ]: 0 : if (infinite_rx_arg_cnt == 1) {
1512 : 0 : ret = rte_kvargs_process(kvlist,
1513 : : ETH_PCAP_INFINITE_RX_ARG,
1514 : : &get_infinite_rx_arg,
1515 : : &devargs_all.infinite_rx);
1516 [ # # ]: 0 : if (ret < 0)
1517 : 0 : goto free_kvlist;
1518 [ # # ]: 0 : PMD_LOG(INFO, "infinite_rx has been %s for %s",
1519 : : devargs_all.infinite_rx ? "enabled" : "disabled",
1520 : : name);
1521 : :
1522 [ # # ]: 0 : } else if (infinite_rx_arg_cnt > 1) {
1523 : 0 : PMD_LOG(WARNING, "infinite_rx has not been enabled since the "
1524 : : "argument has been provided more than once "
1525 : : "for %s", name);
1526 : : }
1527 : :
1528 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_PCAP_ARG,
1529 : : &open_rx_pcap, &pcaps);
1530 [ # # ]: 0 : } else if (devargs_all.is_rx_iface) {
1531 : 0 : ret = rte_kvargs_process(kvlist, NULL,
1532 : : &rx_iface_args_process, &pcaps);
1533 [ # # # # ]: 0 : } else if (devargs_all.is_tx_iface || devargs_all.is_tx_pcap) {
1534 : : unsigned int i;
1535 : :
1536 : : /* Count number of tx queue args passed before dummy rx queue
1537 : : * creation so a dummy rx queue can be created for each tx queue
1538 : : */
1539 : 0 : unsigned int num_tx_queues =
1540 : 0 : (rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) +
1541 : 0 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG));
1542 : :
1543 : 0 : PMD_LOG(INFO, "Creating null rx queue since no rx queues were provided.");
1544 : :
1545 : : /* Creating a dummy rx queue for each tx queue passed */
1546 [ # # ]: 0 : for (i = 0; i < num_tx_queues; i++)
1547 : : ret = add_queue(&pcaps, "dummy_rx", "rx_null", NULL,
1548 : : NULL);
1549 : : } else {
1550 : 0 : PMD_LOG(ERR, "Error - No rx or tx queues provided");
1551 : : ret = -ENOENT;
1552 : : }
1553 [ # # ]: 0 : if (ret < 0)
1554 : 0 : goto free_kvlist;
1555 : :
1556 : : /*
1557 : : * We check whether we want to open a TX stream to a real NIC,
1558 : : * a pcap file, or drop packets on tx
1559 : : */
1560 [ # # ]: 0 : if (devargs_all.is_tx_pcap) {
1561 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_PCAP_ARG,
1562 : : &open_tx_pcap, &dumpers);
1563 [ # # ]: 0 : } else if (devargs_all.is_tx_iface) {
1564 : 0 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_IFACE_ARG,
1565 : : &open_tx_iface, &dumpers);
1566 : : } else {
1567 : : unsigned int i;
1568 : :
1569 : 0 : PMD_LOG(INFO, "Dropping packets on tx since no tx queues were provided.");
1570 : :
1571 : : /* Add 1 dummy queue per rxq which counts and drops packets. */
1572 [ # # ]: 0 : for (i = 0; i < pcaps.num_of_queue; i++)
1573 : : ret = add_queue(&dumpers, "dummy_tx", "tx_drop", NULL,
1574 : : NULL);
1575 : : }
1576 : :
1577 [ # # ]: 0 : if (ret < 0)
1578 : 0 : goto free_kvlist;
1579 : :
1580 : 0 : create_eth:
1581 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1582 : : struct pmd_process_private *pp;
1583 : : unsigned int i;
1584 : :
1585 : : internal = eth_dev->data->dev_private;
1586 : : pp = (struct pmd_process_private *)
1587 : 0 : rte_zmalloc(NULL,
1588 : : sizeof(struct pmd_process_private),
1589 : : RTE_CACHE_LINE_SIZE);
1590 : :
1591 [ # # ]: 0 : if (pp == NULL) {
1592 : 0 : PMD_LOG(ERR,
1593 : : "Failed to allocate memory for process private");
1594 : : ret = -1;
1595 : 0 : goto free_kvlist;
1596 : : }
1597 : :
1598 : 0 : eth_dev->dev_ops = &ops;
1599 : 0 : eth_dev->device = &dev->device;
1600 : :
1601 : : /* setup process private */
1602 [ # # ]: 0 : for (i = 0; i < pcaps.num_of_queue; i++)
1603 : 0 : pp->rx_pcap[i] = pcaps.queue[i].pcap;
1604 : :
1605 [ # # ]: 0 : for (i = 0; i < dumpers.num_of_queue; i++) {
1606 : 0 : pp->tx_dumper[i] = dumpers.queue[i].dumper;
1607 : 0 : pp->tx_pcap[i] = dumpers.queue[i].pcap;
1608 : : }
1609 : :
1610 : 0 : eth_dev->process_private = pp;
1611 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx;
1612 [ # # ]: 0 : if (devargs_all.is_tx_pcap)
1613 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
1614 : : else
1615 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx;
1616 : :
1617 : 0 : rte_eth_dev_probing_finish(eth_dev);
1618 : 0 : goto free_kvlist;
1619 : : }
1620 : :
1621 : 0 : devargs_all.rx_queues = pcaps;
1622 : 0 : devargs_all.tx_queues = dumpers;
1623 : :
1624 : 0 : ret = eth_from_pcaps(dev, &devargs_all);
1625 : :
1626 : 0 : free_kvlist:
1627 : 0 : rte_kvargs_free(kvlist);
1628 : :
1629 [ # # ]: 0 : if (ret < 0)
1630 : 0 : eth_release_pcaps(&pcaps, &dumpers, devargs_all.single_iface);
1631 : :
1632 : : return ret;
1633 : : }
1634 : :
1635 : : static int
1636 : 0 : pmd_pcap_remove(struct rte_vdev_device *dev)
1637 : : {
1638 : : struct rte_eth_dev *eth_dev = NULL;
1639 : :
1640 [ # # ]: 0 : if (!dev)
1641 : : return -1;
1642 : :
1643 : 0 : eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
1644 [ # # ]: 0 : if (eth_dev == NULL)
1645 : : return 0; /* port already released */
1646 : :
1647 : 0 : eth_dev_close(eth_dev);
1648 : 0 : rte_eth_dev_release_port(eth_dev);
1649 : :
1650 : 0 : return 0;
1651 : : }
1652 : :
1653 : : static struct rte_vdev_driver pmd_pcap_drv = {
1654 : : .probe = pmd_pcap_probe,
1655 : : .remove = pmd_pcap_remove,
1656 : : };
1657 : :
1658 : 253 : RTE_PMD_REGISTER_VDEV(net_pcap, pmd_pcap_drv);
1659 : : RTE_PMD_REGISTER_ALIAS(net_pcap, eth_pcap);
1660 : : RTE_PMD_REGISTER_PARAM_STRING(net_pcap,
1661 : : ETH_PCAP_RX_PCAP_ARG "=<string> "
1662 : : ETH_PCAP_TX_PCAP_ARG "=<string> "
1663 : : ETH_PCAP_RX_IFACE_ARG "=<ifc> "
1664 : : ETH_PCAP_RX_IFACE_IN_ARG "=<ifc> "
1665 : : ETH_PCAP_TX_IFACE_ARG "=<ifc> "
1666 : : ETH_PCAP_IFACE_ARG "=<ifc> "
1667 : : ETH_PCAP_PHY_MAC_ARG "=<int>"
1668 : : ETH_PCAP_INFINITE_RX_ARG "=<0|1>");
|