Explorar el Código

Allow specifying a default gateway for bridge networking

Signed-off-by: Sylvain Baubeau <sbaubeau@redhat.com>
Sylvain Baubeau hace 10 años
padre
commit
acb6127c1a

+ 2 - 0
daemon/config.go

@@ -58,6 +58,8 @@ func (config *Config) InstallFlags() {
 	flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
 	flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
 	flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
 	flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
 	flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
 	flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
+	flag.StringVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
+	flag.StringVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
 	flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
 	flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
 	flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
 	flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
 	flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Exec driver to use")
 	flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Exec driver to use")

+ 54 - 6
daemon/networkdriver/bridge/driver.go

@@ -77,8 +77,10 @@ var (
 
 
 	bridgeIface       string
 	bridgeIface       string
 	bridgeIPv4Network *net.IPNet
 	bridgeIPv4Network *net.IPNet
+	gatewayIPv4       net.IP
 	bridgeIPv6Addr    net.IP
 	bridgeIPv6Addr    net.IP
 	globalIPv6Network *net.IPNet
 	globalIPv6Network *net.IPNet
+	gatewayIPv6       net.IP
 	portMapper        *portmapper.PortMapper
 	portMapper        *portmapper.PortMapper
 	once              sync.Once
 	once              sync.Once
 
 
@@ -103,6 +105,8 @@ type Config struct {
 	IP                          string
 	IP                          string
 	FixedCIDR                   string
 	FixedCIDR                   string
 	FixedCIDRv6                 string
 	FixedCIDRv6                 string
+	DefaultGatewayIPv4          string
+	DefaultGatewayIPv6          string
 	InterContainerCommunication bool
 	InterContainerCommunication bool
 }
 }
 
 
@@ -278,6 +282,12 @@ func InitDriver(config *Config) error {
 		}
 		}
 	}
 	}
 
 
+	if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv4, bridgeIPv4Network); err != nil {
+		return err
+	} else {
+		gatewayIPv4 = gateway
+	}
+
 	if config.FixedCIDRv6 != "" {
 	if config.FixedCIDRv6 != "" {
 		_, subnet, err := net.ParseCIDR(config.FixedCIDRv6)
 		_, subnet, err := net.ParseCIDR(config.FixedCIDRv6)
 		if err != nil {
 		if err != nil {
@@ -289,6 +299,12 @@ func InitDriver(config *Config) error {
 			return err
 			return err
 		}
 		}
 		globalIPv6Network = subnet
 		globalIPv6Network = subnet
+
+		if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv6, globalIPv6Network); err != nil {
+			return err
+		} else {
+			gatewayIPv6 = gateway
+		}
 	}
 	}
 
 
 	// Block BridgeIP in IP allocator
 	// Block BridgeIP in IP allocator
@@ -473,6 +489,24 @@ func setupIPv6Bridge(bridgeIPv6 string) error {
 	return nil
 	return nil
 }
 }
 
 
