mirror of
https://github.com/moby/moby.git
synced 2026-07-11 18:13:57 +00:00
A recent change to the vishvananda/netlink package exposes NLM_F_DUMP_INTR in some netlink responses as an EINTR (with no data). Retry the requests when that happens, up to five times, before returning the error. The limit of five is arbitrary, on most systems a single retry will be rare but, there's no guarantee that a retry will succeed. So, on a very busy or misbehaving system the error may still be returned. In most cases, this will lead to failure of the operation being attempted (which may lead to daemon startup failure, network initialisation failure etc). Signed-off-by: Rob Murray <rob.murray@docker.com>
166 lines
4.8 KiB
Go
166 lines
4.8 KiB
Go
package bridge
|
|
|
|
import (
|
|
"net"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/internal/nlwrap"
|
|
"github.com/docker/docker/internal/testutils/netnsutils"
|
|
"github.com/vishvananda/netlink"
|
|
"golang.org/x/sys/unix"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func cidrToIPNet(t *testing.T, cidr string) *net.IPNet {
|
|
t.Helper()
|
|
ip, ipNet, err := net.ParseCIDR(cidr)
|
|
assert.Assert(t, is.Nil(err))
|
|
return &net.IPNet{IP: ip, Mask: ipNet.Mask}
|
|
}
|
|
|
|
func addAddr(t *testing.T, link netlink.Link, addr string) {
|
|
t.Helper()
|
|
ipNet := cidrToIPNet(t, addr)
|
|
err := netlink.AddrAdd(link, &netlink.Addr{IPNet: ipNet})
|
|
assert.Assert(t, is.Nil(err))
|
|
}
|
|
|
|
func prepTestBridge(t *testing.T, nc *networkConfiguration) *bridgeInterface {
|
|
t.Helper()
|
|
nh, err := nlwrap.NewHandle()
|
|
assert.Assert(t, err)
|
|
i, err := newInterface(nh, nc)
|
|
assert.Assert(t, err)
|
|
err = setupDevice(nc, i)
|
|
assert.Assert(t, err)
|
|
return i
|
|
}
|
|
|
|
func TestInterfaceDefaultName(t *testing.T) {
|
|
defer netnsutils.SetupTestOSContext(t)()
|
|
|
|
nh, err := nlwrap.NewHandle()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
config := &networkConfiguration{}
|
|
_, err = newInterface(nh, config)
|
|
assert.Check(t, err)
|
|
assert.Equal(t, config.BridgeName, DefaultBridgeName)
|
|
}
|
|
|
|
func TestAddressesNoInterface(t *testing.T) {
|
|
i := bridgeInterface{}
|
|
addrs, err := i.addresses(netlink.FAMILY_V6)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Len(addrs, 0))
|
|
}
|
|
|
|
func TestAddressesEmptyInterface(t *testing.T) {
|
|
defer netnsutils.SetupTestOSContext(t)()
|
|
|
|
nh, err := nlwrap.NewHandle()
|
|
assert.NilError(t, err)
|
|
|
|
inf, err := newInterface(nh, &networkConfiguration{})
|
|
assert.NilError(t, err)
|
|
|
|
addrsv4, err := inf.addresses(netlink.FAMILY_V4)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Len(addrsv4, 0))
|
|
|
|
addrsv6, err := inf.addresses(netlink.FAMILY_V6)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Len(addrsv6, 0))
|
|
}
|
|
|
|
func TestAddressesNonEmptyInterface(t *testing.T) {
|
|
defer netnsutils.SetupTestOSContext(t)()
|
|
|
|
i := prepTestBridge(t, &networkConfiguration{})
|
|
|
|
const expAddrV4, expAddrV6 = "192.168.1.2/24", "fd00:1234::/64"
|
|
addAddr(t, i.Link, expAddrV4)
|
|
addAddr(t, i.Link, expAddrV6)
|
|
|
|
addrs, err := i.addresses(netlink.FAMILY_V4)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Len(addrs, 1))
|
|
assert.Equal(t, addrs[0].IPNet.String(), expAddrV4)
|
|
|
|
addrs, err = i.addresses(netlink.FAMILY_V6)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Len(addrs, 1))
|
|
assert.Equal(t, addrs[0].IPNet.String(), expAddrV6)
|
|
}
|
|
|
|
func TestProgramIPv6Addresses(t *testing.T) {
|
|
defer netnsutils.SetupTestOSContext(t)()
|
|
|
|
checkAddrs := func(i *bridgeInterface, nc *networkConfiguration, expAddrs []string) {
|
|
t.Helper()
|
|
nladdrs, err := i.addresses(netlink.FAMILY_V6)
|
|
actual := []string{}
|
|
for _, a := range nladdrs {
|
|
actual = append(actual, a.String())
|
|
}
|
|
assert.NilError(t, err)
|
|
exp := append([]string(nil), expAddrs...)
|
|
sort.Strings(exp)
|
|
sort.Strings(actual)
|
|
assert.DeepEqual(t, actual, exp)
|
|
assert.Check(t, is.DeepEqual(i.bridgeIPv6, nc.AddressIPv6))
|
|
assert.Check(t, is.DeepEqual(i.gatewayIPv6, nc.AddressIPv6.IP))
|
|
}
|
|
|
|
nc := &networkConfiguration{}
|
|
i := prepTestBridge(t, nc)
|
|
|
|
// The bridge has no addresses, ask for a regular IPv6 network and expect it to
|
|
// be added to the bridge.
|
|
nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/64")
|
|
err := i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"2000:3000::1/64"})
|
|
|
|
// Shrink the subnet of that regular address, the prefix length of the address
|
|
// will not be modified - but it's informational-only, the address itself has
|
|
// not changed.
|
|
nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/80")
|
|
err = i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"2000:3000::1/64"})
|
|
|
|
// Ask for link-local only, by specifying an address with the Link Local prefix.
|
|
// The regular address should be removed.
|
|
nc.AddressIPv6 = cidrToIPNet(t, "fe80::1/64")
|
|
err = i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"fe80::1/64"})
|
|
|
|
// Swap the standard link local address for a nonstandard one. The standard LL
|
|
// address will not be removed.
|
|
nc.AddressIPv6 = cidrToIPNet(t, "fe80:5555::1/55")
|
|
err = i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"fe80:5555::1/55", "fe80::1/64"})
|
|
|
|
// Back to the original address, expect the nonstandard LL address to be replaced.
|
|
nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/64")
|
|
err = i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64"})
|
|
|
|
// Add a multicast address to the bridge and check it's not removed.
|
|
mcNlAddr, err := netlink.ParseAddr("ff05::db8:0:1234/96")
|
|
assert.NilError(t, err)
|
|
mcNlAddr.Flags = unix.IFA_F_MCAUTOJOIN
|
|
err = i.nlh.AddrAdd(i.Link, mcNlAddr)
|
|
assert.NilError(t, err)
|
|
err = i.programIPv6Addresses(nc)
|
|
assert.NilError(t, err)
|
|
checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64", "ff05::db8:0:1234/96"})
|
|
}
|