ebpf

package module
v0.0.0-...-4233cdb Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2020 License: MIT Imports: 23 Imported by: 13

README

eBPF

eBPF is a pure Go library that provides utilities for loading, compiling, and debugging eBPF programs. It has minimal external dependencies and is intended to be used in long running processes.

ebpf/asm contains a basic assembler.

An Important Note About Licenses:

The main part of this code is governed by an MIT license. However, the examples folder is a near straight port of the Linux eBPF samples folder, which makes that code governed by GPLv2, so be careful if you copy from it heavily as you are likely pinning yourself to GPLv2.

Further reading

Documentation

Overview

Package ebpf is a toolkit for working with eBPF programs.

eBPF programs are small snippets of code which are executed directly in a VM in the Linux kernel, which makes them very fast and flexible. Many Linux subsystems now accept eBPF programs. This makes it possible to implement highly application specific logic inside the kernel, without having to modify the actual kernel itself.

Since eBPF is a relatively young concept, documentation and user space support is still lacking. Most of the available tools are written in C, and reside in the kernel's source tree. The more mature external projects like libbcc focus on using eBPF for instrumentation and debugging. This leads to certain trade-offs which are not acceptable when writing production services.

This package is instead designed for long-running processes which want to use eBPF to implement part of their application logic. It has no run-time dependencies outside of the library and the Linux kernel itself. eBPF code should be compiled ahead of time using clang, and shipped with your application as any other resource.

The two main parts are an ELF loader, which reads object files emitted by clang, and facilities to modify and load eBPF programs into the kernel.

This package doesn't include code required to attach eBPF to Linux subsystems, since this varies per subsystem. See the examples for possible solutions.

Example (ExtractDistance)

ExampleExtractDistance shows how to attach an eBPF socket filter to extract the network distance of an IP host.

package main

// This code is derived from https://github.com/cloudflare/cloudflare-blog/tree/master/2018-03-ebpf
//
// Copyright (c) 2015-2017 Cloudflare, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of the Cloudflare, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import (
	"fmt"
	"net"
	"syscall"

	"github.com/Gui774ume/ebpf"
	"github.com/Gui774ume/ebpf/asm"
)

// ExampleExtractDistance shows how to attach an eBPF socket filter to
// extract the network distance of an IP host.
func main() {
	filter, TTLs, err := newDistanceFilter()
	if err != nil {
		panic(err)
	}
	defer filter.Close()
	defer TTLs.Close()

	// Attach filter before the call to connect()
	dialer := net.Dialer{
		Control: func(network, address string, c syscall.RawConn) (err error) {
			const SO_ATTACH_BPF = 50

			err = c.Control(func(fd uintptr) {
				err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, SO_ATTACH_BPF, filter.FD())
			})
			return err
		},
	}

	conn, err := dialer.Dial("tcp", "1.1.1.1:53")
	if err != nil {
		panic(err)
	}
	conn.Close()

	minDist, err := minDistance(TTLs)
	if err != nil {
		panic(err)
	}

	fmt.Println("1.1.1.1:53 is", minDist, "hops away")
}

func newDistanceFilter() (*ebpf.Program, *ebpf.Map, error) {
	const ETH_P_IPV6 uint16 = 0x86DD

	ttls, err := ebpf.NewMap(&ebpf.MapSpec{
		Type:       ebpf.Hash,
		KeySize:    4,
		ValueSize:  8,
		MaxEntries: 4,
	})
	if err != nil {
		return nil, nil, err
	}

	insns := asm.Instructions{
		// r1 has ctx
		// r0 = ctx[16] (aka protocol)
		asm.LoadMem(asm.R0, asm.R1, 16, asm.Word),

		// Perhaps ipv6
		asm.LoadImm(asm.R2, int64(ETH_P_IPV6), asm.DWord),
		asm.HostTo(asm.BE, asm.R2, asm.Half),
		asm.JEq.Reg(asm.R0, asm.R2, "ipv6"),

		// otherwise assume ipv4
		// 8th byte in IPv4 is TTL
		// LDABS requires ctx in R6
		asm.Mov.Reg(asm.R6, asm.R1),
		asm.LoadAbs(-0x100000+8, asm.Byte),
		asm.Ja.Label("store-ttl"),

		// 7th byte in IPv6 is Hop count
		// LDABS requires ctx in R6
		asm.Mov.Reg(asm.R6, asm.R1).Sym("ipv6"),
		asm.LoadAbs(-0x100000+7, asm.Byte),

		// stash the load result into FP[-4]
		asm.StoreMem(asm.RFP, -4, asm.R0, asm.Word).Sym("store-ttl"),
		// stash the &FP[-4] into r2
		asm.Mov.Reg(asm.R2, asm.RFP),
		asm.Add.Imm(asm.R2, -4),

		// r1 must point to map
		asm.LoadMapPtr(asm.R1, ttls.FD()),
		asm.MapLookupElement.Call(),

		// load ok? inc. Otherwise? jmp to mapupdate
		asm.JEq.Imm(asm.R0, 0, "update-map"),
		asm.Mov.Imm(asm.R1, 1),
		asm.XAdd(asm.R0, asm.R1, asm.DWord),
		asm.Ja.Label("exit"),

		// MapUpdate
		// r1 has map ptr
		asm.LoadMapPtr(asm.R1, ttls.FD()).Sym("update-map"),
		// r2 has key -> &FP[-4]
		asm.Mov.Reg(asm.R2, asm.RFP),
		asm.Add.Imm(asm.R2, -4),
		// r3 has value -> &FP[-16] , aka 1
		asm.StoreImm(asm.RFP, -16, 1, asm.DWord),
		asm.Mov.Reg(asm.R3, asm.RFP),
		asm.Add.Imm(asm.R3, -16),
		// r4 has flags, 0
		asm.Mov.Imm(asm.R4, 0),
		asm.MapUpdateElement.Call(),

		// set exit code to -1, don't trunc packet
		asm.Mov.Imm(asm.R0, -1).Sym("exit"),
		asm.Return(),
	}

	prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
		Name:         "distance_filter",
		Type:         ebpf.SocketFilter,
		License:      "GPL",
		Instructions: insns,
	})
	if err != nil {
		ttls.Close()
		return nil, nil, err
	}

	return prog, ttls, nil
}

