From 1882fa99fc5adc217f354c6f37a172876877f77d Mon Sep 17 00:00:00 2001 From: Sargun Dhillon Date: Wed, 27 Dec 2017 02:00:08 -0800 Subject: [PATCH] Add Matchall filter --- filter.go | 15 ++++++++ filter_linux.go | 37 +++++++++++++++++++ filter_test.go | 97 ++++++++++++++++++++++++++++++++++++++++++++----- nl/tc_linux.go | 7 ++++ 4 files changed, 146 insertions(+), 10 deletions(-) diff --git a/filter.go b/filter.go index 30b5414..c2cf8e4 100644 --- a/filter.go +++ b/filter.go @@ -225,6 +225,21 @@ func (filter *U32) Type() string { return "u32" } +// MatchAll filters match all packets +type MatchAll struct { + FilterAttrs + ClassId uint32 + Actions []Action +} + +func (filter *MatchAll) Attrs() *FilterAttrs { + return &filter.FilterAttrs +} + +func (filter *MatchAll) Type() string { + return "matchall" +} + type FilterFwAttrs struct { ClassId uint32 InDev string diff --git a/filter_linux.go b/filter_linux.go index 7cb7a4f..f0eac6b 100644 --- a/filter_linux.go +++ b/filter_linux.go @@ -222,6 +222,14 @@ func (h *Handle) FilterAdd(filter Filter) error { bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT } nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) + case *MatchAll: + actionsAttr := nl.NewRtAttrChild(options, nl.TCA_MATCHALL_ACT, nil) + if err := EncodeActions(actionsAttr, filter.Actions); err != nil { + return err + } + if filter.ClassId != 0 { + nl.NewRtAttrChild(options, nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId)) + } } req.AddData(options) @@ -288,6 +296,8 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { filter = &Fw{} case "bpf": filter = &BpfFilter{} + case "matchall": + filter = &MatchAll{} default: filter = &GenericFilter{FilterType: filterType} } @@ -312,6 +322,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { if err != nil { return nil, err } + case "matchall": + detailed, err = parseMatchAllData(filter, data) + if err != nil { + return nil, err + } default: detailed = true } @@ -541,6 +556,28 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) return detailed, nil } +func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { + native = nl.NativeEndian() + matchall := filter.(*MatchAll) + detailed := true + for _, datum := range data { + switch datum.Attr.Type { + case nl.TCA_MATCHALL_CLASSID: + matchall.ClassId = native.Uint32(datum.Value[0:4]) + case nl.TCA_MATCHALL_ACT: + tables, err := nl.ParseRouteAttr(datum.Value) + if err != nil { + return detailed, err + } + matchall.Actions, err = parseActions(tables) + if err != nil { + return detailed, err + } + } + } + return detailed, nil +} + func AlignToAtm(size uint) uint { var linksize, cells int cells = int(size / nl.ATM_CELL_PAYLOAD) diff --git a/filter_test.go b/filter_test.go index cf160a7..eb184b8 100644 --- a/filter_test.go +++ b/filter_test.go @@ -168,13 +168,13 @@ func TestAdvancedFilterAddDel(t *testing.T) { } u32SelKeys := []TcU32Key{ - TcU32Key{ + { Mask: 0xff, Val: 80, Off: 20, OffMask: 0, }, - TcU32Key{ + { Mask: 0xffff, Val: 0x146ca, Off: 32, @@ -546,13 +546,11 @@ func TestFilterU32BpfAddDel(t *testing.T) { } } -func TestFilterClsActBpfAddDel(t *testing.T) { - tearDown := setUpNetlinkTest(t) - defer tearDown() - if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil { +func setupLinkForTestWithQdisc(t *testing.T, linkName string) (Qdisc, Link) { + if err := LinkAdd(&Ifb{LinkAttrs{Name: linkName}}); err != nil { t.Fatal(err) } - link, err := LinkByName("foo") + link, err := LinkByName(linkName) if err != nil { t.Fatal(err) } @@ -568,8 +566,6 @@ func TestFilterClsActBpfAddDel(t *testing.T) { QdiscAttrs: attrs, QdiscType: "clsact", } - // This feature was added in kernel 4.5 - minKernelRequired(t, 4, 5) if err := QdiscAdd(qdisc); err != nil { t.Fatal(err) @@ -584,7 +580,17 @@ func TestFilterClsActBpfAddDel(t *testing.T) { if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" { t.Fatal("qdisc is the wrong type") } + return qdiscs[0], link +} +func TestFilterClsActBpfAddDel(t *testing.T) { + // This feature was added in kernel 4.5 + minKernelRequired(t, 4, 5) + + tearDown := setUpNetlinkTest(t) + defer tearDown() + + qdisc, link := setupLinkForTestWithQdisc(t, "foo") filterattrs := FilterAttrs{ LinkIndex: link.Attrs().Index, Parent: HANDLE_MIN_EGRESS, @@ -643,7 +649,7 @@ func TestFilterClsActBpfAddDel(t *testing.T) { if err := QdiscDel(qdisc); err != nil { t.Fatal(err) } - qdiscs, err = SafeQdiscList(link) + qdiscs, err := SafeQdiscList(link) if err != nil { t.Fatal(err) } @@ -651,3 +657,74 @@ func TestFilterClsActBpfAddDel(t *testing.T) { t.Fatal("Failed to remove qdisc") } } + +func TestFilterMatchAllAddDel(t *testing.T) { + // This classifier was added in kernel 4.7 + minKernelRequired(t, 4, 7) + + tearDown := setUpNetlinkTest(t) + defer tearDown() + _, link := setupLinkForTestWithQdisc(t, "foo") + _, link2 := setupLinkForTestWithQdisc(t, "bar") + filter := &MatchAll{ + FilterAttrs: FilterAttrs{ + LinkIndex: link.Attrs().Index, + Parent: HANDLE_MIN_EGRESS, + Priority: 32000, + Protocol: unix.ETH_P_ALL, + }, + Actions: []Action{ + &MirredAction{ + ActionAttrs: ActionAttrs{ + Action: TC_ACT_STOLEN, + }, + MirredAction: TCA_EGRESS_REDIR, + Ifindex: link2.Attrs().Index, + }, + }, + } + 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") + } + matchall, ok := filters[0].(*MatchAll) + if !ok { + t.Fatal("Filter is the wrong type") + } + + if matchall.Priority != 32000 { + t.Fatal("Filter priority does not match") + } + + if len(matchall.Actions) != 1 { + t.Fatal("Filter has no actions") + } + + mirredAction, ok := matchall.Actions[0].(*MirredAction) + if !ok { + t.Fatal("Action does not match") + } + + if mirredAction.Ifindex != link2.Attrs().Index { + t.Fatal("Action ifindex 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") + } + +} diff --git a/nl/tc_linux.go b/nl/tc_linux.go index e91fb21..05a975f 100644 --- a/nl/tc_linux.go +++ b/nl/tc_linux.go @@ -673,3 +673,10 @@ const ( TCA_FW_MASK TCA_FW_MAX = TCA_FW_MASK ) + +const ( + TCA_MATCHALL_UNSPEC = iota + TCA_MATCHALL_CLASSID + TCA_MATCHALL_ACT + TCA_MATCHALL_FLAGS +)