dropbox / goebpf Goto Github PK
View Code? Open in Web Editor NEWLibrary to work with eBPF programs from Go
License: Other
Library to work with eBPF programs from Go
License: Other
is it possible to write eBPF programs in Go or TinyGo since it is based on LLVM?
can someone guide me to do this?
I want to #include <net/sock.h>
in kprobe.c and i also add the path in clang but it failed.
Can you tell me how to include the linux header?
Thanks
Hi,
Does xdpProgram support attaching the same program to multiple interfaces? As far as I can tell from the code, a xdpProgram has one ifname and only detach the the program from this interface. If multiple Attach() are called with different interfaces, only the last one will be detached in the Detach() call. Is this intended? Is there any way to attach the same program to different interfaces?
Thanks!
I want my Go program to catch a limited number of perf events, and then it should ends itself.
When the limited number counted, the function stopPerfEvents
will be called.
func (p *bpfProgram) stopPerfEvents() {
p.pe.Stop()
close(p.stop)
p.wg.Wait()
}
func (p *bpfProgram) startPerfEvents(events <-chan []byte) {
p.wg.Add(1)
go func(events <-chan []byte) {
defer p.wg.Done()
for {
var data []byte
select {
case <-p.stop:
return
case b, ok := <-events:
if !ok {
return
}
data = b
}
var ev bpfEvent
err := ev.unmarshal(data)
if err != nil {
eventAbnormal++
continue
}
e := ev.toEvent()
p.getCallStack(ev.KernelStackID, e)
select {
case p.ev <- e:
case <-p.stop:
return
}
}
}(events)
}
Unexpectedly, it cannot exits. And then I use gops to print out its stack:
goroutine 19 [running]:
runtime/pprof.writeGoroutineStacks(0x6d00a8, 0xc0000a6008, 0xd0, 0x658380)
/usr/local/go/src/runtime/pprof/pprof.go:693 +0x9f
runtime/pprof.writeGoroutine(0x6d00a8, 0xc0000a6008, 0x2, 0xc000038800, 0x0)
/usr/local/go/src/runtime/pprof/pprof.go:682 +0x45
runtime/pprof.(*Profile).WriteTo(0x7f3960, 0x6d00a8, 0xc0000a6008, 0x2, 0xc0000a6008, 0x8)
/usr/local/go/src/runtime/pprof/pprof.go:331 +0x3f2
github.com/google/gops/agent.handle(0x7f7d1ade79c0, 0xc0000a6008, 0xc0000160b8, 0x1, 0x1, 0x0, 0x0)
/root/go/pkg/mod/github.com/google/[email protected]/agent/agent.go:201 +0x1b8
github.com/google/gops/agent.listen()
/root/go/pkg/mod/github.com/google/[email protected]/agent/agent.go:145 +0x2f0
created by github.com/google/gops/agent.Listen
/root/go/pkg/mod/github.com/google/[email protected]/agent/agent.go:123 +0x3ad
goroutine 1 [semacquire, 2 minutes]:
sync.runtime_Semacquire(0xc0000fecf8)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc0000fecf0)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
github.com/dropbox/goebpf.(*PerfEvents).Stop(0xc0000fecb0)
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events.go:138 +0x45
github.com/Asphaltt/skbtracer.(*bpfProgram).stopPerfEvents(0xc00005e000)
/data/skbtracer/bpf.go:189 +0x2f
github.com/Asphaltt/skbtracer.(*bpfProgram).detachProbes(0xc00005e000)
/data/skbtracer/bpf.go:231 +0x45
main.runBpf()
/data/skbtracer/cmd/skbtracer/main.go:69 +0x206
main.glob..func1(0x7f8960, 0xc0000ec040, 0x0, 0x2)
/data/skbtracer/cmd/skbtracer/main.go:38 +0x14d
github.com/spf13/cobra.(*Command).execute(0x7f8960, 0xc00009a160, 0x2, 0x2, 0x7f8960, 0xc00009a160)
/root/go/pkg/mod/github.com/spf13/[email protected]/command.go:860 +0x2c2
github.com/spf13/cobra.(*Command).ExecuteC(0x7f8960, 0x0, 0x7ffc60, 0xc00008e058)
/root/go/pkg/mod/github.com/spf13/[email protected]/command.go:974 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
/root/go/pkg/mod/github.com/spf13/[email protected]/command.go:902
main.main()
/data/skbtracer/cmd/skbtracer/main.go:43 +0x2d
goroutine 6 [semacquire, 2 minutes]:
sync.runtime_Semacquire(0xc0000e4060)
/usr/local/go/src/runtime/sema.go:56 +0x45
sync.(*WaitGroup).Wait(0xc0000e4058)
/usr/local/go/src/sync/waitgroup.go:130 +0x65
github.com/dropbox/goebpf.(*perfEventPoller).Stop(...)
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events_poller.go:98
github.com/dropbox/goebpf.(*PerfEvents).loop.func1(0xc0000e4050, 0xc0000fecb0)
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events.go:165 +0x45
github.com/dropbox/goebpf.(*PerfEvents).loop(0xc0000fecb0)
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events.go:176 +0x24f
created by github.com/dropbox/goebpf.(*PerfEvents).startLoop
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events.go:152 +0xbf
goroutine 7 [select, 2 minutes]:
github.com/Asphaltt/skbtracer.(*bpfProgram).startPerfEvents.func1(0xc00005e000, 0xc00008e3c0)
/data/skbtracer/bpf.go:145 +0xf4
created by github.com/Asphaltt/skbtracer.(*bpfProgram).startPerfEvents
/data/skbtracer/bpf.go:140 +0x66
goroutine 8 [chan receive, 2 minutes]:
main.handleEvent(0xc00008e0c0, 0xc0000b8d20)
/data/skbtracer/cmd/skbtracer/main.go:99 +0x285
created by main.runBpf
/data/skbtracer/cmd/skbtracer/main.go:63 +0x18f
goroutine 22 [chan send, 2 minutes]:
github.com/dropbox/goebpf.(*perfEventPoller).loop(0xc0000e4050)
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events_poller.go:119 +0x9c
created by github.com/dropbox/goebpf.(*perfEventPoller).Start
/root/go/pkg/mod/github.com/dropbox/[email protected]/perf_events_poller.go:90 +0x1e5
goroutine 10 [syscall, 2 minutes]:
os/signal.signal_recv(0x0)
/usr/local/go/src/runtime/sigqueue.go:168 +0xa5
os/signal.loop()
/usr/local/go/src/os/signal/signal_unix.go:23 +0x25
created by os/signal.Notify.func1.1
/usr/local/go/src/os/signal/signal.go:151 +0x45
Analyze it, and the line github.com/dropbox/[email protected]/perf_events_poller.go:119
catches my eyes.
func (p *perfEventPoller) loop() {
defer p.wg.Done()
for {
......
for i := 0; i < readyCnt; i++ {
p.updateChannel <- p.items[int(p.fds[i])] // it's this line
}
}
}
At last, I got my solution:
// Stop stops event polling loop
func (pe *PerfEvents) Stop() {
// Stop poller firstly
pe.poller.Stop()
// Stop poll loop
close(pe.stopChannel)
// Wait until poll loop stopped, then close updates channel
pe.wg.Wait()
close(pe.updatesChannel)
......
}
func (pe *PerfEvents) loop() {
// Setup poller to poll all handlers (one handler per CPU)
pe.poller = newPerfEventPoller()
for _, handler := range pe.handlers {
pe.poller.Add(handler)
}
// Start poller
pollerCh := pe.poller.Start(pe.PollTimeoutMs)
defer func() {
// pe.poller.Stop()
pe.wg.Done()
}()
......
}
I have an xdp script and it loads normally, but I cannot use the data type C as a map key
Hi there, I have been running in to issue trying to read a hash type map with this goebpf package. Is that supported yet? no matter which lookup type i try results in ebpf_map_lookup_elem() failed: No such file or directory
.
map def:
BPF_MAP_DEF(stat) = {
.map_type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = MAX_BPF_IP,
};
BPF_MAP_ADD(stat);
populating it with key ip_stat and value is a counter.
struct ip_stat {
__u32 saddr;
__u32 daddr;
__u32 action;
__u8 proto;
};
I am trying to create my own elf file using examples suggested in the examples. .c file as below
#include "bpf_helpers.h"
struct iphdr {
__u8 ihl : 4;
__u8 version : 4;
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
};
struct Key {
__u32 src_ip; //source ip
__u32 dst_ip; //destination ip
__u16 src_port; //source port
__u16 dst_port; //destination port
};
struct Leaf {
__u64 timestamp; //timestamp in ns
};
// eBPF map to store IP proto counters (tcp, udp, etc)
BPF_MAP_DEF(sessions) = {
.map_type = BPF_MAP_TYPE_HASH,
.key_size = 96,
.value_size = 64,
.max_entries = 255,
};
BPF_MAP_ADD(sessions);
SEC("socket_filter")
int ip_filter(struct __sk_buff *skb) {
struct Key key = {};
struct Leaf zero = {0};
struct iphdr *ip = (struct iphdr *)skb_network_header(skb);
clang -I../../.. -O2 -target bpf -c ebpf_prog/xdp.c -o ebpf_prog/xdp.elf -static
ebpf_prog/xdp.c:59:38: warning: implicit declaration of function 'skb_network_header' is invalid in C99
[-Wimplicit-function-declaration]
struct iphdr *ip = (struct iphdr *)skb_network_header(skb);
^
ebpf_prog/xdp.c:59:22: warning: cast to 'struct iphdr *' from smaller integer type 'int' [-Wint-to-pointer-cast]
struct iphdr *ip = (struct iphdr *)skb_network_header(skb);
LoadElf() failed: loadPrograms() failed: Invalid BPF instruction (at 0): &{133 0 1 0 4294967295}
is there any plan to support eBPF for windows ?
Hi,
when I add bpf_trace_printk in example below, it compiles fine, when run the program, it result in error below:
[root@centos-dev basic_firewall]# ./main -drop 10.169.72.0/24 -iface ens192
LoadElf() failed: loadPrograms() failed: map '' doesn't exist
the diff
diff --git a/examples/xdp/basic_firewall/ebpf_prog/xdp_fw.c b/examples/xdp/basic_firewall/ebpf_prog/xdp_fw.c
index 6d399fb..b9aa66c 100644
--- a/examples/xdp/basic_firewall/ebpf_prog/xdp_fw.c
+++ b/examples/xdp/basic_firewall/ebpf_prog/xdp_fw.c
@@ -80,6 +80,8 @@ int firewall(struct xdp_md *ctx) {
key.prefixlen = 32;
key.saddr = ip->saddr;
+ bpf_trace_printk("Matched with protocol %d and sAddr %lu.\n", ip->protocol, ip->saddr);
+
// Lookup SRC IP in blacklisted IPs
__u64 *rule_idx = bpf_map_lookup_elem(&blacklist, &key);
if (rule_idx) {
possible to include this example for ipv6 as well?
https://github.com/dropbox/goebpf/blob/master/examples/xdp/basic_firewall/main.go
Thanks for open sourcing this. I am curious to understand what are the differences among this and other goebpf libraries?
Calling perf.Stop() immediately after calling perf.StartForAllProcessesAndCPUs() will lead to a crash. This can be reproduced in the xdp_dump example by adding perf.Stop() call after the successful perf.StartForAllProcessesAndCPUs() call.
The initial use case where it was observed was having multiple perf maps, initializing multiple PerfEvents, one for each map, and calling Stop() on the init sequence for the PerfEvents that were already started.
Loading elf files run smoothly without any errors but afterwards it returns empty maps and empty programs (with GetMaps() and GetPrograms()) :( However, eBPF/XDP programs run fine if loaded for example with ip tool. llvm-objdump also show all code and objects! Trying to understand what is the problem? Any help appreciated!
Hello folks,
last week i was working on a small program to submit perf events to the userspace, when i found out that the commit #36 might have introduced the issue.
what happens is that i am able to happily compile the code, however, it barfs like this when i try to load it:
panic: ebpf_prog_load() failed: 0: (bf) r6 = r1
1: (61) r2 = *(u32 *)(r6 +4)
2: (61) r1 = *(u32 *)(r6 +0)
3: (bf) r3 = r1
4: (07) r3 += 14
5: (2d) if r3 > r2 goto pc+41
R1=pkt(id=0,off=0,r=14,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=14,r=14,imm=0) R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
6: (71) r3 = *(u8 *)(r1 +12)
7: (71) r4 = *(u8 *)(r1 +13)
8: (67) r4 <<= 8
9: (4f) r4 |= r3
10: (55) if r4 != 0x8 goto pc+36
R1=pkt(id=0,off=0,r=14,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R4=inv8 R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
11: (bf) r3 = r1
12: (07) r3 += 34
13: (2d) if r3 > r2 goto pc+33
R1=pkt(id=0,off=0,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=34,r=34,imm=0) R4=inv8 R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
14: (71) r3 = *(u8 *)(r1 +23)
15: (55) if r3 != 0x11 goto pc+31
R1=pkt(id=0,off=0,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=inv17 R4=inv8 R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
16: (bf) r3 = r1
17: (07) r3 += 42
18: (2d) if r3 > r2 goto pc+28
R1=pkt(id=0,off=0,r=42,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=42,r=42,imm=0) R4=inv8 R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
19: (bf) r4 = r1
20: (07) r4 += 50
21: (2d) if r4 > r2 goto pc+25
R1=pkt(id=0,off=0,r=50,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=42,r=50,imm=0) R4=pkt(id=0,off=50,r=50,imm=0) R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
22: (69) r2 = *(u16 *)(r1 +36)
23: (55) if r2 != 0x9411 goto pc+23
R1=pkt(id=0,off=0,r=50,imm=0) R2=inv37905 R3=pkt(id=0,off=42,r=50,imm=0) R4=pkt(id=0,off=50,r=50,imm=0) R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
24: (61) r2 = *(u32 *)(r3 +0)
25: (15) if r2 == 0x0 goto pc+21
R1=pkt(id=0,off=0,r=50,imm=0) R2=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3=pkt(id=0,off=42,r=50,imm=0) R4=pkt(id=0,off=50,r=50,imm=0) R6=ctx(id=0,off=0,imm=0) R10=fp0,call_-1
26: (b7) r2 = 0
27: (7b) *(u64 *)(r10 -8) = r2
28: (61) r2 = *(u32 *)(r1 +26)
29: (63) *(u32 *)(r10 -8) = r2
30: (69) r1 = *(u16 *)(r1 +34)
31: (dc) r1 = be16 r1
32: (6b) *(u16 *)(r10 -4) = r1
33: (bf) r7 = r10
34: (07) r7 += -8
35: (18) r1 = 0xffff8fea69922000
37: (bf) r2 = r7
38: (85) call bpf_map_lookup_elem#1
39: (bf) r1 = r6
40: (18) r2 = 0xffff8feaa7c18000
42: (18) r3 = 0xffffffff
44: (bf) r4 = r7
45: (b7) r5 = 8
46: (85) call bpf_skb_load_bytes#26
unknown func bpf_skb_load_bytes#26
goroutine 1 [running]:
main.main()
i found out that the bpf_perf_event_output is called by the id 26, which strangely maps to skb_load_bytes.
# llvm-objdump-9 -S kern/xdp.elf
kern/xdp.elf: file format ELF64-BPF
Disassembly of section xdp:
0000000000000000 xdp_jitd:
0: bf 16 00 00 00 00 00 00 r6 = r1
1: 61 62 04 00 00 00 00 00 r2 = *(u32 *)(r6 + 4)
2: 61 61 00 00 00 00 00 00 r1 = *(u32 *)(r6 + 0)
3: bf 13 00 00 00 00 00 00 r3 = r1
4: 07 03 00 00 0e 00 00 00 r3 += 14
5: 2d 23 29 00 00 00 00 00 if r3 > r2 goto +41 <LBB0_9>
6: 71 13 0c 00 00 00 00 00 r3 = *(u8 *)(r1 + 12)
7: 71 14 0d 00 00 00 00 00 r4 = *(u8 *)(r1 + 13)
8: 67 04 00 00 08 00 00 00 r4 <<= 8
9: 4f 34 00 00 00 00 00 00 r4 |= r3
10: 55 04 24 00 08 00 00 00 if r4 != 8 goto +36 <LBB0_9>
11: bf 13 00 00 00 00 00 00 r3 = r1
12: 07 03 00 00 22 00 00 00 r3 += 34
13: 2d 23 21 00 00 00 00 00 if r3 > r2 goto +33 <LBB0_9>
14: 71 13 17 00 00 00 00 00 r3 = *(u8 *)(r1 + 23)
15: 55 03 1f 00 11 00 00 00 if r3 != 17 goto +31 <LBB0_9>
16: bf 13 00 00 00 00 00 00 r3 = r1
17: 07 03 00 00 2a 00 00 00 r3 += 42
18: 2d 23 1c 00 00 00 00 00 if r3 > r2 goto +28 <LBB0_9>
19: bf 14 00 00 00 00 00 00 r4 = r1
20: 07 04 00 00 32 00 00 00 r4 += 50
21: 2d 24 19 00 00 00 00 00 if r4 > r2 goto +25 <LBB0_9>
22: 69 12 24 00 00 00 00 00 r2 = *(u16 *)(r1 + 36)
23: 55 02 17 00 11 94 00 00 if r2 != 37905 goto +23 <LBB0_9>
24: 61 32 00 00 00 00 00 00 r2 = *(u32 *)(r3 + 0)
25: 15 02 15 00 00 00 00 00 if r2 == 0 goto +21 <LBB0_9>
26: b7 02 00 00 00 00 00 00 r2 = 0
27: 7b 2a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r2
28: 61 12 1a 00 00 00 00 00 r2 = *(u32 *)(r1 + 26)
29: 63 2a f8 ff 00 00 00 00 *(u32 *)(r10 - 8) = r2
30: 69 11 22 00 00 00 00 00 r1 = *(u16 *)(r1 + 34)
31: dc 01 00 00 10 00 00 00 r1 = be16 r1
32: 6b 1a fc ff 00 00 00 00 *(u16 *)(r10 - 4) = r1
33: bf a7 00 00 00 00 00 00 r7 = r10
34: 07 07 00 00 f8 ff ff ff r7 += -8
35: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
37: bf 72 00 00 00 00 00 00 r2 = r7
38: 85 00 00 00 01 00 00 00 call 1
39: bf 61 00 00 00 00 00 00 r1 = r6
40: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll
42: 18 03 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 r3 = 4294967295 ll
44: bf 74 00 00 00 00 00 00 r4 = r7
45: b7 05 00 00 08 00 00 00 r5 = 8
46: 85 00 00 00 1a 00 00 00 call 26
0000000000000178 LBB0_9:
47: b7 00 00 00 02 00 00 00 r0 = 2
48: 95 00 00 00 00 00 00 00 exit
i expected perf_event_output to match the 27th item on the list (index 26) https://github.com/dropbox/goebpf/blob/master/bpf_helpers.h#L268
the program is successfully loaded if i do a git revert on the commit and compile it:
goebpf(master)» git revert 4910d571d799ca6c94728f5aad303c0f154a831f [15:52:46]
[master 6c9a65b] Revert "[maps] Implement bpf_map_get_next_key (#36)"
6 files changed, 321 deletions(-)
--------------
# llvm-objdump-9 -S kern/xdp.elf
kern/xdp.elf: file format ELF64-BPF
Disassembly of section xdp:
0000000000000000 xdp_jitd:
0: bf 16 00 00 00 00 00 00 r6 = r1
1: 61 62 04 00 00 00 00 00 r2 = *(u32 *)(r6 + 4)
2: 61 61 00 00 00 00 00 00 r1 = *(u32 *)(r6 + 0)
3: bf 13 00 00 00 00 00 00 r3 = r1
4: 07 03 00 00 0e 00 00 00 r3 += 14
5: 2d 23 29 00 00 00 00 00 if r3 > r2 goto +41 <LBB0_9>
6: 71 13 0c 00 00 00 00 00 r3 = *(u8 *)(r1 + 12)
7: 71 14 0d 00 00 00 00 00 r4 = *(u8 *)(r1 + 13)
8: 67 04 00 00 08 00 00 00 r4 <<= 8
9: 4f 34 00 00 00 00 00 00 r4 |= r3
10: 55 04 24 00 08 00 00 00 if r4 != 8 goto +36 <LBB0_9>
11: bf 13 00 00 00 00 00 00 r3 = r1
12: 07 03 00 00 22 00 00 00 r3 += 34
13: 2d 23 21 00 00 00 00 00 if r3 > r2 goto +33 <LBB0_9>
14: 71 13 17 00 00 00 00 00 r3 = *(u8 *)(r1 + 23)
15: 55 03 1f 00 11 00 00 00 if r3 != 17 goto +31 <LBB0_9>
16: bf 13 00 00 00 00 00 00 r3 = r1
17: 07 03 00 00 2a 00 00 00 r3 += 42
18: 2d 23 1c 00 00 00 00 00 if r3 > r2 goto +28 <LBB0_9>
19: bf 14 00 00 00 00 00 00 r4 = r1
20: 07 04 00 00 32 00 00 00 r4 += 50
21: 2d 24 19 00 00 00 00 00 if r4 > r2 goto +25 <LBB0_9>
22: 69 12 24 00 00 00 00 00 r2 = *(u16 *)(r1 + 36)
23: 55 02 17 00 11 94 00 00 if r2 != 37905 goto +23 <LBB0_9>
24: 61 32 00 00 00 00 00 00 r2 = *(u32 *)(r3 + 0)
25: 15 02 15 00 00 00 00 00 if r2 == 0 goto +21 <LBB0_9>
26: b7 02 00 00 00 00 00 00 r2 = 0
27: 7b 2a f8 ff 00 00 00 00 *(u64 *)(r10 - 8) = r2
28: 61 12 1a 00 00 00 00 00 r2 = *(u32 *)(r1 + 26)
29: 63 2a f8 ff 00 00 00 00 *(u32 *)(r10 - 8) = r2
30: 69 11 22 00 00 00 00 00 r1 = *(u16 *)(r1 + 34)
31: dc 01 00 00 10 00 00 00 r1 = be16 r1
32: 6b 1a fc ff 00 00 00 00 *(u16 *)(r10 - 4) = r1
33: bf a7 00 00 00 00 00 00 r7 = r10
34: 07 07 00 00 f8 ff ff ff r7 += -8
35: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
37: bf 72 00 00 00 00 00 00 r2 = r7
38: 85 00 00 00 01 00 00 00 call 1
39: bf 61 00 00 00 00 00 00 r1 = r6
40: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll
42: 18 03 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 r3 = 4294967295 ll
44: bf 74 00 00 00 00 00 00 r4 = r7
45: b7 05 00 00 08 00 00 00 r5 = 8
46: 85 00 00 00 19 00 00 00 call 25
0000000000000178 LBB0_9:
47: b7 00 00 00 02 00 00 00 r0 = 2
48: 95 00 00 00 00 00 00 00 exit
-----------------------
# ./<binary>
Maps:
<map1>: Hash, Fd 5
<map2>: Event array, Fd 6
Programs:
<xdp_prog>: XDP, size 392, license "GPL"
System data: map[xdp_prog:0xc0000b8480]Attaching program xdp_prog
[perf event received]
^C
i spent the past two days trying to get it fixed, no luck so far.
can you help me?
thank you!
edit:
if i move get_next_key function (the one introduced on the commit mentioned above) to the end of the list, the perf_event_output function works fine. does the ordering here needs to be taken into account somewhere else?
Hello,
First of all, thank you for working on this library. So far I've had a very positive experience using it, especially with the included examples and documentation.
I do have one suggestion regarding the mocks package. What are your thoughts on providing a way to override the default implementation each mock has? To give you an example:
Currently the LoadElf()
method from mock_ebpf.go
looks something like the following:
func (m *MockSystem) LoadElf(fn string) error {
return nil
}
This is great but it doesn't let the user override with a different behaviour for LoadElf()
, one that could be potentially a non happy-path that returns an error. So with that in mind it would look something like the following:
func (m *MockSystem) LoadElf(fn string) error {
if m.loadElf != nil {
return m.loadElf(fn)
}
return nil
}
Where loadElf is a member of the struct MockSystem
and can be overriden as needed during a unit test where various implementations of LoadElf()
are needed.
Let me know your thoughts, I can draft a PR to incorporate this.
Hi, I can not run any examples due to this error (I'm using Fedora 33):
$ uname -r
5.10.19-200.fc33.x86_64
$ pwd
goebpf/examples/xdp/basic_firewall
$ sudo ulimit
unlimited
$ clang --version
clang version 11.0.0 (Fedora 11.0.0-2.fc33)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ sudo ./main -iface enp7s0u2u1u2 -drop 8.8.8.8
LoadElf() failed: loadAndCreateMaps() failed: map.Create() failed: ebpf_create_map() failed: Operation not permitted
A part of my program is as below,encountered this problem while executing.
Loadmap() failed: ebpf_map_update_elem() failed: Invalid argument
this program works when i changed BPF_MAP_TYPE_PROG_ARRAY to others like BPF_MAP_TYPE_PERCPU_ARRAY
var elf = flag.String("elf", "/usr/src/linux-source-5.11.0/samples/bpf/test_dump.o", "clang/llvm compiled binary file")
var elf1 = flag.String("elf1", "xdp_fw.o", "clang/llvm compiled binary file")
// Create eBPF system
bpf := goebpf.NewDefaultEbpfSystem()
// Load .ELF files compiled by clang/llvm
err := bpf.LoadElf(*elf, 1)
if err != nil {
fatalError("Loadbpf() failed: %v", err)
}
next_prog_map := bpf.GetMapByName("next_prog_map").(*goebpf.EbpfMap)
fmt.Println("46464646", next_prog_map)
bpf1 := goebpf.NewDefaultEbpfSystem()
// Load .ELF files compiled by clang/llvm
err = bpf1.LoadElf(*elf1, 1)
if err != nil {
fatalError("Loadbpf1() failed: %v", err)
}
shtest := bpf1.GetProgramByName("firewall")
err = next_prog_map.Update(0, shtest.GetFd())
if err != nil {
fatalError("Loadmap() failed: %v", err)
}
The basic_firewall does not work, I made the following change, can work properly.
Is this related to the environment?
My system environment
kernel: 5.4.2
llvm: 9.0
xdp_fw.c
// XDP program //
SEC("xdp")
...
__u64 *rule_idx = bpf_map_lookup_elem(&blacklist, &ip->saddr);
...
}
// XDP program //
SEC("xdp")
...
struct {
__u32 prefixlen;
__u32 saddr;
} key;
key.prefixlen = 32;
key.saddr = ip->saddr;
// Lookup SRC IP in blacklisted IPs
__u64 *rule_idx = bpf_map_lookup_elem(&blacklist, &key);
...
}
[root@node01 xdp_dump]# go build
In file included from ../../../map.go:13:0:
./bpf_helpers.h:957:15: error: expected declaration specifiers or '...' before 'sizeof'
static_assert(sizeof(__u8) == 1, "wrong_u8_size");
^
./bpf_helpers.h:957:34: error: expected declaration specifiers or '...' before string constant
static_assert(sizeof(__u8) == 1, "wrong_u8_size");
^
./bpf_helpers.h:958:15: error: expected declaration specifiers or '...' before 'sizeof'
static_assert(sizeof(__u16) == 2, "wrong_u16_size");
^
./bpf_helpers.h:958:35: error: expected declaration specifiers or '...' before string constant
static_assert(sizeof(__u16) == 2, "wrong_u16_size");
^
./bpf_helpers.h:959:15: error: expected declaration specifiers or '...' before 'sizeof'
static_assert(sizeof(__u32) == 4, "wrong_u32_size");
^
./bpf_helpers.h:959:35: error: expected declaration specifiers or '...' before string constant
static_assert(sizeof(__u32) == 4, "wrong_u32_size");
^
./bpf_helpers.h:960:15: error: expected declaration specifiers or '...' before 'sizeof'
static_assert(sizeof(__u64) == 8, "wrong_u64_size");
^
./bpf_helpers.h:960:35: error: expected declaration specifiers or '...' before string constant
static_assert(sizeof(__u64) == 8, "wrong_u64_size");
^
[root@node01 xdp_dump]#
When I run golang side. "LoadElf() failed: loadAndCreateMaps() failed: Invalid binary representation of BPF map" error occurs.
I do not know what the problem is. Can you help about it.
Create object:
clang -I../../.. -O2 -target bpf -c xdp_dump.c -o xdp_dump.elf
XDP Side (xdp_dump.c):
#include <stdbool.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <linux/if_ether.h> // Include this for struct ethhdr
#include <linux/ip.h> // Include this for struct iphdr
#include <linux/tcp.h> // Include this for struct tcphdr
#define MAX_ENTRIES_FLOW 1024
#define min(x, y) ((x) < (y) ? x : y)
char _license[] SEC("license") = "GPL";
struct pkt_trace_metadata {
__u32 ifindex;
__u32 rx_queue;
__u16 pkt_len;
__u16 cap_len;
__u16 flags;
__u16 prog_index;
int action;
} __packed;
// Define the structure for BPF map
struct bpf_map_def {
__u32 type;
__u32 key_size;
__u32 value_size;
__u32 max_entries;
};
#define BPF_MAP(_name, _type, _key_type, _value_type, _max_entries) \
struct bpf_map_def SEC("maps") _name = { \
.type = _type, \
.key_size = sizeof(_key_type), \
.value_size = sizeof(_value_type), \
.max_entries = _max_entries, \
};
#define BPF_HASH(_name, _key_type, _value_type) \
BPF_MAP(_name, BPF_MAP_TYPE_HASH, _key_type, _value_type, 10240);
#define BPF_PACKET_MAP(_name) \
BPF_MAP(_name, BPF_MAP_TYPE_PERF_EVENT_ARRAY, int, __u32, MAX_ENTRIES_FLOW);
BPF_PACKET_MAP(packetmap)
// XDP program //
SEC("xdp")
int xdp_dump(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct pkt_trace_metadata metadata;
//
metadata.prog_index = 0;
metadata.ifindex = ctx->ingress_ifindex;
metadata.rx_queue = ctx->rx_queue_index;
metadata.pkt_len = (__u16)(data_end - data);
metadata.cap_len = min(metadata.pkt_len, 65535);
metadata.action = 0;
metadata.flags = 0;
//
bpf_perf_event_output(ctx, &packetmap, ((__u64)metadata.cap_len << 32) | BPF_F_CURRENT_CPU, &metadata, sizeof(metadata));
return XDP_PASS;
}
GoLang Side:
// Create eBPF system / load .ELF files compiled by clang/llvm
bpf := goebpf.NewDefaultEbpfSystem()
err := bpf.LoadElf("xdp_dump.elf")
if err != nil {
fatalError("LoadElf() failed: %v", err)
}
packetmap := bpf.GetMapByName("packetmap")
if packetmap == nil {
fmt.Println("eBPF map 'packetmap' not found")
fatalError("eBPF map 'packetmap' not found")
}
xdp.Attach("eth0"): "LinkSetXdpFd() failed: invalid argument"
ubuntu version: 5.15.0-1017-aws
however it could run normally when attaching lo
(127.0.0.1)
The operation process is as follows:
git clone https://github.com/dropbox/goebpf.git cd goebpf/examples/kprobe/exec_dump/ make ./main
Program failed to run,error:
write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: no such file or directory write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy write: write /sys/kernel/debug/tracing/kprobe_events: device or resource busy
Hi,
Thanks for the great library. I really like the way goebpf handle ebpf, but I found that goebpf seems not to support af_xdp.
So it would be better to support af_xdp, af_xdp is necessary for integrate with some dpi library like ndpi. What do you think?
Can you please tell me what conditions regarding the interface you need to fulfill in order for the return codes XDP_REDIRECT and XDP_TX to work correctly? For example, I change the destination port, and return the XDP_PASS code, the packet does not get in this interface to the server running on the port that I changed in the package:
struct tcphdr *tcp = ctx->data_start + ctx->nh_offset; tcp->dest = (__u16)bpf_ntohs(some_port_value); // 5555 for example...
Then I tried using the return code XDP_REDIRECT, followed by redirecting the packet to the external interface, but this just led to freezing the external network interface:
`
INTERNAL __u32 redirect(struct context *ctx)
{
struct bpf_fib_lookup fib_params = {};
__u32 action = XDP_PASS;
if (ctx->v4 && ctx->tcp)
{
/* populate the fib_params fields to prepare for the lookup */
fib_params.family = AF_INET;
fib_params.tos = ctx->v4->tos;
fib_params.l4_protocol = ctx->v4->protocol;
fib_params.sport = ctx->tcp->source;
fib_params.dport = some_port_value;
fib_params.tot_len = bpf_ntohs(ctx->v4->tot_len);
fib_params.ipv4_src = ctx->v4->saddr;
fib_params.ipv4_dst = ctx->v4->daddr;
/* Set a proper destination address */
memcpy(custom_ctx.eth->h_dest, , ETH_ALEN);
action = bpf_redirect_map(&tx_port, 0, 0);
}
fib_params.ifindex = 1;
/* this is where the FIB lookup happens. If the lookup is successful */
/* it will populate the fib_params.ifindex with the egress interface index */
__u16 h_proto = ctx->eth->h_proto;
int rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), 0);
switch (rc) {
case BPF_FIB_LKUP_RET_SUCCESS: /* lookup successful */
/* we are a router, so we need to decrease the ttl */
if (h_proto == bpf_htons(ETH_P_IP))
ip_decrease_ttl(ctx->v4);
else if (h_proto == bpf_htons(ETH_P_IPV6))
ctx->v6->hop_limit--;
/* set the correct new source and destionation mac addresses */
/* can be found in fib_params.dmac and fib_params.smac */
memcpy(ctx->eth->h_dest, fib_params.dmac, ETH_ALEN);
memcpy(ctx->eth->h_source, fib_params.smac, ETH_ALEN);
/* and done, now we set the action to bpf_redirect_map with fib_params.ifindex which is the egress port as paramater */
action = bpf_redirect_map(&tx_port, fib_params.ifindex, 0);
break;
case BPF_FIB_LKUP_RET_BLACKHOLE: /* dest is blackholed; can be dropped */
case BPF_FIB_LKUP_RET_UNREACHABLE: /* dest is unreachable; can be dropped */
case BPF_FIB_LKUP_RET_PROHIBIT: /* dest not allowed; can be dropped */
action = XDP_DROP;
break;
case BPF_FIB_LKUP_RET_NOT_FWDED: /* packet is not forwarded */
case BPF_FIB_LKUP_RET_FWD_DISABLED: /* fwding is not enabled on ingress */
case BPF_FIB_LKUP_RET_UNSUPP_LWT: /* fwd requires encapsulation */
case BPF_FIB_LKUP_RET_NO_NEIGH: /* no neighbor entry for nh */
case BPF_FIB_LKUP_RET_FRAG_NEEDED: /* fragmentation required to fwd */
/* PASS */
break;
}
return action;
}
`
Hi,
While trying to compile and run the given example of packet_counter, I faced the following:
BPF_MAP_DEF(protocols) = {
.map_type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 255,
};
BPF_MAP_ADD(protocols);
It is rejected by clang with the following errors:
xdp_cnt.c:28:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_MAP_DEF(protocols) = {
^
xdp_cnt.c:28:13: error: a parameter list without types is only allowed in a function definition
BPF_MAP_DEF(protocols) = {
^
xdp_cnt.c:34:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
BPF_MAP_ADD(protocols);
^
xdp_cnt.c:34:13: error: a parameter list without types is only allowed in a function definition
BPF_MAP_ADD(protocols);
^
xdp_cnt.c:56:43: error: use of undeclared identifier 'protocols'
__u64 *counter = bpf_map_lookup_elem(&protocols, &proto_index);
2 warnings and 3 errors generated.
I have rewrote it in the following way:
struct bpf_map_def SEC ("maps") protocols = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 255,
};
Then it is flawlessly compiled by clang but goebpf fails to load the elf file throwing out: "LoadElf() failed: loadAndCreateMaps() failed: Invalid binary representation of BPF map"
Below attached my reworked C code, Golang code is the same as given in the example:
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
// Ethernet header
struct ethhdr {
__u8 h_dest[6];
__u8 h_source[6];
__u16 h_proto;
} __attribute__((packed));
// IPv4 header
struct iphdr {
__u8 ihl : 4;
__u8 version : 4;
__u8 tos;
__u16 tot_len;
__u16 id;
__u16 frag_off;
__u8 ttl;
__u8 protocol;
__u16 check;
__u32 saddr;
__u32 daddr;
} __attribute__((packed));
// eBPF map to store IP proto counters (tcp, udp, etc)
struct bpf_map_def SEC ("maps") protocols = {
.type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 255,
};
// XDP program //
SEC("xdp")
int packet_count(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
// Only IPv4 supported for this example
struct ethhdr *ether = data;
if (data + sizeof(*ether) > data_end) {
return XDP_ABORTED;
}
if (ether->h_proto == 0x08U) { // htons(ETH_P_IP) -> 0x08U
data += sizeof(*ether);
struct iphdr *ip = data;
if (data + sizeof(*ip) > data_end) {
return XDP_ABORTED;
}
// Increase counter in "protocols" eBPF map
__u32 proto_index = ip->protocol;
__u64 *counter = bpf_map_lookup_elem(&protocols, &proto_index);
if (counter) {
(*counter)++;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPLv2";
Hey all,
at first I want to thank for the great work you've done so far with this package, I really like the simple API and had a very easy quickstart with this.
At the moment, I struggle with having the error LoadElf() failed: loadPrograms() failed: Invalid BPF instruction (at 144): &{133 0 1 0 4294967295}
with the following code:
BPF_MAP_DEF(rxcnt) = {
.map_type = BPF_MAP_TYPE_PERCPU_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 256,
};
BPF_MAP_ADD(rxcnt);
static inline void count_tx(__u32 protocol)
{
__u64 *rxcnt_count;
rxcnt_count = bpf_map_lookup_elem(&rxcnt, &protocol);
if (rxcnt_count)
*rxcnt_count += 1;
}
SEC("xdp") int xdp_sock(struct xdp_md *ctx) {
void *data = (void *)(long)ctx->data;
void *data_end = (void *)(long)ctx->data_end;
size_t offset = sizeof(struct ether_header) +
sizeof(struct iphdr);
if(data + offset > data_end) {
return XDP_PASS; // too short
}
count_tx(0);
const struct ether_header *eh = (const struct ether_header *)data;
// FIXME: Without htons|bpf_htons it works as expected, with one of them we got
// LoadElf() failed: loadPrograms() failed: Invalid BPF instruction (at 144): &{133 0 1 0 4294967295}
if(eh->ether_type != htons(ETHERTYPE_IP)) {
return XDP_PASS; // not IP
}
// FIXME: THis somehow depends on this instruction
// If we have a map lookup after this htons instructions, the error occurs
count_tx(1);
return XDP_PASS;
}
Since I'm new to ebpf, not sure if I'm doing something wrong, but loading the respective ELF file with another approach (https://github.com/xdp-project/xdp-tutorial) works as expected. A full setup to reproduce this can be found here: https://github.com/martenwallewein/goepf-repro.
It would be nice if you could have a look at this if I'm doing something wrong or if there is a bug in the loadPrograms function.
Best,
Marten
Hi,
The library is awesome! Thanks for great work.
But I wonder whether it already supported BPF_PERF_EVENT_OUTPUT() helper?
I compiled tests with make
and ran them with sudo ./itest_test
All tests failed with errors like
loadAndCreateMaps() failed: map.Create() failed: ebpf_create_map() failed: Operation not permitted
ebpf_create_map() failed: Operation not permitted
go version go1.15.7 linux/amd64
Ubuntu 20.04 kernel 5.8.0-41
Hello,
I run the xdp_dump code located under examples in this repo .
When I want to get the full ip/tcp/eth layers, a padding issue occurs. There are errors in the source and destination. For example, the source IP should be 192.168.11.10. It lacks the initial 192.
Problematic part:
Source IP=> 168.11.10.142:18433
Dest IP=> 251.140.67.224:47872
{IpH:{IHL:69 Version:0 TOS:0 TotLen:61 ID:16384 FragOff:16384 TTL:17 Protocol:83 Checksum:49343 SrcAddr:2383023016 DstAddr:3762523387} TcpH:{Source:328 Dest:187 Seq:1145570345 AckSeq:3450062566 Flags:22071 Window:14497 Check:15429 UrgPtr:34857} EthH:{HDest:[9 91 80 34 178 208] HSource:[192 191 47 111 128 8] HProto:0}}
C code side:
// PerfEvent eBPF map
BPF_MAP_DEF(perfmap) = {
.map_type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.max_entries = 128,
};
BPF_MAP_ADD(perfmap);
// PerfEvent item
struct perf_event_item {
// ip header section
struct iphdr iphdr;
struct tcphdr tcphdr;
struct ethhdr ethhdr;
};
_Static_assert(sizeof(struct perf_event_item) == 56, "struct perf_event_item size");
int xdp_dump(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
__u64 packet_size = data_end - data;
// L2
struct ethhdr *ether = data;
if (data + sizeof(*ether) > data_end) {
return XDP_ABORTED;
}
// L3
if (ether->h_proto != 0x08) { // htons(ETH_P_IP) -> 0x08
// Non IPv4
return XDP_PASS;
}
data += sizeof(*ether);
struct iphdr *ip = data;
if (data + sizeof(*ip) > data_end) {
return XDP_ABORTED;
}
// L4
// if (ip->protocol != 0x06) { // IPPROTO_TCP -> 6
// // Non TCP
// return XDP_PASS;
// }
data += ip->ihl * 4;
struct tcphdr *tcp = data;
if (data + sizeof(*tcp) > data_end) {
return XDP_ABORTED;
}
// Emit perf event for every TCP SYN packet
if (tcp->syn) {
struct perf_event_item evt;
memset(&evt, 0, sizeof(evt));
evt.iphdr = *ip;
evt.tcphdr = *tcp;
evt.ethhdr = *ether;
//
// flags for bpf_perf_event_output() actually contain 2 parts (each 32bit long):
//
// bits 0-31: either
// - Just index in eBPF map
// or
// - "BPF_F_CURRENT_CPU" kernel will use current CPU_ID as eBPF map index
//
// bits 32-63: may be used to tell kernel to amend first N bytes
// of original packet (ctx) to the end of the data.
// So total perf event length will be sizeof(evt) + packet_size
bpf_perf_event_output(ctx, &perfmap, BPF_F_CURRENT_CPU, &evt, sizeof(evt));
}
return XDP_PASS;
}
GoLang Side:
func RunDPIXDP(ifacename string) {
// Create eBPF system / load .ELF files compiled by clang/llvm
bpf := goebpf.NewDefaultEbpfSystem()
err := bpf.LoadElf(*elf)
if err != nil {
fatalError("LoadElf() failed: %v", err)
}
printBpfInfo(bpf)
// Find special "PERF_EVENT" eBPF map
perfmap := bpf.GetMapByName("perfmap")
if perfmap == nil {
fmt.Println("eBPF map 'perfmap' not found")
fatalError("eBPF map 'perfmap' not found")
}
// Program name matches function name in xdp.c:
// int xdp_dump(struct xdp_md *ctx)
xdp := bpf.GetProgramByName(*programName)
if xdp == nil {
fatalError("Program '%s' not found.", *programName)
}
// Load XDP program into kernel
err = xdp.Load()
if err != nil {
fatalError("xdp.Load(): %v", err)
}
// Attach to interface
err = xdp.Attach(*iface)
if err != nil {
fmt.Println(err)
fatalError("xdp.Attach(): %v", err)
}
defer xdp.Detach()
// Add CTRL+C handler
ctrlC := make(chan os.Signal, 1)
signal.Notify(ctrlC, os.Interrupt)
// Start listening to Perf Events
perf, _ := goebpf.NewPerfEvents(perfmap)
perfEvents, err := perf.StartForAllProcessesAndCPUs(4096)
if err != nil {
fatalError("perf.StartForAllProcessesAndCPUs(): %v", err)
}
fmt.Println("XDP program successfully loaded and attached.")
fmt.Println("All new TCP connection requests (SYN) coming to this host will be dumped here.")
fmt.Println()
go func() {
var event types.PerfEventItem
for {
if eventData, ok := <-perfEvents; ok {
fmt.Println(eventData)
reader := bytes.NewReader(eventData)
binary.Read(reader, binary.LittleEndian, &event)
fmt.Printf("Event: %+v\n", event)
fmt.Printf("Source IP=> %v:%v\n", intToIPv4(event.IpH.SrcAddr), ntohs(event.TcpH.Source))
fmt.Printf("Dest IP=> %v:%v\n", intToIPv4(event.IpH.DstAddr), ntohs(event.TcpH.Dest))
if len(eventData)-metadataSize > 0 {
}
} else {
// Update channel closed
break
}
}
}()
// Wait until Ctrl+C pressed
<-ctrlC
// Stop perf events and print summary
perf.Stop()
fmt.Println("\nSummary:")
fmt.Printf("\t%d Event(s) Received\n", perf.EventsReceived)
fmt.Printf("\t%d Event(s) lost (e.g. small buffer, delays in processing)\n", perf.EventsLost)
fmt.Println("\nDetaching program and exit...")
}
Hi,
exist kprobe program with map:
BPF_MAP_DEF(pinfo_map) = {
.map_type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(key_type),
.value_size = sizeof(struct event),
.max_entries = 65535,
.persistent_path = "/sys/fs/bpf/pinfo",
};
BPF_MAP_ADD(pinfo_map);
```,
and there is a TC program that should look for values by key in this map. How init this map in TC-program?
If you initiate also, there will be an error:
`LoadElf(tc_prog.o) failed: loadAndCreateMaps() failed: map.Create() failed: ebpfObjPin to '/sys/fs/bpf/pinfo' failed: File exists`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.