github.com/cilium/cilium@v1.16.2/pkg/datapath/loader/netlink_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 //go:build linux 5 6 package loader 7 8 import ( 9 "net" 10 "testing" 11 12 "github.com/cilium/ebpf" 13 "github.com/cilium/ebpf/asm" 14 15 "github.com/spf13/afero" 16 "github.com/stretchr/testify/require" 17 "github.com/vishvananda/netlink" 18 19 "github.com/cilium/cilium/pkg/datapath/linux/sysctl" 20 "github.com/cilium/cilium/pkg/datapath/tunnel" 21 "github.com/cilium/cilium/pkg/defaults" 22 "github.com/cilium/cilium/pkg/option" 23 "github.com/cilium/cilium/pkg/testutils" 24 "github.com/cilium/cilium/pkg/testutils/netns" 25 ) 26 27 // lo accesses the default loopback interface present in the current netns. 28 var lo = &netlink.GenericLink{ 29 LinkAttrs: netlink.LinkAttrs{Name: "lo", Index: 1}, 30 LinkType: "loopback", 31 } 32 33 func mustXDPProgram(t *testing.T, name string) *ebpf.Program { 34 p, err := ebpf.NewProgram(&ebpf.ProgramSpec{ 35 Type: ebpf.XDP, 36 Name: name, 37 Instructions: asm.Instructions{ 38 asm.Mov.Imm(asm.R0, 0), 39 asm.Return(), 40 }, 41 License: "Apache-2.0", 42 }) 43 if err != nil { 44 t.Skipf("xdp programs not supported: %s", err) 45 } 46 t.Cleanup(func() { 47 p.Close() 48 }) 49 return p 50 } 51 52 func TestSetupDev(t *testing.T) { 53 testutils.PrivilegedTest(t) 54 55 sysctl := sysctl.NewDirectSysctl(afero.NewOsFs(), "/proc") 56 57 prevConfigEnableIPv4 := option.Config.EnableIPv4 58 prevConfigEnableIPv6 := option.Config.EnableIPv6 59 t.Cleanup(func() { 60 option.Config.EnableIPv4 = prevConfigEnableIPv4 61 option.Config.EnableIPv6 = prevConfigEnableIPv6 62 }) 63 option.Config.EnableIPv4 = true 64 option.Config.EnableIPv6 = true 65 66 ns := netns.NewNetNS(t) 67 68 ns.Do(func() error { 69 ifName := "dummy" 70 dummy := &netlink.Dummy{ 71 LinkAttrs: netlink.LinkAttrs{ 72 Name: ifName, 73 }, 74 } 75 err := netlink.LinkAdd(dummy) 76 require.NoError(t, err) 77 78 err = enableForwarding(sysctl, dummy) 79 require.NoError(t, err) 80 81 enabledSettings := [][]string{ 82 {"net", "ipv6", "conf", ifName, "forwarding"}, 83 {"net", "ipv4", "conf", ifName, "forwarding"}, 84 {"net", "ipv4", "conf", ifName, "accept_local"}, 85 } 86 disabledSettings := [][]string{ 87 {"net", "ipv4", "conf", ifName, "rp_filter"}, 88 {"net", "ipv4", "conf", ifName, "send_redirects"}, 89 } 90 for _, setting := range enabledSettings { 91 s, err := sysctl.Read(setting) 92 require.NoError(t, err) 93 require.Equal(t, s, "1") 94 } 95 for _, setting := range disabledSettings { 96 s, err := sysctl.Read(setting) 97 require.NoError(t, err) 98 require.Equal(t, s, "0") 99 } 100 101 err = netlink.LinkDel(dummy) 102 require.NoError(t, err) 103 104 return nil 105 }) 106 } 107 108 func TestSetupTunnelDevice(t *testing.T) { 109 testutils.PrivilegedTest(t) 110 111 sysctl := sysctl.NewDirectSysctl(afero.NewOsFs(), "/proc") 112 mtu := 1500 113 114 t.Run("Geneve", func(t *testing.T) { 115 ns := netns.NewNetNS(t) 116 117 ns.Do(func() error { 118 err := setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu) 119 require.NoError(t, err) 120 121 link, err := netlink.LinkByName(defaults.GeneveDevice) 122 require.NoError(t, err) 123 124 geneve, ok := link.(*netlink.Geneve) 125 require.True(t, ok) 126 require.True(t, geneve.FlowBased) 127 require.EqualValues(t, geneve.Dport, defaults.TunnelPortGeneve) 128 129 err = netlink.LinkDel(link) 130 require.NoError(t, err) 131 132 return nil 133 }) 134 }) 135 136 t.Run("GeneveModifyPort", func(t *testing.T) { 137 ns := netns.NewNetNS(t) 138 139 ns.Do(func() error { 140 err := setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu) 141 require.NoError(t, err) 142 143 err = setupTunnelDevice(sysctl, tunnel.Geneve, 12345, mtu) 144 require.NoError(t, err) 145 146 link, err := netlink.LinkByName(defaults.GeneveDevice) 147 require.NoError(t, err) 148 149 geneve, ok := link.(*netlink.Geneve) 150 require.True(t, ok) 151 require.True(t, geneve.FlowBased) 152 require.EqualValues(t, geneve.Dport, 12345) 153 154 err = netlink.LinkDel(link) 155 require.NoError(t, err) 156 157 return nil 158 }) 159 }) 160 161 t.Run("GeneveModifyMTU", func(t *testing.T) { 162 ns := netns.NewNetNS(t) 163 164 ns.Do(func() error { 165 err := setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu) 166 require.NoError(t, err) 167 168 link, err := netlink.LinkByName(defaults.GeneveDevice) 169 require.NoError(t, err) 170 171 // Ensure the ifindex does not change when specifying a different MTU. 172 ifindex := link.Attrs().Index 173 174 err = setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu-1) 175 require.NoError(t, err) 176 177 link, err = netlink.LinkByName(defaults.GeneveDevice) 178 require.NoError(t, err) 179 180 require.Equal(t, ifindex, link.Attrs().Index, "ifindex must not change when changing MTU") 181 require.Equal(t, mtu-1, link.Attrs().MTU) 182 183 return nil 184 }) 185 }) 186 187 t.Run("Vxlan", func(t *testing.T) { 188 ns := netns.NewNetNS(t) 189 190 ns.Do(func() error { 191 err := setupTunnelDevice(sysctl, tunnel.VXLAN, defaults.TunnelPortVXLAN, mtu) 192 require.NoError(t, err) 193 194 link, err := netlink.LinkByName(defaults.VxlanDevice) 195 require.NoError(t, err) 196 197 vxlan, ok := link.(*netlink.Vxlan) 198 require.True(t, ok) 199 require.True(t, vxlan.FlowBased) 200 require.EqualValues(t, vxlan.Port, defaults.TunnelPortVXLAN) 201 202 err = netlink.LinkDel(link) 203 require.NoError(t, err) 204 205 return nil 206 }) 207 }) 208 209 t.Run("VxlanModifyPort", func(t *testing.T) { 210 ns := netns.NewNetNS(t) 211 212 ns.Do(func() error { 213 err := setupTunnelDevice(sysctl, tunnel.VXLAN, defaults.TunnelPortVXLAN, mtu) 214 require.NoError(t, err) 215 216 err = setupTunnelDevice(sysctl, tunnel.VXLAN, 12345, mtu) 217 require.NoError(t, err) 218 219 link, err := netlink.LinkByName(defaults.VxlanDevice) 220 require.NoError(t, err) 221 222 vxlan, ok := link.(*netlink.Vxlan) 223 require.True(t, ok) 224 require.True(t, vxlan.FlowBased) 225 require.EqualValues(t, vxlan.Port, 12345) 226 227 err = netlink.LinkDel(link) 228 require.NoError(t, err) 229 230 return nil 231 }) 232 }) 233 234 t.Run("VxlanModifyMTU", func(t *testing.T) { 235 ns := netns.NewNetNS(t) 236 237 ns.Do(func() error { 238 err := setupTunnelDevice(sysctl, tunnel.VXLAN, defaults.TunnelPortVXLAN, mtu) 239 require.NoError(t, err) 240 241 link, err := netlink.LinkByName(defaults.VxlanDevice) 242 require.NoError(t, err) 243 244 // Ensure the ifindex does not change when specifying a different MTU. 245 ifindex := link.Attrs().Index 246 247 err = setupTunnelDevice(sysctl, tunnel.VXLAN, defaults.TunnelPortVXLAN, mtu-1) 248 require.NoError(t, err) 249 250 link, err = netlink.LinkByName(defaults.VxlanDevice) 251 require.NoError(t, err) 252 253 require.Equal(t, ifindex, link.Attrs().Index, "ifindex must not change when changing MTU") 254 require.Equal(t, mtu-1, link.Attrs().MTU) 255 256 return nil 257 }) 258 }) 259 260 t.Run("EnableSwitchDisable", func(t *testing.T) { 261 ns := netns.NewNetNS(t) 262 263 ns.Do(func() error { 264 // Start with a Geneve tunnel. 265 err := setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu) 266 require.NoError(t, err) 267 _, err = netlink.LinkByName(defaults.GeneveDevice) 268 require.NoError(t, err) 269 _, err = netlink.LinkByName(defaults.VxlanDevice) 270 require.Error(t, err) 271 272 // Switch to vxlan mode. 273 err = setupTunnelDevice(sysctl, tunnel.VXLAN, defaults.TunnelPortVXLAN, mtu) 274 require.NoError(t, err) 275 _, err = netlink.LinkByName(defaults.GeneveDevice) 276 require.Error(t, err) 277 _, err = netlink.LinkByName(defaults.VxlanDevice) 278 require.NoError(t, err) 279 280 // Switch back to Geneve. 281 err = setupTunnelDevice(sysctl, tunnel.Geneve, defaults.TunnelPortGeneve, mtu) 282 require.NoError(t, err) 283 _, err = netlink.LinkByName(defaults.GeneveDevice) 284 require.NoError(t, err) 285 _, err = netlink.LinkByName(defaults.VxlanDevice) 286 require.Error(t, err) 287 288 // Disable tunneling. 289 err = setupTunnelDevice(sysctl, tunnel.Disabled, 0, mtu) 290 require.NoError(t, err) 291 _, err = netlink.LinkByName(defaults.VxlanDevice) 292 require.Error(t, err) 293 _, err = netlink.LinkByName(defaults.GeneveDevice) 294 require.Error(t, err) 295 296 return nil 297 }) 298 }) 299 } 300 301 func TestAddHostDeviceAddr(t *testing.T) { 302 testutils.PrivilegedTest(t) 303 304 // test IP addresses 305 testIPv4 := net.ParseIP("1.2.3.4") 306 testIPv6 := net.ParseIP("2001:db08:0bad:cafe:600d:bee2:0bad:cafe") 307 308 ns := netns.NewNetNS(t) 309 310 ns.Do(func() error { 311 ifName := "dummy" 312 dummy := &netlink.Dummy{ 313 LinkAttrs: netlink.LinkAttrs{ 314 Name: ifName, 315 }, 316 } 317 err := netlink.LinkAdd(dummy) 318 require.NoError(t, err) 319 320 err = addHostDeviceAddr(dummy, testIPv4, testIPv6) 321 require.NoError(t, err) 322 323 addrs, err := netlink.AddrList(dummy, netlink.FAMILY_ALL) 324 require.NoError(t, err) 325 326 var foundIPv4, foundIPv6 bool 327 for _, addr := range addrs { 328 if testIPv4.Equal(addr.IP) { 329 foundIPv4 = true 330 } 331 if testIPv6.Equal(addr.IP) { 332 foundIPv6 = true 333 } 334 } 335 require.Equal(t, foundIPv4, true) 336 require.Equal(t, foundIPv6, true) 337 338 err = netlink.LinkDel(dummy) 339 require.NoError(t, err) 340 341 return nil 342 }) 343 } 344 345 func TestSetupIPIPDevices(t *testing.T) { 346 testutils.PrivilegedTest(t) 347 348 sysctl := sysctl.NewDirectSysctl(afero.NewOsFs(), "/proc") 349 350 ns := netns.NewNetNS(t) 351 352 ns.Do(func() error { 353 err := setupIPIPDevices(sysctl, true, true) 354 require.NoError(t, err) 355 356 _, err = netlink.LinkByName(defaults.IPIPv4Device) 357 require.NoError(t, err) 358 359 _, err = netlink.LinkByName(defaults.IPIPv6Device) 360 require.NoError(t, err) 361 362 _, err = netlink.LinkByName("cilium_tunl") 363 require.NoError(t, err) 364 365 _, err = netlink.LinkByName("cilium_ip6tnl") 366 require.NoError(t, err) 367 368 _, err = netlink.LinkByName("tunl0") 369 require.Error(t, err) 370 371 _, err = netlink.LinkByName("ip6tnl0") 372 require.Error(t, err) 373 374 err = setupIPIPDevices(sysctl, false, false) 375 require.NoError(t, err) 376 377 _, err = netlink.LinkByName(defaults.IPIPv4Device) 378 require.Error(t, err) 379 380 _, err = netlink.LinkByName(defaults.IPIPv6Device) 381 require.Error(t, err) 382 383 return nil 384 }) 385 }