Repository: cilium/ebpf
Pull request #325 (2021-06-15 10:56:52)

internal: export BPFMapCreate syscall wrapper
This commit allows the BPFMapCreate syscall wrapper and BPFMapCreateAttr
type to be used by other subpackages of the library while not publicly
exporting them. 

As discussed in #235 this will help me to move the code in #321 into its own subpackage.
To keep the PR small, I only addressed the function and type I need for now. 

Signed-off-by: Robin Gögge <r.goegge@outlook.com>


Patch:
diff --git a/internal/syscall.go b/internal/syscall.go
index 0ba438d..b9821f7 100644
--- a/internal/syscall.go
+++ b/internal/syscall.go
@@ -178,3 +178,38 @@ func BPFObjGetInfoByFD(fd *FD, info unsafe.Pointer, size uintptr) error {
 	}
 	return nil
 }
+
+// BPFObjName is a null-terminated string made up of
+// 'A-Za-z0-9_' characters.
+type BPFObjName [unix.BPF_OBJ_NAME_LEN]byte
+
+// NewBPFObjName truncates the result if it is too long.
+func NewBPFObjName(name string) BPFObjName {
+	var result BPFObjName
+	copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
+	return result
+}
+
+type BPFMapCreateAttr struct {
+	MapType        uint32
+	KeySize        uint32
+	ValueSize      uint32
+	MaxEntries     uint32
+	Flags          uint32
+	InnerMapFd     uint32     // since 4.12 56f668dfe00d
+	NumaNode       uint32     // since 4.14 96eabe7a40aa
+	MapName        BPFObjName // since 4.15 ad5b177bd73f
+	MapIfIndex     uint32
+	BTFFd          uint32
+	BTFKeyTypeID   uint32
+	BTFValueTypeID uint32
+}
+
+func BPFMapCreate(attr *BPFMapCreateAttr) (*FD, error) {
+	fd, err := BPF(BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+	if err != nil {
+		return nil, err
+	}
+
+	return NewFD(uint32(fd)), nil
+}
diff --git a/map.go b/map.go
index 7c12545..304219e 100644
--- a/map.go
+++ b/map.go
@@ -317,25 +317,25 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
 		}
 	}
 
-	attr := bpfMapCreateAttr{
-		mapType:    spec.Type,
-		keySize:    spec.KeySize,
-		valueSize:  spec.ValueSize,
-		maxEntries: spec.MaxEntries,
-		flags:      spec.Flags,
-		numaNode:   spec.NumaNode,
+	attr := internal.BPFMapCreateAttr{
+		MapType:    uint32(spec.Type),
+		KeySize:    spec.KeySize,
+		ValueSize:  spec.ValueSize,
+		MaxEntries: spec.MaxEntries,
+		Flags:      spec.Flags,
+		NumaNode:   spec.NumaNode,
 	}
 
 	if inner != nil {
 		var err error
-		attr.innerMapFd, err = inner.Value()
+		attr.InnerMapFd, err = inner.Value()
 		if err != nil {
 			return nil, fmt.Errorf("map create: %w", err)
 		}
 	}
 
 	if haveObjName() == nil {
-		attr.mapName = newBPFObjName(spec.Name)
+		attr.MapName = internal.NewBPFObjName(spec.Name)
 	}
 
 	var btfDisabled bool
@@ -347,13 +347,13 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
 		}
 
 		if handle != nil {
-			attr.btfFd = uint32(handle.FD())
-			attr.btfKeyTypeID = btf.MapKey(spec.BTF).ID()
-			attr.btfValueTypeID = btf.MapValue(spec.BTF).ID()
+			attr.BTFFd = uint32(handle.FD())
+			attr.BTFKeyTypeID = uint32(btf.MapKey(spec.BTF).ID())
+			attr.BTFValueTypeID = uint32(btf.MapValue(spec.BTF).ID())
 		}
 	}
 
