ebpf

package
v0.0.0-...-3dd6856 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2019 License: Apache-2.0, Apache-2.0 Imports: 24 Imported by: 0

README

Note

This package is a fork of the weaveworks tcptracer-bpf package which focused on tracing TCP state events (connect, accept, close) without kernel specific runtime dependencies.

This fork adds support for UDP, as well as collection of metrics like bytes sent/received. It also opts for event collection via polling (using BPF maps) instead of being pushed event updates via perf buffers.

tracer-bpf

tracer-bpf is an eBPF program using kprobes to trace TCP/UDP events (connect, accept, close, send_msg, recv_msg).

The eBPF program is compiled to an ELF object file.

tracer-bpf also provides a Go library that provides a simple API for loading the ELF object file. Internally, it is using the gobpf elf package.

tracer-bpf does not have any run-time dependencies on kernel headers and is not tied to a specific kernel version or kernel configuration. This is quite unusual for eBPF programs using kprobes: for example, eBPF programs using kprobes with bcc are compiled on the fly and depend on kernel headers. And perf tools compiled for one kernel version cannot be used on another kernel version.

To adapt to the currently running kernel at run-time, tracer-bpf creates a series of TCP connections with known parameters (such as known IP addresses and ports) and discovers where those parameters are stored in the kernel struct sock. The offsets of the struct sock fields vary depending on the kernel version and kernel configuration. Since an eBPF programs cannot loop, tracer-bpf does not directly iterate over the possible offsets. It is instead controlled from userspace by the Go library using a state machine.

Development

The easiest way to build and test is inside a Vagrant VM. You can provision the VM by running ./tools/dev_setup.sh and SSHing into the VM with vagrant ssh (vagrant must be installed.)

The VM will mount your local $GOPATH, so you can edit source code with your editor of choice.

make nettop will run a small testing program which periodically prints statistics about TCP/UDP traffic inside the VM.

Documentation

Index

Constants

View Source
const (
	// DEBUGCLIENT is the ClientID for debugging
	DEBUGCLIENT = "-1"
)

Variables

View Source
var (
	// ErrNotImplemented will be returned on non-linux environments like Windows and Mac OSX
	ErrNotImplemented = errors.New("BPF-based network tracing not implemented on non-linux systems")
)

Functions

func Asset

func Asset(name string) ([]byte, error)

Asset loads and returns the asset for the given name. It returns an error if the asset could not be found or could not be loaded.

func AssetDir

func AssetDir(name string) ([]string, error)

AssetDir returns the file names below a certain directory embedded in the file by go-bindata. For example if you run go-bindata on data/... and data contains the following hierarchy:

data/
  foo.txt
  img/
    a.png
    b.png

then AssetDir("data") would return []string{"foo.txt", "img"} AssetDir("data/img") would return []string{"a.png", "b.png"} AssetDir("foo.txt") and AssetDir("notexist") would return an error AssetDir("") will return []string{"data"}.

func AssetInfo

func AssetInfo(name string) (os.FileInfo, error)

AssetInfo loads and returns the asset info for the given name. It returns an error if the asset could not be found or could not be loaded.

func AssetNames

func AssetNames() []string

AssetNames returns the names of the assets.

func BeautifyKey

func BeautifyKey(key string) string

