Skip to content

Commit

Permalink
1. filter match support vlanId and srcMac, dstMac.
Browse files Browse the repository at this point in the history
2. filter action support vlan pop/push.
  • Loading branch information
wangling142 committed Nov 29, 2024
1 parent 976bd8d commit 2176e34
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 4 deletions.
29 changes: 29 additions & 0 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,35 @@ func NewCsumAction() *CsumAction {
}
}

type VlanAct int8

type VlanAction struct {
ActionAttrs
Action VlanAct
VlanID uint16
}

const (
TCA_VLAN_ACT_POP VlanAct = 1
TCA_VLAN_ACT_PUSH VlanAct = 2
)

func (action *VlanAction) Type() string {
return "vlan"
}

func (action *VlanAction) Attrs() *ActionAttrs {
return &action.ActionAttrs
}

func NewVlanAction() *VlanAction {
return &VlanAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
}
}

type MirredAct uint8

func (a MirredAct) String() string {
Expand Down
49 changes: 48 additions & 1 deletion filter_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ type Flower struct {
EncSrcIPMask net.IPMask
EncDestPort uint16
EncKeyId uint32
SrcMac net.HardwareAddr
DestMac net.HardwareAddr
VlanId uint16
SkipHw bool
SkipSw bool
IPProto *nl.IPProto
Expand Down Expand Up @@ -135,6 +138,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, filter.SrcMac)
}
if filter.DestMac != nil {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_DST, filter.DestMac)
}
if filter.VlanId != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_VLAN_ID, nl.Uint16Attr(filter.VlanId))
}
if filter.IPProto != nil {
ipproto := *filter.IPProto
parent.AddRtAttr(nl.TCA_FLOWER_KEY_IP_PROTO, ipproto.Serialize())
Expand Down Expand Up @@ -201,6 +213,13 @@ 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 = datum.Value
case nl.TCA_FLOWER_KEY_ETH_DST:
filter.DestMac = datum.Value
case nl.TCA_FLOWER_KEY_VLAN_ID:
filter.VlanId = native.Uint16(datum.Value[0:2])
filter.EthType = unix.ETH_P_8021Q
case nl.TCA_FLOWER_KEY_IP_PROTO:
val := new(nl.IPProto)
*val = nl.IPProto(datum.Value[0])
Expand Down Expand Up @@ -622,6 +641,22 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
}
toTcGen(action.Attrs(), &mirred.TcGen)
aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize())
case *VlanAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("vlan"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
vlan := nl.TcVlan{
Action: int32(action.Action),
}
toTcGen(action.Attrs(), &vlan.TcGen)
aopts.AddRtAttr(nl.TCA_VLAN_PARMS, vlan.Serialize())
if action.Action == TCA_VLAN_ACT_PUSH && action.VlanID == 0 {
return fmt.Errorf("vlan id is required for push action")
}
if action.VlanID != 0 {
aopts.AddRtAttr(nl.TCA_VLAN_PUSH_VLAN_ID, nl.Uint16Attr(action.VlanID))
}
case *TunnelKeyAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
Expand Down Expand Up @@ -792,6 +827,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &CsumAction{}
case "gact":
action = &GenericAction{}
case "vlan":
action = &VlanAction{}
case "tunnel_key":
action = &TunnelKeyAction{}
case "skbedit":
Expand Down Expand Up @@ -822,7 +859,17 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
tcTs := nl.DeserializeTcf(adatum.Value)
actionTimestamp = toTimeStamp(tcTs)
}

case "vlan":
switch adatum.Attr.Type {
case nl.TCA_VLAN_PARMS:
vlan := *nl.DeserializeTcVlan(adatum.Value)
action.(*VlanAction).ActionAttrs = ActionAttrs{}
toAttrs(&vlan.TcGen, action.Attrs())
action.(*VlanAction).Action = VlanAct(vlan.Action)
case nl.TCA_VLAN_PUSH_VLAN_ID:
vlanId := native.Uint16(adatum.Value[0:2])
action.(*VlanAction).VlanID = vlanId
}
case "tunnel_key":
switch adatum.Attr.Type {
case nl.TCA_TUNNEL_KEY_PARMS:
Expand Down
112 changes: 111 additions & 1 deletion filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,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)
}

