Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions libbpf-tools/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
/tcpconnect
/tcpconnlat
/tcplife
/tcpdrop
/tcppktlat
/tcptracer
/tcprtt
Expand Down
1 change: 1 addition & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ APPS = \
tcptracer \
tcpconnect \
tcpconnlat \
tcpdrop \
tcplife \
tcppktlat \
tcprtt \
Expand Down
177 changes: 177 additions & 0 deletions libbpf-tools/tcpdrop.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#include "tcpdrop.h"
#include "vmlinux.h"
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#ifndef AF_INET
#define AF_INET 2
#endif
#ifndef AF_INET6
#define AF_INET6 10
#endif
#ifndef ETH_P_IP
#define ETH_P_IP 0x0800
#endif
#ifndef ETH_P_IPV6
#define ETH_P_IPV6 0x86dd
#endif

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 512);
} events SEC(".maps");

#define MAX_STACK_DEPTH 15
struct {
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__uint(max_entries, 512);
__uint(key_size, sizeof(u32));
__uint(value_size, MAX_STACK_DEPTH * sizeof(u64));
} stack_traces SEC(".maps");

char ipv4_only = 0;
char ipv6_only = 0;
__u32 netns_id = 0;

SEC("tracepoint/skb/kfree_skb")
int tp__skb_free_skb(struct trace_event_raw_kfree_skb *args)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use raw tracepoint instead ?

{
struct event *event = bpf_ringbuf_reserve(&events, sizeof(*event), 0);
if (!event) {
return 0;
}

// Check if reason field is available
if (bpf_core_field_exists(args->reason)) {
if (args->reason <= SKB_DROP_REASON_NOT_SPECIFIED) {
bpf_ringbuf_discard(event, 0);
return 0;
}
event->drop_reason = args->reason;
} else {
event->drop_reason = -1;
}

if (bpf_ringbuf_query(&events, BPF_RB_AVAIL_DATA) >= 511) {
bpf_ringbuf_discard(event, 0);
return 0;
}

u64 pid_tgid = bpf_get_current_pid_tgid();
u32 pid = pid_tgid >> 32;

struct sk_buff *skb = args->skbaddr;
if (!skb) {
bpf_ringbuf_discard(event, 0);
return 0;
}
struct sock *sk = NULL;
bpf_core_read(&sk, sizeof(sk), &skb->sk);

// Get packet headers
void *head;
u16 network_header, transport_header;
if (bpf_core_read(&head, sizeof(head), &skb->head) ||
bpf_core_read(&network_header, sizeof(network_header),
&skb->network_header) ||
bpf_core_read(&transport_header, sizeof(transport_header),
&skb->transport_header)) {
bpf_ringbuf_discard(event, 0);
return 0;
}

// Check protocol and filter by IP family
u16 protocol = args->protocol;
if (protocol != ETH_P_IP && protocol != ETH_P_IPV6) {
bpf_ringbuf_discard(event, 0);
return 0;
}
if (ipv4_only && protocol != ETH_P_IP) {
bpf_ringbuf_discard(event, 0);
return 0;
}
if (ipv6_only && protocol != ETH_P_IPV6) {
bpf_ringbuf_discard(event, 0);
return 0;
}

// Filter by network namespace
if (netns_id && sk) {
struct net *net = NULL;
bpf_core_read(&net, sizeof(net), &sk->__sk_common.skc_net.net);
if (net) {
u32 inum;
bpf_core_read(&inum, sizeof(inum), &net->ns.inum);
if (inum != netns_id) {
bpf_ringbuf_discard(event, 0);
return 0;
}
}
}

event->timestamp = bpf_ktime_get_ns();
event->pid = pid;
bpf_get_current_comm(&event->comm, sizeof(event->comm));
event->stack_id = bpf_get_stackid(args, &stack_traces, 0);
event->state = 127;
if (sk) {
u8 state;
if (!bpf_core_read(&state, sizeof(state),
&sk->__sk_common.skc_state)) {
event->state = state;
}
}

if (protocol == ETH_P_IP) {
struct iphdr ip;
if (bpf_core_read(&ip, sizeof(ip), head + network_header)) {
bpf_ringbuf_discard(event, 0);
return 0;
}
if (ip.protocol != IPPROTO_TCP) {
bpf_ringbuf_discard(event, 0);
return 0;
}
struct tcphdr tcp;
if (bpf_core_read(&tcp, sizeof(tcp), head + transport_header)) {
bpf_ringbuf_discard(event, 0);
return 0;
}
event->ip_version = 4;
event->saddr_v4 = ip.saddr;
event->daddr_v4 = ip.daddr;
event->sport = bpf_ntohs(tcp.source);
event->dport = bpf_ntohs(tcp.dest);
event->tcpflags = ((u8 *)&tcp)[13];
} else {
struct ipv6hdr ip6;
if (bpf_core_read(&ip6, sizeof(ip6), head + network_header)) {
bpf_ringbuf_discard(event, 0);
return 0;
}
if (ip6.nexthdr != IPPROTO_TCP) {
bpf_ringbuf_discard(event, 0);
return 0;
}
struct tcphdr tcp;
if (bpf_core_read(&tcp, sizeof(tcp), head + transport_header)) {
bpf_ringbuf_discard(event, 0);
return 0;
}
event->ip_version = 6;
bpf_core_read(&event->saddr_v6, sizeof(event->saddr_v6),
&ip6.saddr.in6_u.u6_addr32);
bpf_core_read(&event->daddr_v6, sizeof(event->daddr_v6),
&ip6.daddr.in6_u.u6_addr32);
event->sport = bpf_ntohs(tcp.source);
event->dport = bpf_ntohs(tcp.dest);
event->tcpflags = ((u8 *)&tcp)[13];
}

bpf_ringbuf_submit(event, 0);
return 0;
}

char _license[] SEC("license") = "Dual BSD/GPL";
Loading
Loading