Files
weave-scope/experimental/ftrace/main.go
2015-08-21 10:46:30 +00:00

128 lines
2.4 KiB
Go

package main
import (
"fmt"
"strconv"
"time"
"github.com/bluele/gcache"
)
const cacheSize = 500
// On every connect and accept, we lookup the local addr
// As this is expensive, we cache the result
var fdAddrCache = gcache.New(cacheSize).LRU().Expiration(15 * time.Second).Build()
type fdCacheKey struct {
pid int
fd int
}
type fdCacheValue struct {
addr uint32
port uint16
}
func getCachedLocalAddr(pid, fd int) (uint32, uint16, error) {
key := fdCacheKey{pid, fd}
val, err := fdAddrCache.Get(key)
if val != nil {
return val.(fdCacheValue).addr, val.(fdCacheValue).port, nil
}
addr, port, err := getLocalAddr(pid, fd)
if err != nil {
return 0, 0, err
}
fdAddrCache.Set(key, fdCacheValue{addr, port})
return addr, port, nil
}
// On every connect or accept, we cache the syscall that caused
// it for matching with a connection from conntrack
var syscallCache = gcache.New(cacheSize).LRU().Expiration(15 * time.Second).Build()
type syscallCacheKey struct {
localAddr uint32
localPort uint16
}
type syscallCacheValue *syscall
// One ever conntrack connection, we cache it by local addr, port to match with
// a future syscall
var conntrackCache = gcache.New(cacheSize).LRU().Expiration(15 * time.Second).Build()
type conntrackCacheKey syscallCacheKey
// And keep a list of successfully matched connection, for us to close out
// when we get the close syscall
func main() {
ftrace, err := NewFtracer()
if err != nil {
panic(err)
}
ftrace.start()
defer ftrace.stop()
syscalls := make(chan *syscall, 100)
go ftrace.events(syscalls)
onSocket := func(s *syscall) {
}
onConnection := func(s *syscall) {
if s.returnCode != 0 {
return
}
fdStr, ok := s.args["fd"]
if !ok {
panic("no pid")
}
fd64, err := strconv.ParseInt(fdStr, 32, 16)
if err != nil {
panic(err)
}
fd := int(fd64)
addr, port, err := getCachedLocalAddr(s.pid, fd)
if err != nil {
fmt.Printf("Failed to get local addr for pid=%d fd=%d: %v\n", s.pid, fd, err)
return
}
fmt.Printf("%+v %d %d\n", s, addr, port)
syscallCache.Set(syscallCacheKey{addr, port}, s)
}
onAccept := func(s *syscall) {
}
onClose := func(s *syscall) {
}
fmt.Println("Started")
for {
select {
case s := <-syscalls:
switch s.name {
case "socket":
onSocket(s)
case "connect":
onConnection(s)
case "accept", "accept4":
onAccept(s)
case "close":
onClose(s)
}
}
}
}