+func requestDefaultGateway(requestedGateway string, network *net.IPNet) (gateway net.IP, err error) {
+	if requestedGateway != "" {
+		gateway = net.ParseIP(requestedGateway)
+
+		if gateway == nil {
+			return nil, fmt.Errorf("Bad parameter: invalid gateway ip %s", requestedGateway)
+		}
+
+		if !network.Contains(gateway) {
+			return nil, fmt.Errorf("Gateway ip %s must be part of the network %s", requestedGateway, network.String())
+		}
+
+		ipAllocator.RequestIP(network, gateway)
+	}
+
+	return gateway, nil
+}
+
 func createBridgeIface(name string) error {
 func createBridgeIface(name string) error {
 	kv, err := kernel.GetKernelVersion()
 	kv, err := kernel.GetKernelVersion()
 	// Only set the bridge's mac address if the kernel version is > 3.3
 	// Only set the bridge's mac address if the kernel version is > 3.3
@@ -522,10 +556,12 @@ func linkLocalIPv6FromMac(mac string) (string, error) {
 // Allocate a network interface
 // Allocate a network interface
 func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Settings, error) {
 func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Settings, error) {
 	var (
 	var (
-		ip         net.IP
-		mac        net.HardwareAddr
-		err        error
-		globalIPv6 net.IP
+		ip            net.IP
+		mac           net.HardwareAddr
+		err           error
+		globalIPv6    net.IP
+		defaultGWIPv4 net.IP
+		defaultGWIPv6 net.IP
 	)
 	)
 
 
 	ip, err = ipAllocator.RequestIP(bridgeIPv4Network, net.ParseIP(requestedIP))
 	ip, err = ipAllocator.RequestIP(bridgeIPv4Network, net.ParseIP(requestedIP))
@@ -560,6 +596,18 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
 
 
 	maskSize, _ := bridgeIPv4Network.Mask.Size()
 	maskSize, _ := bridgeIPv4Network.Mask.Size()
 
 
+	if gatewayIPv4 != nil {
+		defaultGWIPv4 = gatewayIPv4
+	} else {
+		defaultGWIPv4 = bridgeIPv4Network.IP
+	}
+
+	if gatewayIPv6 != nil {
+		defaultGWIPv6 = gatewayIPv6
+	} else {
+		defaultGWIPv6 = bridgeIPv6Addr
+	}
+
 	// If linklocal IPv6
 	// If linklocal IPv6
 	localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
 	localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
 	if err != nil {
 	if err != nil {
@@ -569,7 +617,7 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
 
 
 	networkSettings := &network.Settings{
 	networkSettings := &network.Settings{
 		IPAddress:            ip.String(),
 		IPAddress:            ip.String(),
-		Gateway:              bridgeIPv4Network.IP.String(),
+		Gateway:              defaultGWIPv4.String(),
 		MacAddress:           mac.String(),
 		MacAddress:           mac.String(),
 		Bridge:               bridgeIface,
 		Bridge:               bridgeIface,
 		IPPrefixLen:          maskSize,
 		IPPrefixLen:          maskSize,
@@ -580,7 +628,7 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
 		networkSettings.GlobalIPv6Address = globalIPv6.String()
 		networkSettings.GlobalIPv6Address = globalIPv6.String()
 		maskV6Size, _ := globalIPv6Network.Mask.Size()
 		maskV6Size, _ := globalIPv6Network.Mask.Size()
 		networkSettings.GlobalIPv6PrefixLen = maskV6Size
 		networkSettings.GlobalIPv6PrefixLen = maskV6Size
-		networkSettings.IPv6Gateway = bridgeIPv6Addr.String()
+		networkSettings.IPv6Gateway = defaultGWIPv6.String()
 	}
 	}
 
 
 	currentInterfaces.Set(id, &networkInterface{
 	currentInterfaces.Set(id, &networkInterface{

+ 6 - 0
docs/man/docker.1.md

@@ -41,6 +41,12 @@ To see the man page for a command run **man docker <command>**.
 **-d**, **--daemon**=*true*|*false*
 **-d**, **--daemon**=*true*|*false*
   Enable daemon mode. Default is false.
   Enable daemon mode. Default is false.
 
 
+**--default-gateway**=""
+  IPv4 address of the container default gateway; this address must be part of the bridge subnet (which is defined by \-b or \--bip)
+
+**--default-gateway-v6**=""
+  IPv6 address of the container default gateway
+
 **--dns**=""
 **--dns**=""
   Force Docker to use specific DNS servers
   Force Docker to use specific DNS servers
 
 

+ 16 - 7
docs/sources/articles/networking.md

@@ -56,6 +56,12 @@ server when it starts up, and cannot be changed once it is running:
  *  `--bip=CIDR` — see
  *  `--bip=CIDR` — see
     [Customizing docker0](#docker0)
     [Customizing docker0](#docker0)
 
 
+ *  `--default-gateway=IP_ADDRESS` — see
+    [How Docker networks a container](#container-networking)
+
+ *  `--default-gateway-v6=IP_ADDRESS` — see
+    [IPv6](#ipv6)
+
  *  `--fixed-cidr` — see
  *  `--fixed-cidr` — see
     [Customizing docker0](#docker0)
     [Customizing docker0](#docker0)
 
 
@@ -499,7 +505,9 @@ want to configure `eth0` via Router Advertisements you should set:
 ![](/article-img/ipv6_basic_host_config.svg)
 ![](/article-img/ipv6_basic_host_config.svg)
 
 
 Every new container will get an IPv6 address from the defined subnet. Further
 Every new container will get an IPv6 address from the defined subnet. Further
-a default route will be added via the gateway `fe80::1` on `eth0`:
+a default route will be added on `eth0` in the container via the address
+specified by the daemon option `--default-gateway-v6` if present, otherwise
+via `fe80::1`:
 
 
     docker run -it ubuntu bash -c "ip -6 addr show dev eth0; ip -6 route show"
     docker run -it ubuntu bash -c "ip -6 addr show dev eth0; ip -6 route show"
 
 
@@ -865,12 +873,13 @@ The steps with which Docker configures a container are:
     parameter or generate a random one.
     parameter or generate a random one.
 
 
 5.  Give the container's `eth0` a new IP address from within the
 5.  Give the container's `eth0` a new IP address from within the
-    bridge's range of network addresses, and set its default route to
-    the IP address that the Docker host owns on the bridge. The MAC
-    address is generated from the IP address unless otherwise specified.
-    This prevents ARP cache invalidation problems, when a new container
-    comes up with an IP used in the past by another container with another
-    MAC.
+    bridge's range of network addresses. The default route is set to the
+    IP address passed to the Docker daemon using the `--default-gateway`
+    option if specified, otherwise to the IP address that the Docker host
+    owns on the bridge. The MAC address is generated from the IP address
+    unless otherwise specified. This prevents ARP cache invalidation
+    problems, when a new container comes up with an IP used in the past by
+    another container with another MAC.
 
 
 With these steps complete, the container now possesses an `eth0`
 With these steps complete, the container now possesses an `eth0`
 (virtual) network card and will find itself able to communicate with
 (virtual) network card and will find itself able to communicate with

+ 2 - 0
docs/sources/reference/commandline/cli.md

@@ -116,6 +116,8 @@ expect an integer, and they can only be specified once.
       --bip=""                               Specify network bridge IP
       --bip=""                               Specify network bridge IP
       -D, --debug=false                      Enable debug mode
       -D, --debug=false                      Enable debug mode
       -d, --daemon=false                     Enable daemon mode
       -d, --daemon=false                     Enable daemon mode
+      --default-gateway=""                   Container default gateway IPv4 address
+      --default-gateway-v6=""                Container default gateway IPv6 address
       --dns=[]                               DNS server to use
       --dns=[]                               DNS server to use
       --dns-search=[]                        DNS search domains to use
       --dns-search=[]                        DNS search domains to use
       -e, --exec-driver="native"             Exec driver to use
       -e, --exec-driver="native"             Exec driver to use