EtherTAP - Collecting Packets
 
 

EtherTAP - Collecting Packets

May 5, 2025
development, projects, HOWTO
EtherTAP, IXDP, AF_XDP, libxdp, RPCL

Collecting Packets with EtherTAP #

Useful Preliminary Information #

The ixdp.pqueue.tap Packet Queue #

ixdp.pqueue.tap is a fast multi-producer/multi-consumer packet queue in shared memory and synchronized with POSIX semaphores. Producers are typically the IXDP threads (one per configured queue), consumer is the collect program (which may be started multiple times in parallel). The controlling RPCL interpreter can also act as a consumer with the tap.queue.get word.

In the Linux shared memory namespace /dev/shm this packet queue appears like this:

$ ls -l /dev/shm 
-rwx------ 1 root root 8392768 May  5 00:49 ixdp.pqueue.tap
$

RPCL Words #

The TAP machash #

The TAP machash defines a set of MAC addresses which allows to restrict packets sent to the IXDP packet queue ixdp.pqueue.tap following these rules:

  • If the TAP machash is empty, all packets qualify to be inserted into the IXDP packet queue.
  • If the TAP machash contains one ore more MAC addresses, a packet qualifies to be inserted if either the source MAC address or the destination MAC address is present.

tap.hash.insert #

add specific MAC address to TAP ( mac - )

Example, inserting 3 MAC addresses:

ok tap.hash.show
ok 00:23:7d:86:71:ff tap.hash.insert
ok 50:1e:2d:49:c2:24 tap.hash.insert 
ok 3c:2a:f4:07:f0:4b tap.hash.insert
ok tap.hash.show
00:23:7d:86:71:ff Hewlett Packard
50:1e:2d:49:c2:24 StreamUnlimited Engineering GmbH
3c:2a:f4:07:f0:4b Brother Industries, LTD.
ok

tap.hash.reset #

reset TAP machash to 0 elements ( - )

Example:

ok tap.hash.show
00:23:7d:86:71:ff Hewlett Packard
50:1e:2d:49:c2:24 StreamUnlimited Engineering GmbH
3c:2a:f4:07:f0:4b Brother Industries, LTD.
ok tap.hash.reset
ok tap.hash.show
ok

tap.hash.show #

show TAP machash ( - )

tap.hash.show shows additionally the Ethernet/OUI manufacturer information (if there’s a match) or recognizes locally administered addresses as such.

Example:

ok tap.hash.show
ok 52:54:00:23:b1:1a tap.hash.insert
ok tap.hash.show
52:54:00:23:b1:1a Locally Administered Address (LAA)
ok

Queue operations #

tap.queue.get #

retrieve packet from TAP queue ( - packet )

Here the RPCL controlling interpreter acts as a packet queue consumer, retrieves the next packet and leaves its contents and length as data on the stack. When there’s no packet in the packet queue, an data type with length 0 is returned.

Example:

ok tap.queue.status
packet queue ixdp.pqueue.tap
  head      27
  tail      28
  inserted  2074
  full      4358
  retrieved 28
ok tap.queue.get
ok tap.queue.status
packet queue ixdp.pqueue.tap
  head      27
  tail      29
  inserted  2074
  full      4360
  retrieved 29
ok .s 
 0 [data length 99]
ok . 
0000  01 80 c2 00 00 0e f0 b2  b9 15 07 ca 88 cc 02 07  |................|
0010  04 f0 b2 b9 15 07 ca 04  07 03 f0 b2 b9 15 07 ca  |................|
0020  06 02 00 79 fe 19 00 80  c2 09 80 00 00 00 00 64  |...y...........d|
0030  00 00 00 00 00 00 00 02  00 00 00 00 00 00 00 fe  |................|
0040  06 00 80 c2 0b 88 00 fe  08 00 80 c2 0c 00 61 89  |..............a.|
0050  06 fe 0e 00 12 0f 05 00  ff 00 ff 00 ff 00 00 00  |................|
0060  00 00 00                                          |...             |
ok tap.queue.reset tap.queue.get .
0000                                                    |                |
ok

tap.queue.reset #

reset (clear) TAP queue ( - )

Example see above.

tap.queue.status #

show TAP packet queue status ( - )

Example see above.

TAP enable/disable #

This set of RPCL words allows to enable and disable TAPping on either RX or TX for each interface. If you wish to preset something by default, just include the desired commands to /etc/ethertap.rpcl.