func minDistance(TTLs *ebpf.Map) (int, error) {
	var (
		entries = TTLs.Iterate()
		ttl     uint32
		minDist uint32 = 255
		count   uint64
	)
	for entries.Next(&ttl, &count) {
		var dist uint32
		switch {
		case ttl > 128:
			dist = 255 - ttl
		case ttl > 64:
			dist = 128 - ttl
		case ttl > 32:
			dist = 64 - ttl
		default:
			dist = 32 - ttl
		}
		if minDist > dist {
			minDist = dist
		}
	}
	return int(minDist), entries.Err()
}
Output:

Example (SocketELF)

ExampleSocketELF demonstrates how to load an eBPF program from an ELF, pin it into the filesystem and attach it to a raw socket.

//go:build linux
// +build linux

package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"syscall"
	"time"

	"github.com/Gui774ume/ebpf"
)

var program = [...]byte{
	0177, 0105, 0114, 0106, 0002, 0001, 0001, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0001, 0000, 0367, 0000, 0001, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0340, 0001, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0100, 0000, 0000, 0000, 0000, 0000, 0100, 0000, 0010, 0000, 0001, 0000,
	0277, 0026, 0000, 0000, 0000, 0000, 0000, 0000, 0060, 0000, 0000, 0000, 0027, 0000, 0000, 0000,
	0143, 0012, 0374, 0377, 0000, 0000, 0000, 0000, 0141, 0141, 0004, 0000, 0000, 0000, 0000, 0000,
	0125, 0001, 0010, 0000, 0004, 0000, 0000, 0000, 0277, 0242, 0000, 0000, 0000, 0000, 0000, 0000,
	0007, 0002, 0000, 0000, 0374, 0377, 0377, 0377, 0030, 0001, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0205, 0000, 0000, 0000, 0001, 0000, 0000, 0000,
	0025, 0000, 0002, 0000, 0000, 0000, 0000, 0000, 0141, 0141, 0000, 0000, 0000, 0000, 0000, 0000,
	0333, 0020, 0000, 0000, 0000, 0000, 0000, 0000, 0267, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0225, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0002, 0000, 0000, 0000, 0004, 0000, 0000, 0000,
	0010, 0000, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0000, 0000, 0000, 0002, 0000, 0000, 0000,
	0004, 0000, 0000, 0000, 0010, 0000, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0000, 0000, 0000,
	0107, 0120, 0114, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0065, 0000, 0000, 0000, 0000, 0000, 0003, 0000, 0150, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0034, 0000, 0000, 0000, 0020, 0000, 0006, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0110, 0000, 0000, 0000, 0020, 0000, 0003, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0014, 0000, 0000, 0000, 0020, 0000, 0005, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0023, 0000, 0000, 0000, 0020, 0000, 0005, 0000, 0024, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0070, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0001, 0000, 0000, 0000, 0004, 0000, 0000, 0000, 0000, 0056, 0164, 0145, 0170, 0164, 0000, 0155,
	0141, 0160, 0163, 0000, 0155, 0171, 0137, 0155, 0141, 0160, 0000, 0164, 0145, 0163, 0164, 0137,
	0155, 0141, 0160, 0000, 0137, 0154, 0151, 0143, 0145, 0156, 0163, 0145, 0000, 0056, 0163, 0164,
	0162, 0164, 0141, 0142, 0000, 0056, 0163, 0171, 0155, 0164, 0141, 0142, 0000, 0114, 0102, 0102,
	0060, 0137, 0063, 0000, 0056, 0162, 0145, 0154, 0163, 0157, 0143, 0153, 0145, 0164, 0061, 0000,
	0142, 0160, 0146, 0137, 0160, 0162, 0157, 0147, 0061, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0045, 0000, 0000, 0000, 0003, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0210, 0001, 0000, 0000, 0000, 0000, 0000, 0000,
	0122, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0001, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0001, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0006, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0100, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0004, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0100, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0006, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0100, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0170, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0010, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0074, 0000, 0000, 0000, 0011, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0170, 0001, 0000, 0000, 0000, 0000, 0000, 0000,
	0020, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0007, 0000, 0000, 0000, 0003, 0000, 0000, 0000,
	0010, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0020, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0007, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0003, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0270, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0050, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0004, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0035, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0003, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0340, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0004, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0001, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0055, 0000, 0000, 0000, 0002, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0350, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
	0220, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0001, 0000, 0000, 0000, 0002, 0000, 0000, 0000,
	0010, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0030, 0000, 0000, 0000, 0000, 0000, 0000, 0000,
}

const sockexPin = "/sys/fs/bpf/sockex1"

// ExampleSocketELF demonstrates how to load an eBPF program from an ELF,
// pin it into the filesystem and attach it to a raw socket.
func main() {
	const SO_ATTACH_BPF = 50

	index := flag.Int("index", 0, "specify ethernet index")
	flag.Parse()
	fi, err := os.Lstat(sockexPin)
	if err != nil && !os.IsNotExist(err) {
		panic(err)
	}
	var coll *ebpf.Collection
	if fi != nil {
		coll, err = ebpf.LoadPinnedCollection(sockexPin)
		if err != nil {
			panic(err)
		}
	} else {
		spec, err := ebpf.LoadCollectionSpecFromReader(bytes.NewReader(program[:]))
		if err != nil {
			panic(err)
		}
		coll, err = ebpf.NewCollection(spec)
		if err != nil {
			panic(err)
		}
		err = coll.Pin(sockexPin, 0600)
		if err != nil {
			panic(err)
		}
	}
	defer coll.Close()

	sock, err := openRawSock(*index)
	if err != nil {
		panic(err)
	}
	defer syscall.Close(sock)

	prog := coll.DetachProgram("bpf_prog1")
	if prog == nil {
		panic("no program named bpf_prog1 found")
	}
	defer prog.Close()

	if err := syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, SO_ATTACH_BPF, prog.FD()); err != nil {
		panic(err)
	}

	fmt.Printf("Filtering on eth index: %d\n", *index)
	fmt.Println("Packet stats:")

	protoStats := coll.DetachMap("my_map")
	if protoStats == nil {
		panic(fmt.Errorf("no map named my_map found"))
	}
	defer protoStats.Close()

	for {
		const (
			ICMP = 0x01
			TCP  = 0x06
			UDP  = 0x11
		)

		time.Sleep(time.Second)
		var icmp uint64
		var tcp uint64
		var udp uint64
		ok, err := protoStats.Get(uint32(ICMP), &icmp)
		if err != nil {
			panic(err)
		}
		assertTrue(ok, "icmp key not found")
		ok, err = protoStats.Get(uint32(TCP), &tcp)
		if err != nil {
			panic(err)
		}
		assertTrue(ok, "tcp key not found")
		ok, err = protoStats.Get(uint32(UDP), &udp)
		if err != nil {
			panic(err)
		}
		assertTrue(ok, "udp key not found")
		fmt.Printf("\r\033[m\tICMP: %d TCP: %d UDP: %d", icmp, tcp, udp)
	}
}

