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 <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : : #include <stdbool.h>
11 : : #include <time.h>
12 : : #include <inttypes.h>
13 : : #include <errno.h>
14 : : #include <sys/time.h>
15 : : #include <sys/types.h>
16 : : #include <unistd.h>
17 : :
18 : : #include <pcap.h>
19 : :
20 : : #include <rte_alarm.h>
21 : : #include <rte_cycles.h>
22 : : #include <rte_ring.h>
23 : : #include <rte_ethdev.h>
24 : : #include <ethdev_driver.h>
25 : : #include <ethdev_vdev.h>
26 : : #include <rte_kvargs.h>
27 : : #include <rte_malloc.h>
28 : : #include <rte_memcpy.h>
29 : : #include <rte_mbuf.h>
30 : : #include <rte_mbuf_dyn.h>
31 : : #include <bus_vdev_driver.h>
32 : : #include <rte_os_shim.h>
33 : : #include <rte_time.h>
34 : :
35 : : #include "pcap_osdep.h"
36 : :
37 : : #define ETH_PCAP_RX_PCAP_ARG "rx_pcap"
38 : : #define ETH_PCAP_TX_PCAP_ARG "tx_pcap"
39 : : #define ETH_PCAP_RX_IFACE_ARG "rx_iface"
40 : : #define ETH_PCAP_RX_IFACE_IN_ARG "rx_iface_in"
41 : : #define ETH_PCAP_TX_IFACE_ARG "tx_iface"
42 : : #define ETH_PCAP_IFACE_ARG "iface"
43 : : #define ETH_PCAP_PHY_MAC_ARG "phy_mac"
44 : : #define ETH_PCAP_INFINITE_RX_ARG "infinite_rx"
45 : : #define ETH_PCAP_EOF_ARG "eof"
46 : : #define ETH_PCAP_SNAPSHOT_LEN_ARG "snaplen"
47 : :
48 : : #define ETH_PCAP_SNAPSHOT_LEN_DEFAULT 65535
49 : :
50 : : /* This is defined in libpcap but not exposed in headers */
51 : : #define ETH_PCAP_MAXIMUM_SNAPLEN 262144
52 : :
53 : : #define ETH_PCAP_LSC_POLL_INTERVAL_US (1000 * 1000) /* 1 second */
54 : :
55 : : #define ETH_PCAP_ARG_MAXLEN 64
56 : :
57 : : #define RTE_PMD_PCAP_MAX_QUEUES 16
58 : :
59 : : static struct timespec start_time;
60 : : static uint64_t start_cycles;
61 : : static uint64_t hz;
62 : :
63 : : static uint64_t timestamp_rx_dynflag;
64 : : static int timestamp_dynfield_offset = -1;
65 : :
66 : : struct queue_stat {
67 : : volatile unsigned long pkts;
68 : : volatile unsigned long bytes;
69 : : volatile unsigned long err_pkts;
70 : : volatile unsigned long rx_nombuf;
71 : : };
72 : :
73 : : struct queue_missed_stat {
74 : : /* last value retrieved from pcap */
75 : : unsigned int pcap;
76 : : /* stores values lost by pcap stop or rollover */
77 : : unsigned long mnemonic;
78 : : /* value on last reset */
79 : : unsigned long reset;
80 : : };
81 : :
82 : : struct pcap_rx_queue {
83 : : uint16_t port_id;
84 : : uint16_t queue_id;
85 : : bool vlan_strip;
86 : : bool rx_scatter;
87 : : bool timestamp_offloading;
88 : : struct rte_mempool *mb_pool;
89 : : struct queue_stat rx_stat;
90 : : struct queue_missed_stat missed_stat;
91 : : char name[PATH_MAX];
92 : : char type[ETH_PCAP_ARG_MAXLEN];
93 : :
94 : : /* Contains pre-generated packets to be looped through */
95 : : struct rte_ring *pkts;
96 : : };
97 : :
98 : : struct pcap_tx_queue {
99 : : uint16_t port_id;
100 : : uint16_t queue_id;
101 : : struct queue_stat tx_stat;
102 : : char name[PATH_MAX];
103 : : char type[ETH_PCAP_ARG_MAXLEN];
104 : :
105 : : /* Temp buffer used for non-linear packets */
106 : : uint8_t *bounce_buf;
107 : : };
108 : :
109 : : struct pmd_internals {
110 : : struct pcap_rx_queue rx_queue[RTE_PMD_PCAP_MAX_QUEUES];
111 : : struct pcap_tx_queue tx_queue[RTE_PMD_PCAP_MAX_QUEUES];
112 : : char devargs[ETH_PCAP_ARG_MAXLEN];
113 : : struct rte_ether_addr eth_addr;
114 : : int if_index;
115 : : uint32_t snapshot_len;
116 : : bool single_iface;
117 : : bool phy_mac;
118 : : bool infinite_rx;
119 : : bool eof;
120 : : RTE_ATOMIC(bool) eof_signaled;
121 : : bool vlan_strip;
122 : : bool rx_scatter;
123 : : bool timestamp_offloading;
124 : : bool lsc_active;
125 : : };
126 : :
127 : : struct pmd_process_private {
128 : : pcap_t *rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
129 : : pcap_t *tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
130 : : pcap_dumper_t *tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
131 : : };
132 : :
133 : : struct pmd_devargs {
134 : : uint16_t num_of_queue;
135 : : bool phy_mac;
136 : : struct devargs_queue {
137 : : pcap_dumper_t *dumper;
138 : : /* pcap and name/type fields... */
139 : : pcap_t *pcap;
140 : : const char *name;
141 : : const char *type;
142 : : } queue[RTE_PMD_PCAP_MAX_QUEUES];
143 : : uint32_t snapshot_len;
144 : : };
145 : :
146 : : struct pmd_devargs_all {
147 : : struct pmd_devargs rx_queues;
148 : : struct pmd_devargs tx_queues;
149 : : uint32_t snapshot_len;
150 : : bool single_iface;
151 : : bool is_tx_pcap;
152 : : bool is_tx_iface;
153 : : bool is_rx_pcap;
154 : : bool is_rx_iface;
155 : : bool infinite_rx;
156 : : bool eof;
157 : : };
158 : :
159 : : static const char *valid_arguments[] = {
160 : : ETH_PCAP_RX_PCAP_ARG,
161 : : ETH_PCAP_TX_PCAP_ARG,
162 : : ETH_PCAP_RX_IFACE_ARG,
163 : : ETH_PCAP_RX_IFACE_IN_ARG,
164 : : ETH_PCAP_TX_IFACE_ARG,
165 : : ETH_PCAP_IFACE_ARG,
166 : : ETH_PCAP_PHY_MAC_ARG,
167 : : ETH_PCAP_INFINITE_RX_ARG,
168 : : ETH_PCAP_EOF_ARG,
169 : : ETH_PCAP_SNAPSHOT_LEN_ARG,
170 : : NULL
171 : : };
172 : :
173 [ - + ]: 286 : RTE_LOG_REGISTER_DEFAULT(eth_pcap_logtype, NOTICE);
174 : :
175 : : /* Forward declarations */
176 : : static int eth_link_update(struct rte_eth_dev *dev, int wait_to_complete);
177 : :
178 : : static struct queue_missed_stat*
179 : 44 : queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
180 : : {
181 : 44 : struct pmd_internals *internals = dev->data->dev_private;
182 : 44 : struct queue_missed_stat *missed_stat =
183 : : &internals->rx_queue[qid].missed_stat;
184 : 44 : const struct pmd_process_private *pp = dev->process_private;
185 : 44 : pcap_t *pcap = pp->rx_pcap[qid];
186 : : struct pcap_stat stat;
187 : :
188 [ + + + + ]: 44 : if (!pcap || (pcap_stats(pcap, &stat) != 0))
189 : 36 : return missed_stat;
190 : :
191 : : /* rollover check - best effort fixup assuming single rollover */
192 [ - + ]: 8 : if (stat.ps_drop < missed_stat->pcap)
193 : 0 : missed_stat->mnemonic += UINT_MAX;
194 : 8 : missed_stat->pcap = stat.ps_drop;
195 : :
196 : 8 : return missed_stat;
197 : : }
198 : :
199 : : static void
200 : : queue_missed_stat_on_stop_update(struct rte_eth_dev *dev, unsigned int qid)
201 : : {
202 : : struct queue_missed_stat *missed_stat =
203 : 31 : queue_missed_stat_update(dev, qid);
204 : :
205 : 31 : missed_stat->mnemonic += missed_stat->pcap;
206 : 31 : missed_stat->pcap = 0;
207 : : }
208 : :
209 : : static void
210 : : queue_missed_stat_reset(struct rte_eth_dev *dev, unsigned int qid)
211 : : {
212 : : struct queue_missed_stat *missed_stat =
213 : 5 : queue_missed_stat_update(dev, qid);
214 : :
215 : 5 : missed_stat->reset = missed_stat->pcap;
216 : 5 : missed_stat->mnemonic = 0;
217 : : }
218 : :
219 : : static unsigned long
220 : : queue_missed_stat_get(struct rte_eth_dev *dev, unsigned int qid)
221 : : {
222 : : const struct queue_missed_stat *missed_stat =
223 : 8 : queue_missed_stat_update(dev, qid);
224 : :
225 : 8 : return missed_stat->pcap + missed_stat->mnemonic - missed_stat->reset;
226 : : }
227 : :
228 : : static int
229 : 32 : eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
230 : : const u_char *data, uint16_t data_len)
231 : : {
232 : : /* Copy the first segment. */
233 : : uint16_t len = rte_pktmbuf_tailroom(mbuf);
234 : : struct rte_mbuf *m = mbuf;
235 : :
236 : 32 : rte_memcpy(rte_pktmbuf_append(mbuf, len), data, len);
237 : 32 : data_len -= len;
238 : 32 : data += len;
239 : :
240 [ + + ]: 160 : while (data_len > 0) {
241 : : /* Allocate next mbuf and point to that. */
242 : 128 : m->next = rte_pktmbuf_alloc(mb_pool);
243 : :
244 [ + - ]: 128 : if (unlikely(!m->next))
245 : : return -1;
246 : :
247 : : m = m->next;
248 : :
249 : : /* Headroom is not needed in chained mbufs. */
250 : : rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
251 : 128 : m->pkt_len = 0;
252 : 128 : m->data_len = 0;
253 : :
254 : : /* Copy next segment. */
255 : 128 : len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len);
256 : 128 : rte_memcpy(rte_pktmbuf_append(m, len), data, len);
257 : :
258 : 128 : mbuf->nb_segs++;
259 : 128 : data_len -= len;
260 : 128 : data += len;
261 : : }
262 : :
263 : 32 : return mbuf->nb_segs;
264 : : }
265 : :
266 : : static uint16_t
267 : 8 : eth_pcap_rx_infinite(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
268 : : {
269 : : int i;
270 : : struct pcap_rx_queue *pcap_q = queue;
271 : : uint32_t rx_bytes = 0;
272 : :
273 [ + - ]: 8 : if (unlikely(nb_pkts == 0))
274 : : return 0;
275 : :
276 [ + - ]: 8 : if (rte_pktmbuf_alloc_bulk(pcap_q->mb_pool, bufs, nb_pkts) != 0)
277 : : return 0;
278 : :
279 [ + + ]: 264 : for (i = 0; i < nb_pkts; i++) {
280 : : struct rte_mbuf *pcap_buf;
281 [ - + - - : 256 : int err = rte_ring_dequeue(pcap_q->pkts, (void **)&pcap_buf);
- ]
282 : : if (err)
283 : 0 : return i;
284 : :
285 : 256 : rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *),
286 : 256 : rte_pktmbuf_mtod(pcap_buf, void *),
287 [ + - ]: 256 : pcap_buf->data_len);
288 : 256 : bufs[i]->data_len = pcap_buf->data_len;
289 : 256 : bufs[i]->pkt_len = pcap_buf->pkt_len;
290 : 256 : bufs[i]->port = pcap_q->port_id;
291 : :
292 [ - + ]: 256 : if (pcap_q->vlan_strip)
293 : 0 : rte_vlan_strip(bufs[i]);
294 : :
295 [ + - ]: 256 : if (pcap_q->timestamp_offloading) {
296 : : struct timespec ts;
297 : :
298 : 256 : timespec_get(&ts, TIME_UTC);
299 : 256 : *RTE_MBUF_DYNFIELD(bufs[i], timestamp_dynfield_offset,
300 : 256 : rte_mbuf_timestamp_t *) = rte_timespec_to_ns(&ts);
301 : 256 : bufs[i]->ol_flags |= timestamp_rx_dynflag;
302 : : }
303 : :
304 : 256 : rx_bytes += bufs[i]->data_len;
305 : :
306 : : /* Enqueue packet back on ring to allow infinite rx. */
307 [ - + - - : 512 : rte_ring_enqueue(pcap_q->pkts, pcap_buf);
- ]
308 : : }
309 : :
310 : 8 : pcap_q->rx_stat.pkts += i;
311 : 8 : pcap_q->rx_stat.bytes += rx_bytes;
312 : :
313 : 8 : return i;
314 : : }
315 : :
316 : : /*
317 : : * Deferred EOF alarm callback.
318 : : *
319 : : * Scheduled from the RX burst path when end-of-file is reached,
320 : : * so that rte_eth_dev_callback_process() runs outside the datapath.
321 : : * This avoids holding any locks that the application callback
322 : : * might also need, preventing potential deadlocks.
323 : : */
324 : : static void
325 : 2 : eth_pcap_eof_alarm(void *arg)
326 : : {
327 : : struct rte_eth_dev *dev = arg;
328 : :
329 : 2 : rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
330 : 2 : }
331 : :
332 : : static uint16_t
333 : 207 : eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
334 : : {
335 : : struct pcap_rx_queue *pcap_q = queue;
336 : 207 : struct rte_eth_dev *dev = &rte_eth_devices[pcap_q->port_id];
337 : 207 : struct pmd_internals *internals = dev->data->dev_private;
338 : : unsigned int i;
339 : : struct pcap_pkthdr *header;
340 : : struct pmd_process_private *pp;
341 : : const u_char *packet;
342 : : struct rte_mbuf *mbuf;
343 : : uint16_t num_rx = 0;
344 : : uint32_t rx_bytes = 0;
345 : : pcap_t *pcap;
346 : :
347 : 207 : pp = rte_eth_devices[pcap_q->port_id].process_private;
348 : 207 : pcap = pp->rx_pcap[pcap_q->queue_id];
349 : :
350 [ + - ]: 207 : if (unlikely(pcap == NULL || nb_pkts == 0))
351 : : return 0;
352 : :
353 : : /* Reads the given number of packets from the pcap file one by one
354 : : * and copies the packet data into a newly allocated mbuf to return.
355 : : */
356 [ + + ]: 1263 : for (i = 0; i < nb_pkts; i++) {
357 : : /* Get the next PCAP packet */
358 : 1111 : int ret = pcap_next_ex(pcap, &header, &packet);
359 [ + + ]: 1111 : if (ret != 1) {
360 [ - + ]: 55 : if (ret == PCAP_ERROR)
361 : 0 : pcap_q->rx_stat.err_pkts++;
362 : :
363 : : /*
364 : : * EOF: if eof mode is enabled, set link down and
365 : : * defer notification via alarm to avoid calling
366 : : * rte_eth_dev_callback_process() from the datapath.
367 : : */
368 [ + + ]: 55 : else if (ret == PCAP_ERROR_BREAK) {
369 : 48 : bool expected = false;
370 : :
371 [ + + ]: 48 : if (internals->eof &&
372 [ + - ]: 2 : rte_atomic_compare_exchange_strong_explicit(
373 : : &internals->eof_signaled, &expected, true,
374 : : rte_memory_order_relaxed, rte_memory_order_relaxed)) {
375 : 2 : eth_link_update(dev, 0);
376 : 2 : rte_eal_alarm_set(1, eth_pcap_eof_alarm, dev);
377 : : }
378 : : }
379 : :
380 : : break;
381 : : }
382 : :
383 : 1056 : mbuf = rte_pktmbuf_alloc(pcap_q->mb_pool);
384 [ - + ]: 1056 : if (unlikely(mbuf == NULL)) {
385 : 0 : pcap_q->rx_stat.rx_nombuf++;
386 : 0 : break;
387 : : }
388 : :
389 [ + + ]: 1056 : uint32_t len = header->caplen;
390 [ + + ]: 1056 : if (len <= rte_pktmbuf_tailroom(mbuf)) {
391 : : /* pcap packet will fit in the mbuf, can copy it */
392 [ + + ]: 1008 : rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packet, len);
393 : 1008 : mbuf->data_len = len;
394 [ + + ]: 48 : } else if (pcap_q->rx_scatter) {
395 : : /* Scatter into multi-segment mbufs. */
396 [ - + ]: 32 : if (unlikely(eth_pcap_rx_jumbo(pcap_q->mb_pool,
397 : : mbuf, packet, len) == -1)) {
398 : 0 : pcap_q->rx_stat.err_pkts++;
399 : 0 : rte_pktmbuf_free(mbuf);
400 : 0 : break;
401 : : }
402 : : } else {
403 : : /* Packet too large and scatter not enabled, drop it. */
404 : 16 : pcap_q->rx_stat.err_pkts++;
405 : 16 : rte_pktmbuf_free(mbuf);
406 : 16 : continue;
407 : : }
408 : :
409 : 1040 : mbuf->pkt_len = len;
410 : :
411 [ - + ]: 1040 : if (pcap_q->vlan_strip)
412 : 0 : rte_vlan_strip(mbuf);
413 : :
414 [ + + ]: 1040 : if (pcap_q->timestamp_offloading) {
415 : : /*
416 : : * The use of tv_usec as nanoseconds is not a bug here.
417 : : * Interface is always created with nanosecond precision, and
418 : : * that is how pcap API bodged in nanoseconds support.
419 : : */
420 : 496 : uint64_t ns = (uint64_t)header->ts.tv_sec * NSEC_PER_SEC
421 : 496 : + header->ts.tv_usec;
422 : :
423 : 496 : *RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset,
424 : 496 : rte_mbuf_timestamp_t *) = ns;
425 : :
426 : 496 : mbuf->ol_flags |= timestamp_rx_dynflag;
427 : : }
428 : :
429 : 1040 : mbuf->port = pcap_q->port_id;
430 : 1040 : bufs[num_rx] = mbuf;
431 : 1040 : num_rx++;
432 : 1040 : rx_bytes += len;
433 : : }
434 : 207 : pcap_q->rx_stat.pkts += num_rx;
435 : 207 : pcap_q->rx_stat.bytes += rx_bytes;
436 : :
437 : 207 : return num_rx;
438 : : }
439 : :
440 : : static uint16_t
441 : 0 : eth_null_rx(void *queue __rte_unused,
442 : : struct rte_mbuf **bufs __rte_unused,
443 : : uint16_t nb_pkts __rte_unused)
444 : : {
445 : 0 : return 0;
446 : : }
447 : :
448 : : /*
449 : : * Calculate current timestamp in nanoseconds by computing
450 : : * offset from starting time value.
451 : : *
452 : : * Note: it is not a bug that this code is putting nanosecond
453 : : * value into microsecond timeval field. The pcap API is old
454 : : * and nanoseconds were bodged on as an after thought.
455 : : * As long as the pcap stream is set to nanosecond precision
456 : : * it expects nanoseconds here.
457 : : */
458 : : static inline void
459 : 13 : calculate_timestamp(struct timeval *ts)
460 : : {
461 : : uint64_t cycles;
462 : : struct timespec cur_time;
463 : :
464 : 13 : cycles = rte_get_timer_cycles() - start_cycles;
465 : 13 : cur_time.tv_sec = cycles / hz;
466 : 13 : cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
467 : :
468 : 13 : ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
469 : 13 : ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
470 [ + + ]: 13 : if (ts->tv_usec >= NSEC_PER_SEC) {
471 : 5 : ts->tv_usec -= NSEC_PER_SEC;
472 : 5 : ts->tv_sec += 1;
473 : : }
474 : 13 : }
475 : :
476 : : /*
477 : : * Insert VLAN tag into packet.
478 : : *
479 : : * rte_vlan_insert() modifies the mbuf in place, prepending
480 : : * RTE_VLAN_HLEN bytes. If mbuf cannot safely be modified in place
481 : : * a private copy is made first.
482 : : *
483 : : * The caller's mbuf pointer is updated on success; on failure the
484 : : * original mbuf is freed and -1 is returned.
485 : : */
486 : : static int
487 : 0 : pcap_tx_vlan_insert(struct rte_mbuf **m)
488 : : {
489 [ # # ]: 0 : struct rte_mbuf *mbuf = *m;
490 : :
491 [ # # # # ]: 0 : if (rte_mbuf_refcnt_read(mbuf) > 1 ||
492 [ # # ]: 0 : rte_pktmbuf_headroom(mbuf) < RTE_VLAN_HLEN) {
493 : : struct rte_mbuf *copy;
494 : :
495 : 0 : copy = rte_pktmbuf_copy(mbuf, mbuf->pool, 0, UINT32_MAX);
496 [ # # ]: 0 : if (unlikely(copy == NULL)) {
497 : 0 : rte_pktmbuf_free(mbuf);
498 : 0 : return -1;
499 : : }
500 : 0 : copy->ol_flags |= RTE_MBUF_F_TX_VLAN;
501 : 0 : copy->vlan_tci = mbuf->vlan_tci;
502 : 0 : rte_pktmbuf_free(mbuf);
503 : 0 : *m = copy;
504 : 0 : mbuf = copy;
505 : : }
506 : :
507 [ # # ]: 0 : if (unlikely(rte_vlan_insert(&mbuf) != 0)) {
508 : 0 : rte_pktmbuf_free(mbuf);
509 : 0 : return -1;
510 : : }
511 : 0 : *m = mbuf;
512 : 0 : return 0;
513 : : }
514 : :
515 : : /*
516 : : * Callback to handle writing packets to a pcap file.
517 : : */
518 : : static uint16_t
519 : 13 : eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
520 : : {
521 : : struct pcap_tx_queue *dumper_q = queue;
522 : 13 : struct rte_eth_dev *dev = &rte_eth_devices[dumper_q->port_id];
523 : 13 : struct pmd_internals *internals = dev->data->dev_private;
524 : 13 : struct pmd_process_private *pp = dev->process_private;
525 : 13 : pcap_dumper_t *dumper = pp->tx_dumper[dumper_q->queue_id];
526 : 13 : unsigned char *temp_data = dumper_q->bounce_buf;
527 : 13 : uint32_t snaplen = internals->snapshot_len;
528 : : uint16_t num_tx = 0;
529 : : uint32_t tx_bytes = 0;
530 : : struct pcap_pkthdr header;
531 : : unsigned int i;
532 : :
533 [ + - ]: 13 : if (unlikely(dumper == NULL))
534 : : return 0;
535 : :
536 : : /* all packets in burst have same timestamp */
537 : 13 : calculate_timestamp(&header.ts);
538 : :
539 : : /* writes the nb_pkts packets to the previously opened pcap file dumper */
540 [ + + ]: 418 : for (i = 0; i < nb_pkts; i++) {
541 : 405 : struct rte_mbuf *mbuf = bufs[i];
542 : : uint32_t len, caplen;
543 : : const uint8_t *data;
544 : :
545 : : /* Do VLAN tag insertion */
546 [ - + ]: 405 : if (unlikely(mbuf->ol_flags & RTE_MBUF_F_TX_VLAN)) {
547 [ # # ]: 0 : if (pcap_tx_vlan_insert(&mbuf) != 0) {
548 : 0 : dumper_q->tx_stat.err_pkts++;
549 : 0 : continue;
550 : : }
551 : 0 : bufs[i] = mbuf;
552 : : }
553 : :
554 : 405 : len = rte_pktmbuf_pkt_len(mbuf);
555 : 405 : caplen = RTE_MIN(len, snaplen);
556 : :
557 : 405 : header.len = len;
558 [ + + ]: 405 : header.caplen = caplen;
559 : :
560 : : data = rte_pktmbuf_read(mbuf, 0, caplen, temp_data);
561 : :
562 : : /* This could only happen if mbuf is bogus pkt_len > data_len */
563 : : RTE_ASSERT(data != NULL);
564 : 405 : pcap_dump((u_char *)dumper, &header, data);
565 : :
566 : 405 : num_tx++;
567 : 405 : tx_bytes += caplen;
568 : :
569 : 405 : rte_pktmbuf_free(mbuf);
570 : : }
571 : :
572 : : /*
573 : : * Since there's no place to hook a callback when the forwarding
574 : : * process stops and to make sure the pcap file is actually written,
575 : : * we flush the pcap dumper within each burst.
576 : : */
577 : 13 : pcap_dump_flush(dumper);
578 : 13 : dumper_q->tx_stat.pkts += num_tx;
579 : 13 : dumper_q->tx_stat.bytes += tx_bytes;
580 : :
581 : 13 : return i;
582 : : }
583 : :
584 : : /*
585 : : * Callback to handle dropping packets in the infinite rx case.
586 : : */
587 : : static uint16_t
588 : 1 : eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
589 : : {
590 : : unsigned int i;
591 : : uint32_t tx_bytes = 0;
592 : : struct pcap_tx_queue *tx_queue = queue;
593 : :
594 [ + + ]: 65 : for (i = 0; i < nb_pkts; i++) {
595 : 64 : tx_bytes += bufs[i]->pkt_len;
596 : 64 : rte_pktmbuf_free(bufs[i]);
597 : : }
598 : :
599 : 1 : tx_queue->tx_stat.pkts += nb_pkts;
600 : 1 : tx_queue->tx_stat.bytes += tx_bytes;
601 : :
602 : 1 : return nb_pkts;
603 : : }
604 : :
605 : : /*
606 : : * Send a burst of packets to a pcap device.
607 : : *
608 : : * On Linux, pcap_sendpacket() calls send() on a blocking PF_PACKET
609 : : * socket with default kernel buffer sizes and no TX ring (PACKET_TX_RING).
610 : : * The send() call only blocks when the kernel socket send buffer is full,
611 : : * providing limited backpressure.
612 : : *
613 : : * On error, pcap_sendpacket() returns non-zero and the loop breaks,
614 : : * leaving remaining packets unsent.
615 : : *
616 : : * Bottom line: backpressure is not an error.
617 : : */
618 : : static uint16_t
619 : 3 : eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
620 : : {
621 : : struct pcap_tx_queue *tx_queue = queue;
622 : 3 : struct rte_eth_dev *dev = &rte_eth_devices[tx_queue->port_id];
623 : 3 : struct pmd_process_private *pp = dev->process_private;
624 : 3 : struct pmd_internals *internals = dev->data->dev_private;
625 : 3 : uint32_t snaplen = internals->snapshot_len;
626 : 3 : pcap_t *pcap = pp->tx_pcap[tx_queue->queue_id];
627 : 3 : unsigned char *temp_data = tx_queue->bounce_buf;
628 : : uint16_t num_tx = 0;
629 : : uint32_t tx_bytes = 0;
630 : : unsigned int i;
631 : :
632 [ + - ]: 3 : if (unlikely(pcap == NULL))
633 : : return 0;
634 : :
635 [ + + ]: 99 : for (i = 0; i < nb_pkts; i++) {
636 : 96 : struct rte_mbuf *mbuf = bufs[i];
637 : : uint32_t len;
638 : : const uint8_t *data;
639 : :
640 : : /* Do VLAN tag insertion */
641 [ - + ]: 96 : if (unlikely(mbuf->ol_flags & RTE_MBUF_F_TX_VLAN)) {
642 [ # # ]: 0 : if (pcap_tx_vlan_insert(&mbuf) != 0) {
643 : 0 : tx_queue->tx_stat.err_pkts++;
644 : 0 : continue;
645 : : }
646 : 0 : bufs[i] = mbuf;
647 : : }
648 : :
649 [ - + ]: 96 : len = rte_pktmbuf_pkt_len(mbuf);
650 : :
651 : : /*
652 : : * multi-segment transmit that has to go through bounce buffer.
653 : : * Make sure it fits; don't want to truncate the packet.
654 : : */
655 [ - + - - ]: 96 : if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) && len > snaplen)) {
656 : : PMD_TX_LOG(ERR, "Multi segment len (%u) > snaplen (%u)",
657 : : len, snaplen);
658 : 0 : rte_pktmbuf_free(mbuf);
659 : 0 : tx_queue->tx_stat.err_pkts++;
660 : 0 : continue;
661 : : }
662 : :
663 : : data = rte_pktmbuf_read(mbuf, 0, len, temp_data);
664 : : RTE_ASSERT(data != NULL);
665 : :
666 [ - + ]: 96 : if (unlikely(pcap_sendpacket(pcap, data, len) != 0)) {
667 : : /* Assume failure is backpressure */
668 : 0 : PMD_LOG(ERR, "pcap_sendpacket() failed: %s", pcap_geterr(pcap));
669 : 0 : break;
670 : : }
671 : 96 : num_tx++;
672 : 96 : tx_bytes += len;
673 : 96 : rte_pktmbuf_free(mbuf);
674 : : }
675 : :
676 : 3 : tx_queue->tx_stat.pkts += num_tx;
677 : 3 : tx_queue->tx_stat.bytes += tx_bytes;
678 : :
679 : 3 : return i;
680 : : }
681 : :
682 : : /*
683 : : * pcap_open_live wrapper function
684 : : */
685 : : static inline int
686 : 7 : open_iface_live(const char *iface, pcap_t **pcap, uint32_t snaplen)
687 : : {
688 : : char errbuf[PCAP_ERRBUF_SIZE];
689 : : pcap_t *pc;
690 : : int status;
691 : :
692 : 7 : pc = pcap_create(iface, errbuf);
693 [ - + ]: 7 : if (pc == NULL) {
694 : 0 : PMD_LOG(ERR, "Couldn't create %s: %s", iface, errbuf);
695 : 0 : goto error;
696 : : }
697 : :
698 : 7 : status = pcap_set_tstamp_precision(pc, PCAP_TSTAMP_PRECISION_NANO);
699 [ - + ]: 7 : if (status != 0) {
700 : 0 : PMD_LOG(ERR, "%s: Could not set to ns precision: %s",
701 : : iface, pcap_statustostr(status));
702 : 0 : goto error;
703 : : }
704 : :
705 : 7 : status = pcap_set_immediate_mode(pc, 1);
706 [ - + ]: 7 : if (status != 0)
707 : 0 : PMD_LOG(WARNING, "%s: Could not set to immediate mode: %s",
708 : : iface, pcap_statustostr(status));
709 : :
710 : 7 : status = pcap_set_promisc(pc, 1);
711 [ - + ]: 7 : if (status != 0)
712 : 0 : PMD_LOG(WARNING, "%s: Could not set to promiscuous: %s",
713 : : iface, pcap_statustostr(status));
714 : :
715 : 7 : status = pcap_set_snaplen(pc, snaplen);
716 [ - + ]: 7 : if (status != 0)
717 : 0 : PMD_LOG(WARNING, "%s: Could not set snapshot length: %s",
718 : : iface, pcap_statustostr(status));
719 : :
720 : 7 : status = pcap_activate(pc);
721 [ - + ]: 7 : if (status < 0) {
722 : 0 : char *cp = pcap_geterr(pc);
723 : :
724 [ # # ]: 0 : if (status == PCAP_ERROR)
725 : 0 : PMD_LOG(ERR, "%s: could not activate: %s", iface, cp);
726 : : else
727 : 0 : PMD_LOG(ERR, "%s: %s (%s)", iface, pcap_statustostr(status), cp);
728 : 0 : goto error;
729 [ - + ]: 7 : } else if (status > 0) {
730 : : /* Warning condition - log but continue */
731 : 0 : PMD_LOG(WARNING, "%s: %s", iface, pcap_statustostr(status));
732 : : }
733 : :
734 : : /*
735 : : * Verify interface supports Ethernet link type.
736 : : * Loopback on FreeBSD/macOS uses DLT_NULL which expects a 4-byte
737 : : * address family header instead of Ethernet, causing kernel warnings.
738 : : */
739 [ - + ]: 7 : if (pcap_datalink(pc) != DLT_EN10MB) {
740 : 0 : PMD_LOG(ERR, "%s: not Ethernet (link type %d)",
741 : : iface, pcap_datalink(pc));
742 : 0 : goto error;
743 : : }
744 : :
745 [ - + ]: 7 : if (pcap_setnonblock(pc, 1, errbuf)) {
746 : 0 : PMD_LOG(ERR, "Couldn't set non-blocking on %s: %s", iface, errbuf);
747 : 0 : goto error;
748 : : }
749 : :
750 : 7 : *pcap = pc;
751 : 7 : return 0;
752 : :
753 : 0 : error:
754 [ # # ]: 0 : if (pc != NULL)
755 : 0 : pcap_close(pc);
756 : : return -1;
757 : : }
758 : :
759 : : static int
760 : 7 : open_single_iface(const char *iface, pcap_t **pcap, uint32_t snaplen)
761 : : {
762 [ - + ]: 7 : if (open_iface_live(iface, pcap, snaplen) < 0) {
763 : 0 : PMD_LOG(ERR, "Couldn't open interface %s", iface);
764 : 0 : return -1;
765 : : }
766 : :
767 : : return 0;
768 : : }
769 : :
770 : : static int
771 : 14 : open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper,
772 : : uint32_t snaplen)
773 : : {
774 : : pcap_t *tx_pcap;
775 : :
776 : : /*
777 : : * We need to create a dummy empty pcap_t to use it
778 : : * with pcap_dump_open(). We create big enough an Ethernet
779 : : * pcap holder.
780 : : */
781 : 14 : tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
782 : : snaplen, PCAP_TSTAMP_PRECISION_NANO);
783 [ - + ]: 14 : if (tx_pcap == NULL) {
784 : 0 : PMD_LOG(ERR, "Couldn't create dead pcap");
785 : 0 : return -1;
786 : : }
787 : :
788 : : /* The dumper is created using the previous pcap_t reference */
789 : 14 : *dumper = pcap_dump_open(tx_pcap, pcap_filename);
790 [ - + ]: 14 : if (*dumper == NULL) {
791 : 0 : PMD_LOG(ERR, "Couldn't open %s for writing: %s",
792 : : pcap_filename, pcap_geterr(tx_pcap));
793 : 0 : pcap_close(tx_pcap);
794 : 0 : return -1;
795 : : }
796 : :
797 : 14 : pcap_close(tx_pcap);
798 : 14 : return 0;
799 : : }
800 : :
801 : : static int
802 : 25 : open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
803 : : {
804 : : char errbuf[PCAP_ERRBUF_SIZE];
805 : :
806 : 25 : *pcap = pcap_open_offline_with_tstamp_precision(pcap_filename,
807 : : PCAP_TSTAMP_PRECISION_NANO, errbuf);
808 [ - + ]: 25 : if (*pcap == NULL) {
809 : 0 : PMD_LOG(ERR, "Couldn't open %s: %s", pcap_filename,
810 : : errbuf);
811 : 0 : return -1;
812 : : }
813 : :
814 : : return 0;
815 : : }
816 : :
817 : : static uint64_t
818 : 2 : count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue *pcap_q)
819 : : {
820 : : const u_char *packet;
821 : : struct pcap_pkthdr header;
822 : : uint64_t pcap_pkt_count = 0;
823 : :
824 [ + + ]: 130 : while ((packet = pcap_next(*pcap, &header)))
825 : 128 : pcap_pkt_count++;
826 : :
827 : : /* The pcap is reopened so it can be used as normal later. */
828 : 2 : pcap_close(*pcap);
829 : 2 : *pcap = NULL;
830 : 2 : open_single_rx_pcap(pcap_q->name, pcap);
831 : :
832 : 2 : return pcap_pkt_count;
833 : : }
834 : :
835 : : /*
836 : : * Periodic alarm to poll link state.
837 : : * Enabled when link state interrupt is enabled in single_iface mode.
838 : : */
839 : : static void
840 : 0 : eth_pcap_lsc_alarm(void *arg)
841 : : {
842 : : struct rte_eth_dev *dev = arg;
843 : 0 : struct pmd_internals *internals = dev->data->dev_private;
844 : : struct rte_eth_link old_link, new_link;
845 : :
846 : 0 : rte_eth_linkstatus_get(dev, &old_link);
847 : 0 : eth_link_update(dev, 0);
848 : 0 : rte_eth_linkstatus_get(dev, &new_link);
849 : :
850 [ # # ]: 0 : if (old_link.link_status != new_link.link_status)
851 : 0 : rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
852 : :
853 [ # # ]: 0 : if (internals->lsc_active)
854 : 0 : rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US, eth_pcap_lsc_alarm, dev);
855 : 0 : }
856 : :
857 : : static int
858 : 1 : set_iface_direction(const char *iface, pcap_t *pcap,
859 : : pcap_direction_t direction)
860 : : {
861 [ - + ]: 1 : const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
862 [ - + ]: 1 : if (pcap_setdirection(pcap, direction) < 0) {
863 : 0 : PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s",
864 : : iface, direction_str, pcap_geterr(pcap));
865 : 0 : return -1;
866 : : }
867 : 1 : PMD_LOG(INFO, "Setting %s pcap direction %s",
868 : : iface, direction_str);
869 : 1 : return 0;
870 : : }
871 : :
872 : : static int
873 : 26 : eth_dev_start(struct rte_eth_dev *dev)
874 : : {
875 : : unsigned int i;
876 : 26 : struct pmd_internals *internals = dev->data->dev_private;
877 : 26 : struct pmd_process_private *pp = dev->process_private;
878 : : struct pcap_tx_queue *tx;
879 : : struct pcap_rx_queue *rx;
880 : 26 : uint32_t snaplen = internals->snapshot_len;
881 : :
882 : : /* Special iface case. Single pcap is open and shared between tx/rx. */
883 [ + + ]: 26 : if (internals->single_iface) {
884 : : tx = &internals->tx_queue[0];
885 : : rx = &internals->rx_queue[0];
886 : :
887 [ - + - - ]: 3 : if (!pp->tx_pcap[0] && strcmp(tx->type, ETH_PCAP_IFACE_ARG) == 0) {
888 [ # # ]: 0 : if (open_single_iface(tx->name, &pp->tx_pcap[0], snaplen) < 0)
889 : : return -1;
890 : 0 : pp->rx_pcap[0] = pp->tx_pcap[0];
891 : : }
892 : :
893 : 3 : goto status_up;
894 : : }
895 : :
896 : : /* If not open already, open tx pcaps/dumpers */
897 [ + + ]: 48 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
898 : : tx = &internals->tx_queue[i];
899 : :
900 [ + + - + ]: 25 : if (!pp->tx_dumper[i] && strcmp(tx->type, ETH_PCAP_TX_PCAP_ARG) == 0) {
901 [ # # ]: 0 : if (open_single_tx_pcap(tx->name, &pp->tx_dumper[i], snaplen) < 0)
902 : : return -1;
903 [ + + - + ]: 25 : } else if (!pp->tx_pcap[i] && strcmp(tx->type, ETH_PCAP_TX_IFACE_ARG) == 0) {
904 [ # # ]: 0 : if (open_single_iface(tx->name, &pp->tx_pcap[i], snaplen) < 0)
905 : : return -1;
906 : : }
907 : : }
908 : :
909 : : /* If not open already, open rx pcaps */
910 [ + + ]: 48 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
911 : : rx = &internals->rx_queue[i];
912 : :
913 [ + + ]: 25 : if (pp->rx_pcap[i] != NULL)
914 : 19 : continue;
915 : :
916 [ + + ]: 6 : if (strcmp(rx->type, ETH_PCAP_RX_PCAP_ARG) == 0) {
917 [ + - ]: 1 : if (open_single_rx_pcap(rx->name, &pp->rx_pcap[i]) < 0)
918 : : return -1;
919 [ + - ]: 5 : } else if (strcmp(rx->type, ETH_PCAP_RX_IFACE_ARG) == 0 ||
920 [ - + ]: 5 : strcmp(rx->type, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
921 [ # # ]: 0 : if (open_single_iface(rx->name, &pp->rx_pcap[i], snaplen) < 0)
922 : : return -1;
923 : : /* Set direction for rx_iface_in */
924 [ # # ]: 0 : if (strcmp(rx->type, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
925 : 0 : set_iface_direction(rx->name, pp->rx_pcap[i],
926 : : PCAP_D_IN);
927 : : }
928 : : }
929 : :
930 : 23 : status_up:
931 [ + + ]: 54 : for (i = 0; i < dev->data->nb_rx_queues; i++)
932 : 28 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
933 : :
934 [ + + ]: 54 : for (i = 0; i < dev->data->nb_tx_queues; i++)
935 : 28 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
936 : :
937 : 26 : rte_atomic_store_explicit(&internals->eof_signaled, false, rte_memory_order_relaxed);
938 : 26 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
939 : :
940 : : /* Start LSC polling for iface mode if application requested it */
941 [ + + - + ]: 26 : if (internals->single_iface && dev->data->dev_conf.intr_conf.lsc) {
942 : 0 : internals->lsc_active = true;
943 : 0 : rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US,
944 : : eth_pcap_lsc_alarm, dev);
945 : : }
946 : :
947 : : return 0;
948 : : }
949 : :
950 : : /*
951 : : * This function gets called when the current port gets stopped.
952 : : * Is the only place for us to close all the tx streams dumpers.
953 : : * If not called the dumpers will be flushed within each tx burst.
954 : : */
955 : : static int
956 : 54 : eth_dev_stop(struct rte_eth_dev *dev)
957 : : {
958 : : unsigned int i;
959 : 54 : struct pmd_internals *internals = dev->data->dev_private;
960 : 54 : struct pmd_process_private *pp = dev->process_private;
961 : : bool expected;
962 : :
963 : : /* Special iface case. Single pcap is open and shared between tx/rx. */
964 [ + + ]: 54 : if (internals->single_iface) {
965 : : /* Cancel LSC polling before closing pcap handles */
966 [ - + ]: 6 : if (internals->lsc_active) {
967 : 0 : internals->lsc_active = false;
968 : 0 : rte_eal_alarm_cancel(eth_pcap_lsc_alarm, dev);
969 : : }
970 : :
971 : : queue_missed_stat_on_stop_update(dev, 0);
972 [ + + ]: 6 : if (pp->tx_pcap[0] != NULL) {
973 : 3 : pcap_close(pp->tx_pcap[0]);
974 : 3 : pp->tx_pcap[0] = NULL;
975 : 3 : pp->rx_pcap[0] = NULL;
976 : : }
977 : 6 : goto status_down;
978 : : }
979 : :
980 [ + + ]: 101 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
981 [ + + ]: 53 : if (pp->tx_dumper[i] != NULL) {
982 : 14 : pcap_dump_close(pp->tx_dumper[i]);
983 : 14 : pp->tx_dumper[i] = NULL;
984 : : }
985 : :
986 [ + + ]: 53 : if (pp->tx_pcap[i] != NULL) {
987 : 2 : pcap_close(pp->tx_pcap[i]);
988 : 2 : pp->tx_pcap[i] = NULL;
989 : : }
990 : : }
991 : :
992 [ + + ]: 102 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
993 [ + + ]: 54 : if (pp->rx_pcap[i] != NULL) {
994 : : queue_missed_stat_on_stop_update(dev, i);
995 : 25 : pcap_close(pp->rx_pcap[i]);
996 : 25 : pp->rx_pcap[i] = NULL;
997 : : }
998 : : }
999 : :
1000 : 48 : status_down:
1001 : : /* Cancel any pending EOF alarm */
1002 : 54 : expected = true;
1003 [ + + ]: 54 : if (rte_atomic_compare_exchange_strong_explicit(
1004 : : &internals->eof_signaled, &expected, false,
1005 : : rte_memory_order_relaxed, rte_memory_order_relaxed))
1006 : 2 : rte_eal_alarm_cancel(eth_pcap_eof_alarm, dev);
1007 : :
1008 [ + + ]: 114 : for (i = 0; i < dev->data->nb_rx_queues; i++)
1009 : 60 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1010 : :
1011 [ + + ]: 113 : for (i = 0; i < dev->data->nb_tx_queues; i++)
1012 : 59 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
1013 : :
1014 : 54 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
1015 : :
1016 : 54 : return 0;
1017 : : }
1018 : :
1019 : : static int
1020 : 25 : eth_dev_configure(struct rte_eth_dev *dev)
1021 : : {
1022 : 25 : struct pmd_internals *internals = dev->data->dev_private;
1023 : : struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
1024 : : const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;
1025 : :
1026 : 25 : internals->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
1027 : 25 : internals->rx_scatter = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER);
1028 : 25 : internals->timestamp_offloading = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP);
1029 : :
1030 [ + + + + ]: 25 : if (internals->timestamp_offloading && timestamp_rx_dynflag == 0) {
1031 : 1 : int ret = rte_mbuf_dyn_rx_timestamp_register(×tamp_dynfield_offset,
1032 : : ×tamp_rx_dynflag);
1033 [ - + ]: 1 : if (ret != 0) {
1034 : 0 : PMD_LOG(ERR, "Failed to register Rx timestamp field/flag");
1035 : 0 : return ret;
1036 : : }
1037 : : }
1038 : :
1039 : : return 0;
1040 : : }
1041 : :
1042 : : static int
1043 : 110 : eth_dev_info(struct rte_eth_dev *dev,
1044 : : struct rte_eth_dev_info *dev_info)
1045 : : {
1046 : 110 : struct pmd_internals *internals = dev->data->dev_private;
1047 : :
1048 : 110 : dev_info->if_index = internals->if_index;
1049 : 110 : dev_info->max_mac_addrs = 1;
1050 : 110 : dev_info->max_rx_pktlen = internals->snapshot_len;
1051 : 110 : dev_info->max_rx_queues = dev->data->nb_rx_queues;
1052 : 110 : dev_info->max_tx_queues = dev->data->nb_tx_queues;
1053 : 110 : dev_info->min_rx_bufsize = RTE_ETHER_MIN_LEN;
1054 : 110 : dev_info->max_mtu = internals->snapshot_len - RTE_ETHER_HDR_LEN;
1055 : 110 : dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
1056 : : RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
1057 : 110 : dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
1058 : : RTE_ETH_RX_OFFLOAD_TIMESTAMP;
1059 : :
1060 [ + + ]: 110 : if (!internals->infinite_rx)
1061 : 102 : dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SCATTER;
1062 : :
1063 : 110 : return 0;
1064 : : }
1065 : :
1066 : : static int
1067 : 8 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
1068 : : struct eth_queue_stats *qstats)
1069 : : {
1070 : : unsigned int i;
1071 : : unsigned long rx_packets_total = 0, rx_bytes_total = 0;
1072 : : unsigned long rx_missed_total = 0;
1073 : : unsigned long rx_nombuf_total = 0, rx_err_total = 0;
1074 : : unsigned long tx_packets_total = 0, tx_bytes_total = 0;
1075 : : unsigned long tx_packets_err_total = 0;
1076 : 8 : const struct pmd_internals *internal = dev->data->dev_private;
1077 : :
1078 [ + - ]: 16 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
1079 [ + + ]: 16 : i < dev->data->nb_rx_queues; i++) {
1080 [ - + ]: 8 : if (qstats != NULL) {
1081 : 0 : qstats->q_ipackets[i] = internal->rx_queue[i].rx_stat.pkts;
1082 : 0 : qstats->q_ibytes[i] = internal->rx_queue[i].rx_stat.bytes;
1083 : : }
1084 : 8 : rx_nombuf_total += internal->rx_queue[i].rx_stat.rx_nombuf;
1085 : 8 : rx_err_total += internal->rx_queue[i].rx_stat.err_pkts;
1086 : 8 : rx_packets_total += internal->rx_queue[i].rx_stat.pkts;
1087 : 8 : rx_bytes_total += internal->rx_queue[i].rx_stat.bytes;
1088 : 8 : rx_missed_total += queue_missed_stat_get(dev, i);
1089 : : }
1090 : :
1091 [ + - ]: 16 : for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
1092 [ + + ]: 16 : i < dev->data->nb_tx_queues; i++) {
1093 [ - + ]: 8 : if (qstats != NULL) {
1094 : 0 : qstats->q_opackets[i] = internal->tx_queue[i].tx_stat.pkts;
1095 : 0 : qstats->q_obytes[i] = internal->tx_queue[i].tx_stat.bytes;
1096 : : }
1097 : 8 : tx_packets_total += internal->tx_queue[i].tx_stat.pkts;
1098 : 8 : tx_bytes_total += internal->tx_queue[i].tx_stat.bytes;
1099 : 8 : tx_packets_err_total += internal->tx_queue[i].tx_stat.err_pkts;
1100 : : }
1101 : :
1102 : 8 : stats->ipackets = rx_packets_total;
1103 : 8 : stats->ibytes = rx_bytes_total;
1104 : 8 : stats->imissed = rx_missed_total;
1105 : 8 : stats->ierrors = rx_err_total;
1106 : 8 : stats->rx_nombuf = rx_nombuf_total;
1107 : 8 : stats->opackets = tx_packets_total;
1108 : 8 : stats->obytes = tx_bytes_total;
1109 : 8 : stats->oerrors = tx_packets_err_total;
1110 : :
1111 : 8 : return 0;
1112 : : }
1113 : :
1114 : : static int
1115 : 5 : eth_stats_reset(struct rte_eth_dev *dev)
1116 : : {
1117 : : unsigned int i;
1118 : 5 : struct pmd_internals *internal = dev->data->dev_private;
1119 : :
1120 [ + + ]: 10 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1121 : 5 : internal->rx_queue[i].rx_stat.pkts = 0;
1122 : 5 : internal->rx_queue[i].rx_stat.bytes = 0;
1123 : 5 : internal->rx_queue[i].rx_stat.err_pkts = 0;
1124 : 5 : internal->rx_queue[i].rx_stat.rx_nombuf = 0;
1125 : : queue_missed_stat_reset(dev, i);
1126 : : }
1127 : :
1128 [ + + ]: 10 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1129 : 5 : internal->tx_queue[i].tx_stat.pkts = 0;
1130 : 5 : internal->tx_queue[i].tx_stat.bytes = 0;
1131 : 5 : internal->tx_queue[i].tx_stat.err_pkts = 0;
1132 : : }
1133 : :
1134 : 5 : return 0;
1135 : : }
1136 : :
1137 : : static inline void
1138 : 2 : infinite_rx_ring_free(struct rte_ring *pkts)
1139 : : {
1140 : : struct rte_mbuf *bufs;
1141 : :
1142 : 2 : while (!rte_ring_dequeue(pkts, (void **)&bufs))
1143 : 128 : rte_pktmbuf_free(bufs);
1144 : :
1145 : 2 : rte_ring_free(pkts);
1146 : 2 : }
1147 : :
1148 : : static int
1149 : 28 : eth_dev_close(struct rte_eth_dev *dev)
1150 : : {
1151 : : unsigned int i;
1152 : 28 : struct pmd_internals *internals = dev->data->dev_private;
1153 : :
1154 : 28 : PMD_LOG(INFO, "Closing pcap ethdev on NUMA socket %d",
1155 : : rte_socket_id());
1156 : :
1157 : 28 : eth_dev_stop(dev);
1158 : :
1159 : 28 : rte_free(dev->process_private);
1160 : :
1161 [ + - ]: 28 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1162 : : return 0;
1163 : :
1164 : : /* Device wide flag, but cleanup must be performed per queue. */
1165 [ + + ]: 28 : if (internals->infinite_rx) {
1166 [ + + ]: 4 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
1167 : : struct pcap_rx_queue *pcap_q = &internals->rx_queue[i];
1168 : :
1169 : : /*
1170 : : * 'pcap_q->pkts' can be NULL if 'eth_dev_close()'
1171 : : * called before 'eth_rx_queue_setup()' has been called
1172 : : */
1173 [ - + ]: 2 : if (pcap_q->pkts == NULL)
1174 : 0 : continue;
1175 : :
1176 : 2 : infinite_rx_ring_free(pcap_q->pkts);
1177 : : }
1178 : : }
1179 : :
1180 [ + - ]: 28 : if (!internals->phy_mac)
1181 : : /* not dynamically allocated, must not be freed */
1182 : 28 : dev->data->mac_addrs = NULL;
1183 : :
1184 : : return 0;
1185 : : }
1186 : :
1187 : : static int
1188 : 31 : eth_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
1189 : : {
1190 : 31 : struct pmd_internals *internals = dev->data->dev_private;
1191 : 31 : struct rte_eth_link link = {
1192 : : .link_speed = RTE_ETH_SPEED_NUM_10G,
1193 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
1194 : : .link_autoneg = RTE_ETH_LINK_FIXED,
1195 : : };
1196 : :
1197 : : /*
1198 : : * For pass-through mode (single_iface), query whether the
1199 : : * underlying interface is up. Otherwise use default values.
1200 : : */
1201 [ + + ]: 31 : if (internals->single_iface) {
1202 : 5 : link.link_status = (osdep_iface_link_status(internals->rx_queue[0].name) > 0) ?
1203 : 5 : RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN;
1204 [ + + ]: 26 : } else if (rte_atomic_load_explicit(&internals->eof_signaled, rte_memory_order_relaxed)) {
1205 : : link.link_status = RTE_ETH_LINK_DOWN;
1206 : : } else {
1207 : 24 : link.link_status = dev->data->dev_started ? RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN;
1208 : : }
1209 : :
1210 : 31 : return rte_eth_linkstatus_set(dev, &link);
1211 : : }
1212 : :
1213 : : static int
1214 : 27 : eth_rx_queue_setup(struct rte_eth_dev *dev,
1215 : : uint16_t rx_queue_id,
1216 : : uint16_t nb_rx_desc __rte_unused,
1217 : : unsigned int socket_id __rte_unused,
1218 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
1219 : : struct rte_mempool *mb_pool)
1220 : : {
1221 : 27 : struct pmd_internals *internals = dev->data->dev_private;
1222 [ + - ]: 27 : struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
1223 : : uint16_t buf_size;
1224 : : bool rx_scatter;
1225 : :
1226 : 27 : buf_size = rte_pktmbuf_data_room_size(mb_pool) - RTE_PKTMBUF_HEADROOM;
1227 : 27 : rx_scatter = !!(dev->data->dev_conf.rxmode.offloads &
1228 : : RTE_ETH_RX_OFFLOAD_SCATTER);
1229 : :
1230 : : /*
1231 : : * If Rx scatter is not enabled, verify that the mbuf data room
1232 : : * can hold the largest received packet in a single segment.
1233 : : * Use the MTU-derived frame size as the expected maximum, not
1234 : : * snapshot_len which is a capture truncation limit rather than
1235 : : * an expected packet size.
1236 : : */
1237 [ + + ]: 27 : if (!rx_scatter) {
1238 : 25 : uint32_t max_rx_pktlen = dev->data->mtu + RTE_ETHER_HDR_LEN;
1239 : :
1240 [ - + ]: 25 : if (max_rx_pktlen > buf_size) {
1241 : 0 : PMD_LOG(ERR,
1242 : : "Rx scatter is disabled and RxQ mbuf pool object size is too small "
1243 : : "(buf_size=%u, max_rx_pkt_len=%u)",
1244 : : buf_size, max_rx_pktlen);
1245 : 0 : return -EINVAL;
1246 : : }
1247 : : }
1248 : :
1249 : 27 : pcap_q->mb_pool = mb_pool;
1250 : 27 : pcap_q->port_id = dev->data->port_id;
1251 : 27 : pcap_q->queue_id = rx_queue_id;
1252 : 27 : pcap_q->vlan_strip = internals->vlan_strip;
1253 : 27 : pcap_q->rx_scatter = rx_scatter;
1254 : 27 : dev->data->rx_queues[rx_queue_id] = pcap_q;
1255 : 27 : pcap_q->timestamp_offloading = internals->timestamp_offloading;
1256 : :
1257 [ + + ]: 27 : if (internals->infinite_rx) {
1258 : : struct pmd_process_private *pp;
1259 : : char ring_name[RTE_RING_NAMESIZE];
1260 : : static uint32_t ring_number;
1261 : : uint64_t pcap_pkt_count = 0;
1262 : : struct rte_mbuf *bufs[1];
1263 : : pcap_t **pcap;
1264 : : bool save_vlan_strip;
1265 : :
1266 [ - + ]: 2 : if (rx_scatter) {
1267 : 0 : PMD_LOG(ERR,
1268 : : "Rx scatter is not supported with infinite_rx mode");
1269 : 0 : return -EINVAL;
1270 : : }
1271 : :
1272 : 2 : pp = rte_eth_devices[pcap_q->port_id].process_private;
1273 : 2 : pcap = &pp->rx_pcap[pcap_q->queue_id];
1274 : :
1275 [ + - ]: 2 : if (unlikely(*pcap == NULL))
1276 : : return -ENOENT;
1277 : :
1278 : 2 : pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
1279 : :
1280 : 2 : snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
1281 : : ring_number);
1282 : :
1283 : 2 : pcap_q->pkts = rte_ring_create(ring_name,
1284 : : rte_align64pow2(pcap_pkt_count + 1), 0,
1285 : : RING_F_SP_ENQ | RING_F_SC_DEQ);
1286 : 2 : ring_number++;
1287 [ + - ]: 2 : if (!pcap_q->pkts)
1288 : : return -ENOENT;
1289 : :
1290 : : /*
1291 : : * Temporarily disable offloads while filling the ring
1292 : : * with raw packets. VLAN strip and timestamp will be
1293 : : * applied later in eth_pcap_rx_infinite() on each copy.
1294 : : */
1295 : 2 : save_vlan_strip = pcap_q->vlan_strip;
1296 : 2 : pcap_q->vlan_strip = false;
1297 : :
1298 : : /* Fill ring with packets from PCAP file one by one. */
1299 [ + + ]: 132 : while (eth_pcap_rx(pcap_q, bufs, 1)) {
1300 : : /* Check for multiseg mbufs. */
1301 [ - + ]: 128 : if (bufs[0]->nb_segs != 1) {
1302 : 0 : infinite_rx_ring_free(pcap_q->pkts);
1303 : 0 : pcap_q->vlan_strip = save_vlan_strip;
1304 : 0 : PMD_LOG(ERR,
1305 : : "Multiseg mbufs are not supported in infinite_rx mode.");
1306 : 0 : return -EINVAL;
1307 : : }
1308 : :
1309 [ - + - - : 128 : rte_ring_enqueue_bulk(pcap_q->pkts,
- ]
1310 : : (void * const *)bufs, 1, NULL);
1311 : : }
1312 : :
1313 : : /* Restore offloads for use during packet delivery */
1314 : 2 : pcap_q->vlan_strip = save_vlan_strip;
1315 : :
1316 [ - + ]: 2 : if (rte_ring_count(pcap_q->pkts) < pcap_pkt_count) {
1317 : 0 : infinite_rx_ring_free(pcap_q->pkts);
1318 : 0 : PMD_LOG(ERR,
1319 : : "Not enough mbufs to accommodate packets in pcap file. "
1320 : : "At least %" PRIu64 " mbufs per queue is required.",
1321 : : pcap_pkt_count);
1322 : 0 : return -EINVAL;
1323 : : }
1324 : :
1325 : : /*
1326 : : * Reset the stats for this queue since eth_pcap_rx calls above
1327 : : * didn't result in the application receiving packets.
1328 : : */
1329 : 2 : pcap_q->rx_stat.pkts = 0;
1330 : 2 : pcap_q->rx_stat.bytes = 0;
1331 : : }
1332 : :
1333 : : return 0;
1334 : : }
1335 : :
1336 : : static int
1337 : 27 : eth_tx_queue_setup(struct rte_eth_dev *dev,
1338 : : uint16_t tx_queue_id,
1339 : : uint16_t nb_tx_desc __rte_unused,
1340 : : unsigned int socket_id,
1341 : : const struct rte_eth_txconf *tx_conf __rte_unused)
1342 : : {
1343 : 27 : struct pmd_internals *internals = dev->data->dev_private;
1344 : 27 : struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
1345 : :
1346 : 27 : pcap_q->port_id = dev->data->port_id;
1347 : 27 : pcap_q->queue_id = tx_queue_id;
1348 : 27 : pcap_q->bounce_buf = rte_malloc_socket(NULL, internals->snapshot_len,
1349 : : RTE_CACHE_LINE_SIZE, socket_id);
1350 [ + - ]: 27 : if (pcap_q->bounce_buf == NULL)
1351 : : return -ENOMEM;
1352 : :
1353 : 27 : dev->data->tx_queues[tx_queue_id] = pcap_q;
1354 : :
1355 : 27 : return 0;
1356 : : }
1357 : :
1358 : : static void
1359 : 0 : eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t tx_queue_id)
1360 : : {
1361 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1362 : 0 : struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
1363 : :
1364 : 0 : rte_free(pcap_q->bounce_buf);
1365 : 0 : pcap_q->bounce_buf = NULL;
1366 : 0 : }
1367 : :
1368 : : static int
1369 : 1 : eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
1370 : : {
1371 : 1 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
1372 : :
1373 : 1 : return 0;
1374 : : }
1375 : :
1376 : : static int
1377 : 1 : eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
1378 : : {
1379 : 1 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
1380 : :
1381 : 1 : return 0;
1382 : : }
1383 : :
1384 : : static int
1385 : 1 : eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
1386 : : {
1387 : 1 : dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
1388 : :
1389 : 1 : return 0;
1390 : : }
1391 : :
1392 : : static int
1393 : 1 : eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
1394 : : {
1395 : 1 : dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
1396 : :
1397 : 1 : return 0;
1398 : : }
1399 : :
1400 : : /* Timestamp values in receive packets from libpcap are in nanoseconds */
1401 : : static int
1402 : 0 : eth_dev_read_clock(struct rte_eth_dev *dev __rte_unused, uint64_t *timestamp)
1403 : : {
1404 : : struct timespec cur_time;
1405 : :
1406 : 0 : timespec_get(&cur_time, TIME_UTC);
1407 : 0 : *timestamp = rte_timespec_to_ns(&cur_time);
1408 : 0 : return 0;
1409 : : }
1410 : :
1411 : : static int
1412 : 0 : eth_vlan_offload_set(struct rte_eth_dev *dev, int mask)
1413 : : {
1414 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1415 : : unsigned int i;
1416 : :
1417 [ # # ]: 0 : if (mask & RTE_ETH_VLAN_STRIP_MASK) {
1418 : 0 : bool vlan_strip = !!(dev->data->dev_conf.rxmode.offloads &
1419 : : RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
1420 : :
1421 : 0 : internals->vlan_strip = vlan_strip;
1422 : :
1423 : : /* Update all RX queues */
1424 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
1425 : 0 : internals->rx_queue[i].vlan_strip = vlan_strip;
1426 : : }
1427 : :
1428 : 0 : return 0;
1429 : : }
1430 : :
1431 : : static const struct eth_dev_ops ops = {
1432 : : .dev_start = eth_dev_start,
1433 : : .dev_stop = eth_dev_stop,
1434 : : .dev_close = eth_dev_close,
1435 : : .dev_configure = eth_dev_configure,
1436 : : .dev_infos_get = eth_dev_info,
1437 : : .read_clock = eth_dev_read_clock,
1438 : : .rx_queue_setup = eth_rx_queue_setup,
1439 : : .tx_queue_setup = eth_tx_queue_setup,
1440 : : .tx_queue_release = eth_tx_queue_release,
1441 : : .rx_queue_start = eth_rx_queue_start,
1442 : : .tx_queue_start = eth_tx_queue_start,
1443 : : .rx_queue_stop = eth_rx_queue_stop,
1444 : : .tx_queue_stop = eth_tx_queue_stop,
1445 : : .link_update = eth_link_update,
1446 : : .stats_get = eth_stats_get,
1447 : : .stats_reset = eth_stats_reset,
1448 : : .vlan_offload_set = eth_vlan_offload_set,
1449 : : };
1450 : :
1451 : : static int
1452 : : add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
1453 : : pcap_t *pcap, pcap_dumper_t *dumper)
1454 : : {
1455 [ + - + - ]: 25 : if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
1456 : : return -1;
1457 [ + - + - ]: 26 : if (pcap)
1458 : 26 : pmd->queue[pmd->num_of_queue].pcap = pcap;
1459 [ + - ]: 14 : if (dumper)
1460 : 14 : pmd->queue[pmd->num_of_queue].dumper = dumper;
1461 : 65 : pmd->queue[pmd->num_of_queue].name = name;
1462 : 65 : pmd->queue[pmd->num_of_queue].type = type;
1463 : 40 : pmd->num_of_queue++;
1464 : 25 : return 0;
1465 : : }
1466 : :
1467 : : /*
1468 : : * Function handler that opens the pcap file for reading a stores a
1469 : : * reference of it for use it later on.
1470 : : */
1471 : : static int
1472 : 22 : open_rx_pcap(const char *key, const char *value, void *extra_args)
1473 : : {
1474 : : const char *pcap_filename = value;
1475 : : struct pmd_devargs *rx = extra_args;
1476 : 22 : pcap_t *pcap = NULL;
1477 : :
1478 [ + - ]: 22 : if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
1479 : : return -1;
1480 : :
1481 [ - + ]: 22 : if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
1482 : 0 : pcap_close(pcap);
1483 : 0 : return -1;
1484 : : }
1485 : :
1486 : : return 0;
1487 : : }
1488 : :
1489 : : /*
1490 : : * Opens a pcap file for writing and stores a reference to it
1491 : : * for use it later on.
1492 : : */
1493 : : static int
1494 : 14 : open_tx_pcap(const char *key, const char *value, void *extra_args)
1495 : : {
1496 : : const char *pcap_filename = value;
1497 : : struct pmd_devargs *dumpers = extra_args;
1498 : : pcap_dumper_t *dumper;
1499 : :
1500 [ + - ]: 14 : if (open_single_tx_pcap(pcap_filename, &dumper,
1501 : : dumpers->snapshot_len) < 0)
1502 : : return -1;
1503 : :
1504 [ - + ]: 14 : if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
1505 : 0 : pcap_dump_close(dumper);
1506 : 0 : return -1;
1507 : : }
1508 : :
1509 : : return 0;
1510 : : }
1511 : :
1512 : : /*
1513 : : * Opens an interface for reading and writing
1514 : : */
1515 : : static inline int
1516 : 3 : open_rx_tx_iface(const char *key, const char *value, void *extra_args)
1517 : : {
1518 : : const char *iface = value;
1519 : : struct pmd_devargs *tx = extra_args;
1520 : 3 : pcap_t *pcap = NULL;
1521 : :
1522 [ + - ]: 3 : if (open_single_iface(iface, &pcap, tx->snapshot_len) < 0)
1523 : : return -1;
1524 : :
1525 : 3 : tx->queue[0].pcap = pcap;
1526 : 3 : tx->queue[0].name = iface;
1527 : 3 : tx->queue[0].type = key;
1528 : :
1529 : 3 : return 0;
1530 : : }
1531 : :
1532 : : static inline int
1533 : 4 : open_iface(const char *key, const char *value, void *extra_args)
1534 : : {
1535 : : const char *iface = value;
1536 : : struct pmd_devargs *pmd = extra_args;
1537 : 4 : pcap_t *pcap = NULL;
1538 : :
1539 [ + - ]: 4 : if (open_single_iface(iface, &pcap, pmd->snapshot_len) < 0)
1540 : : return -1;
1541 [ - + ]: 4 : if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
1542 : 0 : pcap_close(pcap);
1543 : 0 : return -1;
1544 : : }
1545 : :
1546 : : return 0;
1547 : : }
1548 : :
1549 : : /*
1550 : : * Opens a NIC for reading packets from it
1551 : : */
1552 : : static inline int
1553 : 2 : open_rx_iface(const char *key, const char *value, void *extra_args)
1554 : : {
1555 : 2 : int ret = open_iface(key, value, extra_args);
1556 [ + - ]: 2 : if (ret < 0)
1557 : : return ret;
1558 [ + + ]: 2 : if (strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
1559 : : struct pmd_devargs *pmd = extra_args;
1560 : 1 : unsigned int qid = pmd->num_of_queue - 1;
1561 : :
1562 : 1 : set_iface_direction(pmd->queue[qid].name,
1563 : : pmd->queue[qid].pcap,
1564 : : PCAP_D_IN);
1565 : : }
1566 : :
1567 : : return 0;
1568 : : }
1569 : :
1570 : : static inline int
1571 : 4 : rx_iface_args_process(const char *key, const char *value, void *extra_args)
1572 : : {
1573 [ + + ]: 4 : if (strcmp(key, ETH_PCAP_RX_IFACE_ARG) == 0 ||
1574 [ + + ]: 3 : strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
1575 : 2 : return open_rx_iface(key, value, extra_args);
1576 : :
1577 : : return 0;
1578 : : }
1579 : :
1580 : : /*
1581 : : * Opens a NIC for writing packets to it
1582 : : */
1583 : : static int
1584 : 2 : open_tx_iface(const char *key, const char *value, void *extra_args)
1585 : : {
1586 : 2 : return open_iface(key, value, extra_args);
1587 : : }
1588 : :
1589 : : static int
1590 : 5 : process_bool_flag(const char *key, const char *value, void *extra_args)
1591 : : {
1592 : : bool *flag = extra_args;
1593 : :
1594 [ + - - + ]: 5 : if (value == NULL || *value == '\0') {
1595 : 0 : *flag = true; /* default with no additional argument */
1596 [ - + ]: 5 : } else if (strcmp(value, "0") == 0) {
1597 : 0 : *flag = false;
1598 [ + - ]: 5 : } else if (strcmp(value, "1") == 0) {
1599 : 5 : *flag = true;
1600 : : } else {
1601 : 0 : PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
1602 : 0 : return -1;
1603 : : }
1604 : : return 0;
1605 : : }
1606 : :
1607 : : static int
1608 : 3 : process_snapshot_len(const char *key, const char *value, void *extra_args)
1609 : : {
1610 : : uint32_t *snaplen = extra_args;
1611 : : unsigned long val;
1612 : : char *endptr;
1613 : :
1614 [ + - - + ]: 3 : if (value == NULL || *value == '\0') {
1615 : 0 : PMD_LOG(ERR, "Argument '%s' requires a value", key);
1616 : 0 : return -1;
1617 : : }
1618 : :
1619 : 3 : errno = 0;
1620 : 3 : val = strtoul(value, &endptr, 10);
1621 [ + - + - ]: 3 : if (errno != 0 || *endptr != '\0' ||
1622 [ - + ]: 3 : val < RTE_ETHER_HDR_LEN ||
1623 : : val > ETH_PCAP_MAXIMUM_SNAPLEN) {
1624 : 0 : PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
1625 : 0 : return -1;
1626 : : }
1627 : :
1628 : 3 : *snaplen = (uint32_t)val;
1629 : 3 : return 0;
1630 : : }
1631 : :
1632 : : static int
1633 : 28 : pmd_init_internals(struct rte_vdev_device *vdev,
1634 : : const unsigned int nb_rx_queues,
1635 : : const unsigned int nb_tx_queues,
1636 : : struct pmd_internals **internals,
1637 : : struct rte_eth_dev **eth_dev)
1638 : : {
1639 : : struct rte_eth_dev_data *data;
1640 : : struct pmd_process_private *pp;
1641 : 28 : unsigned int numa_node = vdev->device.numa_node;
1642 : :
1643 : 28 : PMD_LOG(INFO, "Creating pcap-backed ethdev on numa socket %u",
1644 : : numa_node);
1645 : :
1646 : 28 : pp = rte_zmalloc_socket("pcap_private", sizeof(struct pmd_process_private),
1647 : : RTE_CACHE_LINE_SIZE, numa_node);
1648 [ - + ]: 28 : if (pp == NULL) {
1649 : 0 : PMD_LOG(ERR,
1650 : : "Failed to allocate memory for process private");
1651 : 0 : return -1;
1652 : : }
1653 : :
1654 : : /* reserve an ethdev entry */
1655 : 28 : *eth_dev = rte_eth_vdev_allocate(vdev, sizeof(**internals));
1656 [ - + ]: 28 : if (!(*eth_dev)) {
1657 : 0 : rte_free(pp);
1658 : 0 : return -1;
1659 : : }
1660 : 28 : (*eth_dev)->process_private = pp;
1661 : : /* now put it all together
1662 : : * - store queue data in internals,
1663 : : * - store numa_node info in eth_dev
1664 : : * - point eth_dev_data to internals
1665 : : * - and point eth_dev structure to new eth_dev_data structure
1666 : : */
1667 : 28 : *internals = (*eth_dev)->data->dev_private;
1668 : : /*
1669 : : * Interface MAC = 02:70:63:61:70:<iface_idx>
1670 : : * derived from: 'locally administered':'p':'c':'a':'p':'iface_idx'
1671 : : * where the middle 4 characters are converted to hex.
1672 : : */
1673 : : static uint8_t iface_idx;
1674 : 28 : (*internals)->eth_addr = (struct rte_ether_addr) {
1675 : 28 : .addr_bytes = { 0x02, 0x70, 0x63, 0x61, 0x70, iface_idx++ }
1676 : : };
1677 : 28 : (*internals)->phy_mac = 0;
1678 : : data = (*eth_dev)->data;
1679 : 28 : data->nb_rx_queues = (uint16_t)nb_rx_queues;
1680 : 28 : data->nb_tx_queues = (uint16_t)nb_tx_queues;
1681 : 28 : data->dev_link = (struct rte_eth_link) {
1682 : : .link_speed = RTE_ETH_SPEED_NUM_NONE,
1683 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
1684 : : .link_status = RTE_ETH_LINK_DOWN,
1685 : : .link_autoneg = RTE_ETH_LINK_FIXED,
1686 : : };
1687 : 28 : data->mac_addrs = &(*internals)->eth_addr;
1688 : 28 : data->promiscuous = 1;
1689 : 28 : data->all_multicast = 1;
1690 : 28 : data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
1691 : :
1692 : : /*
1693 : : * NOTE: we'll replace the data element, of originally allocated
1694 : : * eth_dev so the rings are local per-process
1695 : : */
1696 [ + - ]: 28 : (*eth_dev)->dev_ops = &ops;
1697 : :
1698 : 28 : strlcpy((*internals)->devargs, rte_vdev_device_args(vdev),
1699 : : ETH_PCAP_ARG_MAXLEN);
1700 : :
1701 : 28 : return 0;
1702 : : }
1703 : :
1704 : : static int
1705 : 0 : eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
1706 : : const unsigned int numa_node)
1707 : : {
1708 : : void *mac_addrs;
1709 : : struct rte_ether_addr mac;
1710 : :
1711 [ # # ]: 0 : if (osdep_iface_mac_get(if_name, &mac) < 0)
1712 : : return -1;
1713 : :
1714 : 0 : mac_addrs = rte_zmalloc_socket("pcap_mac", RTE_ETHER_ADDR_LEN, 0, numa_node);
1715 [ # # ]: 0 : if (mac_addrs == NULL)
1716 : : return -1;
1717 : :
1718 : 0 : PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
1719 : : memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
1720 : 0 : eth_dev->data->mac_addrs = mac_addrs;
1721 : 0 : return 0;
1722 : : }
1723 : :
1724 : : static int
1725 : 28 : eth_from_pcaps_common(struct rte_vdev_device *vdev,
1726 : : struct pmd_devargs_all *devargs_all,
1727 : : struct pmd_internals **internals, struct rte_eth_dev **eth_dev)
1728 : : {
1729 : : struct pmd_process_private *pp;
1730 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1731 : : struct pmd_devargs *tx_queues = &devargs_all->tx_queues;
1732 : 28 : const unsigned int nb_rx_queues = rx_queues->num_of_queue;
1733 : 28 : const unsigned int nb_tx_queues = tx_queues->num_of_queue;
1734 : : unsigned int i;
1735 : :
1736 [ + - ]: 28 : if (pmd_init_internals(vdev, nb_rx_queues, nb_tx_queues, internals,
1737 : : eth_dev) < 0)
1738 : : return -1;
1739 : :
1740 : 28 : pp = (*eth_dev)->process_private;
1741 [ + + ]: 64 : for (i = 0; i < nb_rx_queues; i++) {
1742 : 36 : struct pcap_rx_queue *rx = &(*internals)->rx_queue[i];
1743 : : struct devargs_queue *queue = &rx_queues->queue[i];
1744 : :
1745 : 36 : pp->rx_pcap[i] = queue->pcap;
1746 : 36 : strlcpy(rx->name, queue->name, sizeof(rx->name));
1747 : 36 : strlcpy(rx->type, queue->type, sizeof(rx->type));
1748 : : }
1749 : :
1750 [ + + ]: 63 : for (i = 0; i < nb_tx_queues; i++) {
1751 : 35 : struct pcap_tx_queue *tx = &(*internals)->tx_queue[i];
1752 : : struct devargs_queue *queue = &tx_queues->queue[i];
1753 : :
1754 : 35 : pp->tx_dumper[i] = queue->dumper;
1755 : 35 : pp->tx_pcap[i] = queue->pcap;
1756 : 35 : strlcpy(tx->name, queue->name, sizeof(tx->name));
1757 : 35 : strlcpy(tx->type, queue->type, sizeof(tx->type));
1758 : : }
1759 : :
1760 : : return 0;
1761 : : }
1762 : :
1763 : : static int
1764 : 28 : eth_from_pcaps(struct rte_vdev_device *vdev,
1765 : : struct pmd_devargs_all *devargs_all)
1766 : : {
1767 : 28 : struct pmd_internals *internals = NULL;
1768 : 28 : struct rte_eth_dev *eth_dev = NULL;
1769 : : struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
1770 : 28 : int single_iface = devargs_all->single_iface;
1771 : 28 : unsigned int infinite_rx = devargs_all->infinite_rx;
1772 : : int ret;
1773 : :
1774 : 28 : ret = eth_from_pcaps_common(vdev, devargs_all, &internals, ð_dev);
1775 : :
1776 [ + - ]: 28 : if (ret < 0)
1777 : : return ret;
1778 : :
1779 : : /* store weather we are using a single interface for rx/tx or not */
1780 : 28 : internals->single_iface = single_iface;
1781 : :
1782 [ + + ]: 28 : if (single_iface) {
1783 : 3 : internals->if_index =
1784 : 3 : osdep_iface_index_get(rx_queues->queue[0].name);
1785 : :
1786 : : /* Enable LSC interrupt support for iface mode */
1787 : 3 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
1788 : :
1789 : : /* phy_mac arg is applied only if "iface" devarg is provided */
1790 [ - + ]: 3 : if (rx_queues->phy_mac) {
1791 [ # # ]: 0 : if (eth_pcap_update_mac(rx_queues->queue[0].name,
1792 : 0 : eth_dev, vdev->device.numa_node) == 0)
1793 : 0 : internals->phy_mac = 1;
1794 : : }
1795 : : }
1796 : :
1797 : 28 : internals->infinite_rx = infinite_rx;
1798 : 28 : internals->eof = devargs_all->eof;
1799 : 28 : internals->snapshot_len = devargs_all->snapshot_len;
1800 : :
1801 : : /* Enable LSC for eof mode (already set above for single_iface) */
1802 [ + + ]: 28 : if (internals->eof)
1803 : 1 : eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
1804 : :
1805 : : /* Assign rx ops. */
1806 [ + + ]: 28 : if (infinite_rx)
1807 : 2 : eth_dev->rx_pkt_burst = eth_pcap_rx_infinite;
1808 [ + + + + : 26 : else if (devargs_all->is_rx_pcap || devargs_all->is_rx_iface ||
+ + ]
1809 : : single_iface)
1810 : 20 : eth_dev->rx_pkt_burst = eth_pcap_rx;
1811 : : else
1812 : 6 : eth_dev->rx_pkt_burst = eth_null_rx;
1813 : :
1814 : : /* Assign tx ops. */
1815 [ + + ]: 28 : if (devargs_all->is_tx_pcap)
1816 : 10 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
1817 [ + + + + ]: 18 : else if (devargs_all->is_tx_iface || single_iface)
1818 : 5 : eth_dev->tx_pkt_burst = eth_pcap_tx;
1819 : : else
1820 : 13 : eth_dev->tx_pkt_burst = eth_tx_drop;
1821 : :
1822 : 28 : rte_eth_dev_probing_finish(eth_dev);
1823 : 28 : return 0;
1824 : : }
1825 : :
1826 : : static void
1827 : 1 : eth_release_pcaps(struct pmd_devargs *pcaps,
1828 : : struct pmd_devargs *dumpers,
1829 : : int single_iface)
1830 : : {
1831 : : unsigned int i;
1832 : :
1833 [ - + ]: 1 : if (single_iface) {
1834 [ # # ]: 0 : if (pcaps->queue[0].pcap)
1835 : 0 : pcap_close(pcaps->queue[0].pcap);
1836 : 0 : return;
1837 : : }
1838 : :
1839 [ - + ]: 1 : for (i = 0; i < dumpers->num_of_queue; i++) {
1840 [ # # ]: 0 : if (dumpers->queue[i].dumper)
1841 : 0 : pcap_dump_close(dumpers->queue[i].dumper);
1842 : :
1843 [ # # ]: 0 : if (dumpers->queue[i].pcap)
1844 : 0 : pcap_close(dumpers->queue[i].pcap);
1845 : : }
1846 : :
1847 [ - + ]: 1 : for (i = 0; i < pcaps->num_of_queue; i++) {
1848 [ # # ]: 0 : if (pcaps->queue[i].pcap)
1849 : 0 : pcap_close(pcaps->queue[i].pcap);
1850 : : }
1851 : : }
1852 : :
1853 : : static int
1854 : 29 : pmd_pcap_probe(struct rte_vdev_device *dev)
1855 : : {
1856 : : const char *name;
1857 : : struct rte_kvargs *kvlist;
1858 : 29 : struct pmd_devargs pcaps = {0};
1859 : 29 : struct pmd_devargs dumpers = {0};
1860 : : struct rte_eth_dev *eth_dev = NULL;
1861 : : struct pmd_internals *internal;
1862 : : int ret = 0;
1863 : :
1864 [ + - ]: 29 : struct pmd_devargs_all devargs_all = {
1865 : : .snapshot_len = ETH_PCAP_SNAPSHOT_LEN_DEFAULT,
1866 : : .single_iface = 0,
1867 : : .is_tx_pcap = 0,
1868 : : .is_tx_iface = 0,
1869 : : .infinite_rx = 0,
1870 : : };
1871 : :
1872 : : name = rte_vdev_device_name(dev);
1873 : 29 : PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
1874 : :
1875 : : /* Record info for timestamps on first probe */
1876 [ + + ]: 29 : if (hz == 0) {
1877 : 1 : hz = rte_get_timer_hz();
1878 [ - + ]: 1 : if (hz == 0) {
1879 : 0 : PMD_LOG(ERR, "Reported hz is zero!");
1880 : 0 : return -1;
1881 : : }
1882 : 1 : timespec_get(&start_time, TIME_UTC);
1883 : 1 : start_cycles = rte_get_timer_cycles();
1884 : : }
1885 : :
1886 [ - + ]: 29 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
1887 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
1888 [ # # ]: 0 : if (!eth_dev) {
1889 : 0 : PMD_LOG(ERR, "Failed to probe %s", name);
1890 : 0 : return -1;
1891 : : }
1892 : :
1893 : 0 : internal = eth_dev->data->dev_private;
1894 : :
1895 : 0 : kvlist = rte_kvargs_parse(internal->devargs, valid_arguments);
1896 [ # # ]: 0 : if (kvlist == NULL)
1897 : : return -1;
1898 : : } else {
1899 : 29 : kvlist = rte_kvargs_parse(rte_vdev_device_args(dev),
1900 : : valid_arguments);
1901 [ + - ]: 29 : if (kvlist == NULL)
1902 : : return -1;
1903 : : }
1904 : :
1905 : : /*
1906 : : * Process optional snapshot length argument first, so the value
1907 : : * is available when opening pcap handles for files and interfaces.
1908 : : */
1909 [ + + ]: 29 : if (rte_kvargs_count(kvlist, ETH_PCAP_SNAPSHOT_LEN_ARG) == 1) {
1910 : 3 : ret = rte_kvargs_process(kvlist, ETH_PCAP_SNAPSHOT_LEN_ARG,
1911 : : &process_snapshot_len,
1912 : : &devargs_all.snapshot_len);
1913 [ - + ]: 3 : if (ret < 0)
1914 : 0 : goto free_kvlist;
1915 : : }
1916 : :
1917 : : /*
1918 : : * Propagate snapshot length to per-queue devargs so that
1919 : : * the open callbacks can access it.
1920 : : */
1921 : 29 : devargs_all.rx_queues.snapshot_len = devargs_all.snapshot_len;
1922 : 29 : devargs_all.tx_queues.snapshot_len = devargs_all.snapshot_len;
1923 : :
1924 : : /*
1925 : : * If iface argument is passed we open the NICs and use them for
1926 : : * reading / writing
1927 : : */
1928 [ + + ]: 29 : if (rte_kvargs_count(kvlist, ETH_PCAP_IFACE_ARG) == 1) {
1929 : :
1930 : 3 : ret = rte_kvargs_process(kvlist, ETH_PCAP_IFACE_ARG,
1931 : : &open_rx_tx_iface, &pcaps);
1932 [ - + ]: 3 : if (ret < 0)
1933 : 0 : goto free_kvlist;
1934 : :
1935 : 3 : dumpers.queue[0] = pcaps.queue[0];
1936 : :
1937 : 3 : ret = rte_kvargs_process(kvlist, ETH_PCAP_PHY_MAC_ARG,
1938 : : &process_bool_flag, &pcaps.phy_mac);
1939 [ - + ]: 3 : if (ret < 0)
1940 : 0 : goto free_kvlist;
1941 : :
1942 : 3 : dumpers.phy_mac = pcaps.phy_mac;
1943 : :
1944 : 3 : devargs_all.single_iface = 1;
1945 : 3 : pcaps.num_of_queue = 1;
1946 : 3 : dumpers.num_of_queue = 1;
1947 : :
1948 : 3 : goto create_eth;
1949 : : }
1950 : :
1951 : : /*
1952 : : * We check whether we want to open a RX stream from a real NIC, a
1953 : : * pcap file or open a dummy RX stream
1954 : : */
1955 : 26 : devargs_all.is_rx_pcap =
1956 : 26 : rte_kvargs_count(kvlist, ETH_PCAP_RX_PCAP_ARG) ? 1 : 0;
1957 : 26 : devargs_all.is_rx_iface =
1958 : 26 : (rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_ARG) +
1959 : 26 : rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_IN_ARG)) ? 1 : 0;
1960 : 26 : pcaps.num_of_queue = 0;
1961 : :
1962 : 26 : devargs_all.is_tx_pcap =
1963 : 26 : rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) ? 1 : 0;
1964 : 26 : devargs_all.is_tx_iface =
1965 : 26 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG) ? 1 : 0;
1966 : 26 : dumpers.num_of_queue = 0;
1967 : :
1968 [ + + ]: 26 : if (devargs_all.is_rx_pcap) {
1969 : : /*
1970 : : * We check whether we want to infinitely rx the pcap file.
1971 : : */
1972 : 18 : unsigned int infinite_rx_arg_cnt = rte_kvargs_count(kvlist,
1973 : : ETH_PCAP_INFINITE_RX_ARG);
1974 : :
1975 [ + + ]: 18 : if (infinite_rx_arg_cnt == 1) {
1976 : 3 : ret = rte_kvargs_process(kvlist,
1977 : : ETH_PCAP_INFINITE_RX_ARG,
1978 : : &process_bool_flag,
1979 : : &devargs_all.infinite_rx);
1980 [ - + ]: 3 : if (ret < 0)
1981 : 0 : goto free_kvlist;
1982 [ - + ]: 3 : PMD_LOG(INFO, "infinite_rx has been %s for %s",
1983 : : devargs_all.infinite_rx ? "enabled" : "disabled",
1984 : : name);
1985 : :
1986 [ - + ]: 15 : } else if (infinite_rx_arg_cnt > 1) {
1987 : 0 : PMD_LOG(WARNING, "infinite_rx has not been enabled since the "
1988 : : "argument has been provided more than once "
1989 : : "for %s", name);
1990 : : }
1991 : :
1992 : : /*
1993 : : * Check whether to signal EOF via link status change.
1994 : : */
1995 [ + + ]: 18 : if (rte_kvargs_count(kvlist, ETH_PCAP_EOF_ARG) == 1) {
1996 : 2 : ret = rte_kvargs_process(kvlist, ETH_PCAP_EOF_ARG,
1997 : : &process_bool_flag,
1998 : : &devargs_all.eof);
1999 [ - + ]: 2 : if (ret < 0)
2000 : 0 : goto free_kvlist;
2001 : : }
2002 : :
2003 [ + + + + ]: 18 : if (devargs_all.infinite_rx && devargs_all.eof) {
2004 : 1 : PMD_LOG(ERR, "Cannot use both infinite_rx and eof for %s",
2005 : : name);
2006 : : ret = -EINVAL;
2007 : 1 : goto free_kvlist;
2008 : : }
2009 : :
2010 : 17 : ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_PCAP_ARG,
2011 : : &open_rx_pcap, &pcaps);
2012 [ + + ]: 8 : } else if (devargs_all.is_rx_iface) {
2013 : 2 : ret = rte_kvargs_process(kvlist, NULL,
2014 : : &rx_iface_args_process, &pcaps);
2015 [ + - ]: 6 : } else if (devargs_all.is_tx_iface || devargs_all.is_tx_pcap) {
2016 : : unsigned int i;
2017 : :
2018 : : /* Count number of tx queue args passed before dummy rx queue
2019 : : * creation so a dummy rx queue can be created for each tx queue
2020 : : */
2021 : 6 : unsigned int num_tx_queues =
2022 : 6 : (rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) +
2023 : 6 : rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG));
2024 : :
2025 : 6 : PMD_LOG(INFO, "Creating null rx queue since no rx queues were provided.");
2026 : :
2027 : : /* Creating a dummy rx queue for each tx queue passed */
2028 [ + + ]: 15 : for (i = 0; i < num_tx_queues; i++)
2029 : : ret = add_queue(&pcaps, "dummy_rx", "rx_null", NULL,
2030 : : NULL);
2031 : : } else {
2032 : 0 : PMD_LOG(ERR, "Error - No rx or tx queues provided");
2033 : : ret = -ENOENT;
2034 : : }
2035 [ - + ]: 25 : if (ret < 0)
2036 : 0 : goto free_kvlist;
2037 : :
2038 : : /*
2039 : : * We check whether we want to open a TX stream to a real NIC,
2040 : : * a pcap file, or drop packets on tx
2041 : : */
2042 [ + + ]: 25 : if (devargs_all.is_tx_pcap) {
2043 : 10 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_PCAP_ARG,
2044 : : &open_tx_pcap, &dumpers);
2045 [ + + ]: 15 : } else if (devargs_all.is_tx_iface) {
2046 : 2 : ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_IFACE_ARG,
2047 : : &open_tx_iface, &dumpers);
2048 : : } else {
2049 : : unsigned int i;
2050 : :
2051 : 13 : PMD_LOG(INFO, "Dropping packets on tx since no tx queues were provided.");
2052 : :
2053 : : /* Add 1 dummy queue per rxq which counts and drops packets. */
2054 [ + + ]: 29 : for (i = 0; i < pcaps.num_of_queue; i++)
2055 : : ret = add_queue(&dumpers, "dummy_tx", "tx_drop", NULL,
2056 : : NULL);
2057 : : }
2058 : :
2059 [ - + ]: 25 : if (ret < 0)
2060 : 0 : goto free_kvlist;
2061 : :
2062 : 25 : create_eth:
2063 [ - + ]: 28 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
2064 : : struct pmd_process_private *pp;
2065 : : unsigned int i;
2066 : :
2067 : : internal = eth_dev->data->dev_private;
2068 : 0 : pp = rte_zmalloc("pcap_private", sizeof(struct pmd_process_private),
2069 : : RTE_CACHE_LINE_SIZE);
2070 [ # # ]: 0 : if (pp == NULL) {
2071 : 0 : PMD_LOG(ERR,
2072 : : "Failed to allocate memory for process private");
2073 : : ret = -1;
2074 : 0 : goto free_kvlist;
2075 : : }
2076 : :
2077 : 0 : eth_dev->dev_ops = &ops;
2078 : 0 : eth_dev->device = &dev->device;
2079 : :
2080 : : /* setup process private */
2081 [ # # ]: 0 : for (i = 0; i < pcaps.num_of_queue; i++)
2082 : 0 : pp->rx_pcap[i] = pcaps.queue[i].pcap;
2083 : :
2084 [ # # ]: 0 : for (i = 0; i < dumpers.num_of_queue; i++) {
2085 : 0 : pp->tx_dumper[i] = dumpers.queue[i].dumper;
2086 : 0 : pp->tx_pcap[i] = dumpers.queue[i].pcap;
2087 : : }
2088 : :
2089 : 0 : eth_dev->process_private = pp;
2090 : 0 : eth_dev->rx_pkt_burst = eth_pcap_rx;
2091 [ # # ]: 0 : if (devargs_all.is_tx_pcap)
2092 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
2093 : : else
2094 : 0 : eth_dev->tx_pkt_burst = eth_pcap_tx;
2095 : :
2096 : 0 : rte_eth_dev_probing_finish(eth_dev);
2097 : 0 : goto free_kvlist;
2098 : : }
2099 : :
2100 : 28 : devargs_all.rx_queues = pcaps;
2101 : 28 : devargs_all.tx_queues = dumpers;
2102 : :
2103 : 28 : ret = eth_from_pcaps(dev, &devargs_all);
2104 : :
2105 : 29 : free_kvlist:
2106 : 29 : rte_kvargs_free(kvlist);
2107 : :
2108 [ + + ]: 29 : if (ret < 0)
2109 : 1 : eth_release_pcaps(&pcaps, &dumpers, devargs_all.single_iface);
2110 : :
2111 : : return ret;
2112 : : }
2113 : :
2114 : : static int
2115 : 28 : pmd_pcap_remove(struct rte_vdev_device *dev)
2116 : : {
2117 : : struct rte_eth_dev *eth_dev = NULL;
2118 : :
2119 [ + - ]: 28 : if (!dev)
2120 : : return -1;
2121 : :
2122 : 28 : eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
2123 [ + - ]: 28 : if (eth_dev == NULL)
2124 : : return 0; /* port already released */
2125 : :
2126 : 28 : eth_dev_close(eth_dev);
2127 : 28 : rte_eth_dev_release_port(eth_dev);
2128 : :
2129 : 28 : return 0;
2130 : : }
2131 : :
2132 : : static struct rte_vdev_driver pmd_pcap_drv = {
2133 : : .probe = pmd_pcap_probe,
2134 : : .remove = pmd_pcap_remove,
2135 : : };
2136 : :
2137 : 286 : RTE_PMD_REGISTER_VDEV(net_pcap, pmd_pcap_drv);
2138 : : RTE_PMD_REGISTER_ALIAS(net_pcap, eth_pcap);
2139 : : RTE_PMD_REGISTER_PARAM_STRING(net_pcap,
2140 : : ETH_PCAP_RX_PCAP_ARG "=<string> "
2141 : : ETH_PCAP_TX_PCAP_ARG "=<string> "
2142 : : ETH_PCAP_RX_IFACE_ARG "=<ifc> "
2143 : : ETH_PCAP_RX_IFACE_IN_ARG "=<ifc> "
2144 : : ETH_PCAP_TX_IFACE_ARG "=<ifc> "
2145 : : ETH_PCAP_IFACE_ARG "=<ifc> "
2146 : : ETH_PCAP_PHY_MAC_ARG "=<0|1> "
2147 : : ETH_PCAP_INFINITE_RX_ARG "=<0|1> "
2148 : : ETH_PCAP_EOF_ARG "=<0|1> "
2149 : : ETH_PCAP_SNAPSHOT_LEN_ARG "=<int>");
|