-	fd, err := bpfMapCreate(&attr)
+	fd, err := internal.BPFMapCreate(&attr)
 	if err != nil {
 		if errors.Is(err, unix.EPERM) {
 			return nil, fmt.Errorf("map create: RLIMIT_MEMLOCK may be too low: %w", err)
diff --git a/prog.go b/prog.go
index de6d57e..13bdb6d 100644
--- a/prog.go
+++ b/prog.go
@@ -175,7 +175,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
 	}
 
 	if haveObjName() == nil {
-		attr.progName = newBPFObjName(spec.Name)
+		attr.progName = internal.NewBPFObjName(spec.Name)
 	}
 
 	var err error
diff --git a/syscalls.go b/syscalls.go
index c530aad..cf37dc8 100644
--- a/syscalls.go
+++ b/syscalls.go
@@ -13,17 +13,6 @@ import (
 // Generic errors returned by BPF syscalls.
 var ErrNotExist = errors.New("requested object does not exist")
 
-// bpfObjName is a null-terminated string made up of
-// 'A-Za-z0-9_' characters.
-type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte
-
-// newBPFObjName truncates the result if it is too long.
-func newBPFObjName(name string) bpfObjName {
-	var result bpfObjName
-	copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
-	return result
-}
-
 // invalidBPFObjNameChar returns true if char may not appear in
 // a BPF object name.
 func invalidBPFObjNameChar(char rune) bool {
@@ -45,21 +34,6 @@ func invalidBPFObjNameChar(char rune) bool {
 	}
 }
 
-type bpfMapCreateAttr struct {
-	mapType        MapType
-	keySize        uint32
-	valueSize      uint32
-	maxEntries     uint32
-	flags          uint32
-	innerMapFd     uint32     // since 4.12 56f668dfe00d
-	numaNode       uint32     // since 4.14 96eabe7a40aa
-	mapName        bpfObjName // since 4.15 ad5b177bd73f
-	mapIfIndex     uint32
-	btfFd          uint32
-	btfKeyTypeID   btf.TypeID
-	btfValueTypeID btf.TypeID
-}
-
 type bpfMapOpAttr struct {
 	mapFd   uint32
 	padding uint32
@@ -86,10 +60,10 @@ type bpfMapInfo struct {
 	value_size                uint32
 	max_entries               uint32
 	map_flags                 uint32
-	name                      bpfObjName // since 4.15 ad5b177bd73f
-	ifindex                   uint32     // since 4.16 52775b33bb50
-	btf_vmlinux_value_type_id uint32     // since 5.6  85d33df357b6
-	netns_dev                 uint64     // since 4.16 52775b33bb50
+	name                      internal.BPFObjName // since 4.15 ad5b177bd73f
+	ifindex                   uint32              // since 4.16 52775b33bb50
+	btf_vmlinux_value_type_id uint32              // since 5.6  85d33df357b6
+	netns_dev                 uint64              // since 4.16 52775b33bb50
 	netns_ino                 uint64
 	btf_id                    uint32 // since 4.18 78958fca7ead
 	btf_key_type_id           uint32 // since 4.18 9b2cf328b2ec
@@ -104,11 +78,11 @@ type bpfProgLoadAttr struct {
 	logLevel           uint32
 	logSize            uint32
 	logBuf             internal.Pointer
-	kernelVersion      uint32     // since 4.1  2541517c32be
-	progFlags          uint32     // since 4.11 e07b98d9bffe
-	progName           bpfObjName // since 4.15 067cae47771c
-	progIfIndex        uint32     // since 4.15 1f6f4cb7ba21
-	expectedAttachType AttachType // since 4.17 5e43f899b03a
+	kernelVersion      uint32              // since 4.1  2541517c32be
+	progFlags          uint32              // since 4.11 e07b98d9bffe
+	progName           internal.BPFObjName // since 4.15 067cae47771c
+	progIfIndex        uint32              // since 4.15 1f6f4cb7ba21
+	expectedAttachType AttachType          // since 4.17 5e43f899b03a
 	progBTFFd          uint32
 	funcInfoRecSize    uint32
 	funcInfo           internal.Pointer
@@ -132,7 +106,7 @@ type bpfProgInfo struct {
 	created_by_uid           uint32
 	nr_map_ids               uint32
 	map_ids                  internal.Pointer
-	name                     bpfObjName // since 4.15 067cae47771c
+	name                     internal.BPFObjName // since 4.15 067cae47771c
 	ifindex                  uint32
 	gpl_compatible           uint32
 	netns_dev                uint64
@@ -205,23 +179,14 @@ func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
 	return err
 }
 
-func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
-	fd, err := internal.BPF(internal.BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
-	if err != nil {
-		return nil, err
-	}
-
-	return internal.NewFD(uint32(fd)), nil
-}
-
 var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error {
-	_, err := bpfMapCreate(&bpfMapCreateAttr{
-		mapType:    ArrayOfMaps,
-		keySize:    4,
-		valueSize:  4,
-		maxEntries: 1,
+	_, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{
+		MapType:    uint32(ArrayOfMaps),
+		KeySize:    4,
+		ValueSize:  4,
+		MaxEntries: 1,
 		// Invalid file descriptor.
-		innerMapFd: ^uint32(0),
+		InnerMapFd: ^uint32(0),
 	})
 	if errors.Is(err, unix.EINVAL) {
 		return internal.ErrNotSupported
@@ -235,12 +200,12 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error {
 var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error {
 	// This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
 	// BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
-	m, err := bpfMapCreate(&bpfMapCreateAttr{
-		mapType:    Array,
-		keySize:    4,
-		valueSize:  4,
-		maxEntries: 1,
-		flags:      unix.BPF_F_RDONLY_PROG,
+	m, err := internal.BPFMapCreate(&internal.BPFMapCreateAttr{
+		MapType:    uint32(Array),
+		KeySize:    4,
+		ValueSize:  4,
+		MaxEntries: 1,
+		Flags:      unix.BPF_F_RDONLY_PROG,
 	})
 	if err != nil {
 		return internal.ErrNotSupported
@@ -417,15 +382,15 @@ func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) {
 }
 
 var haveObjName = internal.FeatureTest("object names", "4.15", func() error {
-	attr := bpfMapCreateAttr{
-		mapType:    Array,
-		keySize:    4,
-		valueSize:  4,
-		maxEntries: 1,
-		mapName:    newBPFObjName("feature_test"),
+	attr := internal.BPFMapCreateAttr{
+		MapType:    uint32(Array),
+		KeySize:    4,
+		ValueSize:  4,
+		MaxEntries: 1,
+		MapName:    internal.NewBPFObjName("feature_test"),
 	}
 
-	fd, err := bpfMapCreate(&attr)
+	fd, err := internal.BPFMapCreate(&attr)
 	if err != nil {
 		return internal.ErrNotSupported
 	}
@@ -439,15 +404,15 @@ var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func()
 		return err
 	}
 
-	attr := bpfMapCreateAttr{
-		mapType:    Array,
-		keySize:    4,
-		valueSize:  4,
-		maxEntries: 1,
-		mapName:    newBPFObjName(".test"),
+	attr := internal.BPFMapCreateAttr{
+		MapType:    uint32(Array),
+		KeySize:    4,
+		ValueSize:  4,
+		MaxEntries: 1,
+		MapName:    internal.NewBPFObjName(".test"),
 	}
 
-	fd, err := bpfMapCreate(&attr)
+	fd, err := internal.BPFMapCreate(&attr)
 	if err != nil {
 		return internal.ErrNotSupported
 	}
@@ -458,14 +423,14 @@ var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func()
 
 var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error {
 	var maxEntries uint32 = 2
-	attr := bpfMapCreateAttr{
-		mapType:    Hash,
-		keySize:    4,
-		valueSize:  4,
-		maxEntries: maxEntries,
+	attr := internal.BPFMapCreateAttr{
+		MapType:    uint32(Hash),
+		KeySize:    4,
+		ValueSize:  4,
+		MaxEntries: maxEntries,
 	}
 
-	fd, err := bpfMapCreate(&attr)
+	fd, err := internal.BPFMapCreate(&attr)
 	if err != nil {
 		return internal.ErrNotSupported
 	}


Test patch:
diff --git a/internal/syscall_test.go b/internal/syscall_test.go
new file mode 100644
index 0000000..f1f9007
--- /dev/null
+++ b/internal/syscall_test.go
@@ -0,0 +1,17 @@
+package internal
+
+import (
+	"testing"
+
+	"github.com/cilium/ebpf/internal/unix"
+)
+
+func TestObjName(t *testing.T) {
+	name := NewBPFObjName("more_than_16_characters_long")
+	if name[len(name)-1] != 0 {
+		t.Error("NewBPFObjName doesn't null terminate")
+	}
+	if len(name) != unix.BPF_OBJ_NAME_LEN {
+		t.Errorf("Name is %d instead of %d bytes long", len(name), unix.BPF_OBJ_NAME_LEN)
+	}
+}
diff --git a/syscalls_test.go b/syscalls_test.go
index 9e3ab80..b1f6878 100644
--- a/syscalls_test.go
+++ b/syscalls_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 
 	"github.com/cilium/ebpf/internal/testutils"
-	"github.com/cilium/ebpf/internal/unix"
 )
 
 func TestObjNameCharacters(t *testing.T) {
@@ -24,16 +23,6 @@ func TestObjNameCharacters(t *testing.T) {
 	}
 }
 
-func TestObjName(t *testing.T) {
-	name := newBPFObjName("more_than_16_characters_long")
-	if name[len(name)-1] != 0 {
-		t.Error("newBPFObjName doesn't null terminate")
-	}
-	if len(name) != unix.BPF_OBJ_NAME_LEN {
-		t.Errorf("Name is %d instead of %d bytes long", len(name), unix.BPF_OBJ_NAME_LEN)
-	}
-}
-
 func TestHaveBatchAPI(t *testing.T) {
 	testutils.CheckFeatureTest(t, haveBatchAPI)
 }