-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathc_example_test.go
More file actions
131 lines (105 loc) · 2.94 KB
/
Copy pathc_example_test.go
File metadata and controls
131 lines (105 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package cbpfc
import (
"bytes"
"fmt"
"os"
"text/template"
"github.com/cloudflare/cbpfc/clang"
"golang.org/x/net/bpf"
)
var testTemplate = template.Must(template.New(entryPoint).Parse(`
#define __section(NAME) __attribute__((section(NAME), used))
char __license[] __section("license") = "BSD";
// Shim out all the definitions required by cbpfc
// Real programs should use the proper headers
typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
typedef char bool;
#define false 0
#define true 1
#define ntohs __builtin_bswap16
#define ntohl __builtin_bswap32
struct xdp_md {
uint32_t data;
uint32_t data_end;
};
enum xdp_action {
XDP_DROP = 1,
XDP_PASS,
};
{{.Filter}}
__section("xdp") int {{.ProgramName}}(struct xdp_md *ctx) {
uint8_t *data = (uint8_t *)(long)ctx->data;
uint8_t const *data_end = (uint8_t *)(long)ctx->data_end;
if ({{.FilterName}}(data + {{.Offset}}, data_end)) {
return XDP_DROP;
}
return XDP_PASS;
}
`))
type testTemplateOpts struct {
// Definition of the filter
Filter string
// Function name of the filter
FilterName string
// Name of the eBPF program
ProgramName string
// Offset the packet start is advanced by before the filter is called.
// Must match the COpts.PacketStartMaxOffset the filter was compiled with.
Offset uint16
}
// ExampleToC demonstrates how to use ToC() to embed a cBPF filter
// in a C program, and compile it to eBPF.
func ExampleToC() {
// simple cBPF filter that matches all packets
filter := []bpf.Instruction{
bpf.RetConstant{Val: 1},
}
elf, err := buildC(filter, "example", COpts{FunctionName: "example_filter"})
if err != nil {
panic(err)
}
// ELF with a single eBPF program 'example'
// Can be loaded with cilium/ebpf or libbpf
_ = elf
}
// buildC compiles a cBPF filter to C, embeds it in a C template,
// and compiles the resulting C program to eBPF / XDP using clang.
// The XDP program XDP_DROP's incoming packets that match the filter.
// Returns the compiled ELF
func buildC(filter []bpf.Instruction, programName string, opts COpts) ([]byte, error) {
// convert filter to C
ebpfFilter, err := ToC(filter, opts)
if err != nil {
return nil, fmt.Errorf("converting filter to C: %w", err)
}
// embed filter in C template
c := bytes.Buffer{}
err = testTemplate.Execute(&c, testTemplateOpts{
Filter: ebpfFilter,
FilterName: opts.FunctionName,
ProgramName: programName,
Offset: opts.PacketStartMaxOffset,
})
if err != nil {
return nil, fmt.Errorf("executing template with C filter: %w", err)
}
// lookup clang binary to use
clangBin, ok := os.LookupEnv("CLANG")
if !ok {
clangBin = "/usr/bin/clang"
}
// compile C program
elf, err := clang.Compile(c.Bytes(), entryPoint, clang.Opts{
Clang: clangBin,
EmitDebug: true, // For BTF
})
if err != nil {
return nil, fmt.Errorf("compiling C: %w", err)
}
return elf, nil
}