Skip to content

Commit

Permalink
libbpf-tools: Allow tcpconnlat to run on old kernels
Browse files Browse the repository at this point in the history
tcpconnlat uses fentry in BPF programs which may failed on old kernels
which don't have BPF trampline. Let's check fentry support first and
fallback to kprobe if it is not available.

Signed-off-by: Hengqi Chen <[email protected]>
  • Loading branch information
chenhengqi authored and yonghong-song committed Jul 3, 2022
1 parent 118bf16 commit df8d58a
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 21 deletions.
65 changes: 44 additions & 21 deletions libbpf-tools/tcpconnlat.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct {
__uint(value_size, sizeof(u32));
} events SEC(".maps");

static __always_inline int trace_connect(struct sock *sk)
static int trace_connect(struct sock *sk)
{
u32 tgid = bpf_get_current_pid_tgid() >> 32;
struct piddata piddata = {};
Expand All @@ -46,27 +46,14 @@ static __always_inline int trace_connect(struct sock *sk)
return 0;
}

SEC("fentry/tcp_v4_connect")
int BPF_PROG(tcp_v4_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("kprobe/tcp_v6_connect")
int BPF_KPROBE(tcp_v6_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("fentry/tcp_rcv_state_process")
int BPF_PROG(tcp_rcv_state_process, struct sock *sk)
static int handle_tcp_rcv_state_process(void *ctx, struct sock *sk)
{
struct piddata *piddatap;
struct event event = {};
s64 delta;
u64 ts;

if (sk->__sk_common.skc_state != TCP_SYN_SENT)
if (BPF_CORE_READ(sk, __sk_common.skc_state) != TCP_SYN_SENT)
return 0;

piddatap = bpf_map_lookup_elem(&start, &sk);
Expand All @@ -85,12 +72,12 @@ int BPF_PROG(tcp_rcv_state_process, struct sock *sk)
sizeof(event.comm));
event.ts_us = ts / 1000;
event.tgid = piddatap->tgid;
event.lport = sk->__sk_common.skc_num;
event.dport = sk->__sk_common.skc_dport;
event.af = sk->__sk_common.skc_family;
event.lport = BPF_CORE_READ(sk, __sk_common.skc_num);
event.dport = BPF_CORE_READ(sk, __sk_common.skc_dport);
event.af = BPF_CORE_READ(sk, __sk_common.skc_family);
if (event.af == AF_INET) {
event.saddr_v4 = sk->__sk_common.skc_rcv_saddr;
event.daddr_v4 = sk->__sk_common.skc_daddr;
event.saddr_v4 = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr);
event.daddr_v4 = BPF_CORE_READ(sk, __sk_common.skc_daddr);
} else {
BPF_CORE_READ_INTO(&event.saddr_v6, sk,
__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
Expand All @@ -105,4 +92,40 @@ int BPF_PROG(tcp_rcv_state_process, struct sock *sk)
return 0;
}

SEC("kprobe/tcp_v4_connect")
int BPF_KPROBE(tcp_v4_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("kprobe/tcp_v6_connect")
int BPF_KPROBE(tcp_v6_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("kprobe/tcp_rcv_state_process")
int BPF_KPROBE(tcp_rcv_state_process, struct sock *sk)
{
return handle_tcp_rcv_state_process(ctx, sk);
}

SEC("fentry/tcp_v4_connect")
int BPF_PROG(fentry_tcp_v4_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("fentry/tcp_v6_connect")
int BPF_PROG(fentry_tcp_v6_connect, struct sock *sk)
{
return trace_connect(sk);
}

SEC("fentry/tcp_rcv_state_process")
int BPF_PROG(fentry_tcp_rcv_state_process, struct sock *sk)
{
return handle_tcp_rcv_state_process(ctx, sk);
}

char LICENSE[] SEC("license") = "GPL";
13 changes: 13 additions & 0 deletions libbpf-tools/tcpconnlat.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@ int main(int argc, char **argv)
obj->rodata->targ_min_us = env.min_us;
obj->rodata->targ_tgid = env.pid;

if (fentry_can_attach("tcp_v4_connect", NULL)) {
bpf_program__set_attach_target(obj->progs.fentry_tcp_v4_connect, 0, "tcp_v4_connect");
bpf_program__set_attach_target(obj->progs.fentry_tcp_v6_connect, 0, "tcp_v6_connect");
bpf_program__set_attach_target(obj->progs.fentry_tcp_rcv_state_process, 0, "tcp_rcv_state_process");
bpf_program__set_autoload(obj->progs.tcp_v4_connect, false);
bpf_program__set_autoload(obj->progs.tcp_v6_connect, false);
bpf_program__set_autoload(obj->progs.tcp_rcv_state_process, false);
} else {
bpf_program__set_autoload(obj->progs.fentry_tcp_v4_connect, false);
bpf_program__set_autoload(obj->progs.fentry_tcp_v6_connect, false);
bpf_program__set_autoload(obj->progs.fentry_tcp_rcv_state_process, false);
}

err = tcpconnlat_bpf__load(obj);
if (err) {
fprintf(stderr, "failed to load BPF object: %d\n", err);
Expand Down

0 comments on commit df8d58a

Please sign in to comment.