github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/examples/tcprtt/main.go (about) 1 // This program demonstrates attaching a fentry eBPF program to 2 // tcp_close and reading the RTT from the TCP socket using CO-RE helpers. 3 // It prints the IPs/ports/RTT information 4 // once the host closes a TCP connection. 5 // It supports only IPv4 for this example. 6 // 7 // Sample output: 8 // 9 // examples# go run -exec sudo ./tcprtt 10 // 2022/03/19 22:30:34 Src addr Port -> Dest addr Port RTT 11 // 2022/03/19 22:30:36 10.0.1.205 50578 -> 117.102.109.186 5201 195 12 // 2022/03/19 22:30:53 10.0.1.205 0 -> 89.84.1.178 9200 30 13 // 2022/03/19 22:30:53 10.0.1.205 36022 -> 89.84.1.178 9200 28 14 15 package main 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "errors" 21 "log" 22 "net" 23 "os" 24 "os/signal" 25 "syscall" 26 27 "github.com/cilium/ebpf/link" 28 "github.com/cilium/ebpf/ringbuf" 29 "github.com/cilium/ebpf/rlimit" 30 ) 31 32 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -type event bpf tcprtt.c -- -I../headers 33 34 func main() { 35 stopper := make(chan os.Signal, 1) 36 signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) 37 38 // Allow the current process to lock memory for eBPF resources. 39 if err := rlimit.RemoveMemlock(); err != nil { 40 log.Fatal(err) 41 } 42 43 // Load pre-compiled programs and maps into the kernel. 44 objs := bpfObjects{} 45 if err := loadBpfObjects(&objs, nil); err != nil { 46 log.Fatalf("loading objects: %v", err) 47 } 48 defer objs.Close() 49 50 link, err := link.AttachTracing(link.TracingOptions{ 51 Program: objs.bpfPrograms.TcpClose, 52 }) 53 if err != nil { 54 log.Fatal(err) 55 } 56 defer link.Close() 57 58 rd, err := ringbuf.NewReader(objs.bpfMaps.Events) 59 if err != nil { 60 log.Fatalf("opening ringbuf reader: %s", err) 61 } 62 defer rd.Close() 63 64 log.Printf("%-15s %-6s -> %-15s %-6s %-6s", 65 "Src addr", 66 "Port", 67 "Dest addr", 68 "Port", 69 "RTT", 70 ) 71 go readLoop(rd) 72 73 // Wait 74 <-stopper 75 } 76 77 func readLoop(rd *ringbuf.Reader) { 78 // bpfEvent is generated by bpf2go. 79 var event bpfEvent 80 for { 81 record, err := rd.Read() 82 if err != nil { 83 if errors.Is(err, ringbuf.ErrClosed) { 84 log.Println("received signal, exiting..") 85 return 86 } 87 log.Printf("reading from reader: %s", err) 88 continue 89 } 90 91 // Parse the ringbuf event entry into a bpfEvent structure. 92 if err := binary.Read(bytes.NewBuffer(record.RawSample), binary.NativeEndian, &event); err != nil { 93 log.Printf("parsing ringbuf event: %s", err) 94 continue 95 } 96 97 log.Printf("%-15s %-6d -> %-15s %-6d %-6d", 98 intToIP(event.Saddr), 99 event.Sport, 100 intToIP(event.Daddr), 101 event.Dport, 102 event.Srtt, 103 ) 104 } 105 } 106 107 // intToIP converts IPv4 number to net.IP 108 func intToIP(ipNum uint32) net.IP { 109 ip := make(net.IP, 4) 110 binary.NativeEndian.PutUint32(ip, ipNum) 111 return ip 112 }