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  }