Skip to content

Commit

Permalink
Improve compatible with old kernel (#88)
Browse files Browse the repository at this point in the history
* improve compatible with old kernel

* fix "unknown func bpf_get_socket_cookie#46"

* avoid message not include \n on the old kernel
  • Loading branch information
mozillazg authored Jul 17, 2024
1 parent 52816bf commit 9a639ef
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 99 deletions.
61 changes: 14 additions & 47 deletions bpf/bpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,6 @@ import (
const tcFilterName = "ptcpdump"
const logSzie = ebpf.DefaultVerifierLogSize * 64

type BpfObjectsWithoutCgroup struct {
KprobeTcpSendmsg *ebpf.Program `ebpf:"kprobe__tcp_sendmsg"`
KprobeUdpSendmsg *ebpf.Program `ebpf:"kprobe__udp_sendmsg"`
KprobeUdpSendSkb *ebpf.Program `ebpf:"kprobe__udp_send_skb"`
KprobeNfNatManipPkt *ebpf.Program `ebpf:"kprobe__nf_nat_manip_pkt"`
KprobeNfNatPacket *ebpf.Program `ebpf:"kprobe__nf_nat_packet"`
KprobeSecuritySkClassifyFlow *ebpf.Program `ebpf:"kprobe__security_sk_classify_flow"`
RawTracepointSchedProcessExec *ebpf.Program `ebpf:"raw_tracepoint__sched_process_exec"`
RawTracepointSchedProcessExit *ebpf.Program `ebpf:"raw_tracepoint__sched_process_exit"`
RawTracepointSchedProcessFork *ebpf.Program `ebpf:"raw_tracepoint__sched_process_fork"`
TcEgress *ebpf.Program `ebpf:"tc_egress"`
TcIngress *ebpf.Program `ebpf:"tc_ingress"`

BpfMaps
}

type BPF struct {
spec *ebpf.CollectionSpec
objs *BpfObjects
Expand Down Expand Up @@ -135,6 +119,7 @@ func (b *BPF) Load(opts Options) error {
MaxPayloadSize: opts.maxPayloadSize,
}
if !b.isLegacyKernel {
log.Debugf("rewrite constants with %+v", config)
err = b.spec.RewriteConstants(map[string]interface{}{
"g": config,
})
Expand Down Expand Up @@ -164,54 +149,36 @@ func (b *BPF) Load(opts Options) error {
}
}

var skipAttachCgroup bool
if b.isLegacyKernel {
skipAttachCgroup = true
} else {
err = b.spec.LoadAndAssign(b.objs, &ebpf.CollectionOptions{
if b.isLegacyKernel || !supportGetSocketCookieWithCgroup() {
b.skipAttachCgroup = true
objs := BpfObjectsForLegacyKernel{}
if err = b.spec.LoadAndAssign(&objs, &ebpf.CollectionOptions{
Programs: ebpf.ProgramOptions{
KernelTypes: opts.KernelTypes,
LogLevel: ebpf.LogLevelInstruction,
LogSize: logSzie,
},
})
}
if err != nil {
if strings.Contains(err.Error(), "unknown func bpf_get_socket_cookie") {
log.Warnf("will skip attach cgroup due to %s", err)
skipAttachCgroup = true
} else {
}); err != nil {
return fmt.Errorf("bpf load: %w", err)
}
}
if skipAttachCgroup {
b.skipAttachCgroup = true
objs := BpfObjectsWithoutCgroup{}
if err = b.spec.LoadAndAssign(&objs, &ebpf.CollectionOptions{
b.objs.FromLegacy(&objs)
} else {
err = b.spec.LoadAndAssign(b.objs, &ebpf.CollectionOptions{
Programs: ebpf.ProgramOptions{
KernelTypes: opts.KernelTypes,
LogLevel: ebpf.LogLevelInstruction,
LogSize: logSzie,
},
}); err != nil {
})
if err != nil {
return fmt.Errorf("bpf load: %w", err)
}
b.objs.KprobeTcpSendmsg = objs.KprobeTcpSendmsg
b.objs.KprobeUdpSendmsg = objs.KprobeUdpSendmsg
b.objs.KprobeUdpSendSkb = objs.KprobeUdpSendSkb
b.objs.KprobeNfNatManipPkt = objs.KprobeNfNatManipPkt
b.objs.KprobeNfNatPacket = objs.KprobeNfNatPacket
b.objs.KprobeSecuritySkClassifyFlow = objs.KprobeSecuritySkClassifyFlow
b.objs.RawTracepointSchedProcessExec = objs.RawTracepointSchedProcessExec
b.objs.RawTracepointSchedProcessExit = objs.RawTracepointSchedProcessExit
b.objs.RawTracepointSchedProcessFork = objs.RawTracepointSchedProcessFork
b.objs.TcEgress = objs.TcEgress
b.objs.TcIngress = objs.TcIngress
b.objs.BpfMaps = objs.BpfMaps
}

b.opts = opts

if b.isLegacyKernel {
log.Debugf("update config map with %+v", config)
key := uint32(0)
if err := b.objs.BpfMaps.ConfigMap.Update(key, config, ebpf.UpdateAny); err != nil {
return fmt.Errorf(": %w", err)
Expand All @@ -238,7 +205,7 @@ func (b *BPF) Close() {

func (b *BPF) UpdateFlowPidMapValues(data map[*BpfFlowPidKeyT]BpfProcessMetaT) error {
for k, v := range data {
err := b.objs.FlowPidMap.Update(*k, v, ebpf.UpdateNoExist)
err := b.objs.BpfMaps.FlowPidMap.Update(*k, v, ebpf.UpdateNoExist)
if err != nil {
if err == ebpf.ErrKeyExist || strings.Contains(err.Error(), "key already exists") {
continue
Expand Down
Binary file modified bpf/bpf_arm64_bpfel.o
Binary file not shown.
43 changes: 43 additions & 0 deletions bpf/bpf_legacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,55 @@ import (
"fmt"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/features"
"github.com/mozillazg/ptcpdump/internal/log"
)

// $TARGET is set by the Makefile
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -no-strip -no-global-types -target $TARGET bpf_legacy ./ptcpdump.c -- -I./headers -I./headers/$TARGET -I. -Wall -DLEGACY_KERNEL

type BpfObjectsForLegacyKernel struct {
KprobeTcpSendmsg *ebpf.Program `ebpf:"kprobe__tcp_sendmsg"`
KprobeUdpSendmsg *ebpf.Program `ebpf:"kprobe__udp_sendmsg"`
KprobeUdpSendSkb *ebpf.Program `ebpf:"kprobe__udp_send_skb"`
KprobeNfNatManipPkt *ebpf.Program `ebpf:"kprobe__nf_nat_manip_pkt"`
KprobeNfNatPacket *ebpf.Program `ebpf:"kprobe__nf_nat_packet"`
KprobeSecuritySkClassifyFlow *ebpf.Program `ebpf:"kprobe__security_sk_classify_flow"`
RawTracepointSchedProcessExec *ebpf.Program `ebpf:"raw_tracepoint__sched_process_exec"`
RawTracepointSchedProcessExit *ebpf.Program `ebpf:"raw_tracepoint__sched_process_exit"`
RawTracepointSchedProcessFork *ebpf.Program `ebpf:"raw_tracepoint__sched_process_fork"`
TcEgress *ebpf.Program `ebpf:"tc_egress"`
TcIngress *ebpf.Program `ebpf:"tc_ingress"`

BpfMaps
}

func (b *BpfObjects) FromLegacy(o *BpfObjectsForLegacyKernel) {
b.KprobeTcpSendmsg = o.KprobeTcpSendmsg
b.KprobeUdpSendmsg = o.KprobeUdpSendmsg
b.KprobeUdpSendSkb = o.KprobeUdpSendSkb
b.KprobeNfNatManipPkt = o.KprobeNfNatManipPkt
b.KprobeNfNatPacket = o.KprobeNfNatPacket
b.KprobeSecuritySkClassifyFlow = o.KprobeSecuritySkClassifyFlow
b.RawTracepointSchedProcessExec = o.RawTracepointSchedProcessExec
b.RawTracepointSchedProcessExit = o.RawTracepointSchedProcessExit
b.RawTracepointSchedProcessFork = o.RawTracepointSchedProcessFork
b.TcEgress = o.TcEgress
b.TcIngress = o.TcIngress

b.BpfMaps = o.BpfMaps
}

func supportGetSocketCookieWithCgroup() bool {
err := features.HaveProgramHelper(ebpf.CGroupSock, asm.FnGetSocketCookie)
if err != nil {
log.Debugf("%+v", err)
return false
}
return true
}

func kernelVersion(a, b, c int) uint32 {
if c > 255 {
c = 255
Expand Down
Binary file modified bpf/bpf_legacy_arm64_bpfel.o
Binary file not shown.
Binary file modified bpf/bpf_legacy_x86_bpfel.o
Binary file not shown.
Binary file modified bpf/bpf_x86_bpfel.o
Binary file not shown.
14 changes: 7 additions & 7 deletions bpf/headers/custom.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "vmlinux.h"

struct nf_conntrack_tuple__custom {
struct nf_conntrack_tuple___custom {
struct nf_conntrack_man src;
struct {
union nf_inet_addr u3;
Expand Down Expand Up @@ -34,20 +34,20 @@ struct nf_conntrack_tuple__custom {
} dst;
} __attribute__((preserve_access_index));

struct nf_conntrack_tuple_hash__custom {
struct nf_conntrack_tuple_hash___custom {
struct hlist_nulls_node hnnode;
struct nf_conntrack_tuple__custom tuple;
struct nf_conntrack_tuple___custom tuple;
} __attribute__((preserve_access_index));

// https://elixir.bootlin.com/linux/v5.2.21/source/include/net/netfilter/nf_conntrack.h
struct nf_conn__older_52 {
struct nf_conn___older_52 {
struct nf_conntrack ct_general;
spinlock_t lock;
u16 __cpu;
u16 ___cpu;
struct nf_conntrack_zone zone;
struct nf_conntrack_tuple_hash__custom tuplehash[IP_CT_DIR_MAX];
struct nf_conntrack_tuple_hash___custom tuplehash[IP_CT_DIR_MAX];
} __attribute__((preserve_access_index));



#endif /* __CUSTOM_H__ */
#endif /* __CUSTOM_H__ */
Loading

0 comments on commit 9a639ef

Please sign in to comment.