1 package features
2
3 import (
4 "errors"
5 "fmt"
6 "math"
7 "os"
8 "testing"
9
10 "github.com/cilium/ebpf"
11 "github.com/cilium/ebpf/asm"
12 "github.com/cilium/ebpf/internal"
13 "github.com/cilium/ebpf/internal/testutils"
14 )
15
16 var progTypeMinVersion = map[ebpf.ProgramType]string{
17 ebpf.SocketFilter: "3.19",
18 ebpf.Kprobe: "4.1",
19 ebpf.SchedCLS: "4.1",
20 ebpf.SchedACT: "4.1",
21 ebpf.TracePoint: "4.7",
22 ebpf.XDP: "4.8",
23 ebpf.PerfEvent: "4.9",
24 ebpf.CGroupSKB: "4.10",
25 ebpf.CGroupSock: "4.10",
26 ebpf.LWTIn: "4.10",
27 ebpf.LWTOut: "4.10",
28 ebpf.LWTXmit: "4.10",
29 ebpf.SockOps: "4.13",
30 ebpf.SkSKB: "4.14",
31 ebpf.CGroupDevice: "4.15",
32 ebpf.SkMsg: "4.17",
33 ebpf.RawTracepoint: "4.17",
34 ebpf.CGroupSockAddr: "4.17",
35 ebpf.LWTSeg6Local: "4.18",
36 ebpf.LircMode2: "4.18",
37 ebpf.SkReuseport: "4.19",
38 ebpf.FlowDissector: "4.20",
39 ebpf.CGroupSysctl: "5.2",
40 ebpf.RawTracepointWritable: "5.2",
41 ebpf.CGroupSockopt: "5.3",
42 ebpf.Tracing: "5.5",
43 ebpf.StructOps: "5.6",
44 ebpf.Extension: "5.6",
45 ebpf.LSM: "5.7",
46 ebpf.SkLookup: "5.9",
47 ebpf.Syscall: "5.14",
48 }
49
50 func TestHaveProgramType(t *testing.T) {
51 for progType := ebpf.UnspecifiedProgram + 1; progType <= progType.Max(); progType++ {
52
53 pt := progType
54
55 minVersion, ok := progTypeMinVersion[pt]
56 if !ok {
57
58
59 minVersion = "0.0"
60 }
61
62 feature := fmt.Sprintf("program type %s", pt.String())
63
64 t.Run(pt.String(), func(t *testing.T) {
65 t.Parallel()
66
67 if progLoadProbeNotImplemented(pt) {
68 t.Skipf("Test for prog type %s requires working probe", pt.String())
69 }
70 testutils.SkipOnOldKernel(t, minVersion, feature)
71
72 if err := HaveProgramType(pt); err != nil {
73 if pt == ebpf.LircMode2 {
74
75
76
77 testutils.SkipIfNotSupported(t, err)
78 }
79
80 t.Fatalf("Program type %s isn't supported even though kernel is at least %s: %v", pt.String(), minVersion, err)
81 }
82 })
83
84 }
85 }
86
87 func TestHaveProgramTypeUnsupported(t *testing.T) {
88 if err := haveProgramType(ebpf.ProgramType(math.MaxUint32)); err != ebpf.ErrNotSupported {
89 t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
90 }
91 }
92
93 func TestHaveProgramTypeInvalid(t *testing.T) {
94 if err := HaveProgramType(ebpf.ProgramType(math.MaxUint32)); err != os.ErrInvalid {
95 t.Fatalf("Expected os.ErrInvalid but was: %v", err)
96 }
97 }
98
99 func TestHaveProgramHelper(t *testing.T) {
100 type testCase struct {
101 prog ebpf.ProgramType
102 helper asm.BuiltinFunc
103 expected error
104 version string
105 }
106
107
108
109
110
111
112
113
114
115
116 testCases := []testCase{
117 {ebpf.Kprobe, asm.FnMapLookupElem, nil, "3.19"},
118 {ebpf.SocketFilter, asm.FnKtimeGetCoarseNs, nil, "5.11"},
119 {ebpf.SchedCLS, asm.FnSkbVlanPush, nil, "4.3"},
120 {ebpf.Kprobe, asm.FnSkbVlanPush, ebpf.ErrNotSupported, "4.3"},
121 {ebpf.Kprobe, asm.FnSysBpf, ebpf.ErrNotSupported, "5.14"},
122 {ebpf.Syscall, asm.FnSysBpf, nil, "5.14"},
123 {ebpf.XDP, asm.FnJiffies64, nil, "5.5"},
124 {ebpf.XDP, asm.FnKtimeGetBootNs, nil, "5.7"},
125 {ebpf.SchedCLS, asm.FnSkbChangeHead, nil, "5.8"},
126 {ebpf.SchedCLS, asm.FnRedirectNeigh, nil, "5.10"},
127 {ebpf.SchedCLS, asm.FnSkbEcnSetCe, nil, "5.1"},
128 {ebpf.SchedACT, asm.FnSkAssign, nil, "5.6"},
129 {ebpf.SchedACT, asm.FnFibLookup, nil, "4.18"},
130 {ebpf.Kprobe, asm.FnFibLookup, ebpf.ErrNotSupported, "4.18"},
131 {ebpf.CGroupSockAddr, asm.FnGetsockopt, nil, "5.8"},
132 {ebpf.CGroupSockAddr, asm.FnSkLookupTcp, nil, "4.20"},
133 {ebpf.CGroupSockAddr, asm.FnGetNetnsCookie, nil, "5.7"},
134 {ebpf.CGroupSock, asm.FnGetNetnsCookie, nil, "5.7"},
135 }
136
137 for _, tc := range testCases {
138 minVersion := progTypeMinVersion[tc.prog]
139
140 progVersion, err := internal.NewVersion(minVersion)
141 if err != nil {
142 t.Fatalf("Could not read kernel version required for program: %v", err)
143 }
144
145 helperVersion, err := internal.NewVersion(tc.version)
146 if err != nil {
147 t.Fatalf("Could not read kernel version required for helper: %v", err)
148 }
149
150 if progVersion.Less(helperVersion) {
151 minVersion = tc.version
152 }
153
154 t.Run(fmt.Sprintf("%s/%s", tc.prog.String(), tc.helper.String()), func(t *testing.T) {
155 feature := fmt.Sprintf("helper %s for program type %s", tc.helper.String(), tc.prog.String())
156
157 testutils.SkipOnOldKernel(t, minVersion, feature)
158
159 err := HaveProgramHelper(tc.prog, tc.helper)
160 if !errors.Is(err, tc.expected) {
161 t.Fatalf("%s/%s: %v", tc.prog.String(), tc.helper.String(), err)
162 }
163
164 })
165
166 }
167 }
168
169 func TestHaveProgramHelperUnsupported(t *testing.T) {
170 pt := ebpf.SocketFilter
171 minVersion := progTypeMinVersion[pt]
172
173 feature := fmt.Sprintf("program type %s", pt.String())
174
175 testutils.SkipOnOldKernel(t, minVersion, feature)
176
177 if err := haveProgramHelper(pt, asm.BuiltinFunc(math.MaxInt32)); err != ebpf.ErrNotSupported {
178 t.Fatalf("Expected ebpf.ErrNotSupported but was: %v", err)
179 }
180 }
181
View as plain text