Skip to content

Commit

Permalink
Print drop reason from kfree_skb_reason
Browse files Browse the repository at this point in the history
This commit extracts a drop reason from kfree_skb_reason(), and prints
it when kfree_skb_reason() is called.

The helper was introduced in the v5.17. The second function param of it
contains a drop reason which is the "skb_drop_reason" enum. To extract
enum, we parse the kernel's BTF, as the enum is not considered as UAPI,
and there were already some position changes among its values.

An example output:

    0xffff936378692ce8 6 [curl]             nf_hook_slow 172.20.10.2:33918->1.1.1.1:4240(tcp)
    0xffff936378692ce8 6 [curl] kfree_skb_reason(SKB_DROP_REASON_NETFILTER_DROP) 172.20.10.2:33918->1.1.1.1:4240(tcp)

An alternative approach to passing the second param would have been to
set a BPF cookie when attaching the kprobe to the kfree_skb_reason().
However, that would require creating a new bpf/kprobe_pwru*.c, as
the helper bpf_get_attach_cookie() requires the bpf_link support, and
thus a newer kernel than the v5.3 (min required by pwru).

Signed-off-by: Martynas Pumputis <m@lambda.lt>
  • Loading branch information
brb committed Feb 7, 2023
1 parent 1a55e48 commit 8426338
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
2 changes: 2 additions & 0 deletions bpf/kprobe_pwru.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct event_t {
struct skb_meta meta;
struct tuple tuple;
s64 print_stack_id;
u64 param_second;
u32 cpu_id;
} __attribute__((packed));

Expand Down Expand Up @@ -356,6 +357,7 @@ handle_everything(struct sk_buff *skb, struct pt_regs *ctx, bool has_get_func_ip
event.skb_addr = (u64) skb;
event.ts = bpf_ktime_get_ns();
event.cpu_id = bpf_get_smp_processor_id();
event.param_second = PT_REGS_PARM2(ctx);

bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));

Expand Down
45 changes: 43 additions & 2 deletions internal/pwru/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ package pwru
import (
"fmt"
"io"
"log"
"net"
"os"
"runtime"
"syscall"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/btf"
ps "github.com/mitchellh/go-ps"

"github.com/cilium/pwru/internal/byteorder"
Expand All @@ -26,10 +28,11 @@ type output struct {
addr2name Addr2Name
writer io.Writer
kprobeMulti bool
kfreeReasons map[uint64]string
}

func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
addr2Name Addr2Name, kprobeMulti bool) (*output, error) {
addr2Name Addr2Name, kprobeMulti bool, btfSpec *btf.Spec) (*output, error) {

writer := os.Stdout

Expand All @@ -41,6 +44,11 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
writer = file
}

reasons, err := getKFreeSKBReasons(btfSpec)
if err != nil {
log.Printf("Unable to load packet drop reaons: %v", err)
}

return &output{
flags: flags,
lastSeenSkb: map[uint64]uint64{},
Expand All @@ -49,6 +57,7 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
addr2name: addr2Name,
writer: writer,
kprobeMulti: kprobeMulti,
kfreeReasons: reasons,
}, nil
}

Expand Down Expand Up @@ -96,8 +105,18 @@ func (o *output) Print(event *Event) {
} else {
funcName = fmt.Sprintf("0x%x", addr)
}

outFuncName := funcName
if funcName == "kfree_skb_reason" {
if reason, ok := o.kfreeReasons[event.ParamSecond]; ok {
outFuncName = fmt.Sprintf("%s(%s)", funcName, reason)
} else {
outFuncName = fmt.Sprintf("%s (%d)", funcName, event.ParamSecond)
}
}

fmt.Fprintf(o.writer, "%18s %6s %16s %24s", fmt.Sprintf("0x%x", event.SAddr),
fmt.Sprintf("%d", event.CPU), fmt.Sprintf("[%s]", execName), funcName)
fmt.Sprintf("%d", event.CPU), fmt.Sprintf("[%s]", execName), outFuncName)
if o.flags.OutputTS != "none" {
fmt.Fprintf(o.writer, " %16d", ts)
}
Expand Down Expand Up @@ -162,3 +181,25 @@ func addrToStr(proto uint16, addr [16]byte) string {
return ""
}
}

// getKFreeSKBReasons dervices SKB drop reasons from the "skb_drop_reason" enum
// defined in /include/net/dropreason.h.
func getKFreeSKBReasons(spec *btf.Spec) (map[uint64]string, error) {
if _, err := spec.AnyTypeByName("kfree_skb_reason"); err != nil {
// Kernel is too old to have kfree_skb_reason
return nil, nil
}

var dropReasonsEnum *btf.Enum
if err := spec.TypeByName("skb_drop_reason", &dropReasonsEnum); err != nil {
return nil, fmt.Errorf("failed to find 'skb_drop_reason' enum: %v", err)
}

ret := map[uint64]string{}
for _, val := range dropReasonsEnum.Values {
ret[uint64(val.Value)] = val.Name

}

return ret, nil
}
1 change: 1 addition & 0 deletions internal/pwru/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ type Event struct {
Meta Meta
Tuple Tuple
PrintStackId int64
ParamSecond uint64
CPU uint32
}

Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func main() {
file.Close()
}

output, err := pwru.NewOutput(&flags, printSkbMap, printStackMap, addr2name, useKprobeMulti)
output, err := pwru.NewOutput(&flags, printSkbMap, printStackMap, addr2name, useKprobeMulti, btfSpec)
if err != nil {
log.Fatalf("Failed to create outputer: %s", err)
}
Expand Down

0 comments on commit 8426338

Please sign in to comment.