func assertTrue(b bool, msg string) {
	if !b {
		panic(fmt.Errorf("%s", msg))
	}
}

func openRawSock(index int) (int, error) {
	const ETH_P_ALL uint16 = 0x00<<8 | 0x03
	sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, int(ETH_P_ALL))
	if err != nil {
		return 0, err
	}
	sll := syscall.SockaddrLinklayer{}
	sll.Protocol = ETH_P_ALL
	sll.Ifindex = index
	if err := syscall.Bind(sock, &sll); err != nil {
		return 0, err
	}
	return sock, nil
}
Output:

Index

Examples

Constants

View Source
const (
	// RecomputeCSUM SKBStoreBytes flags
	RecomputeCSUM = uint64(1)
	// FInvalidateHash SKBStoreBytes flags
	FInvalidateHash = uint64(1 << 1)

	// FHdrFieldMask CSUMReplaceL4 and CSUMReplaceL3 flags.
	// First 4 bits are for passing the header field size.
	FHdrFieldMask = uint64(0xF)

	// FPseudoHdr CSUMReplaceL4 flags
	FPseudoHdr = uint64(1 << 4)
	// FMarkMangled0 CSUMReplaceL4 flags
	FMarkMangled0 = uint64(1 << 5)
	// FMakrEnforce CSUMReplaceL4 flags
	FMakrEnforce = uint64(1 << 6)

	// FIngress CloneRedirect and Redirect flags
	FIngress = uint64(1)

	// FTunInfoIPV6 SKBSetTunnelKey and SKBGetTunnelKey flags
	FTunInfoIPV6 = uint(1)

	// FSkipFieldMask GetStackID flags
	FSkipFieldMask = uint64(0xff)
	// FUserStack GetStackID flags
	FUserStack = uint64(1 << 8)
	// FFastStackCMP GetStackID flags
	FFastStackCMP = uint64(1 << 9)
	// FReuseStackID GetStackID flags
	FReuseStackID = uint64(1 << 10)

	// FZeroCSUMTx SKBSetTunnelKey flag
	FZeroCSUMTX = uint64(1 << 1)
	// FZeroCSUMTx SKBSetTunnelKey flag
	FDontFragment = uint64(1 << 2)

	// FindIndexMask PerfEventOutput and PerfEventRead flags.
	FIndexMask = uint64(0xffffffff)
	// FCurrentCPU PerfEventOutput and PerfEventRead flags.
	FCurrentCPU = FIndexMask

	// FCtxLenMask PerfEventOutput for SKBuff input context.
	FCtxLenMask = uint64(0xfffff << 32)

	// AdjRoomNet Mode for SKBAdjustRoom helper.
	AdjRoomNet = 0
)

All flags used by eBPF helper functions

View Source
const DefaultVerifierLogSize = 64 * 1024

DefaultVerifierLogSize is the default number of bytes allocated for the verifier log.

Variables

View Source
var (
	ErrNotSupported = errors.New("ebpf: not supported by kernel")
)

Errors returned by the implementation

Functions

func CurrentKernelVersion

func CurrentKernelVersion() (uint32, error)

CurrentKernelVersion returns the current kernel version in LINUX_VERSION_CODE format (see KernelVersionFromReleaseString())

func IsUnreferencedSymbol

func IsUnreferencedSymbol(err error) bool

IsUnreferencedSymbol returns true if err was caused by an unreferenced symbol.

func KernelVersionFromReleaseString

func KernelVersionFromReleaseString(releaseString string) (uint32, error)

KernelVersionFromReleaseString converts a release string with format 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format. That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c)

func SanitizeName

func SanitizeName(name string, replacement rune) string

SanitizeName replaces all invalid characters in name.

Use this to automatically generate valid names for maps and programs at run time.

Passing a negative value for replacement will delete characters instead of replacing them.

Types

type AttachType

type AttachType uint32

AttachType of the eBPF program, needed to differentiate allowed context accesses in some newer program types like CGroupSockAddr. Should be set to AttachNone if not required. Will cause invalid argument (EINVAL) at program load time if set incorrectly.

const (
	AttachCGroupInetIngress AttachType = iota
	AttachCGroupInetEgress
	AttachCGroupInetSockCreate
	AttachCGroupSockOps
	AttachSkSKBStreamParser
	AttachSkSKBStreamVerdict
	AttachCGroupDevice
	AttachSkMsgVerdict
	AttachCGroupInet4Bind
	AttachCGroupInet6Bind
	AttachCGroupInet4Connect
	AttachCGroupInet6Connect
	AttachCGroupInet4PostBind
	AttachCGroupInet6PostBind
	AttachCGroupUDP4Sendmsg
	AttachCGroupUDP6Sendmsg
	AttachLircMode2
	AttachFlowDissector
	AttachCGroupSysctl
	AttachCGroupUDP4Recvmsg
	AttachCGroupUDP6Recvmsg
	AttachCGroupGetsockopt
	AttachCGroupSetsockopt
)
const AttachNone AttachType = 0

AttachNone is an alias for AttachCGroupInetIngress for readability reasons

type Collection

type Collection struct {
	Programs map[string]*Program
	Maps     map[string]*Map
}

Collection is a collection of Programs and Maps associated with their symbols

func LoadCollection

func LoadCollection(file string) (*Collection, error)

LoadCollection parses an object file and converts it to a collection.

func LoadPinnedCollection

func LoadPinnedCollection(dirName string) (*Collection, error)

LoadPinnedCollection loads a Collection from the pinned directory.

