Skip to content

Commit

Permalink
Add kprobe for retransmits (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
vlvkobal authored Jul 20, 2020
1 parent fdeff52 commit 6a598c6
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 80 deletions.
100 changes: 53 additions & 47 deletions kernel/netdata_ebpf.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef _NETDATA_EBPF_PROCESS_
# define _NETDATA_EBPF_PROCESS_ 1
# include <linux/sched.h>
#define _NETDATA_EBPF_PROCESS_ 1

#include <linux/sched.h>

struct netdata_error_report_t {
char comm[TASK_COMM_LEN];
Expand All @@ -10,9 +13,6 @@ struct netdata_error_report_t {
int err;
};


//fork() creates process
//
struct netdata_pid_stat_t {
__u64 pid_tgid; //Unique identifier
__u32 pid; //process id
Expand Down Expand Up @@ -50,63 +50,69 @@ struct netdata_pid_stat_t {
__u8 removeme;
};

//ebpf_process.c
# define NETDATA_GLOBAL_COUNTER 24
// ebpf_process.c
enum process_counters {
NETDATA_KEY_CALLS_DO_SYS_OPEN,
NETDATA_KEY_ERROR_DO_SYS_OPEN,

# define NETDATA_KEY_CALLS_DO_SYS_OPEN 0
# define NETDATA_KEY_ERROR_DO_SYS_OPEN 1
NETDATA_KEY_CALLS_VFS_WRITE,
NETDATA_KEY_ERROR_VFS_WRITE,
NETDATA_KEY_BYTES_VFS_WRITE,

# define NETDATA_KEY_CALLS_VFS_WRITE 2
# define NETDATA_KEY_ERROR_VFS_WRITE 3
# define NETDATA_KEY_BYTES_VFS_WRITE 4
NETDATA_KEY_CALLS_VFS_READ,
NETDATA_KEY_ERROR_VFS_READ,
NETDATA_KEY_BYTES_VFS_READ,

# define NETDATA_KEY_CALLS_VFS_READ 5
# define NETDATA_KEY_ERROR_VFS_READ 6
# define NETDATA_KEY_BYTES_VFS_READ 7
NETDATA_KEY_CALLS_VFS_UNLINK,
NETDATA_KEY_ERROR_VFS_UNLINK,

# define NETDATA_KEY_CALLS_VFS_UNLINK 8
# define NETDATA_KEY_ERROR_VFS_UNLINK 9
NETDATA_KEY_CALLS_DO_EXIT,

# define NETDATA_KEY_CALLS_DO_EXIT 10
NETDATA_KEY_CALLS_RELEASE_TASK,

# define NETDATA_KEY_CALLS_RELEASE_TASK 11
NETDATA_KEY_CALLS_DO_FORK,
NETDATA_KEY_ERROR_DO_FORK,

# define NETDATA_KEY_CALLS_DO_FORK 12
# define NETDATA_KEY_ERROR_DO_FORK 13
NETDATA_KEY_CALLS_CLOSE_FD,
NETDATA_KEY_ERROR_CLOSE_FD,

# define NETDATA_KEY_CALLS_CLOSE_FD 14
# define NETDATA_KEY_ERROR_CLOSE_FD 15
NETDATA_KEY_CALLS_SYS_CLONE,
NETDATA_KEY_ERROR_SYS_CLONE,

# define NETDATA_KEY_CALLS_SYS_CLONE 16
# define NETDATA_KEY_ERROR_SYS_CLONE 17
NETDATA_KEY_CALLS_VFS_WRITEV,
NETDATA_KEY_ERROR_VFS_WRITEV,
NETDATA_KEY_BYTES_VFS_WRITEV,

# define NETDATA_KEY_CALLS_VFS_WRITEV 18
# define NETDATA_KEY_ERROR_VFS_WRITEV 19
# define NETDATA_KEY_BYTES_VFS_WRITEV 20
NETDATA_KEY_CALLS_VFS_READV,
NETDATA_KEY_ERROR_VFS_READV,
NETDATA_KEY_BYTES_VFS_READV,

# define NETDATA_KEY_CALLS_VFS_READV 21
# define NETDATA_KEY_ERROR_VFS_READV 22
# define NETDATA_KEY_BYTES_VFS_READV 23
NETDATA_GLOBAL_COUNTER
};

// network_viewer.c
enum socket_counters {
NETDATA_KEY_CALLS_TCP_SENDMSG,
NETDATA_KEY_ERROR_TCP_SENDMSG,
NETDATA_KEY_BYTES_TCP_SENDMSG,

//network_viewer.c
# define NETDATA_SOCKET_COUNTER 13
NETDATA_KEY_CALLS_TCP_CLEANUP_RBUF,
NETDATA_KEY_ERROR_TCP_CLEANUP_RBUF,
NETDATA_KEY_BYTES_TCP_CLEANUP_RBUF,

# define NETDATA_KEY_CALLS_TCP_SENDMSG 0
# define NETDATA_KEY_ERROR_TCP_SENDMSG 1
# define NETDATA_KEY_BYTES_TCP_SENDMSG 2
NETDATA_KEY_CALLS_TCP_CLOSE,

# define NETDATA_KEY_CALLS_TCP_CLEANUP_RBUF 3
# define NETDATA_KEY_ERROR_TCP_CLEANUP_RBUF 4
# define NETDATA_KEY_BYTES_TCP_CLEANUP_RBUF 5
NETDATA_KEY_CALLS_UDP_RECVMSG,
NETDATA_KEY_ERROR_UDP_RECVMSG,
NETDATA_KEY_BYTES_UDP_RECVMSG,

# define NETDATA_KEY_CALLS_TCP_CLOSE 6
NETDATA_KEY_CALLS_UDP_SENDMSG,
NETDATA_KEY_ERROR_UDP_SENDMSG,
NETDATA_KEY_BYTES_UDP_SENDMSG,

# define NETDATA_KEY_CALLS_UDP_RECVMSG 7
# define NETDATA_KEY_ERROR_UDP_RECVMSG 8
# define NETDATA_KEY_BYTES_UDP_RECVMSG 9
NETDATA_KEY_TCP_RETRANSMIT,

# define NETDATA_KEY_CALLS_UDP_SENDMSG 10
# define NETDATA_KEY_ERROR_UDP_SENDMSG 11
# define NETDATA_KEY_BYTES_UDP_SENDMSG 12
NETDATA_SOCKET_COUNTER
};

#endif
#endif /* _NETDATA_EBPF_PROCESS_ */
97 changes: 64 additions & 33 deletions kernel/network_viewer_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@


/************************************************************************************
*
*
* Hash Table Section
*
*
***********************************************************************************/

/**
Expand All @@ -35,8 +35,10 @@ union netdata_ip {
* Structure to store socket information
*/
typedef struct netdata_socket {
__u64 recv;
__u64 sent;
__u64 recv_packets;
__u64 sent_packets;
__u64 recv_bytes;
__u64 sent_bytes;
__u64 first; //First timestamp
__u64 ct; //Current timestamp
__u16 retransmit; //It is never used with UDP
Expand Down Expand Up @@ -72,11 +74,11 @@ typedef struct netdata_bandwidth {
* Bandwidth hash table
*/
struct bpf_map_def SEC("maps") tbl_bandwidth = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
.type = BPF_MAP_TYPE_HASH,
#else
.type = BPF_MAP_TYPE_PERCPU_HASH,
#endif
#endif
.key_size = sizeof(__u32),
.value_size = sizeof(netdata_bandwidth_t),
.max_entries = 65536
Expand All @@ -87,11 +89,11 @@ struct bpf_map_def SEC("maps") tbl_bandwidth = {
*
*/
struct bpf_map_def SEC("maps") tbl_conn_ipv4 = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
.type = BPF_MAP_TYPE_HASH,
#else
.type = BPF_MAP_TYPE_PERCPU_HASH,
#endif
#endif
.key_size = sizeof(netdata_socket_idx_t),
.value_size = sizeof(netdata_socket_t),
.max_entries = 65536
Expand All @@ -102,27 +104,27 @@ struct bpf_map_def SEC("maps") tbl_conn_ipv4 = {
*
*/
struct bpf_map_def SEC("maps") tbl_conn_ipv6 = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
.type = BPF_MAP_TYPE_HASH,
#else
.type = BPF_MAP_TYPE_PERCPU_HASH,
#endif
#endif
.key_size = sizeof(netdata_socket_idx_t),
.value_size = sizeof(netdata_socket_t),
.max_entries = 65536
};


/**
* UDP hash table, this table is necessry to collect the
* UDP hash table, this table is necessry to collect the
* correct size. More details inside UDP section.
*/
struct bpf_map_def SEC("maps") tbl_nv_udp_conn_stats = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
.type = BPF_MAP_TYPE_HASH,
#else
.type = BPF_MAP_TYPE_PERCPU_HASH,
#endif
#endif
.key_size = sizeof(__u64),
.value_size = sizeof(void *),
.max_entries = 8192
Expand All @@ -143,9 +145,9 @@ struct bpf_map_def SEC("maps") tbl_sock_total_stats = {
};

/************************************************************************************
*
*
* Common Section
*
*
***********************************************************************************/

/**
Expand Down Expand Up @@ -209,31 +211,43 @@ static __u16 set_idx_value(netdata_socket_idx_t *nsi, struct inet_sock *is)
/**
* Update time and bytes sent and received
*/
static void update_socket_stats(netdata_socket_t *ptr, __u64 sent, __u64 received)
static void update_socket_stats(netdata_socket_t *ptr, __u64 sent, __u64 received, __u16 retransmitted)
{
ptr->ct = bpf_ktime_get_ns();

netdata_update_u64(&ptr->sent, sent);
netdata_update_u64(&ptr->recv, received);
if (sent)
netdata_update_u64(&ptr->sent_packets, 1);

if (received)
netdata_update_u64(&ptr->recv_packets, 1);

netdata_update_u64(&ptr->sent_bytes, sent);
netdata_update_u64(&ptr->recv_bytes, received);
netdata_update_u64(&ptr->retransmit, retransmitted);
}

/**
* Update the table for the index idx
*/
static void update_socket_table(struct bpf_map_def *tbl, netdata_socket_idx_t *idx, __u64 sent, __u64 received, __u8 protocol)
static void update_socket_table(struct bpf_map_def *tbl,
netdata_socket_idx_t *idx,
__u64 sent,
__u64 received,
__u16 retransmitted,
__u8 protocol)
{
netdata_socket_t *val;
netdata_socket_t data = { };

val = (netdata_socket_t *) bpf_map_lookup_elem(tbl, idx);
if (val) {
update_socket_stats(val, sent, received);
update_socket_stats(val, sent, received, retransmitted);
if (protocol == IPPROTO_UDP)
val->removeme = 1;
} else {
data.first = bpf_ktime_get_ns();
data.protocol = protocol;
update_socket_stats(&data, sent, received);
update_socket_stats(&data, sent, received, retransmitted);

bpf_map_update_elem(tbl, idx, &data, BPF_ANY);
}
Expand Down Expand Up @@ -265,9 +279,9 @@ static void update_pid_stats(__u32 pid, __u32 tgid, __u64 sent, __u64 received)
}

/************************************************************************************
*
*
* TCP Section
*
*
***********************************************************************************/

/**
Expand All @@ -281,7 +295,7 @@ int netdata_rtcp_sendmsg(struct pt_regs* ctx)

if (ret < 0) {
netdata_update_global(NETDATA_KEY_ERROR_TCP_SENDMSG, 1);
}
}

return 0;
}
Expand All @@ -307,12 +321,29 @@ int netdata_tcp_sendmsg(struct pt_regs* ctx)
tbl = (family == AF_INET6)?&tbl_conn_ipv6:&tbl_conn_ipv4;

netdata_update_global(NETDATA_KEY_BYTES_TCP_SENDMSG, (__u64)sent);
update_socket_table(tbl, &idx,(__u64) sent, 0, IPPROTO_TCP);
update_socket_table(tbl, &idx,(__u64) sent, 0, 0, IPPROTO_TCP);
update_pid_stats(pid, tgid, (__u64)sent, 0);

return 0;
}

SEC("kprobe/tcp_retransmit_skb")
int netdata_tcp_retransmit_skb(struct pt_regs* ctx)
{
__u16 family;
netdata_socket_idx_t idx = { };
struct bpf_map_def *tbl;

struct inet_sock *is = inet_sk((struct sock *)PT_REGS_PARM1(ctx));
family = set_idx_value(&idx, is);
tbl = (family == AF_INET6)?&tbl_conn_ipv6:&tbl_conn_ipv4;

netdata_update_global(NETDATA_KEY_TCP_RETRANSMIT, 1);
update_socket_table(tbl, &idx, 0, 0, 1, IPPROTO_TCP);

return 0;
}

/**
* https://elixir.bootlin.com/linux/v5.6.14/source/net/ipv4/tcp.c#L1528
*/
Expand Down Expand Up @@ -341,7 +372,7 @@ int netdata_tcp_cleanup_rbuf(struct pt_regs* ctx)
tbl = (family == AF_INET6)?&tbl_conn_ipv6:&tbl_conn_ipv4;

netdata_update_global(NETDATA_KEY_BYTES_TCP_CLEANUP_RBUF, received);
update_socket_table(tbl, &idx, 0, received, IPPROTO_TCP);
update_socket_table(tbl, &idx, 0, received, 0, IPPROTO_TCP);
update_pid_stats(pid, tgid, 0, received);

return 0;
Expand Down Expand Up @@ -376,16 +407,16 @@ int netdata_tcp_close(struct pt_regs* ctx)
}

/************************************************************************************
*
*
* UDP Section
*
*
***********************************************************************************/

/* We can only get the accurate number of copied bytes from the return value, so we pass our
* sock* pointer from the kprobe to the kretprobe via a map (udp_recv_sock) to get all required info
*
* The same issue exists for TCP, but we can conveniently use the downstream function tcp_cleanup_rbuf
*/
*/

/**
* https://elixir.bootlin.com/linux/v5.6.14/source/net/ipv4/udp.c#L1726
Expand Down Expand Up @@ -438,7 +469,7 @@ int trace_udp_ret_recvmsg(struct pt_regs* ctx)
tbl = (family == AF_INET6)?&tbl_conn_ipv6:&tbl_conn_ipv4;

netdata_update_global(NETDATA_KEY_BYTES_UDP_RECVMSG, received);
update_socket_table(tbl, &idx, 0, received, IPPROTO_UDP);
update_socket_table(tbl, &idx, 0, received, 0, IPPROTO_UDP);

update_pid_stats(pid, tgid, 0, received);

Expand Down Expand Up @@ -478,7 +509,7 @@ int trace_udp_sendmsg(struct pt_regs* ctx)
family = set_idx_value(&idx, is);
tbl = (family == AF_INET6)?&tbl_conn_ipv6:&tbl_conn_ipv4;

update_socket_table(tbl, &idx, (__u64) sent, 0, IPPROTO_UDP);
update_socket_table(tbl, &idx, (__u64) sent, 0, 0, IPPROTO_UDP);
update_pid_stats(pid, tgid, (__u64) sent, 0);

netdata_update_global(NETDATA_KEY_BYTES_UDP_SENDMSG, (__u64) sent);
Expand All @@ -493,9 +524,9 @@ int trace_udp_sendmsg(struct pt_regs* ctx)
}

/************************************************************************************
*
*
* Process Section
*
*
***********************************************************************************/

/**
Expand Down

0 comments on commit 6a598c6

Please sign in to comment.