github.com/cilium/cilium@v1.16.2/pkg/node/address_linux_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  //go:build !darwin
     5  
     6  package node
     7  
     8  import (
     9  	"fmt"
    10  	"net"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/vishvananda/netlink"
    15  
    16  	"github.com/cilium/cilium/pkg/testutils"
    17  )
    18  
    19  func setUpSuite(tb testing.TB) {
    20  	testutils.PrivilegedTest(tb)
    21  }
    22  
    23  func Test_firstGlobalV4Addr(t *testing.T) {
    24  	setUpSuite(t)
    25  
    26  	testCases := []struct {
    27  		name           string
    28  		ipsOnInterface []string
    29  		preferredIP    string
    30  		preferPublic   bool
    31  		want           string
    32  	}{
    33  		{
    34  			name:           "public IP preferred by default",
    35  			ipsOnInterface: []string{"192.168.0.1", "21.0.0.1"},
    36  			want:           "21.0.0.1",
    37  		},
    38  		{
    39  			name:           "prefer IP when not preferPublic",
    40  			ipsOnInterface: []string{"192.168.0.1", "21.0.0.1"},
    41  			preferredIP:    "192.168.0.1",
    42  			want:           "192.168.0.1",
    43  		},
    44  		{
    45  			name:           "preferPublic when not prefer IP",
    46  			ipsOnInterface: []string{"192.168.0.1", "21.0.0.1"},
    47  			preferPublic:   true,
    48  			want:           "21.0.0.1",
    49  		},
    50  		{
    51  			name:           "preferPublic when prefer IP",
    52  			ipsOnInterface: []string{"192.168.0.1", "21.0.0.1"},
    53  			preferPublic:   true,
    54  			preferredIP:    "192.168.0.1",
    55  			want:           "21.0.0.1",
    56  		},
    57  		{
    58  			name:           "primary IP preferred by default",
    59  			ipsOnInterface: []string{"192.168.0.2", "192.168.0.1"},
    60  			want:           "192.168.0.2",
    61  		},
    62  	}
    63  	const ifName = "dummy_iface"
    64  	for _, tc := range testCases {
    65  		err := setupDummyDevice(ifName, tc.ipsOnInterface...)
    66  		require.NoError(t, err)
    67  
    68  		got, err := firstGlobalV4Addr(ifName, net.ParseIP(tc.preferredIP), tc.preferPublic)
    69  		require.NoError(t, err)
    70  		require.Equal(t, tc.want, got.String())
    71  		removeDevice(ifName)
    72  	}
    73  }
    74  
    75  func setupDummyDevice(name string, ips ...string) error {
    76  	dummy := &netlink.Dummy{
    77  		LinkAttrs: netlink.LinkAttrs{
    78  			Name: name,
    79  		},
    80  	}
    81  	if err := netlink.LinkAdd(dummy); err != nil {
    82  		return fmt.Errorf("netlink.LinkAdd failed: %w", err)
    83  	}
    84  
    85  	if err := netlink.LinkSetUp(dummy); err != nil {
    86  		removeDevice(name)
    87  		return fmt.Errorf("netlink.LinkSetUp failed: %w", err)
    88  	}
    89  
    90  	for _, ipStr := range ips {
    91  		ip := net.ParseIP(ipStr)
    92  		if ip == nil || ip.To4() == nil {
    93  			removeDevice(name)
    94  			return fmt.Errorf("invalid ipv4 IP : %v", ipStr)
    95  		}
    96  		ipnet := &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}
    97  		addr := &netlink.Addr{IPNet: ipnet}
    98  		if err := netlink.AddrAdd(dummy, addr); err != nil {
    99  			removeDevice(name)
   100  			return err
   101  		}
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  func removeDevice(name string) {
   108  	l, err := netlink.LinkByName(name)
   109  	if err == nil {
   110  		netlink.LinkDel(l)
   111  	}
   112  }