//go:build linux package tc import ( "context" "net" "os" "testing" "github.com/stretchr/testify/assert" "github.com/vishvananda/netlink" "github.com/vishvananda/netns" "golang.org/x/sys/unix" "edge-infra.dev/pkg/lib/kernel/netlink/ip" testnetns "edge-infra.dev/pkg/lib/kernel/netlink/netns" "edge-infra.dev/test/f2" ) var ( ipFilter = net.ParseIP("192.168.1.1") maskFilter = net.ParseIP("255.255.255.255") major uint16 = 0x1 minor uint16 = 0x2 priority uint32 = 1 rate uint64 = 4e+6 // 4mbit/s replaceRate uint64 = 10e+6 // 10mbit/s ) var f f2.Framework func TestMain(m *testing.M) { f = f2.New(context.Background(), f2.WithExtensions()). Setup(). Teardown() os.Exit(f.Run(m)) } func TestLinuxTrafficControl(t *testing.T) { var tearDownFunction func() var ns netns.NsHandle var link netlink.Link feature := f2.NewFeature("traffic control"). Setup("setup testing namespace", func(ctx f2.Context, t *testing.T) f2.Context { // until we figure out how to test with kernel modules installed these tests will be skipped ns, tearDownFunction = testnetns.NewTestingNetworkNamespace(t) assert.NoError(t, testnetns.CreateDummyLink()) dummyLink, err := testnetns.GetDummyLink() assert.NoError(t, err) link = dummyLink return ctx }). Test("create qdisc", func(ctx f2.Context, t *testing.T) f2.Context { assert.NoError(t, netns.Set(ns)) htbAttrs := NewQdiscAttrs().WithMakeHandle(major, 0x0).WithLinkIndex(link.Attrs().Index).WithParent(netlink.HANDLE_ROOT).Build() qdisc := NewHtb().WithAttrs(htbAttrs).WithDefaultClass(uint32(minor)).WithRate2Quantum(1500) assert.NoError(t, qdisc.Add()) return ctx }). Test("create class", func(ctx f2.Context, t *testing.T) f2.Context { assert.NoError(t, netns.Set(ns)) classAttrs := NewClassAttrs().WithLinkIndex(link.Attrs().Index).WithMakeHandle(minor, major).WithParent(netlink.HANDLE_ROOT).Build() class := NewClass().WithAttrs(classAttrs).WithRateLimit(rate).WithPriority(priority) assert.NoError(t, class.Add()) class = NewClass().WithAttrs(classAttrs).WithRateLimit(replaceRate).WithPriority(priority) assert.NoError(t, class.Replace()) return ctx }). Test("create filter", func(ctx f2.Context, t *testing.T) f2.Context { filterAttrs := NewFilterAttrs().WithLinkIndex(link.Attrs().Index).WithMakeParent(major, 0x0).WithProtocol(unix.ETH_P_IP).WithPriority(uint16(priority)).WithMakeHandle(major, minor).Build() /* #nosec G115 */ matchIP := NewMatchIP().WithIPv4HeaderOffset(ip.DstAddressBitOffset).WithIP(&ipFilter).WithMask(&maskFilter) filter := NewU32Filter().WithAttrs(filterAttrs).WithMakeClassID(major, minor).WithMatchIP(matchIP).WithHashTable(uint32(major)) assert.NoError(t, filter.Replace()) return ctx }). Teardown("teardown testing namespace", func(ctx f2.Context, _ *testing.T) f2.Context { tearDownFunction() return ctx }).Feature() f.Test(t, feature) }