Skip to content

Commit

Permalink
tc actions
Browse files Browse the repository at this point in the history
Signed-off-by: Florian Lehner <dev@der-flo.net>
  • Loading branch information
florianl committed May 18, 2024
1 parent d584238 commit f0d60d6
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 22 deletions.
77 changes: 77 additions & 0 deletions actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package tc

import (
"github.com/florianl/go-tc/internal/unix"
"github.com/mdlayher/netlink"
)

// Actions represents the actions part of rtnetlink
type Actions struct {
Tc
}

// tcamsg is Actions specific
type tcaMsg struct {
family uint8
_ uint8 // pad1
_ uint16 // pad2
}

// Actions allows to read and alter actions
func (tc *Tc) Actions() *Actions {
return &Actions{*tc}
}

// Add creates a new actions
func (a *Actions) Add(info []*Action) error {
if len(info) == 0 {
return ErrNoArg
}
options, err := validateActionsObject(unix.RTM_NEWACTION, info)
if err != nil {
return err
}
return a.action(unix.RTM_NEWACTION, netlink.Create|netlink.Excl, tcaMsg{
family: unix.AF_UNSPEC,
}, options)
}

// Replace add/remove an actions. If the node does not exist yet it is created
func (a *Actions) Replace(info []*Action) error {
if len(info) == 0 {
return ErrNoArg
}
options, err := validateActionsObject(unix.RTM_NEWACTION, info)
if err != nil {
return err
}
return a.action(unix.RTM_NEWACTION, netlink.Create, tcaMsg{
family: unix.AF_UNSPEC,
}, options)
}

// Delete removes an actions
func (a *Actions) Delete(info []*Action) error {
if len(info) == 0 {
return ErrNoArg
}
options, err := validateActionsObject(unix.RTM_DELACTION, info)
if err != nil {
return err
}
return a.action(unix.RTM_DELACTION, netlink.HeaderFlags(0), tcaMsg{
family: unix.AF_UNSPEC,
}, options)
}

func validateActionsObject(cmd int, info []*Action) ([]tcOption, error) {
options := []tcOption{}

data, err := marshalActions(cmd, info)
if err != nil {
return options, err
}
options = append(options, tcOption{Interpretation: vtBytes, Type: 1 /*TCA_ROOT_TAB*/, Data: data})

return options, nil
}
50 changes: 50 additions & 0 deletions example_actions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//go:build linux
// +build linux

package tc_test

import (
"fmt"
"os"

"github.com/florianl/go-tc"
)

