From 88c5296800b12b02597001db64082a52410aad73 Mon Sep 17 00:00:00 2001 From: thiagoftsm Date: Mon, 14 Mar 2022 12:12:28 +0000 Subject: [PATCH] Socket update (#16) --- .gitignore | 2 +- kernel-collector | 2 +- src/socket.bpf.c | 179 ++++++++++++++++++++++++++++++++++++++++++----- src/socket.c | 58 +++++++++++++-- 4 files changed, 217 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 88b6078..3560355 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ *.skel.h *.a -./src/tests/* +src/tests/* ./src/*.o .local_libbpf/bpf .local_libbpf/pkgconfig diff --git a/kernel-collector b/kernel-collector index 6951d62..a2bed9b 160000 --- a/kernel-collector +++ b/kernel-collector @@ -1 +1 @@ -Subproject commit 6951d62ce58c36125f5c6ab1e7fd8ebd43fdb99b +Subproject commit a2bed9b392ffcf73bb0669b5d2290edf3668d178 diff --git a/src/socket.bpf.c b/src/socket.bpf.c index ffea3ef..1a3ef0a 100644 --- a/src/socket.bpf.c +++ b/src/socket.bpf.c @@ -55,9 +55,9 @@ struct { struct { __uint(type, BPF_MAP_TYPE_HASH); - __type(key, __u16); - __type(value, __u8); - __uint(max_entries, 65536); + __type(key, netdata_passive_connection_idx_t); + __type(value, netdata_passive_connection_t); + __uint(max_entries, 1024); } tbl_lports SEC(".maps"); struct { @@ -171,11 +171,60 @@ static __always_inline void ebpf_socket_reset_bandwidth(__u32 pid, __u32 tgid) bpf_map_update_elem(&tbl_bandwidth, &pid, &data, BPF_ANY); } -static __always_inline void update_pid_cleanup() +static __always_inline void update_pid_connection(__u8 version) +{ + netdata_bandwidth_t *stored; + netdata_bandwidth_t data = { }; + + __u32 key = NETDATA_CONTROLLER_APPS_ENABLED; + __u32 *apps = bpf_map_lookup_elem(&socket_ctrl ,&key); + if (apps) { + if (*apps == 0) + return; + } else + return; + + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 tgid = (__u32)( 0x00000000FFFFFFFF & pid_tgid); + key = (__u32)(pid_tgid >> 32); + + stored = (netdata_bandwidth_t *) bpf_map_lookup_elem(&tbl_bandwidth, &key); + if (stored) { + if (stored->pid != tgid) + ebpf_socket_reset_bandwidth(key, tgid); + + stored->ct = bpf_ktime_get_ns(); + + if (version == 4) + libnetdata_update_u32(&stored->ipv4_connect, 1); + else + libnetdata_update_u32(&stored->ipv6_connect, 1); + } else { + data.pid = tgid; + data.first = bpf_ktime_get_ns(); + data.ct = data.first; + if (version == 4) + data.ipv4_connect = 1; + else + data.ipv6_connect = 1; + + bpf_map_update_elem(&tbl_bandwidth, &key, &data, BPF_ANY); + } +} + +static __always_inline void update_pid_cleanup(__u64 drop, __u64 close) { netdata_bandwidth_t *b; netdata_bandwidth_t data = { }; + __u32 key = NETDATA_CONTROLLER_APPS_ENABLED; + __u32 *apps = bpf_map_lookup_elem(&socket_ctrl ,&key); + if (apps) { + if (*apps == 0) + return; + } else + return; + __u64 pid_tgid = bpf_get_current_pid_tgid(); __u32 pid = (__u32)(pid_tgid >> 32); __u32 tgid = (__u32)( 0x00000000FFFFFFFF & pid_tgid); @@ -185,12 +234,18 @@ static __always_inline void update_pid_cleanup() if (b->pid != tgid) ebpf_socket_reset_bandwidth(pid, tgid); - libnetdata_update_u64(&b->close, 1); + if (drop) + libnetdata_update_u64(&b->drop, 1); + else + libnetdata_update_u64(&b->close, 1); } else { data.pid = tgid; data.first = bpf_ktime_get_ns(); data.ct = data.first; - data.close = 1; + if (drop) + data.drop = 1; + else + data.close = 1; bpf_map_update_elem(&tbl_bandwidth, &pid, &data, BPF_ANY); } @@ -305,12 +360,31 @@ static inline int netdata_common_inet_csk_accept(struct sock *sk) if (!sk) return 0; - __u16 dport = BPF_CORE_READ(sk, __sk_common.skc_num); + netdata_passive_connection_t data = { }; + netdata_passive_connection_idx_t idx = { }; + + __u16 protocol = BPF_CORE_READ(sk, sk_protocol); + if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) + return 0; + + idx.port = BPF_CORE_READ(sk, __sk_common.skc_num); + idx.protocol = protocol; + + __u64 pid_tgid = bpf_get_current_pid_tgid(); + __u32 pid = (__u32)(pid_tgid >> 32); + __u32 tgid = (__u32)( 0x00000000FFFFFFFF & pid_tgid); - __u8 *value = (__u8 *)bpf_map_lookup_elem(&tbl_lports, &dport); - if (!value) { - __u8 value = 1; - bpf_map_update_elem(&tbl_lports, &dport, &value, BPF_ANY); + netdata_passive_connection_t *value = (netdata_passive_connection_t *)bpf_map_lookup_elem(&tbl_lports, &idx); + if (value) { + // Update PID, because process can die. + value->tgid = tgid; + value->pid = pid; + libnetdata_update_u64(&value->counter, 1); + } else { + data.tgid = tgid; + data.pid = pid; + data.counter = 1; + bpf_map_update_elem(&tbl_lports, &idx, &data, BPF_ANY); } return 0; @@ -352,14 +426,10 @@ static inline int netdata_common_tcp_close(struct inet_sock *is) netdata_socket_t *val; __u16 family; netdata_socket_idx_t idx = { }; - __u32 key = NETDATA_CONTROLLER_APPS_ENABLED; libnetdata_update_global(&tbl_global_sock, NETDATA_KEY_CALLS_TCP_CLOSE, 1); - __u32 *apps = bpf_map_lookup_elem(&socket_ctrl ,&key); - if (apps) - if (*apps == 1) - update_pid_cleanup(); + update_pid_cleanup(0, 1); family = set_idx_value(&idx, is); if (!family) @@ -374,6 +444,22 @@ static inline int netdata_common_tcp_close(struct inet_sock *is) return 0; } +static inline int netdata_common_tcp_drop(struct sk_buff *skb) +{ + __u16 protocol; + struct sock *sk = BPF_CORE_READ(skb, sk); + BPF_CORE_READ_INTO(&protocol, sk, sk_protocol); + + if (protocol != IPPROTO_TCP) + return 0; + + libnetdata_update_global(&tbl_global_sock, NETDATA_KEY_TCP_DROP, 1); + + update_pid_cleanup(1, 0); + + return 0; +} + static inline int netdata_common_udp_recvmsg(struct sock *sk) { __u64 pid_tgid = bpf_get_current_pid_tgid(); @@ -384,6 +470,21 @@ static inline int netdata_common_udp_recvmsg(struct sock *sk) return 0; } +static inline int netdata_common_tcp_connect(int ret, enum socket_counters success, + enum socket_counters err, __u8 version) +{ + libnetdata_update_global(&tbl_global_sock, success, 1); + + if (ret < 0) { + libnetdata_update_global(&tbl_global_sock, err, 1); + return 0; + } + + update_pid_connection(version); + + return 0; +} + /*********************************************************************************** * * SOCKET SECTION(kprobe) @@ -398,6 +499,24 @@ int BPF_KRETPROBE(netdata_inet_csk_accept_kretprobe) return netdata_common_inet_csk_accept(sk); } +SEC("kretprobe/tcp_v4_connect") +int BPF_KRETPROBE(netdata_tcp_v4_connect_kretprobe) +{ + int ret = (int)PT_REGS_RC(ctx); + + return netdata_common_tcp_connect(ret, NETDATA_KEY_CALLS_TCP_CONNECT_IPV4, + NETDATA_KEY_ERROR_TCP_CONNECT_IPV4, 4); +} + +SEC("kretprobe/tcp_v6_connect") +int BPF_KRETPROBE(netdata_tcp_v6_connect_kretprobe) +{ + int ret = (int)PT_REGS_RC(ctx); + + return netdata_common_tcp_connect(ret, NETDATA_KEY_CALLS_TCP_CONNECT_IPV6, + NETDATA_KEY_ERROR_TCP_CONNECT_IPV4, 6); +} + SEC("kprobe/tcp_retransmit_skb") int BPF_KPROBE(netdata_tcp_retransmit_skb_kprobe) { @@ -425,6 +544,14 @@ int BPF_KPROBE(netdata_tcp_close_kprobe) return netdata_common_tcp_close(is); } +SEC("kprobe/__kfree_skb") +int BPF_KPROBE(netdata_tcp_drop_kprobe) +{ + struct sk_buff *skb = (struct sk_buff *)PT_REGS_PARM1(ctx); + + return netdata_common_tcp_drop(skb); +} + // https://elixir.bootlin.com/linux/v5.6.14/source/net/ipv4/udp.c#L1726 SEC("kprobe/udp_recvmsg") int BPF_KPROBE(netdata_udp_recvmsg_kprobe) @@ -511,6 +638,20 @@ int BPF_PROG(netdata_inet_csk_accept_fentry, struct sock *sk) return netdata_common_inet_csk_accept(sk); } +SEC("fexit/tcp_v4_connect") +int BPF_PROG(netdata_tcp_v4_connect_fexit, struct sock *sk, struct sockaddr *uaddr, int addr_len, int ret) +{ + return netdata_common_tcp_connect(ret, NETDATA_KEY_CALLS_TCP_CONNECT_IPV4, + NETDATA_KEY_ERROR_TCP_CONNECT_IPV4, 4); +} + +SEC("fexit/tcp_v6_connect") +int BPF_PROG(netdata_tcp_v6_connect_fexit, struct sock *sk, struct sockaddr *uaddr, int addr_len, int ret) +{ + return netdata_common_tcp_connect(ret, NETDATA_KEY_CALLS_TCP_CONNECT_IPV6, + NETDATA_KEY_ERROR_TCP_CONNECT_IPV6, 6); +} + SEC("fentry/tcp_retransmit_skb") int BPF_PROG(netdata_tcp_retransmit_skb_fentry, struct sock *sk) { @@ -537,6 +678,12 @@ int BPF_PROG(netdata_tcp_close_fentry, struct sock *sk) return netdata_common_tcp_close(is); } +SEC("fentry/__kfree_skb") +int BPF_PROG(netdata_tcp_drop_fentry, struct sk_buff *skb) +{ + return netdata_common_tcp_drop(skb); +} + // https://elixir.bootlin.com/linux/v5.6.14/source/net/ipv4/udp.c#L1726 SEC("fentry/udp_recvmsg") int BPF_PROG(netdata_udp_recvmsg_fentry, struct sock *sk) diff --git a/src/socket.c b/src/socket.c index bb6ba3b..c57bfcf 100644 --- a/src/socket.c +++ b/src/socket.c @@ -22,7 +22,10 @@ char *function_list[] = { "inet_csk_accept", "tcp_close", "udp_recvmsg", "tcp_sendmsg", - "udp_sendmsg" }; + "udp_sendmsg", + "__kfree_skb", + "tcp_v4_connect", + "tcp_v6_connect"}; #define NETDATA_IPV4 4 #define NETDATA_IPV6 6 @@ -35,6 +38,18 @@ static int ebpf_attach_probes(struct socket_bpf *obj) if (ret) return -1; + obj->links.netdata_tcp_v4_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v4_connect_kretprobe, + true, function_list[NETDATA_FCNT_TCP_V4_CONNECT]); + ret = libbpf_get_error(obj->links.netdata_tcp_v4_connect_kretprobe); + if (ret) + return -1; + + obj->links.netdata_tcp_v6_connect_kretprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_v6_connect_kretprobe, + true, function_list[NETDATA_FCNT_TCP_V6_CONNECT]); + ret = libbpf_get_error(obj->links.netdata_tcp_v6_connect_kretprobe); + if (ret) + return -1; + obj->links.netdata_tcp_retransmit_skb_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_retransmit_skb_kprobe, false, function_list[NETDATA_FCNT_TCP_RETRANSMIT]); ret = libbpf_get_error(obj->links.netdata_tcp_retransmit_skb_kprobe); @@ -53,6 +68,12 @@ static int ebpf_attach_probes(struct socket_bpf *obj) if (ret) return -1; + obj->links.netdata_tcp_drop_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_tcp_drop_kprobe, + false, function_list[NETDATA_FCNT_TCP_DROP]); + ret = libbpf_get_error(obj->links.netdata_tcp_drop_kprobe); + if (ret) + return -1; + obj->links.netdata_udp_recvmsg_kprobe = bpf_program__attach_kprobe(obj->progs.netdata_udp_recvmsg_kprobe, false, function_list[NETDATA_FCNT_UDP_RECEVMSG]); ret = libbpf_get_error(obj->links.netdata_udp_recvmsg_kprobe); @@ -95,14 +116,30 @@ static int ebpf_attach_probes(struct socket_bpf *obj) static void ebpf_disable_probes(struct socket_bpf *obj) { bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_close_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_drop_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_kprobe, false); + bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kretprobe, false); + bpf_program__set_autoload(obj->progs.netdata_udp_sendmsg_kprobe, false); } static void ebpf_disable_trampoline(struct socket_bpf *obj) { bpf_program__set_autoload(obj->progs.netdata_inet_csk_accept_fentry, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_v4_connect_fexit, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_v6_connect_fexit, false); bpf_program__set_autoload(obj->progs.netdata_tcp_retransmit_skb_fentry, false); bpf_program__set_autoload(obj->progs.netdata_tcp_cleanup_rbuf_fentry, false); bpf_program__set_autoload(obj->progs.netdata_tcp_close_fentry, false); + bpf_program__set_autoload(obj->progs.netdata_tcp_drop_fentry, false); bpf_program__set_autoload(obj->progs.netdata_udp_recvmsg_fentry, false); bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fentry, false); bpf_program__set_autoload(obj->progs.netdata_tcp_sendmsg_fexit, false); @@ -115,6 +152,12 @@ static void ebpf_set_trampoline_target(struct socket_bpf *obj) bpf_program__set_attach_target(obj->progs.netdata_inet_csk_accept_fentry, 0, function_list[NETDATA_FCNT_INET_CSK_ACCEPT]); + bpf_program__set_attach_target(obj->progs.netdata_tcp_v4_connect_fexit, 0, + function_list[NETDATA_FCNT_TCP_V4_CONNECT]); + + bpf_program__set_attach_target(obj->progs.netdata_tcp_v6_connect_fexit, 0, + function_list[NETDATA_FCNT_TCP_V6_CONNECT]); + bpf_program__set_attach_target(obj->progs.netdata_tcp_retransmit_skb_fentry, 0, function_list[NETDATA_FCNT_TCP_RETRANSMIT]); @@ -124,6 +167,9 @@ static void ebpf_set_trampoline_target(struct socket_bpf *obj) bpf_program__set_attach_target(obj->progs.netdata_tcp_close_fentry, 0, function_list[NETDATA_FCNT_TCP_CLOSE]); + bpf_program__set_attach_target(obj->progs.netdata_tcp_drop_fentry, 0, + function_list[NETDATA_FCNT_TCP_DROP]); + bpf_program__set_attach_target(obj->progs.netdata_udp_recvmsg_fentry, 0, function_list[NETDATA_FCNT_UDP_RECEVMSG]); @@ -204,8 +250,8 @@ static inline int update_socket_tables(int fd, netdata_socket_idx_t *idx, netdat static inline int update_local_ports(struct socket_bpf *obj) { - uint16_t idx = 1; - uint8_t value = 1; + netdata_passive_connection_idx_t idx = { .protocol = 6, .port = 44444 }; + netdata_passive_connection_t value = { .tgid = 1, .pid = 1, .counter = 1 }; int fd = bpf_map__fd(obj->maps.tbl_lports); int ret = bpf_map_update_elem(fd, &idx, &value, 0); if (ret) @@ -292,11 +338,11 @@ static int netdata_read_socket(netdata_socket_idx_t *idx, struct socket_bpf *obj static int netdata_read_local_ports(struct socket_bpf *obj) { - uint16_t idx = 1; - uint8_t value = 0; + netdata_passive_connection_idx_t idx = { .protocol = 6, .port = 44444 }; + netdata_passive_connection_t value = { .tgid = 0, .pid = 0, .counter = 0 }; int fd = bpf_map__fd(obj->maps.tbl_lports); if (!bpf_map_lookup_elem(fd, &idx, &value)) { - if (value) + if (value.counter) return 0; }