On Thu, 15 Oct 2026 12:14:30 +0100 Frank Dressler <[email protected]> wrote:
> In contrast to other PMDs, the AF_PACKET PMD does not only return > incoming but also outgoing packets from rte_eth_rx_burst(). This is > fine for applications similar to tcpdump which usually want to see > both. But it is not always the desired behavior. For example, the > AF_PACKET PMD might be used in a testing environment in which no > regular ethernet PMD works. In such an environment, the AF_PACKET > PMD must behave like a regular one, i.e. not return sent packets > from rte_eth_rx_burst(). One could use the AF_XDP PMD for this but > it has different dependencies than the AF_PACKET PMD because it > requires the bpf() syscall, for example, which might not be > available. > > For this reason, this series adds the ignore_outgoing=<0|1> devarg. > When set, the PMD ensures that rte_eth_rx_burst() only returns > incoming traffic. The default is 0 so that existing software works > as before. > > The ignore_outgoing test tags the frames it injects so that it can > distinguish them from stray frames, which would otherwise be counted > as well and could lead to a wrong result. As the pre-existing > loopback test could suffer from stray frames as well, the first patch > changes it to use tagged frames. > > The second patch adds filtering of outgoing packets in the PMD > because that works in all supported kernel versions and for all > queue counts. The test creates an AF_PACKET vdev and injects frames > at the fd end of the TAP device and via a second AF_PACKET vdev. > Frames from the fd end arrive as incoming traffic and frames from > the second vdev as outgoing traffic, so with ignore_outgoing=1 the > first vdev should return only the incoming frames. The frames from > the fd end are required to distinguish a dead device from one which > dropped the outgoing frames. > > The third patch adds PACKET_IGNORE_OUTGOING which moves the > filtering into the kernel. It is supported since Linux 4.20 but only > works for single-queue AF_PACKET scenarios. Multi-queue AF_PACKET > is still filtered in the PMD. > > The fourth patch adds PACKET_FANOUT_FLAG_IGNORE_OUTGOING which is > supported since Linux 6.2 and moves the filtering into the kernel > for the multi-queue scenarios. The kernel does not expose a direct > way to check whether it supports PACKET_FANOUT_FLAG_IGNORE_OUTGOING > but it also does not return an error when the sockopt is set on > kernels that do not support it. Because of that the sockopt is set > opportunistically. The PMD check is kept, since older kernels accept > the flag without effect and support cannot be detected. > > Overall we get the following: > > | Single Queue | Multi-Queue > ------------+--------------+------------- > Kernel 5.4+ | in kernel | in PMD > Kernel 6.2+ | in kernel | in kernel > > I tested this on both, kernel 7.2.8 and kernel 5.4.0 with both single > and multiple queues. My results, strace'ing testpmd 7.2.8, with the > variants of ignore_outgoing=0|1 and single/multi-queue: > > Kernel 5.4.0: > qpairs=1,ignore_outgoing=0: - > qpairs=1,ignore_outgoing=1: setsockopt(14, SOL_PACKET, 0x17 /* > PACKET_??? */, [1], 4) = 0 > // 0x17 is PACKET_IGNORE_OUTGOING > > qpairs=2,ignore_outgoing=0: setsockopt(14, SOL_PACKET, PACKET_FANOUT, > [-1878917532], 4) = 0 > // -1878917532 does NOT contain PACKET_FANOUT_FLAG_IGNORE_OUTGOING<<16 > qpairs=2,ignore_outgoing=1: setsockopt(14, SOL_PACKET, PACKET_FANOUT, > [-805175699], 4) = 0 > // -805175699 does contain PACKET_FANOUT_FLAG_IGNORE_OUTGOING<<16 > > Kernel 7.2.8: > qpairs=1,ignore_outgoing=0: - > qpairs=1,ignore_outgoing=1: setsockopt(13, SOL_PACKET, > PACKET_IGNORE_OUTGOING, [1], 4) = 0 > > qpairs=2,ignore_outgoing=0: setsockopt(13, SOL_PACKET, PACKET_FANOUT, > [-1878978899], 4) = 0 > // -1878978899 does NOT contain PACKET_FANOUT_FLAG_IGNORE_OUTGOING<<16 > qpairs=2,ignore_outgoing=1: setsockopt(13, SOL_PACKET, PACKET_FANOUT, > [-805236964], 4) = 0 > // -805236964 does contain PACKET_FANOUT_FLAG_IGNORE_OUTGOING<<16 > > They show that the setsockopt succeeds even on the old kernel that > does not support PACKET_FANOUT_FLAG_IGNORE_OUTGOING, so setting it > opportunistically is fine. They also show that the code only tries to > set PACKET_FANOUT_FLAG_IGNORE_OUTGOING or PACKET_IGNORE_OUTGOING when > requested by ignore_outgoing=1. And it shows that > PACKET_IGNORE_OUTGOING is used for single and > PACKET_FANOUT_FLAG_IGNORE_OUTGOING for multi-queue. > > I have also manually ran testpmd in all modes and both kernels to > verify that ignore_outgoing works as expected, sending packets and > checking what testpmd was receiving (``set verbose 1``). > > > v6: > - add tags to frames to distinguish injected ones from stray ones > - update the loopback and ignore_outgoing tests to count only tagged > frames > - inject frames as incoming to distinguish a dead port from a > working one in ignore_outgoing=1 > - bound the receive flush so a continuous stream cannot hang the test > - quote rte_eth_rx_burst() with double backticks in the docs > - use Linux 6.2 instead of v6.2 throughout the code and the docs > - add a paragraph to af_packet.rst on single-queue and multi-queue > filtering Still see minor issues in AI reviews that need fix before it gets merged. Subject: Re: [PATCH v6 0/4] net/af_packet: ignore_outgoing devarg Series applies cleanly to main and builds at every commit with -Dwerror=true (driver and dpdk-test). Kernel side checks out: sockaddr_ll is at TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) as the kernel lays it out, PACKET_IGNORE_OUTGOING has no effect once a socket joins a fanout group (the group prot_hook replaces the per-socket one), and pre-6.2 fanout_add() does not validate unknown flag bits, so setting PACKET_FANOUT_FLAG_IGNORE_OUTGOING unconditionally is safe and the PMD-side check remains the correct fallback. Only minor items below. Patch 2/4 net/af_packet: filter Rx of outgoing packets in the PMD ----------------------------------------------------------------- Info: ignore_outgoing is unsigned, log it with %u. - PMD_LOG(DEBUG, "%s:\tignore outgoing %d", name, ignore_outgoing); + PMD_LOG(DEBUG, "%s:\tignore outgoing %u", name, ignore_outgoing); Info: test_af_packet_ignore_outgoing() defines n_inject for the TAP side but hardcodes 4 for the af_packet side. Use one constant for both: - allocated = alloc_tx_mbufs(bufs, 4); + allocated = alloc_tx_mbufs(bufs, n_inject); Patch 3/4 net/af_packet: use kernel to filter single-queue Rx ------------------------------------------------------------- Info: commit message states the 4.20 availability twice. Drop the last paragraph and fold "DPDK requires at least Linux 5.4, so no feature check is needed" into the second one. Info: release notes should say what the user gets, not how it is done. Where filtering happens (and the 6.2 dependency added in 4/4) is already in doc/guides/nics/af_packet.rst. Suggest leaving the release note entry as added in 2/4: Added ``ignore_outgoing`` devarg so ``rte_eth_rx_burst()`` returns only incoming packets. Info: PACKET_QDISC_BYPASS is guarded with #if defined() and 4/4 adds a fallback define for PACKET_FANOUT_FLAG_IGNORE_OUTGOING, but PACKET_IGNORE_OUTGOING is used bare. Fine against any 4.20+ uapi headers; add a matching #ifndef fallback (value 23) only if you want it consistent with 4/4. Reviewed-by: Stephen Hemminger <[email protected]>

