github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/cgroup_skb/main.go (about) 1 // This program demonstrates attaching an eBPF program to a control group. 2 // The eBPF program will be attached as an egress filter, 3 // receiving an `__sk_buff` pointer for each outgoing packet. 4 // It prints the count of total packets every second. 5 package main 6 7 import ( 8 "bufio" 9 "errors" 10 "log" 11 "os" 12 "strings" 13 "time" 14 15 "github.com/cilium/ebpf" 16 "github.com/cilium/ebpf/link" 17 "github.com/cilium/ebpf/rlimit" 18 ) 19 20 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf cgroup_skb.c -- -I../headers 21 22 func main() { 23 // Allow the current process to lock memory for eBPF resources. 24 if err := rlimit.RemoveMemlock(); err != nil { 25 log.Fatal(err) 26 } 27 28 // Load pre-compiled programs and maps into the kernel. 29 objs := bpfObjects{} 30 if err := loadBpfObjects(&objs, nil); err != nil { 31 log.Fatalf("loading objects: %v", err) 32 } 33 defer objs.Close() 34 35 // Get the first-mounted cgroupv2 path. 36 cgroupPath, err := detectCgroupPath() 37 if err != nil { 38 log.Fatal(err) 39 } 40 41 // Link the count_egress_packets program to the cgroup. 42 l, err := link.AttachCgroup(link.CgroupOptions{ 43 Path: cgroupPath, 44 Attach: ebpf.AttachCGroupInetEgress, 45 Program: objs.CountEgressPackets, 46 }) 47 if err != nil { 48 log.Fatal(err) 49 } 50 defer l.Close() 51 52 log.Println("Counting packets...") 53 54 // Read loop reporting the total amount of times the kernel 55 // function was entered, once per second. 56 ticker := time.NewTicker(1 * time.Second) 57 defer ticker.Stop() 58 59 for range ticker.C { 60 var value uint64 61 if err := objs.PktCount.Lookup(uint32(0), &value); err != nil { 62 log.Fatalf("reading map: %v", err) 63 } 64 log.Printf("number of packets: %d\n", value) 65 } 66 } 67 68 // detectCgroupPath returns the first-found mount point of type cgroup2 69 // and stores it in the cgroupPath global variable. 70 func detectCgroupPath() (string, error) { 71 f, err := os.Open("/proc/mounts") 72 if err != nil { 73 return "", err 74 } 75 defer f.Close() 76 77 scanner := bufio.NewScanner(f) 78 for scanner.Scan() { 79 // example fields: cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0 80 fields := strings.Split(scanner.Text(), " ") 81 if len(fields) >= 3 && fields[2] == "cgroup2" { 82 return fields[1], nil 83 } 84 } 85 86 return "", errors.New("cgroup2 not mounted") 87 }