github.com/rish1988/moby@v25.0.2+incompatible/libnetwork/drivers/bridge/interface_linux_test.go (about)

     1  package bridge
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/docker/docker/internal/testutils/netnsutils"
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/vishvananda/netlink"
    12  	"gotest.tools/v3/assert"
    13  	is "gotest.tools/v3/assert/cmp"
    14  )
    15  
    16  func cidrToIPNet(t *testing.T, cidr string) *net.IPNet {
    17  	t.Helper()
    18  	ip, ipNet, err := net.ParseCIDR(cidr)
    19  	assert.Assert(t, is.Nil(err))
    20  	return &net.IPNet{IP: ip, Mask: ipNet.Mask}
    21  }
    22  
    23  func addAddr(t *testing.T, link netlink.Link, addr string) {
    24  	t.Helper()
    25  	ipNet := cidrToIPNet(t, addr)
    26  	err := netlink.AddrAdd(link, &netlink.Addr{IPNet: ipNet})
    27  	assert.Assert(t, is.Nil(err))
    28  }
    29  
    30  func prepTestBridge(t *testing.T, nc *networkConfiguration) *bridgeInterface {
    31  	t.Helper()
    32  	nh, err := netlink.NewHandle()
    33  	assert.Assert(t, err)
    34  	i, err := newInterface(nh, nc)
    35  	assert.Assert(t, err)
    36  	err = setupDevice(nc, i)
    37  	assert.Assert(t, err)
    38  	return i
    39  }
    40  
    41  func TestInterfaceDefaultName(t *testing.T) {
    42  	defer netnsutils.SetupTestOSContext(t)()
    43  
    44  	nh, err := netlink.NewHandle()
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	config := &networkConfiguration{}
    49  	_, err = newInterface(nh, config)
    50  	assert.Check(t, err)
    51  	assert.Equal(t, config.BridgeName, DefaultBridgeName)
    52  }
    53  
    54  func TestAddressesNoInterface(t *testing.T) {
    55  	i := bridgeInterface{}
    56  	addrs, err := i.addresses(netlink.FAMILY_V6)
    57  	assert.NilError(t, err)
    58  	assert.Check(t, is.Len(addrs, 0))
    59  }
    60  
    61  func TestAddressesEmptyInterface(t *testing.T) {
    62  	defer netnsutils.SetupTestOSContext(t)()
    63  
    64  	nh, err := netlink.NewHandle()
    65  	assert.NilError(t, err)
    66  
    67  	inf, err := newInterface(nh, &networkConfiguration{})
    68  	assert.NilError(t, err)
    69  
    70  	addrsv4, err := inf.addresses(netlink.FAMILY_V4)
    71  	assert.NilError(t, err)
    72  	assert.Check(t, is.Len(addrsv4, 0))
    73  
    74  	addrsv6, err := inf.addresses(netlink.FAMILY_V6)
    75  	assert.NilError(t, err)
    76  	assert.Check(t, is.Len(addrsv6, 0))
    77  }
    78  
    79  func TestAddressesNonEmptyInterface(t *testing.T) {
    80  	defer netnsutils.SetupTestOSContext(t)()
    81  
    82  	i := prepTestBridge(t, &networkConfiguration{})
    83  
    84  	const expAddrV4, expAddrV6 = "192.168.1.2/24", "fd00:1234::/64"
    85  	addAddr(t, i.Link, expAddrV4)
    86  	addAddr(t, i.Link, expAddrV6)
    87  
    88  	addrs, err := i.addresses(netlink.FAMILY_V4)
    89  	assert.NilError(t, err)
    90  	assert.Check(t, is.Len(addrs, 1))
    91  	assert.Equal(t, addrs[0].IPNet.String(), expAddrV4)
    92  
    93  	addrs, err = i.addresses(netlink.FAMILY_V6)
    94  	assert.NilError(t, err)
    95  	assert.Check(t, is.Len(addrs, 1))
    96  	assert.Equal(t, addrs[0].IPNet.String(), expAddrV6)
    97  }
    98  
    99  func TestGetRequiredIPv6Addrs(t *testing.T) {
   100  	testcases := []struct {
   101  		name         string
   102  		addressIPv6  string
   103  		expReqdAddrs []string
   104  	}{
   105  		{
   106  			name:         "Regular address, expect default link local",
   107  			addressIPv6:  "2000:3000::1/80",
   108  			expReqdAddrs: []string{"fe80::1/64", "2000:3000::1/80"},
   109  		},
   110  		{
   111  			name:         "Standard link local address only",
   112  			addressIPv6:  "fe80::1/64",
   113  			expReqdAddrs: []string{"fe80::1/64"},
   114  		},
   115  		{
   116  			name:         "Nonstandard link local address",
   117  			addressIPv6:  "fe80:abcd::1/42",
   118  			expReqdAddrs: []string{"fe80:abcd::1/42", "fe80::1/64"},
   119  		},
   120  	}
   121  
   122  	for _, tc := range testcases {
   123  		t.Run(tc.name, func(t *testing.T) {
   124  			config := &networkConfiguration{
   125  				AddressIPv6: cidrToIPNet(t, tc.addressIPv6),
   126  			}
   127  
   128  			expResult := map[netip.Addr]netip.Prefix{}
   129  			for _, addr := range tc.expReqdAddrs {
   130  				expResult[netip.MustParseAddr(strings.Split(addr, "/")[0])] = netip.MustParsePrefix(addr)
   131  			}
   132  
   133  			reqd, err := getRequiredIPv6Addrs(config)
   134  			assert.Check(t, is.Nil(err))
   135  			assert.Check(t, is.DeepEqual(reqd, expResult,
   136  				cmp.Comparer(func(a, b netip.Prefix) bool { return a == b })))
   137  		})
   138  	}
   139  }
   140  
   141  func TestProgramIPv6Addresses(t *testing.T) {
   142  	defer netnsutils.SetupTestOSContext(t)()
   143  
   144  	checkAddrs := func(i *bridgeInterface, nc *networkConfiguration, expAddrs []string) {
   145  		t.Helper()
   146  		exp := []netlink.Addr{}
   147  		for _, a := range expAddrs {
   148  			ipNet := cidrToIPNet(t, a)
   149  			exp = append(exp, netlink.Addr{IPNet: ipNet})
   150  		}
   151  		actual, err := i.addresses(netlink.FAMILY_V6)
   152  		assert.NilError(t, err)
   153  		assert.DeepEqual(t, exp, actual)
   154  		assert.Check(t, is.DeepEqual(i.bridgeIPv6, nc.AddressIPv6))
   155  		assert.Check(t, is.DeepEqual(i.gatewayIPv6, nc.AddressIPv6.IP))
   156  	}
   157  
   158  	nc := &networkConfiguration{}
   159  	i := prepTestBridge(t, nc)
   160  
   161  	// The bridge has no addresses, ask for a regular IPv6 network and expect it to
   162  	// be added to the bridge, with the default link local address.
   163  	nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/64")
   164  	err := i.programIPv6Addresses(nc)
   165  	assert.NilError(t, err)
   166  	checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64"})
   167  
   168  	// Shrink the subnet of that regular address, the prefix length of the address
   169  	// will not be modified - but it's informational-only, the address itself has
   170  	// not changed.
   171  	nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/80")
   172  	err = i.programIPv6Addresses(nc)
   173  	assert.NilError(t, err)
   174  	checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64"})
   175  
   176  	// Ask for link-local only, by specifying an address with the Link Local prefix.
   177  	// The regular address should be removed.
   178  	nc.AddressIPv6 = cidrToIPNet(t, "fe80::1/64")
   179  	err = i.programIPv6Addresses(nc)
   180  	assert.NilError(t, err)
   181  	checkAddrs(i, nc, []string{"fe80::1/64"})
   182  
   183  	// Swap the standard link local address for a nonstandard one.
   184  	nc.AddressIPv6 = cidrToIPNet(t, "fe80:5555::1/55")
   185  	err = i.programIPv6Addresses(nc)
   186  	assert.NilError(t, err)
   187  	checkAddrs(i, nc, []string{"fe80:5555::1/55", "fe80::1/64"})
   188  }