func ExampleActions() {
tcnl, err := tc.Open(&tc.Config{})
if err != nil {
fmt.Fprintf(os.Stderr, "could not open rtnetlink socket: %v\n", err)
return
}
defer func() {
if err := tcnl.Close(); err != nil {
fmt.Fprintf(os.Stderr, "could not close rtnetlink socket: %v\n", err)
}
}()

// Create a gact Actions.
if err := tcnl.Actions().Add([]*tc.Action{
{
Kind: "gact",
Gact: &tc.Gact{
Parms: &tc.GactParms{
Action: 2, // drop
},
},
},
}); err != nil {
fmt.Fprintf(os.Stderr, "failed to add actions: %v\n", err)
return
}

// Delete the gact Actions on Index 1.
if err := tcnl.Actions().Delete([]*tc.Action{
{
Kind: "gact",
Index: 1,
},
}); err != nil {
fmt.Fprintf(os.Stderr, "failed to delete gact actions: %v\n", err)
return
}
}
2 changes: 1 addition & 1 deletion f_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func marshalBasic(info *Basic) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaBasicPolice, Data: data})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaBasicAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_bpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func marshalBpf(info *Bpf) ([]byte, error) {
}
if info.Action != nil {
actions := []*Action{info.Action}
data, err := marshalActions(actions)
data, err := marshalActions(0, actions)
if err != nil {
return []byte{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion f_cgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func marshalCgroup(info *Cgroup) ([]byte, error) {
var multiError error
// TODO: improve logic and check combinations
if info.Action != nil {
data, err := marshalAction(info.Action, tcaActOptions)
data, err := marshalAction(0, info.Action, tcaActOptions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaCgroupAct, Data: data})

Expand Down
2 changes: 1 addition & 1 deletion f_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func marshalFlow(info *Flow) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaFlowEMatches, Data: data})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaFlowAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_flower.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ func marshalFlower(info *Flower) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtString, Type: tcaFlowerIndev, Data: *info.Indev})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaFlowerAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_fw.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func marshalFw(info *Fw) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaFwPolice, Data: data})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaFwAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_matchall.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func marshalMatchall(info *Matchall) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaMatchallClassID, Data: uint32Value(info.ClassID)})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaMatchallAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_route4.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func marshalRoute4(info *Route4) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaRoute4IIf, Data: uint32Value(info.IIf)})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
if err != nil {
return []byte{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion f_rsvp.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func marshalRsvp(info *Rsvp) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaRsvpPolice, Data: data})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaRsvpAct, Data: data})
}
Expand Down
2 changes: 1 addition & 1 deletion f_tcindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func marshalTcIndex(info *TcIndex) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaTcIndexClassID, Data: uint32Value(info.ClassID)})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
if err != nil {
return []byte{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion f_u32.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func marshalU32(info *U32) ([]byte, error) {
options = append(options, tcOption{Interpretation: vtUint32, Type: tcaU32Flags, Data: uint32Value(info.Flags)})
}
if info.Actions != nil {
data, err := marshalActions(*info.Actions)
data, err := marshalActions(0, *info.Actions)
multiError = concatError(multiError, err)
options = append(options, tcOption{Interpretation: vtBytes, Type: tcaU32Act, Data: data})
}
Expand Down
7 changes: 7 additions & 0 deletions internal/unix/types_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,10 @@ const (
RTM_DELCHAIN = linux.RTM_DELCHAIN
RTM_GETCHAIN = linux.RTM_GETCHAIN
)

// Make linter happy with this comment.
const (
RTM_NEWACTION = linux.RTM_NEWACTION
RTM_DELACTION = linux.RTM_DELACTION
RTM_GETACTION = linux.RTM_GETACTION
)
6 changes: 6 additions & 0 deletions internal/unix/types_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ const (
RTM_DELCHAIN = 101
RTM_GETCHAIN = 102
)

const (
RTM_NEWACTION = 48
RTM_DELACTION = 49
RTM_GETACTION = 50
)
39 changes: 31 additions & 8 deletions m_action.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package tc

import (
"errors"
"fmt"

"github.com/florianl/go-tc/internal/unix"
"github.com/mdlayher/netlink"
)

Expand All @@ -14,6 +16,10 @@ const (
tcaActStats
tcaActPad
tcaActCookie
tcaActFlags
tcaActHwStats
tcaActUsedHwStats
tcaActInHwCount
)

// Various action binding types.
Expand Down Expand Up @@ -41,10 +47,15 @@ const (

// Action represents action attributes of various filters and classes
type Action struct {
Kind string
Index uint32
Stats *GenStats
Cookie *[]byte
Kind string
Index uint32
Stats *GenStats
Cookie *[]byte
Flags *uint32 // 32-bit bitfield
HwStats *uint32 // 32-bit bitfield
UsedHwStats *uint32 // 32-bit bitfield
InHwCount *uint32

Bpf *ActBpf
ConnMark *Connmark
CSum *Csum
Expand Down Expand Up @@ -103,6 +114,18 @@ func unmarshalAction(data []byte, info *Action) error {
return err
}
info.Stats = stats
case tcaActFlags:
flags := ad.Uint32()
info.Flags = &flags
case tcaActHwStats:
hwStats := ad.Uint32()
info.HwStats = &hwStats
case tcaActUsedHwStats:
usedHwStats := ad.Uint32()
info.UsedHwStats = &usedHwStats
case tcaActInHwCount:
inHwCount := ad.Uint32()
info.InHwCount = &inHwCount
case tcaActPad:
// padding does not contain data, we just skip it
default:
Expand All @@ -118,11 +141,11 @@ func unmarshalAction(data []byte, info *Action) error {
return ad.Err()
}

func marshalActions(info []*Action) ([]byte, error) {
func marshalActions(cmd int, info []*Action) ([]byte, error) {
options := []tcOption{}

for i, action := range info {
data, err := marshalAction(action, tcaActOptions|nlaFNnested)
data, err := marshalAction(cmd, action, tcaActOptions|nlaFNnested)
if err != nil {
return []byte{}, err
}
Expand All @@ -133,7 +156,7 @@ func marshalActions(info []*Action) ([]byte, error) {
}

// marshalAction returns the binary encoding of Action
func marshalAction(info *Action, actOption uint16) ([]byte, error) {
func marshalAction(cmd int, info *Action, actOption uint16) ([]byte, error) {
options := []tcOption{}

if info == nil {
Expand Down Expand Up @@ -220,7 +243,7 @@ func marshalAction(info *Action, actOption uint16) ([]byte, error) {
}
options = append(options, tcOption{Interpretation: vtString, Type: tcaActKind, Data: info.Kind})

if multiError != nil {
if multiError != nil && !errors.Is(multiError, ErrNoArg) && cmd != unix.RTM_DELACTION {
return []byte{}, multiError
}

Expand Down
4 changes: 2 additions & 2 deletions m_action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestAction(t *testing.T) {

for name, testcase := range tests {
t.Run(name, func(t *testing.T) {
data, err1 := marshalActions([]*Action{&testcase.val})
data, err1 := marshalActions(0, []*Action{&testcase.val})
if err1 != nil {
if !errors.Is(testcase.err1, err1) {
return
Expand All @@ -122,7 +122,7 @@ func TestAction(t *testing.T) {
})
}
t.Run("nil", func(t *testing.T) {
_, err := marshalAction(nil, tcaActOptions)
_, err := marshalAction(0, nil, tcaActOptions)
if !errors.Is(err, ErrNoArg) {
t.Fatalf("unexpected error: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion tc.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (tc *Tc) query(req netlink.Message) ([]netlink.Message, error) {
return tc.con.Receive()
}

func (tc *Tc) action(action int, flags netlink.HeaderFlags, msg *Msg, opts []tcOption) error {
func (tc *Tc) action(action int, flags netlink.HeaderFlags, msg interface{}, opts []tcOption) error {
tcminfo, err := marshalStruct(msg)
if err != nil {
return err
Expand Down

0 comments on commit f0d60d6

Please sign in to comment.