ipproto := new(nl.IPProto)
*ipproto = nl.IPPROTO_TCP
Expand All @@ -1790,10 +1798,25 @@ func TestFilterFlowerAddDel(t *testing.T) {
EncSrcIPMask: testMask,
EncDestPort: 8472,
EncKeyId: 1234,
SrcMac: srcMac,
DestMac: destMac,
IPProto: ipproto,
DestPort: 1111,
SrcPort: 1111,
Actions: []Action{
&VlanAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
Action: TCA_VLAN_ACT_POP,
},
&VlanAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
Action: TCA_VLAN_ACT_PUSH,
VlanID: 1234,
},
&MirredAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_STOLEN,
Expand Down Expand Up @@ -1871,8 +1894,44 @@ func TestFilterFlowerAddDel(t *testing.T) {
if filter.SrcPort != flower.SrcPort {
t.Fatalf("Flower SrcPort 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")
}

va1, ok := flower.Actions[0].(*VlanAction)
if !ok {
t.Fatal("Unable to find vlan action")
}

mia, ok := flower.Actions[0].(*MirredAction)
if va1.Attrs().Action != TC_ACT_PIPE {
t.Fatal("Vlan action isn't TC_ACT_PIPE")
}

if va1.Action != TCA_VLAN_ACT_POP {
t.Fatal("First Vlan action isn't pop")
}

va2, ok := flower.Actions[1].(*VlanAction)
if !ok {
t.Fatal("Unable to find vlan action")
}

if va2.Attrs().Action != TC_ACT_PIPE {
t.Fatal("Vlan action isn't TC_ACT_PIPE")
}

if va2.Action != TCA_VLAN_ACT_PUSH {
t.Fatal("Second Vlan action isn't push")
}

if va2.VlanID != 1234 {
t.Fatal("Second Vlan action vlanId isn't correct")
}

mia, ok := flower.Actions[2].(*MirredAction)
if !ok {
t.Fatal("Unable to find mirred action")
}
Expand Down Expand Up @@ -1917,6 +1976,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)
}
Expand Down
40 changes: 38 additions & 2 deletions nl/tc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ const (
SizeofTcConnmark = SizeofTcGen + 0x04
SizeofTcCsum = SizeofTcGen + 0x04
SizeofTcMirred = SizeofTcGen + 0x08
SizeofTcVlan = SizeofTcGen + 0x04
SizeofTcTunnelKey = SizeofTcGen + 0x04
SizeofTcSkbEdit = SizeofTcGen
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
Expand Down Expand Up @@ -816,6 +817,41 @@ func (x *TcMirred) Serialize() []byte {
return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:]
}

const (
TCA_VLAN_UNSPEC = iota
TCA_VLAN_TM
TCA_VLAN_PARMS
TCA_VLAN_PUSH_VLAN_ID
TCA_VLAN_PUSH_VLAN_PROTOCOL
TCA_VLAN_PAD
TCA_VLAN_PUSH_VLAN_PRIORITY
TCA_VLAN_PUSH_ETH_DST
TCA_VLAN_PUSH_ETH_SRC
TCA_VLAN_MAX
)

//struct tc_vlan {
// tc_gen;
// int v_action;
//};

type TcVlan struct {
TcGen
Action int32
}

func (msg *TcVlan) Len() int {
return SizeofTcVlan
}

func DeserializeTcVlan(b []byte) *TcVlan {
return (*TcVlan)(unsafe.Pointer(&b[0:SizeofTcVlan][0]))
}

func (x *TcVlan) Serialize() []byte {
return (*(*[SizeofTcVlan]byte)(unsafe.Pointer(x)))[:]
}

const (
TCA_TUNNEL_KEY_UNSPEC = iota
TCA_TUNNEL_KEY_TM
Expand Down Expand Up @@ -1239,8 +1275,8 @@ const (
)

// /* TCA_PEDIT_KEY_EX_HDR_TYPE_NETWROK is a special case for legacy users. It
// * means no specific header type - offset is relative to the network layer
// */
// - means no specific header type - offset is relative to the network layer
// */
type PeditHeaderType uint16

const (
Expand Down

0 comments on commit 2176e34

Please sign in to comment.