Browse code

Allow specifying a default gateway for bridge networking

Signed-off-by: Sylvain Baubeau <sbaubeau@redhat.com>

Sylvain Baubeau authored on 2014/12/18 18:09:42
Showing 5 changed files
... ...
@@ -58,6 +58,8 @@ func (config *Config) InstallFlags() {
58 58
 	flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
59 59
 	flag.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs")
60 60
 	flag.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", "IPv6 subnet for fixed IPs")
61
+	flag.StringVar(&config.Bridge.DefaultGatewayIPv4, []string{"-default-gateway"}, "", "Container default gateway IPv4 address")
62
+	flag.StringVar(&config.Bridge.DefaultGatewayIPv6, []string{"-default-gateway-v6"}, "", "Container default gateway IPv6 address")
61 63
 	flag.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
62 64
 	flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Storage driver to use")
63 65
 	flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Exec driver to use")
... ...
@@ -77,8 +77,10 @@ var (
77 77
 
78 78
 	bridgeIface       string
79 79
 	bridgeIPv4Network *net.IPNet
80
+	gatewayIPv4       net.IP
80 81
 	bridgeIPv6Addr    net.IP
81 82
 	globalIPv6Network *net.IPNet
83
+	gatewayIPv6       net.IP
82 84
 	portMapper        *portmapper.PortMapper
83 85
 	once              sync.Once
84 86
 
... ...
@@ -103,6 +105,8 @@ type Config struct {
103 103
 	IP                          string
104 104
 	FixedCIDR                   string
105 105
 	FixedCIDRv6                 string
106
+	DefaultGatewayIPv4          string
107
+	DefaultGatewayIPv6          string
106 108
 	InterContainerCommunication bool
107 109
 }
108 110
 
... ...
@@ -278,6 +282,12 @@ func InitDriver(config *Config) error {
278 278
 		}
279 279
 	}
280 280
 
281
+	if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv4, bridgeIPv4Network); err != nil {
282
+		return err
283
+	} else {
284
+		gatewayIPv4 = gateway
285
+	}
286
+
281 287
 	if config.FixedCIDRv6 != "" {
282 288
 		_, subnet, err := net.ParseCIDR(config.FixedCIDRv6)
283 289
 		if err != nil {
... ...
@@ -289,6 +299,12 @@ func InitDriver(config *Config) error {
289 289
 			return err
290 290
 		}
291 291
 		globalIPv6Network = subnet
292
+
293
+		if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv6, globalIPv6Network); err != nil {
294
+			return err
295
+		} else {
296
+			gatewayIPv6 = gateway
297
+		}
292 298
 	}
293 299
 
294 300
 	// Block BridgeIP in IP allocator
... ...
@@ -473,6 +489,24 @@ func setupIPv6Bridge(bridgeIPv6 string) error {
473 473
 	return nil
474 474
 }
475 475
 
