Skip to content

Commit

Permalink
XDP UTs
Browse files Browse the repository at this point in the history
  • Loading branch information
jayanthvn committed Aug 21, 2023
1 parent ed84377 commit 13f775e
Show file tree
Hide file tree
Showing 5 changed files with 578 additions and 9 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ EBPF_TEST_MAP_BINARY := test-data/test.map.bpf.elf
EBPF_TEST_LIC_SOURCE := test-data/test_license.bpf.c
EBPF_TEST_LIC_BINARY := test-data/test_license.bpf.elf
EBPF_TEST_INV_MAP_SOURCE := test-data/invalid_map.bpf.c
EBPF_TEST_INV_MAP_BINARY := test-data/invalid_map.bpf.elf
EBPF_TEST_INV_MAP_BINARY := test-data/invalid_map.bpf.elf
EBPF_TEST_RECOVERY_SOURCE := test-data/recoverydata.bpf.c
EBPF_TEST_RECOVERY_BINARY := test-data/recoverydata.bpf.elf
EBPF_TEST_XDP_SOURCE := test-data/xdp.bpf.c
EBPF_TEST_XDP_BINARY := test-data/xdp.bpf.elf
build-bpf: ## Build BPF
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_SOURCE) -o $(EBPF_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_SOURCE) -o $(EBPF_TEST_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_MAP_SOURCE) -o $(EBPF_TEST_MAP_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_LIC_SOURCE) -o $(EBPF_TEST_LIC_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_INV_MAP_SOURCE) -o $(EBPF_TEST_INV_MAP_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_RECOVERY_SOURCE) -o $(EBPF_TEST_RECOVERY_BINARY)
$(CLANG) $(CLANG_INCLUDE) -g -O2 -Wall -fpie -target bpf -DCORE -D__BPF_TRACING__ -march=bpf -D__TARGET_ARCH_$(ARCH) -c $(EBPF_TEST_XDP_SOURCE) -o $(EBPF_TEST_XDP_BINARY)

vmlinuxh:
bpftool btf dump file /sys/kernel/btf/vmlinux format c > $(abspath ./test-data/vmlinux.h)
Expand Down
295 changes: 295 additions & 0 deletions pkg/elfparser/elf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,298 @@ func TestParseMap(t *testing.T) {
}

}

func TestParseProg(t *testing.T) {
progtests := []struct {
name string
elfFileName string
want int
invalidate bool
invalidateRelo bool
wantErr error
}{
{
name: "Missing prog section",
elfFileName: "../../test-data/test.map.bpf.elf",
want: 0,
wantErr: nil,
},
{
name: "Test prog data",
elfFileName: "../../test-data/tc.ingress.bpf.elf",
want: 3,
wantErr: nil,
},
{
name: "Missing prog data",
elfFileName: "../../test-data/tc.ingress.bpf.elf",
invalidate: true,
wantErr: errors.New("missing data in prog section"),
},
{
name: "Missing relo data",
elfFileName: "../../test-data/tc.ingress.bpf.elf",
invalidateRelo: true,
wantErr: errors.New("failed to apply relocation: unable to parse relocation entries...."),
},
}

for _, tt := range progtests {
t.Run(tt.name, func(t *testing.T) {

m := setup(t, tt.elfFileName)
defer m.ctrl.Finish()
f, _ := os.Open(m.path)
defer f.Close()

elfFile, err := elf.NewFile(f)
assert.NoError(t, err)
elfLoader := newElfLoader(elfFile, m.ebpf_maps, m.ebpf_progs, "test")

err = elfLoader.parseSection()
assert.NoError(t, err)

mapData, err := elfLoader.parseMap()
assert.NoError(t, err)

m.ebpf_maps.EXPECT().CreateBPFMap(gomock.Any()).AnyTimes()
m.ebpf_maps.EXPECT().PinMap(gomock.Any(), gomock.Any()).AnyTimes()
m.ebpf_maps.EXPECT().GetMapFromPinPath(gomock.Any()).AnyTimes()

loadedMapData, err := elfLoader.loadMap(mapData)
assert.NoError(t, err)

if tt.invalidate {
for progIndex, progEntry := range elfLoader.progSectionMap {
var dummySection elf.Section = elf.Section{}
copiedprogSection := *(progEntry.progSection)
copiedprogSection.SectionHeader = dummySection.SectionHeader
progEntry.progSection = &copiedprogSection
elfLoader.progSectionMap[progIndex] = progEntry
}
}

if tt.invalidateRelo {
for progIndex, reloSection := range elfLoader.reloSectionMap {
var dummySection elf.Section = elf.Section{}
copiedreloSection := *(reloSection)
copiedreloSection.SectionHeader = dummySection.SectionHeader
reloSection = &copiedreloSection
elfLoader.reloSectionMap[progIndex] = reloSection
}
}

parsedProgData, err := elfLoader.parseProg(loadedMapData)

if tt.wantErr != nil {
assert.EqualError(t, err, tt.wantErr.Error())
} else {
progCount := len(parsedProgData)
assert.Equal(t, tt.want, progCount)
}
})
}

}

