Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --filter-ifname #257

Merged
merged 4 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,16 @@ jobs:
ping -W1 -c1 10.0.0.1 || true
expected-output-pattern: 'arp_rcv'

- name: Test --filter-ifname
uses: ./.github/actions/pwru-test
with:
test-name: filter-ifname
pwru-flags: --filter-ifname lo
pwru-pcap-filter: icmp
traffic-setup: |
ping -W1 -c1 127.0.0.1 || true
expected-output-pattern: 'icmp'

- name: Fetch artifacts
if: ${{ !success() }}
uses: cilium/little-vm-helper@908ab1ff8a596a03cd5221a1f8602dc44c3f906d
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Usage: pwru [options] [pcap-filter]
--backend string Tracing backend('kprobe', 'kprobe-multi'). Will auto-detect if not specified.
--filter-func string filter kernel functions to be probed by name (exact match, supports RE2 regular expression)
--filter-mark uint32 filter skb mark
--filter-netns uint32 filter netns inode
--filter-netns string filter netns ("/proc/<pid>/ns/net", "inode:<inode>")
--filter-track-skb trace a packet even if it does not match given filters (e.g., after NAT or tunnel decapsulation)
--kernel-btf string specify kernel BTF file
--kmods strings list of kernel modules names to attach to
Expand Down
5 changes: 4 additions & 1 deletion bpf/kprobe_pwru.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct {
struct config {
u32 netns;
u32 mark;
u32 ifindex;
u8 output_timestamp;
u8 output_meta;
u8 output_tuple;
Expand Down Expand Up @@ -106,7 +107,6 @@ struct {
} print_skb_map SEC(".maps");
#endif


static __always_inline u32
get_netns(struct sk_buff *skb) {
u32 netns = BPF_CORE_READ(skb, dev, nd_net.net, ns.inum);
Expand All @@ -130,6 +130,9 @@ filter_meta(struct sk_buff *skb) {
if (cfg->mark && BPF_CORE_READ(skb, mark) != cfg->mark) {
return false;
}
if (cfg->ifindex != 0 && BPF_CORE_READ(skb, dev, ifindex) != cfg->ifindex) {
return false;
}
return true;
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/cloudflare/cbpfc v0.0.0-20221017140110-11acb56438a2
github.com/mitchellh/go-ps v1.0.0
github.com/spf13/pflag v1.0.5
github.com/vishvananda/netns v0.0.4
golang.org/x/net v0.15.0
golang.org/x/sys v0.12.0
golang.org/x/tools v0.13.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
Expand Down
89 changes: 80 additions & 9 deletions internal/pwru/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@

package pwru

import (
"fmt"
"net"
"runtime"
"strconv"
"strings"

"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)

// Version is the pwru version and is set at compile time via LDFLAGS-
var Version string = "version unknown"

type FilterCfg struct {
FilterNetns uint32
FilterMark uint32
FilterNetns uint32
FilterMark uint32
FilterIfindex uint32

// TODO: if there are more options later, then you can consider using a bit map
OutputRelativeTS uint8
Expand All @@ -22,11 +34,10 @@ type FilterCfg struct {
TrackSkb byte
}

func GetConfig(flags *Flags) FilterCfg {
cfg := FilterCfg{
FilterNetns: flags.FilterNetns,
FilterMark: flags.FilterMark,
IsSet: 1,
func GetConfig(flags *Flags) (cfg FilterCfg, err error) {
cfg = FilterCfg{
FilterMark: flags.FilterMark,
IsSet: 1,
}
if flags.OutputSkb {
cfg.OutputSkb = 1
Expand All @@ -40,10 +51,70 @@ func GetConfig(flags *Flags) FilterCfg {
if flags.OutputStack {
cfg.OutputStack = 1
}

if flags.FilterTrackSkb {
cfg.TrackSkb = 1
}

return cfg
netnsID, ns, err := parseNetns(flags.FilterNetns)
if err != nil {
return
}
if flags.FilterIfname != "" || flags.FilterNetns != "" {
cfg.FilterNetns = netnsID
}
if cfg.FilterIfindex, err = parseIfindex(flags.FilterIfname, ns); err != nil {
return
}
return
}

func parseNetns(netnsSpecifier string) (netnsID uint32, ns netns.NsHandle, err error) {
switch {
case netnsSpecifier == "":
ns, err = netns.Get()
case strings.HasPrefix(netnsSpecifier, "/"):
ns, err = netns.GetFromPath(netnsSpecifier)
case strings.HasPrefix(netnsSpecifier, "inode:"):
var netnsInode int
netnsInode, err = strconv.Atoi(netnsSpecifier[6:])
netnsID = uint32(netnsInode)
default:
err = fmt.Errorf("invalid netns specifier: %s", netnsSpecifier)
}
if ns == 0 || err != nil {
return
}
var s unix.Stat_t
if err = unix.Fstat(int(ns), &s); err != nil {
return
}
return uint32(s.Ino), ns, nil
}

func parseIfindex(ifname string, ns netns.NsHandle) (ifindex uint32, err error) {
if ifname == "" {
return
}
if ns == 0 {
return 0, fmt.Errorf("inode netns specifier cannot be used with --filter-ifname")
}

runtime.LockOSThread()
defer runtime.UnlockOSThread()

currentNetns, err := netns.Get()
if err != nil {
return
}
defer netns.Set(currentNetns)

if err = netns.Set(ns); err != nil {
return
}

iface, err := net.InterfaceByName(ifname)
if err != nil {
return
}
return uint32(iface.Index), nil
}
8 changes: 5 additions & 3 deletions internal/pwru/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ type Flags struct {

KernelBTF string

FilterNetns uint32
FilterNetns string
FilterMark uint32
FilterFunc string
FilterTrackSkb bool
FilterIfname string
FilterPcap string

OutputTS string
Expand All @@ -53,15 +54,16 @@ func (f *Flags) SetFlags() {
flag.StringSliceVar(&f.KMods, "kmods", nil, "list of kernel modules names to attach to")
flag.BoolVar(&f.AllKMods, "all-kmods", false, "attach to all available kernel modules")
flag.StringVar(&f.FilterFunc, "filter-func", "", "filter kernel functions to be probed by name (exact match, supports RE2 regular expression)")
flag.Uint32Var(&f.FilterNetns, "filter-netns", 0, "filter netns inode")
flag.StringVar(&f.FilterNetns, "filter-netns", "", "filter netns (\"/proc/<pid>/ns/net\", \"inode:<inode>\")")
flag.Uint32Var(&f.FilterMark, "filter-mark", 0, "filter skb mark")
flag.BoolVar(&f.FilterTrackSkb, "filter-track-skb", false, "trace a packet even if it does not match given filters (e.g., after NAT or tunnel decapsulation)")
flag.StringVar(&f.FilterIfname, "filter-ifname", "", "filter skb ifname in --filter-netns (if not specified, use current netns)")
flag.StringVar(&f.OutputTS, "timestamp", "none", "print timestamp per skb (\"current\", \"relative\", \"absolute\", \"none\")")
flag.BoolVar(&f.OutputMeta, "output-meta", false, "print skb metadata")
flag.BoolVar(&f.OutputTuple, "output-tuple", false, "print L4 tuple")
flag.BoolVar(&f.OutputSkb, "output-skb", false, "print skb")
flag.BoolVar(&f.OutputStack, "output-stack", false, "print stack")
flag.Uint64Var(&f.OutputLimitLines, "output-limit-lines", 0, "exit the program after the number of events has been received/printed")
flag.BoolVar(&f.FilterTrackSkb, "filter-track-skb", false, "trace a packet even if it does not match given filters (e.g., after NAT or tunnel decapsulation)")

flag.StringVar(&f.OutputFile, "output-file", "", "write traces to file")

Expand Down
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,12 @@ func main() {
}
}

pwruConfig, err := pwru.GetConfig(&flags)
if err != nil {
log.Fatalf("Failed to get pwru config: %v", err)
}
if err := bpfSpec.RewriteConstants(map[string]interface{}{
"CFG": pwru.GetConfig(&flags),
"CFG": pwruConfig,
}); err != nil {
log.Fatalf("Failed to rewrite config: %v", err)
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading