Network Drop Monitoring (dropwatch)

Overview

dropwatch is a kernel network drop observability tool provided by HUATUO. It attaches to the kernel tracepoint tracepoint/skb/kfree_skb to capture network drop events in real time, and outputs the full drop context: protocol type, IP five-tuple, process name, PID, network device, MAC address, and the complete kernel call stack that triggered the drop.

dropwatch supports kernel-side filtering based on tcpdump-style filter expressions. The filter logic is compiled into eBPF bytecode at load time by the built-in pure-Go pcap compiler internal/pcapfilter. Filtering is performed entirely in kernel mode — only matching packets are reported to user space, reducing performance impact on the host.

In addition, dropwatch supports device whitelist/blacklist filtering, global per-second rate limiting, and integration with huatuo-bamai to store drop events in Elasticsearch for long-term analysis.


Scenarios

1. Kubernetes Cloud-Native Network Drop Diagnosis

In scenarios such as container migration, frequent Pod restarts, and Service port conflicts, dropwatch captures kfree_skb events in real time and correlates them with specific containers to quickly identify the root cause of packet drops. Combined with --filter "tcp and port <service-port>" to filter specific business traffic, the mean time to root cause is reduced from hours to minutes.

2. Network Performance Spike Analysis

For intermittent spikes in network latency or drops in throughput, dropwatch collects drop events and, together with the kernel call stack, identifies the specific kernel function where the drop occurred (e.g. tcp_v4_rcv, ip_output). This helps distinguish whether the cause is a firewall drop, routing failure, buffer overflow, or other reasons.

3. Multi-Tenant Network Isolation Troubleshooting

In container environments that share network namespaces or veth devices, use --device to filter by network device and --filter to filter by protocol. This precisely captures drop events for the target container, preventing other tenants’ traffic from interfering with the diagnosis.

4. Observability Platform Integration

Use --output-storage to send drop events to huatuo-bamai, which stores them in Elasticsearch for multi-dimensional correlation with metrics and logs. Overlay drop events on a Grafana timeline, aligned with application error rates and latency curves, to correlate kernel drops with application anomalies precisely.


Usage

1. Filter Expressions

Filter expressions use tcpdump syntax. The built-in pure-Go pcap compiler internal/pcapfilter compiles them into eBPF bytecode at load time. Filtering is performed entirely in kernel mode, reducing host impact — only matching packets are reported to user space.

1.1 Supported Expressions

internal/pcapfilter supports a subset of the standard tcpdump syntax. The following primitives are reliable:

Protocols

ip   ip6   tcp   udp   icmp   icmp6   igmp   pim   esp   ah   vrrp   arp   rarp
ip proto tcp      ip6 proto udp        (protocol names only; numeric protocol numbers not supported)

Host addresses

host 10.0.0.1
src host 10.0.0.1
dst host 10.0.0.1

Ports

port 80
src port 443
dst port 8080

Networks (CIDR)

net 10.0.0.0/8
src net 192.168.1.0/24
dst net 172.16.0.0/12

Multicast and Ethernet addresses

ip multicast    ip6 multicast    multicast    ether multicast
ether host 00:11:22:33:44:55

Boolean operators and grouping

tcp and port 80
tcp or udp
not arp
tcp and (port 80 or port 443)
ip and src net 192.168.1.0/24 and tcp dst port 3306

1.2 Unsupported Expressions

The following expressions are not supported. Using them causes compilation failures or incorrect match results:

Expression Reason
tcp[tcpflags] & tcp-syn != 0, ip[8], tcp[0:4] Byte-offset expressions (proto[offset:size]) not implemented
ip proto 6, ip6 proto 17 Numeric protocol numbers not supported; use names (e.g. ip proto tcp)
ether proto 0x0800 Hex EtherType not supported; use names (e.g. ether proto ip)
sctp Keyword not recognized
portrange 80-90, tcp portrange 1-100 Port ranges not supported
less N, greater N Packet-length filtering not supported
ip broadcast, ether broadcast Broadcast matching not supported
vlan, mpls, pppoes Tunnel/encapsulation keywords not supported
gateway Not supported

