Skip to content

Commit

Permalink
examples: attach to tcp_close using fentry program with CO-RE
Browse files Browse the repository at this point in the history
This commit adds a new `fentry` program to showcase how `preserve_access_index`
can be used to read fields from kernel structs without knowing the entire
struct definition. That is, CO-RE takes care of finding the offset of
the field the caller is looking for within the struct in the host kernel.
  • Loading branch information
gmichelo authored and ti-mo committed Mar 30, 2022
1 parent e0ada27 commit 6375442
Show file tree
Hide file tree
Showing 7 changed files with 488 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
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.
* 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
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 6375442

Please sign in to comment.