034 Project 34: eBPF XDP Packet Counter
034 Build an eBPF XDP Packet Counter
Attach an XDP program to a NIC and count packets in a BPF map.
Goal
- attach XDP to interface
- increment packet counter map in kernel
- read counter from userspace every second
main.go skeleton
package main
import (
"fmt"
"log"
"time"
"github.com/cilium/ebpf/link"
)
func main() {
objs := bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
log.Fatal(err)
}
defer objs.Close()
l, err := link.AttachXDP(link.XDPOptions{
Program: objs.XdpCount,
Interface: 2, // set your interface index
})
if err != nil {
log.Fatal(err)
}
defer l.Close()
for range time.Tick(time.Second) {
var key uint32 = 0
var value uint64
if err := objs.PacketCount.Lookup(&key, &value); err == nil {
fmt.Printf("packets=%d\n", value)
}
}
}Notes
- Keep this in a lab VM.
- Add interface discovery + CLI flags.
- Add map reset endpoint after reading.
Step-by-Step Explanation
- Keep kernel-side eBPF logic minimal and focused.
- Load and attach program from userspace.
- Stream events or counters from maps/buffers.
- Handle shutdown and detachment cleanly.
- Validate behavior in an isolated Linux lab environment.
Code Anatomy
- eBPF program runs in kernel hook.
- Userspace Go loader manages attach/read lifecycle.
- Reader loop transforms low-level events into readable output.
Learning Goals
- Understand event-driven observability close to the kernel.
- Learn safe iteration practices for low-level tooling.
- Build confidence with modern Linux instrumentation.