Example, enabling RX TAP for both interfaces in bridging mode:

if.stats shows interface specific statistics, counters and flags summarized over all configured queues/threads. To show solely the IXDP/AF_XDP counters of a specific interface and queue use if.qstats when required.
ok if.stats
0 enp1s0f0 ixgbe queues:1 ZEROCOPY
  rx                 64183713
  tx                 1946237
  drop               0
  noif               0
  err                0
  RX tap             enabled
  TX tap             disabled
  fault injection    disabled
    drop propability 0 (0.000%) 
    flip propability 0 (0.000%) 
    dropped by FI    0
    flipped by FI    0
1 enp1s0f1 ixgbe queues:1 ZEROCOPY
  rx                 1946246
  tx                 64183713
  drop               9
  noif               0
  err                0
  RX tap             disabled
  TX tap             disabled
  fault injection    disabled
    drop propability 0 (0.000%) 
    flip propability 0 (0.000%) 
    dropped by FI    0
    flipped by FI    0
ok 0 tap.rx.enable
ok 1 tap.rx.enable
ok if.stats
0 enp1s0f0 ixgbe queues:1 ZEROCOPY
  rx                 64183713
  tx                 1946237
  drop               0
  noif               0
  err                0
  RX tap             disabled
  TX tap             disabled
  fault injection    disabled
    drop propability 0 (0.000%) 
    flip propability 0 (0.000%) 
    dropped by FI    0
    flipped by FI    0
1 enp1s0f1 ixgbe queues:1 ZEROCOPY
  rx                 1946246
  tx                 64183713
  drop               9
  noif               0
  err                0
  RX tap             enabled
  TX tap             disabled
  fault injection    disabled
    drop propability 0 (0.000%) 
    flip propability 0 (0.000%) 
    dropped by FI    0
    flipped by FI    0
ok

tap.rx.disable #

disable RX TAP for interface ( interface - )

Example see above.

tap.rx.enable #

enable RX TAP for interface ( interface - )

Example see above.

tap.tx.disable #

disable TX TAP for interface ( interface - )

Example see above.

tap.tx.enable #

enable TX TAP for interface ( interface - )

Example see above.

Collect #

Collect is a consumer of ixdp.pqueue.tap, retrieves the raw packets and generally writes PCAP format either to a file or stdout. The PCAP timestamp is set to the time the packet is written to the PCAP stream.

$ collect -h
usage: collect [options] output.pcap
       options:
       -b|--blimit <n>    specify a byte limit
       -p|--plimit <n>    specify a packet limit
       -q|--queue <q>     specify packet queue
       -n|--noreset       do not empty queue on startup
       -s|--silent        silent mode
       -d|--daemon        detach and run in background
       -h|--help          show usage
       -v|--version       show version
       -c|--copyright     show copyright
$

Collect Options #

-b|–blimit <n> #

This option sets a byte limit for the current collect invocation. When this limit is reached, the PCAP stream is closed and collect exits.

-p|–plimit <n> #

This option sets a packet count limit for the current collect invocation. When this limit is reached, the PCAP stream is closed and collect exits.

-q|–queue <q> #

With -q|queue an alternative packet queue name can be provided, the default is ixdp.pqueue.tap.

-n|–noreset #

With this option, collect does not remove the current packet queue contents on start. This is helpful, if the adminstrator wishes to retrieve waiting packets in the queue.

-s|–silent #

With this option, collect does not visualise the collection progress.

-d|–daemon #

With this option, collect detaches itself and continues to run in background. Note that the PCAP filename should be provided with an absolute path, since the current working directory is changed to / when daemonizing. Also, pipe redirection is not working since the previous stdout as known to the shell gets disconnected by the implicit fork(). The --silent operation is also set automatically with --daemon.

Collect Usage Examples #

Recording to a PCAP File #

Example:

Sending a PCAP Packet Stream to stdout #

Piping directly to tshark -r - looks like this:

$ sudo collect --silent - | tshark -r - 
  ... output omitted ...
$

Running collect in Background #

When collect is started with --daemon, the PCAP file name should be provided with an absolute path, since daemonizing changes the current working directory to /.

Example:

$ sudo collect /tmp/packets.pcap --daemon 
collect going to background ...
$ sudo control collect status
collect PID 22880 running
$ sudo control collect stop 
shutdown of collect PID 22880 complete
$