Requires at least Linux 4.13, use LoadPinnedCollectionExplicit on earlier versions.

func LoadPinnedCollectionExplicit

func LoadPinnedCollectionExplicit(dirName string, maps map[string]*MapABI, progs map[string]*ProgramABI) (*Collection, error)

LoadPinnedCollectionExplicit loads a Collection from the pinned directory with explicit parameters.

func NewCollection

func NewCollection(spec *CollectionSpec) (*Collection, error)

NewCollection creates a Collection from a specification.

Only maps referenced by at least one of the programs are initialized.

func NewCollectionWithOptions

func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error)

NewCollectionWithOptions creates a Collection from a specification.

Only maps referenced by at least one of the programs are initialized.

func (*Collection) AttachCgroupProgram

func (coll *Collection) AttachCgroupProgram(secName string, cgroupPath string) error

AttachCgroupProgram attaches a program to a cgroup

func (*Collection) Close

func (coll *Collection) Close() []error

Close frees all maps and programs associated with the collection.

The collection mustn't be used afterwards.

func (*Collection) DetachMap

func (coll *Collection) DetachMap(name string) *Map

DetachMap removes the named map from the Collection.

This means that a later call to Close() will not affect this map.

Returns nil if no map of that name exists.

func (*Collection) DetachProgram

func (coll *Collection) DetachProgram(name string) *Program

DetachProgram removes the named program from the Collection.

This means that a later call to Close() will not affect this program.

Returns nil if no program of that name exists.

func (*Collection) EnableKprobe

func (coll *Collection) EnableKprobe(secName string, maxactive int) error

EnableKprobe enables the kprobe selected by its section name.

For kretprobes, you can configure the maximum number of instances of the function that can be probed simultaneously with maxactive. If maxactive is 0 it will be set to the default value: if CONFIG_PREEMPT is enabled, this is max(10, 2*NR_CPUS); otherwise, it is NR_CPUS. For kprobes, maxactive is ignored.

func (*Collection) EnableKprobes

func (coll *Collection) EnableKprobes(maxactive int) error

EnableKprobes enables all kprobes/kretprobes included in the collection.

For kretprobes, you can configure the maximum number of instances of the function that can be probed simultaneously with maxactive. If maxactive is 0 it will be set to the default value: if CONFIG_PREEMPT is enabled, this is max(10, 2*NR_CPUS); otherwise, it is NR_CPUS. For kprobes, maxactive is ignored.

func (*Collection) EnableTracepoint

func (coll *Collection) EnableTracepoint(secName string) error

EnableTracepoint enables the tracepoint selected by its section name.

func (*Collection) EnableTracepoints

func (coll *Collection) EnableTracepoints() error

EnableTracepoints enables all tracepoints included in the collection.

func (*Collection) Pin

func (coll *Collection) Pin(dirName string, fileMode os.FileMode) error

Pin persits a Collection beyond the lifetime of the process that created it

This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional

type CollectionABI

type CollectionABI struct {
	Maps     map[string]*MapABI
	Programs map[string]*ProgramABI
}

CollectionABI describes the interface of an eBPF collection.

Example
abi := CollectionABI{
	Maps: map[string]*MapABI{
		"a": {
			Type: Array,
			// Members which aren't specified are not checked
		},
		// Use an empty ABI if you just want to make sure
		// something is present.
		"b": {},
	},
	Programs: map[string]*ProgramABI{
		"1": {Type: XDP},
	},
}

spec, err := LoadCollectionSpec("from-somewhere.elf")
if err != nil {
	panic(err)
}

// CheckSpec only makes sure that all entries of the ABI
// are present. It doesn't check whether the ABI is correct.
// See below for how to do that.
if err := abi.CheckSpec(spec); err != nil {
	panic(err)
}

coll, err := NewCollection(spec)
if err != nil {
	panic(err)
}

// Check finally compares the ABI and the collection, and
// makes sure that they match.
if err := abi.Check(coll); err != nil {
	panic(err)
}
Output:

func (*CollectionABI) Check

func (abi *CollectionABI) Check(coll *Collection) error

Check verifies that all items in a collection conform to this ABI.

func (*CollectionABI) CheckSpec

func (abi *CollectionABI) CheckSpec(cs *CollectionSpec) error

CheckSpec verifies that all maps and programs mentioned in the ABI are present in the spec.

type CollectionOptions

type CollectionOptions struct {
	Programs ProgramOptions
}

CollectionOptions control loading a collection into the kernel.

type CollectionSpec

type CollectionSpec struct {
	Maps     map[string]*MapSpec
	Programs map[string]*ProgramSpec
}

CollectionSpec describes a collection.

func LoadCollectionSpec

func LoadCollectionSpec(file string) (*CollectionSpec, error)

LoadCollectionSpec parse an object file and convert it to a collection

func LoadCollectionSpecFromReader

func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error)

LoadCollectionSpecFromReader parses an io.ReaderAt that represents an ELF layout into a CollectionSpec.

func (*CollectionSpec) Copy

func (cs *CollectionSpec) Copy() *CollectionSpec

Copy returns a recursive copy of the spec.

type Editor

type Editor struct {
	ReferenceOffsets map[string][]int
	// contains filtered or unexported fields
}

Editor modifies eBPF instructions.

Example (RewriteConstant)

ExampleEditor_rewriteConstant shows how to change constants in compiled eBPF byte code.

The C should look something like this:

#define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var))

