2014-03-20 21:51:28 +00:00
package bridge
2014-01-29 16:59:21 -08:00
import (
2015-01-09 00:03:19 +01:00
"encoding/hex"
"errors"
2014-01-29 16:59:21 -08:00
"fmt"
2014-05-05 22:51:32 +00:00
"io/ioutil"
"net"
2014-10-05 00:21:59 -04:00
"os"
2015-04-14 15:02:02 -07:00
"os/exec"
2015-04-04 00:06:48 -04:00
"strconv"
2015-01-09 00:03:19 +01:00
"strings"
2014-05-29 16:28:06 +04:00
"sync"
2014-05-05 22:51:32 +00:00
2015-03-26 23:22:04 +01:00
"github.com/Sirupsen/logrus"
2015-04-04 00:06:48 -04:00
"github.com/docker/docker/daemon/network"
2014-07-24 22:19:50 +00:00
"github.com/docker/docker/daemon/networkdriver"
"github.com/docker/docker/daemon/networkdriver/ipallocator"
"github.com/docker/docker/daemon/networkdriver/portmapper"
2014-09-17 01:08:30 +00:00
"github.com/docker/docker/nat"
2014-07-24 22:19:50 +00:00
"github.com/docker/docker/pkg/iptables"
2014-07-28 17:23:38 -07:00
"github.com/docker/docker/pkg/parsers/kernel"
2015-03-22 23:27:04 -07:00
"github.com/docker/docker/pkg/resolvconf"
2014-07-24 22:25:29 +00:00
"github.com/docker/libcontainer/netlink"
2014-01-29 16:59:21 -08:00
)
const (
2014-06-26 00:09:19 -07:00
DefaultNetworkBridge = "docker0"
MaxAllocatedPortAttempts = 10
2014-01-29 16:59:21 -08:00
)
// Network interface represents the networking stack of a container
type networkInterface struct {
IP net . IP
2015-01-09 00:03:19 +01:00
IPv6 net . IP
2015-03-03 23:39:04 +08:00
PortMappings [ ] net . Addr // There are mappings to the host interfaces
2014-01-29 16:59:21 -08:00
}
2014-05-29 16:28:06 +04:00
type ifaces struct {
c map [ string ] * networkInterface
sync . Mutex
}
func ( i * ifaces ) Set ( key string , n * networkInterface ) {
i . Lock ( )
i . c [ key ] = n
i . Unlock ( )
}
func ( i * ifaces ) Get ( key string ) * networkInterface {
i . Lock ( )
res := i . c [ key ]
i . Unlock ( )
return res
}
2014-01-29 16:59:21 -08:00
var (
addrs = [ ] string {
// Here we don't follow the convention of using the 1st IP of the range for the gateway.
// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
2015-04-04 15:22:24 +02:00
// on the internal addressing or other things like that.
2014-04-15 17:35:36 -04:00
// They shouldn't, but hey, let's not break them unless we really have to.
2014-01-29 16:59:21 -08:00
"172.17.42.1/16" , // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
"10.0.42.1/16" , // Don't even try using the entire /8, that's too intrusive
"10.1.42.1/16" ,
"10.42.42.1/16" ,
"172.16.42.1/24" ,
"172.16.43.1/24" ,
"172.16.44.1/24" ,
"10.0.42.1/24" ,
"10.0.43.1/24" ,
"192.168.42.1/24" ,
"192.168.43.1/24" ,
"192.168.44.1/24" ,
}
2015-01-09 00:03:19 +01:00
bridgeIface string
bridgeIPv4Network * net . IPNet
2014-12-18 10:09:42 +01:00
gatewayIPv4 net . IP
2015-01-09 00:03:19 +01:00
bridgeIPv6Addr net . IP
globalIPv6Network * net . IPNet
2014-12-18 10:09:42 +01:00
gatewayIPv6 net . IP
2015-03-30 18:06:16 -07:00
portMapper * portmapper . PortMapper
2015-03-31 09:34:03 -07:00
once sync . Once
2014-01-29 16:59:21 -08:00
2014-01-30 14:52:59 -08:00
defaultBindingIP = net . ParseIP ( "0.0.0.0" )
2014-05-29 16:28:06 +04:00
currentInterfaces = ifaces { c : make ( map [ string ] * networkInterface ) }
2015-03-23 20:20:10 -07:00
ipAllocator = ipallocator . New ( )
2014-01-29 16:59:21 -08:00
)
2015-03-31 09:34:03 -07:00
func initPortMapper ( ) {
once . Do ( func ( ) {
portMapper = portmapper . New ( )
} )
}
2015-04-04 00:06:48 -04:00
type Config struct {
EnableIPv6 bool
EnableIptables bool
EnableIpForward bool
EnableIpMasq bool
DefaultIp net . IP
Iface string
IP string
FixedCIDR string
FixedCIDRv6 string
2014-12-18 10:09:42 +01:00
DefaultGatewayIPv4 string
DefaultGatewayIPv6 string
2015-04-04 00:06:48 -04:00
InterContainerCommunication bool
}
func InitDriver ( config * Config ) error {
2014-01-29 16:59:21 -08:00
var (
2015-04-04 00:06:48 -04:00
networkv4 * net . IPNet
networkv6 * net . IPNet
addrv4 net . Addr
addrsv6 [ ] net . Addr
bridgeIPv6 = "fe80::1/64"
2014-01-29 16:59:21 -08:00
)
2015-04-14 15:02:02 -07:00
// try to modprobe bridge first
// see gh#12177
if out , err := exec . Command ( "modprobe" , "-va" , "bridge" , "nf_nat" ) . Output ( ) ; err != nil {
logrus . Warnf ( "Running modprobe bridge nf_nat failed with message: %s, error: %v" , out , err )
}
2015-03-31 09:34:03 -07:00
initPortMapper ( )
2014-01-29 18:34:43 -08:00
2015-04-04 00:06:48 -04:00
if config . DefaultIp != nil {
defaultBindingIP = config . DefaultIp
2014-01-30 14:52:59 -08:00
}
2014-01-30 11:25:06 -08:00
2015-04-04 00:06:48 -04:00
bridgeIface = config . Iface
2014-04-08 14:07:02 -04:00
usingDefaultBridge := false
2014-01-29 18:34:43 -08:00
if bridgeIface == "" {
2014-04-08 14:07:02 -04:00
usingDefaultBridge = true
2014-01-29 18:34:43 -08:00
bridgeIface = DefaultNetworkBridge
}
2014-01-29 16:59:21 -08:00
2015-01-09 00:03:19 +01:00
addrv4 , addrsv6 , err := networkdriver . GetIfaceAddr ( bridgeIface )
2014-01-29 16:59:21 -08:00
if err != nil {
2015-03-03 00:52:53 +08:00
// No Bridge existent, create one
2014-04-08 14:07:02 -04:00
// If we're not using the default bridge, fail without trying to create it
if ! usingDefaultBridge {
2015-03-25 08:44:12 +01:00
return err
2014-04-08 14:07:02 -04:00
}
2015-01-09 00:03:19 +01:00
2015-04-12 15:49:29 -07:00
logrus . Info ( "Bridge interface not found, trying to create it" )
2015-04-11 10:40:37 -07:00
2015-01-09 00:03:19 +01:00
// If the iface is not found, try to create it
2015-04-04 00:06:48 -04:00
if err := configureBridge ( config . IP , bridgeIPv6 , config . EnableIPv6 ) ; err != nil {
2015-04-11 10:40:37 -07:00
logrus . Errorf ( "Could not configure Bridge: %s" , err )
2015-03-25 08:44:12 +01:00
return err
2014-01-29 16:59:21 -08:00
}
2015-01-09 00:03:19 +01:00
addrv4 , addrsv6 , err = networkdriver . GetIfaceAddr ( bridgeIface )
2014-01-29 16:59:21 -08:00
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-01-29 16:59:21 -08:00
}
2015-01-09 00:03:19 +01:00
2015-04-04 00:06:48 -04:00
if config . FixedCIDRv6 != "" {
2015-01-09 00:03:19 +01:00
// Setting route to global IPv6 subnet
2015-04-04 00:06:48 -04:00
logrus . Infof ( "Adding route to IPv6 network %q via device %q" , config . FixedCIDRv6 , bridgeIface )
if err := netlink . AddRoute ( config . FixedCIDRv6 , "" , "" , bridgeIface ) ; err != nil {
logrus . Fatalf ( "Could not add route to IPv6 network %q via device %q" , config . FixedCIDRv6 , bridgeIface )
2015-01-09 00:03:19 +01:00
}
}
2014-01-29 16:59:21 -08:00
} else {
2015-03-03 00:52:53 +08:00
// Bridge exists already, getting info...
2015-03-03 23:39:04 +08:00
// Validate that the bridge ip matches the ip specified by BridgeIP
2015-04-04 00:06:48 -04:00
if config . IP != "" {
2015-01-09 00:03:19 +01:00
networkv4 = addrv4 . ( * net . IPNet )
2015-04-04 00:06:48 -04:00
bip , _ , err := net . ParseCIDR ( config . IP )
2014-04-28 17:04:56 -07:00
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-04-28 17:04:56 -07:00
}
2015-01-09 00:03:19 +01:00
if ! networkv4 . IP . Equal ( bip ) {
2015-03-25 08:44:12 +01:00
return fmt . Errorf ( "Bridge ip (%s) does not match existing bridge configuration %s" , networkv4 . IP , bip )
2014-03-26 11:51:27 +00:00
}
}
2015-01-09 00:03:19 +01:00
2015-03-03 23:39:04 +08:00
// A bridge might exist but not have any IPv6 addr associated with it yet
2015-01-27 22:03:27 -05:00
// (for example, an existing Docker installation that has only been used
// with IPv4 and docker0 already is set up) In that case, we can perform
// the bridge init for IPv6 here, else we will error out below if --ipv6=true
2015-04-04 00:06:48 -04:00
if len ( addrsv6 ) == 0 && config . EnableIPv6 {
2015-01-27 22:03:27 -05:00
if err := setupIPv6Bridge ( bridgeIPv6 ) ; err != nil {
2015-03-25 08:44:12 +01:00
return err
2015-01-27 22:03:27 -05:00
}
2015-03-03 23:39:04 +08:00
// Recheck addresses now that IPv6 is setup on the bridge
2015-01-27 22:03:27 -05:00
addrv4 , addrsv6 , err = networkdriver . GetIfaceAddr ( bridgeIface )
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2015-01-27 22:03:27 -05:00
}
}
2015-04-04 00:06:48 -04:00
// TODO: Check if route to config.FixedCIDRv6 is set
2015-01-09 00:03:19 +01:00
}
2015-04-04 00:06:48 -04:00
if config . EnableIPv6 {
2015-01-09 00:03:19 +01:00
bip6 , _ , err := net . ParseCIDR ( bridgeIPv6 )
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2015-01-09 00:03:19 +01:00
}
found := false
for _ , addrv6 := range addrsv6 {
networkv6 = addrv6 . ( * net . IPNet )
if networkv6 . IP . Equal ( bip6 ) {
found = true
break
}
}
if ! found {
2015-03-25 08:44:12 +01:00
return fmt . Errorf ( "Bridge IPv6 does not match existing bridge configuration %s" , bip6 )
2015-01-09 00:03:19 +01:00
}
}
networkv4 = addrv4 . ( * net . IPNet )
2015-04-04 00:06:48 -04:00
if config . EnableIPv6 {
2015-01-09 00:03:19 +01:00
if len ( addrsv6 ) == 0 {
2015-03-25 08:44:12 +01:00
return errors . New ( "IPv6 enabled but no IPv6 detected" )
2015-01-09 00:03:19 +01:00
}
bridgeIPv6Addr = networkv6 . IP
2014-01-29 16:59:21 -08:00
}
// Configure iptables for link support
2015-04-04 00:06:48 -04:00
if config . EnableIptables {
if err := setupIPTables ( addrv4 , config . InterContainerCommunication , config . EnableIpMasq ) ; err != nil {
2015-04-11 10:40:37 -07:00
logrus . Errorf ( "Error configuing iptables: %s" , err )
2015-03-25 08:44:12 +01:00
return err
2014-01-29 16:59:21 -08:00
}
2015-01-09 00:03:19 +01:00
2014-01-29 16:59:21 -08:00
}
2015-04-04 00:06:48 -04:00
if config . EnableIpForward {
2014-01-29 16:59:21 -08:00
// Enable IPv4 forwarding
if err := ioutil . WriteFile ( "/proc/sys/net/ipv4/ip_forward" , [ ] byte { '1' , '\n' } , 0644 ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Warnf ( "WARNING: unable to enable IPv4 forwarding: %s\n" , err )
2014-01-29 16:59:21 -08:00
}
2015-01-09 00:03:19 +01:00
2015-04-04 00:06:48 -04:00
if config . FixedCIDRv6 != "" {
2015-01-09 00:03:19 +01:00
// Enable IPv6 forwarding
if err := ioutil . WriteFile ( "/proc/sys/net/ipv6/conf/default/forwarding" , [ ] byte { '1' , '\n' } , 0644 ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Warnf ( "WARNING: unable to enable IPv6 default forwarding: %s\n" , err )
2015-01-09 00:03:19 +01:00
}
if err := ioutil . WriteFile ( "/proc/sys/net/ipv6/conf/all/forwarding" , [ ] byte { '1' , '\n' } , 0644 ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Warnf ( "WARNING: unable to enable IPv6 all forwarding: %s\n" , err )
2015-01-09 00:03:19 +01:00
}
}
2014-01-29 16:59:21 -08:00
}
// We can always try removing the iptables
2014-07-16 22:03:01 +10:00
if err := iptables . RemoveExistingChain ( "DOCKER" , iptables . Nat ) ; err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-01-29 16:59:21 -08:00
}
2015-04-04 00:06:48 -04:00
if config . EnableIptables {
2014-07-16 22:03:01 +10:00
_ , err := iptables . NewChain ( "DOCKER" , bridgeIface , iptables . Nat )
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-07-16 22:03:01 +10:00
}
chain , err := iptables . NewChain ( "DOCKER" , bridgeIface , iptables . Filter )
2014-01-29 16:59:21 -08:00
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-01-29 16:59:21 -08:00
}
2015-03-30 18:06:16 -07:00
portMapper . SetIptablesChain ( chain )
2014-01-29 16:59:21 -08:00
}
2015-01-09 00:03:19 +01:00
bridgeIPv4Network = networkv4
2015-04-04 00:06:48 -04:00
if config . FixedCIDR != "" {
_ , subnet , err := net . ParseCIDR ( config . FixedCIDR )
2014-05-29 00:06:23 +04:00
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-05-29 00:06:23 +04:00
}
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "Subnet: %v" , subnet )
2015-03-23 20:20:10 -07:00
if err := ipAllocator . RegisterSubnet ( bridgeIPv4Network , subnet ) ; err != nil {
2015-04-11 10:40:37 -07:00
logrus . Errorf ( "Error registering subnet for IPv4 bridge network: %s" , err )
2015-03-25 08:44:12 +01:00
return err
2015-01-09 00:03:19 +01:00
}
}
2014-12-18 10:09:42 +01:00
if gateway , err := requestDefaultGateway ( config . DefaultGatewayIPv4 , bridgeIPv4Network ) ; err != nil {
return err
} else {
gatewayIPv4 = gateway
}
2015-04-04 00:06:48 -04:00
if config . FixedCIDRv6 != "" {
_ , subnet , err := net . ParseCIDR ( config . FixedCIDRv6 )
2015-01-09 00:03:19 +01:00
if err != nil {
2015-03-25 08:44:12 +01:00
return err
2015-01-09 00:03:19 +01:00
}
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "Subnet: %v" , subnet )
2015-03-23 20:20:10 -07:00
if err := ipAllocator . RegisterSubnet ( subnet , subnet ) ; err != nil {
2015-04-12 15:49:29 -07:00
logrus . Errorf ( "Error registering subnet for IPv6 bridge network: %s" , err )
2015-03-25 08:44:12 +01:00
return err
2014-05-29 00:06:23 +04:00
}
2015-01-09 00:03:19 +01:00
globalIPv6Network = subnet
2014-12-18 10:09:42 +01:00
if gateway , err := requestDefaultGateway ( config . DefaultGatewayIPv6 , globalIPv6Network ) ; err != nil {
return err
} else {
gatewayIPv6 = gateway
}
2014-05-29 00:06:23 +04:00
}
2014-01-29 18:34:43 -08:00
2015-01-08 16:21:01 +01:00
// Block BridgeIP in IP allocator
2015-03-23 20:20:10 -07:00
ipAllocator . RequestIP ( bridgeIPv4Network , bridgeIPv4Network . IP )
2015-01-08 16:21:01 +01:00
2015-03-25 08:44:12 +01:00
return nil
2014-01-29 16:59:21 -08:00
}
2014-09-16 20:00:15 -07:00
func setupIPTables ( addr net . Addr , icc , ipmasq bool ) error {
2014-01-29 16:59:21 -08:00
// Enable NAT
2014-09-16 20:00:15 -07:00
if ipmasq {
2015-02-13 22:10:14 -05:00
natArgs := [ ] string { "-s" , addr . String ( ) , "!" , "-o" , bridgeIface , "-j" , "MASQUERADE" }
2014-09-16 20:00:15 -07:00
2015-02-13 22:10:14 -05:00
if ! iptables . Exists ( iptables . Nat , "POSTROUTING" , natArgs ... ) {
if output , err := iptables . Raw ( append ( [ ] string {
"-t" , string ( iptables . Nat ) , "-I" , "POSTROUTING" } , natArgs ... ) ... ) ; err != nil {
2014-09-16 20:00:15 -07:00
return fmt . Errorf ( "Unable to enable network bridge NAT: %s" , err )
} else if len ( output ) != 0 {
2015-04-16 21:22:32 +02:00
return iptables . ChainError { Chain : "POSTROUTING" , Output : output }
2014-09-16 20:00:15 -07:00
}
2014-01-29 16:59:21 -08:00
}
}
var (
2015-02-13 22:10:14 -05:00
args = [ ] string { "-i" , bridgeIface , "-o" , bridgeIface , "-j" }
2014-01-29 16:59:21 -08:00
acceptArgs = append ( args , "ACCEPT" )
dropArgs = append ( args , "DROP" )
)
if ! icc {
2015-02-13 22:10:14 -05:00
iptables . Raw ( append ( [ ] string { "-D" , "FORWARD" } , acceptArgs ... ) ... )
2014-01-29 16:59:21 -08:00
2015-02-13 22:10:14 -05:00
if ! iptables . Exists ( iptables . Filter , "FORWARD" , dropArgs ... ) {
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "Disable inter-container communication" )
2015-02-13 22:10:14 -05:00
if output , err := iptables . Raw ( append ( [ ] string { "-I" , "FORWARD" } , dropArgs ... ) ... ) ; err != nil {
2014-01-29 16:59:21 -08:00
return fmt . Errorf ( "Unable to prevent intercontainer communication: %s" , err )
} else if len ( output ) != 0 {
return fmt . Errorf ( "Error disabling intercontainer communication: %s" , output )
}
}
} else {
2015-02-13 22:10:14 -05:00
iptables . Raw ( append ( [ ] string { "-D" , "FORWARD" } , dropArgs ... ) ... )
2014-01-29 16:59:21 -08:00
2015-02-13 22:10:14 -05:00
if ! iptables . Exists ( iptables . Filter , "FORWARD" , acceptArgs ... ) {
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "Enable inter-container communication" )
2015-02-13 22:10:14 -05:00
if output , err := iptables . Raw ( append ( [ ] string { "-I" , "FORWARD" } , acceptArgs ... ) ... ) ; err != nil {
2014-01-29 16:59:21 -08:00
return fmt . Errorf ( "Unable to allow intercontainer communication: %s" , err )
} else if len ( output ) != 0 {
return fmt . Errorf ( "Error enabling intercontainer communication: %s" , output )
}
}
}
// Accept all non-intercontainer outgoing packets
2015-02-13 22:10:14 -05:00
outgoingArgs := [ ] string { "-i" , bridgeIface , "!" , "-o" , bridgeIface , "-j" , "ACCEPT" }
if ! iptables . Exists ( iptables . Filter , "FORWARD" , outgoingArgs ... ) {
if output , err := iptables . Raw ( append ( [ ] string { "-I" , "FORWARD" } , outgoingArgs ... ) ... ) ; err != nil {
2014-01-29 16:59:21 -08:00
return fmt . Errorf ( "Unable to allow outgoing packets: %s" , err )
} else if len ( output ) != 0 {
2015-04-16 21:22:32 +02:00
return iptables . ChainError { Chain : "FORWARD outgoing" , Output : output }
2014-01-29 16:59:21 -08:00
}
}
// Accept incoming packets for existing connections
2015-02-13 22:10:14 -05:00
existingArgs := [ ] string { "-o" , bridgeIface , "-m" , "conntrack" , "--ctstate" , "RELATED,ESTABLISHED" , "-j" , "ACCEPT" }
2014-01-29 16:59:21 -08:00
2015-02-13 22:10:14 -05:00
if ! iptables . Exists ( iptables . Filter , "FORWARD" , existingArgs ... ) {
if output , err := iptables . Raw ( append ( [ ] string { "-I" , "FORWARD" } , existingArgs ... ) ... ) ; err != nil {
2014-01-29 16:59:21 -08:00
return fmt . Errorf ( "Unable to allow incoming packets: %s" , err )
} else if len ( output ) != 0 {
2015-04-16 21:22:32 +02:00
return iptables . ChainError { Chain : "FORWARD incoming" , Output : output }
2014-01-29 16:59:21 -08:00
}
}
return nil
}
2015-03-30 18:06:16 -07:00
func RequestPort ( ip net . IP , proto string , port int ) ( int , error ) {
2015-03-31 09:34:03 -07:00
initPortMapper ( )
2015-03-30 18:06:16 -07:00
return portMapper . Allocator . RequestPort ( ip , proto , port )
}
2014-11-12 16:55:34 -05:00
// configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host
2014-10-05 00:21:59 -04:00
// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
2014-11-12 16:55:34 -05:00
// If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing
2014-10-05 00:21:59 -04:00
// bridge (fixes issue #8444)
// If an address which doesn't conflict with existing interfaces can't be found, an error is returned.
2015-01-09 00:03:19 +01:00
func configureBridge ( bridgeIP string , bridgeIPv6 string , enableIPv6 bool ) error {
2014-01-29 16:59:21 -08:00
nameservers := [ ] string { }
2014-05-05 22:51:32 +00:00
resolvConf , _ := resolvconf . Get ( )
2015-03-03 23:39:04 +08:00
// We don't check for an error here, because we don't really care
2014-01-29 16:59:21 -08:00
// if we can't read /etc/resolv.conf. So instead we skip the append
// if resolvConf is nil. It either doesn't exist, or we can't read it
// for some reason.
if resolvConf != nil {
2014-05-05 22:51:32 +00:00
nameservers = append ( nameservers , resolvconf . GetNameserversAsCIDR ( resolvConf ) ... )
2014-01-29 16:59:21 -08:00
}
var ifaceAddr string
if len ( bridgeIP ) != 0 {
_ , _ , err := net . ParseCIDR ( bridgeIP )
if err != nil {
return err
}
ifaceAddr = bridgeIP
} else {
for _ , addr := range addrs {
_ , dockerNetwork , err := net . ParseCIDR ( addr )
if err != nil {
return err
}
if err := networkdriver . CheckNameserverOverlaps ( nameservers , dockerNetwork ) ; err == nil {
if err := networkdriver . CheckRouteOverlaps ( dockerNetwork ) ; err == nil {
ifaceAddr = addr
break
} else {
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "%s %s" , addr , err )
2014-01-29 16:59:21 -08:00
}
}
}
}
if ifaceAddr == "" {
return fmt . Errorf ( "Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'" , bridgeIface , bridgeIface )
}
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "Creating bridge %s with network %s" , bridgeIface , ifaceAddr )
2014-01-29 16:59:21 -08:00
if err := createBridgeIface ( bridgeIface ) ; err != nil {
2015-03-03 23:39:04 +08:00
// The bridge may already exist, therefore we can ignore an "exists" error
2014-10-05 00:21:59 -04:00
if ! os . IsExist ( err ) {
return err
}
2014-01-29 16:59:21 -08:00
}
iface , err := net . InterfaceByName ( bridgeIface )
if err != nil {
return err
}
ipAddr , ipNet , err := net . ParseCIDR ( ifaceAddr )
if err != nil {
return err
}
2015-01-23 14:32:36 -08:00
if err := netlink . NetworkLinkAddIp ( iface , ipAddr , ipNet ) ; err != nil {
2014-01-29 16:59:21 -08:00
return fmt . Errorf ( "Unable to add private network: %s" , err )
}
2015-01-09 00:03:19 +01:00
if enableIPv6 {
2015-01-27 22:03:27 -05:00
if err := setupIPv6Bridge ( bridgeIPv6 ) ; err != nil {
2015-01-09 00:03:19 +01:00
return err
}
}
2014-01-29 16:59:21 -08:00
if err := netlink . NetworkLinkUp ( iface ) ; err != nil {
return fmt . Errorf ( "Unable to start network bridge: %s" , err )
}
return nil
}
2015-01-27 22:03:27 -05:00
func setupIPv6Bridge ( bridgeIPv6 string ) error {
iface , err := net . InterfaceByName ( bridgeIface )
if err != nil {
return err
}
// Enable IPv6 on the bridge
procFile := "/proc/sys/net/ipv6/conf/" + iface . Name + "/disable_ipv6"
if err := ioutil . WriteFile ( procFile , [ ] byte { '0' , '\n' } , 0644 ) ; err != nil {
return fmt . Errorf ( "Unable to enable IPv6 addresses on bridge: %v" , err )
}
ipAddr6 , ipNet6 , err := net . ParseCIDR ( bridgeIPv6 )
if err != nil {
return fmt . Errorf ( "Unable to parse bridge IPv6 address: %q, error: %v" , bridgeIPv6 , err )
}
if err := netlink . NetworkLinkAddIp ( iface , ipAddr6 , ipNet6 ) ; err != nil {
return fmt . Errorf ( "Unable to add private IPv6 network: %v" , err )
}
return nil
}
2014-12-18 10:09:42 +01:00
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
}
2014-01-29 16:59:21 -08:00
func createBridgeIface ( name string ) error {
2014-07-28 17:23:38 -07:00
kv , err := kernel . GetKernelVersion ( )
2015-03-03 23:39:04 +08:00
// Only set the bridge's mac address if the kernel version is > 3.3
2014-03-31 21:02:42 +00:00
// before that it was not supported
setBridgeMacAddr := err == nil && ( kv . Kernel >= 3 && kv . Major >= 3 )
2015-03-26 23:22:04 +01:00
logrus . Debugf ( "setting bridge mac address = %v" , setBridgeMacAddr )
2014-03-31 21:02:42 +00:00
return netlink . CreateBridge ( name , setBridgeMacAddr )
2014-01-29 16:59:21 -08:00
}
2014-10-02 16:46:06 -07:00
// Generate a IEEE802 compliant MAC address from the given IP address.
//
// The generator is guaranteed to be consistent: the same IP will always yield the same
// MAC address. This is to avoid ARP cache issues.
func generateMacAddr ( ip net . IP ) net . HardwareAddr {
hw := make ( net . HardwareAddr , 6 )
// The first byte of the MAC address has to comply with these rules:
// 1. Unicast: Set the least-significant bit to 0.
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
hw [ 0 ] = 0x02
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
// Since this address is locally administered, we can do whatever we want as long as
// it doesn't conflict with other addresses.
hw [ 1 ] = 0x42
// Insert the IP address into the last 32 bits of the MAC address.
// This is a simple way to guarantee the address will be consistent and unique.
copy ( hw [ 2 : ] , ip . To4 ( ) )
return hw
}
2015-01-09 00:03:19 +01:00
func linkLocalIPv6FromMac ( mac string ) ( string , error ) {
hx := strings . Replace ( mac , ":" , "" , - 1 )
hw , err := hex . DecodeString ( hx )
if err != nil {
return "" , errors . New ( "Could not parse MAC address " + mac )
}
hw [ 0 ] ^ = 0x2
return fmt . Sprintf ( "fe80::%x%x:%xff:fe%x:%x%x/64" , hw [ 0 ] , hw [ 1 ] , hw [ 2 ] , hw [ 3 ] , hw [ 4 ] , hw [ 5 ] ) , nil
}
2014-01-29 16:59:21 -08:00
// Allocate a network interface
2015-04-04 00:06:48 -04:00
func Allocate ( id , requestedMac , requestedIP , requestedIPv6 string ) ( * network . Settings , error ) {
2014-01-30 12:02:56 -08:00
var (
2014-12-18 10:09:42 +01:00
ip net . IP
mac net . HardwareAddr
err error
globalIPv6 net . IP
defaultGWIPv4 net . IP
defaultGWIPv6 net . IP
2014-01-30 12:02:56 -08:00
)
2014-01-29 16:59:21 -08:00
2015-04-04 00:06:48 -04:00
ip , err = ipAllocator . RequestIP ( bridgeIPv4Network , net . ParseIP ( requestedIP ) )
2014-01-29 16:59:21 -08:00
if err != nil {
2015-04-04 00:06:48 -04:00
return nil , err
2014-01-29 16:59:21 -08:00
}
2014-10-02 16:46:06 -07:00
// If no explicit mac address was given, generate a random one.
2015-04-04 00:06:48 -04:00
if mac , err = net . ParseMAC ( requestedMac ) ; err != nil {
2014-10-02 16:46:06 -07:00
mac = generateMacAddr ( ip )
}
2015-01-09 00:03:19 +01:00
if globalIPv6Network != nil {
2015-03-03 23:39:04 +08:00
// If globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address
2015-03-25 19:40:23 -06:00
netmaskOnes , _ := globalIPv6Network . Mask . Size ( )
2015-04-04 00:06:48 -04:00
ipv6 := net . ParseIP ( requestedIPv6 )
if ipv6 == nil && netmaskOnes <= 80 {
ipv6 = make ( net . IP , len ( globalIPv6Network . IP ) )
copy ( ipv6 , globalIPv6Network . IP )
2015-01-09 00:03:19 +01:00
for i , h := range mac {
2015-04-04 00:06:48 -04:00
ipv6 [ i + 10 ] = h
2015-01-09 00:03:19 +01:00
}
}
2015-04-04 00:06:48 -04:00
globalIPv6 , err = ipAllocator . RequestIP ( globalIPv6Network , ipv6 )
2015-01-09 00:03:19 +01:00
if err != nil {
2015-03-26 23:22:04 +01:00
logrus . Errorf ( "Allocator: RequestIP v6: %v" , err )
2015-04-04 00:06:48 -04:00
return nil , err
2015-01-09 00:03:19 +01:00
}
2015-03-26 23:22:04 +01:00
logrus . Infof ( "Allocated IPv6 %s" , globalIPv6 )
2015-01-09 00:03:19 +01:00
}
2015-04-04 00:06:48 -04:00
maskSize , _ := bridgeIPv4Network . Mask . Size ( )
2014-01-29 16:59:21 -08:00
2014-12-18 10:09:42 +01:00
if gatewayIPv4 != nil {
defaultGWIPv4 = gatewayIPv4
} else {
defaultGWIPv4 = bridgeIPv4Network . IP
}
if gatewayIPv6 != nil {
defaultGWIPv6 = gatewayIPv6
} else {
defaultGWIPv6 = bridgeIPv6Addr
}
2015-03-03 23:39:04 +08:00
// If linklocal IPv6
2015-01-09 00:03:19 +01:00
localIPv6Net , err := linkLocalIPv6FromMac ( mac . String ( ) )
if err != nil {
2015-04-04 00:06:48 -04:00
return nil , err
2015-01-09 00:03:19 +01:00
}
localIPv6 , _ , _ := net . ParseCIDR ( localIPv6Net )
2015-04-04 00:06:48 -04:00
networkSettings := & network . Settings {
IPAddress : ip . String ( ) ,
2014-12-18 10:09:42 +01:00
Gateway : defaultGWIPv4 . String ( ) ,
2015-04-04 00:06:48 -04:00
MacAddress : mac . String ( ) ,
Bridge : bridgeIface ,
IPPrefixLen : maskSize ,
LinkLocalIPv6Address : localIPv6 . String ( ) ,
}
2015-01-09 00:03:19 +01:00
if globalIPv6Network != nil {
2015-04-04 00:06:48 -04:00
networkSettings . GlobalIPv6Address = globalIPv6 . String ( )
maskV6Size , _ := globalIPv6Network . Mask . Size ( )
networkSettings . GlobalIPv6PrefixLen = maskV6Size
2014-12-18 10:09:42 +01:00
networkSettings . IPv6Gateway = defaultGWIPv6 . String ( )
2015-01-09 00:03:19 +01:00
}
2014-05-29 16:28:06 +04:00
currentInterfaces . Set ( id , & networkInterface {
2015-01-09 00:03:19 +01:00
IP : ip ,
IPv6 : globalIPv6 ,
2014-05-29 16:28:06 +04:00
} )
2014-01-29 16:59:21 -08:00
2015-04-04 00:06:48 -04:00
return networkSettings , nil
2014-01-29 16:59:21 -08:00
}
2015-03-03 23:39:04 +08:00
// Release an interface for a select ip
2015-04-04 00:06:48 -04:00
func Release ( id string ) {
var containerInterface = currentInterfaces . Get ( id )
2014-01-29 16:59:21 -08:00
2014-02-06 03:18:12 -08:00
if containerInterface == nil {
2015-04-04 00:06:48 -04:00
logrus . Warnf ( "No network information to release for %s" , id )
2015-04-13 20:24:10 +08:00
return
2014-02-06 03:18:12 -08:00
}
2014-01-29 16:59:21 -08:00
for _ , nat := range containerInterface . PortMappings {
2015-03-30 18:06:16 -07:00
if err := portMapper . Unmap ( nat ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Infof ( "Unable to unmap port %s: %s" , nat , err )
2014-01-29 16:59:21 -08:00
}
}
2015-03-23 20:20:10 -07:00
if err := ipAllocator . ReleaseIP ( bridgeIPv4Network , containerInterface . IP ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Infof ( "Unable to release IPv4 %s" , err )
2015-01-09 00:03:19 +01:00
}
if globalIPv6Network != nil {
2015-03-23 20:20:10 -07:00
if err := ipAllocator . ReleaseIP ( globalIPv6Network , containerInterface . IPv6 ) ; err != nil {
2015-03-26 23:22:04 +01:00
logrus . Infof ( "Unable to release IPv6 %s" , err )
2015-01-09 00:03:19 +01:00
}
2014-01-29 16:59:21 -08:00
}
}
// Allocate an external port and map it to the interface
2015-04-04 00:06:48 -04:00
func AllocatePort ( id string , port nat . Port , binding nat . PortBinding ) ( nat . PortBinding , error ) {
2014-01-29 16:59:21 -08:00
var (
ip = defaultBindingIP
2015-04-04 00:06:48 -04:00
proto = port . Proto ( )
containerPort = port . Int ( )
2014-05-29 16:28:06 +04:00
network = currentInterfaces . Get ( id )
2014-01-29 16:59:21 -08:00
)
2015-04-04 00:06:48 -04:00
if binding . HostIp != "" {
ip = net . ParseIP ( binding . HostIp )
2014-09-19 21:31:57 +09:00
if ip == nil {
2015-04-04 00:06:48 -04:00
return nat . PortBinding { } , fmt . Errorf ( "Bad parameter: invalid host ip %s" , binding . HostIp )
2014-09-19 21:31:57 +09:00
}
2014-01-29 16:59:21 -08:00
}
2014-06-19 23:33:51 +02:00
// host ip, proto, and host port
var container net . Addr
switch proto {
case "tcp" :
container = & net . TCPAddr { IP : network . IP , Port : containerPort }
case "udp" :
container = & net . UDPAddr { IP : network . IP , Port : containerPort }
default :
2015-04-04 00:06:48 -04:00
return nat . PortBinding { } , fmt . Errorf ( "unsupported address type %s" , proto )
2014-06-19 23:33:51 +02:00
}
2014-01-29 16:59:21 -08:00
2014-06-26 00:09:19 -07:00
//
// Try up to 10 times to get a port that's not already allocated.
//
// In the event of failure to bind, return the error that portmapper.Map
// yields.
//
2014-05-20 21:19:55 -07:00
2015-04-04 00:06:48 -04:00
var (
host net . Addr
err error
)
hostPort , err := nat . ParsePort ( binding . HostPort )
if err != nil {
return nat . PortBinding { } , err
}
2014-06-26 00:09:19 -07:00
for i := 0 ; i < MaxAllocatedPortAttempts ; i ++ {
2015-03-30 18:06:16 -07:00
if host , err = portMapper . Map ( container , ip , hostPort ) ; err == nil {
2014-06-19 23:33:51 +02:00
break
2014-05-20 21:19:55 -07:00
}
2014-12-01 16:24:43 -08:00
// There is no point in immediately retrying to map an explicitly
// chosen port.
if hostPort != 0 {
2015-03-26 23:22:04 +01:00
logrus . Warnf ( "Failed to allocate and map port %d: %s" , hostPort , err )
2014-05-20 21:19:55 -07:00
break
}
2015-03-26 23:22:04 +01:00
logrus . Warnf ( "Failed to allocate and map port: %s, retry: %d" , err , i + 1 )
2014-01-29 16:59:21 -08:00
}
2014-05-20 21:19:55 -07:00
if err != nil {
2015-04-04 00:06:48 -04:00
return nat . PortBinding { } , err
2014-01-29 16:59:21 -08:00
}
2014-05-20 21:19:55 -07:00
2014-01-29 16:59:21 -08:00
network . PortMappings = append ( network . PortMappings , host )
2014-06-19 23:33:51 +02:00
switch netAddr := host . ( type ) {
case * net . TCPAddr :
2015-04-04 00:06:48 -04:00
return nat . PortBinding { HostIp : netAddr . IP . String ( ) , HostPort : strconv . Itoa ( netAddr . Port ) } , nil
2014-06-19 23:33:51 +02:00
case * net . UDPAddr :
2015-04-04 00:06:48 -04:00
return nat . PortBinding { HostIp : netAddr . IP . String ( ) , HostPort : strconv . Itoa ( netAddr . Port ) } , nil
default :
return nat . PortBinding { } , fmt . Errorf ( "unsupported address type %T" , netAddr )
2014-01-30 14:52:59 -08:00
}
2014-01-29 16:59:21 -08:00
}
2014-01-30 12:43:49 -08:00
2015-04-04 00:06:48 -04:00
//TODO: should it return something more than just an error?
func LinkContainers ( action , parentIP , childIP string , ports [ ] nat . Port , ignoreErrors bool ) error {
var nfAction iptables . Action
2014-06-27 17:29:55 +10:00
switch action {
case "-A" :
nfAction = iptables . Append
case "-I" :
nfAction = iptables . Insert
case "-D" :
nfAction = iptables . Delete
default :
2015-03-25 08:44:12 +01:00
return fmt . Errorf ( "Invalid action '%s' specified" , action )
2014-06-27 17:29:55 +10:00
}
2014-02-09 01:43:46 -08:00
2014-06-27 17:29:55 +10:00
ip1 := net . ParseIP ( parentIP )
if ip1 == nil {
2015-03-25 08:44:12 +01:00
return fmt . Errorf ( "Parent IP '%s' is invalid" , parentIP )
2014-06-27 17:29:55 +10:00
}
ip2 := net . ParseIP ( childIP )
if ip2 == nil {
2015-03-25 08:44:12 +01:00
return fmt . Errorf ( "Child IP '%s' is invalid" , childIP )
2014-06-27 17:29:55 +10:00
}
2014-12-21 13:42:02 +10:00
chain := iptables . Chain { Name : "DOCKER" , Bridge : bridgeIface }
2015-04-04 00:06:48 -04:00
for _ , port := range ports {
2014-11-15 11:36:38 +10:00
if err := chain . Link ( nfAction , ip1 , ip2 , port . Int ( ) , port . Proto ( ) ) ; ! ignoreErrors && err != nil {
2015-03-25 08:44:12 +01:00
return err
2014-02-09 01:43:46 -08:00
}
2014-01-30 12:43:49 -08:00
}
2015-03-25 08:44:12 +01:00
return nil
2014-01-30 12:43:49 -08:00
}