Skip to content

Commit

Permalink
filter, action: Add support for skbedit
Browse files Browse the repository at this point in the history
Signed-off-by: Zhiyuan Hou <[email protected]>
  • Loading branch information
zhiyuan0x authored and aboch committed Dec 17, 2019
1 parent e25c252 commit ed89313
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 0 deletions.
24 changes: 24 additions & 0 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,30 @@ func NewTunnelKeyAction() *TunnelKeyAction {
}
}

type SkbEditAction struct {
ActionAttrs
QueueMapping *uint16
PType *uint16
Priority *uint32
Mark *uint32
}

func (action *SkbEditAction) Type() string {
return "skbedit"
}

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

func NewSkbEditAction() *SkbEditAction {
return &SkbEditAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
}
}

// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs
Expand Down
41 changes: 41 additions & 0 deletions filter_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,26 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr)
}
}
case *SkbEditAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
skbedit := nl.TcSkbEdit{}
toTcGen(action.Attrs(), &skbedit.TcGen)
aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize())
if action.QueueMapping != nil {
aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping))
}
if action.Priority != nil {
aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority))
}
if action.PType != nil {
aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType))
}
if action.Mark != nil {
aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark))
}
case *ConnmarkAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
Expand Down Expand Up @@ -516,6 +536,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &GenericAction{}
case "tunnel_key":
action = &TunnelKeyAction{}
case "skbedit":
action = &SkbEditAction{}
default:
break nextattr
}
Expand Down Expand Up @@ -551,6 +573,25 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:])
}
case "skbedit":
switch adatum.Attr.Type {
case nl.TCA_SKBEDIT_PARMS:
skbedit := *nl.DeserializeSkbEdit(adatum.Value)
action.(*SkbEditAction).ActionAttrs = ActionAttrs{}
toAttrs(&skbedit.TcGen, action.Attrs())
case nl.TCA_SKBEDIT_MARK:
mark := native.Uint32(adatum.Value[0:4])
action.(*SkbEditAction).Mark = &mark
case nl.TCA_SKBEDIT_PRIORITY:
priority := native.Uint32(adatum.Value[0:4])
action.(*SkbEditAction).Priority = &priority
case nl.TCA_SKBEDIT_PTYPE:
ptype := native.Uint16(adatum.Value[0:2])
action.(*SkbEditAction).PType = &ptype
case nl.TCA_SKBEDIT_QUEUE_MAPPING:
mapping := native.Uint16(adatum.Value[0:2])
action.(*SkbEditAction).QueueMapping = &mapping
}
case "bpf":
switch adatum.Attr.Type {
case nl.TCA_ACT_BPF_PARMS:
Expand Down
172 changes: 172 additions & 0 deletions filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1134,3 +1134,175 @@ func TestFilterU32TunnelKeyAddDel(t *testing.T) {
t.Fatal("Failed to remove qdisc")
}
}

func TestFilterU32SkbEditAddDel(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)
}

found := false
for _, v := range qdiscs {
if _, ok := v.(*Ingress); ok {
found = true
break
}
}
if !found {
t.Fatal("Qdisc is the wrong type")
}

skbedit := NewSkbEditAction()
ptype := uint16(unix.PACKET_HOST)
skbedit.PType = &ptype
priority := uint32(0xff)
skbedit.Priority = &priority
mark := uint32(0xfe)
skbedit.Mark = &mark
mapping := uint16(0xf)
skbedit.QueueMapping = &mapping

classId := MakeHandle(1, 1)
filter := &U32{
FilterAttrs: FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Priority: 1,
Protocol: unix.ETH_P_ALL,
},
ClassId: classId,
Actions: []Action{
skbedit,
&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")
}
u32, ok := filters[0].(*U32)
if !ok {
t.Fatal("Filter is the wrong type")
}

if len(u32.Actions) != 2 {
t.Fatalf("Too few Actions in filter")
}
if u32.ClassId != classId {
t.Fatalf("ClassId of the filter is the wrong value")
}

// actions can be returned in reverse order
edit, ok := u32.Actions[0].(*SkbEditAction)
if !ok {
edit, ok = u32.Actions[1].(*SkbEditAction)
if !ok {
t.Fatal("Unable to find tunnel action")
}
}

if edit.Attrs().Action != TC_ACT_PIPE {
t.Fatal("SkbEdit action isn't TC_ACT_PIPE")
}
if edit.PType == nil || *edit.PType != *skbedit.PType {
t.Fatal("Action PType doesn't match")
}
if edit.QueueMapping == nil || *edit.QueueMapping != *skbedit.QueueMapping {
t.Fatal("Action QueueMapping doesn't match")
}
if edit.Mark == nil || *edit.Mark != *skbedit.Mark {
t.Fatal("Action Mark doesn't match")
}
if edit.Priority == nil || *edit.Priority != *skbedit.Priority {
t.Fatal("Action Priority doesn't match")
}

mia, ok := u32.Actions[0].(*MirredAction)
if !ok {
mia, ok = u32.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 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)
}

found = false
for _, v := range qdiscs {
if _, ok := v.(*Ingress); ok {
found = true
break
}
}
if found {
t.Fatal("Failed to remove qdisc")
}
}
29 changes: 29 additions & 0 deletions nl/tc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const (
SizeofTcConnmark = SizeofTcGen + 0x04
SizeofTcMirred = SizeofTcGen + 0x08
SizeofTcTunnelKey = SizeofTcGen + 0x04
SizeofTcSkbEdit = SizeofTcGen
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
)

Expand Down Expand Up @@ -754,6 +755,34 @@ func (x *TcTunnelKey) Serialize() []byte {
return (*(*[SizeofTcTunnelKey]byte)(unsafe.Pointer(x)))[:]
}

const (
TCA_SKBEDIT_UNSPEC = iota
TCA_SKBEDIT_TM
TCA_SKBEDIT_PARMS
TCA_SKBEDIT_PRIORITY
TCA_SKBEDIT_QUEUE_MAPPING
TCA_SKBEDIT_MARK
TCA_SKBEDIT_PAD
TCA_SKBEDIT_PTYPE
TCA_SKBEDIT_MAX = TCA_SKBEDIT_MARK
)

type TcSkbEdit struct {
TcGen
}

func (x *TcSkbEdit) Len() int {
return SizeofTcSkbEdit
}

func DeserializeSkbEdit(b []byte) *TcSkbEdit {
return (*TcSkbEdit)(unsafe.Pointer(&b[0:SizeofTcSkbEdit][0]))
}

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

// struct tc_police {
// __u32 index;
// int action;
Expand Down

0 comments on commit ed89313

Please sign in to comment.