func mount_bpf_fs() error {
fmt.Println("Let's mount BPF FS")
err := syscall.Mount("bpf", "/sys/fs/bpf", "bpf", 0, "mode=0700")
if err != nil {
fmt.Println("error mounting bpffs")
}
return err
}

func unmount_bpf_fs() error {
fmt.Println("Let's unmount BPF FS")
err := syscall.Unmount("/sys/fs/bpf", 0)
if err != nil {
fmt.Println("error unmounting bpffs")
}
return err
}

func TestRecoveryWithoutMount(t *testing.T) {
m := setup(t, "../../test-data/recoverydata.bpf.elf")
defer m.ctrl.Finish()

bpfSDKclient := New()

unmount_bpf_fs()

_, err := bpfSDKclient.RecoverAllBpfProgramsAndMaps()

assert.EqualError(t, err, errors.New("error checking BPF FS might not be mounted").Error())

}

func TestRecovery(t *testing.T) {

mount_bpf_fs()
defer unmount_bpf_fs()

progtests := []struct {
name string
elfFileName string
wantMap int
wantProg int
recoverGlobal bool
wantErr error
}{
{
name: "Recover Global maps",
elfFileName: "../../test-data/test.map.bpf.elf",
wantMap: 1,
recoverGlobal: true,
wantErr: nil,
},
{
name: "Recover BPF data",
elfFileName: "../../test-data/recoverydata.bpf.elf",
wantProg: 3,
wantErr: nil,
},
}

for _, tt := range progtests {
t.Run(tt.name, func(t *testing.T) {

m := setup(t, tt.elfFileName)
defer m.ctrl.Finish()

bpfSDKclient := New()

if tt.recoverGlobal {
_, _, err := bpfSDKclient.LoadBpfFile(m.path, "global")
if err != nil {
assert.NoError(t, err)
}
recoveredMaps, err := bpfSDKclient.RecoverGlobalMaps()
if tt.wantErr != nil {
assert.EqualError(t, err, tt.wantErr.Error())
} else {
assert.Equal(t, tt.wantMap, len(recoveredMaps))
}
} else {
_, _, err := bpfSDKclient.LoadBpfFile(m.path, "test")
if err != nil {
assert.NoError(t, err)
}

recoveredData, err := bpfSDKclient.RecoverAllBpfProgramsAndMaps()
if tt.wantErr != nil {
assert.EqualError(t, err, tt.wantErr.Error())
} else {
assert.Equal(t, tt.wantProg, len(recoveredData))
}
}
})
}
}