int xdp() {
    bool my_constant;
    LOAD_CONSTANT("SYMBOL_NAME", my_constant);

    if (my_constant) ...
// This assembly is roughly equivalent to what clang
// would emit for the C above.
insns := asm.Instructions{
	asm.LoadImm(asm.R0, 0, asm.DWord),
	asm.Return(),
}

insns[0].Reference = "my_ret"

editor := Edit(&insns)
if err := editor.RewriteConstant("my_ret", 42); err != nil {
	panic(err)
}

fmt.Printf("%0.0s", insns)
Output:

0: LdImmDW dst: r0 imm: 42 <my_ret>
2: Exit

func Edit

func Edit(insns *asm.Instructions) *Editor

Edit creates a new Editor.

The editor retains a reference to insns and modifies its contents.

func (ed *Editor) Link(sections ...asm.Instructions) error

Link resolves bpf-to-bpf calls.

Each section may contain multiple functions / labels, and is only linked if the program being edited references one of these functions.

Sections must not require linking themselves.

func (*Editor) RewriteConstant

func (ed *Editor) RewriteConstant(symbol string, value uint64) error

RewriteConstant rewrites all loads of a symbol to a constant value.

This is a way to parameterize clang-compiled eBPF byte code at load time.

The following macro should be used to access the constant:

#define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var))

int xdp() {
    bool my_constant;
    LOAD_CONSTANT("SYMBOL_NAME", my_constant);

    if (my_constant) ...

Caveats:

  • The symbol name you pick must be unique

  • Failing to rewrite a symbol will not result in an error, 0 will be loaded instead (subject to change)

Use IsUnreferencedSymbol if you want to rewrite potentially unused symbols.

func (*Editor) RewriteMap

func (ed *Editor) RewriteMap(symbol string, m *Map) error

RewriteMap rewrites a symbol to point at a Map.

Use IsUnreferencedSymbol if you want to rewrite potentially unused maps.

type Map

type Map struct {
	// MapSpec - pointer to the MapSpec
	MapSpec *MapSpec
	// contains filtered or unexported fields
}

Map represents a Map file descriptor.

It is not safe to close a map which is used by other goroutines.

Methods which take interface{} arguments by default encode them using binary.Read/Write in the machine's native endianness.

Implement Marshaler on the arguments if you need custom encoding.

Example (PerCPU)

Per CPU maps store a distinct value for each CPU. They are useful to collect metrics.

arr, err := NewMap(&MapSpec{
	Type:       PerCPUArray,
	KeySize:    4,
	ValueSize:  4,
	MaxEntries: 2,
})
if err != nil {
	panic(err)
}

first := []uint32{4, 5}
if err := arr.Put(uint32(0), first); err != nil {
	panic(err)
}

second := []uint32{2, 8}
if err := arr.Put(uint32(1), second); err != nil {
	panic(err)
}

var values []uint32
if ok, err := arr.Get(uint32(0), &values); err != nil {
	panic(err)
} else if !ok {
	panic("item 0 not found")
}

fmt.Println("First two values:", values[:2])

var (
	key     uint32
	entries = arr.Iterate()
)

for entries.Next(&key, &values) {
	// NB: sum can overflow, real code should check for this
	var sum uint32
	for _, n := range values {
		sum += n
	}
	fmt.Printf("Sum of %d: %d\n", key, sum)
}

if err := entries.Err(); err != nil {
	panic(err)
}
Output:

Example (ZeroCopy)

It is possible to use unsafe.Pointer to avoid marshalling and copy overhead. It is the resposibility of the caller to ensure the correct size of unsafe.Pointers.

Note that using unsafe.Pointer is only marginally faster than implementing Marshaler on the type.

hash := createHash()
defer hash.Close()

key := [5]byte{'h', 'e', 'l', 'l', 'o'}
value := uint32(23)

if err := hash.Put(unsafe.Pointer(&key), unsafe.Pointer(&value)); err != nil {
	panic(err)
}

value = 0
if ok, err := hash.Get(unsafe.Pointer(&key), unsafe.Pointer(&value)); !ok || err != nil {
	panic("can't get value:" + err.Error())
}

fmt.Printf("The value is: %d\n", value)
Output:

The value is: 23

func LoadPinnedMap

func LoadPinnedMap(fileName string) (*Map, error)

LoadPinnedMap load a Map from a BPF file.

Requires at least Linux 4.13, and is not compatible with nested maps. Use LoadPinnedMapExplicit in these situations.

func LoadPinnedMapExplicit

func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error)

LoadPinnedMapExplicit loads a map with explicit parameters.

func NewMap

func NewMap(spec *MapSpec) (*Map, error)

NewMap creates a new Map.

Creating a map for the first time will perform feature detection by creating small, temporary maps.

func (*Map) ABI

func (m *Map) ABI() MapABI

ABI gets the ABI of the Map

func (*Map) Clone

func (m *Map) Clone() (*Map, error)

Clone creates a duplicate of the Map.

Closing the duplicate does not affect the original, and vice versa. Changes made to the map are reflected by both instances however.

Cloning a nil Map returns nil.

func (*Map) Close

func (m *Map) Close() error

Close removes a Map

func (*Map) Create

func (m *Map) Create(key, value interface{}) error

Create creates a new value in a map, failing if the key exists already

func (*Map) Delete

func (m *Map) Delete(key interface{}) error

Delete removes a value.

Use DeleteStrict if you desire an error if key does not exist.

func (*Map) DeleteStrict

func (m *Map) DeleteStrict(key interface{}) error

DeleteStrict removes a key and returns an error if the key doesn't exist.

func (*Map) FD

func (m *Map) FD() int

FD gets the file descriptor of the Map.

Calling this function is invalid after Close has been called.

func (*Map) Get

func (m *Map) Get(key, valueOut interface{}) (bool, error)

Get retrieves a value from a Map.

Calls Close() on valueOut if it is of type **Map or **Program, and *valueOut is not nil.

func (*Map) GetBytes

func (m *Map) GetBytes(key interface{}) ([]byte, error)

GetBytes gets a value from Map

func (*Map) Iterate

func (m *Map) Iterate() *MapIterator

Iterate traverses a map.

It's safe to create multiple iterators at the same time.

It's not possible to guarantee that all keys in a map will be returned if there are concurrent modifications to the map.

Example

ExampleMap_Iterate demonstrates how to iterate over all entries in a map.

hash := createHash()
defer hash.Close()

if err := hash.Put("hello", uint32(21)); err != nil {
	panic(err)
}

if err := hash.Put("world", uint32(42)); err != nil {
	panic(err)
}

var (
	key     string
	value   uint32
	entries = hash.Iterate()
)

for entries.Next(&key, &value) {
	// Order of keys is non-deterministic due to randomized map seed
	fmt.Printf("key: %s, value: %d\n", key, value)
}

if err := entries.Err(); err != nil {
	panic(fmt.Sprint("Iterator encountered an error:", err))
}
Output:

Example (NestedMapsAndProgramArrays)

It is possible to iterate nested maps and program arrays by unmarshaling into a *Map or *Program.

var arrayOfMaps *Map // Set this up somehow

var (
	key     uint32
	m       *Map
	entries = arrayOfMaps.Iterate()
)

// Make sure that the iterated map is closed after
// we are done.
defer m.Close()

for entries.Next(&key, &m) {
	// Order of keys is non-deterministic due to randomized map seed
	fmt.Printf("key: %v, map: %v\n", key, m)
}

if err := entries.Err(); err != nil {
	panic(fmt.Sprint("Iterator encountered an error:", err))
}
Output:

func (*Map) MarshalBinary

func (m *Map) MarshalBinary() ([]byte, error)

MarshalBinary implements BinaryMarshaler.

func (*Map) NextKey

func (m *Map) NextKey(key, nextKeyOut interface{}) (bool, error)

NextKey finds the key following an initial key.

See NextKeyBytes for details.

Example
hash := createHash()
defer hash.Close()

if err := hash.Put("hello", uint32(21)); err != nil {
	panic(err)
}

if err := hash.Put("world", uint32(42)); err != nil {
	panic(err)
}

var firstKey string
if ok, err := hash.NextKey(nil, &firstKey); err != nil {
	panic(err)
} else if !ok {
	panic("map is empty")
}

var nextKey string
if ok, err := hash.NextKey(firstKey, &nextKey); err != nil {
	panic(err)
} else if !ok {
	panic("no keys after " + firstKey)
}

// Order of keys is non-deterministic due to randomized map seed
Output:

func (*Map) NextKeyBytes

func (m *Map) NextKeyBytes(key interface{}) ([]byte, error)

NextKeyBytes returns the key following an initial key as a byte slice.

Passing nil will return the first key.

Use Iterate if you want to traverse all entries in the map.

func (*Map) Pin

func (m *Map) Pin(fileName string) error

Pin persists the map past the lifetime of the process that created it.

This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional

func (*Map) Put

func (m *Map) Put(key, value interface{}) error

Put replaces or creates a value in map

func (*Map) Replace

func (m *Map) Replace(key, value interface{}) error

Replace replaces a value in a map, failing if the value did not exist

func (*Map) String

func (m *Map) String() string

type MapABI

type MapABI struct {
	Type       MapType
	KeySize    uint32
	ValueSize  uint32
	MaxEntries uint32
	InnerMap   *MapABI
}

MapABI describes a Map.

Members which have the zero value of their type are not checked.

func (*MapABI) Check

func (abi *MapABI) Check(m *Map) error

Check verifies that a Map conforms to the ABI.

type MapIterator

type MapIterator struct {
	// contains filtered or unexported fields
}

MapIterator iterates a Map.

See Map.Iterate.

func (*MapIterator) Err

func (mi *MapIterator) Err() error

Err returns any encountered error.

The method must be called after Next returns nil.

func (*MapIterator) Next

func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool

Next decodes the next key and value.

Returns false if there are no more entries.

See Map.Get for further caveats around valueOut.

type MapSpec

type MapSpec struct {
	// Name is passed to the kernel as a debug aid. Must only contain
	// alpha numeric and '_' characters.
	Name       string
	Type       MapType
	KeySize    uint32
	ValueSize  uint32
	MaxEntries uint32
	Flags      uint32
	// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
	InnerMap *MapSpec
}

MapSpec defines a Map.

func (*MapSpec) Copy

func (ms *MapSpec) Copy() *MapSpec

Copy returns a copy of the spec.

func (*MapSpec) String

func (ms *MapSpec) String() string

type MapType

type MapType uint32

MapType indicates the type map structure that will be initialized in the kernel.

const (
	UnspecifiedMap MapType = iota
	// Hash is a hash map
	Hash
	// Array is an array map
	Array
	// ProgramArray - A program array map is a special kind of array map whose map
	// values contain only file descriptors referring to other eBPF
	// programs.  Thus, both the key_size and value_size must be
	// exactly four bytes.  This map is used in conjunction with the
	// TailCall helper.
	ProgramArray
	// PerfEventArray - A perf event array is used in conjunction with PerfEventRead
	// and PerfEventOutput calls, to read the raw bpf_perf_data from the registers.
	PerfEventArray
	// PerCPUHash - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	PerCPUHash
	// PerCPUArray - This data structure is useful for people who have high performance
	// network needs and can reconcile adds at the end of some cycle, so that
	// hashes can be lock free without the use of XAdd, which can be costly.
	// Each CPU gets a copy of this hash, the contents of all of which can be reconciled
	// later.
	PerCPUArray
	// StackTrace - This holds whole user and kernel stack traces, it can be retrieved with
	// GetStackID
	StackTrace
	// CGroupArray - This is a very niche structure used to help SKBInCGroup determine
	// if an skb is from a socket belonging to a specific cgroup
	CGroupArray
	// LRUHash - This allows you to create a small hash structure that will purge the
	// least recently used items rather than thow an error when you run out of memory
	LRUHash
	// LRUCPUHash - This is NOT like PerCPUHash, this structure is shared among the CPUs,
	// it has more to do with including the CPU id with the LRU calculation so that if a
	// particular CPU is using a value over-and-over again, then it will be saved, but if
	// a value is being retrieved a lot but sparsely across CPUs it is not as important, basically
	// giving weight to CPU locality over overall usage.
	LRUCPUHash
	// LPMTrie - This is an implementation of Longest-Prefix-Match Trie structure. It is useful,
	// for storing things like IP addresses which can be bit masked allowing for keys of differing
	// values to refer to the same reference based on their masks. See wikipedia for more details.
	LPMTrie
	// ArrayOfMaps - Each item in the array is another map. The inner map mustn't be a map of maps
	// itself.
	ArrayOfMaps
	// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps
	// itself.
	HashOfMaps
)

All the various map types that can be created

func (MapType) String

func (i MapType) String() string

type Marshaler

type Marshaler interface {
	encoding.BinaryMarshaler
	encoding.BinaryUnmarshaler
}

Marshaler allows controlling the binary representation used for getting and setting keys on a map.

Example

ExampleMarshaler shows how to use custom encoding with map methods.

package main

import (
	"fmt"
	"strings"
)

// Assert that customEncoding implements the correct interfaces.
var _ Marshaler = (*customEncoding)(nil)

type customEncoding struct {
	data string
}

func (ce *customEncoding) MarshalBinary() ([]byte, error) {
	return []byte(strings.ToUpper(ce.data)), nil
}

func (ce *customEncoding) UnmarshalBinary(buf []byte) error {
	ce.data = string(buf)
	return nil
}

// ExampleMarshaler shows how to use custom encoding with map methods.
func main() {
	hash := createHash()
	defer hash.Close()

	if err := hash.Put(&customEncoding{"hello"}, uint32(111)); err != nil {
		panic(err)
	}

	var (
		key     customEncoding
		value   uint32
		entries = hash.Iterate()
	)

	for entries.Next(&key, &value) {
		fmt.Printf("key: %s, value: %d\n", key.data, value)
	}

	if err := entries.Err(); err != nil {
		panic(err)
	}

}
Output:

key: HELLO, value: 111

type PerfReader

type PerfReader struct {

	// Error receives a write if the reader exits
	// due to an error.
	Error <-chan error

	// Samples is closed when the Reader exits.
	Samples <-chan *PerfSample

	// LostRecords is closed when the Reader exists.
	LostRecords <-chan uint64
	// contains filtered or unexported fields
}

PerfReader allows reading bpf_perf_event_output from user space.

Example

ExamplePerfReader submits a perf event using BPF, and then reads it in user space.

The BPF will look something like this:

struct map events __section("maps") = {
  .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
};

__section("xdp") int output_single(void *ctx) {
  unsigned char buf[] = {
    1, 2, 3, 4, 5
  };

   return perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &buf[0], 5);
 }

