...

Source file src/github.com/cilium/ebpf/features/prog_test.go

Documentation: github.com/cilium/ebpf/features

     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  		// 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  }
   181  

View as plain text