1.3 Examples

# Monitor all TCP drops (default — reliable in both L2 and L3 contexts)
--filter "tcp"

# TCP and UDP
--filter "tcp or udp"

# Specific destination host (applies to both TCP and UDP)
--filter "dst host 10.0.0.1"

# Specific port
--filter "tcp and port 443"

# Exclude a noisy host
--filter "tcp and not host 169.254.169.254"

# Specific subnet + specific port
--filter "src net 192.168.1.0/24 and tcp dst port 3306"

# Monitor non-TCP drops (UDP and ICMP only — avoid "not tcp", which captures unknown L3 events)
--filter "udp or icmp"

# Monitor ARP drops only (effective only in L2 context; never matches at L3)
--filter "arp"

--filter "ip" / --filter "ip6" now correctly match the corresponding IP protocol family (L2 by EtherType, L3 by version nibble). If you only care about a specific transport layer or host, prefer the more precise tcp, udp, host, or ip proto <name>.


2. Running dropwatch

dropwatch [flags]
Flag Default Description
--bpf-path <path> required Path to the dropwatch eBPF object file
--filter <expr> (none) tcpdump-style filter expression
--device <names> (none) Device whitelist: only collect drops from these devices; comma-separated (e.g. eth0,eth1)
--device-excluded <names> (none) Device blacklist: exclude drops from these devices; mutually exclusive with --device
--duration <n> 0 Stop after N seconds (0 = run until Ctrl-C)
--output <json|text> text Output format; ignored when --output-storage is set
--output-storage <path> (none) Send events to huatuo-bamai via Unix socket
--task-id <id> (none) Task ID for this session; typically used with --output-storage
--max-events-per-second <n> 0 Global rate limit in events/sec (0 = unlimited); applied after --device / --filter

--filter and device filtering are orthogonal; when both are specified, both apply (AND semantics). If neither --device nor --device-excluded is specified, all devices are collected. --device and --device-excluded are mutually exclusive; whitelist mode drops SKBs without a net_device, while blacklist mode passes them.

Examples

# Text output, monitor TCP drops on all devices
sudo dropwatch --bpf-path bpf/dropwatch.o --filter "tcp"

# Monitor drops on eth0 only
sudo dropwatch --bpf-path bpf/dropwatch.o --device eth0 --output json

# Exclude loopback
sudo dropwatch --bpf-path bpf/dropwatch.o --device-excluded lo --output json

# Combine device and protocol filters
sudo dropwatch --bpf-path bpf/dropwatch.o --device eth0 --filter "tcp and port 443" --output json

# Capture for 60 seconds and exit
sudo dropwatch --bpf-path bpf/dropwatch.o --filter "tcp and port 443" --duration 60 --output json

# Forward events to a running huatuo-bamai instance
sudo dropwatch --bpf-path bpf/dropwatch.o --filter "tcp" --output-storage /var/run/huatuo/events.sock

# Use jq to filter and show only RST packets
sudo dropwatch --bpf-path bpf/dropwatch.o --output json 2>/dev/null | jq 'select(.layers.tcp.flags == "RST")'

# Capture 10 seconds of JSON output, excluding events whose stack contains ip_finish_output
sudo dropwatch --output json --duration 10 --bpf-path bpf/dropwatch.o | jq -c 'select(.stack | test("ip_finish_output") | not)'

# Capture 10 seconds of JSON output, printing all fields except stack
sudo dropwatch --output json --duration 10 --bpf-path bpf/dropwatch.o | jq -c 'del(.stack)'

jq -c compresses each matching event into a single-line JSON, convenient for saving as NDJSON or further pipe processing. test("ip_finish_output") checks whether stack matches the regex; not negates the result, so the command above excludes stacks containing ip_finish_output. Remove | not to keep only those containing ip_finish_output. del(.stack) removes the stack field from the jq output, useful for viewing just the timestamp, device, process, packet_* metadata, and layers protocol fields. For kernel-side call-stack filtering, configure EventTracing.IssuesList in huatuo-bamai (see Section 4).


