Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Filtering packets from anywhere in the networking stack

October 2, 2025
Paolo Valerio
Related topics:
LinuxObservability
Related products:
Red Hat Enterprise LinuxRed Hat OpenShift

Share:

    Dumping packets from a network interface is a common debugging step. But the ability to dump them from anywhere in the networking stack is a concept that holds significant potential, as described in a previous article. However, excessive and uncontrolled dumping can quickly become overwhelming, in terms of the amount of data and the impact on the inspected system. For this reason, tools like tcpdump and tshark use capture filters, which helps reduce the overhead introduced by a capture session on a live system.

    Retis is no exception. In this article, we will explore Retis filtering capabilities, highlighting the differences, similarities, and expectations compared to other existing tools.

    Why filtering matters

    Filtering is more than just a convenient way for users to narrow down data during capture or mitigate overhead in a production system. It is essential for obtaining correct and complete captures with no missing events.

    One primary cause of loss is Retis needing to process too many events. Depending on the starting condition, processing may not be possible if the event count is too high, as shown here:

    > sudo retis -p ifdump collect -c skb,dev,ns -o /dev/null
    Applying profile ifdump
    5 probe(s) loaded
    ^CReceived signal, terminating...
    199152 event(s) processed
    WARN  lost 108594 event(s) from net:net_dev_start_xmit
    WARN  lost 406816 event(s) from net:netif_receive_skb
    WARN  total events lost: 515410

    As you can see, Retis does its best to report when events are lost. When lost warnings appear, it likely requires a narrower filter to capture the desired data.

    Retis offers two distinct methods for filtering data:

    • Packet filtering: Similar to tcpdump capture filters, this method operates by directly inspecting the packet headers.
    • Meta-data filtering: Based on the sk_buff fields, a core Linux kernel data structure that represents a network packet. It contains, in addition to the packet data, extensive metadata about it, such as the associated network device, VLAN, checksum information, etc.

    Packet filtering

    Tools like tcpdump and tshark use capture filters that adhere to the PCAP-FILTER(7) syntax. These tools normally translate a capture filter into a filter program, which is a sequence of the popular legacy bpf instructions, usually called cBPF.

    The cBPF pseudo architecture consists of a program counter, an accumulator A, an index register X, a scratch memory area M[], and the instructions in the following fixed-length format (from linux/filter.h):

    struct sock_filter {    /* Filter block */
           __u16   code;   /* Actual filter code */
           __u8    jt;     /* Jump true */
           __u8    jf;     /* Jump false */
           __u32   k;      /* Generic multiuse field */
    };

    The filter machine section of the BPF(4) in FreeBSD man pages thoroughly explains the instructions and what they can do. The following output shows the cBPF instructions translated from a pcap-filter, generated using tcpdump -y EN10MB -d "ip && tcp dst port 80" (comments added for clarity).

    (000) ldh [12]                ; A <- P[EtherType:2]
                                  ;   Load half word at offset EtherType in reg A
    (001) jeq #0x800 jt 2 jf 10   ; pc += (A == EtherType.IPv4) ? 0 : 9
                                  ;   if EtherType is IPv4 goto the next
                                  ;   instruction, otherwise return with no match.
    (002) ldb [23]                ; A <- P[Protocol:1]
                                  ;   Load 1 byte at offset ipv4.proto
    (003) jeq #0x6 jt 4 jf 10     ; pc += (A == TCP) ? 0 : 8
                                  ;   if EtherType is IPv4 proceed,
                                  ;   otherwise return signaling no match
    (004) ldh [20]                ; A <- P[Flags:2]
                                  ;   Load ip.flags + ip.frag_off in reg A
    (005) jset #0x1fff jt 10 jf 6 ; pc += (A & 0x1fff) ? 4 : 0
                                  ;   if later fragment, return false, else proceed
    (006) ldxb 4*([14]&0xf)       ; X <- 4*(P[14:1]&0xf) ;
                                  ;   Load one byte from the beginning of the ip header,
                                  ;   keep the lower nibble containing the ip.ihl and multiply
                                  ;   the result by 4 (IHL is expressed in multiple of 4 bytes)
    (007) ldh [x + 16]            ; A <- P[X+16:2]
                                  ;   Load 2 bytes from
                                  ;   mac.len (14) + ip.len (X) + 2 (offset of dst port
                                  ;   in TCP header) in A
    (008) jeq #0x50 jt 9 jf 10    ; pc += (A == 80) ? 0 : 1
                                  ;   if dst port is 80, return match, else no match
    (009) ret #262144             ; return match
    (010) ret #0                  ; return no match

    Normally, applications such as tcpdump request to attach the cBPF filters to a socket. During this process, the classic BPF (cBPF) instructions are translated into extended BPF (eBPF) instructions. Upon successful conversion, the kernel attaches the filter to the socket that will later run to determine which packets subsequently deliver to the socket.

    Retis has adopted many of the aforementioned packet filtering concepts. It uses libpcap to convert PCAP filters into cBPF instructions, implementing its converter of cBPF instructions into eBPF. Then the resulting eBPF binaries are inlined into the target programs that in turn are eventually attached to various probe points throughout the networking stack. This approach is very flexible because it enables filtering at any point in the stack, a capability typically restricted to fixed points in the receive and transmit paths in other tools.

    The ability of Retis to attach its programs to any skb-aware function or tracepoint in the kernel is one of the things that makes Retis slightly different from other tools. This level of flexibility, however, introduces unique considerations. The specific events collected will vary significantly based on the probe points chosen, largely dictated by the packet path. While some scenarios may be straightforward, others will diverge from the behavior observed with conventional packet sniffers.

    There are cases where the results match what we're used to seeing with tools like tcpdump, as in the following example:

    > sudo retis -p ifdump collect -c skb,dev,ns -f "icmp and host 192.168.1.1"
    [...]
    31676532023225 (14) [ping] 60234 [tp] net:net_dev_start_xmit
     192.168.1.10 > 192.168.1.1 tos 0x0 ttl 64 id 52363 off 0 [DF] len 84 proto ICMP (1) type 8 code 0
     ns 0x1/4026531840 if 2 (eno1)
    31676532568924 (9) [swapper/9] 0 [tp] net:netif_receive_skb
     192.168.1.1 > 192.168.1.10 tos 0x0 ttl 64 id 61547 off 0 len 84 proto ICMP (1) type 0 code 0
     ns 0x1/4026531840 if 2 (eno1)
    [...]

    In the next section, we will see how minor modifications can lead to different outcomes.

    Metadata filtering

    In the previous section, we demonstrated how using the Retis profile ifdump (-p net:netif_receive_skb and -p net:dev_hard_start_xmit) can yield captures similar to tcpdump. One could argue that, under the right conditions, the ifdump profile closely resembles tcpdump when capturing from all interfaces and in both directions (-i any).
     

    This holds true for the simple case shown in the last example, where locally generated packets traverse a physical interface. However, the situation changes in different scenarios. For instance, let's consider a slightly different setup involving two additional namespaces and bridged veths, as illustrated in Figure 1.

    namespaces
    Figure 1: An illustration of a simple setup involving multiple namespaces.

    As soon as we start capturing packets traversing multiple network namespaces, we begin to see the first key difference. Retis probes kernel functions directly, and this implies we can find ourselves outside the namespace abstraction; meaning a simple capture can generate events from all of them, as follows:

    > sudo retis -p ifdump collect -c skb,dev,ns -f 'icmp and net 10.0.0.0/24'
    [...]
    59411690053173 (22) [ping] 106735 [tp] net:net_dev_start_xmit
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 42483 off 0 [DF] len 84 proto ICMP (1) type 8 code 0
     ns 0x19007/4026535345 if 197 (veth01)
    59411690066848 (22) [ping] 106735 [tp] net:netif_receive_skb
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 42483 off 0 [DF] len 84 proto ICMP (1) type 8 code 0
     ns 0x1/4026531840 if 198 (veth00)
    59411690073882 (22) [ping] 106735 [tp] net:net_dev_start_xmit
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 42483 off 0 [DF] len 84 proto ICMP (1) type 8 code 0
     ns 0x1/4026531840 if 200 (veth10) rxif 198
    59411690076176 (22) [ping] 106735 [tp] net:netif_receive_skb
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 42483 off 0 [DF] len 84 proto ICMP (1) type 8 code 0
     ns 0xc005/4026535413 if 199 (veth11)
    59411690090402 (22) [ping] 106735 [tp] net:net_dev_start_xmit
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 15229 off 0 len 84 proto ICMP (1) type 0 code 0
     ns 0xc005/4026535413 if 199 (veth11)
    59411690095742 (22) [ping] 106735 [tp] net:netif_receive_skb
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 15229 off 0 len 84 proto ICMP (1) type 0 code 0
     ns 0x1/4026531840 if 200 (veth10)
    59411690098067 (22) [ping] 106735 [tp] net:net_dev_start_xmit
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 15229 off 0 len 84 proto ICMP (1) type 0 code 0
     ns 0x1/4026531840 if 198 (veth00) rxif 200
    59411690099970 (22) [ping] 106735 [tp] net:netif_receive_skb
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 15229 off 0 len 84 proto ICMP (1) type 0 code 0
     ns 0x19007/4026535345 if 197 (veth01)
    [...]

    In contrast, if we attempt to perform the same action with tcpdump from the root namespace, we observe only packets traversing its interfaces.

    > sudo tcpdump -vvi any "icmp and net 10.0.0.0/24"
    00:23:38.774201 veth00 P   IP (tos 0x0, ttl 64, id 13908, offset 0, flags [DF], proto ICMP (1), length 84)
       10.0.0.2 > 10.0.0.3: ICMP echo request, id 41706, seq 3, length 64
    00:23:38.774214 veth10 Out IP (tos 0x0, ttl 64, id 13908, offset 0, flags [DF], proto ICMP (1), length 84)
       10.0.0.2 > 10.0.0.3: ICMP echo request, id 41706, seq 3, length 64
    00:23:38.774229 veth10 P   IP (tos 0x0, ttl 64, id 34754, offset 0, flags [none], proto ICMP (1), length 84)
       10.0.0.3 > 10.0.0.2: ICMP echo reply, id 41706, seq 3, length 64
    00:23:38.774237 veth00 Out IP (tos 0x0, ttl 64, id 34754, offset 0, flags [none], proto ICMP (1), length 84)
       10.0.0.3 > 10.0.0.2: ICMP echo reply, id 41706, seq 3, length 64

    It’s easy to see that Retis produces a greater number of events in this scenario. To further narrow down the collected events based on criteria that go beyond the packet header (i.e., a network namespace), packet filtering alone is no longer enough. Therefore, we must rely on meta-data filtering.

    Meta-filtering is an additional way Retis offers to filter packets before tracking. It is essentially based on BTF, and allows the user to match against sk_buffs and inner data structures fields (e.g., skb->dev->name, skb->mark, etc.) and support the vast majority of field types. Lastly, like packet filtering, the resulting filter is in the form of eBPF bytecode and can combine with packet filtering.

    Meta-filtering supports multiple types, allows multiple relational operators, boolean expressions, and precedence override. It also covers fairly advanced uses, including bit masking, casting, and bitfield matching. For further details about basic and advanced meta-filtering capabilities, check out the documentation.

    All of this comes with one limitation. Access to any field is safe but unprotected, meaning any external access to specific fields (e.g., protected by a spinlock) is not synchronized. This is normally not an issue for a Retis use case, but it's always good to keep it in mind while debugging.

    Returning to our previous example, to limit the captured events to packets traversing the root netns, we may consider filtering on its netns inum and cookie, using the following meta-filtering expression:

    sk_buff.dev.nd_net.net.ns.inum == 4026531840 and sk_buff.dev.nd_net.net.net_cookie == 0x1.

     

    We also enable the skb-tracking collector to provide enhanced visibility of the tracking information. Once the capture begins, the first two events show that the ICMP echo request is received on veth00 in the root network namespace, and the same packet is then transmitted from veth10 to its peer:

    > sudo retis -p ifdump collect -c skb,dev,ns,skb-tracking -f "icmp and net 10.0.0.0/24" \
        -m "sk_buff.dev.nd_net.net.ns.inum == 4026531840 and sk_buff.dev.nd_net.net.net_cookie == 0x1"
    [...]
    59603498163280 (22) [ping] 107888 [tp] net:netif_receive_skb #bb86bbe8aeffff8f03defdc200 (skb ffff8f0f97684000)
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 22544 off 0 [DF] len 84 proto ICMP (1)
       type 8 code 0
     ns 0x1/4026531840 if 208 (veth00)
    59603498172337 (22) [ping] 107888 [tp] net:net_dev_start_xmit #bb86bbe8aeffff8f03defdc200 (skb ffff8f0f97684000)
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 22544 off 0 [DF] len 84 proto ICMP (1)
       type 8 code 0
     ns 0x1/4026531840 if 210 (veth10) rxif 208

    The next entry shows the peer receiving the packet, an event not belonging to the root netns (with 0xd014/4026535413 identifying ns1). But a closer look at the tracking information (right after the tracepoint identifier) reveals that's exactly what we expect:

    59603498175102 (22) [ping] 107888 [tp] net:netif_receive_skb #bb86bbe8aeffff8f03defdc200 (skb ffff8f0f97684000)
     10.0.0.2 > 10.0.0.3 tos 0x0 ttl 64 id 22544 off 0 [DF] len 84 proto ICMP (1)
       type 8 code 0
     ns 0xd014/4026535413 if 209 (veth11)

    This is because filtering is not a standalone component; it's tied to Retis's built-in tracking feature. This ensures we can follow a packet's entire journey through the network stack, even if it moves into a different network namespace that no longer matches the original filter. We'll discuss more about this in the next section.

    For completeness, the capture shows a similar event sequence for the ICMP echo reply:

    59603498193457 (22) [ping] 107888 [tp] net:netif_receive_skb #bb86bc9074ffff8f03defd9080 (skb ffff8f03e1d92e00)
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 59703 off 0 len 84 proto ICMP (1)
       type 0 code 0
     ns 0x1/4026531840 if 210 (veth10)
    59603498195791 (22) [ping] 107888 [tp] net:net_dev_start_xmit #bb86bc9074ffff8f03defd9080 (skb ffff8f03e1d92e00)
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 59703 off 0 len 84 proto ICMP (1) 
       type 0 code 0
     ns 0x1/4026531840 if 208 (veth00) rxif 210
    59603498197384 (22) [ping] 107888 [tp] net:netif_receive_skb #bb86bc9074ffff8f03defd9080 (skb ffff8f03e1d92e00)
     10.0.0.3 > 10.0.0.2 tos 0x0 ttl 64 id 59703 off 0 len 84 proto ICMP (1)
       type 0 code 0
     ns 0x5006/4026535345 if 207 (veth01)

    As we've seen, Retis filters work alongside packet tracking. This ensures, once the filters emits a match verdict, that a packet can be followed even after it is encapsulated, manipulated, or in general its data and metadata no longer match the initial criteria specified in the filtering expressions.

    Combining filtering and tracking

    We've previously introduced the interaction between filtering and tracking, but without clearly defining what to expect from it. Let's consider our last example, which also filtered by namespace:

    > retis collect -p ifdump collect -c skb,dev,ns,skb-tracking -f "icmp and net 10.0.0.0/24" \
       -m 'sk_buff.dev.nd_net.net.ns.inum == 4026531840 and \
       sk_buff.dev.nd_net.net.net_cookie == 0x1'

    When the ICMP echo request is sent from ns0, the packet goes through veth01, and Retis processes the echo request as follows:

    >> net:net_dev_start_xmit {ns0, veth01}
       <tracking check (miss)>
       <packet filter (no match)>
       <meta filter (no match)>
       <event not sent>
      >> net:netif_receive_skb {rootns, veth00}
         <tracking check (miss)>
         <packet filter (match)>
         <meta filter (match)>
         <packet starts getting tracked>
         <event sent>
        >> net:net_dev_start_xmit {rootns, veth10}
           <tracking check (hit)>
           <event sent>
          >> net:netif_receive_skb {ns1, veth11}
             <tracking check (hit)>
             <event sent>

    As this sequence illustrates, filtering occurs for untracked packets. If all the specified filters match, packet tracking starts operating. From this point, Retis generates the new events for the tracked packet, ideally throughout the skb's lifetime across all probes.

    Learn more

    In this article, we demonstrated how Retis adopts familiar concepts already used by other popular tools. We introduced more concepts behind filtering and the interaction with packet tracking, while clarifying how they work and what to expect. We learned that, when an untracked packet hits the first probe point, it's subjected to packet and metadata filtering. If a packet matches all the applied filters, packet tracking activates, ensuring that monitoring continues throughout the packet journey in the networking stack, regardless of subsequent changes.

    As Retis evolves, future iterations may further enhance filtering and tracking granularity, providing users with increased control and power to simplify network troubleshooting. Visit the Retis open source project to review its code.

    Related Posts

    • Dumping packets from anywhere in the networking stack

    • Tracing packets inside Open vSwitch

    • How to retrieve packet drop reasons in the Linux kernel

    • Packet capture using Network Observability eBPF Agent

    Recent Posts

    • Autoscaling vLLM with OpenShift AI

    • Filtering packets from anywhere in the networking stack

    • PostGIS: A powerful geospatial extension for PostgreSQL

    • Kafka Monthly Digest: September 2025

    • A more secure way to handle secrets in OpenShift

    What’s up next?

    Open source AI for developers introduces and covers key features of Red Hat OpenShift AI, including Jupyter Notebooks, PyTorch, and enhanced monitoring and observability tools, along with MLOps and continuous integration/continuous deployment (CI/CD) workflows.

    Get the e-book
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue