Skip to content

Commit

Permalink
Add TCX and Netlink tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelroquetto committed Jan 8, 2025
1 parent 6403683 commit 28d807f
Showing 1 changed file with 366 additions and 0 deletions.
366 changes: 366 additions & 0 deletions pkg/internal/ebpf/tcmanager/tcmanager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
package tcmanager

import (
"bytes"
"context"
"errors"
"os"
"testing"
"time"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
"github.com/stretchr/testify/assert"
"github.com/vishvananda/netlink"
)

const privilegedEnv = "PRIVILEGED_TESTS"

func TestTCXManagerTcxAttachType(t *testing.T) {
test := func(in AttachmentType, out ebpf.AttachType) {
r, err := tcxAttachType(in)
assert.NoError(t, err)
assert.Equal(t, out, r)
}

test(AttachmentEgress, ebpf.AttachTCXEgress)
test(AttachmentIngress, ebpf.AttachTCXIngress)
}

func isBpfProgLoaded(name string) (bool, error) {
id := ebpf.ProgramID(0)
var err error

for {
id, err = ebpf.ProgramGetNextID(id)

if err != nil {
if errors.Is(err, os.ErrNotExist) {
break
}

return false, err
}

prog, err := ebpf.NewProgramFromID(id)

if err != nil {
if errors.Is(err, os.ErrNotExist) {
// the program has been closed in the meantime, continue
continue
}

return false, err
}

defer prog.Close()

info, err := prog.Info()

if err != nil {
return false, err
}

if info.Name == name {
return true, nil
}
}

return false, nil
}

func isBpfProgLinked(name string) (bool, error) {
it := new(link.Iterator)

for it.Next() {
link := it.Take()
defer link.Close()

info, err := link.Info()

if err != nil {
return false, err
}

prog, err := ebpf.NewProgramFromID(info.Program)

if err != nil {
return false, err
}

defer prog.Close()

progInfo, err := prog.Info()

if err != nil {
return false, err
}

if progInfo.Name == name {
return true, nil
}
}

return false, nil
}

type Progs struct {
Ingress *ebpf.Program `ebpf:"beyla_ingress"`
Egress *ebpf.Program `ebpf:"beyla_egress"`
}

func loadProgs(t *testing.T) Progs {
reader := bytes.NewReader(tc_program)
assert.NotNil(t, reader)

spec, err := ebpf.LoadCollectionSpecFromReader(reader)
assert.NoError(t, err)

coll, err := ebpf.NewCollection(spec)
assert.NoError(t, err)
assert.NotNil(t, coll)

var progs Progs
err = coll.Assign(&progs)
assert.NoError(t, err)
assert.NotNil(t, progs.Ingress)
assert.NotNil(t, progs.Egress)

return progs
}

func TestTCXManagerAddRemove(t *testing.T) {
if os.Getenv(privilegedEnv) == "" {
t.Skipf("Skipping this test because %v is not set", privilegedEnv)
}

progs := loadProgs(t)

tcx := NewTCXManager()
assert.NotNil(t, tcx)

ctx := context.Background()

tcx.Start(ctx)

test := func(progName string, prog *ebpf.Program, attachType AttachmentType) {
tcx.AddProgram(progName, prog, attachType)

// wait for links to come up
time.Sleep(5 * time.Second)

linked, err := isBpfProgLinked(progName)
assert.NoError(t, err)
assert.True(t, linked)

tcx.RemoveProgram(progName)

prog.Close()

linked, err = isBpfProgLinked(progName)
assert.NoError(t, err)
assert.False(t, linked)

loaded, err := isBpfProgLoaded(progName)
assert.NoError(t, err)
assert.False(t, loaded)
}

test("beyla_ingress", progs.Ingress, AttachmentIngress)
test("beyla_egress", progs.Egress, AttachmentEgress)
}

