github.com/kubeshark/ebpf@v0.9.2/features/prog_test.go (about) 1 package features 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 "os" 8 "testing" 9 10 "github.com/kubeshark/ebpf" 11 "github.com/kubeshark/ebpf/asm" 12 "github.com/kubeshark/ebpf/internal" 13 "github.com/kubeshark/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 // Need inner loop copy to make use of t.Parallel() 53 pt := progType 54 55 minVersion, ok := progTypeMinVersion[pt] 56 if !ok { 57 // In cases where a new prog type wasn't added to progTypeMinVersion 58 // we should make sure the test runs anyway and fails on old kernels 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 // CI kernels are built with CONFIG_BPF_LIRC_MODE2, but some 75 // mainstream distro's don't ship with it. Make this prog type 76 // optional to retain compatibility with those kernels. 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 // Referencing linux kernel commits to track the kernel version required to pass these test cases. 108 // They cases are derived from libbpf's selftests and helper/prog combinations that are 109 // probed for in cilium/cilium. 110 // Still missing since those helpers are not available in the lib yet, are: 111 // - Kprobe, GetBranchSnapshot 112 // - SchedCLS, SkbSetTstamp 113 // These two test cases depend on CI kernels supporting those: 114 // {ebpf.Kprobe, asm.FnKtimeGetCoarseNs, ebpf.ErrNotSupported, "5.16"}, // 5e0bc3082e2e 115 // {ebpf.CGroupSockAddr, asm.FnGetCgroupClassid, nil, "5.10"}, // b426ce83baa7 116 testCases := []testCase{ 117 {ebpf.Kprobe, asm.FnMapLookupElem, nil, "3.19"}, // d0003ec01c66 118 {ebpf.SocketFilter, asm.FnKtimeGetCoarseNs, nil, "5.11"}, // d05512618056 119 {ebpf.SchedCLS, asm.FnSkbVlanPush, nil, "4.3"}, // 4e10df9a60d9 120 {ebpf.Kprobe, asm.FnSkbVlanPush, ebpf.ErrNotSupported, "4.3"}, // 4e10df9a60d9 121 {ebpf.Kprobe, asm.FnSysBpf, ebpf.ErrNotSupported, "5.14"}, // 79a7f8bdb159 122 {ebpf.Syscall, asm.FnSysBpf, nil, "5.14"}, // 79a7f8bdb159 123 {ebpf.XDP, asm.FnJiffies64, nil, "5.5"}, // 5576b991e9c1 124 {ebpf.XDP, asm.FnKtimeGetBootNs, nil, "5.7"}, // 71d19214776e 125 {ebpf.SchedCLS, asm.FnSkbChangeHead, nil, "5.8"}, // 6f3f65d80dac 126 {ebpf.SchedCLS, asm.FnRedirectNeigh, nil, "5.10"}, // b4ab31414970 127 {ebpf.SchedCLS, asm.FnSkbEcnSetCe, nil, "5.1"}, // f7c917ba11a6 128 {ebpf.SchedACT, asm.FnSkAssign, nil, "5.6"}, // cf7fbe660f2d 129 {ebpf.SchedACT, asm.FnFibLookup, nil, "4.18"}, // 87f5fc7e48dd 130 {ebpf.Kprobe, asm.FnFibLookup, ebpf.ErrNotSupported, "4.18"}, // 87f5fc7e48dd 131 {ebpf.CGroupSockAddr, asm.FnGetsockopt, nil, "5.8"}, // beecf11bc218 132 {ebpf.CGroupSockAddr, asm.FnSkLookupTcp, nil, "4.20"}, // 6acc9b432e67 133 {ebpf.CGroupSockAddr, asm.FnGetNetnsCookie, nil, "5.7"}, // f318903c0bf4 134 {ebpf.CGroupSock, asm.FnGetNetnsCookie, nil, "5.7"}, // f318903c0bf4 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 }