476
+func requestDefaultGateway(requestedGateway string, network *net.IPNet) (gateway net.IP, err error) {
477
+	if requestedGateway != "" {
478
+		gateway = net.ParseIP(requestedGateway)
479
+
480
+		if gateway == nil {
481
+			return nil, fmt.Errorf("Bad parameter: invalid gateway ip %s", requestedGateway)
482
+		}
483
+
484
+		if !network.Contains(gateway) {
485
+			return nil, fmt.Errorf("Gateway ip %s must be part of the network %s", requestedGateway, network.String())
486
+		}
487
+
488
+		ipAllocator.RequestIP(network, gateway)
489
+	}
490
+
491
+	return gateway, nil
492
+}
493
+
476 494
 func createBridgeIface(name string) error {
477 495
 	kv, err := kernel.GetKernelVersion()
478 496
 	// Only set the bridge's mac address if the kernel version is > 3.3
... ...
@@ -522,10 +556,12 @@ func linkLocalIPv6FromMac(mac string) (string, error) {
522 522
 // Allocate a network interface
523 523
 func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Settings, error) {
524 524
 	var (
525
-		ip         net.IP
526
-		mac        net.HardwareAddr
527
-		err        error
528
-		globalIPv6 net.IP
525
+		ip            net.IP
526
+		mac           net.HardwareAddr
527
+		err           error
528
+		globalIPv6    net.IP
529
+		defaultGWIPv4 net.IP
530
+		defaultGWIPv6 net.IP
529 531
 	)
530 532
 
531 533
 	ip, err = ipAllocator.RequestIP(bridgeIPv4Network, net.ParseIP(requestedIP))
... ...
@@ -560,6 +596,18 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
560 560
 
561 561
 	maskSize, _ := bridgeIPv4Network.Mask.Size()
562 562
 
563
+	if gatewayIPv4 != nil {
564
+		defaultGWIPv4 = gatewayIPv4
565
+	} else {
566
+		defaultGWIPv4 = bridgeIPv4Network.IP
567
+	}
568
+
569
+	if gatewayIPv6 != nil {
570
+		defaultGWIPv6 = gatewayIPv6
571
+	} else {
572
+		defaultGWIPv6 = bridgeIPv6Addr
573
+	}
574
+
563 575
 	// If linklocal IPv6
564 576
 	localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
565 577
 	if err != nil {
... ...
@@ -569,7 +617,7 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
569 569
 
570 570
 	networkSettings := &network.Settings{
571 571
 		IPAddress:            ip.String(),
572
-		Gateway:              bridgeIPv4Network.IP.String(),
572
+		Gateway:              defaultGWIPv4.String(),
573 573
 		MacAddress:           mac.String(),
574 574
 		Bridge:               bridgeIface,
575 575
 		IPPrefixLen:          maskSize,
... ...
@@ -580,7 +628,7 @@ func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Set
580 580
 		networkSettings.GlobalIPv6Address = globalIPv6.String()
581 581
 		maskV6Size, _ := globalIPv6Network.Mask.Size()
582 582
 		networkSettings.GlobalIPv6PrefixLen = maskV6Size
583
-		networkSettings.IPv6Gateway = bridgeIPv6Addr.String()
583
+		networkSettings.IPv6Gateway = defaultGWIPv6.String()
584 584
 	}
585 585
 
586 586
 	currentInterfaces.Set(id, &networkInterface{
... ...
@@ -41,6 +41,12 @@ To see the man page for a command run **man docker <command>**.
41 41
 **-d**, **--daemon**=*true*|*false*
42 42
   Enable daemon mode. Default is false.
43 43
 
44
+**--default-gateway**=""
45
+  IPv4 address of the container default gateway; this address must be part of the bridge subnet (which is defined by \-b or \--bip)
46
+
47
+**--default-gateway-v6**=""
48
+  IPv6 address of the container default gateway
49
+
44 50
 **--dns**=""
45 51
   Force Docker to use specific DNS servers
46 52
 
... ...
@@ -56,6 +56,12 @@ server when it starts up, and cannot be changed once it is running:
56 56
  *  `--bip=CIDR` — see
57 57
     [Customizing docker0](#docker0)
58 58
 
59
+ *  `--default-gateway=IP_ADDRESS` — see
60
+    [How Docker networks a container](#container-networking)
61
+
62
+ *  `--default-gateway-v6=IP_ADDRESS` — see
63
+    [IPv6](#ipv6)
64
+
59 65
  *  `--fixed-cidr` — see
60 66
     [Customizing docker0](#docker0)
61 67
 
... ...
@@ -499,7 +505,9 @@ want to configure `eth0` via Router Advertisements you should set:
499 499
 ![](/article-img/ipv6_basic_host_config.svg)
500 500
 
501 501
 Every new container will get an IPv6 address from the defined subnet. Further
502
-a default route will be added via the gateway `fe80::1` on `eth0`:
502
+a default route will be added on `eth0` in the container via the address
503
+specified by the daemon option `--default-gateway-v6` if present, otherwise
504
+via `fe80::1`:
503 505
 
504 506
     docker run -it ubuntu bash -c "ip -6 addr show dev eth0; ip -6 route show"
505 507
 
... ...
@@ -865,12 +873,13 @@ The steps with which Docker configures a container are:
865 865
     parameter or generate a random one.
866 866
 
867 867
 5.  Give the container's `eth0` a new IP address from within the
868
-    bridge's range of network addresses, and set its default route to
869
-    the IP address that the Docker host owns on the bridge. The MAC
870
-    address is generated from the IP address unless otherwise specified.
871
-    This prevents ARP cache invalidation problems, when a new container
872
-    comes up with an IP used in the past by another container with another
873
-    MAC.
868
+    bridge's range of network addresses. The default route is set to the
869
+    IP address passed to the Docker daemon using the `--default-gateway`
870
+    option if specified, otherwise to the IP address that the Docker host
871
+    owns on the bridge. The MAC address is generated from the IP address
872
+    unless otherwise specified. This prevents ARP cache invalidation
873
+    problems, when a new container comes up with an IP used in the past by
874
+    another container with another MAC.
874 875
 
875 876
 With these steps complete, the container now possesses an `eth0`
876 877
 (virtual) network card and will find itself able to communicate with
... ...
@@ -116,6 +116,8 @@ expect an integer, and they can only be specified once.
116 116
       --bip=""                               Specify network bridge IP
117 117
       -D, --debug=false                      Enable debug mode
118 118
       -d, --daemon=false                     Enable daemon mode
119
+      --default-gateway=""                   Container default gateway IPv4 address
120
+      --default-gateway-v6=""                Container default gateway IPv6 address
119 121
       --dns=[]                               DNS server to use
120 122
       --dns-search=[]                        DNS search domains to use
121 123
       -e, --exec-driver="native"             Exec driver to use