filter, action: Add support for skbedit

Signed-off-by: Zhiyuan Hou <zhiyuan2048@linux.alibaba.com>
This commit is contained in:
Zhiyuan Hou 2019-12-11 17:03:31 +08:00 committed by Alessandro Boch
parent e25c252266
commit ed8931371a
4 changed files with 266 additions and 0 deletions

View File

@ -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

View File

@ -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++
@ -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
}
@ -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:

View File

@ -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")
}
}

View File

@ -92,6 +92,7 @@ const (
SizeofTcConnmark = SizeofTcGen + 0x04
SizeofTcMirred = SizeofTcGen + 0x08
SizeofTcTunnelKey = SizeofTcGen + 0x04
SizeofTcSkbEdit = SizeofTcGen
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
)
@ -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;