func TestGetMapNameFromBPFPinPath(t *testing.T) {
type args struct {
pinPath string
}

tests := []struct {
name string
args args
want [2]string
}{
{
name: "Ingress Map Pinpath",
args: args{
pinPath: "/sys/fs/bpf/globals/aws/maps/hello-udp-748dc8d996-default_ingress_map",
},
want: [2]string{"ingress_map", "hello-udp-748dc8d996-default"},
},
{
name: "Egress Map Pinpath",
args: args{
pinPath: "/sys/fs/bpf/globals/aws/maps/hello-udp-748dc8d996-default_egress_map",
},
want: [2]string{"egress_map", "hello-udp-748dc8d996-default"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got1, got2 := GetMapNameFromBPFPinPath(tt.args.pinPath)
assert.Equal(t, tt.want[0], got1)
assert.Equal(t, tt.want[1], got2)
})
}
}

func TestMapGlobal(t *testing.T) {
type args struct {
pinPath string
}

tests := []struct {
name string
args args
want bool
}{
{
name: "Ingress Map",
args: args{
pinPath: "/sys/fs/bpf/globals/aws/maps/hello-udp-748dc8d996-default_ingress_map",
},
want: false,
},
{
name: "Egress Map",
args: args{
pinPath: "/sys/fs/bpf/globals/aws/maps/hello-udp-748dc8d996-default_egress_map",
},
want: false,
},
{
name: "Global",
args: args{
pinPath: "/sys/fs/bpf/globals/aws/maps/test_global",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsMapGlobal(tt.args.pinPath)
assert.Equal(t, tt.want, got)
})
}
}

func TestProgType(t *testing.T) {

tests := []struct {
name string
progType string
want bool
}{
{
name: "XDP",
progType: "xdp",
want: true,
},
{
name: "TC",
progType: "tc_cls",
want: true,
},
{
name: "Invalid prod",
progType: "tcc_cls",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isProgTypeSupported(tt.progType)
assert.Equal(t, tt.want, got)
})
}
}
>>>>>>> 7da4278 (XDP UTs)

Check failure on line 707 in pkg/elfparser/elf_test.go

View workflow job for this annotation

GitHub Actions / Unit test

expected declaration, found '>>'

Check failure on line 707 in pkg/elfparser/elf_test.go

View workflow job for this annotation

GitHub Actions / Unit test

expected declaration, found '>>'
34 changes: 26 additions & 8 deletions pkg/xdp/xdp.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,48 @@ import (

var log = logger.Get()

func XDPAttach(interfaceName string, progFD int) error {
type BpfXdp interface {
XDPAttach(progFD int) error
XDPDetach() error
}

var _ BpfXdp = &bpfXdp{}

type bpfXdp struct {
interfaceName string
}

func New(ifName string) BpfXdp {
return &bpfXdp{
interfaceName: ifName,
}

}

func (b *bpfXdp) XDPAttach(progFD int) error {

link, err := netlink.LinkByName(interfaceName)
link, err := netlink.LinkByName(b.interfaceName)
if err != nil {
log.Errorf("failed to obtain link info for %s : %v", interfaceName, err)
log.Errorf("failed to obtain link info for %s : %v", b.interfaceName, err)
return err
}

log.Infof("Attaching xdp prog %d to interface %s", progFD, interfaceName)
log.Infof("Attaching xdp prog %d to interface %s", progFD, b.interfaceName)

if err := netlink.LinkSetXdpFdWithFlags(link, progFD, constdef.XDP_ATTACH_MODE_SKB); err != nil {
log.Errorf("failed to setup xdp: %v", err)
return err
}
log.Infof("Attached XDP to interface %s", interfaceName)
log.Infof("Attached XDP to interface %s", b.interfaceName)

return nil
}

func XDPDetach(interfaceName string) error {
func (b *bpfXdp) XDPDetach() error {

link, err := netlink.LinkByName(interfaceName)
link, err := netlink.LinkByName(b.interfaceName)
if err != nil {
log.Errorf("failed to obtain link info for %s : %v", interfaceName, err)
log.Errorf("failed to obtain link info for %s : %v", b.interfaceName, err)
return err
}

Expand Down
Loading

0 comments on commit 13f775e

Please sign in to comment.