From e9c4c513d11e6c3986f8858b9a11535d61cfdf74 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 16 Sep 2016 22:46:20 -0700 Subject: [PATCH] Fix issue for `--fixed-cidr` when bridge has multiple addresses This fix tries to address the issue raised in 26341 where multiple addresses in a bridge may cause `--fixed-cidr` to not have the correct addresses. The issue is that `netutils.ElectInterfaceAddresses(bridgeName)` only returns the first IPv4 address. This fix (together with the PR created in libnetwork ) changes `ElectInterfaceAddresses()` and `addresses()` so that all IPv4 addresses are returned. This will allow the possibility of selectively choose the address needed. In `daemon_unix.go`, bridge address is chosen by comparing with the `--fixed-cidr` first, thus resolve the issue in 26341. This fix is tested manually, as is described in 26341: ``` brctl addbr cbr0 ip addr add 10.111.111.111/20 dev cbr0 label cbr0:main ip addr add 10.222.222.222/12 dev cbr0 label cbr0:docker ip link set cbr0 up docker daemon --bridge=cbr0 --iptables=false --ip-masq=false --fixed-cidr=10.222.222.222/24 docker run --rm busybox ip route get 8.8.8.8 | grep -Po 'src.*' src 10.222.222.0 ``` This fix fixes 26341. Signed-off-by: Yong Tang --- daemon/daemon_unix.go | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 2ea6be25be..95e6a20b36 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -41,6 +41,7 @@ import ( rsystem "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/user" specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" "github.com/vishvananda/netlink" ) @@ -710,13 +711,30 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} - nw, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) - if err == nil { - ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() - hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) - if hip.IsGlobalUnicast() { - ipamV4Conf.Gateway = nw.IP.String() + nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) + if err != nil { + return errors.Wrap(err, "list bridge addresses failed") + } + + nw := nwList[0] + if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { + _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) + if err != nil { + return errors.Wrap(err, "parse CIDR failed") } + // Iterate through in case there are multiple addresses for the bridge + for _, entry := range nwList { + if fCIDR.Contains(entry.IP) { + nw = entry + break + } + } + } + + ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() + hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) + if hip.IsGlobalUnicast() { + ipamV4Conf.Gateway = nw.IP.String() } if config.bridgeConfig.IP != "" {