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 }