// Copyright 2016 Netflix, Inc. // Licensed under the Apache License, Version 2.0 (the "License") #include #include #include #define RETRANSMIT 1 #define TLP 2 // separate data structs for ipv4 and ipv6 struct ipv4_data_t { // XXX: switch some to u32's when supported u64 pid; u64 ip; u64 saddr; u64 daddr; u64 lport; u64 dport; u64 state; u64 type; }; BPF_PERF_OUTPUT(ipv4_events); struct ipv6_data_t { u64 pid; u64 ip; unsigned __int128 saddr; unsigned __int128 daddr; u64 lport; u64 dport; u64 state; u64 type; }; BPF_PERF_OUTPUT(ipv6_events); // separate flow keys per address family struct ipv4_flow_key_t { u32 saddr; u32 daddr; u16 lport; u16 dport; }; BPF_HASH(ipv4_count, struct ipv4_flow_key_t); struct ipv6_flow_key_t { unsigned __int128 saddr; unsigned __int128 daddr; u16 lport; u16 dport; }; BPF_HASH(ipv6_count, struct ipv6_flow_key_t); static int trace_event(struct pt_regs *ctx, struct sock *skp, int type) { if (skp == NULL) return 0; u32 pid = bpf_get_current_pid_tgid() >> 32; // pull in details u16 family = skp->__sk_common.skc_family; u16 lport = skp->__sk_common.skc_num; u16 dport = skp->__sk_common.skc_dport; char state = skp->__sk_common.skc_state; if (family == AF_INET) { struct ipv4_flow_key_t flow_key = {}; flow_key.saddr = skp->__sk_common.skc_rcv_saddr; flow_key.daddr = skp->__sk_common.skc_daddr; // lport is host order flow_key.lport = lport; flow_key.dport = ntohs(dport); u64 zero = 0, *val; val = ipv4_count.lookup_or_init(&flow_key, &zero); if (val) { (*val)++; } } else if (family == AF_INET6) { struct ipv6_flow_key_t flow_key = {}; bpf_probe_read(&flow_key.saddr, sizeof(flow_key.saddr), skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); bpf_probe_read(&flow_key.daddr, sizeof(flow_key.daddr), skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32); // lport is host order flow_key.lport = lport; flow_key.dport = ntohs(dport); u64 zero = 0, *val; val = ipv6_count.lookup_or_init(&flow_key, &zero); if (val) { (*val)++; } } // else drop return 0; } int trace_retransmit(struct pt_regs *ctx, struct sock *sk) { trace_event(ctx, sk, RETRANSMIT); return 0; } int trace_tlp(struct pt_regs *ctx, struct sock *sk) { trace_event(ctx, sk, TLP); return 0; }