├── .gitignore ├── Dockerfile ├── Gopkg.lock ├── Gopkg.toml ├── Makefile ├── README.md ├── Vagrantfile ├── bpf ├── Dockerfile ├── Makefile ├── bpf_sockmap.c └── include │ ├── README.md │ ├── bpf.h │ ├── bpf_helpers.h │ └── bpf_map.h ├── cmd └── sockmap │ └── main.go ├── pkg └── sockmap │ ├── .gitignore │ └── sockmap.go ├── vagrant ├── README.md └── setup.sh └── vendor └── github.com ├── dippynark └── gobpf │ ├── COPYRIGHT.txt │ ├── LICENSE-bpf.txt │ ├── LICENSE.txt │ ├── bcc │ ├── module.go │ ├── perf.go │ ├── symbol.go │ └── table.go │ ├── bpf.go │ ├── bpf_test.go │ ├── elf │ ├── compat.go │ ├── compat_test.go │ ├── elf.go │ ├── elf_test.go │ ├── elf_unsupported.go │ ├── include │ │ ├── bpf.h │ │ └── bpf_map.h │ ├── kernel_version.go │ ├── kernel_version_test.go │ ├── module.go │ ├── module_unsupported.go │ ├── perf.go │ ├── perf_unsupported.go │ ├── pinning.go │ ├── table.go │ ├── utsname_int8.go │ └── utsname_uint8.go │ ├── examples │ ├── bcc │ │ ├── bash_readline │ │ │ └── bash_readline.go │ │ ├── execsnoop │ │ │ ├── execsnoop.go │ │ │ └── output.go │ │ ├── perf │ │ │ └── perf.go │ │ ├── strlen_count │ │ │ └── strlen_count.go │ │ └── xdp │ │ │ └── xdp_drop.go │ └── tracepipe │ │ └── tracepipe.go │ ├── pkg │ ├── bpffs │ │ └── fs.go │ ├── cpuonline │ │ ├── cpu_range.go │ │ └── cpu_range_test.go │ ├── ksym │ │ ├── ksym.go │ │ └── ksym_test.go │ ├── progtestrun │ │ └── prog_test_run.go │ └── tracepipe │ │ ├── trace_pipe.go │ │ └── trace_pipe_test.go │ └── tests │ └── dummy.c └── iovisor └── gobpf ├── COPYRIGHT.txt ├── LICENSE-bpf.txt ├── LICENSE.txt ├── bcc ├── module.go ├── perf.go ├── symbol.go └── table.go ├── bpf.go ├── bpf_test.go ├── elf ├── compat.go ├── compat_test.go ├── elf.go ├── elf_test.go ├── elf_unsupported.go ├── include │ ├── bpf.h │ └── bpf_map.h ├── kernel_version.go ├── kernel_version_test.go ├── module.go ├── module_unsupported.go ├── perf.go ├── perf_unsupported.go ├── pinning.go ├── table.go ├── utsname_int8.go └── utsname_uint8.go ├── examples ├── bcc │ ├── bash_readline │ │ └── bash_readline.go │ ├── execsnoop │ │ ├── execsnoop.go │ │ └── output.go │ ├── perf │ │ └── perf.go │ ├── strlen_count │ │ └── strlen_count.go │ └── xdp │ │ └── xdp_drop.go └── tracepipe │ └── tracepipe.go ├── pkg ├── bpffs │ └── fs.go ├── cpuonline │ ├── cpu_range.go │ └── cpu_range_test.go ├── ksym │ ├── ksym.go │ └── ksym_test.go ├── progtestrun │ └── prog_test_run.go └── tracepipe │ ├── trace_pipe.go │ └── trace_pipe_test.go └── tests └── dummy.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .vagrant 3 | bpf_sockmap.go 4 | bpf_sockmap.o 5 | *-console.log -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the sockmap binary 2 | FROM golang:1.12.1 as builder 3 | 4 | # Copy in the go src 5 | WORKDIR /go/src/github.com/dippynark/bpf-sockmap 6 | COPY pkg/ pkg/ 7 | COPY cmd/ cmd/ 8 | COPY vendor/ vendor/ 9 | 10 | # Build 11 | # TODO: statically compile CGO_ENABLED=0 12 | RUN GOOS=linux GOARCH=amd64 go build -tags netgo -a -o sockmap github.com/dippynark/bpf-sockmap/cmd/sockmap 13 | 14 | # Copy the sockmap binary into a thin image 15 | FROM frolvlad/alpine-glibc 16 | WORKDIR / 17 | COPY --from=builder /go/src/github.com/dippynark/bpf-sockmap/sockmap . 18 | ENTRYPOINT ["/sockmap"] 19 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "177-add-sockmap-support" 6 | digest = "1:06041960f4f7c786550ea43bc75ada92ac12c1df36776154a327f31cd79772a9" 7 | name = "github.com/dippynark/gobpf" 8 | packages = ["elf"] 9 | pruneopts = "N" 10 | revision = "44541a4f6c8eada7b8682a505707946f19e2acde" 11 | 12 | [[projects]] 13 | branch = "master" 14 | digest = "1:5de9833d72874102ec6c4a29fd1499d7564517f2a2ee522b4e180fd3983051f7" 15 | name = "github.com/iovisor/gobpf" 16 | packages = [ 17 | "pkg/bpffs", 18 | "pkg/cpuonline", 19 | ] 20 | pruneopts = "N" 21 | revision = "e0d8d785d368abfb47287693c4daa1c760e2b558" 22 | 23 | [solve-meta] 24 | analyzer-name = "dep" 25 | analyzer-version = 1 26 | input-imports = ["github.com/dippynark/gobpf/elf"] 27 | solver-name = "gps-cdcl" 28 | solver-version = 1 29 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | #[[constraint]] 28 | # branch = "master" 29 | # name = "github.com/iovisor/gobpf" 30 | 31 | # using fork until https://github.com/iovisor/gobpf/pull/179 has merged 32 | [[constraint]] 33 | branch = "177-add-sockmap-support" 34 | name = "github.com/dippynark/gobpf" 35 | 36 | [prune] 37 | non-go = true 38 | 39 | [[prune.project]] 40 | #name = "github.com/iovisor/gobpf" 41 | name = "github.com/dippynark/gobpf" -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOOS := linux 2 | GOARCH := amd64 3 | GOLDFLAGS := -ldflags 4 | 5 | BPF_DOCKERFILE ?= bpf/Dockerfile 6 | REGISTRY ?= dippynark 7 | IMAGE ?= bpf-sockmap 8 | TAG ?= $(shell uname -r) 9 | 10 | DEBUG=1 11 | 12 | # If you can use docker without being root, you can do "make SUDO=" 13 | SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E") 14 | 15 | build: bpf docker_build 16 | 17 | run: 18 | $(SUDO) docker run -it --privileged --net=host ${REGISTRY}/${IMAGE}:${TAG} 19 | 20 | docker_build: 21 | $(SUDO) docker build -t ${REGISTRY}/${IMAGE}:${TAG} . 22 | 23 | docker_push: 24 | $(SUDO) docker push ${REGISTRY}/${IMAGE}:${TAG} 25 | 26 | bpf: docker_build_bpf install_bpf 27 | 28 | docker_build_bpf: docker_build_image 29 | $(SUDO) docker run --rm -e DEBUG=$(DEBUG) \ 30 | -v $(CURDIR):/src:ro \ 31 | -v $(CURDIR)/bpf:/dist/ \ 32 | -v /usr/src:/usr/src \ 33 | --workdir=/src/bpf \ 34 | $(REGISTRY)/bpf-builder \ 35 | make assets 36 | 37 | docker_build_image: 38 | $(SUDO) docker build -t $(REGISTRY)/bpf-builder -f $(BPF_DOCKERFILE) . 39 | 40 | install_bpf: 41 | mkdir -p pkg/sockmap/include 42 | cp -a bpf/include/*.h pkg/sockmap/include 43 | cp -a bpf/*.go pkg/sockmap 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bpf-sockmap 2 | 3 | bpf-sockmap uses [BPF_PROG_TYPE_SK_SKB](https://lwn.net/Articles/731133/) BPF programs to create a simple telnet echo server. It is heavily inspired by the [Cloudflare blog](https://blog.cloudflare.com/sockmap-tcp-splicing-of-the-future/). 4 | 5 | ## Quickstart 6 | 7 | [Vagrant](https://www.vagrantup.com/) can be used to spin up a virtual environment to test the BPF programs. The environment depends on [VirtualBox](https://www.virtualbox.org/wiki/Downloads) but other [providers](https://www.vagrantup.com/docs/providers/) exist. 8 | 9 | ``` 10 | $ vagrant plugin install vagrant-reload 11 | $ vagrant box list | grep ubuntu/bionic64 || vagrant box add ubuntu/bionic64 12 | $ vagrant up 13 | $ vagrant ssh 14 | # we are assuming commands are run from within the vagrant vm from here 15 | $ cd /vagrant 16 | $ make build 17 | $ make run 18 | ... 19 | 2019/04/03 00:53:12 listening on address: 0.0.0.0:12345 20 | # in another terminal watch debug output 21 | $ sudo cat /sys/kernel/debug/tracing/trace_pipe 22 | # in yet another terminal start a telnet session 23 | $ telnet 127.0.0.1 12345 24 | Trying 127.0.0.1... 25 | Connected to 127.0.0.1. 26 | Escape character is '^]'. 27 | Hello! 28 | Hello! 29 | Bye 30 | Bye 31 | ^]q 32 | 33 | telnet> q 34 | Connection closed. 35 | ``` 36 | 37 | ## Debug 38 | 39 | The generated object file can be inspected using `llvm-objdump` 40 | 41 | ``` 42 | llvm-objdump -S ./bpf/bpf_sockmap.o 43 | ``` 44 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | ['vagrant-reload'].each do |plugin| 2 | unless Vagrant.has_plugin?(plugin) 3 | raise "Vagrant plugin #{plugin} is not installed!" 4 | end 5 | end 6 | 7 | Vagrant.configure('2') do |config| 8 | config.vm.box = "ubuntu/bionic64" # Ubuntu 18.04 9 | config.vm.network "private_network", type: "dhcp" 10 | 11 | # fix issues with slow dns http://serverfault.com/a/595010 12 | config.vm.provider :virtualbox do |vb, override| 13 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] 14 | vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"] 15 | vb.customize ["modifyvm", :id, "--memory", "2048"] 16 | vb.customize ["modifyvm", :id, "--cpus", 2] 17 | end 18 | 19 | config.vm.provision :shell, :privileged => true, :path => "vagrant/setup.sh" 20 | config.vm.provision :shell, :privileged => true, :inline => "/usr/sbin/usermod -aG docker vagrant" 21 | config.vm.provision :reload 22 | end 23 | 24 | -------------------------------------------------------------------------------- /bpf/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV GOPATH /go 4 | 5 | RUN apt-get update && apt-get install -y \ 6 | llvm \ 7 | clang \ 8 | git \ 9 | golang \ 10 | linux-headers-$(uname -r) 11 | 12 | RUN mkdir -p /src /go 13 | 14 | RUN go get -u github.com/jteeuwen/go-bindata/... && \ 15 | mv $GOPATH/bin/go-bindata /usr/local/bin 16 | -------------------------------------------------------------------------------- /bpf/Makefile: -------------------------------------------------------------------------------- 1 | LINUX_HEADERS=$(shell uname -r | awk '{print "/usr/src/linux-headers-"$$1}') 2 | DEST_DIR?=/dist 3 | 4 | ASSETS = bpf_sockmap.go 5 | 6 | CLANG ?= clang 7 | CLANG_FLAGS := -D__KERNEL__ -D__ASM_SYSREG_H \ 8 | -D__NR_CPUS__=$(shell nproc) \ 9 | -Wno-unused-value \ 10 | -Wno-pointer-sign \ 11 | -Wno-compare-distinct-pointer-types \ 12 | -Wunused \ 13 | -Wall \ 14 | -Werror \ 15 | -O2 -emit-llvm \ 16 | --sysroot ${CURDIR} \ 17 | $(foreach path,$(LINUX_HEADERS),-I $(path)/include -I $(path)/arch/x86/include -I $(path)/arch/x86/include/generated -I $(path)/include/generated/uapi -I $(path)/arch/x86/include/uapi -I $(path)/include/uapi) 18 | 19 | LLC ?= llc 20 | LLC_FLAGS := -march=bpf -filetype=obj 21 | 22 | GO_BINDATA := go-bindata 23 | GO_BINDATA_FLAGS := -pkg sockmap -prefix "${DEST_DIR}/" -modtime 1 24 | 25 | assets: $(ASSETS) 26 | 27 | %.go: %.o 28 | ${GO_BINDATA} ${GO_BINDATA_FLAGS} -o "${DEST_DIR}/$(@)" "${DEST_DIR}/$(@:.go=.o)" 29 | 30 | %.o: %.c 31 | @mkdir -p "$(DEST_DIR)" 32 | ${CLANG} ${CLANG_FLAGS} -c $< -o - | ${LLC} ${LLC_FLAGS} -o "${DEST_DIR}/$@" 33 | -------------------------------------------------------------------------------- /bpf/bpf_sockmap.c: -------------------------------------------------------------------------------- 1 | // disable randomised task struct (Linux 4.13) 2 | #define randomized_struct_fields_start struct { 3 | #define randomized_struct_fields_end }; 4 | 5 | #include 6 | #include 7 | 8 | #include "bpf_helpers.h" 9 | #include "bpf_map.h" 10 | 11 | struct bpf_map_def SEC("maps/sockmap") sock_map = { 12 | .type = BPF_MAP_TYPE_SOCKMAP, 13 | .key_size = sizeof(int), 14 | .value_size = sizeof(unsigned int), 15 | .max_entries = 2, 16 | .pinning = 0, 17 | .namespace = "", 18 | }; 19 | 20 | //#define DEBUG 1 21 | #ifndef DEBUG 22 | /* Only use this for debug output. Notice output from bpf_trace_printk() 23 | * end-up in /sys/kernel/debug/tracing/trace_pipe 24 | */ 25 | #define bpf_debug(fmt, ...) \ 26 | ({ \ 27 | char ____fmt[] = fmt; \ 28 | bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ 29 | }) 30 | #else 31 | #define bpf_debug(fmt, ...){;} 32 | #endif 33 | 34 | SEC("sk/skb/parser/sockmap") 35 | int _prog_parser(struct __sk_buff *skb) 36 | { 37 | bpf_debug("parser\n"); 38 | return skb->len; 39 | } 40 | 41 | SEC("sk/skb/verdict/sockmap") 42 | int _prog_verdict(struct __sk_buff *skb) 43 | { 44 | bpf_debug("verdict\n"); 45 | uint32_t idx = 0; 46 | return bpf_sk_redirect_map(skb, &sock_map, idx, 0); 47 | } 48 | 49 | char _license[] SEC("license") = "GPL"; 50 | u32 _version SEC("version") = LINUX_VERSION_CODE; 51 | -------------------------------------------------------------------------------- /bpf/include/README.md: -------------------------------------------------------------------------------- 1 | # bpf include 2 | 3 | ``` 4 | # https://lwn.net/Articles/507794/ 5 | #bpf.h: #include 6 | #bpf.h: cp -a /usr/src/linux-headers-4.18.0-16/include/uapi/linux/bpf.h /vagrant/bpf/include/ 7 | bpf.h: https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h 8 | # remove bpf_map_def 9 | bpf_helpers.h: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/bpf_helpers.h 10 | bpf_map.h: https://github.com/iovisor/gobpf/blob/master/elf/include/bpf_map.h 11 | ``` -------------------------------------------------------------------------------- /bpf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int pinning; 10 | char namespace[BUF_SIZE_MAP_NS]; 11 | } bpf_map_def; 12 | 13 | enum bpf_pin_type { 14 | PIN_NONE = 0, 15 | PIN_OBJECT_NS, 16 | PIN_GLOBAL_NS, 17 | PIN_CUSTOM_NS, 18 | }; -------------------------------------------------------------------------------- /cmd/sockmap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net" 8 | "syscall" 9 | 10 | "github.com/dippynark/bpf-sockmap/pkg/sockmap" 11 | ) 12 | 13 | const ( 14 | defaultPort = 12345 15 | ) 16 | 17 | var portFlag = flag.Int("port", defaultPort, "listen port") 18 | 19 | func main() { 20 | 21 | flag.Parse() 22 | port := *portFlag 23 | 24 | // setup sockmap module 25 | sockmap, err := sockmap.New() 26 | if err != nil { 27 | log.Fatalf("failed to create new sockmap module: %s", err) 28 | } 29 | log.Print("created new sockmap module") 30 | defer func() { 31 | err := sockmap.Close() 32 | if err != nil { 33 | log.Fatalf("failed to close sockmap module: %s", err) 34 | } 35 | }() 36 | 37 | // listen 38 | listenAddress := fmt.Sprintf("0.0.0.0:%d", port) 39 | l, err := net.Listen("tcp", listenAddress) 40 | if err != nil { 41 | log.Fatalf("failed to listen on port %d: %s", port, err) 42 | } 43 | defer func() { 44 | err := l.Close() 45 | if err != nil { 46 | log.Fatalf("failed to close socket: %s", err) 47 | } 48 | }() 49 | log.Printf("listening on address: %s", listenAddress) 50 | 51 | // add accepted connections to sockmap 52 | for { 53 | // accept 54 | conn, err := l.Accept() 55 | if err != nil { 56 | log.Fatalf("error accepting: %s", err) 57 | } 58 | 59 | // retrieve copy of connection file descriptor 60 | tcpConn, ok := conn.(*net.TCPConn) 61 | if !ok { 62 | log.Fatalf("failed to cast connection to TCP connection") 63 | } 64 | f, err := tcpConn.File() 65 | if err != nil { 66 | log.Fatalf("failed to retrieve copy of the underlying TCP connection file") 67 | } 68 | d := f.Fd() 69 | 70 | // update element 71 | err = sockmap.UpdateSocketDescriptor(d) 72 | if err != nil { 73 | log.Fatalf("failed to update socket descriptor: %s", err) 74 | } 75 | 76 | // we don't need two copies of the connection file descriptor so close the copy 77 | // https://stackoverflow.com/questions/28967701/golang-tcp-socket-cant-close-after-get-file#answer-28968431 78 | err = syscall.SetNonblock(int(d), true) 79 | if err != nil { 80 | log.Fatalf("failed to put file descriptor in non-blocking mode: %s", err) 81 | } 82 | err = f.Close() 83 | if err != nil { 84 | log.Fatalf("failed to close file descriptor copy: %s", err) 85 | } 86 | } 87 | } 88 | 89 | /* 90 | func waitForCloseByClient(conn net.Conn) { 91 | fmt.Println("Accepted connection from", conn.RemoteAddr()) 92 | 93 | defer func() { 94 | fmt.Println("Closing connection from", conn.RemoteAddr()) 95 | conn.Close() 96 | }() 97 | 98 | buf := make([]byte, 1024) 99 | for { 100 | _, err := conn.Read(buf) 101 | if err == io.EOF { 102 | fmt.Println("Read error", err.Error()) 103 | return 104 | } 105 | } 106 | } 107 | */ 108 | -------------------------------------------------------------------------------- /pkg/sockmap/.gitignore: -------------------------------------------------------------------------------- 1 | include -------------------------------------------------------------------------------- /pkg/sockmap/sockmap.go: -------------------------------------------------------------------------------- 1 | package sockmap 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "unsafe" 8 | 9 | "github.com/dippynark/gobpf/elf" 10 | ) 11 | 12 | /* 13 | #include "include/bpf.h" 14 | */ 15 | import "C" 16 | 17 | type Sockmap struct { 18 | module *elf.Module 19 | } 20 | 21 | func New() (*Sockmap, error) { 22 | 23 | buf, err := Asset("bpf_sockmap.o") 24 | if err != nil { 25 | return nil, err 26 | } 27 | reader := bytes.NewReader(buf) 28 | 29 | m := elf.NewModuleFromReader(reader) 30 | if m == nil { 31 | return nil, errors.New("failed to create new module") 32 | } 33 | 34 | err = m.Load(map[string]elf.SectionParams{}) 35 | if err != nil { 36 | return nil, fmt.Errorf("failed to load BPF programs and maps: %s", err) 37 | } 38 | 39 | err = m.AttachParserVerdictPrograms() 40 | if err != nil { 41 | return nil, fmt.Errorf("failed to attach sockmap programs: %s", err) 42 | } 43 | 44 | sockmap := Sockmap{module: m} 45 | 46 | return &sockmap, nil 47 | } 48 | 49 | func (s *Sockmap) Close() error { 50 | return s.module.Close() 51 | } 52 | 53 | func (s *Sockmap) UpdateSocketDescriptor(socketDescriptor uintptr) error { 54 | sockmap := s.module.Map("sockmap") 55 | if sockmap == nil { 56 | return errors.New("failed to retrieve sockmap map") 57 | } 58 | key := 0 59 | value := socketDescriptor 60 | err := s.module.UpdateElement(sockmap, unsafe.Pointer(&key), unsafe.Pointer(&value), C.BPF_ANY) 61 | if err != nil { 62 | return fmt.Errorf("failed to update element: %s", err) 63 | } 64 | return nil 65 | } 66 | 67 | -------------------------------------------------------------------------------- /vagrant/README.md: -------------------------------------------------------------------------------- 1 | # vagrant 2 | 3 | ``` 4 | vagrant plugin install vagrant-reload 5 | ``` -------------------------------------------------------------------------------- /vagrant/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | set -o xtrace 7 | 8 | export DEBIAN_FRONTEND=noninteractive 9 | 10 | apt-get update -y 11 | apt-get install -y \ 12 | linux-image-4.18.0-16-generic \ 13 | linux-headers-4.18.0-16-generic \ 14 | make \ 15 | docker.io \ 16 | llvm 17 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 PLUMgrid 2 | Copyright 2016 Kinvolk 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/bcc/perf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "encoding/binary" 19 | "fmt" 20 | "sync" 21 | "unsafe" 22 | 23 | "github.com/iovisor/gobpf/pkg/cpuonline" 24 | ) 25 | 26 | /* 27 | #cgo CFLAGS: -I/usr/include/bcc/compat 28 | #cgo LDFLAGS: -lbcc 29 | #include 30 | #include 31 | #include 32 | 33 | // perf_reader_raw_cb as defined in bcc libbpf.h 34 | // typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size); 35 | extern void callback_to_go(void*, void*, int); 36 | */ 37 | import "C" 38 | 39 | type PerfMap struct { 40 | table *Table 41 | readers []*C.struct_perf_reader 42 | stop chan bool 43 | } 44 | 45 | type callbackData struct { 46 | receiverChan chan []byte 47 | } 48 | 49 | const BPF_PERF_READER_PAGE_CNT = 8 50 | 51 | var byteOrder binary.ByteOrder 52 | var callbackRegister = make(map[uint64]*callbackData) 53 | var callbackIndex uint64 54 | var mu sync.Mutex 55 | 56 | // In lack of binary.HostEndian ... 57 | func init() { 58 | byteOrder = determineHostByteOrder() 59 | } 60 | 61 | func registerCallback(data *callbackData) uint64 { 62 | mu.Lock() 63 | defer mu.Unlock() 64 | callbackIndex++ 65 | for callbackRegister[callbackIndex] != nil { 66 | callbackIndex++ 67 | } 68 | callbackRegister[callbackIndex] = data 69 | return callbackIndex 70 | } 71 | 72 | func unregisterCallback(i uint64) { 73 | mu.Lock() 74 | defer mu.Unlock() 75 | delete(callbackRegister, i) 76 | } 77 | 78 | func lookupCallback(i uint64) *callbackData { 79 | return callbackRegister[i] 80 | } 81 | 82 | // Gateway function as required with CGO Go >= 1.6 83 | // "If a C-program wants a function pointer, a gateway function has to 84 | // be written. This is because we can't take the address of a Go 85 | // function and give that to C-code since the cgo tool will generate a 86 | // stub in C that should be called." 87 | //export callback_to_go 88 | func callback_to_go(cbCookie unsafe.Pointer, raw unsafe.Pointer, rawSize C.int) { 89 | callbackData := lookupCallback(uint64(uintptr(cbCookie))) 90 | callbackData.receiverChan <- C.GoBytes(raw, rawSize) 91 | } 92 | 93 | // GetHostByteOrder returns the current byte-order. 94 | func GetHostByteOrder() binary.ByteOrder { 95 | return byteOrder 96 | } 97 | 98 | func determineHostByteOrder() binary.ByteOrder { 99 | var i int32 = 0x01020304 100 | u := unsafe.Pointer(&i) 101 | pb := (*byte)(u) 102 | b := *pb 103 | if b == 0x04 { 104 | return binary.LittleEndian 105 | } 106 | 107 | return binary.BigEndian 108 | } 109 | 110 | // InitPerfMap initializes a perf map with a receiver channel. 111 | func InitPerfMap(table *Table, receiverChan chan []byte) (*PerfMap, error) { 112 | fd := table.Config()["fd"].(int) 113 | keySize := table.Config()["key_size"].(uint64) 114 | leafSize := table.Config()["leaf_size"].(uint64) 115 | 116 | if keySize != 4 || leafSize != 4 { 117 | return nil, fmt.Errorf("passed table has wrong size") 118 | } 119 | 120 | callbackDataIndex := registerCallback(&callbackData{ 121 | receiverChan, 122 | }) 123 | 124 | key := make([]byte, keySize) 125 | leaf := make([]byte, leafSize) 126 | keyP := unsafe.Pointer(&key[0]) 127 | leafP := unsafe.Pointer(&leaf[0]) 128 | 129 | readers := []*C.struct_perf_reader{} 130 | 131 | cpus, err := cpuonline.Get() 132 | if err != nil { 133 | return nil, fmt.Errorf("failed to determine online cpus: %v", err) 134 | } 135 | 136 | for _, cpu := range cpus { 137 | reader, err := bpfOpenPerfBuffer(cpu, callbackDataIndex) 138 | if err != nil { 139 | return nil, fmt.Errorf("failed to open perf buffer: %v", err) 140 | } 141 | 142 | perfFd := C.perf_reader_fd((*C.struct_perf_reader)(reader)) 143 | 144 | readers = append(readers, (*C.struct_perf_reader)(reader)) 145 | 146 | byteOrder.PutUint32(leaf, uint32(perfFd)) 147 | 148 | r, err := C.bpf_update_elem(C.int(fd), keyP, leafP, 0) 149 | if r != 0 { 150 | return nil, fmt.Errorf("unable to initialize perf map: %v", err) 151 | } 152 | r = C.bpf_get_next_key(C.int(fd), keyP, keyP) 153 | if r != 0 { 154 | break 155 | } 156 | } 157 | return &PerfMap{ 158 | table, 159 | readers, 160 | make(chan bool), 161 | }, nil 162 | } 163 | 164 | // Start to poll the perf map reader and send back event data 165 | // over the connected channel. 166 | func (pm *PerfMap) Start() { 167 | go pm.poll(500) 168 | } 169 | 170 | // Stop to poll the perf map readers after a maximum of 500ms 171 | // (the timeout we use for perf_reader_poll). Ideally we would 172 | // have a way to cancel the poll, but perf_reader_poll doesn't 173 | // support that yet. 174 | func (pm *PerfMap) Stop() { 175 | pm.stop <- true 176 | } 177 | 178 | func (pm *PerfMap) poll(timeout int) { 179 | for { 180 | select { 181 | case <-pm.stop: 182 | return 183 | default: 184 | C.perf_reader_poll(C.int(len(pm.readers)), &pm.readers[0], C.int(timeout)) 185 | } 186 | } 187 | } 188 | 189 | func bpfOpenPerfBuffer(cpu uint, callbackDataIndex uint64) (unsafe.Pointer, error) { 190 | cpuC := C.int(cpu) 191 | reader, err := C.bpf_open_perf_buffer( 192 | (C.perf_reader_raw_cb)(unsafe.Pointer(C.callback_to_go)), 193 | nil, 194 | unsafe.Pointer(uintptr(callbackDataIndex)), 195 | -1, cpuC, BPF_PERF_READER_PAGE_CNT) 196 | if reader == nil { 197 | return nil, fmt.Errorf("failed to open perf buffer: %v", err) 198 | } 199 | return reader, nil 200 | } 201 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/bcc/symbol.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Louis McCormack 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "fmt" 19 | "regexp" 20 | "sync" 21 | "unsafe" 22 | ) 23 | 24 | /* 25 | #cgo CFLAGS: -I/usr/include/bcc/compat 26 | #cgo LDFLAGS: -lbcc 27 | #include 28 | #include 29 | #include 30 | extern void foreach_symbol_callback(char*, uint64_t); 31 | */ 32 | import "C" 33 | 34 | type symbolAddress struct { 35 | name string 36 | addr uint64 37 | } 38 | 39 | //symbolCache will cache module lookups 40 | var symbolCache = struct { 41 | cache map[string][]*symbolAddress 42 | currentModule string 43 | lock *sync.Mutex 44 | }{ 45 | cache: map[string][]*symbolAddress{}, 46 | currentModule: "", 47 | lock: &sync.Mutex{}, 48 | } 49 | 50 | type bccSymbol struct { 51 | name *C.char 52 | demangleName *C.char 53 | module *C.char 54 | offset C.ulonglong 55 | } 56 | 57 | type bccSymbolOption struct { 58 | useDebugFile int 59 | checkDebugFileCrc int 60 | useSymbolType uint32 61 | } 62 | 63 | // resolveSymbolPath returns the file and offset to locate symname in module 64 | func resolveSymbolPath(module string, symname string, addr uint64, pid int) (string, uint64, error) { 65 | if pid == -1 { 66 | pid = 0 67 | } 68 | 69 | modname, offset, err := bccResolveSymname(module, symname, addr, pid) 70 | if err != nil { 71 | return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err) 72 | } 73 | 74 | return modname, offset, nil 75 | } 76 | 77 | func bccResolveSymname(module string, symname string, addr uint64, pid int) (string, uint64, error) { 78 | symbol := &bccSymbol{} 79 | symbolC := (*C.struct_bcc_symbol)(unsafe.Pointer(symbol)) 80 | moduleCS := C.CString(module) 81 | defer C.free(unsafe.Pointer(moduleCS)) 82 | symnameCS := C.CString(symname) 83 | defer C.free(unsafe.Pointer(symnameCS)) 84 | 85 | res, err := C.bcc_resolve_symname(moduleCS, symnameCS, (C.uint64_t)(addr), C.int(pid), nil, symbolC) 86 | if res < 0 { 87 | return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err) 88 | } 89 | 90 | return C.GoString(symbolC.module), (uint64)(symbolC.offset), nil 91 | } 92 | 93 | func bccResolveName(module, symname string, pid int) (uint64, error) { 94 | symbol := &bccSymbolOption{} 95 | symbolC := (*C.struct_bcc_symbol_option)(unsafe.Pointer(symbol)) 96 | 97 | pidC := C.int(pid) 98 | cache := C.bcc_symcache_new(pidC, symbolC) 99 | 100 | moduleCS := C.CString(module) 101 | defer C.free(unsafe.Pointer(moduleCS)) 102 | 103 | nameCS := C.CString(symname) 104 | defer C.free(unsafe.Pointer(nameCS)) 105 | 106 | var addr uint64 107 | addrC := C.uint64_t(addr) 108 | res := C.bcc_symcache_resolve_name(cache, moduleCS, nameCS, &addrC) 109 | if res < 0 { 110 | return 0, fmt.Errorf("unable to locate symbol %s in module %s", symname, module) 111 | } 112 | 113 | return addr, nil 114 | } 115 | 116 | // getUserSymbolsAndAddresses finds a list of symbols associated with a module, 117 | // along with their addresses. The results are cached in the symbolCache and 118 | // returned 119 | func getUserSymbolsAndAddresses(module string) ([]*symbolAddress, error) { 120 | symbolCache.lock.Lock() 121 | defer symbolCache.lock.Unlock() 122 | // return previously cached list if it exists 123 | if _, ok := symbolCache.cache[module]; ok { 124 | return symbolCache.cache[module], nil 125 | } 126 | 127 | symbolCache.cache[module] = []*symbolAddress{} 128 | symbolCache.currentModule = module 129 | 130 | if err := bccForeachSymbol(module); err != nil { 131 | return nil, err 132 | } 133 | 134 | return symbolCache.cache[module], nil 135 | } 136 | 137 | func matchUserSymbols(module, match string) ([]*symbolAddress, error) { 138 | r, err := regexp.Compile(match) 139 | if err != nil { 140 | return nil, fmt.Errorf("invalid regex %s : %s", match, err) 141 | } 142 | matchedSymbols := []*symbolAddress{} 143 | symbols, err := getUserSymbolsAndAddresses(module) 144 | if err != nil { 145 | return nil, err 146 | } 147 | for _, sym := range symbols { 148 | if r.MatchString(sym.name) { 149 | matchedSymbols = append(matchedSymbols, sym) 150 | } 151 | } 152 | return matchedSymbols, nil 153 | } 154 | 155 | // foreach_symbol_callback is a gateway function that will be exported to C 156 | // so that it can be referenced as a function pointer 157 | //export foreach_symbol_callback 158 | func foreach_symbol_callback(symname *C.char, addr C.uint64_t) { 159 | symbolCache.cache[symbolCache.currentModule] = 160 | append(symbolCache.cache[symbolCache.currentModule], &symbolAddress{C.GoString(symname), (uint64)(addr)}) 161 | } 162 | 163 | func bccForeachSymbol(module string) error { 164 | moduleCS := C.CString(module) 165 | defer C.free(unsafe.Pointer(moduleCS)) 166 | res := C.bcc_foreach_function_symbol(moduleCS, (C.SYM_CB)(unsafe.Pointer(C.foreach_symbol_callback))) 167 | if res < 0 { 168 | return fmt.Errorf("unable to list symbols for %s", module) 169 | } 170 | return nil 171 | } 172 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/bcc/table.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PLUMgrid 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "bytes" 19 | "errors" 20 | "fmt" 21 | "os" 22 | "unsafe" 23 | ) 24 | 25 | /* 26 | #cgo CFLAGS: -I/usr/include/bcc/compat 27 | #cgo LDFLAGS: -lbcc 28 | #include 29 | #include 30 | */ 31 | import "C" 32 | 33 | var errIterationFailed = errors.New("table.Iter: leaf for next key not found") 34 | 35 | // Table references a BPF table. The zero value cannot be used. 36 | type Table struct { 37 | id C.size_t 38 | module *Module 39 | } 40 | 41 | // New tables returns a refernce to a BPF table. 42 | func NewTable(id C.size_t, module *Module) *Table { 43 | return &Table{ 44 | id: id, 45 | module: module, 46 | } 47 | } 48 | 49 | // ID returns the table id. 50 | func (table *Table) ID() string { 51 | return C.GoString(C.bpf_table_name(table.module.p, table.id)) 52 | } 53 | 54 | // Name returns the table name. 55 | func (table *Table) Name() string { 56 | return C.GoString(C.bpf_table_name(table.module.p, table.id)) 57 | } 58 | 59 | // Config returns the table properties (name, fd, ...). 60 | func (table *Table) Config() map[string]interface{} { 61 | mod := table.module.p 62 | return map[string]interface{}{ 63 | "name": C.GoString(C.bpf_table_name(mod, table.id)), 64 | "fd": int(C.bpf_table_fd_id(mod, table.id)), 65 | "key_size": uint64(C.bpf_table_key_size_id(mod, table.id)), 66 | "leaf_size": uint64(C.bpf_table_leaf_size_id(mod, table.id)), 67 | "key_desc": C.GoString(C.bpf_table_key_desc_id(mod, table.id)), 68 | "leaf_desc": C.GoString(C.bpf_table_leaf_desc_id(mod, table.id)), 69 | } 70 | } 71 | 72 | func (table *Table) LeafStrToBytes(leafStr string) ([]byte, error) { 73 | mod := table.module.p 74 | 75 | leafSize := C.bpf_table_leaf_size_id(mod, table.id) 76 | leaf := make([]byte, leafSize) 77 | leafP := unsafe.Pointer(&leaf[0]) 78 | 79 | leafCS := C.CString(leafStr) 80 | defer C.free(unsafe.Pointer(leafCS)) 81 | 82 | r := C.bpf_table_leaf_sscanf(mod, table.id, leafCS, leafP) 83 | if r != 0 { 84 | return nil, fmt.Errorf("error scanning leaf (%v) from string", leafStr) 85 | } 86 | return leaf, nil 87 | } 88 | 89 | func (table *Table) KeyStrToBytes(keyStr string) ([]byte, error) { 90 | mod := table.module.p 91 | 92 | keySize := C.bpf_table_key_size_id(mod, table.id) 93 | key := make([]byte, keySize) 94 | keyP := unsafe.Pointer(&key[0]) 95 | 96 | keyCS := C.CString(keyStr) 97 | defer C.free(unsafe.Pointer(keyCS)) 98 | 99 | r := C.bpf_table_key_sscanf(mod, table.id, keyCS, keyP) 100 | if r != 0 { 101 | return nil, fmt.Errorf("error scanning key (%v) from string", keyStr) 102 | } 103 | return key, nil 104 | } 105 | 106 | // KeyBytesToStr returns the given key value formatted using the bcc-table's key string printer. 107 | func (table *Table) KeyBytesToStr(key []byte) (string, error) { 108 | keySize := len(key) 109 | keyP := unsafe.Pointer(&key[0]) 110 | 111 | keyStr := make([]byte, keySize*8) 112 | keyStrP := (*C.char)(unsafe.Pointer(&keyStr[0])) 113 | 114 | if res := C.bpf_table_key_snprintf(table.module.p, table.id, keyStrP, C.size_t(len(keyStr)), keyP); res != 0 { 115 | return "", fmt.Errorf("formatting table-key: %d", res) 116 | } 117 | 118 | return string(keyStr[:bytes.IndexByte(keyStr, 0)]), nil 119 | } 120 | 121 | // LeafBytesToStr returns the given leaf value formatted using the bcc-table's leaf string printer. 122 | func (table *Table) LeafBytesToStr(leaf []byte) (string, error) { 123 | leafSize := len(leaf) 124 | leafP := unsafe.Pointer(&leaf[0]) 125 | 126 | leafStr := make([]byte, leafSize*8) 127 | leafStrP := (*C.char)(unsafe.Pointer(&leafStr[0])) 128 | 129 | if res := C.bpf_table_leaf_snprintf(table.module.p, table.id, leafStrP, C.size_t(len(leafStr)), leafP); res != 0 { 130 | return "", fmt.Errorf("formatting table-leaf: %d", res) 131 | } 132 | 133 | return string(leafStr[:bytes.IndexByte(leafStr, 0)]), nil 134 | } 135 | 136 | // Get takes a key and returns the value or nil, and an 'ok' style indicator. 137 | func (table *Table) Get(key []byte) ([]byte, error) { 138 | mod := table.module.p 139 | fd := C.bpf_table_fd_id(mod, table.id) 140 | 141 | keyP := unsafe.Pointer(&key[0]) 142 | 143 | leafSize := C.bpf_table_leaf_size_id(mod, table.id) 144 | leaf := make([]byte, leafSize) 145 | leafP := unsafe.Pointer(&leaf[0]) 146 | 147 | r, err := C.bpf_lookup_elem(fd, keyP, leafP) 148 | if r != 0 { 149 | keyStr, errK := table.KeyBytesToStr(key) 150 | if errK != nil { 151 | keyStr = fmt.Sprintf("%v", key) 152 | } 153 | return nil, fmt.Errorf("Table.Get: key %v: %v", keyStr, err) 154 | } 155 | 156 | return leaf, nil 157 | } 158 | 159 | // GetP takes a key and returns the value or nil. 160 | func (table *Table) GetP(key unsafe.Pointer) (unsafe.Pointer, error) { 161 | fd := C.bpf_table_fd_id(table.module.p, table.id) 162 | 163 | leafSize := C.bpf_table_leaf_size_id(table.module.p, table.id) 164 | leaf := make([]byte, leafSize) 165 | leafP := unsafe.Pointer(&leaf[0]) 166 | 167 | _, err := C.bpf_lookup_elem(fd, key, leafP) 168 | if err != nil { 169 | return nil, err 170 | } 171 | return leafP, nil 172 | } 173 | 174 | // Set a key to a value. 175 | func (table *Table) Set(key, leaf []byte) error { 176 | fd := C.bpf_table_fd_id(table.module.p, table.id) 177 | 178 | keyP := unsafe.Pointer(&key[0]) 179 | leafP := unsafe.Pointer(&leaf[0]) 180 | 181 | r, err := C.bpf_update_elem(fd, keyP, leafP, 0) 182 | if r != 0 { 183 | keyStr, errK := table.KeyBytesToStr(key) 184 | if errK != nil { 185 | keyStr = fmt.Sprintf("%v", key) 186 | } 187 | leafStr, errL := table.LeafBytesToStr(leaf) 188 | if errL != nil { 189 | leafStr = fmt.Sprintf("%v", leaf) 190 | } 191 | 192 | return fmt.Errorf("Table.Set: update %v to %v: %v", keyStr, leafStr, err) 193 | } 194 | 195 | return nil 196 | } 197 | 198 | // SetP a key to a value as unsafe.Pointer. 199 | func (table *Table) SetP(key, leaf unsafe.Pointer) error { 200 | fd := C.bpf_table_fd_id(table.module.p, table.id) 201 | 202 | _, err := C.bpf_update_elem(fd, key, leaf, 0) 203 | if err != nil { 204 | return err 205 | } 206 | 207 | return nil 208 | } 209 | 210 | // Delete a key. 211 | func (table *Table) Delete(key []byte) error { 212 | fd := C.bpf_table_fd_id(table.module.p, table.id) 213 | keyP := unsafe.Pointer(&key[0]) 214 | r, err := C.bpf_delete_elem(fd, keyP) 215 | if r != 0 { 216 | keyStr, errK := table.KeyBytesToStr(key) 217 | if errK != nil { 218 | keyStr = fmt.Sprintf("%v", key) 219 | } 220 | return fmt.Errorf("Table.Delete: key %v: %v", keyStr, err) 221 | } 222 | return nil 223 | } 224 | 225 | // DeleteP a key. 226 | func (table *Table) DeleteP(key unsafe.Pointer) error { 227 | fd := C.bpf_table_fd_id(table.module.p, table.id) 228 | _, err := C.bpf_delete_elem(fd, key) 229 | if err != nil { 230 | return err 231 | } 232 | return nil 233 | } 234 | 235 | // DeleteAll deletes all entries from the table 236 | func (table *Table) DeleteAll() error { 237 | mod := table.module.p 238 | fd := C.bpf_table_fd_id(mod, table.id) 239 | 240 | keySize := C.bpf_table_key_size_id(mod, table.id) 241 | key := make([]byte, keySize) 242 | keyP := unsafe.Pointer(&key[0]) 243 | for res := C.bpf_get_first_key(fd, keyP, keySize); res == 0; res = C.bpf_get_next_key(fd, keyP, keyP) { 244 | r, err := C.bpf_delete_elem(fd, keyP) 245 | if r != 0 { 246 | return fmt.Errorf("Table.DeleteAll: unable to delete element: %v", err) 247 | } 248 | } 249 | return nil 250 | } 251 | 252 | // TableIterator contains the current position for iteration over a *bcc.Table and provides methods for iteration. 253 | type TableIterator struct { 254 | table *Table 255 | fd C.int 256 | 257 | err error 258 | 259 | key []byte 260 | leaf []byte 261 | } 262 | 263 | // Iter returns an iterator to list all table entries available as raw bytes. 264 | func (table *Table) Iter() *TableIterator { 265 | fd := C.bpf_table_fd_id(table.module.p, table.id) 266 | 267 | return &TableIterator{ 268 | table: table, 269 | fd: fd, 270 | } 271 | } 272 | 273 | // Next looks up the next element and return true if one is available. 274 | func (it *TableIterator) Next() bool { 275 | if it.err != nil { 276 | return false 277 | } 278 | 279 | if it.key == nil { 280 | keySize := C.bpf_table_key_size_id(it.table.module.p, it.table.id) 281 | 282 | key := make([]byte, keySize) 283 | keyP := unsafe.Pointer(&key[0]) 284 | if res, err := C.bpf_get_first_key(it.fd, keyP, keySize); res != 0 { 285 | if !os.IsNotExist(err) { 286 | it.err = err 287 | } 288 | return false 289 | } 290 | 291 | leafSize := C.bpf_table_leaf_size_id(it.table.module.p, it.table.id) 292 | leaf := make([]byte, leafSize) 293 | 294 | it.key = key 295 | it.leaf = leaf 296 | } else { 297 | keyP := unsafe.Pointer(&it.key[0]) 298 | if res, err := C.bpf_get_next_key(it.fd, keyP, keyP); res != 0 { 299 | if !os.IsNotExist(err) { 300 | it.err = err 301 | } 302 | return false 303 | } 304 | } 305 | 306 | keyP := unsafe.Pointer(&it.key[0]) 307 | leafP := unsafe.Pointer(&it.leaf[0]) 308 | if res, err := C.bpf_lookup_elem(it.fd, keyP, leafP); res != 0 { 309 | it.err = errIterationFailed 310 | if !os.IsNotExist(err) { 311 | it.err = err 312 | } 313 | return false 314 | } 315 | 316 | return true 317 | } 318 | 319 | // Key returns the current key value of the iterator, if the most recent call to Next returned true. 320 | // The slice is valid only until the next call to Next. 321 | func (it *TableIterator) Key() []byte { 322 | return it.key 323 | } 324 | 325 | // Leaf returns the current leaf value of the iterator, if the most recent call to Next returned true. 326 | // The slice is valid only until the next call to Next. 327 | func (it *TableIterator) Leaf() []byte { 328 | return it.leaf 329 | } 330 | 331 | // Err returns the last error that ocurred while table.Iter oder iter.Next 332 | func (it *TableIterator) Err() error { 333 | return it.err 334 | } 335 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/bpf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bpf 16 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/compat.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // (c) 2018 Suchakra Sharma 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "errors" 21 | "io/ioutil" 22 | "regexp" 23 | "runtime" 24 | ) 25 | 26 | const defaultSymFile = "/proc/kallsyms" 27 | 28 | // Returns the qualified syscall named by going through '/proc/kallsyms' on the 29 | // system on which its executed. It allows BPF programs that may have been compiled 30 | // for older syscall functions to run on newer kernels 31 | func GetSyscallFnName(name string) (string, error) { 32 | // Get kernel symbols 33 | syms, err := ioutil.ReadFile(defaultSymFile) 34 | if err != nil { 35 | return "", err 36 | } 37 | return getSyscallFnNameWithKallsyms(name, string(syms)) 38 | } 39 | 40 | func getSyscallFnNameWithKallsyms(name string, kallsymsContent string) (string, error) { 41 | var arch string 42 | switch runtime.GOARCH { 43 | case "386": 44 | arch = "ia32" 45 | default: 46 | arch = "x64" 47 | } 48 | 49 | // We should search for new syscall function like "__x64__sys_open" 50 | // Note the start of word boundary. Should return exactly one string 51 | regexStr := `(\b__` + arch + `_[Ss]y[sS]_` + name + `\b)` 52 | fnRegex := regexp.MustCompile(regexStr) 53 | 54 | match := fnRegex.FindAllString(kallsymsContent, -1) 55 | 56 | // If nothing found, search for old syscall function to be sure 57 | if len(match) == 0 { 58 | newRegexStr := `(\b[Ss]y[sS]_` + name + `\b)` 59 | fnRegex = regexp.MustCompile(newRegexStr) 60 | newMatch := fnRegex.FindAllString(kallsymsContent, -1) 61 | 62 | // If we get something like 'sys_open' or 'SyS_open', return 63 | // either (they have same addr) else, just return original string 64 | if len(newMatch) >= 1 { 65 | return newMatch[0], nil 66 | } else { 67 | return "", errors.New("could not find a valid syscall name") 68 | } 69 | } 70 | 71 | return match[0], nil 72 | } 73 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/compat_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // (c) 2018 ShiftLeft GmbH 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | const prefixedKallsymsSymbols = ` 24 | 0000000000000000 W __x32_compat_sys_open_by_handle_at 25 | 0000000000000000 T do_sys_open 26 | 0000000000000000 T __x64_sys_open 27 | 0000000000000000 T __ia32_sys_open 28 | 0000000000000000 T __x64_sys_openat 29 | 0000000000000000 T __ia32_sys_openat 30 | 0000000000000000 T __ia32_compat_sys_open 31 | 0000000000000000 T __ia32_compat_sys_openat 32 | 0000000000000000 T __x64_sys_open_by_handle_at 33 | 0000000000000000 T __ia32_sys_open_by_handle_at 34 | 0000000000000000 T __ia32_compat_sys_open_by_handle_at 35 | 0000000000000000 t proc_sys_open 36 | 0000000000000000 t _eil_addr___ia32_compat_sys_openat 37 | 0000000000000000 t _eil_addr___ia32_compat_sys_open 38 | 0000000000000000 t _eil_addr___ia32_sys_openat 39 | 0000000000000000 t _eil_addr___x64_sys_openat 40 | 0000000000000000 t _eil_addr___ia32_sys_open 41 | 0000000000000000 t _eil_addr___x64_sys_open 42 | 0000000000000000 t _eil_addr___ia32_compat_sys_open_by_handle_at 43 | 0000000000000000 t _eil_addr___ia32_sys_open_by_handle_at 44 | 0000000000000000 t _eil_addr___x64_sys_open_by_handle_at 45 | ` 46 | 47 | const kallsymsSymbols = ` 48 | 0000000000000000 T dentry_open 49 | 0000000000000000 T filp_clone_open 50 | 0000000000000000 T file_open_name 51 | 0000000000000000 T filp_open 52 | 0000000000000000 T do_sys_open 53 | 0000000000000000 T SyS_open 54 | 0000000000000000 T sys_open 55 | 0000000000000000 T SyS_openat 56 | 0000000000000000 T sys_openat 57 | 0000000000000000 T compat_SyS_open 58 | 0000000000000000 T compat_sys_open 59 | 0000000000000000 T compat_SyS_openat 60 | 0000000000000000 T compat_sys_openat 61 | 0000000000000000 T SyS_creat 62 | 0000000000000000 T sys_creat 63 | 0000000000000000 T sys_vhangup 64 | ` 65 | 66 | func TestGetSyscallFnName(t *testing.T) { 67 | fnName, err := getSyscallFnNameWithKallsyms("open", prefixedKallsymsSymbols) 68 | if err != nil && fnName != "__x64_sys_open" { 69 | t.Errorf("expected __x64_sys_open : %s", err) 70 | } 71 | fnName, err = getSyscallFnNameWithKallsyms("open", kallsymsSymbols) 72 | if err != nil { 73 | if fnName != "SyS_open" { 74 | t.Errorf("expected SyS_open :%s", err) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/elf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestValidateMapPath(t *testing.T) { 24 | tests := []struct { 25 | input string 26 | expected bool 27 | }{ 28 | { 29 | input: "/sys/fs/bpf/good/path", 30 | expected: true, 31 | }, 32 | { 33 | input: "/sys/fs/bpf/../../bad/path", 34 | expected: false, 35 | }, 36 | { 37 | input: "/sys/fs/bpf/./bad/path", 38 | expected: false, 39 | }, 40 | { 41 | input: "/bad/path", 42 | expected: false, 43 | }, 44 | } 45 | 46 | for i, tt := range tests { 47 | if isValid := validateMapPath(tt.input); isValid != tt.expected { 48 | t.Fatalf("test %d (%s) expected %t but got %t", i, tt.input, tt.expected, isValid) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/elf_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // not supported; dummy struct 10 | type BPFKProbePerf struct{} 11 | type SectionParams struct{} 12 | 13 | func (b *Module) Load(parameters map[string]SectionParams) error { 14 | return fmt.Errorf("not supported") 15 | } 16 | 17 | func NewBpfPerfEvent(fileName string) *BPFKProbePerf { 18 | // not supported 19 | return nil 20 | } 21 | 22 | func (b *BPFKProbePerf) Load() error { 23 | return fmt.Errorf("not supported") 24 | } 25 | 26 | func (b *BPFKProbePerf) PollStart(mapName string, receiverChan chan []byte, lostChan chan uint64) { 27 | // not supported 28 | return 29 | } 30 | 31 | func (b *BPFKProbePerf) PollStop(mapName string) { 32 | // not supported 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int pinning; 10 | char namespace[BUF_SIZE_MAP_NS]; 11 | } bpf_map_def; 12 | 13 | enum bpf_pin_type { 14 | PIN_NONE = 0, 15 | PIN_OBJECT_NS, 16 | PIN_GLOBAL_NS, 17 | PIN_CUSTOM_NS, 18 | }; 19 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/kernel_version.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016-2017 Kinvolk 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "regexp" 23 | "strconv" 24 | "strings" 25 | "syscall" 26 | ) 27 | 28 | var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`) 29 | 30 | // KernelVersionFromReleaseString converts a release string with format 31 | // 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format. 32 | // That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c) 33 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) { 34 | versionParts := versionRegex.FindStringSubmatch(releaseString) 35 | if len(versionParts) != 4 { 36 | return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) 37 | } 38 | major, err := strconv.Atoi(versionParts[1]) 39 | if err != nil { 40 | return 0, err 41 | } 42 | 43 | minor, err := strconv.Atoi(versionParts[2]) 44 | if err != nil { 45 | return 0, err 46 | } 47 | 48 | patch, err := strconv.Atoi(versionParts[3]) 49 | if err != nil { 50 | return 0, err 51 | } 52 | out := major*256*256 + minor*256 + patch 53 | return uint32(out), nil 54 | } 55 | 56 | func currentVersionUname() (uint32, error) { 57 | var buf syscall.Utsname 58 | if err := syscall.Uname(&buf); err != nil { 59 | return 0, err 60 | } 61 | releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00") 62 | return KernelVersionFromReleaseString(releaseString) 63 | } 64 | 65 | func currentVersionUbuntu() (uint32, error) { 66 | procVersion, err := ioutil.ReadFile("/proc/version_signature") 67 | if err != nil { 68 | return 0, err 69 | } 70 | var u1, u2, releaseString string 71 | _, err = fmt.Sscanf(string(procVersion), "%s %s %s", &u1, &u2, &releaseString) 72 | if err != nil { 73 | return 0, err 74 | } 75 | return KernelVersionFromReleaseString(releaseString) 76 | } 77 | 78 | var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+) .*`) 79 | 80 | func currentVersionDebian() (uint32, error) { 81 | procVersion, err := ioutil.ReadFile("/proc/version") 82 | if err != nil { 83 | return 0, err 84 | } 85 | match := debianVersionRegex.FindStringSubmatch(string(procVersion)) 86 | if len(match) != 2 { 87 | return 0, fmt.Errorf("failed to get kernel version from /proc/version: %s", procVersion) 88 | } 89 | return KernelVersionFromReleaseString(match[1]) 90 | } 91 | 92 | // CurrentKernelVersion returns the current kernel version in 93 | // LINUX_VERSION_CODE format (see KernelVersionFromReleaseString()) 94 | func CurrentKernelVersion() (uint32, error) { 95 | // We need extra checks for Debian and Ubuntu as they modify 96 | // the kernel version patch number for compatibilty with 97 | // out-of-tree modules. Linux perf tools do the same for Ubuntu 98 | // systems: https://github.com/torvalds/linux/commit/d18acd15c 99 | // 100 | // See also: 101 | // https://kernel-handbook.alioth.debian.org/ch-versions.html 102 | // https://wiki.ubuntu.com/Kernel/FAQ 103 | version, err := currentVersionUbuntu() 104 | if err == nil { 105 | return version, nil 106 | } 107 | version, err = currentVersionDebian() 108 | if err == nil { 109 | return version, nil 110 | } 111 | return currentVersionUname() 112 | } 113 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/kernel_version_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2017 Kinvolk 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | var testData = []struct { 24 | succeed bool 25 | releaseString string 26 | kernelVersion uint32 27 | }{ 28 | {true, "4.1.2-3", 262402}, 29 | {true, "4.8.14-200.fc24.x86_64", 264206}, 30 | {true, "4.1.2-3foo", 262402}, 31 | {true, "4.1.2foo-1", 262402}, 32 | {true, "4.1.2-rkt-v1", 262402}, 33 | {true, "4.1.2rkt-v1", 262402}, 34 | {true, "4.1.2-3 foo", 262402}, 35 | {false, "foo 4.1.2-3", 0}, 36 | {true, "4.1.2", 262402}, 37 | {false, ".4.1.2", 0}, 38 | {false, "4.1.", 0}, 39 | {false, "4.1", 0}, 40 | } 41 | 42 | func TestKernelVersionFromReleaseString(t *testing.T) { 43 | for _, test := range testData { 44 | version, err := KernelVersionFromReleaseString(test.releaseString) 45 | if err != nil && test.succeed { 46 | t.Errorf("expected %q to succeed: %s", test.releaseString, err) 47 | } else if err == nil && !test.succeed { 48 | t.Errorf("expected %q to fail", test.releaseString) 49 | } 50 | if version != test.kernelVersion { 51 | t.Errorf("expected kernel version %d, got %d", test.kernelVersion, version) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/module_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | type Module struct{} 11 | type Kprobe struct{} 12 | type CgroupProgram struct{} 13 | type AttachType struct{} 14 | 15 | func NewModule(fileName string) *Module { 16 | return nil 17 | } 18 | 19 | func NewModuleFromReader(fileReader io.ReaderAt) *Module { 20 | return nil 21 | } 22 | 23 | func (b *Module) EnableKprobe(secName string, maxactive int) error { 24 | return fmt.Errorf("not supported") 25 | } 26 | 27 | func (b *Module) IterKprobes() <-chan *Kprobe { 28 | return nil 29 | } 30 | 31 | func (b *Module) EnableKprobes(maxactive int) error { 32 | return fmt.Errorf("not supported") 33 | } 34 | 35 | func (b *Module) IterCgroupProgram() <-chan *CgroupProgram { 36 | return nil 37 | } 38 | 39 | func (b *Module) CgroupProgram(name string) *CgroupProgram { 40 | return nil 41 | } 42 | 43 | func (b *Module) Kprobe(name string) *Kprobe { 44 | return nil 45 | } 46 | 47 | func (b *Module) AttachProgram(cgroupProg *CgroupProgram, cgroupPath string, attachType AttachType) error { 48 | return fmt.Errorf("not supported") 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/perf.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016 Cilium Project 4 | // Copyright 2016 Sylvain Afchain 5 | // Copyright 2016 Kinvolk 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | package elf 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | "sort" 25 | "syscall" 26 | "unsafe" 27 | ) 28 | 29 | /* 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // from https://github.com/cilium/cilium/blob/master/pkg/bpf/perf.go 38 | 39 | struct event_sample { 40 | struct perf_event_header header; 41 | uint32_t size; 42 | uint8_t data[]; 43 | }; 44 | 45 | struct read_state { 46 | void *buf; 47 | int buf_len; 48 | }; 49 | 50 | static int perf_event_read(int page_count, int page_size, void *_state, 51 | void *_header, void *_sample_ptr, void *_lost_ptr) 52 | { 53 | volatile struct perf_event_mmap_page *header = _header; 54 | uint64_t data_head = *((volatile uint64_t *) &header->data_head); 55 | uint64_t data_tail = header->data_tail; 56 | uint64_t raw_size = (uint64_t)page_count * page_size; 57 | void *base = ((uint8_t *)header) + page_size; 58 | struct read_state *state = _state; 59 | struct event_sample *e; 60 | void *begin, *end; 61 | void **sample_ptr = (void **) _sample_ptr; 62 | void **lost_ptr = (void **) _lost_ptr; 63 | 64 | // No data to read on this ring 65 | __sync_synchronize(); 66 | if (data_head == data_tail) 67 | return 0; 68 | 69 | begin = base + data_tail % raw_size; 70 | e = begin; 71 | end = base + (data_tail + e->header.size) % raw_size; 72 | 73 | if (state->buf_len < e->header.size || !state->buf) { 74 | state->buf = realloc(state->buf, e->header.size); 75 | state->buf_len = e->header.size; 76 | } 77 | 78 | if (end < begin) { 79 | uint64_t len = base + raw_size - begin; 80 | 81 | memcpy(state->buf, begin, len); 82 | memcpy((char *) state->buf + len, base, e->header.size - len); 83 | 84 | e = state->buf; 85 | } else { 86 | memcpy(state->buf, begin, e->header.size); 87 | } 88 | 89 | switch (e->header.type) { 90 | case PERF_RECORD_SAMPLE: 91 | *sample_ptr = state->buf; 92 | break; 93 | case PERF_RECORD_LOST: 94 | *lost_ptr = state->buf; 95 | break; 96 | } 97 | 98 | __sync_synchronize(); 99 | header->data_tail += e->header.size; 100 | 101 | return e->header.type; 102 | } 103 | */ 104 | import "C" 105 | 106 | type PerfMap struct { 107 | name string 108 | program *Module 109 | pageCount int 110 | receiverChan chan []byte 111 | lostChan chan uint64 112 | pollStop chan struct{} 113 | timestamp func(*[]byte) uint64 114 | } 115 | 116 | // Matching 'struct perf_event_sample in kernel sources 117 | type PerfEventSample struct { 118 | PerfEventHeader 119 | Size uint32 120 | data byte // Size bytes of data 121 | } 122 | 123 | func InitPerfMap(b *Module, mapName string, receiverChan chan []byte, lostChan chan uint64) (*PerfMap, error) { 124 | m, ok := b.maps[mapName] 125 | if !ok { 126 | return nil, fmt.Errorf("no map with name %s", mapName) 127 | } 128 | if receiverChan == nil { 129 | return nil, fmt.Errorf("receiverChan is nil") 130 | } 131 | // Maps are initialized in b.Load(), nothing to do here 132 | return &PerfMap{ 133 | name: mapName, 134 | program: b, 135 | pageCount: m.pageCount, 136 | receiverChan: receiverChan, 137 | lostChan: lostChan, 138 | pollStop: make(chan struct{}), 139 | }, nil 140 | } 141 | 142 | // SetTimestampFunc registers a timestamp callback that will be used to 143 | // reorder the perf events chronologically. 144 | // 145 | // If not set, the order of events sent through receiverChan is not guaranteed. 146 | // 147 | // Typically, the ebpf program will use bpf_ktime_get_ns() to get a timestamp 148 | // and store it in the perf event. The perf event struct is opaque to this 149 | // package, hence the need for a callback. 150 | func (pm *PerfMap) SetTimestampFunc(timestamp func(*[]byte) uint64) { 151 | pm.timestamp = timestamp 152 | } 153 | 154 | func (pm *PerfMap) PollStart() { 155 | incoming := OrderedBytesArray{timestamp: pm.timestamp} 156 | 157 | m, ok := pm.program.maps[pm.name] 158 | if !ok { 159 | // should not happen or only when pm.program is 160 | // suddenly changed 161 | panic(fmt.Sprintf("cannot find map %q", pm.name)) 162 | } 163 | 164 | go func() { 165 | cpuCount := len(m.pmuFDs) 166 | pageSize := os.Getpagesize() 167 | state := C.struct_read_state{} 168 | 169 | defer func() { 170 | close(pm.receiverChan) 171 | if pm.lostChan != nil { 172 | close(pm.lostChan) 173 | } 174 | }() 175 | 176 | for { 177 | select { 178 | case <-pm.pollStop: 179 | break 180 | default: 181 | perfEventPoll(m.pmuFDs) 182 | } 183 | 184 | harvestLoop: 185 | for { 186 | select { 187 | case <-pm.pollStop: 188 | return 189 | default: 190 | } 191 | 192 | var harvestCount C.int 193 | beforeHarvest := nowNanoseconds() 194 | for cpu := 0; cpu < cpuCount; cpu++ { 195 | ringBufferLoop: 196 | for { 197 | var sample *PerfEventSample 198 | var lost *PerfEventLost 199 | 200 | ok := C.perf_event_read(C.int(pm.pageCount), C.int(pageSize), 201 | unsafe.Pointer(&state), unsafe.Pointer(m.headers[cpu]), 202 | unsafe.Pointer(&sample), unsafe.Pointer(&lost)) 203 | 204 | switch ok { 205 | case 0: 206 | break ringBufferLoop // nothing to read 207 | case C.PERF_RECORD_SAMPLE: 208 | size := sample.Size - 4 209 | b := C.GoBytes(unsafe.Pointer(&sample.data), C.int(size)) 210 | incoming.bytesArray = append(incoming.bytesArray, b) 211 | harvestCount++ 212 | if pm.timestamp == nil { 213 | continue ringBufferLoop 214 | } 215 | if incoming.timestamp(&b) > beforeHarvest { 216 | // see comment below 217 | break ringBufferLoop 218 | } 219 | case C.PERF_RECORD_LOST: 220 | if pm.lostChan != nil { 221 | select { 222 | case pm.lostChan <- lost.Lost: 223 | case <-pm.pollStop: 224 | return 225 | } 226 | } 227 | default: 228 | // ignore unknown events 229 | } 230 | } 231 | } 232 | 233 | if incoming.timestamp != nil { 234 | sort.Sort(incoming) 235 | } 236 | for incoming.Len() > 0 { 237 | if incoming.timestamp != nil && incoming.timestamp(&incoming.bytesArray[0]) > beforeHarvest { 238 | // This record has been sent after the beginning of the harvest. Stop 239 | // processing here to keep the order. "incoming" is sorted, so the next 240 | // elements also must not be processed now. 241 | break harvestLoop 242 | } 243 | select { 244 | case pm.receiverChan <- incoming.bytesArray[0]: 245 | case <-pm.pollStop: 246 | return 247 | } 248 | // remove first element 249 | incoming.bytesArray = incoming.bytesArray[1:] 250 | } 251 | if harvestCount == 0 && len(incoming.bytesArray) == 0 { 252 | break harvestLoop 253 | } 254 | } 255 | } 256 | }() 257 | } 258 | 259 | // PollStop stops the goroutine that polls the perf event map. 260 | // Callers must not close receiverChan or lostChan: they will be automatically 261 | // closed on the sender side. 262 | func (pm *PerfMap) PollStop() { 263 | close(pm.pollStop) 264 | } 265 | 266 | func perfEventPoll(fds []C.int) error { 267 | var pfds []C.struct_pollfd 268 | 269 | for i, _ := range fds { 270 | var pfd C.struct_pollfd 271 | 272 | pfd.fd = fds[i] 273 | pfd.events = C.POLLIN 274 | 275 | pfds = append(pfds, pfd) 276 | } 277 | _, err := C.poll(&pfds[0], C.nfds_t(len(fds)), 500) 278 | if err != nil { 279 | return fmt.Errorf("error polling: %v", err.(syscall.Errno)) 280 | } 281 | 282 | return nil 283 | } 284 | 285 | // Assume the timestamp is at the beginning of the user struct 286 | type OrderedBytesArray struct { 287 | bytesArray [][]byte 288 | timestamp func(*[]byte) uint64 289 | } 290 | 291 | func (a OrderedBytesArray) Len() int { 292 | return len(a.bytesArray) 293 | } 294 | 295 | func (a OrderedBytesArray) Swap(i, j int) { 296 | a.bytesArray[i], a.bytesArray[j] = a.bytesArray[j], a.bytesArray[i] 297 | } 298 | 299 | func (a OrderedBytesArray) Less(i, j int) bool { 300 | return a.timestamp(&a.bytesArray[i]) < a.timestamp(&a.bytesArray[j]) 301 | } 302 | 303 | // Matching 'struct perf_event_header in 304 | type PerfEventHeader struct { 305 | Type uint32 306 | Misc uint16 307 | TotalSize uint16 308 | } 309 | 310 | // Matching 'struct perf_event_lost in kernel sources 311 | type PerfEventLost struct { 312 | PerfEventHeader 313 | Id uint64 314 | Lost uint64 315 | } 316 | 317 | // nowNanoseconds returns a time that can be compared to bpf_ktime_get_ns() 318 | func nowNanoseconds() uint64 { 319 | var ts syscall.Timespec 320 | syscall.Syscall(syscall.SYS_CLOCK_GETTIME, 1 /* CLOCK_MONOTONIC */, uintptr(unsafe.Pointer(&ts)), 0) 321 | sec, nsec := ts.Unix() 322 | return 1000*1000*1000*uint64(sec) + uint64(nsec) 323 | } 324 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/perf_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import "fmt" 6 | 7 | type PerfMap struct{} 8 | 9 | func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap, error) { 10 | return nil, fmt.Errorf("not supported") 11 | } 12 | 13 | func (pm *PerfMap) SetTimestampFunc(timestamp func(*[]byte) uint64) {} 14 | 15 | func (pm *PerfMap) PollStart() {} 16 | 17 | func (pm *PerfMap) PollStop() {} 18 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/pinning.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | "unsafe" 11 | 12 | "github.com/iovisor/gobpf/pkg/bpffs" 13 | ) 14 | 15 | /* 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern __u64 ptr_to_u64(void *); 22 | 23 | int bpf_pin_object(int fd, const char *pathname) 24 | { 25 | union bpf_attr attr = {}; 26 | 27 | attr.pathname = ptr_to_u64((void *)pathname); 28 | attr.bpf_fd = fd; 29 | 30 | return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr)); 31 | } 32 | */ 33 | import "C" 34 | 35 | const ( 36 | BPFDirGlobals = "globals" // as in iproute2's BPF_DIR_GLOBALS 37 | BPFFSPath = "/sys/fs/bpf/" 38 | ) 39 | 40 | func validPinPath(PinPath string) bool { 41 | if !strings.HasPrefix(PinPath, BPFFSPath) { 42 | return false 43 | } 44 | 45 | return filepath.Clean(PinPath) == PinPath 46 | } 47 | 48 | func pinObject(fd int, pinPath string) error { 49 | mounted, err := bpffs.IsMounted() 50 | if err != nil { 51 | return fmt.Errorf("error checking if %q is mounted: %v", BPFFSPath, err) 52 | } 53 | if !mounted { 54 | return fmt.Errorf("bpf fs not mounted at %q", BPFFSPath) 55 | } 56 | err = os.MkdirAll(filepath.Dir(pinPath), 0755) 57 | if err != nil { 58 | return fmt.Errorf("error creating directory %q: %v", filepath.Dir(pinPath), err) 59 | } 60 | _, err = os.Stat(pinPath) 61 | if err == nil { 62 | return fmt.Errorf("aborting, found file at %q", pinPath) 63 | } 64 | if err != nil && !os.IsNotExist(err) { 65 | return fmt.Errorf("failed to stat %q: %v", pinPath, err) 66 | } 67 | pinPathC := C.CString(pinPath) 68 | defer C.free(unsafe.Pointer(pinPathC)) 69 | ret, err := C.bpf_pin_object(C.int(fd), pinPathC) 70 | if ret != 0 { 71 | return fmt.Errorf("error pinning object to %q: %v", pinPath, err) 72 | } 73 | return nil 74 | } 75 | 76 | // PinObjectGlobal pins and object to a name in a namespaces 77 | // e.g. `/sys/fs/bpf/my-namespace/globals/my-name` 78 | func PinObjectGlobal(fd int, namespace, name string) error { 79 | pinPath := filepath.Join(BPFFSPath, namespace, BPFDirGlobals, name) 80 | return pinObject(fd, pinPath) 81 | } 82 | 83 | // PinObject pins an object to a path 84 | func PinObject(fd int, pinPath string) error { 85 | if !validPinPath(pinPath) { 86 | return fmt.Errorf("not a valid pin path: %s", pinPath) 87 | } 88 | return pinObject(fd, pinPath) 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/table.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016 Cilium Project 4 | // Copyright 2016 Sylvain Afchain 5 | // Copyright 2016 Kinvolk 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | package elf 20 | 21 | import ( 22 | "fmt" 23 | "syscall" 24 | "unsafe" 25 | ) 26 | 27 | /* 28 | #include 29 | #include 30 | 31 | extern __u64 ptr_to_u64(void *); 32 | 33 | // from https://github.com/cilium/cilium/blob/master/pkg/bpf/bpf.go 34 | // Apache License, Version 2.0 35 | 36 | static void create_bpf_update_elem(int fd, void *key, void *value, 37 | unsigned long long flags, void *attr) 38 | { 39 | union bpf_attr* ptr_bpf_attr; 40 | ptr_bpf_attr = (union bpf_attr*)attr; 41 | ptr_bpf_attr->map_fd = fd; 42 | ptr_bpf_attr->key = ptr_to_u64(key); 43 | ptr_bpf_attr->value = ptr_to_u64(value); 44 | ptr_bpf_attr->flags = flags; 45 | } 46 | 47 | static void create_bpf_lookup_elem(int fd, void *key, void *value, void *attr) 48 | { 49 | union bpf_attr* ptr_bpf_attr; 50 | ptr_bpf_attr = (union bpf_attr*)attr; 51 | ptr_bpf_attr->map_fd = fd; 52 | ptr_bpf_attr->key = ptr_to_u64(key); 53 | ptr_bpf_attr->value = ptr_to_u64(value); 54 | } 55 | 56 | static int next_bpf_elem(int fd, void *key, void *next_key, void *attr) 57 | { 58 | union bpf_attr* ptr_bpf_attr; 59 | ptr_bpf_attr = (union bpf_attr*)attr; 60 | ptr_bpf_attr->map_fd = fd; 61 | ptr_bpf_attr->key = ptr_to_u64(key); 62 | ptr_bpf_attr->next_key = ptr_to_u64(next_key); 63 | } 64 | */ 65 | import "C" 66 | 67 | // UpdateElement stores value in key in the map stored in mp. 68 | // The flags can have the following values (if you include "uapi/linux/bpf.h"): 69 | // C.BPF_ANY to create new element or update existing; 70 | // C.BPF_NOEXIST to create new element if it didn't exist; 71 | // C.BPF_EXIST to update existing element. 72 | func (b *Module) UpdateElement(mp *Map, key, value unsafe.Pointer, flags uint64) error { 73 | uba := C.union_bpf_attr{} 74 | C.create_bpf_update_elem( 75 | C.int(mp.m.fd), 76 | key, 77 | value, 78 | C.ulonglong(flags), 79 | unsafe.Pointer(&uba), 80 | ) 81 | ret, _, err := syscall.Syscall( 82 | C.__NR_bpf, 83 | C.BPF_MAP_UPDATE_ELEM, 84 | uintptr(unsafe.Pointer(&uba)), 85 | unsafe.Sizeof(uba), 86 | ) 87 | 88 | if ret != 0 || err != 0 { 89 | return fmt.Errorf("unable to update element: %s", err) 90 | } 91 | 92 | return nil 93 | } 94 | 95 | // LookupElement looks up the given key in the the map stored in mp. 96 | // The value is stored in the value unsafe.Pointer. 97 | func (b *Module) LookupElement(mp *Map, key, value unsafe.Pointer) error { 98 | uba := C.union_bpf_attr{} 99 | C.create_bpf_lookup_elem( 100 | C.int(mp.m.fd), 101 | key, 102 | value, 103 | unsafe.Pointer(&uba), 104 | ) 105 | ret, _, err := syscall.Syscall( 106 | C.__NR_bpf, 107 | C.BPF_MAP_LOOKUP_ELEM, 108 | uintptr(unsafe.Pointer(&uba)), 109 | unsafe.Sizeof(uba), 110 | ) 111 | 112 | if ret != 0 || err != 0 { 113 | return fmt.Errorf("unable to lookup element: %s", err) 114 | } 115 | 116 | return nil 117 | } 118 | 119 | // DeleteElement deletes the given key in the the map stored in mp. 120 | // The key is stored in the key unsafe.Pointer. 121 | func (b *Module) DeleteElement(mp *Map, key unsafe.Pointer) error { 122 | uba := C.union_bpf_attr{} 123 | value := unsafe.Pointer(nil) 124 | C.create_bpf_lookup_elem( 125 | C.int(mp.m.fd), 126 | key, 127 | value, 128 | unsafe.Pointer(&uba), 129 | ) 130 | ret, _, err := syscall.Syscall( 131 | C.__NR_bpf, 132 | C.BPF_MAP_DELETE_ELEM, 133 | uintptr(unsafe.Pointer(&uba)), 134 | unsafe.Sizeof(uba), 135 | ) 136 | 137 | if ret != 0 || err != 0 { 138 | return fmt.Errorf("unable to delete element: %s", err) 139 | } 140 | 141 | return nil 142 | } 143 | 144 | // LookupNextElement looks up the next element in mp using the given key. 145 | // The next key and the value are stored in the nextKey and value parameter. 146 | // Returns false at the end of the mp. 147 | func (b *Module) LookupNextElement(mp *Map, key, nextKey, value unsafe.Pointer) (bool, error) { 148 | uba := C.union_bpf_attr{} 149 | C.next_bpf_elem( 150 | C.int(mp.m.fd), 151 | key, 152 | nextKey, 153 | unsafe.Pointer(&uba), 154 | ) 155 | ret, _, err := syscall.Syscall( 156 | C.__NR_bpf, 157 | C.BPF_MAP_GET_NEXT_KEY, 158 | uintptr(unsafe.Pointer(&uba)), 159 | unsafe.Sizeof(uba), 160 | ) 161 | if err != 0 { 162 | return false, fmt.Errorf("unable to find next element: %s", err) 163 | } 164 | if ret != 0 { 165 | return false, nil 166 | } 167 | 168 | if err := b.LookupElement(mp, nextKey, value); err != nil { 169 | return false, err 170 | } 171 | return true, nil 172 | } 173 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/utsname_int8.go: -------------------------------------------------------------------------------- 1 | // +build linux,amd64 linux,arm64 2 | 3 | package elf 4 | 5 | func utsnameStr(in []int8) string { 6 | out := make([]byte, len(in)) 7 | for i := 0; i < len(in); i++ { 8 | if in[i] == 0 { 9 | break 10 | } 11 | out = append(out, byte(in[i])) 12 | } 13 | return string(out) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/elf/utsname_uint8.go: -------------------------------------------------------------------------------- 1 | // +build linux,arm linux,ppc64 linux,ppc64le s390x 2 | 3 | package elf 4 | 5 | func utsnameStr(in []uint8) string { 6 | out := make([]byte, len(in)) 7 | for i := 0; i < len(in); i++ { 8 | if in[i] == 0 { 9 | break 10 | } 11 | out = append(out, byte(in[i])) 12 | } 13 | return string(out) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/bash_readline/bash_readline.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Louis McCormack 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "encoding/binary" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | 24 | bpf "github.com/iovisor/gobpf/bcc" 25 | ) 26 | 27 | const source string = ` 28 | #include 29 | 30 | struct readline_event_t { 31 | u32 pid; 32 | char str[80]; 33 | } __attribute__((packed)); 34 | 35 | BPF_PERF_OUTPUT(readline_events); 36 | 37 | int get_return_value(struct pt_regs *ctx) { 38 | struct readline_event_t event = {}; 39 | u32 pid; 40 | if (!PT_REGS_RC(ctx)) 41 | return 0; 42 | pid = bpf_get_current_pid_tgid(); 43 | event.pid = pid; 44 | bpf_probe_read(&event.str, sizeof(event.str), (void *)PT_REGS_RC(ctx)); 45 | readline_events.perf_submit(ctx, &event, sizeof(event)); 46 | 47 | return 0; 48 | } 49 | ` 50 | 51 | type readlineEvent struct { 52 | Pid uint32 53 | Str [80]byte 54 | } 55 | 56 | func main() { 57 | m := bpf.NewModule(source, []string{}) 58 | defer m.Close() 59 | 60 | readlineUretprobe, err := m.LoadUprobe("get_return_value") 61 | if err != nil { 62 | fmt.Fprintf(os.Stderr, "Failed to load get_return_value: %s\n", err) 63 | os.Exit(1) 64 | } 65 | 66 | err = m.AttachUretprobe("/bin/bash", "readline", readlineUretprobe, -1) 67 | if err != nil { 68 | fmt.Fprintf(os.Stderr, "Failed to attach return_value: %s\n", err) 69 | os.Exit(1) 70 | } 71 | 72 | table := bpf.NewTable(m.TableId("readline_events"), m) 73 | 74 | channel := make(chan []byte) 75 | 76 | perfMap, err := bpf.InitPerfMap(table, channel) 77 | if err != nil { 78 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 79 | os.Exit(1) 80 | } 81 | 82 | sig := make(chan os.Signal, 1) 83 | signal.Notify(sig, os.Interrupt, os.Kill) 84 | 85 | fmt.Printf("%10s\t%s\n", "PID", "COMMAND") 86 | go func() { 87 | var event readlineEvent 88 | for { 89 | data := <-channel 90 | err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event) 91 | if err != nil { 92 | fmt.Printf("failed to decode received data: %s\n", err) 93 | continue 94 | } 95 | // Convert C string (null-terminated) to Go string 96 | comm := string(event.Str[:bytes.IndexByte(event.Str[:], 0)]) 97 | fmt.Printf("%10d\t%s\n", event.Pid, comm) 98 | } 99 | }() 100 | 101 | perfMap.Start() 102 | <-sig 103 | perfMap.Stop() 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/execsnoop/execsnoop.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package main 14 | 15 | import ( 16 | "bufio" 17 | "bytes" 18 | "encoding/binary" 19 | "flag" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | "strconv" 24 | "strings" 25 | "unsafe" 26 | 27 | bpf "github.com/iovisor/gobpf/bcc" 28 | ) 29 | 30 | import "C" 31 | 32 | type EventType int32 33 | 34 | const ( 35 | eventArg EventType = iota 36 | eventRet 37 | ) 38 | 39 | const source string = ` 40 | #include 41 | #include 42 | #include 43 | 44 | #define ARGSIZE 128 45 | 46 | enum event_type { 47 | EVENT_ARG, 48 | EVENT_RET, 49 | }; 50 | 51 | struct data_t { 52 | u64 pid; // PID as in the userspace term (i.e. task->tgid in kernel) 53 | u64 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel) 54 | char comm[TASK_COMM_LEN]; 55 | enum event_type type; 56 | char argv[ARGSIZE]; 57 | int retval; 58 | }; 59 | 60 | BPF_PERF_OUTPUT(events); 61 | 62 | static int __submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 63 | { 64 | bpf_probe_read(data->argv, sizeof(data->argv), ptr); 65 | events.perf_submit(ctx, data, sizeof(struct data_t)); 66 | return 1; 67 | } 68 | 69 | static int submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 70 | { 71 | const char *argp = NULL; 72 | bpf_probe_read(&argp, sizeof(argp), ptr); 73 | if (argp) { 74 | return __submit_arg(ctx, (void *)(argp), data); 75 | } 76 | return 0; 77 | } 78 | 79 | int syscall__execve(struct pt_regs *ctx, 80 | const char __user *filename, 81 | const char __user *const __user *__argv, 82 | const char __user *const __user *__envp) 83 | { 84 | // create data here and pass to submit_arg to save stack space (#555) 85 | struct data_t data = {}; 86 | struct task_struct *task; 87 | 88 | data.pid = bpf_get_current_pid_tgid() >> 32; 89 | 90 | task = (struct task_struct *)bpf_get_current_task(); 91 | // Some kernels, like Ubuntu 4.13.0-generic, return 0 92 | // as the real_parent->tgid. 93 | // We use the getPpid function as a fallback in those cases. 94 | // See https://github.com/iovisor/bcc/issues/1883. 95 | data.ppid = task->real_parent->tgid; 96 | 97 | bpf_get_current_comm(&data.comm, sizeof(data.comm)); 98 | data.type = EVENT_ARG; 99 | 100 | __submit_arg(ctx, (void *)filename, &data); 101 | 102 | // skip first arg, as we submitted filename 103 | #pragma unroll 104 | for (int i = 1; i < MAX_ARGS; i++) { 105 | if (submit_arg(ctx, (void *)&__argv[i], &data) == 0) 106 | goto out; 107 | } 108 | 109 | // handle truncated argument list 110 | char ellipsis[] = "..."; 111 | __submit_arg(ctx, (void *)ellipsis, &data); 112 | out: 113 | return 0; 114 | } 115 | 116 | int do_ret_sys_execve(struct pt_regs *ctx) 117 | { 118 | struct data_t data = {}; 119 | struct task_struct *task; 120 | 121 | data.pid = bpf_get_current_pid_tgid() >> 32; 122 | 123 | task = (struct task_struct *)bpf_get_current_task(); 124 | // Some kernels, like Ubuntu 4.13.0-generic, return 0 125 | // as the real_parent->tgid. 126 | // We use the getPpid function as a fallback in those cases. 127 | // See https://github.com/iovisor/bcc/issues/1883. 128 | data.ppid = task->real_parent->tgid; 129 | 130 | bpf_get_current_comm(&data.comm, sizeof(data.comm)); 131 | data.type = EVENT_RET; 132 | data.retval = PT_REGS_RC(ctx); 133 | events.perf_submit(ctx, &data, sizeof(data)); 134 | 135 | return 0; 136 | } 137 | ` 138 | 139 | type execveEvent struct { 140 | Pid uint64 141 | Ppid uint64 142 | Comm [16]byte 143 | Type int32 144 | Argv [128]byte 145 | RetVal int32 146 | } 147 | 148 | type eventPayload struct { 149 | Time string `json:"time,omitempty"` 150 | Comm string `json:"comm"` 151 | Pid uint64 `json:"pid"` 152 | Ppid string `json:"ppid"` 153 | Argv string `json:"argv"` 154 | RetVal int32 `json:"retval"` 155 | } 156 | 157 | // getPpid is a fallback to read the parent PID from /proc. 158 | // Some kernel versions, like 4.13.0 return 0 getting the parent PID 159 | // from the current task, so we need to use this fallback to have 160 | // the parent PID in any kernel. 161 | func getPpid(pid uint64) uint64 { 162 | f, err := os.OpenFile(fmt.Sprintf("/proc/%d/status", pid), os.O_RDONLY, os.ModePerm) 163 | if err != nil { 164 | return 0 165 | } 166 | defer f.Close() 167 | 168 | sc := bufio.NewScanner(f) 169 | for sc.Scan() { 170 | text := sc.Text() 171 | if strings.Contains(text, "PPid:") { 172 | f := strings.Fields(text) 173 | i, _ := strconv.ParseUint(f[len(f)-1], 10, 64) 174 | return i 175 | } 176 | } 177 | return 0 178 | } 179 | 180 | func main() { 181 | run() 182 | } 183 | 184 | func run() { 185 | traceFailed := flag.Bool("x", false, "trace failed exec()s") 186 | timestamps := flag.Bool("t", false, "include timestamps") 187 | quotemarks := flag.Bool("q", false, `add "quotemarks" around arguments`) 188 | filterComm := flag.String("n", "", `only print command lines containing a name, for example "main"`) 189 | filterArg := flag.String("l", "", `only print command where arguments contain an argument, for example "tpkg"`) 190 | format := flag.String("o", "table", "output format, either table or json") 191 | pretty := flag.Bool("p", false, "pretty print json output") 192 | maxArgs := flag.Uint64("m", 20, "maximum number of arguments parsed and displayed, defaults to 20") 193 | 194 | flag.Parse() 195 | 196 | m := bpf.NewModule(strings.Replace(source, "MAX_ARGS", strconv.FormatUint(*maxArgs, 10), -1), []string{}) 197 | defer m.Close() 198 | 199 | fnName := bpf.GetSyscallFnName("execve") 200 | 201 | kprobe, err := m.LoadKprobe("syscall__execve") 202 | if err != nil { 203 | fmt.Fprintf(os.Stderr, "Failed to load syscall__execve: %s\n", err) 204 | os.Exit(1) 205 | } 206 | 207 | // passing -1 for maxActive signifies to use the default 208 | // according to the kernel kprobes documentation 209 | if err := m.AttachKprobe(fnName, kprobe, -1); err != nil { 210 | fmt.Fprintf(os.Stderr, "Failed to attach syscall__execve: %s\n", err) 211 | os.Exit(1) 212 | } 213 | 214 | kretprobe, err := m.LoadKprobe("do_ret_sys_execve") 215 | if err != nil { 216 | fmt.Fprintf(os.Stderr, "Failed to load do_ret_sys_execve: %s\n", err) 217 | os.Exit(1) 218 | } 219 | 220 | // passing -1 for maxActive signifies to use the default 221 | // according to the kernel kretprobes documentation 222 | if err := m.AttachKretprobe(fnName, kretprobe, -1); err != nil { 223 | fmt.Fprintf(os.Stderr, "Failed to attach do_ret_sys_execve: %s\n", err) 224 | os.Exit(1) 225 | } 226 | 227 | table := bpf.NewTable(m.TableId("events"), m) 228 | 229 | channel := make(chan []byte, 1000) 230 | 231 | perfMap, err := bpf.InitPerfMap(table, channel) 232 | if err != nil { 233 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 234 | os.Exit(1) 235 | } 236 | 237 | sig := make(chan os.Signal, 1) 238 | signal.Notify(sig, os.Interrupt, os.Kill) 239 | 240 | go func() { 241 | out := newOutput(*format, *pretty, *timestamps) 242 | out.PrintHeader() 243 | 244 | args := make(map[uint64][]string) 245 | 246 | for { 247 | data := <-channel 248 | 249 | var event execveEvent 250 | err := binary.Read(bytes.NewBuffer(data), bpf.GetHostByteOrder(), &event) 251 | 252 | if err != nil { 253 | fmt.Printf("failed to decode received data: %s\n", err) 254 | continue 255 | } 256 | 257 | if eventArg == EventType(event.Type) { 258 | e, ok := args[event.Pid] 259 | if !ok { 260 | e = make([]string, 0) 261 | } 262 | argv := (*C.char)(unsafe.Pointer(&event.Argv)) 263 | 264 | e = append(e, C.GoString(argv)) 265 | args[event.Pid] = e 266 | } else { 267 | if event.RetVal != 0 && !*traceFailed { 268 | delete(args, event.Pid) 269 | continue 270 | } 271 | 272 | comm := C.GoString((*C.char)(unsafe.Pointer(&event.Comm))) 273 | if *filterComm != "" && !strings.Contains(comm, *filterComm) { 274 | delete(args, event.Pid) 275 | continue 276 | } 277 | 278 | argv, ok := args[event.Pid] 279 | if !ok { 280 | continue 281 | } 282 | 283 | if *filterArg != "" && !strings.Contains(strings.Join(argv, " "), *filterArg) { 284 | delete(args, event.Pid) 285 | continue 286 | } 287 | 288 | p := eventPayload{ 289 | Pid: event.Pid, 290 | Ppid: "?", 291 | Comm: comm, 292 | RetVal: event.RetVal, 293 | } 294 | 295 | if event.Ppid == 0 { 296 | event.Ppid = getPpid(event.Pid) 297 | } 298 | 299 | if event.Ppid != 0 { 300 | p.Ppid = strconv.FormatUint(event.Ppid, 10) 301 | } 302 | 303 | if *quotemarks { 304 | var b bytes.Buffer 305 | for i, a := range argv { 306 | b.WriteString(strings.Replace(a, `"`, `\"`, -1)) 307 | if i != len(argv)-1 { 308 | b.WriteString(" ") 309 | } 310 | } 311 | p.Argv = b.String() 312 | } else { 313 | p.Argv = strings.Join(argv, " ") 314 | } 315 | p.Argv = strings.TrimSpace(strings.Replace(p.Argv, "\n", "\\n", -1)) 316 | 317 | out.PrintLine(p) 318 | delete(args, event.Pid) 319 | } 320 | } 321 | }() 322 | 323 | perfMap.Start() 324 | <-sig 325 | perfMap.Stop() 326 | } 327 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/execsnoop/output.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type output interface { 10 | PrintHeader() 11 | PrintLine(eventPayload) 12 | } 13 | 14 | type timing struct { 15 | start time.Time 16 | } 17 | 18 | func newTiming() timing { 19 | return timing{time.Now()} 20 | } 21 | 22 | func (t timing) Now() float64 { 23 | return time.Now().Sub(t.start).Seconds() 24 | } 25 | 26 | func newOutput(name string, pretty, timestamp bool) output { 27 | switch name { 28 | case "json": 29 | return newJSONOutput(pretty, timestamp) 30 | } 31 | return newTableOutput(timestamp) 32 | } 33 | 34 | type tableOutput struct { 35 | timing timing 36 | timestamp bool 37 | } 38 | 39 | func (t tableOutput) PrintHeader() { 40 | header := "%-16s %-6s %-6s %3s %s\n" 41 | args := []interface{}{"PCOMM", "PID", "PPID", "RET", "ARGS"} 42 | if t.timestamp { 43 | header = "%-8s" + header 44 | args = []interface{}{"TIME(s)", "PCOMM", "PID", "PPID", "RET", "ARGS"} 45 | } 46 | fmt.Printf(header, args...) 47 | } 48 | 49 | func (t tableOutput) PrintLine(e eventPayload) { 50 | header := "%-16s %-6d %-6s %3d %s\n" 51 | args := []interface{}{e.Comm, e.Pid, e.Ppid, e.RetVal, e.Argv} 52 | if t.timestamp { 53 | header = "%-8.3f" + header 54 | args = append([]interface{}{t.timing.Now()}, args...) 55 | } 56 | fmt.Printf(header, args...) 57 | } 58 | 59 | func newTableOutput(timestamp bool) output { 60 | return &tableOutput{newTiming(), timestamp} 61 | } 62 | 63 | type jsonOutput struct { 64 | timing timing 65 | pretty bool 66 | timestamp bool 67 | } 68 | 69 | func (jsonOutput) PrintHeader() { 70 | // jsonOutput doesn't have any header 71 | } 72 | 73 | func (j jsonOutput) PrintLine(e eventPayload) { 74 | if j.timestamp { 75 | e.Time = fmt.Sprintf("%.3f", j.timing.Now()) 76 | } 77 | var m []byte 78 | if j.pretty { 79 | m, _ = json.MarshalIndent(e, "", " ") 80 | } else { 81 | m, _ = json.Marshal(e) 82 | } 83 | if len(m) > 0 { 84 | fmt.Println(string(m)) 85 | } 86 | } 87 | 88 | func newJSONOutput(pretty, timestamp bool) output { 89 | return jsonOutput{newTiming(), pretty, timestamp} 90 | } 91 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/perf/perf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "encoding/binary" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | "unsafe" 24 | 25 | bpf "github.com/iovisor/gobpf/bcc" 26 | ) 27 | 28 | import "C" 29 | 30 | const source string = ` 31 | #include 32 | #include 33 | 34 | typedef struct { 35 | u32 pid; 36 | uid_t uid; 37 | gid_t gid; 38 | int ret; 39 | char filename[256]; 40 | } chown_event_t; 41 | 42 | BPF_PERF_OUTPUT(chown_events); 43 | BPF_HASH(chowncall, u64, chown_event_t); 44 | 45 | int kprobe__sys_fchownat(struct pt_regs *ctx, int dfd, const char *filename, 46 | uid_t uid, gid_t gid, int flag) 47 | { 48 | u64 pid = bpf_get_current_pid_tgid(); 49 | chown_event_t event = { 50 | .pid = pid >> 32, 51 | .uid = uid, 52 | .gid = gid, 53 | }; 54 | bpf_probe_read(&event.filename, sizeof(event.filename), (void *)filename); 55 | chowncall.update(&pid, &event); 56 | return 0; 57 | } 58 | 59 | int kretprobe__sys_fchownat(struct pt_regs *ctx) 60 | { 61 | int ret = PT_REGS_RC(ctx); 62 | u64 pid = bpf_get_current_pid_tgid(); 63 | chown_event_t *eventp = chowncall.lookup(&pid); 64 | if (eventp == 0) { 65 | return 0; 66 | } 67 | chown_event_t event = *eventp; 68 | event.ret = ret; 69 | chown_events.perf_submit(ctx, &event, sizeof(event)); 70 | chowncall.delete(&pid); 71 | return 0; 72 | }; 73 | ` 74 | 75 | type chownEvent struct { 76 | Pid uint32 77 | Uid uint32 78 | Gid uint32 79 | ReturnValue int32 80 | Filename [256]byte 81 | } 82 | 83 | func main() { 84 | m := bpf.NewModule(source, []string{}) 85 | defer m.Close() 86 | 87 | chownKprobe, err := m.LoadKprobe("kprobe__sys_fchownat") 88 | if err != nil { 89 | fmt.Fprintf(os.Stderr, "Failed to load kprobe__sys_fchownat: %s\n", err) 90 | os.Exit(1) 91 | } 92 | 93 | syscallName := bpf.GetSyscallFnName("fchownat") 94 | 95 | // passing -1 for maxActive signifies to use the default 96 | // according to the kernel kprobes documentation 97 | err = m.AttachKprobe(syscallName, chownKprobe, -1) 98 | if err != nil { 99 | fmt.Fprintf(os.Stderr, "Failed to attach kprobe__sys_fchownat: %s\n", err) 100 | os.Exit(1) 101 | } 102 | 103 | chownKretprobe, err := m.LoadKprobe("kretprobe__sys_fchownat") 104 | if err != nil { 105 | fmt.Fprintf(os.Stderr, "Failed to load kretprobe__sys_fchownat: %s\n", err) 106 | os.Exit(1) 107 | } 108 | 109 | // passing -1 for maxActive signifies to use the default 110 | // according to the kernel kretprobes documentation 111 | err = m.AttachKretprobe(syscallName, chownKretprobe, -1) 112 | if err != nil { 113 | fmt.Fprintf(os.Stderr, "Failed to attach kretprobe__sys_fchownat: %s\n", err) 114 | os.Exit(1) 115 | } 116 | 117 | table := bpf.NewTable(m.TableId("chown_events"), m) 118 | 119 | channel := make(chan []byte) 120 | 121 | perfMap, err := bpf.InitPerfMap(table, channel) 122 | if err != nil { 123 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 124 | os.Exit(1) 125 | } 126 | 127 | sig := make(chan os.Signal, 1) 128 | signal.Notify(sig, os.Interrupt, os.Kill) 129 | 130 | go func() { 131 | var event chownEvent 132 | for { 133 | data := <-channel 134 | err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event) 135 | if err != nil { 136 | fmt.Printf("failed to decode received data: %s\n", err) 137 | continue 138 | } 139 | filename := (*C.char)(unsafe.Pointer(&event.Filename)) 140 | fmt.Printf("uid %d gid %d pid %d called fchownat(2) on %s (return value: %d)\n", 141 | event.Uid, event.Gid, event.Pid, C.GoString(filename), event.ReturnValue) 142 | } 143 | }() 144 | 145 | perfMap.Start() 146 | <-sig 147 | perfMap.Stop() 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/strlen_count/strlen_count.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package main 14 | 15 | import ( 16 | "encoding/binary" 17 | "flag" 18 | "fmt" 19 | "os" 20 | "os/signal" 21 | "regexp" 22 | 23 | bpf "github.com/iovisor/gobpf/bcc" 24 | ) 25 | 26 | import "C" 27 | 28 | const source string = ` 29 | #include 30 | typedef char strlenkey_t[80]; 31 | BPF_HASH(counts, strlenkey_t); 32 | 33 | int count(struct pt_regs *ctx) { 34 | if (!PT_REGS_PARM1(ctx)) 35 | return 0; 36 | 37 | strlenkey_t key; 38 | u64 zero = 0, *val; 39 | 40 | bpf_probe_read(&key, sizeof(key), (void *)PT_REGS_PARM1(ctx)); 41 | val = counts.lookup_or_init(&key, &zero); 42 | (*val)++; 43 | return 0; 44 | } 45 | ` 46 | 47 | var ansiEscape = regexp.MustCompile(`[[:cntrl:]]`) 48 | 49 | func main() { 50 | pid := flag.Int("pid", -1, "attach to pid, default is all processes") 51 | flag.Parse() 52 | m := bpf.NewModule(source, []string{}) 53 | defer m.Close() 54 | 55 | strlenUprobe, err := m.LoadUprobe("count") 56 | if err != nil { 57 | fmt.Fprintf(os.Stderr, "Failed to load uprobe count: %s\n", err) 58 | os.Exit(1) 59 | } 60 | 61 | err = m.AttachUprobe("c", "strlen", strlenUprobe, *pid) 62 | if err != nil { 63 | fmt.Fprintf(os.Stderr, "Failed to attach uprobe to strlen: %s\n", err) 64 | os.Exit(1) 65 | } 66 | 67 | table := bpf.NewTable(m.TableId("counts"), m) 68 | 69 | fmt.Println("Tracing strlen()... hit Ctrl-C to end.") 70 | 71 | sig := make(chan os.Signal, 1) 72 | signal.Notify(sig, os.Interrupt) 73 | <-sig 74 | 75 | fmt.Printf("%10s %s\n", "COUNT", "STRING") 76 | for it := table.Iter(); it.Next(); { 77 | k := ansiEscape.ReplaceAll(it.Key(), []byte{}) 78 | v := binary.LittleEndian.Uint64(it.Leaf()) 79 | fmt.Printf("%10d \"%s\"\n", v, k) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/bcc/xdp/xdp_drop.go: -------------------------------------------------------------------------------- 1 | // xdp_drop.go Drop incoming packets on XDP layer and count for which 2 | // protocol type. Based on: 3 | // https://github.com/iovisor/bcc/blob/master/examples/networking/xdp/xdp_drop_count.py 4 | // 5 | // Copyright (c) 2017 GustavoKatel 6 | // Licensed under the Apache License, Version 2.0 (the "License") 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | "os/signal" 14 | 15 | bpf "github.com/iovisor/gobpf/bcc" 16 | ) 17 | 18 | /* 19 | #cgo CFLAGS: -I/usr/include/bcc/compat 20 | #cgo LDFLAGS: -lbcc 21 | #include 22 | #include 23 | void perf_reader_free(void *ptr); 24 | */ 25 | import "C" 26 | 27 | const source string = ` 28 | #define KBUILD_MODNAME "foo" 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | BPF_TABLE("array", int, long, dropcnt, 256); 38 | 39 | static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) { 40 | struct iphdr *iph = data + nh_off; 41 | 42 | if ((void*)&iph[1] > data_end) 43 | return 0; 44 | return iph->protocol; 45 | } 46 | 47 | static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) { 48 | struct ipv6hdr *ip6h = data + nh_off; 49 | 50 | if ((void*)&ip6h[1] > data_end) 51 | return 0; 52 | return ip6h->nexthdr; 53 | } 54 | 55 | int xdp_prog1(struct CTXTYPE *ctx) { 56 | 57 | void* data_end = (void*)(long)ctx->data_end; 58 | void* data = (void*)(long)ctx->data; 59 | 60 | struct ethhdr *eth = data; 61 | 62 | // drop packets 63 | int rc = RETURNCODE; // let pass XDP_PASS or redirect to tx via XDP_TX 64 | long *value; 65 | uint16_t h_proto; 66 | uint64_t nh_off = 0; 67 | int index; 68 | 69 | nh_off = sizeof(*eth); 70 | 71 | if (data + nh_off > data_end) 72 | return rc; 73 | 74 | h_proto = eth->h_proto; 75 | 76 | // While the following code appears to be duplicated accidentally, 77 | // it's intentional to handle double tags in ethernet frames. 78 | if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 79 | struct vlan_hdr *vhdr; 80 | 81 | vhdr = data + nh_off; 82 | nh_off += sizeof(struct vlan_hdr); 83 | if (data + nh_off > data_end) 84 | return rc; 85 | h_proto = vhdr->h_vlan_encapsulated_proto; 86 | } 87 | if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 88 | struct vlan_hdr *vhdr; 89 | 90 | vhdr = data + nh_off; 91 | nh_off += sizeof(struct vlan_hdr); 92 | if (data + nh_off > data_end) 93 | return rc; 94 | h_proto = vhdr->h_vlan_encapsulated_proto; 95 | } 96 | 97 | if (h_proto == htons(ETH_P_IP)) 98 | index = parse_ipv4(data, nh_off, data_end); 99 | else if (h_proto == htons(ETH_P_IPV6)) 100 | index = parse_ipv6(data, nh_off, data_end); 101 | else 102 | index = 0; 103 | 104 | value = dropcnt.lookup(&index); 105 | if (value) lock_xadd(value, 1); 106 | 107 | return rc; 108 | } 109 | ` 110 | 111 | func usage() { 112 | fmt.Printf("Usage: %v \n", os.Args[0]) 113 | fmt.Printf("e.g.: %v eth0\n", os.Args[0]) 114 | os.Exit(1) 115 | } 116 | 117 | func main() { 118 | var device string 119 | 120 | if len(os.Args) != 2 { 121 | usage() 122 | } 123 | 124 | device = os.Args[1] 125 | 126 | ret := "XDP_DROP" 127 | ctxtype := "xdp_md" 128 | 129 | module := bpf.NewModule(source, []string{ 130 | "-w", 131 | "-DRETURNCODE=" + ret, 132 | "-DCTXTYPE=" + ctxtype, 133 | }) 134 | defer module.Close() 135 | 136 | fn, err := module.Load("xdp_prog1", C.BPF_PROG_TYPE_XDP, 1, 65536) 137 | if err != nil { 138 | fmt.Fprintf(os.Stderr, "Failed to load xdp prog: %v\n", err) 139 | os.Exit(1) 140 | } 141 | 142 | err = module.AttachXDP(device, fn) 143 | if err != nil { 144 | fmt.Fprintf(os.Stderr, "Failed to attach xdp prog: %v\n", err) 145 | os.Exit(1) 146 | } 147 | 148 | defer func() { 149 | if err := module.RemoveXDP(device); err != nil { 150 | fmt.Fprintf(os.Stderr, "Failed to remove XDP from %s: %v\n", device, err) 151 | } 152 | }() 153 | 154 | fmt.Println("Dropping packets, hit CTRL+C to stop") 155 | 156 | sig := make(chan os.Signal, 1) 157 | signal.Notify(sig, os.Interrupt, os.Kill) 158 | 159 | dropcnt := bpf.NewTable(module.TableId("dropcnt"), module) 160 | 161 | <-sig 162 | 163 | fmt.Printf("\n{IP protocol-number}: {total dropped pkts}\n") 164 | for it := dropcnt.Iter(); it.Next(); { 165 | key := bpf.GetHostByteOrder().Uint32(it.Key()) 166 | value := bpf.GetHostByteOrder().Uint64(it.Leaf()) 167 | 168 | if value > 0 { 169 | fmt.Printf("%v: %v pkts\n", key, value) 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/examples/tracepipe/tracepipe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | 21 | "github.com/iovisor/gobpf/pkg/tracepipe" 22 | ) 23 | 24 | func main() { 25 | tp, err := tracepipe.New() 26 | if err != nil { 27 | fmt.Fprintf(os.Stderr, "%s\n", err) 28 | os.Exit(1) 29 | } 30 | defer tp.Close() 31 | 32 | channel, errorChannel := tp.Channel() 33 | 34 | for { 35 | select { 36 | case event := <-channel: 37 | fmt.Printf("%+v\n", event) 38 | case err := <-errorChannel: 39 | fmt.Printf("%+v\n", err) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/bpffs/fs.go: -------------------------------------------------------------------------------- 1 | package bpffs 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | const BPFFSPath = "/sys/fs/bpf" 10 | 11 | var FsMagicBPFFS int32 12 | 13 | func init() { 14 | // https://github.com/coreutils/coreutils/blob/v8.27/src/stat.c#L275 15 | // https://github.com/torvalds/linux/blob/v4.8/include/uapi/linux/magic.h#L80 16 | magic := uint32(0xCAFE4A11) 17 | // 0xCAFE4A11 overflows an int32, which is what's expected by Statfs_t.Type in 32bit platforms. 18 | // To avoid conditional compilation for all 32bit/64bit platforms, we use an unsafe cast 19 | FsMagicBPFFS = *(*int32)(unsafe.Pointer(&magic)) 20 | } 21 | 22 | // IsMountedAt checks if the BPF fs is mounted already in the custom location 23 | func IsMountedAt(mountpoint string) (bool, error) { 24 | var data syscall.Statfs_t 25 | if err := syscall.Statfs(mountpoint, &data); err != nil { 26 | return false, fmt.Errorf("cannot statfs %q: %v", mountpoint, err) 27 | } 28 | return int32(data.Type) == FsMagicBPFFS, nil 29 | } 30 | 31 | // IsMounted checks if the BPF fs is mounted already in the default location 32 | func IsMounted() (bool, error) { 33 | return IsMountedAt(BPFFSPath) 34 | } 35 | 36 | // MountAt mounts the BPF fs in the custom location (if not already mounted) 37 | func MountAt(mountpoint string) error { 38 | mounted, err := IsMountedAt(mountpoint) 39 | if err != nil { 40 | return err 41 | } 42 | if mounted { 43 | return nil 44 | } 45 | if err := syscall.Mount(mountpoint, mountpoint, "bpf", 0, ""); err != nil { 46 | return fmt.Errorf("error mounting %q: %v", mountpoint, err) 47 | } 48 | return nil 49 | } 50 | 51 | // Mount mounts the BPF fs in the default location (if not already mounted) 52 | func Mount() error { 53 | return MountAt(BPFFSPath) 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/cpuonline/cpu_range.go: -------------------------------------------------------------------------------- 1 | package cpuonline 2 | 3 | import ( 4 | "io/ioutil" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | const cpuOnline = "/sys/devices/system/cpu/online" 10 | 11 | // loosely based on https://github.com/iovisor/bcc/blob/v0.3.0/src/python/bcc/utils.py#L15 12 | func readCPURange(cpuRangeStr string) ([]uint, error) { 13 | var cpus []uint 14 | cpuRangeStr = strings.Trim(cpuRangeStr, "\n ") 15 | for _, cpuRange := range strings.Split(cpuRangeStr, ",") { 16 | rangeOp := strings.SplitN(cpuRange, "-", 2) 17 | first, err := strconv.ParseUint(rangeOp[0], 10, 32) 18 | if err != nil { 19 | return nil, err 20 | } 21 | if len(rangeOp) == 1 { 22 | cpus = append(cpus, uint(first)) 23 | continue 24 | } 25 | last, err := strconv.ParseUint(rangeOp[1], 10, 32) 26 | if err != nil { 27 | return nil, err 28 | } 29 | for n := first; n <= last; n++ { 30 | cpus = append(cpus, uint(n)) 31 | } 32 | } 33 | return cpus, nil 34 | } 35 | 36 | // Get returns a slice with the online CPUs, for example `[0, 2, 3]` 37 | func Get() ([]uint, error) { 38 | buf, err := ioutil.ReadFile(cpuOnline) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return readCPURange(string(buf)) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/cpuonline/cpu_range_test.go: -------------------------------------------------------------------------------- 1 | package cpuonline 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestGetOnlineCPUs(t *testing.T) { 8 | tests := []struct { 9 | data string 10 | expected []uint 11 | valid bool 12 | }{ 13 | { 14 | "", 15 | nil, 16 | false, 17 | }, 18 | { 19 | "0-3\n", 20 | []uint{0, 1, 2, 3}, 21 | true, 22 | }, 23 | { 24 | " 0-2,5", 25 | []uint{0, 1, 2, 5}, 26 | true, 27 | }, 28 | { 29 | "0,2,4-5,7-9", 30 | []uint{0, 2, 4, 5, 7, 8, 9}, 31 | true, 32 | }, 33 | { 34 | "0,2", 35 | []uint{0, 2}, 36 | true, 37 | }, 38 | { 39 | "0", 40 | []uint{0}, 41 | true, 42 | }, 43 | { 44 | "-2,5", 45 | nil, 46 | false, 47 | }, 48 | { 49 | "2-@,5", 50 | nil, 51 | false, 52 | }, 53 | { 54 | "-", 55 | nil, 56 | false, 57 | }, 58 | } 59 | for _, test := range tests { 60 | cpus, err := readCPURange(test.data) 61 | if test.valid && err != nil { 62 | t.Errorf("expected input %q to not return an error but got: %v\n", test.data, err) 63 | } 64 | if !test.valid && err == nil { 65 | t.Errorf("expected input %q to return an error\n", test.data) 66 | } 67 | for i := range cpus { 68 | if cpus[i] != test.expected[i] { 69 | t.Errorf("expected %q but got %q\n", test.expected, cpus) 70 | break 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/ksym/ksym.go: -------------------------------------------------------------------------------- 1 | package ksym 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | "os" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | const ( 13 | KALLSYMS = "/proc/kallsyms" 14 | ) 15 | 16 | type ksymCache struct { 17 | sync.RWMutex 18 | ksym map[string]string 19 | } 20 | 21 | var cache ksymCache 22 | 23 | // Ksym translates a kernel memory address into a kernel function name 24 | // using `/proc/kallsyms` 25 | func Ksym(addr string) (string, error) { 26 | if cache.ksym == nil { 27 | cache.ksym = make(map[string]string) 28 | } 29 | 30 | cache.Lock() 31 | defer cache.Unlock() 32 | 33 | if _, ok := cache.ksym[addr]; !ok { 34 | fd, err := os.Open(KALLSYMS) 35 | if err != nil { 36 | return "", err 37 | } 38 | defer fd.Close() 39 | 40 | fn := ksym(addr, fd) 41 | if fn == "" { 42 | return "", errors.New("kernel function not found for " + addr) 43 | } 44 | 45 | cache.ksym[addr] = fn 46 | } 47 | 48 | return cache.ksym[addr], nil 49 | } 50 | 51 | func ksym(addr string, r io.Reader) string { 52 | s := bufio.NewScanner(r) 53 | for s.Scan() { 54 | l := s.Text() 55 | ar := strings.Split(l, " ") 56 | if len(ar) != 3 { 57 | continue 58 | } 59 | 60 | if ar[0] == addr { 61 | return ar[2] 62 | } 63 | } 64 | 65 | return "" 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/ksym/ksym_test.go: -------------------------------------------------------------------------------- 1 | package ksym 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestKsym(t *testing.T) { 9 | data := "ffffffff91b2a340 T cgroup_freezing" 10 | 11 | r := strings.NewReader(data) 12 | fn := ksym("ffffffff91b2a340", r) 13 | 14 | if fn != "cgroup_freezing" { 15 | t.Error("unexpected result") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/progtestrun/prog_test_run.go: -------------------------------------------------------------------------------- 1 | package progtestrun 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | /* 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static __u64 ptr_to_u64(void *ptr) 17 | { 18 | return (__u64) (unsigned long) ptr; 19 | } 20 | 21 | int bpf_prog_test_run(int fd, int repeat, char *data, int data_size, 22 | char *data_out, int *data_out_size, int *retval, 23 | int *duration) 24 | { 25 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) 26 | union bpf_attr attr = {}; 27 | int ret; 28 | 29 | memset(&attr, 0, sizeof(attr)); 30 | 31 | attr.test.prog_fd = fd; 32 | attr.test.data_in = ptr_to_u64((void *) data); 33 | attr.test.data_out = ptr_to_u64((void *) data_out); 34 | attr.test.data_size_in = data_size; 35 | attr.test.repeat = repeat; 36 | 37 | ret = syscall(__NR_bpf, BPF_PROG_TEST_RUN, &attr, sizeof(attr)); 38 | if (data_out_size) 39 | *data_out_size = attr.test.data_size_out; 40 | if (retval) 41 | *retval = attr.test.retval; 42 | if (duration) 43 | *duration = attr.test.duration; 44 | return ret; 45 | #else 46 | errno = ENOSYS; 47 | return -1; 48 | #endif 49 | } 50 | */ 51 | import "C" 52 | 53 | // Run exposes BPF_PROG_TEST_RUN to test xdp and skp programs. 54 | // `data` will be passed to your program as `__sk_buff *ptr`. 55 | // `dataOut` (optional) will hold `skb->data` after run, if large enough. 56 | func Run(progFd, repeat int, data []byte, dataOut []byte) (int, int, int, error) { 57 | if data == nil { 58 | // http://elixir.free-electrons.com/linux/v4.12/source/net/bpf/test_run.c#L78 59 | // http://elixir.free-electrons.com/linux/v4.12/source/include/uapi/linux/if_ether.h#L32 60 | return -1, 0, 0, fmt.Errorf("data must be at least 14 bytes (corresponding to ETH_HLEN)") 61 | } 62 | var ( 63 | dataOutPtr *C.char 64 | dataOutLen C.int 65 | returnValue C.int 66 | duration C.int 67 | 68 | dataPtr = (*C.char)(unsafe.Pointer(&data[0])) 69 | dataLen = C.int(len(data)) 70 | ) 71 | if dataOut != nil { 72 | dataOutPtr = (*C.char)(unsafe.Pointer(&dataOut[0])) 73 | } 74 | ret, err := C.bpf_prog_test_run(C.int(progFd), C.int(repeat), dataPtr, dataLen, dataOutPtr, &dataOutLen, &returnValue, &duration) 75 | if ret != 0 { 76 | return -1, 0, 0, fmt.Errorf("bpf_prog_test_run failed: %v (%d)", err, ret) 77 | } 78 | return int(returnValue), int(duration), int(dataOutLen), nil 79 | } 80 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/tracepipe/trace_pipe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tracepipe 16 | 17 | import ( 18 | "bufio" 19 | "fmt" 20 | "io" 21 | "os" 22 | "regexp" 23 | "strings" 24 | ) 25 | 26 | const tracePipeFile = "/sys/kernel/debug/tracing/trace_pipe" 27 | 28 | // TracePipe to read from /sys/kernel/debug/tracing/trace_pipe 29 | // Note that data can be read only once, i.e. if you have more than 30 | // one tracer / channel, only one will receive an event: 31 | // "Once data is read from this file, it is consumed, and will not be 32 | // read again with a sequential read." 33 | // https://www.kernel.org/doc/Documentation/trace/ftrace.txt 34 | type TracePipe struct { 35 | file *os.File 36 | reader *bufio.Reader 37 | stop chan struct{} 38 | } 39 | 40 | // TraceEvent contains the raw event as well as the contents of 41 | // every field as string, as defined under "Output format" in 42 | // https://www.kernel.org/doc/Documentation/trace/ftrace.txt 43 | type TraceEvent struct { 44 | Raw string 45 | Task string 46 | PID string 47 | CPU string 48 | Flags string 49 | Timestamp string 50 | Function string 51 | Message string 52 | } 53 | 54 | func New() (*TracePipe, error) { 55 | f, err := os.Open(tracePipeFile) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return &TracePipe{ 60 | file: f, 61 | reader: bufio.NewReader(f), 62 | stop: make(chan struct{}), 63 | }, nil 64 | } 65 | 66 | // A line from trace_pipe looks like (leading spaces included): 67 | // ` chromium-15581 [000] d... 92783.722567: : Hello, World!` 68 | var traceLineRegexp = regexp.MustCompile(`(.{16})-(\d+) +\[(\d{3})\] (.{4}) +(\d+\.\d+)\: (.*?)\: (.*)`) 69 | 70 | func parseTraceLine(raw string) (*TraceEvent, error) { 71 | fields := traceLineRegexp.FindStringSubmatch(raw) 72 | if len(fields) != 8 { 73 | return nil, fmt.Errorf("received unexpected input %q", raw) 74 | } 75 | return &TraceEvent{ 76 | Raw: raw, 77 | Task: strings.Trim(fields[1], " "), 78 | PID: fields[2], 79 | CPU: fields[3], 80 | Flags: fields[4], 81 | Timestamp: fields[5], 82 | Function: fields[6], 83 | Message: fields[7], 84 | }, nil 85 | } 86 | 87 | func (t *TracePipe) ReadLine() (*TraceEvent, error) { 88 | line, err := t.reader.ReadString('\n') 89 | if err != nil { 90 | return nil, err 91 | } 92 | traceEvent, err := parseTraceLine(line) 93 | if err != nil { 94 | return nil, err 95 | } 96 | return traceEvent, nil 97 | } 98 | 99 | func (t *TracePipe) Channel() (<-chan *TraceEvent, <-chan error) { 100 | channelEvents := make(chan *TraceEvent) 101 | channelErrors := make(chan error) 102 | go func() { 103 | for { 104 | select { 105 | case <-t.stop: 106 | return 107 | default: 108 | } 109 | traceEvent, err := t.ReadLine() 110 | if err != nil { 111 | if err == io.EOF { 112 | continue 113 | } 114 | channelErrors <- err 115 | } else { 116 | channelEvents <- traceEvent 117 | } 118 | } 119 | }() 120 | return channelEvents, channelErrors 121 | } 122 | 123 | func (t *TracePipe) Close() error { 124 | close(t.stop) 125 | return t.file.Close() 126 | } 127 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/pkg/tracepipe/trace_pipe_test.go: -------------------------------------------------------------------------------- 1 | package tracepipe 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestParseTraceLine(t *testing.T) { 8 | testEvents := []struct { 9 | input string 10 | expected TraceEvent 11 | }{ 12 | { 13 | " chromium-15581 [000] d... 92783.722567: : Hello, World!", 14 | TraceEvent{ 15 | Task: "chromium", 16 | Function: "", 17 | Message: "Hello, World!", 18 | }, 19 | }, 20 | { 21 | " curl-18597 [000] dN.. 463.471554: : kretprobe__tcp_v4_connect - pid_tgid 79873506822309\n", 22 | TraceEvent{ 23 | Task: "curl", 24 | Function: "", 25 | Message: "kretprobe__tcp_v4_connect - pid_tgid 79873506822309", 26 | }, 27 | }, 28 | { 29 | " trace_pipe-23553 [000] .... 205825.968557: sys_enter: NR 0 (3, c420098000, 1000, 0, 0, 0)\n", 30 | TraceEvent{ 31 | Task: "trace_pipe", 32 | Function: "sys_enter", 33 | Message: "NR 0 (3, c420098000, 1000, 0, 0, 0)", 34 | }, 35 | }, 36 | { 37 | " trace_pipe-23553 [000] .... 205825.968557: sys_enter: hello: world\n", 38 | TraceEvent{ 39 | Task: "trace_pipe", 40 | Function: "sys_enter", 41 | Message: "hello: world", 42 | }, 43 | }, 44 | } 45 | for _, testEvent := range testEvents { 46 | result, err := parseTraceLine(testEvent.input) 47 | if err != nil { 48 | t.Errorf("%q could not be parsed", testEvent.input) 49 | } 50 | if testEvent.expected.Task != result.Task { 51 | t.Errorf("result task %q doesn't match expected %q", result.Task, testEvent.expected.Task) 52 | } 53 | if testEvent.expected.Function != result.Function { 54 | t.Errorf("result function %q doesn't match expected %q", result.Function, testEvent.expected.Function) 55 | } 56 | if testEvent.expected.Message != result.Message { 57 | t.Errorf("result message %q doesn't match expected %q", result.Message, testEvent.expected.Message) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/dippynark/gobpf/tests/dummy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Compiled with './build' 3 | */ 4 | 5 | #include "../elf/include/bpf.h" 6 | #include "../elf/include/bpf_map.h" 7 | 8 | #define SEC(NAME) __attribute__((section(NAME), used)) 9 | 10 | #define PERF_MAX_STACK_DEPTH 127 11 | 12 | #define KERNEL_VERSION_GTE(X) (KERNEL_VERSION >= X) 13 | 14 | struct pt_regs{}; 15 | 16 | struct bpf_map_def SEC("maps/dummy_hash") dummy_hash = { 17 | .type = BPF_MAP_TYPE_HASH, 18 | .key_size = sizeof(int), 19 | .value_size = sizeof(unsigned int), 20 | .max_entries = 128, 21 | }; 22 | 23 | struct bpf_map_def SEC("maps/dummy_array") dummy_array = { 24 | .type = BPF_MAP_TYPE_ARRAY, 25 | .key_size = sizeof(int), 26 | .value_size = sizeof(unsigned int), 27 | .max_entries = 128, 28 | }; 29 | 30 | struct bpf_map_def SEC("maps/dummy_prog_array") dummy_prog_array = { 31 | .type = BPF_MAP_TYPE_PROG_ARRAY, 32 | .key_size = sizeof(int), 33 | .value_size = sizeof(unsigned int), 34 | .max_entries = 128, 35 | }; 36 | 37 | struct bpf_map_def SEC("maps/dummy_perf") dummy_perf = { 38 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 39 | .key_size = sizeof(int), 40 | .value_size = sizeof(unsigned int), 41 | .max_entries = 128, 42 | }; 43 | 44 | #if KERNEL_VERSION_GTE(46) 45 | struct bpf_map_def SEC("maps/dummy_percpu_hash") dummy_percpu_hash = { 46 | .type = BPF_MAP_TYPE_PERCPU_HASH, 47 | .key_size = sizeof(int), 48 | .value_size = sizeof(unsigned int), 49 | .max_entries = 128, 50 | }; 51 | 52 | struct bpf_map_def SEC("maps/dummy_percpu_array") dummy_percpu_array = { 53 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, 54 | .key_size = sizeof(int), 55 | .value_size = sizeof(unsigned int), 56 | .max_entries = 128, 57 | }; 58 | 59 | struct bpf_map_def SEC("maps/dummy_stack_trace") dummy_stack_trace = { 60 | .type = BPF_MAP_TYPE_STACK_TRACE, 61 | .key_size = sizeof(int), 62 | .value_size = PERF_MAX_STACK_DEPTH * sizeof(unsigned long long), 63 | .max_entries = 128, 64 | }; 65 | #endif 66 | 67 | #if KERNEL_VERSION_GTE(48) 68 | struct bpf_map_def SEC("maps/dummy_cgroup_array") dummy_cgroup_array = { 69 | .type = BPF_MAP_TYPE_CGROUP_ARRAY, 70 | .key_size = sizeof(int), 71 | .value_size = sizeof(unsigned int), 72 | .max_entries = 128, 73 | }; 74 | #endif 75 | 76 | struct bpf_map_def SEC("maps/dummy_array_custom") dummy_array_custom = { 77 | .type = BPF_MAP_TYPE_ARRAY, 78 | .key_size = sizeof(int), 79 | .value_size = sizeof(unsigned int), 80 | .max_entries = 128, 81 | .pinning = PIN_CUSTOM_NS, 82 | }; 83 | 84 | struct bpf_map_def SEC("maps/dummy_sockmap") sock_map = { 85 | .type = BPF_MAP_TYPE_SOCKMAP, 86 | .key_size = sizeof(int), 87 | .value_size = sizeof(unsigned int), 88 | .max_entries = 128, 89 | }; 90 | 91 | SEC("kprobe/dummy") 92 | int kprobe__dummy(struct pt_regs *ctx) 93 | { 94 | return 0; 95 | } 96 | 97 | SEC("kretprobe/dummy") 98 | int kretprobe__dummy(struct pt_regs *ctx) 99 | { 100 | return 0; 101 | } 102 | 103 | SEC("uprobe/dummy") 104 | int uprobe__dummy(struct pt_regs *ctx) 105 | { 106 | return 0; 107 | } 108 | 109 | SEC("uretprobe/dummy") 110 | int uretprobe__dummy(struct pt_regs *ctx) 111 | { 112 | return 0; 113 | } 114 | 115 | #if KERNEL_VERSION_GTE(410) 116 | SEC("cgroup/skb") 117 | int cgroup_skb__dummy(struct __sk_buff *skb) 118 | { 119 | return 1; 120 | } 121 | 122 | SEC("cgroup/sock") 123 | int cgroup_sock__dummy(struct __sk_buff *skb) 124 | { 125 | return 0; 126 | } 127 | #endif 128 | 129 | #if KERNEL_VERSION_GTE(47) 130 | SEC("tracepoint/raw_syscalls/sys_enter") 131 | int tracepoint__raw_sys_enter() 132 | { 133 | return 0; 134 | } 135 | #endif 136 | 137 | SEC("socket/dummy") 138 | int socket__dummy(struct __sk_buff *skb) 139 | { 140 | return 0; 141 | } 142 | 143 | SEC("sk/skb/parser/dummy_sockmap") 144 | int parser_dummy(struct __sk_buff *skb) 145 | { 146 | return 0; 147 | } 148 | 149 | SEC("sk/skb/verdict/dummy_sockmap") 150 | int verdict_dummy(struct __sk_buff *skb) 151 | { 152 | return 0; 153 | } 154 | 155 | unsigned int _version SEC("version") = 0xFFFFFFFE; 156 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 PLUMgrid 2 | Copyright 2016 Kinvolk 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/bcc/perf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "encoding/binary" 19 | "fmt" 20 | "sync" 21 | "unsafe" 22 | 23 | "github.com/iovisor/gobpf/pkg/cpuonline" 24 | ) 25 | 26 | /* 27 | #cgo CFLAGS: -I/usr/include/bcc/compat 28 | #cgo LDFLAGS: -lbcc 29 | #include 30 | #include 31 | #include 32 | 33 | // perf_reader_raw_cb as defined in bcc libbpf.h 34 | // typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size); 35 | extern void callback_to_go(void*, void*, int); 36 | */ 37 | import "C" 38 | 39 | type PerfMap struct { 40 | table *Table 41 | readers []*C.struct_perf_reader 42 | stop chan bool 43 | } 44 | 45 | type callbackData struct { 46 | receiverChan chan []byte 47 | } 48 | 49 | const BPF_PERF_READER_PAGE_CNT = 8 50 | 51 | var byteOrder binary.ByteOrder 52 | var callbackRegister = make(map[uint64]*callbackData) 53 | var callbackIndex uint64 54 | var mu sync.Mutex 55 | 56 | // In lack of binary.HostEndian ... 57 | func init() { 58 | byteOrder = determineHostByteOrder() 59 | } 60 | 61 | func registerCallback(data *callbackData) uint64 { 62 | mu.Lock() 63 | defer mu.Unlock() 64 | callbackIndex++ 65 | for callbackRegister[callbackIndex] != nil { 66 | callbackIndex++ 67 | } 68 | callbackRegister[callbackIndex] = data 69 | return callbackIndex 70 | } 71 | 72 | func unregisterCallback(i uint64) { 73 | mu.Lock() 74 | defer mu.Unlock() 75 | delete(callbackRegister, i) 76 | } 77 | 78 | func lookupCallback(i uint64) *callbackData { 79 | return callbackRegister[i] 80 | } 81 | 82 | // Gateway function as required with CGO Go >= 1.6 83 | // "If a C-program wants a function pointer, a gateway function has to 84 | // be written. This is because we can't take the address of a Go 85 | // function and give that to C-code since the cgo tool will generate a 86 | // stub in C that should be called." 87 | //export callback_to_go 88 | func callback_to_go(cbCookie unsafe.Pointer, raw unsafe.Pointer, rawSize C.int) { 89 | callbackData := lookupCallback(uint64(uintptr(cbCookie))) 90 | callbackData.receiverChan <- C.GoBytes(raw, rawSize) 91 | } 92 | 93 | // GetHostByteOrder returns the current byte-order. 94 | func GetHostByteOrder() binary.ByteOrder { 95 | return byteOrder 96 | } 97 | 98 | func determineHostByteOrder() binary.ByteOrder { 99 | var i int32 = 0x01020304 100 | u := unsafe.Pointer(&i) 101 | pb := (*byte)(u) 102 | b := *pb 103 | if b == 0x04 { 104 | return binary.LittleEndian 105 | } 106 | 107 | return binary.BigEndian 108 | } 109 | 110 | // InitPerfMap initializes a perf map with a receiver channel. 111 | func InitPerfMap(table *Table, receiverChan chan []byte) (*PerfMap, error) { 112 | fd := table.Config()["fd"].(int) 113 | keySize := table.Config()["key_size"].(uint64) 114 | leafSize := table.Config()["leaf_size"].(uint64) 115 | 116 | if keySize != 4 || leafSize != 4 { 117 | return nil, fmt.Errorf("passed table has wrong size") 118 | } 119 | 120 | callbackDataIndex := registerCallback(&callbackData{ 121 | receiverChan, 122 | }) 123 | 124 | key := make([]byte, keySize) 125 | leaf := make([]byte, leafSize) 126 | keyP := unsafe.Pointer(&key[0]) 127 | leafP := unsafe.Pointer(&leaf[0]) 128 | 129 | readers := []*C.struct_perf_reader{} 130 | 131 | cpus, err := cpuonline.Get() 132 | if err != nil { 133 | return nil, fmt.Errorf("failed to determine online cpus: %v", err) 134 | } 135 | 136 | for _, cpu := range cpus { 137 | reader, err := bpfOpenPerfBuffer(cpu, callbackDataIndex) 138 | if err != nil { 139 | return nil, fmt.Errorf("failed to open perf buffer: %v", err) 140 | } 141 | 142 | perfFd := C.perf_reader_fd((*C.struct_perf_reader)(reader)) 143 | 144 | readers = append(readers, (*C.struct_perf_reader)(reader)) 145 | 146 | byteOrder.PutUint32(leaf, uint32(perfFd)) 147 | 148 | r, err := C.bpf_update_elem(C.int(fd), keyP, leafP, 0) 149 | if r != 0 { 150 | return nil, fmt.Errorf("unable to initialize perf map: %v", err) 151 | } 152 | r = C.bpf_get_next_key(C.int(fd), keyP, keyP) 153 | if r != 0 { 154 | break 155 | } 156 | } 157 | return &PerfMap{ 158 | table, 159 | readers, 160 | make(chan bool), 161 | }, nil 162 | } 163 | 164 | // Start to poll the perf map reader and send back event data 165 | // over the connected channel. 166 | func (pm *PerfMap) Start() { 167 | go pm.poll(500) 168 | } 169 | 170 | // Stop to poll the perf map readers after a maximum of 500ms 171 | // (the timeout we use for perf_reader_poll). Ideally we would 172 | // have a way to cancel the poll, but perf_reader_poll doesn't 173 | // support that yet. 174 | func (pm *PerfMap) Stop() { 175 | pm.stop <- true 176 | } 177 | 178 | func (pm *PerfMap) poll(timeout int) { 179 | for { 180 | select { 181 | case <-pm.stop: 182 | return 183 | default: 184 | C.perf_reader_poll(C.int(len(pm.readers)), &pm.readers[0], C.int(timeout)) 185 | } 186 | } 187 | } 188 | 189 | func bpfOpenPerfBuffer(cpu uint, callbackDataIndex uint64) (unsafe.Pointer, error) { 190 | cpuC := C.int(cpu) 191 | reader, err := C.bpf_open_perf_buffer( 192 | (C.perf_reader_raw_cb)(unsafe.Pointer(C.callback_to_go)), 193 | nil, 194 | unsafe.Pointer(uintptr(callbackDataIndex)), 195 | -1, cpuC, BPF_PERF_READER_PAGE_CNT) 196 | if reader == nil { 197 | return nil, fmt.Errorf("failed to open perf buffer: %v", err) 198 | } 199 | return reader, nil 200 | } 201 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/bcc/symbol.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Louis McCormack 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "fmt" 19 | "regexp" 20 | "sync" 21 | "unsafe" 22 | ) 23 | 24 | /* 25 | #cgo CFLAGS: -I/usr/include/bcc/compat 26 | #cgo LDFLAGS: -lbcc 27 | #include 28 | #include 29 | #include 30 | extern void foreach_symbol_callback(char*, uint64_t); 31 | */ 32 | import "C" 33 | 34 | type symbolAddress struct { 35 | name string 36 | addr uint64 37 | } 38 | 39 | //symbolCache will cache module lookups 40 | var symbolCache = struct { 41 | cache map[string][]*symbolAddress 42 | currentModule string 43 | lock *sync.Mutex 44 | }{ 45 | cache: map[string][]*symbolAddress{}, 46 | currentModule: "", 47 | lock: &sync.Mutex{}, 48 | } 49 | 50 | type bccSymbol struct { 51 | name *C.char 52 | demangleName *C.char 53 | module *C.char 54 | offset C.ulonglong 55 | } 56 | 57 | type bccSymbolOption struct { 58 | useDebugFile int 59 | checkDebugFileCrc int 60 | useSymbolType uint32 61 | } 62 | 63 | // resolveSymbolPath returns the file and offset to locate symname in module 64 | func resolveSymbolPath(module string, symname string, addr uint64, pid int) (string, uint64, error) { 65 | if pid == -1 { 66 | pid = 0 67 | } 68 | 69 | modname, offset, err := bccResolveSymname(module, symname, addr, pid) 70 | if err != nil { 71 | return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err) 72 | } 73 | 74 | return modname, offset, nil 75 | } 76 | 77 | func bccResolveSymname(module string, symname string, addr uint64, pid int) (string, uint64, error) { 78 | symbol := &bccSymbol{} 79 | symbolC := (*C.struct_bcc_symbol)(unsafe.Pointer(symbol)) 80 | moduleCS := C.CString(module) 81 | defer C.free(unsafe.Pointer(moduleCS)) 82 | symnameCS := C.CString(symname) 83 | defer C.free(unsafe.Pointer(symnameCS)) 84 | 85 | res, err := C.bcc_resolve_symname(moduleCS, symnameCS, (C.uint64_t)(addr), C.int(pid), nil, symbolC) 86 | if res < 0 { 87 | return "", 0, fmt.Errorf("unable to locate symbol %s in module %s: %v", symname, module, err) 88 | } 89 | 90 | return C.GoString(symbolC.module), (uint64)(symbolC.offset), nil 91 | } 92 | 93 | func bccResolveName(module, symname string, pid int) (uint64, error) { 94 | symbol := &bccSymbolOption{} 95 | symbolC := (*C.struct_bcc_symbol_option)(unsafe.Pointer(symbol)) 96 | 97 | pidC := C.int(pid) 98 | cache := C.bcc_symcache_new(pidC, symbolC) 99 | 100 | moduleCS := C.CString(module) 101 | defer C.free(unsafe.Pointer(moduleCS)) 102 | 103 | nameCS := C.CString(symname) 104 | defer C.free(unsafe.Pointer(nameCS)) 105 | 106 | var addr uint64 107 | addrC := C.uint64_t(addr) 108 | res := C.bcc_symcache_resolve_name(cache, moduleCS, nameCS, &addrC) 109 | if res < 0 { 110 | return 0, fmt.Errorf("unable to locate symbol %s in module %s", symname, module) 111 | } 112 | 113 | return addr, nil 114 | } 115 | 116 | // getUserSymbolsAndAddresses finds a list of symbols associated with a module, 117 | // along with their addresses. The results are cached in the symbolCache and 118 | // returned 119 | func getUserSymbolsAndAddresses(module string) ([]*symbolAddress, error) { 120 | symbolCache.lock.Lock() 121 | defer symbolCache.lock.Unlock() 122 | // return previously cached list if it exists 123 | if _, ok := symbolCache.cache[module]; ok { 124 | return symbolCache.cache[module], nil 125 | } 126 | 127 | symbolCache.cache[module] = []*symbolAddress{} 128 | symbolCache.currentModule = module 129 | 130 | if err := bccForeachSymbol(module); err != nil { 131 | return nil, err 132 | } 133 | 134 | return symbolCache.cache[module], nil 135 | } 136 | 137 | func matchUserSymbols(module, match string) ([]*symbolAddress, error) { 138 | r, err := regexp.Compile(match) 139 | if err != nil { 140 | return nil, fmt.Errorf("invalid regex %s : %s", match, err) 141 | } 142 | matchedSymbols := []*symbolAddress{} 143 | symbols, err := getUserSymbolsAndAddresses(module) 144 | if err != nil { 145 | return nil, err 146 | } 147 | for _, sym := range symbols { 148 | if r.MatchString(sym.name) { 149 | matchedSymbols = append(matchedSymbols, sym) 150 | } 151 | } 152 | return matchedSymbols, nil 153 | } 154 | 155 | // foreach_symbol_callback is a gateway function that will be exported to C 156 | // so that it can be referenced as a function pointer 157 | //export foreach_symbol_callback 158 | func foreach_symbol_callback(symname *C.char, addr C.uint64_t) { 159 | symbolCache.cache[symbolCache.currentModule] = 160 | append(symbolCache.cache[symbolCache.currentModule], &symbolAddress{C.GoString(symname), (uint64)(addr)}) 161 | } 162 | 163 | func bccForeachSymbol(module string) error { 164 | moduleCS := C.CString(module) 165 | defer C.free(unsafe.Pointer(moduleCS)) 166 | res := C.bcc_foreach_function_symbol(moduleCS, (C.SYM_CB)(unsafe.Pointer(C.foreach_symbol_callback))) 167 | if res < 0 { 168 | return fmt.Errorf("unable to list symbols for %s", module) 169 | } 170 | return nil 171 | } 172 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/bcc/table.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 PLUMgrid 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bcc 16 | 17 | import ( 18 | "bytes" 19 | "errors" 20 | "fmt" 21 | "os" 22 | "unsafe" 23 | ) 24 | 25 | /* 26 | #cgo CFLAGS: -I/usr/include/bcc/compat 27 | #cgo LDFLAGS: -lbcc 28 | #include 29 | #include 30 | */ 31 | import "C" 32 | 33 | var errIterationFailed = errors.New("table.Iter: leaf for next key not found") 34 | 35 | // Table references a BPF table. The zero value cannot be used. 36 | type Table struct { 37 | id C.size_t 38 | module *Module 39 | } 40 | 41 | // New tables returns a refernce to a BPF table. 42 | func NewTable(id C.size_t, module *Module) *Table { 43 | return &Table{ 44 | id: id, 45 | module: module, 46 | } 47 | } 48 | 49 | // ID returns the table id. 50 | func (table *Table) ID() string { 51 | return C.GoString(C.bpf_table_name(table.module.p, table.id)) 52 | } 53 | 54 | // Name returns the table name. 55 | func (table *Table) Name() string { 56 | return C.GoString(C.bpf_table_name(table.module.p, table.id)) 57 | } 58 | 59 | // Config returns the table properties (name, fd, ...). 60 | func (table *Table) Config() map[string]interface{} { 61 | mod := table.module.p 62 | return map[string]interface{}{ 63 | "name": C.GoString(C.bpf_table_name(mod, table.id)), 64 | "fd": int(C.bpf_table_fd_id(mod, table.id)), 65 | "key_size": uint64(C.bpf_table_key_size_id(mod, table.id)), 66 | "leaf_size": uint64(C.bpf_table_leaf_size_id(mod, table.id)), 67 | "key_desc": C.GoString(C.bpf_table_key_desc_id(mod, table.id)), 68 | "leaf_desc": C.GoString(C.bpf_table_leaf_desc_id(mod, table.id)), 69 | } 70 | } 71 | 72 | func (table *Table) LeafStrToBytes(leafStr string) ([]byte, error) { 73 | mod := table.module.p 74 | 75 | leafSize := C.bpf_table_leaf_size_id(mod, table.id) 76 | leaf := make([]byte, leafSize) 77 | leafP := unsafe.Pointer(&leaf[0]) 78 | 79 | leafCS := C.CString(leafStr) 80 | defer C.free(unsafe.Pointer(leafCS)) 81 | 82 | r := C.bpf_table_leaf_sscanf(mod, table.id, leafCS, leafP) 83 | if r != 0 { 84 | return nil, fmt.Errorf("error scanning leaf (%v) from string", leafStr) 85 | } 86 | return leaf, nil 87 | } 88 | 89 | func (table *Table) KeyStrToBytes(keyStr string) ([]byte, error) { 90 | mod := table.module.p 91 | 92 | keySize := C.bpf_table_key_size_id(mod, table.id) 93 | key := make([]byte, keySize) 94 | keyP := unsafe.Pointer(&key[0]) 95 | 96 | keyCS := C.CString(keyStr) 97 | defer C.free(unsafe.Pointer(keyCS)) 98 | 99 | r := C.bpf_table_key_sscanf(mod, table.id, keyCS, keyP) 100 | if r != 0 { 101 | return nil, fmt.Errorf("error scanning key (%v) from string", keyStr) 102 | } 103 | return key, nil 104 | } 105 | 106 | // KeyBytesToStr returns the given key value formatted using the bcc-table's key string printer. 107 | func (table *Table) KeyBytesToStr(key []byte) (string, error) { 108 | keySize := len(key) 109 | keyP := unsafe.Pointer(&key[0]) 110 | 111 | keyStr := make([]byte, keySize*8) 112 | keyStrP := (*C.char)(unsafe.Pointer(&keyStr[0])) 113 | 114 | if res := C.bpf_table_key_snprintf(table.module.p, table.id, keyStrP, C.size_t(len(keyStr)), keyP); res != 0 { 115 | return "", fmt.Errorf("formatting table-key: %d", res) 116 | } 117 | 118 | return string(keyStr[:bytes.IndexByte(keyStr, 0)]), nil 119 | } 120 | 121 | // LeafBytesToStr returns the given leaf value formatted using the bcc-table's leaf string printer. 122 | func (table *Table) LeafBytesToStr(leaf []byte) (string, error) { 123 | leafSize := len(leaf) 124 | leafP := unsafe.Pointer(&leaf[0]) 125 | 126 | leafStr := make([]byte, leafSize*8) 127 | leafStrP := (*C.char)(unsafe.Pointer(&leafStr[0])) 128 | 129 | if res := C.bpf_table_leaf_snprintf(table.module.p, table.id, leafStrP, C.size_t(len(leafStr)), leafP); res != 0 { 130 | return "", fmt.Errorf("formatting table-leaf: %d", res) 131 | } 132 | 133 | return string(leafStr[:bytes.IndexByte(leafStr, 0)]), nil 134 | } 135 | 136 | // Get takes a key and returns the value or nil, and an 'ok' style indicator. 137 | func (table *Table) Get(key []byte) ([]byte, error) { 138 | mod := table.module.p 139 | fd := C.bpf_table_fd_id(mod, table.id) 140 | 141 | keyP := unsafe.Pointer(&key[0]) 142 | 143 | leafSize := C.bpf_table_leaf_size_id(mod, table.id) 144 | leaf := make([]byte, leafSize) 145 | leafP := unsafe.Pointer(&leaf[0]) 146 | 147 | r, err := C.bpf_lookup_elem(fd, keyP, leafP) 148 | if r != 0 { 149 | keyStr, errK := table.KeyBytesToStr(key) 150 | if errK != nil { 151 | keyStr = fmt.Sprintf("%v", key) 152 | } 153 | return nil, fmt.Errorf("Table.Get: key %v: %v", keyStr, err) 154 | } 155 | 156 | return leaf, nil 157 | } 158 | 159 | // GetP takes a key and returns the value or nil. 160 | func (table *Table) GetP(key unsafe.Pointer) (unsafe.Pointer, error) { 161 | fd := C.bpf_table_fd_id(table.module.p, table.id) 162 | 163 | leafSize := C.bpf_table_leaf_size_id(table.module.p, table.id) 164 | leaf := make([]byte, leafSize) 165 | leafP := unsafe.Pointer(&leaf[0]) 166 | 167 | _, err := C.bpf_lookup_elem(fd, key, leafP) 168 | if err != nil { 169 | return nil, err 170 | } 171 | return leafP, nil 172 | } 173 | 174 | // Set a key to a value. 175 | func (table *Table) Set(key, leaf []byte) error { 176 | fd := C.bpf_table_fd_id(table.module.p, table.id) 177 | 178 | keyP := unsafe.Pointer(&key[0]) 179 | leafP := unsafe.Pointer(&leaf[0]) 180 | 181 | r, err := C.bpf_update_elem(fd, keyP, leafP, 0) 182 | if r != 0 { 183 | keyStr, errK := table.KeyBytesToStr(key) 184 | if errK != nil { 185 | keyStr = fmt.Sprintf("%v", key) 186 | } 187 | leafStr, errL := table.LeafBytesToStr(leaf) 188 | if errL != nil { 189 | leafStr = fmt.Sprintf("%v", leaf) 190 | } 191 | 192 | return fmt.Errorf("Table.Set: update %v to %v: %v", keyStr, leafStr, err) 193 | } 194 | 195 | return nil 196 | } 197 | 198 | // SetP a key to a value as unsafe.Pointer. 199 | func (table *Table) SetP(key, leaf unsafe.Pointer) error { 200 | fd := C.bpf_table_fd_id(table.module.p, table.id) 201 | 202 | _, err := C.bpf_update_elem(fd, key, leaf, 0) 203 | if err != nil { 204 | return err 205 | } 206 | 207 | return nil 208 | } 209 | 210 | // Delete a key. 211 | func (table *Table) Delete(key []byte) error { 212 | fd := C.bpf_table_fd_id(table.module.p, table.id) 213 | keyP := unsafe.Pointer(&key[0]) 214 | r, err := C.bpf_delete_elem(fd, keyP) 215 | if r != 0 { 216 | keyStr, errK := table.KeyBytesToStr(key) 217 | if errK != nil { 218 | keyStr = fmt.Sprintf("%v", key) 219 | } 220 | return fmt.Errorf("Table.Delete: key %v: %v", keyStr, err) 221 | } 222 | return nil 223 | } 224 | 225 | // DeleteP a key. 226 | func (table *Table) DeleteP(key unsafe.Pointer) error { 227 | fd := C.bpf_table_fd_id(table.module.p, table.id) 228 | _, err := C.bpf_delete_elem(fd, key) 229 | if err != nil { 230 | return err 231 | } 232 | return nil 233 | } 234 | 235 | // DeleteAll deletes all entries from the table 236 | func (table *Table) DeleteAll() error { 237 | mod := table.module.p 238 | fd := C.bpf_table_fd_id(mod, table.id) 239 | 240 | keySize := C.bpf_table_key_size_id(mod, table.id) 241 | key := make([]byte, keySize) 242 | keyP := unsafe.Pointer(&key[0]) 243 | for res := C.bpf_get_first_key(fd, keyP, keySize); res == 0; res = C.bpf_get_next_key(fd, keyP, keyP) { 244 | r, err := C.bpf_delete_elem(fd, keyP) 245 | if r != 0 { 246 | return fmt.Errorf("Table.DeleteAll: unable to delete element: %v", err) 247 | } 248 | } 249 | return nil 250 | } 251 | 252 | // TableIterator contains the current position for iteration over a *bcc.Table and provides methods for iteration. 253 | type TableIterator struct { 254 | table *Table 255 | fd C.int 256 | 257 | err error 258 | 259 | key []byte 260 | leaf []byte 261 | } 262 | 263 | // Iter returns an iterator to list all table entries available as raw bytes. 264 | func (table *Table) Iter() *TableIterator { 265 | fd := C.bpf_table_fd_id(table.module.p, table.id) 266 | 267 | return &TableIterator{ 268 | table: table, 269 | fd: fd, 270 | } 271 | } 272 | 273 | // Next looks up the next element and return true if one is available. 274 | func (it *TableIterator) Next() bool { 275 | if it.err != nil { 276 | return false 277 | } 278 | 279 | if it.key == nil { 280 | keySize := C.bpf_table_key_size_id(it.table.module.p, it.table.id) 281 | 282 | key := make([]byte, keySize) 283 | keyP := unsafe.Pointer(&key[0]) 284 | if res, err := C.bpf_get_first_key(it.fd, keyP, keySize); res != 0 { 285 | if !os.IsNotExist(err) { 286 | it.err = err 287 | } 288 | return false 289 | } 290 | 291 | leafSize := C.bpf_table_leaf_size_id(it.table.module.p, it.table.id) 292 | leaf := make([]byte, leafSize) 293 | 294 | it.key = key 295 | it.leaf = leaf 296 | } else { 297 | keyP := unsafe.Pointer(&it.key[0]) 298 | if res, err := C.bpf_get_next_key(it.fd, keyP, keyP); res != 0 { 299 | if !os.IsNotExist(err) { 300 | it.err = err 301 | } 302 | return false 303 | } 304 | } 305 | 306 | keyP := unsafe.Pointer(&it.key[0]) 307 | leafP := unsafe.Pointer(&it.leaf[0]) 308 | if res, err := C.bpf_lookup_elem(it.fd, keyP, leafP); res != 0 { 309 | it.err = errIterationFailed 310 | if !os.IsNotExist(err) { 311 | it.err = err 312 | } 313 | return false 314 | } 315 | 316 | return true 317 | } 318 | 319 | // Key returns the current key value of the iterator, if the most recent call to Next returned true. 320 | // The slice is valid only until the next call to Next. 321 | func (it *TableIterator) Key() []byte { 322 | return it.key 323 | } 324 | 325 | // Leaf returns the current leaf value of the iterator, if the most recent call to Next returned true. 326 | // The slice is valid only until the next call to Next. 327 | func (it *TableIterator) Leaf() []byte { 328 | return it.leaf 329 | } 330 | 331 | // Err returns the last error that ocurred while table.Iter oder iter.Next 332 | func (it *TableIterator) Err() error { 333 | return it.err 334 | } 335 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/bpf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package bpf 16 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/compat.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // (c) 2018 Suchakra Sharma 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "errors" 21 | "io/ioutil" 22 | "regexp" 23 | "runtime" 24 | ) 25 | 26 | const defaultSymFile = "/proc/kallsyms" 27 | 28 | // Returns the qualified syscall named by going through '/proc/kallsyms' on the 29 | // system on which its executed. It allows BPF programs that may have been compiled 30 | // for older syscall functions to run on newer kernels 31 | func GetSyscallFnName(name string) (string, error) { 32 | // Get kernel symbols 33 | syms, err := ioutil.ReadFile(defaultSymFile) 34 | if err != nil { 35 | return "", err 36 | } 37 | return getSyscallFnNameWithKallsyms(name, string(syms)) 38 | } 39 | 40 | func getSyscallFnNameWithKallsyms(name string, kallsymsContent string) (string, error) { 41 | var arch string 42 | switch runtime.GOARCH { 43 | case "386": 44 | arch = "ia32" 45 | default: 46 | arch = "x64" 47 | } 48 | 49 | // We should search for new syscall function like "__x64__sys_open" 50 | // Note the start of word boundary. Should return exactly one string 51 | regexStr := `(\b__` + arch + `_[Ss]y[sS]_` + name + `\b)` 52 | fnRegex := regexp.MustCompile(regexStr) 53 | 54 | match := fnRegex.FindAllString(kallsymsContent, -1) 55 | 56 | // If nothing found, search for old syscall function to be sure 57 | if len(match) == 0 { 58 | newRegexStr := `(\b[Ss]y[sS]_` + name + `\b)` 59 | fnRegex = regexp.MustCompile(newRegexStr) 60 | newMatch := fnRegex.FindAllString(kallsymsContent, -1) 61 | 62 | // If we get something like 'sys_open' or 'SyS_open', return 63 | // either (they have same addr) else, just return original string 64 | if len(newMatch) >= 1 { 65 | return newMatch[0], nil 66 | } else { 67 | return "", errors.New("could not find a valid syscall name") 68 | } 69 | } 70 | 71 | return match[0], nil 72 | } 73 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/compat_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // (c) 2018 ShiftLeft GmbH 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | const prefixedKallsymsSymbols = ` 24 | 0000000000000000 W __x32_compat_sys_open_by_handle_at 25 | 0000000000000000 T do_sys_open 26 | 0000000000000000 T __x64_sys_open 27 | 0000000000000000 T __ia32_sys_open 28 | 0000000000000000 T __x64_sys_openat 29 | 0000000000000000 T __ia32_sys_openat 30 | 0000000000000000 T __ia32_compat_sys_open 31 | 0000000000000000 T __ia32_compat_sys_openat 32 | 0000000000000000 T __x64_sys_open_by_handle_at 33 | 0000000000000000 T __ia32_sys_open_by_handle_at 34 | 0000000000000000 T __ia32_compat_sys_open_by_handle_at 35 | 0000000000000000 t proc_sys_open 36 | 0000000000000000 t _eil_addr___ia32_compat_sys_openat 37 | 0000000000000000 t _eil_addr___ia32_compat_sys_open 38 | 0000000000000000 t _eil_addr___ia32_sys_openat 39 | 0000000000000000 t _eil_addr___x64_sys_openat 40 | 0000000000000000 t _eil_addr___ia32_sys_open 41 | 0000000000000000 t _eil_addr___x64_sys_open 42 | 0000000000000000 t _eil_addr___ia32_compat_sys_open_by_handle_at 43 | 0000000000000000 t _eil_addr___ia32_sys_open_by_handle_at 44 | 0000000000000000 t _eil_addr___x64_sys_open_by_handle_at 45 | ` 46 | 47 | const kallsymsSymbols = ` 48 | 0000000000000000 T dentry_open 49 | 0000000000000000 T filp_clone_open 50 | 0000000000000000 T file_open_name 51 | 0000000000000000 T filp_open 52 | 0000000000000000 T do_sys_open 53 | 0000000000000000 T SyS_open 54 | 0000000000000000 T sys_open 55 | 0000000000000000 T SyS_openat 56 | 0000000000000000 T sys_openat 57 | 0000000000000000 T compat_SyS_open 58 | 0000000000000000 T compat_sys_open 59 | 0000000000000000 T compat_SyS_openat 60 | 0000000000000000 T compat_sys_openat 61 | 0000000000000000 T SyS_creat 62 | 0000000000000000 T sys_creat 63 | 0000000000000000 T sys_vhangup 64 | ` 65 | 66 | func TestGetSyscallFnName(t *testing.T) { 67 | fnName, err := getSyscallFnNameWithKallsyms("open", prefixedKallsymsSymbols) 68 | if err != nil && fnName != "__x64_sys_open" { 69 | t.Errorf("expected __x64_sys_open : %s", err) 70 | } 71 | fnName, err = getSyscallFnNameWithKallsyms("open", kallsymsSymbols) 72 | if err != nil { 73 | if fnName != "SyS_open" { 74 | t.Errorf("expected SyS_open :%s", err) 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/elf_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestValidateMapPath(t *testing.T) { 24 | tests := []struct { 25 | input string 26 | expected bool 27 | }{ 28 | { 29 | input: "/sys/fs/bpf/good/path", 30 | expected: true, 31 | }, 32 | { 33 | input: "/sys/fs/bpf/../../bad/path", 34 | expected: false, 35 | }, 36 | { 37 | input: "/sys/fs/bpf/./bad/path", 38 | expected: false, 39 | }, 40 | { 41 | input: "/bad/path", 42 | expected: false, 43 | }, 44 | } 45 | 46 | for i, tt := range tests { 47 | if isValid := validateMapPath(tt.input); isValid != tt.expected { 48 | t.Fatalf("test %d (%s) expected %t but got %t", i, tt.input, tt.expected, isValid) 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/elf_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // not supported; dummy struct 10 | type BPFKProbePerf struct{} 11 | type SectionParams struct{} 12 | 13 | func (b *Module) Load(parameters map[string]SectionParams) error { 14 | return fmt.Errorf("not supported") 15 | } 16 | 17 | func NewBpfPerfEvent(fileName string) *BPFKProbePerf { 18 | // not supported 19 | return nil 20 | } 21 | 22 | func (b *BPFKProbePerf) Load() error { 23 | return fmt.Errorf("not supported") 24 | } 25 | 26 | func (b *BPFKProbePerf) PollStart(mapName string, receiverChan chan []byte, lostChan chan uint64) { 27 | // not supported 28 | return 29 | } 30 | 31 | func (b *BPFKProbePerf) PollStop(mapName string) { 32 | // not supported 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/include/bpf_map.h: -------------------------------------------------------------------------------- 1 | #define BUF_SIZE_MAP_NS 256 2 | 3 | typedef struct bpf_map_def { 4 | unsigned int type; 5 | unsigned int key_size; 6 | unsigned int value_size; 7 | unsigned int max_entries; 8 | unsigned int map_flags; 9 | unsigned int pinning; 10 | char namespace[BUF_SIZE_MAP_NS]; 11 | } bpf_map_def; 12 | 13 | enum bpf_pin_type { 14 | PIN_NONE = 0, 15 | PIN_OBJECT_NS, 16 | PIN_GLOBAL_NS, 17 | PIN_CUSTOM_NS, 18 | }; 19 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/kernel_version.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016-2017 Kinvolk 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "fmt" 21 | "io/ioutil" 22 | "regexp" 23 | "strconv" 24 | "strings" 25 | "syscall" 26 | ) 27 | 28 | var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`) 29 | 30 | // KernelVersionFromReleaseString converts a release string with format 31 | // 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format. 32 | // That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c) 33 | func KernelVersionFromReleaseString(releaseString string) (uint32, error) { 34 | versionParts := versionRegex.FindStringSubmatch(releaseString) 35 | if len(versionParts) != 4 { 36 | return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) 37 | } 38 | major, err := strconv.Atoi(versionParts[1]) 39 | if err != nil { 40 | return 0, err 41 | } 42 | 43 | minor, err := strconv.Atoi(versionParts[2]) 44 | if err != nil { 45 | return 0, err 46 | } 47 | 48 | patch, err := strconv.Atoi(versionParts[3]) 49 | if err != nil { 50 | return 0, err 51 | } 52 | out := major*256*256 + minor*256 + patch 53 | return uint32(out), nil 54 | } 55 | 56 | func currentVersionUname() (uint32, error) { 57 | var buf syscall.Utsname 58 | if err := syscall.Uname(&buf); err != nil { 59 | return 0, err 60 | } 61 | releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00") 62 | return KernelVersionFromReleaseString(releaseString) 63 | } 64 | 65 | func currentVersionUbuntu() (uint32, error) { 66 | procVersion, err := ioutil.ReadFile("/proc/version_signature") 67 | if err != nil { 68 | return 0, err 69 | } 70 | var u1, u2, releaseString string 71 | _, err = fmt.Sscanf(string(procVersion), "%s %s %s", &u1, &u2, &releaseString) 72 | if err != nil { 73 | return 0, err 74 | } 75 | return KernelVersionFromReleaseString(releaseString) 76 | } 77 | 78 | var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+) .*`) 79 | 80 | func currentVersionDebian() (uint32, error) { 81 | procVersion, err := ioutil.ReadFile("/proc/version") 82 | if err != nil { 83 | return 0, err 84 | } 85 | match := debianVersionRegex.FindStringSubmatch(string(procVersion)) 86 | if len(match) != 2 { 87 | return 0, fmt.Errorf("failed to get kernel version from /proc/version: %s", procVersion) 88 | } 89 | return KernelVersionFromReleaseString(match[1]) 90 | } 91 | 92 | // CurrentKernelVersion returns the current kernel version in 93 | // LINUX_VERSION_CODE format (see KernelVersionFromReleaseString()) 94 | func CurrentKernelVersion() (uint32, error) { 95 | // We need extra checks for Debian and Ubuntu as they modify 96 | // the kernel version patch number for compatibilty with 97 | // out-of-tree modules. Linux perf tools do the same for Ubuntu 98 | // systems: https://github.com/torvalds/linux/commit/d18acd15c 99 | // 100 | // See also: 101 | // https://kernel-handbook.alioth.debian.org/ch-versions.html 102 | // https://wiki.ubuntu.com/Kernel/FAQ 103 | version, err := currentVersionUbuntu() 104 | if err == nil { 105 | return version, nil 106 | } 107 | version, err = currentVersionDebian() 108 | if err == nil { 109 | return version, nil 110 | } 111 | return currentVersionUname() 112 | } 113 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/kernel_version_test.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2017 Kinvolk 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package elf 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | var testData = []struct { 24 | succeed bool 25 | releaseString string 26 | kernelVersion uint32 27 | }{ 28 | {true, "4.1.2-3", 262402}, 29 | {true, "4.8.14-200.fc24.x86_64", 264206}, 30 | {true, "4.1.2-3foo", 262402}, 31 | {true, "4.1.2foo-1", 262402}, 32 | {true, "4.1.2-rkt-v1", 262402}, 33 | {true, "4.1.2rkt-v1", 262402}, 34 | {true, "4.1.2-3 foo", 262402}, 35 | {false, "foo 4.1.2-3", 0}, 36 | {true, "4.1.2", 262402}, 37 | {false, ".4.1.2", 0}, 38 | {false, "4.1.", 0}, 39 | {false, "4.1", 0}, 40 | } 41 | 42 | func TestKernelVersionFromReleaseString(t *testing.T) { 43 | for _, test := range testData { 44 | version, err := KernelVersionFromReleaseString(test.releaseString) 45 | if err != nil && test.succeed { 46 | t.Errorf("expected %q to succeed: %s", test.releaseString, err) 47 | } else if err == nil && !test.succeed { 48 | t.Errorf("expected %q to fail", test.releaseString) 49 | } 50 | if version != test.kernelVersion { 51 | t.Errorf("expected kernel version %d, got %d", test.kernelVersion, version) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/module_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | type Module struct{} 11 | type Kprobe struct{} 12 | type CgroupProgram struct{} 13 | type AttachType struct{} 14 | 15 | func NewModule(fileName string) *Module { 16 | return nil 17 | } 18 | 19 | func NewModuleFromReader(fileReader io.ReaderAt) *Module { 20 | return nil 21 | } 22 | 23 | func (b *Module) EnableKprobe(secName string, maxactive int) error { 24 | return fmt.Errorf("not supported") 25 | } 26 | 27 | func (b *Module) IterKprobes() <-chan *Kprobe { 28 | return nil 29 | } 30 | 31 | func (b *Module) EnableKprobes(maxactive int) error { 32 | return fmt.Errorf("not supported") 33 | } 34 | 35 | func (b *Module) IterCgroupProgram() <-chan *CgroupProgram { 36 | return nil 37 | } 38 | 39 | func (b *Module) CgroupProgram(name string) *CgroupProgram { 40 | return nil 41 | } 42 | 43 | func (b *Module) Kprobe(name string) *Kprobe { 44 | return nil 45 | } 46 | 47 | func (b *Module) AttachProgram(cgroupProg *CgroupProgram, cgroupPath string, attachType AttachType) error { 48 | return fmt.Errorf("not supported") 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/perf.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016 Cilium Project 4 | // Copyright 2016 Sylvain Afchain 5 | // Copyright 2016 Kinvolk 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | package elf 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | "sort" 25 | "syscall" 26 | "unsafe" 27 | ) 28 | 29 | /* 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // from https://github.com/cilium/cilium/blob/master/pkg/bpf/perf.go 38 | 39 | struct event_sample { 40 | struct perf_event_header header; 41 | uint32_t size; 42 | uint8_t data[]; 43 | }; 44 | 45 | struct read_state { 46 | void *buf; 47 | int buf_len; 48 | }; 49 | 50 | static int perf_event_read(int page_count, int page_size, void *_state, 51 | void *_header, void *_sample_ptr, void *_lost_ptr) 52 | { 53 | volatile struct perf_event_mmap_page *header = _header; 54 | uint64_t data_head = *((volatile uint64_t *) &header->data_head); 55 | uint64_t data_tail = header->data_tail; 56 | uint64_t raw_size = (uint64_t)page_count * page_size; 57 | void *base = ((uint8_t *)header) + page_size; 58 | struct read_state *state = _state; 59 | struct event_sample *e; 60 | void *begin, *end; 61 | void **sample_ptr = (void **) _sample_ptr; 62 | void **lost_ptr = (void **) _lost_ptr; 63 | 64 | // No data to read on this ring 65 | __sync_synchronize(); 66 | if (data_head == data_tail) 67 | return 0; 68 | 69 | begin = base + data_tail % raw_size; 70 | e = begin; 71 | end = base + (data_tail + e->header.size) % raw_size; 72 | 73 | if (state->buf_len < e->header.size || !state->buf) { 74 | state->buf = realloc(state->buf, e->header.size); 75 | state->buf_len = e->header.size; 76 | } 77 | 78 | if (end < begin) { 79 | uint64_t len = base + raw_size - begin; 80 | 81 | memcpy(state->buf, begin, len); 82 | memcpy((char *) state->buf + len, base, e->header.size - len); 83 | 84 | e = state->buf; 85 | } else { 86 | memcpy(state->buf, begin, e->header.size); 87 | } 88 | 89 | switch (e->header.type) { 90 | case PERF_RECORD_SAMPLE: 91 | *sample_ptr = state->buf; 92 | break; 93 | case PERF_RECORD_LOST: 94 | *lost_ptr = state->buf; 95 | break; 96 | } 97 | 98 | __sync_synchronize(); 99 | header->data_tail += e->header.size; 100 | 101 | return e->header.type; 102 | } 103 | */ 104 | import "C" 105 | 106 | type PerfMap struct { 107 | name string 108 | program *Module 109 | pageCount int 110 | receiverChan chan []byte 111 | lostChan chan uint64 112 | pollStop chan struct{} 113 | timestamp func(*[]byte) uint64 114 | } 115 | 116 | // Matching 'struct perf_event_sample in kernel sources 117 | type PerfEventSample struct { 118 | PerfEventHeader 119 | Size uint32 120 | data byte // Size bytes of data 121 | } 122 | 123 | func InitPerfMap(b *Module, mapName string, receiverChan chan []byte, lostChan chan uint64) (*PerfMap, error) { 124 | m, ok := b.maps[mapName] 125 | if !ok { 126 | return nil, fmt.Errorf("no map with name %s", mapName) 127 | } 128 | if receiverChan == nil { 129 | return nil, fmt.Errorf("receiverChan is nil") 130 | } 131 | // Maps are initialized in b.Load(), nothing to do here 132 | return &PerfMap{ 133 | name: mapName, 134 | program: b, 135 | pageCount: m.pageCount, 136 | receiverChan: receiverChan, 137 | lostChan: lostChan, 138 | pollStop: make(chan struct{}), 139 | }, nil 140 | } 141 | 142 | // SetTimestampFunc registers a timestamp callback that will be used to 143 | // reorder the perf events chronologically. 144 | // 145 | // If not set, the order of events sent through receiverChan is not guaranteed. 146 | // 147 | // Typically, the ebpf program will use bpf_ktime_get_ns() to get a timestamp 148 | // and store it in the perf event. The perf event struct is opaque to this 149 | // package, hence the need for a callback. 150 | func (pm *PerfMap) SetTimestampFunc(timestamp func(*[]byte) uint64) { 151 | pm.timestamp = timestamp 152 | } 153 | 154 | func (pm *PerfMap) PollStart() { 155 | incoming := OrderedBytesArray{timestamp: pm.timestamp} 156 | 157 | m, ok := pm.program.maps[pm.name] 158 | if !ok { 159 | // should not happen or only when pm.program is 160 | // suddenly changed 161 | panic(fmt.Sprintf("cannot find map %q", pm.name)) 162 | } 163 | 164 | go func() { 165 | cpuCount := len(m.pmuFDs) 166 | pageSize := os.Getpagesize() 167 | state := C.struct_read_state{} 168 | 169 | defer func() { 170 | close(pm.receiverChan) 171 | if pm.lostChan != nil { 172 | close(pm.lostChan) 173 | } 174 | }() 175 | 176 | for { 177 | select { 178 | case <-pm.pollStop: 179 | break 180 | default: 181 | perfEventPoll(m.pmuFDs) 182 | } 183 | 184 | harvestLoop: 185 | for { 186 | select { 187 | case <-pm.pollStop: 188 | return 189 | default: 190 | } 191 | 192 | var harvestCount C.int 193 | beforeHarvest := nowNanoseconds() 194 | for cpu := 0; cpu < cpuCount; cpu++ { 195 | ringBufferLoop: 196 | for { 197 | var sample *PerfEventSample 198 | var lost *PerfEventLost 199 | 200 | ok := C.perf_event_read(C.int(pm.pageCount), C.int(pageSize), 201 | unsafe.Pointer(&state), unsafe.Pointer(m.headers[cpu]), 202 | unsafe.Pointer(&sample), unsafe.Pointer(&lost)) 203 | 204 | switch ok { 205 | case 0: 206 | break ringBufferLoop // nothing to read 207 | case C.PERF_RECORD_SAMPLE: 208 | size := sample.Size - 4 209 | b := C.GoBytes(unsafe.Pointer(&sample.data), C.int(size)) 210 | incoming.bytesArray = append(incoming.bytesArray, b) 211 | harvestCount++ 212 | if pm.timestamp == nil { 213 | continue ringBufferLoop 214 | } 215 | if incoming.timestamp(&b) > beforeHarvest { 216 | // see comment below 217 | break ringBufferLoop 218 | } 219 | case C.PERF_RECORD_LOST: 220 | if pm.lostChan != nil { 221 | select { 222 | case pm.lostChan <- lost.Lost: 223 | case <-pm.pollStop: 224 | return 225 | } 226 | } 227 | default: 228 | // ignore unknown events 229 | } 230 | } 231 | } 232 | 233 | if incoming.timestamp != nil { 234 | sort.Sort(incoming) 235 | } 236 | for incoming.Len() > 0 { 237 | if incoming.timestamp != nil && incoming.timestamp(&incoming.bytesArray[0]) > beforeHarvest { 238 | // This record has been sent after the beginning of the harvest. Stop 239 | // processing here to keep the order. "incoming" is sorted, so the next 240 | // elements also must not be processed now. 241 | break harvestLoop 242 | } 243 | select { 244 | case pm.receiverChan <- incoming.bytesArray[0]: 245 | case <-pm.pollStop: 246 | return 247 | } 248 | // remove first element 249 | incoming.bytesArray = incoming.bytesArray[1:] 250 | } 251 | if harvestCount == 0 && len(incoming.bytesArray) == 0 { 252 | break harvestLoop 253 | } 254 | } 255 | } 256 | }() 257 | } 258 | 259 | // PollStop stops the goroutine that polls the perf event map. 260 | // Callers must not close receiverChan or lostChan: they will be automatically 261 | // closed on the sender side. 262 | func (pm *PerfMap) PollStop() { 263 | close(pm.pollStop) 264 | } 265 | 266 | func perfEventPoll(fds []C.int) error { 267 | var pfds []C.struct_pollfd 268 | 269 | for i, _ := range fds { 270 | var pfd C.struct_pollfd 271 | 272 | pfd.fd = fds[i] 273 | pfd.events = C.POLLIN 274 | 275 | pfds = append(pfds, pfd) 276 | } 277 | _, err := C.poll(&pfds[0], C.nfds_t(len(fds)), 500) 278 | if err != nil { 279 | return fmt.Errorf("error polling: %v", err.(syscall.Errno)) 280 | } 281 | 282 | return nil 283 | } 284 | 285 | // Assume the timestamp is at the beginning of the user struct 286 | type OrderedBytesArray struct { 287 | bytesArray [][]byte 288 | timestamp func(*[]byte) uint64 289 | } 290 | 291 | func (a OrderedBytesArray) Len() int { 292 | return len(a.bytesArray) 293 | } 294 | 295 | func (a OrderedBytesArray) Swap(i, j int) { 296 | a.bytesArray[i], a.bytesArray[j] = a.bytesArray[j], a.bytesArray[i] 297 | } 298 | 299 | func (a OrderedBytesArray) Less(i, j int) bool { 300 | return a.timestamp(&a.bytesArray[i]) < a.timestamp(&a.bytesArray[j]) 301 | } 302 | 303 | // Matching 'struct perf_event_header in 304 | type PerfEventHeader struct { 305 | Type uint32 306 | Misc uint16 307 | TotalSize uint16 308 | } 309 | 310 | // Matching 'struct perf_event_lost in kernel sources 311 | type PerfEventLost struct { 312 | PerfEventHeader 313 | Id uint64 314 | Lost uint64 315 | } 316 | 317 | // nowNanoseconds returns a time that can be compared to bpf_ktime_get_ns() 318 | func nowNanoseconds() uint64 { 319 | var ts syscall.Timespec 320 | syscall.Syscall(syscall.SYS_CLOCK_GETTIME, 1 /* CLOCK_MONOTONIC */, uintptr(unsafe.Pointer(&ts)), 0) 321 | sec, nsec := ts.Unix() 322 | return 1000*1000*1000*uint64(sec) + uint64(nsec) 323 | } 324 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/perf_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package elf 4 | 5 | import "fmt" 6 | 7 | type PerfMap struct{} 8 | 9 | func InitPerfMap(b *Module, mapName string, receiverChan chan []byte) (*PerfMap, error) { 10 | return nil, fmt.Errorf("not supported") 11 | } 12 | 13 | func (pm *PerfMap) SetTimestampFunc(timestamp func(*[]byte) uint64) {} 14 | 15 | func (pm *PerfMap) PollStart() {} 16 | 17 | func (pm *PerfMap) PollStop() {} 18 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/pinning.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package elf 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | "unsafe" 11 | 12 | "github.com/iovisor/gobpf/pkg/bpffs" 13 | ) 14 | 15 | /* 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern __u64 ptr_to_u64(void *); 22 | 23 | int bpf_pin_object(int fd, const char *pathname) 24 | { 25 | union bpf_attr attr = {}; 26 | 27 | attr.pathname = ptr_to_u64((void *)pathname); 28 | attr.bpf_fd = fd; 29 | 30 | return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr)); 31 | } 32 | */ 33 | import "C" 34 | 35 | const ( 36 | BPFDirGlobals = "globals" // as in iproute2's BPF_DIR_GLOBALS 37 | BPFFSPath = "/sys/fs/bpf/" 38 | ) 39 | 40 | func validPinPath(PinPath string) bool { 41 | if !strings.HasPrefix(PinPath, BPFFSPath) { 42 | return false 43 | } 44 | 45 | return filepath.Clean(PinPath) == PinPath 46 | } 47 | 48 | func pinObject(fd int, pinPath string) error { 49 | mounted, err := bpffs.IsMounted() 50 | if err != nil { 51 | return fmt.Errorf("error checking if %q is mounted: %v", BPFFSPath, err) 52 | } 53 | if !mounted { 54 | return fmt.Errorf("bpf fs not mounted at %q", BPFFSPath) 55 | } 56 | err = os.MkdirAll(filepath.Dir(pinPath), 0755) 57 | if err != nil { 58 | return fmt.Errorf("error creating directory %q: %v", filepath.Dir(pinPath), err) 59 | } 60 | _, err = os.Stat(pinPath) 61 | if err == nil { 62 | return fmt.Errorf("aborting, found file at %q", pinPath) 63 | } 64 | if err != nil && !os.IsNotExist(err) { 65 | return fmt.Errorf("failed to stat %q: %v", pinPath, err) 66 | } 67 | pinPathC := C.CString(pinPath) 68 | defer C.free(unsafe.Pointer(pinPathC)) 69 | ret, err := C.bpf_pin_object(C.int(fd), pinPathC) 70 | if ret != 0 { 71 | return fmt.Errorf("error pinning object to %q: %v", pinPath, err) 72 | } 73 | return nil 74 | } 75 | 76 | // PinObjectGlobal pins and object to a name in a namespaces 77 | // e.g. `/sys/fs/bpf/my-namespace/globals/my-name` 78 | func PinObjectGlobal(fd int, namespace, name string) error { 79 | pinPath := filepath.Join(BPFFSPath, namespace, BPFDirGlobals, name) 80 | return pinObject(fd, pinPath) 81 | } 82 | 83 | // PinObject pins an object to a path 84 | func PinObject(fd int, pinPath string) error { 85 | if !validPinPath(pinPath) { 86 | return fmt.Errorf("not a valid pin path: %s", pinPath) 87 | } 88 | return pinObject(fd, pinPath) 89 | } 90 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/table.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Copyright 2016 Cilium Project 4 | // Copyright 2016 Sylvain Afchain 5 | // Copyright 2016 Kinvolk 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | package elf 20 | 21 | import ( 22 | "fmt" 23 | "syscall" 24 | "unsafe" 25 | ) 26 | 27 | /* 28 | #include 29 | #include 30 | 31 | extern __u64 ptr_to_u64(void *); 32 | 33 | // from https://github.com/cilium/cilium/blob/master/pkg/bpf/bpf.go 34 | // Apache License, Version 2.0 35 | 36 | static void create_bpf_update_elem(int fd, void *key, void *value, 37 | unsigned long long flags, void *attr) 38 | { 39 | union bpf_attr* ptr_bpf_attr; 40 | ptr_bpf_attr = (union bpf_attr*)attr; 41 | ptr_bpf_attr->map_fd = fd; 42 | ptr_bpf_attr->key = ptr_to_u64(key); 43 | ptr_bpf_attr->value = ptr_to_u64(value); 44 | ptr_bpf_attr->flags = flags; 45 | } 46 | 47 | static void create_bpf_lookup_elem(int fd, void *key, void *value, void *attr) 48 | { 49 | union bpf_attr* ptr_bpf_attr; 50 | ptr_bpf_attr = (union bpf_attr*)attr; 51 | ptr_bpf_attr->map_fd = fd; 52 | ptr_bpf_attr->key = ptr_to_u64(key); 53 | ptr_bpf_attr->value = ptr_to_u64(value); 54 | } 55 | 56 | static int next_bpf_elem(int fd, void *key, void *next_key, void *attr) 57 | { 58 | union bpf_attr* ptr_bpf_attr; 59 | ptr_bpf_attr = (union bpf_attr*)attr; 60 | ptr_bpf_attr->map_fd = fd; 61 | ptr_bpf_attr->key = ptr_to_u64(key); 62 | ptr_bpf_attr->next_key = ptr_to_u64(next_key); 63 | } 64 | */ 65 | import "C" 66 | 67 | // UpdateElement stores value in key in the map stored in mp. 68 | // The flags can have the following values (if you include "uapi/linux/bpf.h"): 69 | // C.BPF_ANY to create new element or update existing; 70 | // C.BPF_NOEXIST to create new element if it didn't exist; 71 | // C.BPF_EXIST to update existing element. 72 | func (b *Module) UpdateElement(mp *Map, key, value unsafe.Pointer, flags uint64) error { 73 | uba := C.union_bpf_attr{} 74 | C.create_bpf_update_elem( 75 | C.int(mp.m.fd), 76 | key, 77 | value, 78 | C.ulonglong(flags), 79 | unsafe.Pointer(&uba), 80 | ) 81 | ret, _, err := syscall.Syscall( 82 | C.__NR_bpf, 83 | C.BPF_MAP_UPDATE_ELEM, 84 | uintptr(unsafe.Pointer(&uba)), 85 | unsafe.Sizeof(uba), 86 | ) 87 | 88 | if ret != 0 || err != 0 { 89 | return fmt.Errorf("unable to update element: %s", err) 90 | } 91 | 92 | return nil 93 | } 94 | 95 | // LookupElement looks up the given key in the the map stored in mp. 96 | // The value is stored in the value unsafe.Pointer. 97 | func (b *Module) LookupElement(mp *Map, key, value unsafe.Pointer) error { 98 | uba := C.union_bpf_attr{} 99 | C.create_bpf_lookup_elem( 100 | C.int(mp.m.fd), 101 | key, 102 | value, 103 | unsafe.Pointer(&uba), 104 | ) 105 | ret, _, err := syscall.Syscall( 106 | C.__NR_bpf, 107 | C.BPF_MAP_LOOKUP_ELEM, 108 | uintptr(unsafe.Pointer(&uba)), 109 | unsafe.Sizeof(uba), 110 | ) 111 | 112 | if ret != 0 || err != 0 { 113 | return fmt.Errorf("unable to lookup element: %s", err) 114 | } 115 | 116 | return nil 117 | } 118 | 119 | // DeleteElement deletes the given key in the the map stored in mp. 120 | // The key is stored in the key unsafe.Pointer. 121 | func (b *Module) DeleteElement(mp *Map, key unsafe.Pointer) error { 122 | uba := C.union_bpf_attr{} 123 | value := unsafe.Pointer(nil) 124 | C.create_bpf_lookup_elem( 125 | C.int(mp.m.fd), 126 | key, 127 | value, 128 | unsafe.Pointer(&uba), 129 | ) 130 | ret, _, err := syscall.Syscall( 131 | C.__NR_bpf, 132 | C.BPF_MAP_DELETE_ELEM, 133 | uintptr(unsafe.Pointer(&uba)), 134 | unsafe.Sizeof(uba), 135 | ) 136 | 137 | if ret != 0 || err != 0 { 138 | return fmt.Errorf("unable to delete element: %s", err) 139 | } 140 | 141 | return nil 142 | } 143 | 144 | // LookupNextElement looks up the next element in mp using the given key. 145 | // The next key and the value are stored in the nextKey and value parameter. 146 | // Returns false at the end of the mp. 147 | func (b *Module) LookupNextElement(mp *Map, key, nextKey, value unsafe.Pointer) (bool, error) { 148 | uba := C.union_bpf_attr{} 149 | C.next_bpf_elem( 150 | C.int(mp.m.fd), 151 | key, 152 | nextKey, 153 | unsafe.Pointer(&uba), 154 | ) 155 | ret, _, err := syscall.Syscall( 156 | C.__NR_bpf, 157 | C.BPF_MAP_GET_NEXT_KEY, 158 | uintptr(unsafe.Pointer(&uba)), 159 | unsafe.Sizeof(uba), 160 | ) 161 | if err != 0 { 162 | return false, fmt.Errorf("unable to find next element: %s", err) 163 | } 164 | if ret != 0 { 165 | return false, nil 166 | } 167 | 168 | if err := b.LookupElement(mp, nextKey, value); err != nil { 169 | return false, err 170 | } 171 | return true, nil 172 | } 173 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/utsname_int8.go: -------------------------------------------------------------------------------- 1 | // +build linux,amd64 linux,arm64 2 | 3 | package elf 4 | 5 | func utsnameStr(in []int8) string { 6 | out := make([]byte, len(in)) 7 | for i := 0; i < len(in); i++ { 8 | if in[i] == 0 { 9 | break 10 | } 11 | out = append(out, byte(in[i])) 12 | } 13 | return string(out) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/elf/utsname_uint8.go: -------------------------------------------------------------------------------- 1 | // +build linux,arm linux,ppc64 linux,ppc64le s390x 2 | 3 | package elf 4 | 5 | func utsnameStr(in []uint8) string { 6 | out := make([]byte, len(in)) 7 | for i := 0; i < len(in); i++ { 8 | if in[i] == 0 { 9 | break 10 | } 11 | out = append(out, byte(in[i])) 12 | } 13 | return string(out) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/bash_readline/bash_readline.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Louis McCormack 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "encoding/binary" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | 24 | bpf "github.com/iovisor/gobpf/bcc" 25 | ) 26 | 27 | const source string = ` 28 | #include 29 | 30 | struct readline_event_t { 31 | u32 pid; 32 | char str[80]; 33 | } __attribute__((packed)); 34 | 35 | BPF_PERF_OUTPUT(readline_events); 36 | 37 | int get_return_value(struct pt_regs *ctx) { 38 | struct readline_event_t event = {}; 39 | u32 pid; 40 | if (!PT_REGS_RC(ctx)) 41 | return 0; 42 | pid = bpf_get_current_pid_tgid(); 43 | event.pid = pid; 44 | bpf_probe_read(&event.str, sizeof(event.str), (void *)PT_REGS_RC(ctx)); 45 | readline_events.perf_submit(ctx, &event, sizeof(event)); 46 | 47 | return 0; 48 | } 49 | ` 50 | 51 | type readlineEvent struct { 52 | Pid uint32 53 | Str [80]byte 54 | } 55 | 56 | func main() { 57 | m := bpf.NewModule(source, []string{}) 58 | defer m.Close() 59 | 60 | readlineUretprobe, err := m.LoadUprobe("get_return_value") 61 | if err != nil { 62 | fmt.Fprintf(os.Stderr, "Failed to load get_return_value: %s\n", err) 63 | os.Exit(1) 64 | } 65 | 66 | err = m.AttachUretprobe("/bin/bash", "readline", readlineUretprobe, -1) 67 | if err != nil { 68 | fmt.Fprintf(os.Stderr, "Failed to attach return_value: %s\n", err) 69 | os.Exit(1) 70 | } 71 | 72 | table := bpf.NewTable(m.TableId("readline_events"), m) 73 | 74 | channel := make(chan []byte) 75 | 76 | perfMap, err := bpf.InitPerfMap(table, channel) 77 | if err != nil { 78 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 79 | os.Exit(1) 80 | } 81 | 82 | sig := make(chan os.Signal, 1) 83 | signal.Notify(sig, os.Interrupt, os.Kill) 84 | 85 | fmt.Printf("%10s\t%s\n", "PID", "COMMAND") 86 | go func() { 87 | var event readlineEvent 88 | for { 89 | data := <-channel 90 | err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event) 91 | if err != nil { 92 | fmt.Printf("failed to decode received data: %s\n", err) 93 | continue 94 | } 95 | // Convert C string (null-terminated) to Go string 96 | comm := string(event.Str[:bytes.IndexByte(event.Str[:], 0)]) 97 | fmt.Printf("%10d\t%s\n", event.Pid, comm) 98 | } 99 | }() 100 | 101 | perfMap.Start() 102 | <-sig 103 | perfMap.Stop() 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/execsnoop/execsnoop.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package main 14 | 15 | import ( 16 | "bufio" 17 | "bytes" 18 | "encoding/binary" 19 | "flag" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | "strconv" 24 | "strings" 25 | "unsafe" 26 | 27 | bpf "github.com/iovisor/gobpf/bcc" 28 | ) 29 | 30 | import "C" 31 | 32 | type EventType int32 33 | 34 | const ( 35 | eventArg EventType = iota 36 | eventRet 37 | ) 38 | 39 | const source string = ` 40 | #include 41 | #include 42 | #include 43 | 44 | #define ARGSIZE 128 45 | 46 | enum event_type { 47 | EVENT_ARG, 48 | EVENT_RET, 49 | }; 50 | 51 | struct data_t { 52 | u64 pid; // PID as in the userspace term (i.e. task->tgid in kernel) 53 | u64 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel) 54 | char comm[TASK_COMM_LEN]; 55 | enum event_type type; 56 | char argv[ARGSIZE]; 57 | int retval; 58 | }; 59 | 60 | BPF_PERF_OUTPUT(events); 61 | 62 | static int __submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 63 | { 64 | bpf_probe_read(data->argv, sizeof(data->argv), ptr); 65 | events.perf_submit(ctx, data, sizeof(struct data_t)); 66 | return 1; 67 | } 68 | 69 | static int submit_arg(struct pt_regs *ctx, void *ptr, struct data_t *data) 70 | { 71 | const char *argp = NULL; 72 | bpf_probe_read(&argp, sizeof(argp), ptr); 73 | if (argp) { 74 | return __submit_arg(ctx, (void *)(argp), data); 75 | } 76 | return 0; 77 | } 78 | 79 | int syscall__execve(struct pt_regs *ctx, 80 | const char __user *filename, 81 | const char __user *const __user *__argv, 82 | const char __user *const __user *__envp) 83 | { 84 | // create data here and pass to submit_arg to save stack space (#555) 85 | struct data_t data = {}; 86 | struct task_struct *task; 87 | 88 | data.pid = bpf_get_current_pid_tgid() >> 32; 89 | 90 | task = (struct task_struct *)bpf_get_current_task(); 91 | // Some kernels, like Ubuntu 4.13.0-generic, return 0 92 | // as the real_parent->tgid. 93 | // We use the getPpid function as a fallback in those cases. 94 | // See https://github.com/iovisor/bcc/issues/1883. 95 | data.ppid = task->real_parent->tgid; 96 | 97 | bpf_get_current_comm(&data.comm, sizeof(data.comm)); 98 | data.type = EVENT_ARG; 99 | 100 | __submit_arg(ctx, (void *)filename, &data); 101 | 102 | // skip first arg, as we submitted filename 103 | #pragma unroll 104 | for (int i = 1; i < MAX_ARGS; i++) { 105 | if (submit_arg(ctx, (void *)&__argv[i], &data) == 0) 106 | goto out; 107 | } 108 | 109 | // handle truncated argument list 110 | char ellipsis[] = "..."; 111 | __submit_arg(ctx, (void *)ellipsis, &data); 112 | out: 113 | return 0; 114 | } 115 | 116 | int do_ret_sys_execve(struct pt_regs *ctx) 117 | { 118 | struct data_t data = {}; 119 | struct task_struct *task; 120 | 121 | data.pid = bpf_get_current_pid_tgid() >> 32; 122 | 123 | task = (struct task_struct *)bpf_get_current_task(); 124 | // Some kernels, like Ubuntu 4.13.0-generic, return 0 125 | // as the real_parent->tgid. 126 | // We use the getPpid function as a fallback in those cases. 127 | // See https://github.com/iovisor/bcc/issues/1883. 128 | data.ppid = task->real_parent->tgid; 129 | 130 | bpf_get_current_comm(&data.comm, sizeof(data.comm)); 131 | data.type = EVENT_RET; 132 | data.retval = PT_REGS_RC(ctx); 133 | events.perf_submit(ctx, &data, sizeof(data)); 134 | 135 | return 0; 136 | } 137 | ` 138 | 139 | type execveEvent struct { 140 | Pid uint64 141 | Ppid uint64 142 | Comm [16]byte 143 | Type int32 144 | Argv [128]byte 145 | RetVal int32 146 | } 147 | 148 | type eventPayload struct { 149 | Time string `json:"time,omitempty"` 150 | Comm string `json:"comm"` 151 | Pid uint64 `json:"pid"` 152 | Ppid string `json:"ppid"` 153 | Argv string `json:"argv"` 154 | RetVal int32 `json:"retval"` 155 | } 156 | 157 | // getPpid is a fallback to read the parent PID from /proc. 158 | // Some kernel versions, like 4.13.0 return 0 getting the parent PID 159 | // from the current task, so we need to use this fallback to have 160 | // the parent PID in any kernel. 161 | func getPpid(pid uint64) uint64 { 162 | f, err := os.OpenFile(fmt.Sprintf("/proc/%d/status", pid), os.O_RDONLY, os.ModePerm) 163 | if err != nil { 164 | return 0 165 | } 166 | defer f.Close() 167 | 168 | sc := bufio.NewScanner(f) 169 | for sc.Scan() { 170 | text := sc.Text() 171 | if strings.Contains(text, "PPid:") { 172 | f := strings.Fields(text) 173 | i, _ := strconv.ParseUint(f[len(f)-1], 10, 64) 174 | return i 175 | } 176 | } 177 | return 0 178 | } 179 | 180 | func main() { 181 | run() 182 | } 183 | 184 | func run() { 185 | traceFailed := flag.Bool("x", false, "trace failed exec()s") 186 | timestamps := flag.Bool("t", false, "include timestamps") 187 | quotemarks := flag.Bool("q", false, `add "quotemarks" around arguments`) 188 | filterComm := flag.String("n", "", `only print command lines containing a name, for example "main"`) 189 | filterArg := flag.String("l", "", `only print command where arguments contain an argument, for example "tpkg"`) 190 | format := flag.String("o", "table", "output format, either table or json") 191 | pretty := flag.Bool("p", false, "pretty print json output") 192 | maxArgs := flag.Uint64("m", 20, "maximum number of arguments parsed and displayed, defaults to 20") 193 | 194 | flag.Parse() 195 | 196 | m := bpf.NewModule(strings.Replace(source, "MAX_ARGS", strconv.FormatUint(*maxArgs, 10), -1), []string{}) 197 | defer m.Close() 198 | 199 | fnName := bpf.GetSyscallFnName("execve") 200 | 201 | kprobe, err := m.LoadKprobe("syscall__execve") 202 | if err != nil { 203 | fmt.Fprintf(os.Stderr, "Failed to load syscall__execve: %s\n", err) 204 | os.Exit(1) 205 | } 206 | 207 | // passing -1 for maxActive signifies to use the default 208 | // according to the kernel kprobes documentation 209 | if err := m.AttachKprobe(fnName, kprobe, -1); err != nil { 210 | fmt.Fprintf(os.Stderr, "Failed to attach syscall__execve: %s\n", err) 211 | os.Exit(1) 212 | } 213 | 214 | kretprobe, err := m.LoadKprobe("do_ret_sys_execve") 215 | if err != nil { 216 | fmt.Fprintf(os.Stderr, "Failed to load do_ret_sys_execve: %s\n", err) 217 | os.Exit(1) 218 | } 219 | 220 | // passing -1 for maxActive signifies to use the default 221 | // according to the kernel kretprobes documentation 222 | if err := m.AttachKretprobe(fnName, kretprobe, -1); err != nil { 223 | fmt.Fprintf(os.Stderr, "Failed to attach do_ret_sys_execve: %s\n", err) 224 | os.Exit(1) 225 | } 226 | 227 | table := bpf.NewTable(m.TableId("events"), m) 228 | 229 | channel := make(chan []byte, 1000) 230 | 231 | perfMap, err := bpf.InitPerfMap(table, channel) 232 | if err != nil { 233 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 234 | os.Exit(1) 235 | } 236 | 237 | sig := make(chan os.Signal, 1) 238 | signal.Notify(sig, os.Interrupt, os.Kill) 239 | 240 | go func() { 241 | out := newOutput(*format, *pretty, *timestamps) 242 | out.PrintHeader() 243 | 244 | args := make(map[uint64][]string) 245 | 246 | for { 247 | data := <-channel 248 | 249 | var event execveEvent 250 | err := binary.Read(bytes.NewBuffer(data), bpf.GetHostByteOrder(), &event) 251 | 252 | if err != nil { 253 | fmt.Printf("failed to decode received data: %s\n", err) 254 | continue 255 | } 256 | 257 | if eventArg == EventType(event.Type) { 258 | e, ok := args[event.Pid] 259 | if !ok { 260 | e = make([]string, 0) 261 | } 262 | argv := (*C.char)(unsafe.Pointer(&event.Argv)) 263 | 264 | e = append(e, C.GoString(argv)) 265 | args[event.Pid] = e 266 | } else { 267 | if event.RetVal != 0 && !*traceFailed { 268 | delete(args, event.Pid) 269 | continue 270 | } 271 | 272 | comm := C.GoString((*C.char)(unsafe.Pointer(&event.Comm))) 273 | if *filterComm != "" && !strings.Contains(comm, *filterComm) { 274 | delete(args, event.Pid) 275 | continue 276 | } 277 | 278 | argv, ok := args[event.Pid] 279 | if !ok { 280 | continue 281 | } 282 | 283 | if *filterArg != "" && !strings.Contains(strings.Join(argv, " "), *filterArg) { 284 | delete(args, event.Pid) 285 | continue 286 | } 287 | 288 | p := eventPayload{ 289 | Pid: event.Pid, 290 | Ppid: "?", 291 | Comm: comm, 292 | RetVal: event.RetVal, 293 | } 294 | 295 | if event.Ppid == 0 { 296 | event.Ppid = getPpid(event.Pid) 297 | } 298 | 299 | if event.Ppid != 0 { 300 | p.Ppid = strconv.FormatUint(event.Ppid, 10) 301 | } 302 | 303 | if *quotemarks { 304 | var b bytes.Buffer 305 | for i, a := range argv { 306 | b.WriteString(strings.Replace(a, `"`, `\"`, -1)) 307 | if i != len(argv)-1 { 308 | b.WriteString(" ") 309 | } 310 | } 311 | p.Argv = b.String() 312 | } else { 313 | p.Argv = strings.Join(argv, " ") 314 | } 315 | p.Argv = strings.TrimSpace(strings.Replace(p.Argv, "\n", "\\n", -1)) 316 | 317 | out.PrintLine(p) 318 | delete(args, event.Pid) 319 | } 320 | } 321 | }() 322 | 323 | perfMap.Start() 324 | <-sig 325 | perfMap.Stop() 326 | } 327 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/execsnoop/output.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type output interface { 10 | PrintHeader() 11 | PrintLine(eventPayload) 12 | } 13 | 14 | type timing struct { 15 | start time.Time 16 | } 17 | 18 | func newTiming() timing { 19 | return timing{time.Now()} 20 | } 21 | 22 | func (t timing) Now() float64 { 23 | return time.Now().Sub(t.start).Seconds() 24 | } 25 | 26 | func newOutput(name string, pretty, timestamp bool) output { 27 | switch name { 28 | case "json": 29 | return newJSONOutput(pretty, timestamp) 30 | } 31 | return newTableOutput(timestamp) 32 | } 33 | 34 | type tableOutput struct { 35 | timing timing 36 | timestamp bool 37 | } 38 | 39 | func (t tableOutput) PrintHeader() { 40 | header := "%-16s %-6s %-6s %3s %s\n" 41 | args := []interface{}{"PCOMM", "PID", "PPID", "RET", "ARGS"} 42 | if t.timestamp { 43 | header = "%-8s" + header 44 | args = []interface{}{"TIME(s)", "PCOMM", "PID", "PPID", "RET", "ARGS"} 45 | } 46 | fmt.Printf(header, args...) 47 | } 48 | 49 | func (t tableOutput) PrintLine(e eventPayload) { 50 | header := "%-16s %-6d %-6s %3d %s\n" 51 | args := []interface{}{e.Comm, e.Pid, e.Ppid, e.RetVal, e.Argv} 52 | if t.timestamp { 53 | header = "%-8.3f" + header 54 | args = append([]interface{}{t.timing.Now()}, args...) 55 | } 56 | fmt.Printf(header, args...) 57 | } 58 | 59 | func newTableOutput(timestamp bool) output { 60 | return &tableOutput{newTiming(), timestamp} 61 | } 62 | 63 | type jsonOutput struct { 64 | timing timing 65 | pretty bool 66 | timestamp bool 67 | } 68 | 69 | func (jsonOutput) PrintHeader() { 70 | // jsonOutput doesn't have any header 71 | } 72 | 73 | func (j jsonOutput) PrintLine(e eventPayload) { 74 | if j.timestamp { 75 | e.Time = fmt.Sprintf("%.3f", j.timing.Now()) 76 | } 77 | var m []byte 78 | if j.pretty { 79 | m, _ = json.MarshalIndent(e, "", " ") 80 | } else { 81 | m, _ = json.Marshal(e) 82 | } 83 | if len(m) > 0 { 84 | fmt.Println(string(m)) 85 | } 86 | } 87 | 88 | func newJSONOutput(pretty, timestamp bool) output { 89 | return jsonOutput{newTiming(), pretty, timestamp} 90 | } 91 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/perf/perf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "encoding/binary" 20 | "fmt" 21 | "os" 22 | "os/signal" 23 | "unsafe" 24 | 25 | bpf "github.com/iovisor/gobpf/bcc" 26 | ) 27 | 28 | import "C" 29 | 30 | const source string = ` 31 | #include 32 | #include 33 | 34 | typedef struct { 35 | u32 pid; 36 | uid_t uid; 37 | gid_t gid; 38 | int ret; 39 | char filename[256]; 40 | } chown_event_t; 41 | 42 | BPF_PERF_OUTPUT(chown_events); 43 | BPF_HASH(chowncall, u64, chown_event_t); 44 | 45 | int kprobe__sys_fchownat(struct pt_regs *ctx, int dfd, const char *filename, 46 | uid_t uid, gid_t gid, int flag) 47 | { 48 | u64 pid = bpf_get_current_pid_tgid(); 49 | chown_event_t event = { 50 | .pid = pid >> 32, 51 | .uid = uid, 52 | .gid = gid, 53 | }; 54 | bpf_probe_read(&event.filename, sizeof(event.filename), (void *)filename); 55 | chowncall.update(&pid, &event); 56 | return 0; 57 | } 58 | 59 | int kretprobe__sys_fchownat(struct pt_regs *ctx) 60 | { 61 | int ret = PT_REGS_RC(ctx); 62 | u64 pid = bpf_get_current_pid_tgid(); 63 | chown_event_t *eventp = chowncall.lookup(&pid); 64 | if (eventp == 0) { 65 | return 0; 66 | } 67 | chown_event_t event = *eventp; 68 | event.ret = ret; 69 | chown_events.perf_submit(ctx, &event, sizeof(event)); 70 | chowncall.delete(&pid); 71 | return 0; 72 | }; 73 | ` 74 | 75 | type chownEvent struct { 76 | Pid uint32 77 | Uid uint32 78 | Gid uint32 79 | ReturnValue int32 80 | Filename [256]byte 81 | } 82 | 83 | func main() { 84 | m := bpf.NewModule(source, []string{}) 85 | defer m.Close() 86 | 87 | chownKprobe, err := m.LoadKprobe("kprobe__sys_fchownat") 88 | if err != nil { 89 | fmt.Fprintf(os.Stderr, "Failed to load kprobe__sys_fchownat: %s\n", err) 90 | os.Exit(1) 91 | } 92 | 93 | syscallName := bpf.GetSyscallFnName("fchownat") 94 | 95 | // passing -1 for maxActive signifies to use the default 96 | // according to the kernel kprobes documentation 97 | err = m.AttachKprobe(syscallName, chownKprobe, -1) 98 | if err != nil { 99 | fmt.Fprintf(os.Stderr, "Failed to attach kprobe__sys_fchownat: %s\n", err) 100 | os.Exit(1) 101 | } 102 | 103 | chownKretprobe, err := m.LoadKprobe("kretprobe__sys_fchownat") 104 | if err != nil { 105 | fmt.Fprintf(os.Stderr, "Failed to load kretprobe__sys_fchownat: %s\n", err) 106 | os.Exit(1) 107 | } 108 | 109 | // passing -1 for maxActive signifies to use the default 110 | // according to the kernel kretprobes documentation 111 | err = m.AttachKretprobe(syscallName, chownKretprobe, -1) 112 | if err != nil { 113 | fmt.Fprintf(os.Stderr, "Failed to attach kretprobe__sys_fchownat: %s\n", err) 114 | os.Exit(1) 115 | } 116 | 117 | table := bpf.NewTable(m.TableId("chown_events"), m) 118 | 119 | channel := make(chan []byte) 120 | 121 | perfMap, err := bpf.InitPerfMap(table, channel) 122 | if err != nil { 123 | fmt.Fprintf(os.Stderr, "Failed to init perf map: %s\n", err) 124 | os.Exit(1) 125 | } 126 | 127 | sig := make(chan os.Signal, 1) 128 | signal.Notify(sig, os.Interrupt, os.Kill) 129 | 130 | go func() { 131 | var event chownEvent 132 | for { 133 | data := <-channel 134 | err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event) 135 | if err != nil { 136 | fmt.Printf("failed to decode received data: %s\n", err) 137 | continue 138 | } 139 | filename := (*C.char)(unsafe.Pointer(&event.Filename)) 140 | fmt.Printf("uid %d gid %d pid %d called fchownat(2) on %s (return value: %d)\n", 141 | event.Uid, event.Gid, event.Pid, C.GoString(filename), event.ReturnValue) 142 | } 143 | }() 144 | 145 | perfMap.Start() 146 | <-sig 147 | perfMap.Stop() 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/strlen_count/strlen_count.go: -------------------------------------------------------------------------------- 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | package main 14 | 15 | import ( 16 | "encoding/binary" 17 | "flag" 18 | "fmt" 19 | "os" 20 | "os/signal" 21 | "regexp" 22 | 23 | bpf "github.com/iovisor/gobpf/bcc" 24 | ) 25 | 26 | import "C" 27 | 28 | const source string = ` 29 | #include 30 | typedef char strlenkey_t[80]; 31 | BPF_HASH(counts, strlenkey_t); 32 | 33 | int count(struct pt_regs *ctx) { 34 | if (!PT_REGS_PARM1(ctx)) 35 | return 0; 36 | 37 | strlenkey_t key; 38 | u64 zero = 0, *val; 39 | 40 | bpf_probe_read(&key, sizeof(key), (void *)PT_REGS_PARM1(ctx)); 41 | val = counts.lookup_or_init(&key, &zero); 42 | (*val)++; 43 | return 0; 44 | } 45 | ` 46 | 47 | var ansiEscape = regexp.MustCompile(`[[:cntrl:]]`) 48 | 49 | func main() { 50 | pid := flag.Int("pid", -1, "attach to pid, default is all processes") 51 | flag.Parse() 52 | m := bpf.NewModule(source, []string{}) 53 | defer m.Close() 54 | 55 | strlenUprobe, err := m.LoadUprobe("count") 56 | if err != nil { 57 | fmt.Fprintf(os.Stderr, "Failed to load uprobe count: %s\n", err) 58 | os.Exit(1) 59 | } 60 | 61 | err = m.AttachUprobe("c", "strlen", strlenUprobe, *pid) 62 | if err != nil { 63 | fmt.Fprintf(os.Stderr, "Failed to attach uprobe to strlen: %s\n", err) 64 | os.Exit(1) 65 | } 66 | 67 | table := bpf.NewTable(m.TableId("counts"), m) 68 | 69 | fmt.Println("Tracing strlen()... hit Ctrl-C to end.") 70 | 71 | sig := make(chan os.Signal, 1) 72 | signal.Notify(sig, os.Interrupt) 73 | <-sig 74 | 75 | fmt.Printf("%10s %s\n", "COUNT", "STRING") 76 | for it := table.Iter(); it.Next(); { 77 | k := ansiEscape.ReplaceAll(it.Key(), []byte{}) 78 | v := binary.LittleEndian.Uint64(it.Leaf()) 79 | fmt.Printf("%10d \"%s\"\n", v, k) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/bcc/xdp/xdp_drop.go: -------------------------------------------------------------------------------- 1 | // xdp_drop.go Drop incoming packets on XDP layer and count for which 2 | // protocol type. Based on: 3 | // https://github.com/iovisor/bcc/blob/master/examples/networking/xdp/xdp_drop_count.py 4 | // 5 | // Copyright (c) 2017 GustavoKatel 6 | // Licensed under the Apache License, Version 2.0 (the "License") 7 | 8 | package main 9 | 10 | import ( 11 | "fmt" 12 | "os" 13 | "os/signal" 14 | 15 | bpf "github.com/iovisor/gobpf/bcc" 16 | ) 17 | 18 | /* 19 | #cgo CFLAGS: -I/usr/include/bcc/compat 20 | #cgo LDFLAGS: -lbcc 21 | #include 22 | #include 23 | void perf_reader_free(void *ptr); 24 | */ 25 | import "C" 26 | 27 | const source string = ` 28 | #define KBUILD_MODNAME "foo" 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | BPF_TABLE("array", int, long, dropcnt, 256); 38 | 39 | static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) { 40 | struct iphdr *iph = data + nh_off; 41 | 42 | if ((void*)&iph[1] > data_end) 43 | return 0; 44 | return iph->protocol; 45 | } 46 | 47 | static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) { 48 | struct ipv6hdr *ip6h = data + nh_off; 49 | 50 | if ((void*)&ip6h[1] > data_end) 51 | return 0; 52 | return ip6h->nexthdr; 53 | } 54 | 55 | int xdp_prog1(struct CTXTYPE *ctx) { 56 | 57 | void* data_end = (void*)(long)ctx->data_end; 58 | void* data = (void*)(long)ctx->data; 59 | 60 | struct ethhdr *eth = data; 61 | 62 | // drop packets 63 | int rc = RETURNCODE; // let pass XDP_PASS or redirect to tx via XDP_TX 64 | long *value; 65 | uint16_t h_proto; 66 | uint64_t nh_off = 0; 67 | int index; 68 | 69 | nh_off = sizeof(*eth); 70 | 71 | if (data + nh_off > data_end) 72 | return rc; 73 | 74 | h_proto = eth->h_proto; 75 | 76 | // While the following code appears to be duplicated accidentally, 77 | // it's intentional to handle double tags in ethernet frames. 78 | if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 79 | struct vlan_hdr *vhdr; 80 | 81 | vhdr = data + nh_off; 82 | nh_off += sizeof(struct vlan_hdr); 83 | if (data + nh_off > data_end) 84 | return rc; 85 | h_proto = vhdr->h_vlan_encapsulated_proto; 86 | } 87 | if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 88 | struct vlan_hdr *vhdr; 89 | 90 | vhdr = data + nh_off; 91 | nh_off += sizeof(struct vlan_hdr); 92 | if (data + nh_off > data_end) 93 | return rc; 94 | h_proto = vhdr->h_vlan_encapsulated_proto; 95 | } 96 | 97 | if (h_proto == htons(ETH_P_IP)) 98 | index = parse_ipv4(data, nh_off, data_end); 99 | else if (h_proto == htons(ETH_P_IPV6)) 100 | index = parse_ipv6(data, nh_off, data_end); 101 | else 102 | index = 0; 103 | 104 | value = dropcnt.lookup(&index); 105 | if (value) lock_xadd(value, 1); 106 | 107 | return rc; 108 | } 109 | ` 110 | 111 | func usage() { 112 | fmt.Printf("Usage: %v \n", os.Args[0]) 113 | fmt.Printf("e.g.: %v eth0\n", os.Args[0]) 114 | os.Exit(1) 115 | } 116 | 117 | func main() { 118 | var device string 119 | 120 | if len(os.Args) != 2 { 121 | usage() 122 | } 123 | 124 | device = os.Args[1] 125 | 126 | ret := "XDP_DROP" 127 | ctxtype := "xdp_md" 128 | 129 | module := bpf.NewModule(source, []string{ 130 | "-w", 131 | "-DRETURNCODE=" + ret, 132 | "-DCTXTYPE=" + ctxtype, 133 | }) 134 | defer module.Close() 135 | 136 | fn, err := module.Load("xdp_prog1", C.BPF_PROG_TYPE_XDP, 1, 65536) 137 | if err != nil { 138 | fmt.Fprintf(os.Stderr, "Failed to load xdp prog: %v\n", err) 139 | os.Exit(1) 140 | } 141 | 142 | err = module.AttachXDP(device, fn) 143 | if err != nil { 144 | fmt.Fprintf(os.Stderr, "Failed to attach xdp prog: %v\n", err) 145 | os.Exit(1) 146 | } 147 | 148 | defer func() { 149 | if err := module.RemoveXDP(device); err != nil { 150 | fmt.Fprintf(os.Stderr, "Failed to remove XDP from %s: %v\n", device, err) 151 | } 152 | }() 153 | 154 | fmt.Println("Dropping packets, hit CTRL+C to stop") 155 | 156 | sig := make(chan os.Signal, 1) 157 | signal.Notify(sig, os.Interrupt, os.Kill) 158 | 159 | dropcnt := bpf.NewTable(module.TableId("dropcnt"), module) 160 | 161 | <-sig 162 | 163 | fmt.Printf("\n{IP protocol-number}: {total dropped pkts}\n") 164 | for it := dropcnt.Iter(); it.Next(); { 165 | key := bpf.GetHostByteOrder().Uint32(it.Key()) 166 | value := bpf.GetHostByteOrder().Uint64(it.Leaf()) 167 | 168 | if value > 0 { 169 | fmt.Printf("%v: %v pkts\n", key, value) 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/examples/tracepipe/tracepipe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "os" 20 | 21 | "github.com/iovisor/gobpf/pkg/tracepipe" 22 | ) 23 | 24 | func main() { 25 | tp, err := tracepipe.New() 26 | if err != nil { 27 | fmt.Fprintf(os.Stderr, "%s\n", err) 28 | os.Exit(1) 29 | } 30 | defer tp.Close() 31 | 32 | channel, errorChannel := tp.Channel() 33 | 34 | for { 35 | select { 36 | case event := <-channel: 37 | fmt.Printf("%+v\n", event) 38 | case err := <-errorChannel: 39 | fmt.Printf("%+v\n", err) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/bpffs/fs.go: -------------------------------------------------------------------------------- 1 | package bpffs 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | const BPFFSPath = "/sys/fs/bpf" 10 | 11 | var FsMagicBPFFS int32 12 | 13 | func init() { 14 | // https://github.com/coreutils/coreutils/blob/v8.27/src/stat.c#L275 15 | // https://github.com/torvalds/linux/blob/v4.8/include/uapi/linux/magic.h#L80 16 | magic := uint32(0xCAFE4A11) 17 | // 0xCAFE4A11 overflows an int32, which is what's expected by Statfs_t.Type in 32bit platforms. 18 | // To avoid conditional compilation for all 32bit/64bit platforms, we use an unsafe cast 19 | FsMagicBPFFS = *(*int32)(unsafe.Pointer(&magic)) 20 | } 21 | 22 | // IsMountedAt checks if the BPF fs is mounted already in the custom location 23 | func IsMountedAt(mountpoint string) (bool, error) { 24 | var data syscall.Statfs_t 25 | if err := syscall.Statfs(mountpoint, &data); err != nil { 26 | return false, fmt.Errorf("cannot statfs %q: %v", mountpoint, err) 27 | } 28 | return int32(data.Type) == FsMagicBPFFS, nil 29 | } 30 | 31 | // IsMounted checks if the BPF fs is mounted already in the default location 32 | func IsMounted() (bool, error) { 33 | return IsMountedAt(BPFFSPath) 34 | } 35 | 36 | // MountAt mounts the BPF fs in the custom location (if not already mounted) 37 | func MountAt(mountpoint string) error { 38 | mounted, err := IsMountedAt(mountpoint) 39 | if err != nil { 40 | return err 41 | } 42 | if mounted { 43 | return nil 44 | } 45 | if err := syscall.Mount(mountpoint, mountpoint, "bpf", 0, ""); err != nil { 46 | return fmt.Errorf("error mounting %q: %v", mountpoint, err) 47 | } 48 | return nil 49 | } 50 | 51 | // Mount mounts the BPF fs in the default location (if not already mounted) 52 | func Mount() error { 53 | return MountAt(BPFFSPath) 54 | } 55 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/cpuonline/cpu_range.go: -------------------------------------------------------------------------------- 1 | package cpuonline 2 | 3 | import ( 4 | "io/ioutil" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | const cpuOnline = "/sys/devices/system/cpu/online" 10 | 11 | // loosely based on https://github.com/iovisor/bcc/blob/v0.3.0/src/python/bcc/utils.py#L15 12 | func readCPURange(cpuRangeStr string) ([]uint, error) { 13 | var cpus []uint 14 | cpuRangeStr = strings.Trim(cpuRangeStr, "\n ") 15 | for _, cpuRange := range strings.Split(cpuRangeStr, ",") { 16 | rangeOp := strings.SplitN(cpuRange, "-", 2) 17 | first, err := strconv.ParseUint(rangeOp[0], 10, 32) 18 | if err != nil { 19 | return nil, err 20 | } 21 | if len(rangeOp) == 1 { 22 | cpus = append(cpus, uint(first)) 23 | continue 24 | } 25 | last, err := strconv.ParseUint(rangeOp[1], 10, 32) 26 | if err != nil { 27 | return nil, err 28 | } 29 | for n := first; n <= last; n++ { 30 | cpus = append(cpus, uint(n)) 31 | } 32 | } 33 | return cpus, nil 34 | } 35 | 36 | // Get returns a slice with the online CPUs, for example `[0, 2, 3]` 37 | func Get() ([]uint, error) { 38 | buf, err := ioutil.ReadFile(cpuOnline) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return readCPURange(string(buf)) 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/cpuonline/cpu_range_test.go: -------------------------------------------------------------------------------- 1 | package cpuonline 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestGetOnlineCPUs(t *testing.T) { 8 | tests := []struct { 9 | data string 10 | expected []uint 11 | valid bool 12 | }{ 13 | { 14 | "", 15 | nil, 16 | false, 17 | }, 18 | { 19 | "0-3\n", 20 | []uint{0, 1, 2, 3}, 21 | true, 22 | }, 23 | { 24 | " 0-2,5", 25 | []uint{0, 1, 2, 5}, 26 | true, 27 | }, 28 | { 29 | "0,2,4-5,7-9", 30 | []uint{0, 2, 4, 5, 7, 8, 9}, 31 | true, 32 | }, 33 | { 34 | "0,2", 35 | []uint{0, 2}, 36 | true, 37 | }, 38 | { 39 | "0", 40 | []uint{0}, 41 | true, 42 | }, 43 | { 44 | "-2,5", 45 | nil, 46 | false, 47 | }, 48 | { 49 | "2-@,5", 50 | nil, 51 | false, 52 | }, 53 | { 54 | "-", 55 | nil, 56 | false, 57 | }, 58 | } 59 | for _, test := range tests { 60 | cpus, err := readCPURange(test.data) 61 | if test.valid && err != nil { 62 | t.Errorf("expected input %q to not return an error but got: %v\n", test.data, err) 63 | } 64 | if !test.valid && err == nil { 65 | t.Errorf("expected input %q to return an error\n", test.data) 66 | } 67 | for i := range cpus { 68 | if cpus[i] != test.expected[i] { 69 | t.Errorf("expected %q but got %q\n", test.expected, cpus) 70 | break 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/ksym/ksym.go: -------------------------------------------------------------------------------- 1 | package ksym 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | "os" 8 | "strings" 9 | "sync" 10 | ) 11 | 12 | const ( 13 | KALLSYMS = "/proc/kallsyms" 14 | ) 15 | 16 | type ksymCache struct { 17 | sync.RWMutex 18 | ksym map[string]string 19 | } 20 | 21 | var cache ksymCache 22 | 23 | // Ksym translates a kernel memory address into a kernel function name 24 | // using `/proc/kallsyms` 25 | func Ksym(addr string) (string, error) { 26 | if cache.ksym == nil { 27 | cache.ksym = make(map[string]string) 28 | } 29 | 30 | cache.Lock() 31 | defer cache.Unlock() 32 | 33 | if _, ok := cache.ksym[addr]; !ok { 34 | fd, err := os.Open(KALLSYMS) 35 | if err != nil { 36 | return "", err 37 | } 38 | defer fd.Close() 39 | 40 | fn := ksym(addr, fd) 41 | if fn == "" { 42 | return "", errors.New("kernel function not found for " + addr) 43 | } 44 | 45 | cache.ksym[addr] = fn 46 | } 47 | 48 | return cache.ksym[addr], nil 49 | } 50 | 51 | func ksym(addr string, r io.Reader) string { 52 | s := bufio.NewScanner(r) 53 | for s.Scan() { 54 | l := s.Text() 55 | ar := strings.Split(l, " ") 56 | if len(ar) != 3 { 57 | continue 58 | } 59 | 60 | if ar[0] == addr { 61 | return ar[2] 62 | } 63 | } 64 | 65 | return "" 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/ksym/ksym_test.go: -------------------------------------------------------------------------------- 1 | package ksym 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestKsym(t *testing.T) { 9 | data := "ffffffff91b2a340 T cgroup_freezing" 10 | 11 | r := strings.NewReader(data) 12 | fn := ksym("ffffffff91b2a340", r) 13 | 14 | if fn != "cgroup_freezing" { 15 | t.Error("unexpected result") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/progtestrun/prog_test_run.go: -------------------------------------------------------------------------------- 1 | package progtestrun 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | /* 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static __u64 ptr_to_u64(void *ptr) 17 | { 18 | return (__u64) (unsigned long) ptr; 19 | } 20 | 21 | int bpf_prog_test_run(int fd, int repeat, char *data, int data_size, 22 | char *data_out, int *data_out_size, int *retval, 23 | int *duration) 24 | { 25 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) 26 | union bpf_attr attr = {}; 27 | int ret; 28 | 29 | memset(&attr, 0, sizeof(attr)); 30 | 31 | attr.test.prog_fd = fd; 32 | attr.test.data_in = ptr_to_u64((void *) data); 33 | attr.test.data_out = ptr_to_u64((void *) data_out); 34 | attr.test.data_size_in = data_size; 35 | attr.test.repeat = repeat; 36 | 37 | ret = syscall(__NR_bpf, BPF_PROG_TEST_RUN, &attr, sizeof(attr)); 38 | if (data_out_size) 39 | *data_out_size = attr.test.data_size_out; 40 | if (retval) 41 | *retval = attr.test.retval; 42 | if (duration) 43 | *duration = attr.test.duration; 44 | return ret; 45 | #else 46 | errno = ENOSYS; 47 | return -1; 48 | #endif 49 | } 50 | */ 51 | import "C" 52 | 53 | // Run exposes BPF_PROG_TEST_RUN to test xdp and skp programs. 54 | // `data` will be passed to your program as `__sk_buff *ptr`. 55 | // `dataOut` (optional) will hold `skb->data` after run, if large enough. 56 | func Run(progFd, repeat int, data []byte, dataOut []byte) (int, int, int, error) { 57 | if data == nil { 58 | // http://elixir.free-electrons.com/linux/v4.12/source/net/bpf/test_run.c#L78 59 | // http://elixir.free-electrons.com/linux/v4.12/source/include/uapi/linux/if_ether.h#L32 60 | return -1, 0, 0, fmt.Errorf("data must be at least 14 bytes (corresponding to ETH_HLEN)") 61 | } 62 | var ( 63 | dataOutPtr *C.char 64 | dataOutLen C.int 65 | returnValue C.int 66 | duration C.int 67 | 68 | dataPtr = (*C.char)(unsafe.Pointer(&data[0])) 69 | dataLen = C.int(len(data)) 70 | ) 71 | if dataOut != nil { 72 | dataOutPtr = (*C.char)(unsafe.Pointer(&dataOut[0])) 73 | } 74 | ret, err := C.bpf_prog_test_run(C.int(progFd), C.int(repeat), dataPtr, dataLen, dataOutPtr, &dataOutLen, &returnValue, &duration) 75 | if ret != 0 { 76 | return -1, 0, 0, fmt.Errorf("bpf_prog_test_run failed: %v (%d)", err, ret) 77 | } 78 | return int(returnValue), int(duration), int(dataOutLen), nil 79 | } 80 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/tracepipe/trace_pipe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Kinvolk 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tracepipe 16 | 17 | import ( 18 | "bufio" 19 | "fmt" 20 | "io" 21 | "os" 22 | "regexp" 23 | "strings" 24 | ) 25 | 26 | const tracePipeFile = "/sys/kernel/debug/tracing/trace_pipe" 27 | 28 | // TracePipe to read from /sys/kernel/debug/tracing/trace_pipe 29 | // Note that data can be read only once, i.e. if you have more than 30 | // one tracer / channel, only one will receive an event: 31 | // "Once data is read from this file, it is consumed, and will not be 32 | // read again with a sequential read." 33 | // https://www.kernel.org/doc/Documentation/trace/ftrace.txt 34 | type TracePipe struct { 35 | file *os.File 36 | reader *bufio.Reader 37 | stop chan struct{} 38 | } 39 | 40 | // TraceEvent contains the raw event as well as the contents of 41 | // every field as string, as defined under "Output format" in 42 | // https://www.kernel.org/doc/Documentation/trace/ftrace.txt 43 | type TraceEvent struct { 44 | Raw string 45 | Task string 46 | PID string 47 | CPU string 48 | Flags string 49 | Timestamp string 50 | Function string 51 | Message string 52 | } 53 | 54 | func New() (*TracePipe, error) { 55 | f, err := os.Open(tracePipeFile) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return &TracePipe{ 60 | file: f, 61 | reader: bufio.NewReader(f), 62 | stop: make(chan struct{}), 63 | }, nil 64 | } 65 | 66 | // A line from trace_pipe looks like (leading spaces included): 67 | // ` chromium-15581 [000] d... 92783.722567: : Hello, World!` 68 | var traceLineRegexp = regexp.MustCompile(`(.{16})-(\d+) +\[(\d{3})\] (.{4}) +(\d+\.\d+)\: (.*?)\: (.*)`) 69 | 70 | func parseTraceLine(raw string) (*TraceEvent, error) { 71 | fields := traceLineRegexp.FindStringSubmatch(raw) 72 | if len(fields) != 8 { 73 | return nil, fmt.Errorf("received unexpected input %q", raw) 74 | } 75 | return &TraceEvent{ 76 | Raw: raw, 77 | Task: strings.Trim(fields[1], " "), 78 | PID: fields[2], 79 | CPU: fields[3], 80 | Flags: fields[4], 81 | Timestamp: fields[5], 82 | Function: fields[6], 83 | Message: fields[7], 84 | }, nil 85 | } 86 | 87 | func (t *TracePipe) ReadLine() (*TraceEvent, error) { 88 | line, err := t.reader.ReadString('\n') 89 | if err != nil { 90 | return nil, err 91 | } 92 | traceEvent, err := parseTraceLine(line) 93 | if err != nil { 94 | return nil, err 95 | } 96 | return traceEvent, nil 97 | } 98 | 99 | func (t *TracePipe) Channel() (<-chan *TraceEvent, <-chan error) { 100 | channelEvents := make(chan *TraceEvent) 101 | channelErrors := make(chan error) 102 | go func() { 103 | for { 104 | select { 105 | case <-t.stop: 106 | return 107 | default: 108 | } 109 | traceEvent, err := t.ReadLine() 110 | if err != nil { 111 | if err == io.EOF { 112 | continue 113 | } 114 | channelErrors <- err 115 | } else { 116 | channelEvents <- traceEvent 117 | } 118 | } 119 | }() 120 | return channelEvents, channelErrors 121 | } 122 | 123 | func (t *TracePipe) Close() error { 124 | close(t.stop) 125 | return t.file.Close() 126 | } 127 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/pkg/tracepipe/trace_pipe_test.go: -------------------------------------------------------------------------------- 1 | package tracepipe 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestParseTraceLine(t *testing.T) { 8 | testEvents := []struct { 9 | input string 10 | expected TraceEvent 11 | }{ 12 | { 13 | " chromium-15581 [000] d... 92783.722567: : Hello, World!", 14 | TraceEvent{ 15 | Task: "chromium", 16 | Function: "", 17 | Message: "Hello, World!", 18 | }, 19 | }, 20 | { 21 | " curl-18597 [000] dN.. 463.471554: : kretprobe__tcp_v4_connect - pid_tgid 79873506822309\n", 22 | TraceEvent{ 23 | Task: "curl", 24 | Function: "", 25 | Message: "kretprobe__tcp_v4_connect - pid_tgid 79873506822309", 26 | }, 27 | }, 28 | { 29 | " trace_pipe-23553 [000] .... 205825.968557: sys_enter: NR 0 (3, c420098000, 1000, 0, 0, 0)\n", 30 | TraceEvent{ 31 | Task: "trace_pipe", 32 | Function: "sys_enter", 33 | Message: "NR 0 (3, c420098000, 1000, 0, 0, 0)", 34 | }, 35 | }, 36 | { 37 | " trace_pipe-23553 [000] .... 205825.968557: sys_enter: hello: world\n", 38 | TraceEvent{ 39 | Task: "trace_pipe", 40 | Function: "sys_enter", 41 | Message: "hello: world", 42 | }, 43 | }, 44 | } 45 | for _, testEvent := range testEvents { 46 | result, err := parseTraceLine(testEvent.input) 47 | if err != nil { 48 | t.Errorf("%q could not be parsed", testEvent.input) 49 | } 50 | if testEvent.expected.Task != result.Task { 51 | t.Errorf("result task %q doesn't match expected %q", result.Task, testEvent.expected.Task) 52 | } 53 | if testEvent.expected.Function != result.Function { 54 | t.Errorf("result function %q doesn't match expected %q", result.Function, testEvent.expected.Function) 55 | } 56 | if testEvent.expected.Message != result.Message { 57 | t.Errorf("result message %q doesn't match expected %q", result.Message, testEvent.expected.Message) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/iovisor/gobpf/tests/dummy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Compiled with './build' 3 | */ 4 | 5 | #include "../elf/include/bpf.h" 6 | #include "../elf/include/bpf_map.h" 7 | 8 | #define SEC(NAME) __attribute__((section(NAME), used)) 9 | 10 | #define PERF_MAX_STACK_DEPTH 127 11 | 12 | #define KERNEL_VERSION_GTE(X) (KERNEL_VERSION >= X) 13 | 14 | struct pt_regs{}; 15 | 16 | struct bpf_map_def SEC("maps/dummy_hash") dummy_hash = { 17 | .type = BPF_MAP_TYPE_HASH, 18 | .key_size = sizeof(int), 19 | .value_size = sizeof(unsigned int), 20 | .max_entries = 128, 21 | }; 22 | 23 | struct bpf_map_def SEC("maps/dummy_array") dummy_array = { 24 | .type = BPF_MAP_TYPE_ARRAY, 25 | .key_size = sizeof(int), 26 | .value_size = sizeof(unsigned int), 27 | .max_entries = 128, 28 | }; 29 | 30 | struct bpf_map_def SEC("maps/dummy_prog_array") dummy_prog_array = { 31 | .type = BPF_MAP_TYPE_PROG_ARRAY, 32 | .key_size = sizeof(int), 33 | .value_size = sizeof(unsigned int), 34 | .max_entries = 128, 35 | }; 36 | 37 | struct bpf_map_def SEC("maps/dummy_perf") dummy_perf = { 38 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, 39 | .key_size = sizeof(int), 40 | .value_size = sizeof(unsigned int), 41 | .max_entries = 128, 42 | }; 43 | 44 | #if KERNEL_VERSION_GTE(46) 45 | struct bpf_map_def SEC("maps/dummy_percpu_hash") dummy_percpu_hash = { 46 | .type = BPF_MAP_TYPE_PERCPU_HASH, 47 | .key_size = sizeof(int), 48 | .value_size = sizeof(unsigned int), 49 | .max_entries = 128, 50 | }; 51 | 52 | struct bpf_map_def SEC("maps/dummy_percpu_array") dummy_percpu_array = { 53 | .type = BPF_MAP_TYPE_PERCPU_ARRAY, 54 | .key_size = sizeof(int), 55 | .value_size = sizeof(unsigned int), 56 | .max_entries = 128, 57 | }; 58 | 59 | struct bpf_map_def SEC("maps/dummy_stack_trace") dummy_stack_trace = { 60 | .type = BPF_MAP_TYPE_STACK_TRACE, 61 | .key_size = sizeof(int), 62 | .value_size = PERF_MAX_STACK_DEPTH * sizeof(unsigned long long), 63 | .max_entries = 128, 64 | }; 65 | #endif 66 | 67 | #if KERNEL_VERSION_GTE(48) 68 | struct bpf_map_def SEC("maps/dummy_cgroup_array") dummy_cgroup_array = { 69 | .type = BPF_MAP_TYPE_CGROUP_ARRAY, 70 | .key_size = sizeof(int), 71 | .value_size = sizeof(unsigned int), 72 | .max_entries = 128, 73 | }; 74 | #endif 75 | 76 | struct bpf_map_def SEC("maps/dummy_array_custom") dummy_array_custom = { 77 | .type = BPF_MAP_TYPE_ARRAY, 78 | .key_size = sizeof(int), 79 | .value_size = sizeof(unsigned int), 80 | .max_entries = 128, 81 | .pinning = PIN_CUSTOM_NS, 82 | }; 83 | 84 | SEC("kprobe/dummy") 85 | int kprobe__dummy(struct pt_regs *ctx) 86 | { 87 | return 0; 88 | } 89 | 90 | SEC("kretprobe/dummy") 91 | int kretprobe__dummy(struct pt_regs *ctx) 92 | { 93 | return 0; 94 | } 95 | 96 | SEC("uprobe/dummy") 97 | int uprobe__dummy(struct pt_regs *ctx) 98 | { 99 | return 0; 100 | } 101 | 102 | SEC("uretprobe/dummy") 103 | int uretprobe__dummy(struct pt_regs *ctx) 104 | { 105 | return 0; 106 | } 107 | 108 | #if KERNEL_VERSION_GTE(410) 109 | SEC("cgroup/skb") 110 | int cgroup_skb__dummy(struct __sk_buff *skb) 111 | { 112 | return 1; 113 | } 114 | 115 | SEC("cgroup/sock") 116 | int cgroup_sock__dummy(struct __sk_buff *skb) 117 | { 118 | return 0; 119 | } 120 | #endif 121 | 122 | #if KERNEL_VERSION_GTE(47) 123 | SEC("tracepoint/raw_syscalls/sys_enter") 124 | int tracepoint__raw_sys_enter() 125 | { 126 | return 0; 127 | } 128 | #endif 129 | 130 | SEC("socket/dummy") 131 | int socket__dummy(struct __sk_buff *skb) 132 | { 133 | return 0; 134 | } 135 | 136 | unsigned int _version SEC("version") = 0xFFFFFFFE; 137 | --------------------------------------------------------------------------------