0001
0002
0003
0004
0005 #include <linux/bpf.h>
0006
0007 #include <bpf/bpf_helpers.h>
0008 #include <bpf/bpf_endian.h>
0009
0010 #define INTERVAL 1000000000ULL
0011
0012 int _version SEC("version") = 1;
0013 char _license[] SEC("license") = "GPL";
0014
0015 struct {
0016 __u32 type;
0017 __u32 map_flags;
0018 int *key;
0019 __u64 *value;
0020 } bpf_next_dump SEC(".maps") = {
0021 .type = BPF_MAP_TYPE_SK_STORAGE,
0022 .map_flags = BPF_F_NO_PREALLOC,
0023 };
0024
0025 SEC("sockops")
0026 int _sockops(struct bpf_sock_ops *ctx)
0027 {
0028 struct bpf_tcp_sock *tcp_sk;
0029 struct bpf_sock *sk;
0030 __u64 *next_dump;
0031 __u64 now;
0032
0033 switch (ctx->op) {
0034 case BPF_SOCK_OPS_TCP_CONNECT_CB:
0035 bpf_sock_ops_cb_flags_set(ctx, BPF_SOCK_OPS_RTT_CB_FLAG);
0036 return 1;
0037 case BPF_SOCK_OPS_RTT_CB:
0038 break;
0039 default:
0040 return 1;
0041 }
0042
0043 sk = ctx->sk;
0044 if (!sk)
0045 return 1;
0046
0047 next_dump = bpf_sk_storage_get(&bpf_next_dump, sk, 0,
0048 BPF_SK_STORAGE_GET_F_CREATE);
0049 if (!next_dump)
0050 return 1;
0051
0052 now = bpf_ktime_get_ns();
0053 if (now < *next_dump)
0054 return 1;
0055
0056 tcp_sk = bpf_tcp_sock(sk);
0057 if (!tcp_sk)
0058 return 1;
0059
0060 *next_dump = now + INTERVAL;
0061
0062 bpf_printk("dsack_dups=%u delivered=%u\n",
0063 tcp_sk->dsack_dups, tcp_sk->delivered);
0064 bpf_printk("delivered_ce=%u icsk_retransmits=%u\n",
0065 tcp_sk->delivered_ce, tcp_sk->icsk_retransmits);
0066
0067 return 1;
0068 }