func TestNetlinkManagerNetlinkAttachType(t *testing.T) {
test := func(in AttachmentType, out uint32) {
r, err := netlinkAttachType(in)
assert.NoError(t, err)
assert.Equal(t, out, r)
}

test(AttachmentEgress, netlink.HANDLE_MIN_EGRESS)
test(AttachmentIngress, netlink.HANDLE_MIN_INGRESS)
}

func isNetlinkFilterPresent(filterName string, attachType AttachmentType, netManager *netlinkManager) (bool, error) {
filterCount := 0

for ifaceIndex := range netManager.interfaces {
link, err := netlink.LinkByIndex(ifaceIndex)

if err != nil {
return false, err
}

aType, err := netlinkAttachType(attachType)

if err != nil {
return false, err
}

filters, err := netlink.FilterList(link, aType)

if err != nil {
return false, err
}

for _, filter := range filters {
bpfFilter, ok := filter.(*netlink.BpfFilter)

if !ok {
continue
}

if bpfFilter.Name == filterName {
filterCount++
}
}
}

if filterCount == len(netManager.interfaces) {
return true, nil
}

return false, nil
}

func TestNetlinkManagerAddRemove(t *testing.T) {
if os.Getenv(privilegedEnv) == "" {
t.Skipf("Skipping this test because %v is not set", privilegedEnv)
}

progs := loadProgs(t)

tc := NewNetlinkManager()
assert.NotNil(t, tc)

netManager := tc.(*netlinkManager)

ctx := context.Background()

tc.Start(ctx)

test := func(progName string, prog *ebpf.Program, attachType AttachmentType) {
tc.AddProgram(progName, prog, attachType)

// wait for links to come up
time.Sleep(5 * time.Second)

linked, err := isNetlinkFilterPresent(progName, attachType, netManager)
assert.NoError(t, err)
assert.True(t, linked)

tc.RemoveProgram(progName)

prog.Close()

time.Sleep(5 * time.Second)

linked, err = isNetlinkFilterPresent(progName, attachType, netManager)
assert.NoError(t, err)
assert.False(t, linked)

loaded, err := isBpfProgLoaded(progName)
assert.NoError(t, err)
assert.False(t, loaded)
}

test("beyla_ingress", progs.Ingress, AttachmentIngress)
test("beyla_egress", progs.Egress, AttachmentEgress)

netManager.shutdown()
}

/*
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
char __license[] SEC("license") = "Dual MIT/GPL";
SEC("tc_ingress")
int beyla_ingress(struct __sk_buff *skb) {
return 0;
}
SEC("tc_egress")
int beyla_egress(struct __sk_buff *skb) {
return 0;
}
clang -c -target bpf -O2 -o tc_program.o tc_program.c
xxd --include tc_program.o > tc_program.c
*/

// nolint: stylecheck,revive
var tc_program = []byte{
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf7, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x08, 0x00, 0x01, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x75, 0x61, 0x6c, 0x20, 0x4d, 0x49, 0x54, 0x2f, 0x47, 0x50, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x12, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x11, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04, 0x00, 0x2e, 0x74, 0x65, 0x78,
0x74, 0x00, 0x74, 0x63, 0x5f, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73,
0x00, 0x62, 0x65, 0x79, 0x6c, 0x61, 0x5f, 0x69, 0x6e, 0x67, 0x72, 0x65,
0x73, 0x73, 0x00, 0x74, 0x63, 0x5f, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73,
0x00, 0x62, 0x65, 0x79, 0x6c, 0x61, 0x5f, 0x65, 0x67, 0x72, 0x65, 0x73,
0x73, 0x00, 0x2e, 0x6c, 0x6c, 0x76, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x72,
0x73, 0x69, 0x67, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
0x65, 0x00, 0x66, 0x6f, 0x6f, 0x2e, 0x63, 0x00, 0x2e, 0x73, 0x74, 0x72,
0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x37, 0x00, 0x00, 0x00, 0x03, 0x4c, 0xff, 0x6f, 0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}

0 comments on commit 28d807f

Please sign in to comment.