BCC (BPF Compiler Collection) uses eBPF technology to write tracing programs that run inside the Linux kernel, enabling efficient and low-overhead monitoring of system events.
GitHub - iovisor/bcc: BCC - Tools for BPF-based Linux IO analysis, networking, monitoring, and more
The socket address is unique to each socket because it is an address value.
int trace_tcp_state_change(struct pt_regs *ctx, struct sock *sk, int state) {
u16 family = sk->__sk_common.skc_family;
if (family != AF_INET)
return 0;
u32 daddr = sk->__sk_common.skc_daddr;
if (daddr != DEST_IP)
return 0;
struct event_t ev = {};
ev.skaddr = (u64)sk;
ev.pid = bpf_get_current_pid_tgid() >> 32;
ev.state = state;
bpf_probe_read_kernel(&ev.saddr, sizeof(ev.saddr), &sk->__sk_common.skc_rcv_saddr);
bpf_probe_read_kernel(&ev.daddr, sizeof(ev.daddr), &sk->__sk_common.skc_daddr);
bpf_probe_read_kernel(&ev.sport, sizeof(ev.sport), &sk->__sk_common.skc_num);
bpf_probe_read_kernel(&ev.dport, sizeof(ev.dport), &sk->__sk_common.skc_dport);
ev.dport = ntohs(ev.dport);
events.perf_submit(ctx, &ev, sizeof(ev));
return 0;
}
def print_event(cpu, data, size):
event = ctypes.cast(data, ctypes.POINTER(Event)).contents
state_name = TCP_STATES.get(event.state, f"UNKNOWN({event.state})")
logger.info("%-6d %-15s %-15s %-15s %-6d %-6d" % (
event.pid,
state_name,
inet_ntoa(event.saddr),
inet_ntoa(event.daddr),
event.sport,
event.dport
))
if state_name == "SYN_SENT":
conn_attempts[event.skaddr] = event
elif state_name == "ESTABLISHED":
conn_attempts.pop(event.skaddr, None)
elif state_name == "CLOSE":
if event.skaddr in conn_attempts:
dest_ip=inet_ntoa(event.daddr)
dest_port=event.dport
logger.warning(f"TCP failure detected: {dest_ip}:{dest_port}")
alert_message_slack(f"TCP failure detected: {dest_ip}:{dest_port}")
conn_attempts.pop(event.skaddr, None)
[Unit]
Description=TCP Trace BPF Monitor
After=network.target
[Service]
ExecStart=/usr/bin/python3 /usr/local/bin/tcp_trace.py --log-file /var/log/tcp_trace.log
Restart=on-failure
User=root
Environment=DEST_IP=172.217.161.228
Environment=SLACK_URL=https://hooks.slack.com/services
StandardOutput=null
StandardError=null
[Install]
WantedBy=multi-user.target
In actual operation, logrotate is also necessary.
This test was not a rigorous load test, so it is difficult to confidently assert that the monitoring system can operate under typical production loads without any issues.
However, it clearly confirms that eBPF-based monitoring incurs minimal overhead as theoretically expected.
By utilizing BCC (BPF Compiler Collection) to trace kernel-level TCP events based on eBPF, the following characteristics were directly observed:
Of course, compared to commercial eBPF-based network monitoring products, this implementation is relatively simple and limited in functionality.
However, considering the time and effort required for development, the results were quite satisfactory.
It was impressive to see that even a simple structure can enable a meaningful level of network state monitoring.