BeautifyKey returns a human readable byte key (used for debugging purposes) it should be in sync with ByteKey Note: This is only used in /debug/* endpoints

func CurrentKernelVersion

func CurrentKernelVersion() (uint32, error)

CurrentKernelVersion is not implemented on non-linux systems

func IsTracerSupportedByOS

func IsTracerSupportedByOS(exclusionList []string) (bool, error)

IsTracerSupportedByOS returns whether or not the current kernel version supports tracer functionality

func MustAsset

func MustAsset(name string) []byte

MustAsset is like Asset but panics when Asset would return an error. It simplifies safe initialization of global variables.

func RestoreAsset

func RestoreAsset(dir, name string) error

RestoreAsset restores an asset under the given directory

func RestoreAssets

func RestoreAssets(dir, name string) error

RestoreAssets restores an asset under the given directory recursively

Types

type Address

type Address interface {
	Bytes() []byte
	String() string
	MarshalEasyJSON(w *jwriter.Writer)
}

Address is an IP abstraction that is family (v4/v6) agnostic

func V4Address

func V4Address(ip uint32) Address

V4Address creates an Address using the uint32 representation of an v4 IP

func V4AddressFromBytes

func V4AddressFromBytes(buf []byte) Address

V4AddressFromBytes creates an Address using the byte representation of an v4 IP

func V4AddressFromString

func V4AddressFromString(ip string) Address

V4AddressFromString creates an Address using the string representation of an v4 IP

func V6Address

func V6Address(low, high uint64) Address

V6Address creates an Address using the uint128 representation of an v6 IP

func V6AddressFromBytes

func V6AddressFromBytes(buf []byte) Address

V6AddressFromBytes creates an Address using the byte representation of an v6 IP

func V6AddressFromString

func V6AddressFromString(ip string) Address

V6AddressFromString creates an Address using the string representation of an v6 IP

type Config

type Config struct {
	// CollectTCPConns specifies whether the tracer should collect traffic statistics for TCP connections
	CollectTCPConns bool

	// CollectUDPConns specifies whether the tracer should collect traffic statistics for UDP connections
	CollectUDPConns bool

	// CollectIPv6Conns specifics whether the tracer should capture traffic for IPv6 TCP/UDP connections
	CollectIPv6Conns bool

	// CollectLocalDNS specifies whether the tracer should capture traffic for local DNS calls
	CollectLocalDNS bool

	// UDPConnTimeout determines the length of traffic inactivity between two (IP, port)-pairs before declaring a UDP
	// connection as inactive.
	// Note: As UDP traffic is technically "connection-less", for tracking, we consider a UDP connection to be traffic
	//       between a source and destination IP and port.
	UDPConnTimeout time.Duration

	// TCPConnTimeout is like UDPConnTimeout, but for TCP connections. TCP connections are cleared when
	// the BPF module receives a tcp_close call, but TCP connections also age out to catch cases where
	// tcp_close is not intercepted for some reason.
	TCPConnTimeout time.Duration

	// MaxTrackedConnections specifies the maximum number of connections we can track, this will be the size of the BPF maps
	MaxTrackedConnections uint

	// ProcRoot is the root path to the proc filesystem
	ProcRoot string

	// BPFDebug enables bpf debug logs
	BPFDebug bool

	//  EnableConntrack enables probing conntrack for network address translation via netlink
	EnableConntrack bool

	// ConntrackShortTermBufferSize is the maximum number of short term conntracked connections that will
	// held in memory at once
	ConntrackShortTermBufferSize int
}

Config stores all flags used by the eBPF tracer

func NewDefaultConfig

func NewDefaultConfig() *Config

NewDefaultConfig enables traffic collection for all connection types

func (*Config) EnabledKProbes

func (c *Config) EnabledKProbes() map[KProbeName]struct{}

EnabledKProbes returns a map of kprobes that are enabled per config settings

type ConnectionDirection

type ConnectionDirection uint8

ConnectionDirection indicates if the connection is incoming to the host or outbound

const (
	// INCOMING represents connections inbound to the host
	INCOMING ConnectionDirection = 1

	// OUTGOING represents outbound connections from the host
	OUTGOING ConnectionDirection = 2

	// LOCAL represents connections that don't leave the host
	LOCAL ConnectionDirection = 3
)

func (ConnectionDirection) String

func (d ConnectionDirection) String() string

type ConnectionFamily

type ConnectionFamily uint8

ConnectionFamily will be either v4 or v6

const (
	// AFINET represents v4 connections
	AFINET ConnectionFamily = 0

	// AFINET6 represents v6 connections
	AFINET6 ConnectionFamily = 1
)

type ConnectionStats

type ConnectionStats struct {
	// Source & Dest represented as a string to handle both IPv4 & IPv6
	// Note: As ebpf.Address is an interface, we need to use interface{} for easyjson
	Source interface{} `json:"source,string"`
	Dest   interface{} `json:"dest,string"`

	MonotonicSentBytes uint64 `json:"monotonic_sent_bytes"`
	LastSentBytes      uint64 `json:"last_sent_bytes"`

	MonotonicRecvBytes uint64 `json:"monotonic_recv_bytes"`
	LastRecvBytes      uint64 `json:"last_recv_bytes"`

	// Last time the stats for this connection were updated
	LastUpdateEpoch uint64 `json:"last_update_epoch"`

	MonotonicRetransmits uint32 `json:"monotonic_retransmits"`
	LastRetransmits      uint32 `json:"last_retransmits"`

	Pid   uint32 `json:"pid"`
	NetNS uint32 `json:"net_ns"`

	SPort         uint16                 `json:"sport"`
	DPort         uint16                 `json:"dport"`
	Type          ConnectionType         `json:"type"`
	Family        ConnectionFamily       `json:"family"`
	Direction     ConnectionDirection    `json:"direction"`
	IPTranslation *netlink.IPTranslation `json:"conntrack"`
}

ConnectionStats stores statistics for a single connection. Field order in the struct should be 8-byte aligned

func (ConnectionStats) ByteKey

func (c ConnectionStats) ByteKey(buffer *bytes.Buffer) ([]byte, error)

ByteKey returns a unique key for this connection represented as a byte array

func (ConnectionStats) DestAddr

func (c ConnectionStats) DestAddr() Address

DestAddr returns the dest address in the Address abstraction

func (ConnectionStats) MarshalEasyJSON

func (v ConnectionStats) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (ConnectionStats) MarshalJSON

func (v ConnectionStats) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (ConnectionStats) SourceAddr

func (c ConnectionStats) SourceAddr() Address

SourceAddr returns the source address in the Address abstraction

func (ConnectionStats) String

func (c ConnectionStats) String() string

func (*ConnectionStats) UnmarshalEasyJSON

func (v *ConnectionStats) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*ConnectionStats) UnmarshalJSON

func (v *ConnectionStats) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type ConnectionType

type ConnectionType uint8

ConnectionType will be either TCP or UDP

const (
	// TCP connection type
	TCP ConnectionType = 0

	// UDP connection type
	UDP ConnectionType = 1
)

func (ConnectionType) String

func (c ConnectionType) String() string

type Connections

type Connections struct {
	Conns []ConnectionStats `json:"connections"`
}

Connections wraps a collection of ConnectionStats

func (Connections) MarshalEasyJSON

func (v Connections) MarshalEasyJSON(w *jwriter.Writer)

MarshalEasyJSON supports easyjson.Marshaler interface

func (Connections) MarshalJSON

func (v Connections) MarshalJSON() ([]byte, error)

MarshalJSON supports json.Marshaler interface

func (*Connections) UnmarshalEasyJSON

func (v *Connections) UnmarshalEasyJSON(l *jlexer.Lexer)

UnmarshalEasyJSON supports easyjson.Unmarshaler interface

func (*Connections) UnmarshalJSON

func (v *Connections) UnmarshalJSON(data []byte) error

UnmarshalJSON supports json.Unmarshaler interface

type KProbeName

type KProbeName string

KProbeName stores the name of the kernel probes setup for tracing

const (
	// TCPv4Connect traces the v4 connect() system call
	TCPv4Connect KProbeName = "kprobe/tcp_v4_connect"
	// TCPv4ConnectReturn traces the return value for the v4 connect() system call
	TCPv4ConnectReturn KProbeName = "kretprobe/tcp_v4_connect"
	// TCPv4DestroySock traces the tcp_v4_destroy_sock system call (called for both ipv4 and ipv6)
	TCPv4DestroySock KProbeName = "kprobe/tcp_v4_destroy_sock"

	// TCPv6Connect traces the v6 connect() system call
	TCPv6Connect KProbeName = "kprobe/tcp_v6_connect"
	// TCPv6ConnectReturn traces the return value for the v6 connect() system call
	TCPv6ConnectReturn KProbeName = "kretprobe/tcp_v6_connect"

	// TCPSendMsg traces the tcp_sendmsg() system call
	TCPSendMsg KProbeName = "kprobe/tcp_sendmsg"
	// TCPCleanupRBuf traces the tcp_cleanup_rbuf() system call
	TCPCleanupRBuf KProbeName = "kprobe/tcp_cleanup_rbuf"
	// TCPClose traces the tcp_close() system call
	TCPClose KProbeName = "kprobe/tcp_close"

	// UDPSendMsg traces the udp_sendmsg() system call
	UDPSendMsg KProbeName = "kprobe/udp_sendmsg"
	// UDPRecvMsg traces the udp_recvmsg() system call
	UDPRecvMsg KProbeName = "kprobe/udp_recvmsg"
	// UDPRecvMsgReturn traces the return value for the udp_recvmsg() system call
	UDPRecvMsgReturn KProbeName = "kretprobe/udp_recvmsg"

	// TCPRetransmit traces the return value for the tcp_retransmit_skb() system call
	TCPRetransmit KProbeName = "kprobe/tcp_retransmit_skb"

	// InetCskAcceptReturn traces the return value for the inet_csk_accept syscall
	InetCskAcceptReturn KProbeName = "kretprobe/inet_csk_accept"
)

type NetworkState

type NetworkState interface {
	// Connections returns the list of connections for the given client when provided the latest set of active connections
	Connections(clientID string, latestTime uint64, latestConns []ConnectionStats) []ConnectionStats

	// StoreClosedConnection stores a new closed connection
	StoreClosedConnection(conn ConnectionStats)

	// RemoveClient stops tracking stateful data for a given client
	RemoveClient(clientID string)

	// RemoveExpiredClients removes expired clients from the state
	RemoveExpiredClients(now time.Time)

	// RemoveConnections removes the given keys from the state
	RemoveConnections(keys []string)

	// GetStats returns a map of statistics about the current network state
	GetStats(closedPollLost, closedPollReceived, tracerSkippedCount, expiredTCP uint64) map[string]interface{}

	// DebugNetworkState returns a map with the current network state for a client ID
	DumpState(clientID string) map[string]interface{}
}

NetworkState takes care of handling the logic for: - closed connections - sent and received bytes per connection

func NewDefaultNetworkState

func NewDefaultNetworkState() NetworkState

NewDefaultNetworkState creates a new network state with default settings

func NewNetworkState

func NewNetworkState(clientExpiry time.Duration, maxClosedConns, maxClientStats int) NetworkState

NewNetworkState creates a new network state

type PortMapping

type PortMapping struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

PortMapping tracks which ports a pid is listening on

func NewPortMapping

func NewPortMapping(procRoot string, config *Config) *PortMapping

NewPortMapping creates a new PortMapping instance

func (*PortMapping) AddMapping

func (pm *PortMapping) AddMapping(port uint16)

AddMapping indicates that something is listening on the provided port

func (*PortMapping) IsListening

func (pm *PortMapping) IsListening(port uint16) bool

IsListening returns true if something is listening on the given port

func (*PortMapping) ReadInitialState

func (pm *PortMapping) ReadInitialState() error

ReadInitialState reads the /proc filesystem and determines which ports are being listened on

func (*PortMapping) RemoveMapping

func (pm *PortMapping) RemoveMapping(port uint16)

RemoveMapping indicates that the provided port is no longer being listened on

type Tracer

type Tracer struct{}

Tracer is not implemented on non-linux systems

func NewTracer

func NewTracer(_ *Config) (*Tracer, error)

NewTracer is not implemented on non-linux systems

func (*Tracer) DebugNetworkMaps

func (t *Tracer) DebugNetworkMaps() (*Connections, error)

DebugNetworkMaps is not implemented on non-linux systems

func (*Tracer) DebugNetworkState

func (t *Tracer) DebugNetworkState(clientID string) (map[string]interface{}, error)

DebugNetworkState is not implemented on non-linux systems

func (*Tracer) GetActiveConnections

func (t *Tracer) GetActiveConnections(_ string) (*Connections, error)

GetActiveConnections is not implemented on non-linux systems

func (*Tracer) GetStats

func (t *Tracer) GetStats() (map[string]interface{}, error)

GetStats is not implemented on non-linux systems

func (*Tracer) Stop

func (t *Tracer) Stop()

Stop is not implemented on non-linux systems

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL