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

Support TC "sample" filter action #1042

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
23 changes: 23 additions & 0 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,29 @@ func NewPoliceAction() *PoliceAction {
}
}

type SampleAction struct {
ActionAttrs
Group uint32
Rate uint32
TruncSize uint32
}

func (action *SampleAction) Type() string {
return "sample"
}

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

func NewSampleAction() *SampleAction {
return &SampleAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
}
}

// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs
Expand Down
25 changes: 25 additions & 0 deletions filter_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,17 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
case *SampleAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("sample"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen)
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PARMS, gen.Serialize())
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_RATE, nl.Uint32Attr(action.Rate))
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP, nl.Uint32Attr(action.Group))
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_TRUNC_SIZE, nl.Uint32Attr(action.TruncSize))
case *GenericAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
Expand Down Expand Up @@ -825,6 +836,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &ConnmarkAction{}
case "csum":
action = &CsumAction{}
case "sample":
action = &SampleAction{}
case "gact":
action = &GenericAction{}
case "vlan":
Expand Down Expand Up @@ -949,6 +962,18 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
tcTs := nl.DeserializeTcf(adatum.Value)
actionTimestamp = toTimeStamp(tcTs)
}
case "sample":
switch adatum.Attr.Type {
case nl.TCA_ACT_SAMPLE_PARMS:
gen := *nl.DeserializeTcGen(adatum.Value)
toAttrs(&gen, action.Attrs())
case nl.TCA_ACT_SAMPLE_RATE:
action.(*SampleAction).Rate = native.Uint32(adatum.Value[0:4])
case nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP:
action.(*SampleAction).Group = native.Uint32(adatum.Value[0:4])
case nl.TCA_ACT_SAMPLE_TRUNC_SIZE:
action.(*SampleAction).TruncSize = native.Uint32(adatum.Value[0:4])
}
case "gact":
switch adatum.Attr.Type {
case nl.TCA_GACT_PARMS:
Expand Down
132 changes: 132 additions & 0 deletions filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2599,3 +2599,135 @@ func TestFilterChainAddDel(t *testing.T) {
t.Fatal("Failed to remove qdisc")
}
}

func TestFilterSampleAddDel(t *testing.T) {
minKernelRequired(t, 4, 11)
if _, err := GenlFamilyGet("psample"); err != nil {
t.Skip("psample genetlink family unavailable - is CONFIG_PSAMPLE enabled?")
}

tearDown := setUpNetlinkTest(t)
defer tearDown()
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if err := LinkSetUp(link); 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")
}

sample := NewSampleAction()
sample.Group = 7
sample.Rate = 12
sample.TruncSize = 200

classId := MakeHandle(1, 1)
filter := &MatchAll{
FilterAttrs: FilterAttrs{
LinkIndex: link.Attrs().Index,
Parent: MakeHandle(0xffff, 0),
Priority: 1,
Protocol: unix.ETH_P_ALL,
},
ClassId: classId,
Actions: []Action{
sample,
},
}

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")
}
mf, ok := filters[0].(*MatchAll)
if !ok {
t.Fatal("Filter is the wrong type")
}

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

lsample, ok := mf.Actions[0].(*SampleAction)
if !ok {
t.Fatal("Unable to find sample action")
}
if lsample.Group != sample.Group {
t.Fatalf("Inconsistent sample action group")
}
if lsample.Rate != sample.Rate {
t.Fatalf("Inconsistent sample action rate")
}
if lsample.TruncSize != sample.TruncSize {
t.Fatalf("Inconsistent sample truncation size")
}

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")
}
}
11 changes: 11 additions & 0 deletions nl/tc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ const (
TCA_ACT_MAX
)

const (
TCA_ACT_SAMPLE_UNSPEC = iota
TCA_ACT_SAMPLE_TM
TCA_ACT_SAMPLE_PARMS
TCA_ACT_SAMPLE_RATE
TCA_ACT_SAMPLE_TRUNC_SIZE
TCA_ACT_SAMPLE_PSAMPLE_GROUP
TCA_ACT_SAMPLE_PAD
TCA_ACT_SAMPLE_MAX
)

const (
TCA_PRIO_UNSPEC = iota
TCA_PRIO_MQ
Expand Down