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