github.com/cilium/ebpf@v0.10.0/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  // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
    21  //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf cgroup_skb.c -- -I../headers
    22  
    23  func main() {
    24  	// Allow the current process to lock memory for eBPF resources.
    25  	if err := rlimit.RemoveMemlock(); err != nil {
    26  		log.Fatal(err)
    27  	}
    28  
    29  	// Load pre-compiled programs and maps into the kernel.
    30  	objs := bpfObjects{}
    31  	if err := loadBpfObjects(&objs, nil); err != nil {
    32  		log.Fatalf("loading objects: %v", err)
    33  	}
    34  	defer objs.Close()
    35  
    36  	// Get the first-mounted cgroupv2 path.
    37  	cgroupPath, err := detectCgroupPath()
    38  	if err != nil {
    39  		log.Fatal(err)
    40  	}
    41  
    42  	// Link the count_egress_packets program to the cgroup.
    43  	l, err := link.AttachCgroup(link.CgroupOptions{
    44  		Path:    cgroupPath,
    45  		Attach:  ebpf.AttachCGroupInetEgress,
    46  		Program: objs.CountEgressPackets,
    47  	})
    48  	if err != nil {
    49  		log.Fatal(err)
    50  	}
    51  	defer l.Close()
    52  
    53  	log.Println("Counting packets...")
    54  
    55  	// Read loop reporting the total amount of times the kernel
    56  	// function was entered, once per second.
    57  	ticker := time.NewTicker(1 * time.Second)
    58  	defer ticker.Stop()
    59  
    60  	for range ticker.C {
    61  		var value uint64
    62  		if err := objs.PktCount.Lookup(uint32(0), &value); err != nil {
    63  			log.Fatalf("reading map: %v", err)
    64  		}
    65  		log.Printf("number of packets: %d\n", value)
    66  	}
    67  }
    68  
    69  // detectCgroupPath returns the first-found mount point of type cgroup2
    70  // and stores it in the cgroupPath global variable.
    71  func detectCgroupPath() (string, error) {
    72  	f, err := os.Open("/proc/mounts")
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  	defer f.Close()
    77  
    78  	scanner := bufio.NewScanner(f)
    79  	for scanner.Scan() {
    80  		// example fields: cgroup2 /sys/fs/cgroup/unified cgroup2 rw,nosuid,nodev,noexec,relatime 0 0
    81  		fields := strings.Split(scanner.Text(), " ")
    82  		if len(fields) >= 3 && fields[2] == "cgroup2" {
    83  			return fields[1], nil
    84  		}
    85  	}
    86  
    87  	return "", errors.New("cgroup2 not mounted")
    88  }