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 }