diff --git a/filter_linux.go b/filter_linux.go index 4c6d1cf7..1d820d19 100644 --- a/filter_linux.go +++ b/filter_linux.go @@ -64,6 +64,9 @@ type Flower struct { EncSrcIPMask net.IPMask EncDestPort uint16 EncKeyId uint32 + SrcMac net.HardwareAddr + DestMac net.HardwareAddr + VlanId uint16 Actions []Action } @@ -129,6 +132,15 @@ func (filter *Flower) encode(parent *nl.RtAttr) error { if filter.EncKeyId != 0 { parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_KEY_ID, htonl(filter.EncKeyId)) } + if filter.SrcMac != nil { + parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_SRC, []byte(filter.SrcMac)) + } + if filter.DestMac != nil { + parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_DST, []byte(filter.DestMac)) + } + if filter.VlanId != 0 { + parent.AddRtAttr(nl.TCA_FLOWER_KEY_VLAN_ID, nl.Uint16Attr(filter.VlanId)) + } actionsAttr := parent.AddRtAttr(nl.TCA_FLOWER_ACT, nil) if err := EncodeActions(actionsAttr, filter.Actions); err != nil { @@ -162,6 +174,12 @@ func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error { filter.EncDestPort = ntohs(datum.Value) case nl.TCA_FLOWER_KEY_ENC_KEY_ID: filter.EncKeyId = ntohl(datum.Value) + case nl.TCA_FLOWER_KEY_ETH_SRC: + filter.SrcMac = net.HardwareAddr(datum.Value) + case nl.TCA_FLOWER_KEY_ETH_DST: + filter.DestMac = net.HardwareAddr(datum.Value) + case nl.TCA_FLOWER_KEY_VLAN_ID: + filter.VlanId = native.Uint16(datum.Value[0:2]) case nl.TCA_FLOWER_ACT: tables, err := nl.ParseRouteAttr(datum.Value) if err != nil { diff --git a/filter_test.go b/filter_test.go index 06016c56..d976be34 100644 --- a/filter_test.go +++ b/filter_test.go @@ -1635,6 +1635,14 @@ func TestFilterFlowerAddDel(t *testing.T) { } testMask := net.CIDRMask(24, 32) + srcMac, err := net.ParseMAC("2C:54:91:88:C9:E3") + if err != nil { + t.Fatal(err) + } + destMac, err := net.ParseMAC("2C:54:91:88:C9:E5") + if err != nil { + t.Fatal(err) + } filter := &Flower{ FilterAttrs: FilterAttrs{ @@ -1654,6 +1662,8 @@ func TestFilterFlowerAddDel(t *testing.T) { EncSrcIPMask: testMask, EncDestPort: 8472, EncKeyId: 1234, + SrcMac: srcMac, + DestMac: destMac, Actions: []Action{ &MirredAction{ ActionAttrs: ActionAttrs{ @@ -1716,6 +1726,12 @@ func TestFilterFlowerAddDel(t *testing.T) { if filter.EncDestPort != flower.EncDestPort { t.Fatalf("Flower EncDestPort doesn't match") } + if !(filter.SrcMac.String() == flower.SrcMac.String()) { + t.Fatalf("Flower SrcMac doesn't match") + } + if !(filter.DestMac.String() == flower.DestMac.String()) { + t.Fatalf("Flower DestMac doesn't match") + } mia, ok := flower.Actions[0].(*MirredAction) if !ok { @@ -1737,6 +1753,57 @@ func TestFilterFlowerAddDel(t *testing.T) { t.Fatal("Failed to remove filter") } + filter = &Flower{ + FilterAttrs: FilterAttrs{ + LinkIndex: link.Attrs().Index, + Parent: MakeHandle(0xffff, 0), + Priority: 1, + Protocol: unix.ETH_P_8021Q, + }, + EthType: unix.ETH_P_8021Q, + VlanId: 2046, + 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") + } + flower, ok = filters[0].(*Flower) + if !ok { + t.Fatal("Filter is the wrong type") + } + + if filter.VlanId != flower.VlanId { + t.Fatalf("Flower VlanId 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 := QdiscDel(qdisc); err != nil { t.Fatal(err) }