github.com/cilium/cilium@v1.16.2/pkg/datapath/loader/tc_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package loader
     5  
     6  import (
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/cilium/ebpf"
    13  	"github.com/cilium/ebpf/asm"
    14  
    15  	"github.com/cilium/cilium/pkg/testutils"
    16  	"github.com/cilium/cilium/pkg/testutils/netns"
    17  )
    18  
    19  func newTCProgram() (*ebpf.Program, error) {
    20  	return ebpf.NewProgram(&ebpf.ProgramSpec{
    21  		Type: ebpf.SchedCLS,
    22  		Instructions: asm.Instructions{
    23  			asm.Mov.Imm(asm.R0, 0),
    24  			asm.Return(),
    25  		},
    26  		License: "Apache-2.0",
    27  	})
    28  }
    29  
    30  func mustTCProgram(tb testing.TB) *ebpf.Program {
    31  	p, err := newTCProgram()
    32  	if err != nil {
    33  		tb.Skipf("tc programs not supported: %s", err)
    34  	}
    35  	tb.Cleanup(func() {
    36  		p.Close()
    37  	})
    38  	return p
    39  }
    40  
    41  func mustTCProgramWithName(t *testing.T, name string) *ebpf.Program {
    42  	p, err := ebpf.NewProgram(&ebpf.ProgramSpec{
    43  		Name: name,
    44  		Type: ebpf.SchedCLS,
    45  		Instructions: asm.Instructions{
    46  			asm.Mov.Imm(asm.R0, 0),
    47  			asm.Return(),
    48  		},
    49  		License: "Apache-2.0",
    50  	})
    51  	if err != nil {
    52  		t.Skipf("tc programs not supported: %s", err)
    53  	}
    54  	t.Cleanup(func() {
    55  		p.Close()
    56  	})
    57  	return p
    58  }
    59  
    60  func TestAttachDetachSKBProgramLegacy(t *testing.T) {
    61  	testutils.PrivilegedTest(t)
    62  
    63  	ns := netns.NewNetNS(t)
    64  	ns.Do(func() error {
    65  		prog := mustTCProgram(t)
    66  		linkDir := testutils.TempBPFFS(t)
    67  
    68  		require.NoError(t, attachSKBProgram(lo, prog, "cil_test", linkDir, directionToParent(dirEgress), false))
    69  		hasFilters, err := hasCiliumTCFilters(lo, directionToParent(dirEgress))
    70  		require.NoError(t, err)
    71  		require.True(t, hasFilters)
    72  
    73  		require.NoError(t, detachSKBProgram(lo, "cil_test", linkDir, directionToParent(dirEgress)))
    74  		hasFilters, err = hasCiliumTCFilters(lo, directionToParent(dirEgress))
    75  		require.NoError(t, err)
    76  		require.False(t, hasFilters)
    77  
    78  		return nil
    79  	})
    80  }
    81  
    82  func TestAttachDetachTCProgram(t *testing.T) {
    83  	testutils.PrivilegedTest(t)
    84  
    85  	ns := netns.NewNetNS(t)
    86  	ns.Do(func() error {
    87  		prog := mustTCProgram(t)
    88  
    89  		require.NoError(t, attachTCProgram(lo, prog, "cil_test", directionToParent(dirEgress)))
    90  		hasFilters, err := hasCiliumTCFilters(lo, directionToParent(dirEgress))
    91  		require.NoError(t, err)
    92  		require.True(t, hasFilters)
    93  
    94  		require.NoError(t, removeTCFilters(lo, directionToParent(dirEgress)))
    95  		hasFilters, err = hasCiliumTCFilters(lo, directionToParent(dirEgress))
    96  		require.NoError(t, err)
    97  		require.False(t, hasFilters)
    98  
    99  		return nil
   100  	})
   101  }
   102  
   103  func TestHasCiliumTCFilters(t *testing.T) {
   104  	testutils.PrivilegedTest(t)
   105  
   106  	ns := netns.NewNetNS(t)
   107  	ns.Do(func() error {
   108  		// Test if function succeeds and returns false if no filters are attached
   109  		hasFilters, err := hasCiliumTCFilters(lo, directionToParent(dirEgress))
   110  		require.NoError(t, err)
   111  		require.False(t, hasFilters)
   112  
   113  		prog := mustTCProgram(t)
   114  
   115  		err = attachTCProgram(lo, prog, "no_prefix_test", directionToParent(dirEgress))
   116  		require.NoError(t, err)
   117  
   118  		// Test if function succeeds and return false if no filter with 'cil' prefix is attached
   119  		hasFilters, err = hasCiliumTCFilters(lo, directionToParent(dirEgress))
   120  		require.NoError(t, err)
   121  		require.False(t, hasFilters)
   122  
   123  		err = attachTCProgram(lo, prog, "cil_test", directionToParent(dirEgress))
   124  		require.NoError(t, err)
   125  
   126  		// Test if function succeeds and return true if filter with 'cil' prefix is attached
   127  		hasFilters, err = hasCiliumTCFilters(lo, directionToParent(dirEgress))
   128  		require.NoError(t, err)
   129  		require.True(t, hasFilters)
   130  
   131  		return nil
   132  	})
   133  }
   134  
   135  // Upgrade a legacy tc program to tcx.
   136  func TestAttachSKBUpgrade(t *testing.T) {
   137  	testutils.PrivilegedTest(t)
   138  
   139  	skipTCXUnsupported(t)
   140  
   141  	ns := netns.NewNetNS(t)
   142  	ns.Do(func() error {
   143  		prog := mustTCProgramWithName(t, "cil_test")
   144  		linkDir := testutils.TempBPFFS(t)
   145  
   146  		// Use the cil_ prefix so the attachment algorithm knows which tc filter to
   147  		// clean up after attaching tcx.
   148  		require.NoError(t, attachTCProgram(lo, prog, "cil_test", directionToParent(dirEgress)))
   149  
   150  		require.NoError(t, attachSKBProgram(lo, prog, "cil_test", linkDir, directionToParent(dirEgress), true))
   151  
   152  		hasFilters, err := hasCiliumTCFilters(lo, directionToParent(dirEgress))
   153  		require.NoError(t, err)
   154  		require.False(t, hasFilters)
   155  
   156  		require.NoError(t, testutils.WaitUntil(func() bool {
   157  			hasLinks, err := hasCiliumTCXLinks(lo, ebpf.AttachTCXEgress)
   158  			require.NoError(t, err)
   159  			return hasLinks
   160  		}, time.Second))
   161  
   162  		return nil
   163  	})
   164  }
   165  
   166  // Downgrade a tcx program to legacy tc.
   167  func TestAttachSKBDowngrade(t *testing.T) {
   168  	testutils.PrivilegedTest(t)
   169  
   170  	skipTCXUnsupported(t)
   171  
   172  	ns := netns.NewNetNS(t)
   173  	ns.Do(func() error {
   174  		prog := mustTCProgramWithName(t, "cil_test")
   175  		linkDir := testutils.TempBPFFS(t)
   176  
   177  		require.NoError(t, upsertTCXProgram(lo, prog, "cil_test", linkDir, directionToParent(dirEgress)))
   178  
   179  		require.NoError(t, attachSKBProgram(lo, prog, "cil_test", linkDir, directionToParent(dirEgress), false))
   180  
   181  		hasFilters, err := hasCiliumTCFilters(lo, directionToParent(dirEgress))
   182  		require.NoError(t, err)
   183  		require.True(t, hasFilters)
   184  
   185  		require.NoError(t, testutils.WaitUntil(func() bool {
   186  			hasLinks, err := hasCiliumTCXLinks(lo, ebpf.AttachTCXEgress)
   187  			require.NoError(t, err)
   188  			return !hasLinks
   189  		}, time.Second))
   190  
   191  		return nil
   192  	})
   193  }