From 009e92288be77829272bf10984bbac0828342377 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Mon, 26 Aug 2024 11:56:22 +0200 Subject: [PATCH] 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 --- btf/btf.go | 12 ++++++++++-- internal/endian_le.go | 2 +- internal/io.go | 3 ++- map.go | 6 +++--- syscalls.go | 3 ++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/btf/btf.go b/btf/btf.go index 671f680b2..20bed62c6 100644 --- a/btf/btf.go +++ b/btf/btf.go @@ -632,8 +632,16 @@ func (s *Spec) TypeByName(name string, typ interface{}) error { wanted = typPtr.Elem().Type() } - if !wanted.AssignableTo(typeInterface) { - return fmt.Errorf("%T does not satisfy Type interface", typ) + switch wanted { + case reflect.TypeOf((**Datasec)(nil)).Elem(): + // Those types are already assignable to Type. No need to call + // AssignableTo. Avoid it when possible to workaround + // limitation in tinygo: + // https://github.com/tinygo-org/tinygo/issues/4277 + default: + if !wanted.AssignableTo(typeInterface) { + return fmt.Errorf("%T does not satisfy Type interface", typ) + } } types, err := s.AnyTypesByName(name) diff --git a/internal/endian_le.go b/internal/endian_le.go index 6dcd916d5..d833ea764 100644 --- a/internal/endian_le.go +++ b/internal/endian_le.go @@ -1,4 +1,4 @@ -//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv64 +//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || ppc64le || riscv64 || wasm package internal diff --git a/internal/io.go b/internal/io.go index 1eaf4775a..6ccbd8c24 100644 --- a/internal/io.go +++ b/internal/io.go @@ -27,8 +27,9 @@ func NewBufferedSectionReader(ra io.ReaderAt, off, n int64) *bufio.Reader { // of a file into memory. bufio.NewReader uses a hardcoded default buffer // of 4096. Allow arches with larger pages to allocate more, but don't // allocate a fixed 4k buffer if we only need to read a small segment. + pageSize := int64(4096) buf := n - if ps := int64(os.Getpagesize()); n > ps { + if ps := pageSize; n > ps { buf = ps } diff --git a/map.go b/map.go index d0ea05d4a..0a66d3386 100644 --- a/map.go +++ b/map.go @@ -6,7 +6,7 @@ import ( "fmt" "io" "math/rand" - "os" + //"os" "path/filepath" "reflect" "slices" @@ -507,7 +507,7 @@ func handleMapCreateError(attr sys.MapCreateAttr, spec *MapSpec, err error) erro // BPF_MAP_TYPE_RINGBUF's max_entries must be a power-of-2 multiple of kernel's page size. if errors.Is(err, unix.EINVAL) && (attr.MapType == sys.BPF_MAP_TYPE_RINGBUF || attr.MapType == sys.BPF_MAP_TYPE_USER_RINGBUF) { - pageSize := uint32(os.Getpagesize()) + pageSize := uint32(4096) maxEntries := attr.MaxEntries if maxEntries%pageSize != 0 || !internal.IsPow(maxEntries) { return fmt.Errorf("map create: %w (ring map size %d not a multiple of page size %d)", err, maxEntries, pageSize) @@ -950,7 +950,7 @@ func (m *Map) nextKey(key interface{}, nextKeyOut sys.Pointer) error { } var mmapProtectedPage = sync.OnceValues(func() ([]byte, error) { - return unix.Mmap(-1, 0, os.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED) + return unix.Mmap(-1, 0, 4096, unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED) }) // guessNonExistentKey attempts to perform a map lookup that returns ENOENT. diff --git a/syscalls.go b/syscalls.go index 0766e7dd6..d0ea244f4 100644 --- a/syscalls.go +++ b/syscalls.go @@ -27,7 +27,8 @@ var ( // invalidBPFObjNameChar returns true if char may not appear in // a BPF object name. func invalidBPFObjNameChar(char rune) bool { - dotAllowed := objNameAllowsDot() == nil + //dotAllowed := objNameAllowsDot() == nil + dotAllowed := true switch { case char >= 'A' && char <= 'Z':