Also see BPF_F_CTXLEN_MASK if you want to sample packet data from SKB or XDP programs.

coll, err := LoadCollection("testdata/perf_output.elf")
if err != nil {
	panic(err)
}
defer coll.Close()

rd, err := NewPerfReader(PerfReaderOptions{
	Map:          coll.DetachMap("events"),
	PerCPUBuffer: 4096,
	// Notify immediately
	Watermark: 1,
})
if err != nil {
	panic(err)
}
defer rd.Close()

prog := coll.DetachProgram("output_single")
defer prog.Close()

ret, _, err := prog.Test(make([]byte, 14))
if err != nil {
	panic(err)
}

if ret != 0 {
	panic("expected 0 return value")
}

select {
case sample := <-rd.Samples:
	// Data is padded with 0 for alignment
	fmt.Println("Sample:", sample.Data)
case err := <-rd.Error:
	panic(err)
}
Output:

Sample: [1 2 3 4 5 0 0 0 0 0 0 0]

func NewPerfReader

func NewPerfReader(opts PerfReaderOptions) (out *PerfReader, err error)

NewPerfReader creates a new reader with the given options.

The value returned by LostSamples() will increase if the buffer isn't large enough to contain all incoming samples.

func (*PerfReader) Close

func (pr *PerfReader) Close() (err error)

