mirror of
https://github.com/vishvananda/netlink
synced 2024-12-29 02:02:21 +00:00
fadc1088f6
* Add netlink definitions for extra IFLAs The relevant IFLA_* are defined in the kernel but not in the syscall package. * Parameterize the return value of loadSimpleBpf Allow the return value of the bpf program created by loadSimpleBpf to be specified by the caller. Before this, the value was hardcoded to 1. * Add support for a new IFLA that enables using a bpf program as a filter early in the driver path of some NICs. * Add a test for set/get of an xdp program. Since currently, the XDP IFLA is optional, check that the hardware supports it before trying to set the field. Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
473 lines
9.5 KiB
Go
473 lines
9.5 KiB
Go
package netlink
|
|
|
|
import (
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func TestFilterAddDel(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link, err := LinkByName("foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
redir, err := LinkByName("bar")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(redir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdisc := &Ingress{
|
|
QdiscAttrs: QdiscAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Handle: MakeHandle(0xffff, 0),
|
|
Parent: HANDLE_INGRESS,
|
|
},
|
|
}
|
|
if err := QdiscAdd(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err := QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 1 {
|
|
t.Fatal("Failed to add qdisc")
|
|
}
|
|
_, ok := qdiscs[0].(*Ingress)
|
|
if !ok {
|
|
t.Fatal("Qdisc is the wrong type")
|
|
}
|
|
filter := &U32{
|
|
FilterAttrs: FilterAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Parent: MakeHandle(0xffff, 0),
|
|
Priority: 1,
|
|
Protocol: syscall.ETH_P_IP,
|
|
},
|
|
RedirIndex: redir.Attrs().Index,
|
|
}
|
|
if err := FilterAdd(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 1 {
|
|
t.Fatal("Failed to add filter")
|
|
}
|
|
if err := FilterDel(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 0 {
|
|
t.Fatal("Failed to remove filter")
|
|
}
|
|
if err := QdiscDel(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err = QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 0 {
|
|
t.Fatal("Failed to remove qdisc")
|
|
}
|
|
}
|
|
|
|
func TestFilterFwAddDel(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link, err := LinkByName("foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
redir, err := LinkByName("bar")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(redir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
attrs := QdiscAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Handle: MakeHandle(0xffff, 0),
|
|
Parent: HANDLE_ROOT,
|
|
}
|
|
qdisc := NewHtb(attrs)
|
|
if err := QdiscAdd(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err := QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 1 {
|
|
t.Fatal("Failed to add qdisc")
|
|
}
|
|
_, ok := qdiscs[0].(*Htb)
|
|
if !ok {
|
|
t.Fatal("Qdisc is the wrong type")
|
|
}
|
|
|
|
classattrs := ClassAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Parent: MakeHandle(0xffff, 0),
|
|
Handle: MakeHandle(0xffff, 2),
|
|
}
|
|
|
|
htbclassattrs := HtbClassAttrs{
|
|
Rate: 1234000,
|
|
Cbuffer: 1690,
|
|
}
|
|
class := NewHtbClass(classattrs, htbclassattrs)
|
|
if err := ClassAdd(class); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
classes, err := ClassList(link, MakeHandle(0xffff, 2))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(classes) != 1 {
|
|
t.Fatal("Failed to add class")
|
|
}
|
|
|
|
filterattrs := FilterAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Parent: MakeHandle(0xffff, 0),
|
|
Handle: MakeHandle(0, 0x6),
|
|
Priority: 1,
|
|
Protocol: syscall.ETH_P_IP,
|
|
}
|
|
fwattrs := FilterFwAttrs{
|
|
Buffer: 12345,
|
|
Rate: 1234,
|
|
PeakRate: 2345,
|
|
Action: TC_POLICE_SHOT,
|
|
ClassId: MakeHandle(0xffff, 2),
|
|
}
|
|
|
|
filter, err := NewFw(filterattrs, fwattrs)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := FilterAdd(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 1 {
|
|
t.Fatal("Failed to add filter")
|
|
}
|
|
fw, ok := filters[0].(*Fw)
|
|
if !ok {
|
|
t.Fatal("Filter is the wrong type")
|
|
}
|
|
if fw.Police.Rate.Rate != filter.Police.Rate.Rate {
|
|
t.Fatal("Police Rate doesn't match")
|
|
}
|
|
for i := range fw.Rtab {
|
|
if fw.Rtab[i] != filter.Rtab[i] {
|
|
t.Fatal("Rtab doesn't match")
|
|
}
|
|
if fw.Ptab[i] != filter.Ptab[i] {
|
|
t.Fatal("Ptab doesn't match")
|
|
}
|
|
}
|
|
if fw.ClassId != filter.ClassId {
|
|
t.Fatal("ClassId doesn't match")
|
|
}
|
|
if fw.InDev != filter.InDev {
|
|
t.Fatal("InDev doesn't match")
|
|
}
|
|
if fw.AvRate != filter.AvRate {
|
|
t.Fatal("AvRate doesn't match")
|
|
}
|
|
|
|
if err := FilterDel(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 0 {
|
|
t.Fatal("Failed to remove filter")
|
|
}
|
|
if err := ClassDel(class); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
classes, err = ClassList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(classes) != 0 {
|
|
t.Fatal("Failed to remove class")
|
|
}
|
|
|
|
if err := QdiscDel(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err = QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 0 {
|
|
t.Fatal("Failed to remove qdisc")
|
|
}
|
|
}
|
|
|
|
func TestFilterU32BpfAddDel(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link, err := LinkByName("foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
redir, err := LinkByName("bar")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(redir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdisc := &Ingress{
|
|
QdiscAttrs: QdiscAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Handle: MakeHandle(0xffff, 0),
|
|
Parent: HANDLE_INGRESS,
|
|
},
|
|
}
|
|
if err := QdiscAdd(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err := QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 1 {
|
|
t.Fatal("Failed to add qdisc")
|
|
}
|
|
_, ok := qdiscs[0].(*Ingress)
|
|
if !ok {
|
|
t.Fatal("Qdisc is the wrong type")
|
|
}
|
|
|
|
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
|
|
if err != nil {
|
|
t.Skipf("Loading bpf program failed: %s", err)
|
|
}
|
|
filter := &U32{
|
|
FilterAttrs: FilterAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Parent: MakeHandle(0xffff, 0),
|
|
Priority: 1,
|
|
Protocol: syscall.ETH_P_ALL,
|
|
},
|
|
ClassId: MakeHandle(1, 1),
|
|
Actions: []Action{
|
|
&BpfAction{Fd: fd, Name: "simple"},
|
|
&MirredAction{
|
|
ActionAttrs: ActionAttrs{
|
|
Action: TC_ACT_STOLEN,
|
|
},
|
|
MirredAction: TCA_EGRESS_REDIR,
|
|
Ifindex: redir.Attrs().Index,
|
|
},
|
|
},
|
|
}
|
|
|
|
if err := FilterAdd(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
filters, err := FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 1 {
|
|
t.Fatal("Failed to add filter")
|
|
}
|
|
u32, ok := filters[0].(*U32)
|
|
if !ok {
|
|
t.Fatal("Filter is the wrong type")
|
|
}
|
|
|
|
if len(u32.Actions) != 2 {
|
|
t.Fatalf("Too few Actions in filter")
|
|
}
|
|
bpfAction, ok := u32.Actions[0].(*BpfAction)
|
|
if !ok {
|
|
t.Fatal("Action[0] is the wrong type")
|
|
}
|
|
if bpfAction.Fd != fd {
|
|
t.Fatal("Action Fd does not match")
|
|
}
|
|
if _, ok := u32.Actions[1].(*MirredAction); !ok {
|
|
t.Fatal("Action[1] is the wrong type")
|
|
}
|
|
|
|
if err := FilterDel(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters, err = FilterList(link, MakeHandle(0xffff, 0))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 0 {
|
|
t.Fatal("Failed to remove filter")
|
|
}
|
|
|
|
if err := QdiscDel(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err = QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 0 {
|
|
t.Fatal("Failed to remove qdisc")
|
|
}
|
|
}
|
|
|
|
func TestFilterClsActBpfAddDel(t *testing.T) {
|
|
tearDown := setUpNetlinkTest(t)
|
|
defer tearDown()
|
|
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
link, err := LinkByName("foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := LinkSetUp(link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
attrs := QdiscAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Handle: MakeHandle(0xffff, 0),
|
|
Parent: HANDLE_CLSACT,
|
|
}
|
|
qdisc := &GenericQdisc{
|
|
QdiscAttrs: attrs,
|
|
QdiscType: "clsact",
|
|
}
|
|
// This feature was added in kernel 4.5
|
|
if err := QdiscAdd(qdisc); err != nil {
|
|
t.Skipf("Failed adding clsact qdisc, unsupported kernel")
|
|
}
|
|
qdiscs, err := QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 1 {
|
|
t.Fatal("Failed to add qdisc")
|
|
}
|
|
if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" {
|
|
t.Fatal("qdisc is the wrong type")
|
|
}
|
|
|
|
filterattrs := FilterAttrs{
|
|
LinkIndex: link.Attrs().Index,
|
|
Parent: HANDLE_MIN_EGRESS,
|
|
Handle: MakeHandle(0, 1),
|
|
Protocol: syscall.ETH_P_ALL,
|
|
Priority: 1,
|
|
}
|
|
fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
|
|
if err != nil {
|
|
t.Skipf("Loading bpf program failed: %s", err)
|
|
}
|
|
filter := &BpfFilter{
|
|
FilterAttrs: filterattrs,
|
|
Fd: fd,
|
|
Name: "simple",
|
|
DirectAction: true,
|
|
}
|
|
if filter.Fd < 0 {
|
|
t.Skipf("Failed to load bpf program")
|
|
}
|
|
|
|
if err := FilterAdd(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
filters, err := FilterList(link, HANDLE_MIN_EGRESS)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 1 {
|
|
t.Fatal("Failed to add filter")
|
|
}
|
|
bpf, ok := filters[0].(*BpfFilter)
|
|
if !ok {
|
|
t.Fatal("Filter is the wrong type")
|
|
}
|
|
|
|
if bpf.Fd != filter.Fd {
|
|
t.Fatal("Filter Fd does not match")
|
|
}
|
|
if bpf.DirectAction != filter.DirectAction {
|
|
t.Fatal("Filter DirectAction does not match")
|
|
}
|
|
|
|
if err := FilterDel(filter); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
filters, err = FilterList(link, HANDLE_MIN_EGRESS)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(filters) != 0 {
|
|
t.Fatal("Failed to remove filter")
|
|
}
|
|
|
|
if err := QdiscDel(qdisc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qdiscs, err = QdiscList(link)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(qdiscs) != 0 {
|
|
t.Fatal("Failed to remove qdisc")
|
|
}
|
|
}
|