Skip to content

Commit a8ec889

Browse files
committed
New architecture: wasm
cilium/ebpf currently does not compile to wasm with tinygo. This patch makes it compile. I am working on a website where users can submit ebpf binaries (either in ELF format or as an Inspektor Gadget export) and the website will parse the ebpf binary client-side with wasm. The wasm code is written in Go, using cilium/ebpf and is compiled with tinygo. My wasm code uses ebpf.LoadCollectionSpecFromReader() to display information about the ebpf binary. But it will not call ebpf.NewCollection() because the wasm/javascript environment in the browser cannot interact with the Linux kernel. Signed-off-by: Alban Crequy <[email protected]>
1 parent 625b0a9 commit a8ec889

File tree

7 files changed

+39
-8
lines changed

7 files changed

+39
-8
lines changed

Diff for: btf/btf.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,16 @@ func (s *Spec) TypeByName(name string, typ interface{}) error {
632632
wanted = typPtr.Elem().Type()
633633
}
634634

635-
if !wanted.AssignableTo(typeInterface) {
636-
return fmt.Errorf("%T does not satisfy Type interface", typ)
635+
switch wanted {
636+
case reflect.TypeOf((**Datasec)(nil)).Elem():
637+
// Those types are already assignable to Type. No need to call
638+
// AssignableTo. Avoid it when possible to workaround
639+
// limitation in tinygo:
640+
// https://github.com/tinygo-org/tinygo/issues/4277
641+
default:
642+
if !wanted.AssignableTo(typeInterface) {
643+
return fmt.Errorf("%T does not satisfy Type interface", typ)
644+
}
637645
}
638646

639647
types, err := s.AnyTypesByName(name)

Diff for: internal/endian_le.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv64
1+
//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv64 || wasm
22

33
package internal
44

Diff for: internal/io.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewBufferedSectionReader(ra io.ReaderAt, off, n int64) *bufio.Reader {
2828
// of 4096. Allow arches with larger pages to allocate more, but don't
2929
// allocate a fixed 4k buffer if we only need to read a small segment.
3030
buf := n
31-
if ps := int64(os.Getpagesize()); n > ps {
31+
if ps := int64(Getpagesize()); n > ps {
3232
buf = ps
3333
}
3434

Diff for: internal/page_others.go

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build !wasm
2+
3+
package internal
4+
5+
import "os"
6+
7+
func Getpagesize() int {
8+
return os.Getpagesize()
9+
}

Diff for: internal/page_wasm.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build wasm
2+
3+
package internal
4+
5+
func Getpagesize() int {
6+
// A WebAssembly page has a constant size of 65,536 bytes, i.e., 64KiB
7+
return 64 * 1024
8+
}

Diff for: map.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"fmt"
77
"io"
88
"math/rand"
9-
"os"
109
"path/filepath"
1110
"reflect"
1211
"slices"
@@ -507,7 +506,7 @@ func handleMapCreateError(attr sys.MapCreateAttr, spec *MapSpec, err error) erro
507506
// BPF_MAP_TYPE_RINGBUF's max_entries must be a power-of-2 multiple of kernel's page size.
508507
if errors.Is(err, unix.EINVAL) &&
509508
(attr.MapType == sys.BPF_MAP_TYPE_RINGBUF || attr.MapType == sys.BPF_MAP_TYPE_USER_RINGBUF) {
510-
pageSize := uint32(os.Getpagesize())
509+
pageSize := uint32(internal.Getpagesize())
511510
maxEntries := attr.MaxEntries
512511
if maxEntries%pageSize != 0 || !internal.IsPow(maxEntries) {
513512
return fmt.Errorf("map create: %w (ring map size %d not a multiple of page size %d)", err, maxEntries, pageSize)
@@ -950,7 +949,7 @@ func (m *Map) nextKey(key interface{}, nextKeyOut sys.Pointer) error {
950949
}
951950

952951
var mmapProtectedPage = sync.OnceValues(func() ([]byte, error) {
953-
return unix.Mmap(-1, 0, os.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED)
952+
return unix.Mmap(-1, 0, internal.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED)
954953
})
955954

956955
// guessNonExistentKey attempts to perform a map lookup that returns ENOENT.

Diff for: syscalls.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ var (
2727
// invalidBPFObjNameChar returns true if char may not appear in
2828
// a BPF object name.
2929
func invalidBPFObjNameChar(char rune) bool {
30-
dotAllowed := objNameAllowsDot() == nil
30+
var dotAllowed bool
31+
if runtime.GOOS == "js" {
32+
// In Javascript environments, BPF objects are not going to be
33+
// loaded to a kernel, so we can use dots without testing.
34+
dotAllowed = true
35+
} else {
36+
dotAllowed = objNameAllowsDot() == nil
37+
}
3138

3239
switch {
3340
case char >= 'A' && char <= 'Z':

0 commit comments

Comments
 (0)