Skip to content

Commit 1f0e5c4

Browse files
authored
Merge pull request #235 from bobrik/ivan/kfree-skb-port
Add proto and port breakdown to kfree_skb
2 parents 51aa663 + 9617e1d commit 1f0e5c4

File tree

2 files changed

+105
-5
lines changed

2 files changed

+105
-5
lines changed

examples/kfree_skb.bpf.c

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,98 @@
11
#include <vmlinux.h>
22
#include <bpf/bpf_tracing.h>
3+
#include <bpf/bpf_endian.h>
34
#include "maps.bpf.h"
45

6+
#define ETH_P_IPV6 0x86DD
7+
#define ETH_P_IP 0x0800
8+
9+
struct kfree_skb_key_t {
10+
u16 eth_proto;
11+
u16 ip_proto;
12+
u16 port;
13+
u16 reason;
14+
};
15+
516
struct {
617
__uint(type, BPF_MAP_TYPE_HASH);
7-
__uint(max_entries, 1024);
8-
__type(key, u16);
18+
__uint(max_entries, 10240);
19+
__type(key, struct kfree_skb_key_t);
920
__type(value, u64);
1021
} kfree_skb_total SEC(".maps");
1122

12-
SEC("tp_btf/kfree_skb")
13-
int BPF_PROG(kfree_skb, struct sk_buff *skb, void *location, enum skb_drop_reason reason)
23+
SEC("tp_btf/kfree_skb") int BPF_PROG(kfree_skb, struct sk_buff *skb, void *location, enum skb_drop_reason reason)
1424
{
15-
u16 key = reason;
25+
struct kfree_skb_key_t key;
26+
struct ethhdr eth_hdr;
27+
struct iphdr ip_hdr;
28+
struct ipv6hdr ipv6_hdr;
29+
struct tcphdr tcp_hdr;
30+
struct udphdr udp_hdr;
31+
u16 ip_proto = 0;
32+
33+
// Same as skb_mac_header_was_set:
34+
// * https://elixir.bootlin.com/linux/v6.5-rc1/source/include/linux/skbuff.h#L2899
35+
if (skb->mac_header == (typeof(skb->mac_header)) ~0U) {
36+
return 0;
37+
}
38+
39+
if (bpf_probe_read_kernel(&eth_hdr, sizeof(eth_hdr), skb->head + skb->mac_header)) {
40+
return 0;
41+
}
42+
43+
key.eth_proto = bpf_ntohs(eth_hdr.h_proto);
44+
45+
if (!key.eth_proto && !bpf_ntohs(skb->protocol)) {
46+
return 0;
47+
}
48+
49+
switch (key.eth_proto) {
50+
case ETH_P_IP:
51+
if (bpf_probe_read_kernel(&ip_hdr, sizeof(ip_hdr), skb->head + skb->network_header) < 0) {
52+
return 0;
53+
}
54+
ip_proto = ip_hdr.protocol;
55+
break;
56+
case ETH_P_IPV6:
57+
if (bpf_probe_read_kernel(&ipv6_hdr, sizeof(ipv6_hdr), skb->head + skb->network_header) < 0) {
58+
return 0;
59+
}
60+
ip_proto = ipv6_hdr.nexthdr;
61+
break;
62+
}
63+
64+
key.ip_proto = ip_proto;
65+
66+
// Same as skb_transport_header_was_set:
67+
// * https://elixir.bootlin.com/linux/v6.5-rc1/source/include/linux/skbuff.h#L2860
68+
if (skb->transport_header == (typeof(skb->transport_header)) ~0U) {
69+
return 0;
70+
}
71+
72+
// Using key.ip_proto directly is not allowed for some reason:
73+
//
74+
// ; switch (key.ip_proto) {
75+
// 48: (54) w1 &= 65535
76+
// R1 32-bit pointer arithmetic prohibited
77+
switch (ip_proto) {
78+
case IPPROTO_TCP:
79+
if (bpf_probe_read_kernel(&tcp_hdr, sizeof(tcp_hdr), skb->head + skb->transport_header) < 0) {
80+
return 0;
81+
}
82+
key.port = bpf_ntohs(tcp_hdr.dest);
83+
break;
84+
case IPPROTO_UDP:
85+
if (bpf_probe_read_kernel(&udp_hdr, sizeof(udp_hdr), skb->head + skb->transport_header) < 0) {
86+
return 0;
87+
}
88+
key.port = bpf_ntohs(udp_hdr.dest);
89+
break;
90+
}
91+
92+
key.reason = reason;
93+
1694
increment_map(&kfree_skb_total, &key, 1);
95+
1796
return 0;
1897
}
1998

examples/kfree_skb.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,27 @@ metrics:
33
- name: kfree_skb_total
44
help: Number of calls into skb:kfree_skb with a per-reason breakdown
55
labels:
6+
- name: eth_proto
7+
size: 2
8+
decoders:
9+
- name: uint
10+
- name: static_map
11+
static_map:
12+
2048: ipv4
13+
34525: ipv6
14+
- name: ip_proto
15+
size: 2
16+
decoders:
17+
- name: uint
18+
- name: static_map
19+
static_map:
20+
1: icmp
21+
6: tcp
22+
17: udp
23+
- name: port
24+
size: 2
25+
decoders:
26+
- name: uint
627
- name: reason
728
size: 2
829
decoders:

0 commit comments

Comments
 (0)