1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
#+EXPORT_FILE_NAME: xdpdump
#+TITLE: xdpdump
#+MAN_CLASS_OPTIONS: :section-id "8\" \"DATE\" \"VERSION\" \"a simple tcpdump like tool for capturing packets at the XDP layer"
# This file serves both as a README on github, and as the source for the man
# page; the latter through the org-mode man page export support.
# .
# To export the man page, simply use the org-mode exporter; (require 'ox-man) if
# it's not available.
# .
# The org-mode export doesn't support extended title lines, so manually copy
# over the first line of the resulting .man file before exporting and
# committing.
* xdpdump - a simple tcpdump like tool for capturing packets at the XDP layer
=xdpdump= is a simple XDP packet capture tool that tries to behave similar to
=tcpdump=, however, it has no packet filter or decode capabilities.
This can be used for debugging XDP programs that are already loaded on an
interface. Packets can be dumped/inspected before on *entry* to XDP program,
or after at *exit* from an XDP program. Furthermore, at *exit* the XDP
action is also captured. This means that even packets that are dropped at the
XDP layer can be captured via this tool.
=xdpdump= works by attaching a bpf trace program to the XDP entry and/or exit
function which stores the raw packet in a perf trace buffer. If no XDP program
is loaded this approach can not be used and the tool will use a libpcap
live-capture to be backward compatible.
** Running xdpdump
The syntax for running =xdpdump= is:
#+begin_src
Usage: xdpdump [options]
XDPDump tool to dump network traffic
Options:
--rx-capture <mode> Capture point for the rx direction (valid values: entry,exit)
-D, --list-interfaces Print the list of available interfaces
-i, --interface <ifname> Name of interface to capture on
--perf-wakeup <events> Wake up xdpdump every <events> packets
-p, --program-names <prog> Specific program to attach to
-s, --snapshot-length <snaplen> Minimum bytes of packet to capture
--use-pcap Use legacy pcap format for XDP traces
-w, --write <file> Write raw packets to pcap file
-x, --hex Print the full packet in hex
-v, --verbose Enable verbose logging (-vv: more verbose)
--version Display version information
-h, --help Show this help
#+end_src
* The options explained
The =xdpdump= tool tries to mimic the basic =tcpdump= options, but just in case
below each of the available options is explained:
** --rx-capture <mode>
Specify where the ingress packet gets captured. Either at the entry of the XDP
program and/or exit of the XDP program. Valid options are *entry*, *exit*,
or both *entry,exit*. The packet at *exit* can be modified by the XDP
program. If you are interested to see both the original and modified packet,
use the *entry,exit* option. With this, each packet is captured twice. The
default value for this is *entry*.
** -D, --list-interfaces
Display a list of available interfaces and any XDP program loaded
** --load-xdp-mode
Specifies which loader mode to use with the =--load-xdp-program= option. The
valid values are ‘native’, which is the default in-driver XDP mode, ‘skb’, which
causes the so-called skb mode (also known as generic XDP) to be used, ‘hw’ which
causes the program to be offloaded to the hardware, or ‘unspecified’ which
leaves it up to the kernel to pick a mode (which it will do by picking native
mode if the driver supports it, or generic mode otherwise). Note that using
‘unspecified’ can make it difficult to predict what mode a program will end up
being loaded in. For this reason, the default is ‘native’.
** --load-xdp-program
If no XDP program is loaded on the interface, by default, xdpdump will fallback
to libpcap's live capture mode to capture the packets. Alternatively, with this
option, you can ask xdpdump to load an XDP program to capture the packets
directly.
** -i, --interface <ifname>
Listen on interface =ifname=. Note that if no XDP program is loaded on the
interface it will use libpcap's live capture mode to capture the packets.
** --perf-wakeup <events> :feat_perfbuf:
Let the Kernel wake up =xdpdump= once for every =<events>= being posted in the
perf ring buffer. The higher the number the less the impact is on the actual
XDP program. The default value is 0, which automatically calculates the
value based on the available CPUs/buffers. Use -v to see the actual used value.
** -p, --program-names [<prog>|all]
This option allows you to capture packets for a specific, set of, or all XDP
programs loaded on the interface. You can either specify the actual program
names or program IDs separated by commas. In the case where multiple programs
are attached with the same name, you should use the program ID. Use the -D
option to see the loaded programs and their IDs.
In addition, the Linux API does not provide the full name of the attached eBPF
entry function if it's longer than 15 characters. xdpdump will try to guess the
correct function name from the available BTF debug information. However, if
multiple functions exist with the same leading name, it can not pick the correct
one. It will dump the available functions, and you can choose the correct one,
and supply it with this option. If you have programs with duplicate long names,
you also need to specify the program ID with the full name. This can be done by
adding the id to the name with the =@<id>= suffix.
** -P, --promiscuous-mode
This option puts the interface into promiscuous mode.
** -s, --snapshot-length <snaplen>
Capture *snaplen* bytes of a packet rather than the default 262144 bytes.
** --use-pcap
Use legacy pcap format for XDP traces. By default, it will use the PcapNG format
so that it can store various metadata.
** -w, --write <file>
Write the raw packets to a pcap file rather than printing them out hexadecimal. Standard output is used if *file* is =-=.
** -x, --hex
When dumping packets on the console also print the full packet content in hex.
** -v, --verbose
Enable debug logging. Specify twice for even more verbosity.
** --version
Display =xpdump= version information and exit.
** -h, --help
Display a summary of the available options
* Examples
The below will load the =xdp-filter= program on eth0, but it does not do any
actual filtering:
#+begin_src
# xdp-filter load --mode skb eth0
#
# xdpdump -D
Interface Prio Program name Mode ID Tag Chain actions
--------------------------------------------------------------------------------------
lo <No XDP program loaded!>
eth0 xdp_dispatcher skb 10651 d51e469e988d81da
=> 10 xdpfilt_alw_all 10669 0b394f43ab24501c XDP_PASS
#+end_src
Now we can try =xdpdump=:
#+begin_src
# xdpdump -i eth0 -x
listening on eth0, ingress XDP program ID 10651 func xdp_dispatcher, capture mode entry, capture size 262144 bytes
1584373839.460733895: xdp_dispatcher()@entry: packet size 102 bytes, captured 102 bytes on if_index 2, rx queue 0, id 1
0x0000: 52 54 00 db 44 b6 52 54 00 34 38 da 08 00 45 48 RT..D.RT.48...EH
0x0010: 00 58 d7 dd 40 00 40 06 ec c3 c0 a8 7a 01 c0 a8 .X..@.@.....z...
0x0020: 7a 64 9c de 00 16 0d d5 c6 bc 46 c9 bb 11 80 18 zd........F.....
0x0030: 01 f5 7b b4 00 00 01 01 08 0a 77 0a 8c b8 40 12 ..{.......w...@.
0x0040: cc a6 00 00 00 10 54 ce 6e 20 c3 e7 da 6c 08 42 ......T.n ...l.B
0x0050: d6 d9 ee 42 42 f0 82 c9 4f 12 ed 7b 19 ab 22 0d ...BB...O..{..".
0x0060: 09 29 a9 ee df 89 .)....
1584373839.462340808: xdp_dispatcher()@entry: packet size 66 bytes, captured 66 bytes on if_index 2, rx queue 0, id 2
0x0000: 52 54 00 db 44 b6 52 54 00 34 38 da 08 00 45 48 RT..D.RT.48...EH
0x0010: 00 34 d7 de 40 00 40 06 ec e6 c0 a8 7a 01 c0 a8 .4..@.@.....z...
0x0020: 7a 64 9c de 00 16 0d d5 c6 e0 46 c9 bc 85 80 10 zd........F.....
0x0030: 01 f5 74 0c 00 00 01 01 08 0a 77 0a 8c ba 40 12 ..t.......w...@.
0x0040: d2 34 .4
^C
2 packets captured
0 packets dropped by perf ring
#+end_src
Below are two more examples redirecting the capture file to =tcpdump= or
=tshark=:
#+begin_src
# xdpdump -i eth0 -w - | tcpdump -r - -n
listening on eth0, ingress XDP program ID 10651 func xdp_dispatcher, capture mode entry, capture size 262144 bytes
reading from file -, link-type EN10MB (Ethernet)
15:55:09.075887 IP 192.168.122.1.40928 > 192.168.122.100.ssh: Flags [P.], seq 3857553815:3857553851, ack 3306438882, win 501, options [nop,nop,TS val 1997449167 ecr 1075234328], length 36
15:55:09.077756 IP 192.168.122.1.40928 > 192.168.122.100.ssh: Flags [.], ack 37, win 501, options [nop,nop,TS val 1997449169 ecr 1075244363], length 0
15:55:09.750230 IP 192.168.122.1.40928 > 192.168.122.100.ssh: Flags [P.], seq 36:72, ack 37, win 501, options [nop,nop,TS val 1997449842 ecr 1075244363], length 36
#+end_src
#+begin_src
# xdpdump -i eth0 -w - | tshark -r - -n
listening on eth0, ingress XDP program ID 10651 func xdp_dispatcher, capture mode entry, capture size 262144 bytes
1 0.000000 192.168.122.1 → 192.168.122.100 SSH 102 Client: Encrypted packet (len=36)
2 0.000646 192.168.122.1 → 192.168.122.100 TCP 66 40158 → 22 [ACK] Seq=37 Ack=37 Win=1467 Len=0 TSval=1997621571 TSecr=1075416765
3 12.218164 192.168.122.1 → 192.168.122.100 SSH 102 Client: Encrypted packet (len=36)
#+end_src
One final example capturing specific XDP programs loaded on the interface:
#+begin_src
# xdpdump -D
Interface Prio Program name Mode ID Tag Chain actions
--------------------------------------------------------------------------------------
lo <No XDP program loaded!>
eth0 xdp_dispatcher skb 10558 d51e469e988d81da
=> 5 xdp_test_prog_w 10576 b5a46c6e9935298c XDP_PASS
=> 10 xdp_pass 10582 3b185187f1855c4c XDP_PASS
=> 10 xdp_pass 10587 3b185187f1855c4c XDP_PASS
#+end_src
We would like to see the packets on the =xdp_dispatcher()= and the 2nd =xdp_pass()= program:
#+begin_src
# xdpdump -i eth0 --rx-capture=entry,exit -p xdp_dispatcher,xdp_pass@10587
or
# xdpdump -i eth0 --rx-capture=entry,exit -p 10558,10587
listening on eth0, ingress XDP program ID 10558 func xdp_dispatcher, ID 10587 func xdp_pass, capture mode entry/exit, capture size 262144 bytes
1607694215.501287259: xdp_dispatcher()@entry: packet size 102 bytes on if_index 2, rx queue 0, id 1
1607694215.501371504: xdp_pass()@entry: packet size 102 bytes on if_index 2, rx queue 0, id 1
1607694215.501383099: xdp_pass()@exit[PASS]: packet size 102 bytes on if_index 2, rx queue 0, id 1
1607694215.501394709: xdp_dispatcher()@exit[PASS]: packet size 102 bytes on if_index 2, rx queue 0, id 1
^C
4 packets captured
0 packets dropped by perf ring
#+end_src
* BUGS
Please report any bugs on Github: https://github.com/xdp-project/xdp-tools/issues
* AUTHOR
=xdpdump= was written by Eelco Chaudron
|