From d3b8a16e9b459ca8e294ba31b3e93bc96cd6f6bd Mon Sep 17 00:00:00 2001 From: chengzhycn Date: Sat, 24 Sep 2022 13:51:26 +0800 Subject: [PATCH] add actions support for fwfilter Signed-off-by: chengzhycn --- filter.go | 1 + filter_linux.go | 13 +++++ filter_test.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/filter.go b/filter.go index 900a173..a71beb4 100644 --- a/filter.go +++ b/filter.go @@ -349,6 +349,7 @@ type FwFilter struct { InDev string Mask uint32 Police *PoliceAction + Actions []Action } func (filter *FwFilter) Attrs() *FilterAttrs { diff --git a/filter_linux.go b/filter_linux.go index e626bc6..6239001 100644 --- a/filter_linux.go +++ b/filter_linux.go @@ -312,6 +312,10 @@ func (h *Handle) filterModify(filter Filter, flags int) error { native.PutUint32(b, filter.ClassId) options.AddRtAttr(nl.TCA_FW_CLASSID, b) } + actionsAttr := options.AddRtAttr(nl.TCA_FW_ACT, nil) + if err := EncodeActions(actionsAttr, filter.Actions); err != nil { + return err + } case *BpfFilter: var bpfFlags uint32 if filter.ClassId != 0 { @@ -861,6 +865,15 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) { parsePolice(aattr, &police) } fw.Police = &police + case nl.TCA_FW_ACT: + tables, err := nl.ParseRouteAttr(datum.Value) + if err != nil { + return detailed, err + } + fw.Actions, err = parseActions(tables) + if err != nil { + return detailed, err + } } } return detailed, nil diff --git a/filter_test.go b/filter_test.go index c1e79dc..142ea51 100644 --- a/filter_test.go +++ b/filter_test.go @@ -510,6 +510,135 @@ func TestFilterFwAddDel(t *testing.T) { } } +func TestFilterFwActAddDel(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 := SafeQdiscList(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") + } + + classId := MakeHandle(1, 1) + filter := &FwFilter{ + FilterAttrs: FilterAttrs{ + LinkIndex: link.Attrs().Index, + Parent: MakeHandle(0xffff, 0), + Priority: 1, + Protocol: unix.ETH_P_ALL, + Handle: MakeHandle(0, 0x6), + }, + ClassId: classId, + Actions: []Action{ + &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") + } + fw, ok := filters[0].(*FwFilter) + if !ok { + t.Fatal("Filter is the wrong type") + } + + if len(fw.Actions) != 1 { + t.Fatalf("Too few Actions in filter") + } + if fw.ClassId != classId { + t.Fatalf("ClassId of the filter is the wrong value") + } + + mia, ok := fw.Actions[0].(*MirredAction) + if !ok { + t.Fatal("Unable to find mirred action") + } + + if mia.Attrs().Action != TC_ACT_STOLEN { + t.Fatal("Mirred action isn't TC_ACT_STOLEN") + } + + if mia.MirredAction != TCA_EGRESS_REDIR { + t.Fatal("MirredAction isn't TCA_EGRESS_REDIR") + } + + if mia.Ifindex != redir.Attrs().Index { + t.Fatal("Unmatched redirect index") + } + + 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 = SafeQdiscList(link) + if err != nil { + t.Fatal(err) + } + if len(qdiscs) != 0 { + t.Fatal("Failed to remove qdisc") + } +} + func TestFilterU32BpfAddDel(t *testing.T) { t.Skipf("Fd does not match in ci") tearDown := setUpNetlinkTest(t)