Close stops the reader, discarding any samples not yet written to 'Samples'.

Calls to perf_event_output from eBPF programs will return ENOENT after calling this method.

func (*PerfReader) FlushAndClose

func (pr *PerfReader) FlushAndClose() error

FlushAndClose stops the reader, flushing any samples to 'Samples'. Will block if no consumer reads from 'Samples'.

Calls to perf_event_output from eBPF programs will return ENOENT after calling this method.

func (*PerfReader) LostSamples

func (pr *PerfReader) LostSamples() uint64

LostSamples returns the number of samples dropped by the perf subsystem.

type PerfReaderOptions

type PerfReaderOptions struct {
	// A map of type PerfEventArray. The reader takes ownership of the
	// map and takes care of closing it.
	Map *Map
	// Controls the size of the per CPU buffer in bytes. LostSamples() will
	// increase if the buffer is too small.
	PerCPUBuffer int
	// The reader will start processing samples once the per CPU buffer
	// exceeds this value. Must be smaller than PerCPUBuffer.
	Watermark int
	// Size of the channel used to retrieve the events from the kernel.
	// The default and minimum size is the number of CPUs.
	UserSpaceChanSize int
}

PerfReaderOptions control the behaviour of the user space reader.

type PerfSample

type PerfSample struct {
	// Data are padded with 0 to have a 64-bit alignment.
	// If you are using variable length samples you need to take
	// this into account.
	Data []byte
}

PerfSample is read from the kernel by PerfReader.

type ProgType

type ProgType uint32

ProgType of the eBPF program

const (
	// Unrecognized program type
	Unrecognized ProgType = iota
	// SocketFilter socket or seccomp filter
	SocketFilter
	// Kprobe program
	Kprobe
	// SchedCLS traffic control shaper
	SchedCLS
	// SchedACT routing control shaper
	SchedACT
	// TracePoint program
	TracePoint
	// XDP program
	XDP
	// PerfEvent program
	PerfEvent
	// CGroupSKB program
	CGroupSKB
	// CGroupSock program
	CGroupSock
	// LWTIn program
	LWTIn
	// LWTOut program
	LWTOut
	// LWTXmit program
	LWTXmit
	// SockOps program
	SockOps
	// SkSKB program
	SkSKB
	// CGroupDevice program
	CGroupDevice
	// SkMsg program
	SkMsg
	// RawTracepoint program
	RawTracepoint
	// CGroupSockAddr program
	CGroupSockAddr
	// LWTSeg6Local program
	LWTSeg6Local
	// LircMode2 program
	LircMode2
	// SkReuseport program
	SkReuseport
	// FlowDissector program
	FlowDissector
	// CGroupSysctl program
	CGroupSysctl
	// RawTracepointWritable program
	RawTracepointWritable
	// CGroupSockopt program
	CGroupSockopt
)

eBPF program types

func (ProgType) String

func (i ProgType) String() string

type Program

type Program struct {
	// Contains the output of the kernel verifier if enabled,
	// otherwise it is empty.
	VerifierLog string
	// ProgramSpec - Pointer to the ProgramSpec
	ProgramSpec *ProgramSpec
	// contains filtered or unexported fields
}

Program represents BPF program loaded into the kernel.

It is not safe to close a Program which is used by other goroutines.

Example (UnmarshalFromMap)

It's possible to read a program directly from a ProgramArray.

progArray, err := LoadPinnedMap("/path/to/map")
if err != nil {
	panic(err)
}
defer progArray.Close()