3. Event Data Structure

Each drop event is represented as an NDJSON object (types.DropWatchTracing).

Field Type Description
observed_timestamp string UTC timestamp when the event was captured (RFC3339Nano)
type string Event type reserved field; currently empty string
drop_reason string Drop reason reserved field; currently empty string
source string Event source; when present, indicates events or tools (omitempty)
comm string Process name at the time of the drop
pid uint64 Process TGID
container_id string Container ID (populated by huatuo-bamai resolution, omitempty)
memory_cgroup_css_addr string Memory cgroup CSS address, used for container resolution
net_namespace_cookie uint64 Network namespace cookie, used for container resolution
net_namespace_inode uint32 Network namespace inode, used for container resolution
netdev_name string Network device name (e.g. eth0)
netdev_ifindex uint32 Network interface index
netdev_queue_mapping uint32 TX queue mapping
netdev_linkstatus []string Network device link status flags
packet_skb_addr string SKB address (hexadecimal, omitempty)
packet_eth_proto string Raw EtherType (hexadecimal, e.g. 0x0800)
packet_len uint32 Packet length in bytes
layers object Layered protocol parse result; missing layers are omitted
stack string Kernel call stack (newline-separated)

layers uses fixed fields to express the protocol stack, without relying on a separate protocol enumeration:

Field Description
layers.label Protocol combination label, e.g. IPv4/TCP, IPv6/UDP, ARP, unknown
layers.ether L2 fields: src, dst, type, len (present only for 802.3 frames)
layers.ipv4 IPv4 fields: version, ihl, tos, len, id, flags, frag_offset, ttl, protocol, checksum, src, dst
layers.ipv6 IPv6 fields: version, traffic_class, flow_label, len, next_header, hop_limit, src, dst
layers.tcp TCP fields: sport, dport, seq, ack, data_offset, flags, window, checksum, urgent, sk_state
layers.udp UDP fields: sport, dport, len, checksum
layers.icmp ICMP/ICMPv6 fields: type, code, checksum, id, seq
layers.arp ARP fields: addr_type, protocol, hw_address_size, prot_address_size, operation, sender_mac, sender_ip, target_mac, target_ip

4. Integration with huatuo-bamai

huatuo-bamai launches dropwatch as a subprocess and uses --output-storage to send events to the built-in processing pipeline, which ultimately stores them in Elasticsearch. Typical parameters:

dropwatch \
  --bpf-path <CoreBpfDir>/dropwatch.o \
  --output-storage /var/run/huatuo/events.sock \
  --filter "tcp"

4.1 Configuration Reference (huatuo-bamai.conf)

[EventTracing]
    # Known noisy call-stack filters. dropwatch discards events whose stack matches these regexes.
    # The default examples cover neighbor table cleanup and bnxt TX completion SKB frees.
    IssuesList = [["neigh_invalidate", "neigh_invalidate"], ["bnxt_tx_int", "bnxt_tx_int"]]

[EventTracing.Dropwatch]
    # tcpdump filter expression, forwarded to dropwatch --filter.
    # Default: "tcp"
    Filter = "tcp"

    # Forwarded to dropwatch --max-events-per-second.
    # Default: 100
    MaxEventsPerSecond = 100

4.2 Noise Filtering

The following three categories of kfree_skb events are filtered by default because they are not real data-plane drops:

Pattern Stack Frame Prefix Reason
TCP CLOSE_WAIT + skb_rbtree_purge skb_rbtree_purge/ Normal socket teardown: the kernel releases in-flight SKBs when closing a socket in CLOSE_WAIT state.
ARP/neighbor table expiry neigh_invalidate/ Neighbor table entry expiration cleanup; does not affect any active data flow. Remove the rule from EventTracing.IssuesList to disable this filter.
bnxt NIC TX completion bnxt_tx_int/ or __bnxt_tx_int/ The Broadcom bnxt NIC driver calls kfree_skb to release SKBs after DMA transmit completion; this is normal behavior, not a drop.

Closing