Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TC FLOWER enrich match field and action about vlan #1045

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
132 changes: 130 additions & 2 deletions 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,19 @@ 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_PUSH,
VlanID: 1234,
},
&MirredAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_STOLEN,
Expand Down Expand Up @@ -1871,8 +1888,31 @@ 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")
}

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

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

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

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

mia, ok := flower.Actions[1].(*MirredAction)
if !ok {
t.Fatal("Unable to find mirred action")
}
Expand All @@ -1889,7 +1929,7 @@ func TestFilterFlowerAddDel(t *testing.T) {
t.Fatal("Incorrect mirred action stats")
}

ga, ok := flower.Actions[1].(*GenericAction)
ga, ok := flower.Actions[2].(*GenericAction)
if !ok {
t.Fatal("Unable to find generic action")
}
Expand Down Expand Up @@ -1917,6 +1957,94 @@ 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{
&VlanAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
Action: TCA_VLAN_ACT_POP,
},
&MirredAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_STOLEN,
},
MirredAction: TCA_EGRESS_REDIR,
Ifindex: redir.Attrs().Index,
},
},
}

if err := FilterAdd(filter); err != nil {
t.Fatal(err)
}

time.Sleep(time.Second)
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")
}

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

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

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

mia, ok = flower.Actions[1].(*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.Timestamp == nil || mia.Timestamp.Installed == 0 {
t.Fatal("Incorrect mirred action timestamp")
}

if mia.Statistics == nil {
t.Fatal("Incorrect mirred action stats")
}

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
Loading