github.com/cilium/ebpf@v0.16.0/examples/tcx/main.go (about) 1 // This program demonstrates attaching an eBPF program to a network interface 2 // with Linux TC (Traffic Control). The program counts ingress and egress 3 // packets using two ARRAY maps. 4 // The userspace program (Go code in this file) prints the contents 5 // of the two maps to stdout every second. 6 // This example depends on tcx bpf_link, available in Linux kernel version 6.6 or newer. 7 package main 8 9 import ( 10 "fmt" 11 "log" 12 "net" 13 "os" 14 "time" 15 16 "github.com/cilium/ebpf" 17 "github.com/cilium/ebpf/link" 18 ) 19 20 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf tcx.c -- -I../headers 21 func main() { 22 if len(os.Args) < 2 { 23 log.Fatalf("Please specify a network interface") 24 } 25 26 // Look up the network interface by name. 27 ifaceName := os.Args[1] 28 iface, err := net.InterfaceByName(ifaceName) 29 if err != nil { 30 log.Fatalf("lookup network iface %q: %s", ifaceName, err) 31 } 32 33 // Load pre-compiled programs into the kernel. 34 objs := bpfObjects{} 35 if err := loadBpfObjects(&objs, nil); err != nil { 36 log.Fatalf("loading objects: %s", err) 37 } 38 defer objs.Close() 39 40 // Attach the program to Ingress TC. 41 l, err := link.AttachTCX(link.TCXOptions{ 42 Interface: iface.Index, 43 Program: objs.IngressProgFunc, 44 Attach: ebpf.AttachTCXIngress, 45 }) 46 if err != nil { 47 log.Fatalf("could not attach TCx program: %s", err) 48 } 49 defer l.Close() 50 51 log.Printf("Attached TCx program to INGRESS iface %q (index %d)", iface.Name, iface.Index) 52 53 // Attach the program to Egress TC. 54 l2, err := link.AttachTCX(link.TCXOptions{ 55 Interface: iface.Index, 56 Program: objs.EgressProgFunc, 57 Attach: ebpf.AttachTCXEgress, 58 }) 59 if err != nil { 60 log.Fatalf("could not attach TCx program: %s", err) 61 } 62 defer l2.Close() 63 64 log.Printf("Attached TCx program to EGRESS iface %q (index %d)", iface.Name, iface.Index) 65 log.Printf("Press Ctrl-C to exit and remove the program") 66 67 // Print the contents of the counters maps. 68 ticker := time.NewTicker(1 * time.Second) 69 defer ticker.Stop() 70 for range ticker.C { 71 s, err := formatCounters(objs.IngressPktCount, objs.EgressPktCount) 72 if err != nil { 73 log.Printf("Error reading map: %s", err) 74 continue 75 } 76 77 log.Printf("Packet Count: %s\n", s) 78 } 79 } 80 81 func formatCounters(ingressMap, egressMap *ebpf.Map) (string, error) { 82 var ( 83 ingressPacketCount uint64 84 egressPacketCount uint64 85 key int32 86 ) 87 88 // retrieve value from the ingress map 89 if err := ingressMap.Lookup(&key, &ingressPacketCount); err != nil { 90 return "", err 91 } 92 93 // retrieve value from the egress map 94 if err := egressMap.Lookup(&key, &egressPacketCount); err != nil { 95 return "", err 96 } 97 98 return fmt.Sprintf("%10v Ingress, %10v Egress", ingressPacketCount, egressPacketCount), nil 99 }