Browse Source

Allow bridge net driver to skip IPv4 configuration of bridge interface

Introduce "com.docker.network.bridge.inhibit_ipv4" option to the bridge
network driver. If set, this option will prevent docker from setting or
modifying Layer-3 (IP) configuration on the bridge interface in any way.

This option should allow connecting containers to pre-existing network
segments (with e.g., pre-existing default gateways) while simultaneously
preserving our ability to communicate with the host and/or configure the
properties of the host-side container virtual network interface (e.g.,
delay/loss/jitter via netem), which can not be done using macvlan.

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
Gabriel L. Somlo 6 years ago
parent
commit
10027e8c01

+ 6 - 1
libnetwork/drivers/bridge/bridge.go

@@ -68,6 +68,7 @@ type networkConfiguration struct {
 	EnableIPv6           bool
 	EnableIPMasquerade   bool
 	EnableICC            bool
+	InhibitIPv4          bool
 	Mtu                  int
 	DefaultBindingIP     net.IP
 	DefaultBridge        bool
@@ -243,6 +244,10 @@ func (c *networkConfiguration) fromLabels(labels map[string]string) error {
 			if c.EnableICC, err = strconv.ParseBool(value); err != nil {
 				return parseErr(label, value, err.Error())
 			}
+		case InhibitIPv4:
+			if c.InhibitIPv4, err = strconv.ParseBool(value); err != nil {
+				return parseErr(label, value, err.Error())
+			}
 		case DefaultBridge:
 			if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
 				return parseErr(label, value, err.Error())
@@ -699,7 +704,7 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
 
 		// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
 		// the case of a previously existing device.
-		{bridgeAlreadyExists, setupVerifyAndReconcile},
+		{bridgeAlreadyExists && !config.InhibitIPv4, setupVerifyAndReconcile},
 
 		// Enable IPv6 Forwarding
 		{enableIPv6Forwarding, setupIPv6Forwarding},

+ 2 - 0
libnetwork/drivers/bridge/bridge_store.go

@@ -137,6 +137,7 @@ func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
 	nMap["EnableIPv6"] = ncfg.EnableIPv6
 	nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
 	nMap["EnableICC"] = ncfg.EnableICC
+	nMap["InhibitIPv4"] = ncfg.InhibitIPv4
 	nMap["Mtu"] = ncfg.Mtu
 	nMap["Internal"] = ncfg.Internal
 	nMap["DefaultBridge"] = ncfg.DefaultBridge
@@ -192,6 +193,7 @@ func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
 	ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
 	ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
 	ncfg.EnableICC = nMap["EnableICC"].(bool)
+	ncfg.InhibitIPv4 = nMap["InhibitIPv4"].(bool)
 	ncfg.Mtu = int(nMap["Mtu"].(float64))
 	if v, ok := nMap["Internal"]; ok {
 		ncfg.Internal = v.(bool)

+ 3 - 0
libnetwork/drivers/bridge/labels.go

@@ -10,6 +10,9 @@ const (
 	// EnableICC label
 	EnableICC = "com.docker.network.bridge.enable_icc"
 
+	// InhibitIPv4 label
+	InhibitIPv4 = "com.docker.network.bridge.inhibit_ipv4"
+
 	// DefaultBindingIP label
 	DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4"
 

+ 15 - 13
libnetwork/drivers/bridge/setup_ipv4.go

@@ -27,22 +27,24 @@ func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.A
 }
 
 func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
-	addrv4List, _, err := i.addresses()
-	if err != nil {
-		return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
-	}
+	if !config.InhibitIPv4 {
+		addrv4List, _, err := i.addresses()
+		if err != nil {
+			return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
+		}
 
-	addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
+		addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
 
-	if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
-		if addrv4.IPNet != nil {
-			if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
-				return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
+		if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
+			if addrv4.IPNet != nil {
+				if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
+					return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
+				}
+			}
+			logrus.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
+			if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
+				return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
 			}
-		}
-		logrus.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
-		if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
-			return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
 		}
 	}