5
5
package pwru
6
6
7
7
import (
8
+ "errors"
8
9
"fmt"
9
10
"io"
10
11
"log"
11
12
"net"
12
13
"os"
14
+ "path/filepath"
13
15
"runtime"
16
+ "strconv"
14
17
"syscall"
15
18
"time"
16
19
17
20
"github.com/cilium/ebpf"
18
21
"github.com/cilium/ebpf/btf"
22
+ "github.com/jsimonetti/rtnetlink"
19
23
ps "github.com/mitchellh/go-ps"
24
+ "github.com/vishvananda/netns"
25
+ "golang.org/x/sys/unix"
20
26
21
27
"github.com/cilium/pwru/internal/byteorder"
22
28
)
@@ -32,6 +38,7 @@ type output struct {
32
38
writer io.Writer
33
39
kprobeMulti bool
34
40
kfreeReasons map [uint64 ]string
41
+ ifaceCache map [uint64 ]map [uint32 ]string
35
42
}
36
43
37
44
func NewOutput (flags * Flags , printSkbMap * ebpf.Map , printStackMap * ebpf.Map ,
@@ -52,6 +59,14 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
52
59
log .Printf ("Unable to load packet drop reaons: %v" , err )
53
60
}
54
61
62
+ var ifs map [uint64 ]map [uint32 ]string
63
+ if flags .OutputMeta {
64
+ ifs , err = getIfaces ()
65
+ if err != nil {
66
+ log .Printf ("Failed to retrieve all ifaces from all network namespaces: %v. Some iface names might be not shown." , err )
67
+ }
68
+ }
69
+
55
70
return & output {
56
71
flags : flags ,
57
72
lastSeenSkb : map [uint64 ]uint64 {},
@@ -61,6 +76,7 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
61
76
writer : writer ,
62
77
kprobeMulti : kprobeMulti ,
63
78
kfreeReasons : reasons ,
79
+ ifaceCache : ifs ,
64
80
}, nil
65
81
}
66
82
@@ -132,7 +148,10 @@ func (o *output) Print(event *Event) {
132
148
o .lastSeenSkb [event .SAddr ] = event .Timestamp
133
149
134
150
if o .flags .OutputMeta {
135
- fmt .Fprintf (o .writer , " netns=%d mark=0x%x ifindex=%d proto=%x mtu=%d len=%d" , event .Meta .Netns , event .Meta .Mark , event .Meta .Ifindex , event .Meta .Proto , event .Meta .MTU , event .Meta .Len )
151
+ fmt .Fprintf (o .writer , " netns=%d mark=0x%x iface=%s proto=%x mtu=%d len=%d" ,
152
+ event .Meta .Netns , event .Meta .Mark ,
153
+ o .getIfaceName (event .Meta .Netns , event .Meta .Ifindex ),
154
+ event .Meta .Proto , event .Meta .MTU , event .Meta .Len )
136
155
}
137
156
138
157
if o .flags .OutputTuple {
@@ -165,6 +184,15 @@ func (o *output) Print(event *Event) {
165
184
fmt .Fprintln (o .writer )
166
185
}
167
186
187
+ func (o * output ) getIfaceName (netnsInode , ifindex uint32 ) string {
188
+ if ifaces , ok := o .ifaceCache [uint64 (netnsInode )]; ok {
189
+ if name , ok := ifaces [ifindex ]; ok {
190
+ return fmt .Sprintf ("%d(%s)" , ifindex , name )
191
+ }
192
+ }
193
+ return fmt .Sprintf ("%d" , ifindex )
194
+ }
195
+
168
196
func protoToStr (proto uint8 ) string {
169
197
switch proto {
170
198
case syscall .IPPROTO_TCP :
@@ -212,3 +240,97 @@ func getKFreeSKBReasons(spec *btf.Spec) (map[uint64]string, error) {
212
240
213
241
return ret , nil
214
242
}
243
+
244
+ func getIfaces () (map [uint64 ]map [uint32 ]string , error ) {
245
+ var err error
246
+ procPath := "/proc"
247
+
248
+ ifaceCache := make (map [uint64 ]map [uint32 ]string )
249
+
250
+ dirs , err := os .ReadDir (procPath )
251
+ if err != nil {
252
+ return nil , err
253
+ }
254
+
255
+ for _ , d := range dirs {
256
+ if ! d .IsDir () {
257
+ continue
258
+ }
259
+
260
+ // skip non-process dirs
261
+ if _ , err := strconv .Atoi (d .Name ()); err != nil {
262
+ continue
263
+ }
264
+
265
+ // get inode of netns
266
+ path := filepath .Join (procPath , d .Name (), "ns" , "net" )
267
+ fd , err0 := os .Open (path )
268
+ if err0 != nil {
269
+ err = errors .Join (err , err0 )
270
+ continue
271
+ }
272
+ var stat unix.Stat_t
273
+ if err0 := unix .Fstat (int (fd .Fd ()), & stat ); err != nil {
274
+ err = errors .Join (err , err0 )
275
+ continue
276
+ }
277
+ inode := stat .Ino
278
+
279
+ if _ , exists := ifaceCache [inode ]; exists {
280
+ continue // we already checked that netns
281
+ } else {
282
+ ifaceCache [inode ] = make (map [uint32 ]string )
283
+ }
284
+
285
+ ifaces , err0 := getIfacesInNetNs (path )
286
+ if err0 != nil {
287
+ err = errors .Join (err , err0 )
288
+ continue
289
+ }
290
+
291
+ ifaceCache [inode ] = ifaces
292
+
293
+ }
294
+
295
+ return ifaceCache , err
296
+
297
+ }
298
+
299
+ func getIfacesInNetNs (path string ) (map [uint32 ]string , error ) {
300
+ current , err := netns .Get ()
301
+ if err != nil {
302
+ return nil , err
303
+ }
304
+
305
+ remote , err := netns .GetFromPath (path )
306
+ if err != nil {
307
+ return nil , err
308
+ }
309
+
310
+ runtime .LockOSThread ()
311
+ defer runtime .UnlockOSThread ()
312
+
313
+ if err := netns .Set (remote ); err != nil {
314
+ return nil , err
315
+ }
316
+
317
+ defer netns .Set (current )
318
+
319
+ conn , err := rtnetlink .Dial (nil )
320
+ if err != nil {
321
+ return nil , err
322
+ }
323
+ defer conn .Close ()
324
+
325
+ msg , err := conn .Link .List ()
326
+ if err != nil {
327
+ return nil , err
328
+ }
329
+
330
+ ifaces := make (map [uint32 ]string )
331
+ for _ , link := range msg {
332
+ ifaces [link .Index ] = link .Attributes .Name
333
+ }
334
+
335
+ return ifaces , nil
336
+ }
0 commit comments