github.com/cilium/ebpf@v0.10.0/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/internal" 28 "github.com/cilium/ebpf/link" 29 "github.com/cilium/ebpf/ringbuf" 30 "github.com/cilium/ebpf/rlimit" 31 ) 32 33 // $BPF_CLANG and $BPF_CFLAGS are set by the Makefile. 34 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -type event bpf tcprtt.c -- -I../headers 35 36 func main() { 37 stopper := make(chan os.Signal, 1) 38 signal.Notify(stopper, os.Interrupt, syscall.SIGTERM) 39 40 // Allow the current process to lock memory for eBPF resources. 41 if err := rlimit.RemoveMemlock(); err != nil { 42 log.Fatal(err) 43 } 44 45 // Load pre-compiled programs and maps into the kernel. 46 objs := bpfObjects{} 47 if err := loadBpfObjects(&objs, nil); err != nil { 48 log.Fatalf("loading objects: %v", err) 49 } 50 defer objs.Close() 51 52 link, err := link.AttachTracing(link.TracingOptions{ 53 Program: objs.bpfPrograms.TcpClose, 54 }) 55 if err != nil { 56 log.Fatal(err) 57 } 58 defer link.Close() 59 60 rd, err := ringbuf.NewReader(objs.bpfMaps.Events) 61 if err != nil { 62 log.Fatalf("opening ringbuf reader: %s", err) 63 } 64 defer rd.Close() 65 66 log.Printf("%-15s %-6s -> %-15s %-6s %-6s", 67 "Src addr", 68 "Port", 69 "Dest addr", 70 "Port", 71 "RTT", 72 ) 73 go readLoop(rd) 74 75 // Wait 76 <-stopper 77 } 78 79 func readLoop(rd *ringbuf.Reader) { 80 // bpfEvent is generated by bpf2go. 81 var event bpfEvent 82 for { 83 record, err := rd.Read() 84 if err != nil { 85 if errors.Is(err, ringbuf.ErrClosed) { 86 log.Println("received signal, exiting..") 87 return 88 } 89 log.Printf("reading from reader: %s", err) 90 continue 91 } 92 93 // Parse the ringbuf event entry into a bpfEvent structure. 94 if err := binary.Read(bytes.NewBuffer(record.RawSample), internal.NativeEndian, &event); err != nil { 95 log.Printf("parsing ringbuf event: %s", err) 96 continue 97 } 98 99 log.Printf("%-15s %-6d -> %-15s %-6d %-6d", 100 intToIP(event.Saddr), 101 event.Sport, 102 intToIP(event.Daddr), 103 event.Dport, 104 event.Srtt, 105 ) 106 } 107 } 108 109 // intToIP converts IPv4 number to net.IP 110 func intToIP(ipNum uint32) net.IP { 111 ip := make(net.IP, 4) 112 internal.NativeEndian.PutUint32(ip, ipNum) 113 return ip 114 }