// Load a single program
var prog *Program
if ok, err := progArray.Get(uint32(0), &prog); !ok {
	panic("key not found")
} else if err != nil {
	panic(err)
}
defer prog.Close()

fmt.Println("first prog:", prog)

// Iterate all programs
var (
	key     uint32
	entries = progArray.Iterate()
)

for entries.Next(&key, &prog) {
	fmt.Println(key, "is", prog)
}

if err := entries.Err(); err != nil {
	panic(err)
}
Output:

func LoadPinnedProgram

func LoadPinnedProgram(fileName string) (*Program, error)

LoadPinnedProgram loads a Program from a BPF file.

Requires at least Linux 4.13, use LoadPinnedProgramExplicit on earlier versions.

func LoadPinnedProgramExplicit

func LoadPinnedProgramExplicit(fileName string, abi *ProgramABI) (*Program, error)

LoadPinnedProgramExplicit loads a program with explicit parameters.

func NewProgram

func NewProgram(spec *ProgramSpec) (*Program, error)

NewProgram creates a new Program.

Loading a program for the first time will perform feature detection by loading small, temporary programs.

func NewProgramWithOptions

func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error)

NewProgramWithOptions creates a new Program.

Loading a program for the first time will perform feature detection by loading small, temporary programs.

Example

Use NewProgramWithOptions if you'd like to get the verifier output for a program, or if you want to change the buffer size used when generating error messages.

spec := &ProgramSpec{
	Type: SocketFilter,
	Instructions: asm.Instructions{
		asm.LoadImm(asm.R0, 0, asm.DWord),
		asm.Return(),
	},
	License: "MIT",
}

prog, err := NewProgramWithOptions(spec, ProgramOptions{
	LogLevel: 2,
	LogSize:  1024,
})
if err != nil {
	panic(err)
}
defer prog.Close()

fmt.Println("The verifier output is:")
fmt.Println(prog.VerifierLog)
Output:

func (*Program) ABI

func (bpf *Program) ABI() ProgramABI

ABI gets the ABI of the Program

func (*Program) AttachCgroup

func (bpf *Program) AttachCgroup(cgroupPath string) error

AttachCgroup attaches the program to a cgroup

func (*Program) Benchmark

func (bpf *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error)

Benchmark runs the Program with the given input for a number of times and returns the time taken per iteration.

The returned value is the return value of the last execution of the program.

This function requires at least Linux 4.12.

func (*Program) Clone

func (bpf *Program) Clone() (*Program, error)

Clone creates a duplicate of the Program.

Closing the duplicate does not affect the original, and vice versa.

Cloning a nil Program returns nil.

func (*Program) Close

func (bpf *Program) Close() error

Close unloads the program from the kernel.

func (*Program) EnableKprobe

func (bpf *Program) EnableKprobe(maxactive int) error

EnableKprobe enables the program if it is a kprobe.

For kretprobes, you can configure the maximum number of instances of the function that can be probed simultaneously with maxactive. If maxactive is 0 it will be set to the default value: if CONFIG_PREEMPT is enabled, this is max(10, 2*NR_CPUS); otherwise, it is NR_CPUS. For kprobes, maxactive is ignored.

func (*Program) EnableTracepoint

func (bpf *Program) EnableTracepoint() error

EnableTracepoint enables the program if it is a tracepoint.

func (*Program) FD

func (bpf *Program) FD() int

FD gets the file descriptor of the Program.

It is invalid to call this function after Close has been called.

func (*Program) IsCgroupProgram

func (bpf *Program) IsCgroupProgram() bool

IsCgroupProgram returns true if the program is a cgroup program

func (*Program) IsKProbe

func (bpf *Program) IsKProbe() bool

IsKProbe returns true if the program is a kprobe

func (*Program) IsKRetProbe

func (bpf *Program) IsKRetProbe() bool

IsKRetProbe returns true if the program is a kretprobe

func (*Program) IsUProbe

func (bpf *Program) IsUProbe() bool

IsUProbe returns true if the program is a uprobe

func (*Program) MarshalBinary

func (bpf *Program) MarshalBinary() ([]byte, error)

MarshalBinary implements BinaryMarshaler.

func (*Program) Pin

func (bpf *Program) Pin(fileName string) error

Pin persists the Program past the lifetime of the process that created it

This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional

func (*Program) String

func (bpf *Program) String() string

func (*Program) Test

func (bpf *Program) Test(in []byte) (uint32, []byte, error)

Test runs the Program in the kernel with the given input and returns the value returned by the eBPF program. outLen may be zero.

Note: the kernel expects at least 14 bytes input for an ethernet header for XDP and SKB programs.

This function requires at least Linux 4.12.

type ProgramABI

type ProgramABI struct {
	Type ProgType
}

ProgramABI describes a Program.

Members which have the zero value of their type are not checked.

func (*ProgramABI) Check

func (abi *ProgramABI) Check(prog *Program) error

Check verifies that a Program conforms to the ABI.

type ProgramOptions

type ProgramOptions struct {
	// Controls the detail emitted by the kernel verifier. Set to non-zero
	// to enable logging.
	LogLevel uint32
	// Controls the output buffer size for the verifier. Defaults to
	// DefaultVerifierLogSize.
	LogSize int
}

ProgramOptions control loading a program into the kernel.

type ProgramSpec

type ProgramSpec struct {
	// Name is passed to the kernel as a debug aid. Must only contain
	// alpha numeric and '_' characters.
	Name          string
	SectionName   string
	Type          ProgType
	AttachType    AttachType
	Instructions  asm.Instructions
	License       string
	KernelVersion uint32
}

ProgramSpec defines a Program

func (*ProgramSpec) Copy

func (ps *ProgramSpec) Copy() *ProgramSpec

Copy returns a copy of the spec.

Directories

Path Synopsis
Package asm is an assembler for eBPF bytecode.
Package asm is an assembler for eBPF bytecode.
cmd
ebpf-dump
Program ebpf-dump writes the contents of an ELF file to stdout.
Program ebpf-dump writes the contents of an ELF file to stdout.
ebpf-test
Program ebpf-test allows testing eBPF from an ELF file.
Program ebpf-test allows testing eBPF from an ELF file.
examples

Jump to

Keyboard shortcuts

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