Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: add example for CO-RE kernel struct (tcp_sock) #602

Merged
merged 1 commit into from Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/README.md
Expand Up @@ -15,6 +15,7 @@
* Fentry - Attach a program to the entrypoint of a kernel function.
Like kprobes, but with better performance and usability, for kernels 5.5 and later.
* [tcp_connect](fentry/) - Trace outgoing IPv4 TCP connections.
* [tcp_close](tcprtt/) - Log RTT of IPv4 TCP connections using eBPF CO-RE helpers.
gmichelo marked this conversation as resolved.
Show resolved Hide resolved
* Add your use case(s) here!

## How to run
Expand Down
127 changes: 127 additions & 0 deletions examples/tcprtt/bpf_bpfeb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added examples/tcprtt/bpf_bpfeb.o
Binary file not shown.
127 changes: 127 additions & 0 deletions examples/tcprtt/bpf_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added examples/tcprtt/bpf_bpfel.o
Binary file not shown.
117 changes: 117 additions & 0 deletions examples/tcprtt/main.go
@@ -0,0 +1,117 @@
//go:build linux
// +build linux

// This program demonstrates attaching a fentry eBPF program to
// tcp_close and reading the RTT from the TCP socket using CO-RE helpers.
// It prints the IPs/ports/RTT information
// once the host closes a TCP connection.
// It supports only IPv4 for this example.
//
// Sample output:
//
// examples# go run -exec sudo ./tcprtt
// 2022/03/19 22:30:34 Src addr Port -> Dest addr Port RTT
// 2022/03/19 22:30:36 10.0.1.205 50578 -> 117.102.109.186 5201 195
// 2022/03/19 22:30:53 10.0.1.205 0 -> 89.84.1.178 9200 30
// 2022/03/19 22:30:53 10.0.1.205 36022 -> 89.84.1.178 9200 28

package main

import (
"bytes"
"encoding/binary"
"errors"
"log"
"net"
"os"
"os/signal"
"syscall"

"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/ringbuf"
"github.com/cilium/ebpf/rlimit"
)

// $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS -type event bpf tcprtt.c -- -I../headers

func main() {
stopper := make(chan os.Signal, 1)
signal.Notify(stopper, os.Interrupt, syscall.SIGTERM)

// Allow the current process to lock memory for eBPF resources.
if err := rlimit.RemoveMemlock(); err != nil {
log.Fatal(err)
}

// Load pre-compiled programs and maps into the kernel.
objs := bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
log.Fatalf("loading objects: %v", err)
}
defer objs.Close()

link, err := link.AttachTracing(link.TracingOptions{
Program: objs.bpfPrograms.TcpClose,
})
if err != nil {
log.Fatal(err)
}
defer link.Close()

rd, err := ringbuf.NewReader(objs.bpfMaps.Events)
if err != nil {
log.Fatalf("opening ringbuf reader: %s", err)
}
defer rd.Close()

log.Printf("%-15s %-6s -> %-15s %-6s %-6s",
"Src addr",
"Port",
"Dest addr",
"Port",
"RTT",
)
go readLoop(rd)

// Wait
<-stopper
}

func readLoop(rd *ringbuf.Reader) {
// bpfEvent is generated by bpf2go.
var event bpfEvent
for {
record, err := rd.Read()
if err != nil {
if errors.Is(err, ringbuf.ErrClosed) {
log.Println("received signal, exiting..")
return
}
log.Printf("reading from reader: %s", err)
continue
}

// Parse the ringbuf event entry into a bpfEvent structure.
if err := binary.Read(bytes.NewBuffer(record.RawSample), internal.NativeEndian, &event); err != nil {
log.Printf("parsing ringbuf event: %s", err)
continue
}

log.Printf("%-15s %-6d -> %-15s %-6d %-6d",
intToIP(event.Saddr),
event.Sport,
intToIP(event.Daddr),
event.Dport,
event.Srtt,
)
}
}

// intToIP converts IPv4 number to net.IP
func intToIP(ipNum uint32) net.IP {
ip := make(net.IP, 4)
internal.NativeEndian.PutUint32(ip, ipNum)
return ip
}