Skip to content

Commit 29198e7

Browse files
author
Mateusz Zalega
committed
Support "sample" filter action
This change adds support for packet sampling using "psample" kernel module.
1 parent 378a404 commit 29198e7

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

filter.go

+23
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,29 @@ func NewPoliceAction() *PoliceAction {
329329
}
330330
}
331331

332+
type SampleAction struct {
333+
ActionAttrs
334+
Group uint32
335+
Rate uint32
336+
TruncSize uint32
337+
}
338+
339+
func (action *SampleAction) Type() string {
340+
return "sample"
341+
}
342+
343+
func (action *SampleAction) Attrs() *ActionAttrs {
344+
return &action.ActionAttrs
345+
}
346+
347+
func NewSampleAction() *SampleAction {
348+
return &SampleAction{
349+
ActionAttrs: ActionAttrs{
350+
Action: TC_ACT_PIPE,
351+
},
352+
}
353+
}
354+
332355
// MatchAll filters match all packets
333356
type MatchAll struct {
334357
FilterAttrs

filter_linux.go

+25
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,17 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
649649
aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
650650
aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
651651
aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
652+
case *SampleAction:
653+
table := attr.AddRtAttr(tabIndex, nil)
654+
tabIndex++
655+
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("sample"))
656+
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
657+
gen := nl.TcGen{}
658+
toTcGen(action.Attrs(), &gen)
659+
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PARMS, gen.Serialize())
660+
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_RATE, nl.Uint32Attr(action.Rate))
661+
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP, nl.Uint32Attr(action.Group))
662+
aopts.AddRtAttr(nl.TCA_ACT_SAMPLE_TRUNC_SIZE, nl.Uint32Attr(action.TruncSize))
652663
case *GenericAction:
653664
table := attr.AddRtAttr(tabIndex, nil)
654665
tabIndex++
@@ -709,6 +720,8 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
709720
action = &ConnmarkAction{}
710721
case "csum":
711722
action = &CsumAction{}
723+
case "sample":
724+
action = &SampleAction{}
712725
case "gact":
713726
action = &GenericAction{}
714727
case "tunnel_key":
@@ -800,6 +813,18 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
800813
toAttrs(&csum.TcGen, action.Attrs())
801814
action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags)
802815
}
816+
case "sample":
817+
switch adatum.Attr.Type {
818+
case nl.TCA_ACT_SAMPLE_PARMS:
819+
gen := *nl.DeserializeTcGen(adatum.Value)
820+
toAttrs(&gen, action.Attrs())
821+
case nl.TCA_ACT_SAMPLE_RATE:
822+
action.(*SampleAction).Rate = native.Uint32(adatum.Value[0:4])
823+
case nl.TCA_ACT_SAMPLE_PSAMPLE_GROUP:
824+
action.(*SampleAction).Group = native.Uint32(adatum.Value[0:4])
825+
case nl.TCA_ACT_SAMPLE_TRUNC_SIZE:
826+
action.(*SampleAction).TruncSize = native.Uint32(adatum.Value[0:4])
827+
}
803828
case "gact":
804829
switch adatum.Attr.Type {
805830
case nl.TCA_GACT_PARMS:

filter_test.go

+132
Original file line numberDiff line numberDiff line change
@@ -2162,3 +2162,135 @@ func TestFilterChainAddDel(t *testing.T) {
21622162
t.Fatal("Failed to remove qdisc")
21632163
}
21642164
}
2165+
2166+
func TestFilterSampleAddDel(t *testing.T) {
2167+
minKernelRequired(t, 4, 11)
2168+
if _, err := GenlFamilyGet("psample"); err != nil {
2169+
t.Skip("psample genetlink family unavailable - is CONFIG_PSAMPLE enabled?")
2170+
}
2171+
2172+
tearDown := setUpNetlinkTest(t)
2173+
defer tearDown()
2174+
if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
2175+
t.Fatal(err)
2176+
}
2177+
link, err := LinkByName("foo")
2178+
if err != nil {
2179+
t.Fatal(err)
2180+
}
2181+
if err := LinkSetUp(link); err != nil {
2182+
t.Fatal(err)
2183+
}
2184+
2185+
qdisc := &Ingress{
2186+
QdiscAttrs: QdiscAttrs{
2187+
LinkIndex: link.Attrs().Index,
2188+
Handle: MakeHandle(0xffff, 0),
2189+
Parent: HANDLE_INGRESS,
2190+
},
2191+
}
2192+
if err := QdiscAdd(qdisc); err != nil {
2193+
t.Fatal(err)
2194+
}
2195+
qdiscs, err := SafeQdiscList(link)
2196+
if err != nil {
2197+
t.Fatal(err)
2198+
}
2199+
2200+
found := false
2201+
for _, v := range qdiscs {
2202+
if _, ok := v.(*Ingress); ok {
2203+
found = true
2204+
break
2205+
}
2206+
}
2207+
if !found {
2208+
t.Fatal("Qdisc is the wrong type")
2209+
}
2210+
2211+
sample := NewSampleAction()
2212+
sample.Group = 7
2213+
sample.Rate = 12
2214+
sample.TruncSize = 200
2215+
2216+
classId := MakeHandle(1, 1)
2217+
filter := &MatchAll{
2218+
FilterAttrs: FilterAttrs{
2219+
LinkIndex: link.Attrs().Index,
2220+
Parent: MakeHandle(0xffff, 0),
2221+
Priority: 1,
2222+
Protocol: unix.ETH_P_ALL,
2223+
},
2224+
ClassId: classId,
2225+
Actions: []Action{
2226+
sample,
2227+
},
2228+
}
2229+
2230+
if err := FilterAdd(filter); err != nil {
2231+
t.Fatal(err)
2232+
}
2233+
2234+
filters, err := FilterList(link, MakeHandle(0xffff, 0))
2235+
if err != nil {
2236+
t.Fatal(err)
2237+
}
2238+
if len(filters) != 1 {
2239+
t.Fatal("Failed to add filter")
2240+
}
2241+
u32, ok := filters[0].(*MatchAll)
2242+
if !ok {
2243+
t.Fatal("Filter is the wrong type")
2244+
}
2245+
2246+
if len(u32.Actions) < 1 {
2247+
t.Fatalf("Too few Actions in filter")
2248+
}
2249+
if u32.ClassId != classId {
2250+
t.Fatalf("ClassId of the filter is the wrong value")
2251+
}
2252+
2253+
lsample, ok := u32.Actions[0].(*SampleAction)
2254+
if !ok {
2255+
t.Fatal("Unable to find sample action")
2256+
}
2257+
if lsample.Group != sample.Group {
2258+
t.Fatalf("Inconsistent sample action group")
2259+
}
2260+
if lsample.Rate != sample.Rate {
2261+
t.Fatalf("Inconsistent sample action rate")
2262+
}
2263+
if lsample.TruncSize != sample.TruncSize {
2264+
t.Fatalf("Inconsistent sample truncation size")
2265+
}
2266+
2267+
if err := FilterDel(filter); err != nil {
2268+
t.Fatal(err)
2269+
}
2270+
filters, err = FilterList(link, MakeHandle(0xffff, 0))
2271+
if err != nil {
2272+
t.Fatal(err)
2273+
}
2274+
if len(filters) != 0 {
2275+
t.Fatal("Failed to remove filter")
2276+
}
2277+
2278+
if err := QdiscDel(qdisc); err != nil {
2279+
t.Fatal(err)
2280+
}
2281+
qdiscs, err = SafeQdiscList(link)
2282+
if err != nil {
2283+
t.Fatal(err)
2284+
}
2285+
2286+
found = false
2287+
for _, v := range qdiscs {
2288+
if _, ok := v.(*Ingress); ok {
2289+
found = true
2290+
break
2291+
}
2292+
}
2293+
if found {
2294+
t.Fatal("Failed to remove qdisc")
2295+
}
2296+
}

nl/tc_linux.go

+11
Original file line numberDiff line numberDiff line change
@@ -1139,3 +1139,14 @@ func DeserializeTcSfqQoptV1(b []byte) *TcSfqQoptV1 {
11391139
func (x *TcSfqQoptV1) Serialize() []byte {
11401140
return (*(*[SizeofTcSfqQoptV1]byte)(unsafe.Pointer(x)))[:]
11411141
}
1142+
1143+
const (
1144+
TCA_ACT_SAMPLE_UNSPEC = iota
1145+
TCA_ACT_SAMPLE_TM
1146+
TCA_ACT_SAMPLE_PARMS
1147+
TCA_ACT_SAMPLE_RATE
1148+
TCA_ACT_SAMPLE_TRUNC_SIZE
1149+
TCA_ACT_SAMPLE_PSAMPLE_GROUP
1150+
TCA_ACT_SAMPLE_PAD
1151+
TCA_ACT_SAMPLE_MAX
1152+
)

0 commit comments

Comments
 (0)