1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Remove jobs from daemon/networkdriver/bridge

Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
Tibor Vass 2015-04-04 00:06:48 -04:00
parent 7233bd223d
commit 53582321ee
11 changed files with 233 additions and 433 deletions

View file

@ -1,10 +1,10 @@
package client package client
import ( import (
"encoding/json"
"fmt" "fmt"
"strings" "strings"
"github.com/docker/docker/engine"
"github.com/docker/docker/nat" "github.com/docker/docker/nat"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
) )
@ -23,12 +23,13 @@ func (cli *DockerCli) CmdPort(args ...string) error {
return err return err
} }
env := engine.Env{} var c struct {
if err := env.Decode(stream); err != nil { NetworkSettings struct {
return err Ports nat.PortMap
}
} }
ports := nat.PortMap{}
if err := env.GetSubEnv("NetworkSettings").GetJson("Ports", &ports); err != nil { if err := json.NewDecoder(stream).Decode(&c); err != nil {
return err return err
} }
@ -44,7 +45,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
proto = parts[1] proto = parts[1]
} }
natPort := port + "/" + proto natPort := port + "/" + proto
if frontends, exists := ports[nat.Port(port+"/"+proto)]; exists && frontends != nil { if frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
for _, frontend := range frontends { for _, frontend := range frontends {
fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort) fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
} }
@ -53,7 +54,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0)) return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
} }
for from, frontends := range ports { for from, frontends := range c.NetworkSettings.Ports {
for _, frontend := range frontends { for _, frontend := range frontends {
fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort) fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIp, frontend.HostPort)
} }

View file

@ -6,15 +6,11 @@ import (
"github.com/docker/docker/api" "github.com/docker/docker/api"
apiserver "github.com/docker/docker/api/server" apiserver "github.com/docker/docker/api/server"
"github.com/docker/docker/autogen/dockerversion" "github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine" "github.com/docker/docker/engine"
"github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/kernel"
) )
func Register(eng *engine.Engine) error { func Register(eng *engine.Engine) error {
if err := daemon(eng); err != nil {
return err
}
if err := remote(eng); err != nil { if err := remote(eng); err != nil {
return err return err
} }
@ -33,25 +29,6 @@ func remote(eng *engine.Engine) error {
return eng.Register("acceptconnections", apiserver.AcceptConnections) return eng.Register("acceptconnections", apiserver.AcceptConnections)
} }
// daemon: a default execution and storage backend for Docker on Linux,
// with the following underlying components:
//
// * Pluggable storage drivers including aufs, vfs, lvm and btrfs.
// * Pluggable execution drivers including lxc and chroot.
//
// In practice `daemon` still includes most core Docker components, including:
//
// * The reference registry client implementation
// * Image management
// * The build facility
// * Logging
//
// These components should be broken off into plugins of their own.
//
func daemon(eng *engine.Engine) error {
return eng.Register("init_networkdriver", bridge.InitDriver)
}
// builtins jobs independent of any subsystem // builtins jobs independent of any subsystem
func dockerVersion(job *engine.Job) error { func dockerVersion(job *engine.Job) error {
v := &engine.Env{} v := &engine.Env{}

View file

@ -1,9 +1,8 @@
package daemon package daemon
import ( import (
"net"
"github.com/docker/docker/daemon/networkdriver" "github.com/docker/docker/daemon/networkdriver"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/opts" "github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/ulimit" "github.com/docker/docker/pkg/ulimit"
@ -20,35 +19,27 @@ const (
// to the docker daemon when you launch it with say: `docker -d -e lxc` // to the docker daemon when you launch it with say: `docker -d -e lxc`
// FIXME: separate runtime configuration from http api configuration // FIXME: separate runtime configuration from http api configuration
type Config struct { type Config struct {
Pidfile string Bridge bridge.Config
Root string
AutoRestart bool Pidfile string
Dns []string Root string
DnsSearch []string AutoRestart bool
EnableIPv6 bool Dns []string
EnableIptables bool DnsSearch []string
EnableIpForward bool GraphDriver string
EnableIpMasq bool GraphOptions []string
DefaultIp net.IP ExecDriver string
BridgeIface string Mtu int
BridgeIP string SocketGroup string
FixedCIDR string EnableCors bool
FixedCIDRv6 string CorsHeaders string
InterContainerCommunication bool DisableNetwork bool
GraphDriver string EnableSelinuxSupport bool
GraphOptions []string Context map[string][]string
ExecDriver string TrustKeyPath string
Mtu int Labels []string
SocketGroup string Ulimits map[string]*ulimit.Ulimit
EnableCors bool LogConfig runconfig.LogConfig
CorsHeaders string
DisableNetwork bool
EnableSelinuxSupport bool
Context map[string][]string
TrustKeyPath string
Labels []string
Ulimits map[string]*ulimit.Ulimit
LogConfig runconfig.LogConfig
} }
// InstallFlags adds command-line options to the top-level flag parser for // InstallFlags adds command-line options to the top-level flag parser for
@ -59,15 +50,15 @@ func (config *Config) InstallFlags() {
flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") flag.StringVar(&config.Pidfile, []string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file")
flag.StringVar(&config.Root, []string{"g", "-graph"}, "/var/lib/docker", "Root of the Docker runtime") flag.StringVar(&config.Root, []string{"g", "-graph"}, "/var/lib/docker", "Root of the Docker runtime")
flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run") flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
flag.BoolVar(&config.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules") flag.BoolVar(&config.Bridge.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
flag.BoolVar(&config.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward") flag.BoolVar(&config.Bridge.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
flag.BoolVar(&config.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading") flag.BoolVar(&config.Bridge.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
flag.BoolVar(&config.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking") flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Specify network bridge IP") flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
flag.StringVar(&config.BridgeIface, []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.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.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.BoolVar(&config.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")
flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support") flag.BoolVar(&config.EnableSelinuxSupport, []string{"-selinux-enabled"}, false, "Enable selinux support")
@ -75,7 +66,7 @@ func (config *Config) InstallFlags() {
flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket") flag.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", "Group for the unix socket")
flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header") flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API") flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
opts.IPVar(&config.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports") opts.IPVar(&config.Bridge.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options") opts.ListVar(&config.GraphOptions, []string{"-storage-opt"}, "Set storage driver options")
// FIXME: why the inconsistency between "hosts" and "sockets"? // FIXME: why the inconsistency between "hosts" and "sockets"?
opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use") opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")

View file

@ -24,6 +24,8 @@ import (
"github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/jsonfilelog" "github.com/docker/docker/daemon/logger/jsonfilelog"
"github.com/docker/docker/daemon/logger/syslog" "github.com/docker/docker/daemon/logger/syslog"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine" "github.com/docker/docker/engine"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/links" "github.com/docker/docker/links"
@ -73,7 +75,7 @@ type Container struct {
Config *runconfig.Config Config *runconfig.Config
ImageID string `json:"Image"` ImageID string `json:"Image"`
NetworkSettings *NetworkSettings NetworkSettings *network.Settings
ResolvConfPath string ResolvConfPath string
HostnamePath string HostnamePath string
@ -571,17 +573,12 @@ func (container *Container) AllocateNetwork() error {
} }
var ( var (
env *engine.Env
err error err error
eng = container.daemon.eng eng = container.daemon.eng
) )
job := eng.Job("allocate_interface", container.ID) networkSettings, err := bridge.Allocate(container.ID, container.Config.MacAddress, "", "")
job.Setenv("RequestedMac", container.Config.MacAddress) if err != nil {
if env, err = job.Stdout.AddEnv(); err != nil {
return err
}
if err = job.Run(); err != nil {
return err return err
} }
@ -591,12 +588,12 @@ func (container *Container) AllocateNetwork() error {
if container.Config.PortSpecs != nil { if container.Config.PortSpecs != nil {
if err = migratePortMappings(container.Config, container.hostConfig); err != nil { if err = migratePortMappings(container.Config, container.hostConfig); err != nil {
eng.Job("release_interface", container.ID).Run() bridge.Release(container.ID)
return err return err
} }
container.Config.PortSpecs = nil container.Config.PortSpecs = nil
if err = container.WriteHostConfig(); err != nil { if err = container.WriteHostConfig(); err != nil {
eng.Job("release_interface", container.ID).Run() bridge.Release(container.ID)
return err return err
} }
} }
@ -626,23 +623,14 @@ func (container *Container) AllocateNetwork() error {
for port := range portSpecs { for port := range portSpecs {
if err = container.allocatePort(eng, port, bindings); err != nil { if err = container.allocatePort(eng, port, bindings); err != nil {
eng.Job("release_interface", container.ID).Run() bridge.Release(container.ID)
return err return err
} }
} }
container.WriteHostConfig() container.WriteHostConfig()
container.NetworkSettings.Ports = bindings networkSettings.Ports = bindings
container.NetworkSettings.Bridge = env.Get("Bridge") container.NetworkSettings = networkSettings
container.NetworkSettings.IPAddress = env.Get("IP")
container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
container.NetworkSettings.MacAddress = env.Get("MacAddress")
container.NetworkSettings.Gateway = env.Get("Gateway")
container.NetworkSettings.LinkLocalIPv6Address = env.Get("LinkLocalIPv6")
container.NetworkSettings.LinkLocalIPv6PrefixLen = 64
container.NetworkSettings.GlobalIPv6Address = env.Get("GlobalIPv6")
container.NetworkSettings.GlobalIPv6PrefixLen = env.GetInt("GlobalIPv6PrefixLen")
container.NetworkSettings.IPv6Gateway = env.Get("IPv6Gateway")
return nil return nil
} }
@ -651,12 +639,10 @@ func (container *Container) ReleaseNetwork() {
if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() { if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() {
return return
} }
eng := container.daemon.eng
job := eng.Job("release_interface", container.ID) bridge.Release(container.ID)
job.SetenvBool("overrideShutdown", true)
job.Run() container.NetworkSettings = &network.Settings{}
container.NetworkSettings = &NetworkSettings{}
} }
func (container *Container) isNetworkAllocated() bool { func (container *Container) isNetworkAllocated() bool {
@ -675,10 +661,7 @@ func (container *Container) RestoreNetwork() error {
eng := container.daemon.eng eng := container.daemon.eng
// Re-allocate the interface with the same IP and MAC address. // Re-allocate the interface with the same IP and MAC address.
job := eng.Job("allocate_interface", container.ID) if _, err := bridge.Allocate(container.ID, container.NetworkSettings.MacAddress, container.NetworkSettings.IPAddress, ""); err != nil {
job.Setenv("RequestedIP", container.NetworkSettings.IPAddress)
job.Setenv("RequestedMac", container.NetworkSettings.MacAddress)
if err := job.Run(); err != nil {
return err return err
} }
@ -1077,7 +1060,7 @@ func (container *Container) setupContainerDns() error {
latestResolvConf, latestHash := resolvconf.GetLastModified() latestResolvConf, latestHash := resolvconf.GetLastModified()
// clean container resolv.conf re: localhost nameservers and IPv6 NS (if IPv6 disabled) // clean container resolv.conf re: localhost nameservers and IPv6 NS (if IPv6 disabled)
updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.EnableIPv6) updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.Bridge.EnableIPv6)
if modified { if modified {
// changes have occurred during resolv.conf localhost cleanup: generate an updated hash // changes have occurred during resolv.conf localhost cleanup: generate an updated hash
newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf)) newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf))
@ -1131,7 +1114,7 @@ func (container *Container) setupContainerDns() error {
} }
// replace any localhost/127.*, and remove IPv6 nameservers if IPv6 disabled in daemon // replace any localhost/127.*, and remove IPv6 nameservers if IPv6 disabled in daemon
resolvConf, _ = resolvconf.FilterResolvDns(resolvConf, daemon.config.EnableIPv6) resolvConf, _ = resolvconf.FilterResolvDns(resolvConf, daemon.config.Bridge.EnableIPv6)
} }
//get a sha256 hash of the resolv conf at this point so we can check //get a sha256 hash of the resolv conf at this point so we can check
//for changes when the host resolv.conf changes (e.g. network update) //for changes when the host resolv.conf changes (e.g. network update)
@ -1481,24 +1464,10 @@ func (container *Container) allocatePort(eng *engine.Engine, port nat.Port, bind
} }
for i := 0; i < len(binding); i++ { for i := 0; i < len(binding); i++ {
b := binding[i] b, err := bridge.AllocatePort(container.ID, port, binding[i])
job := eng.Job("allocate_port", container.ID)
job.Setenv("HostIP", b.HostIp)
job.Setenv("HostPort", b.HostPort)
job.Setenv("Proto", port.Proto())
job.Setenv("ContainerPort", port.Port())
portEnv, err := job.Stdout.AddEnv()
if err != nil { if err != nil {
return err return err
} }
if err := job.Run(); err != nil {
return err
}
b.HostIp = portEnv.Get("HostIP")
b.HostPort = portEnv.Get("HostPort")
binding[i] = b binding[i] = b
} }
bindings[port] = binding bindings[port] = binding

View file

@ -25,7 +25,8 @@ import (
"github.com/docker/docker/daemon/execdriver/lxc" "github.com/docker/docker/daemon/execdriver/lxc"
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
_ "github.com/docker/docker/daemon/graphdriver/vfs" _ "github.com/docker/docker/daemon/graphdriver/vfs"
_ "github.com/docker/docker/daemon/networkdriver/bridge" "github.com/docker/docker/daemon/network"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine" "github.com/docker/docker/engine"
"github.com/docker/docker/graph" "github.com/docker/docker/graph"
"github.com/docker/docker/image" "github.com/docker/docker/image"
@ -445,7 +446,7 @@ func (daemon *Daemon) setupResolvconfWatcher() error {
logrus.Debugf("Error retrieving updated host resolv.conf: %v", err) logrus.Debugf("Error retrieving updated host resolv.conf: %v", err)
} else if updatedResolvConf != nil { } else if updatedResolvConf != nil {
// because the new host resolv.conf might have localhost nameservers.. // because the new host resolv.conf might have localhost nameservers..
updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.EnableIPv6) updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.Bridge.EnableIPv6)
if modified { if modified {
// changes have occurred during localhost cleanup: generate an updated hash // changes have occurred during localhost cleanup: generate an updated hash
newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf)) newHash, err := utils.HashData(bytes.NewReader(updatedResolvConf))
@ -653,7 +654,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
Config: config, Config: config,
hostConfig: &runconfig.HostConfig{}, hostConfig: &runconfig.HostConfig{},
ImageID: imgID, ImageID: imgID,
NetworkSettings: &NetworkSettings{}, NetworkSettings: &network.Settings{},
Name: name, Name: name,
Driver: daemon.driver.String(), Driver: daemon.driver.String(),
ExecDriver: daemon.execDriver.Name(), ExecDriver: daemon.execDriver.Name(),
@ -807,16 +808,16 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
config.Mtu = getDefaultNetworkMtu() config.Mtu = getDefaultNetworkMtu()
} }
// Check for mutually incompatible config options // Check for mutually incompatible config options
if config.BridgeIface != "" && config.BridgeIP != "" { if config.Bridge.Iface != "" && config.Bridge.IP != "" {
return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.") return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
} }
if !config.EnableIptables && !config.InterContainerCommunication { if !config.Bridge.EnableIptables && !config.Bridge.InterContainerCommunication {
return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.") return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
} }
if !config.EnableIptables && config.EnableIpMasq { if !config.Bridge.EnableIptables && config.Bridge.EnableIpMasq {
config.EnableIpMasq = false config.Bridge.EnableIpMasq = false
} }
config.DisableNetwork = config.BridgeIface == disableNetworkBridge config.DisableNetwork = config.Bridge.Iface == disableNetworkBridge
// Claim the pidfile first, to avoid any and all unexpected race conditions. // Claim the pidfile first, to avoid any and all unexpected race conditions.
// Some of the init doesn't need a pidfile lock - but let's not try to be smart. // Some of the init doesn't need a pidfile lock - but let's not try to be smart.
@ -948,20 +949,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine, registryService
} }
if !config.DisableNetwork { if !config.DisableNetwork {
job := eng.Job("init_networkdriver") if err := bridge.InitDriver(&config.Bridge); err != nil {
job.SetenvBool("EnableIptables", config.EnableIptables)
job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
job.SetenvBool("EnableIpForward", config.EnableIpForward)
job.SetenvBool("EnableIpMasq", config.EnableIpMasq)
job.SetenvBool("EnableIPv6", config.EnableIPv6)
job.Setenv("BridgeIface", config.BridgeIface)
job.Setenv("BridgeIP", config.BridgeIP)
job.Setenv("FixedCIDR", config.FixedCIDR)
job.Setenv("FixedCIDRv6", config.FixedCIDRv6)
job.Setenv("DefaultBindingIP", config.DefaultIp.String())
if err := job.Run(); err != nil {
return nil, err return nil, err
} }
} }

View file

@ -1,13 +1,8 @@
package daemon package network
import ( import "github.com/docker/docker/nat"
"github.com/docker/docker/nat"
)
// FIXME: move deprecated port stuff to nat to clean up the core. type Settings struct {
type PortMapping map[string]string // Deprecated
type NetworkSettings struct {
IPAddress string IPAddress string
IPPrefixLen int IPPrefixLen int
MacAddress string MacAddress string
@ -18,6 +13,6 @@ type NetworkSettings struct {
Gateway string Gateway string
IPv6Gateway string IPv6Gateway string
Bridge string Bridge string
PortMapping map[string]PortMapping // Deprecated PortMapping map[string]map[string]string // Deprecated
Ports nat.PortMap Ports nat.PortMap
} }

View file

@ -7,14 +7,15 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"os" "os"
"strconv"
"strings" "strings"
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/daemon/networkdriver" "github.com/docker/docker/daemon/networkdriver"
"github.com/docker/docker/daemon/networkdriver/ipallocator" "github.com/docker/docker/daemon/networkdriver/ipallocator"
"github.com/docker/docker/daemon/networkdriver/portmapper" "github.com/docker/docker/daemon/networkdriver/portmapper"
"github.com/docker/docker/engine"
"github.com/docker/docker/nat" "github.com/docker/docker/nat"
"github.com/docker/docker/pkg/iptables" "github.com/docker/docker/pkg/iptables"
"github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/kernel"
@ -91,29 +92,34 @@ func initPortMapper() {
}) })
} }
func InitDriver(job *engine.Job) error { type Config struct {
EnableIPv6 bool
EnableIptables bool
EnableIpForward bool
EnableIpMasq bool
DefaultIp net.IP
Iface string
IP string
FixedCIDR string
FixedCIDRv6 string
InterContainerCommunication bool
}
func InitDriver(config *Config) error {
var ( var (
networkv4 *net.IPNet networkv4 *net.IPNet
networkv6 *net.IPNet networkv6 *net.IPNet
addrv4 net.Addr addrv4 net.Addr
addrsv6 []net.Addr addrsv6 []net.Addr
enableIPTables = job.GetenvBool("EnableIptables") bridgeIPv6 = "fe80::1/64"
enableIPv6 = job.GetenvBool("EnableIPv6")
icc = job.GetenvBool("InterContainerCommunication")
ipMasq = job.GetenvBool("EnableIpMasq")
ipForward = job.GetenvBool("EnableIpForward")
bridgeIP = job.Getenv("BridgeIP")
bridgeIPv6 = "fe80::1/64"
fixedCIDR = job.Getenv("FixedCIDR")
fixedCIDRv6 = job.Getenv("FixedCIDRv6")
) )
initPortMapper() initPortMapper()
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" { if config.DefaultIp != nil {
defaultBindingIP = net.ParseIP(defaultIP) defaultBindingIP = config.DefaultIp
} }
bridgeIface = job.Getenv("BridgeIface") bridgeIface = config.Iface
usingDefaultBridge := false usingDefaultBridge := false
if bridgeIface == "" { if bridgeIface == "" {
usingDefaultBridge = true usingDefaultBridge = true
@ -130,7 +136,7 @@ func InitDriver(job *engine.Job) error {
} }
// If the iface is not found, try to create it // If the iface is not found, try to create it
if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil { if err := configureBridge(config.IP, bridgeIPv6, config.EnableIPv6); err != nil {
return err return err
} }
@ -139,19 +145,19 @@ func InitDriver(job *engine.Job) error {
return err return err
} }
if fixedCIDRv6 != "" { if config.FixedCIDRv6 != "" {
// Setting route to global IPv6 subnet // Setting route to global IPv6 subnet
logrus.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) logrus.Infof("Adding route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface)
if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil { if err := netlink.AddRoute(config.FixedCIDRv6, "", "", bridgeIface); err != nil {
logrus.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) logrus.Fatalf("Could not add route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface)
} }
} }
} else { } else {
// Bridge exists already, getting info... // Bridge exists already, getting info...
// Validate that the bridge ip matches the ip specified by BridgeIP // Validate that the bridge ip matches the ip specified by BridgeIP
if bridgeIP != "" { if config.IP != "" {
networkv4 = addrv4.(*net.IPNet) networkv4 = addrv4.(*net.IPNet)
bip, _, err := net.ParseCIDR(bridgeIP) bip, _, err := net.ParseCIDR(config.IP)
if err != nil { if err != nil {
return err return err
} }
@ -164,7 +170,7 @@ func InitDriver(job *engine.Job) error {
// (for example, an existing Docker installation that has only been used // (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 // 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 // the bridge init for IPv6 here, else we will error out below if --ipv6=true
if len(addrsv6) == 0 && enableIPv6 { if len(addrsv6) == 0 && config.EnableIPv6 {
if err := setupIPv6Bridge(bridgeIPv6); err != nil { if err := setupIPv6Bridge(bridgeIPv6); err != nil {
return err return err
} }
@ -175,10 +181,10 @@ func InitDriver(job *engine.Job) error {
} }
} }
// TODO: Check if route to fixedCIDRv6 is set // TODO: Check if route to config.FixedCIDRv6 is set
} }
if enableIPv6 { if config.EnableIPv6 {
bip6, _, err := net.ParseCIDR(bridgeIPv6) bip6, _, err := net.ParseCIDR(bridgeIPv6)
if err != nil { if err != nil {
return err return err
@ -198,7 +204,7 @@ func InitDriver(job *engine.Job) error {
networkv4 = addrv4.(*net.IPNet) networkv4 = addrv4.(*net.IPNet)
if enableIPv6 { if config.EnableIPv6 {
if len(addrsv6) == 0 { if len(addrsv6) == 0 {
return errors.New("IPv6 enabled but no IPv6 detected") return errors.New("IPv6 enabled but no IPv6 detected")
} }
@ -206,20 +212,20 @@ func InitDriver(job *engine.Job) error {
} }
// Configure iptables for link support // Configure iptables for link support
if enableIPTables { if config.EnableIptables {
if err := setupIPTables(addrv4, icc, ipMasq); err != nil { if err := setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq); err != nil {
return err return err
} }
} }
if ipForward { if config.EnableIpForward {
// Enable IPv4 forwarding // Enable IPv4 forwarding
if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
logrus.Warnf("WARNING: unable to enable IPv4 forwarding: %s\n", err) logrus.Warnf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
} }
if fixedCIDRv6 != "" { if config.FixedCIDRv6 != "" {
// Enable IPv6 forwarding // Enable IPv6 forwarding
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil {
logrus.Warnf("WARNING: unable to enable IPv6 default forwarding: %s\n", err) logrus.Warnf("WARNING: unable to enable IPv6 default forwarding: %s\n", err)
@ -235,7 +241,7 @@ func InitDriver(job *engine.Job) error {
return err return err
} }
if enableIPTables { if config.EnableIptables {
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat) _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat)
if err != nil { if err != nil {
return err return err
@ -248,8 +254,8 @@ func InitDriver(job *engine.Job) error {
} }
bridgeIPv4Network = networkv4 bridgeIPv4Network = networkv4
if fixedCIDR != "" { if config.FixedCIDR != "" {
_, subnet, err := net.ParseCIDR(fixedCIDR) _, subnet, err := net.ParseCIDR(config.FixedCIDR)
if err != nil { if err != nil {
return err return err
} }
@ -259,8 +265,8 @@ func InitDriver(job *engine.Job) error {
} }
} }
if fixedCIDRv6 != "" { if config.FixedCIDRv6 != "" {
_, subnet, err := net.ParseCIDR(fixedCIDRv6) _, subnet, err := net.ParseCIDR(config.FixedCIDRv6)
if err != nil { if err != nil {
return err return err
} }
@ -274,19 +280,6 @@ func InitDriver(job *engine.Job) error {
// Block BridgeIP in IP allocator // Block BridgeIP in IP allocator
ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
// https://github.com/docker/docker/issues/2768
job.Eng.HackSetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP)
for name, f := range map[string]engine.Handler{
"allocate_interface": Allocate,
"release_interface": Release,
"allocate_port": AllocatePort,
"link": LinkContainers,
} {
if err := job.Eng.Register(name, f); err != nil {
return err
}
}
return nil return nil
} }
@ -513,70 +506,67 @@ func linkLocalIPv6FromMac(mac string) (string, error) {
} }
// Allocate a network interface // Allocate a network interface
func Allocate(job *engine.Job) error { func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Settings, error) {
var ( var (
ip net.IP ip net.IP
mac net.HardwareAddr mac net.HardwareAddr
err error err error
id = job.Args[0] globalIPv6 net.IP
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6"))
globalIPv6 net.IP
) )
ip, err = ipAllocator.RequestIP(bridgeIPv4Network, requestedIP) ip, err = ipAllocator.RequestIP(bridgeIPv4Network, net.ParseIP(requestedIP))
if err != nil { if err != nil {
return err return nil, err
} }
// If no explicit mac address was given, generate a random one. // If no explicit mac address was given, generate a random one.
if mac, err = net.ParseMAC(job.Getenv("RequestedMac")); err != nil { if mac, err = net.ParseMAC(requestedMac); err != nil {
mac = generateMacAddr(ip) mac = generateMacAddr(ip)
} }
if globalIPv6Network != nil { if globalIPv6Network != nil {
// If globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address // If globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address
netmaskOnes, _ := globalIPv6Network.Mask.Size() netmaskOnes, _ := globalIPv6Network.Mask.Size()
if requestedIPv6 == nil && netmaskOnes <= 80 { ipv6 := net.ParseIP(requestedIPv6)
requestedIPv6 = make(net.IP, len(globalIPv6Network.IP)) if ipv6 == nil && netmaskOnes <= 80 {
copy(requestedIPv6, globalIPv6Network.IP) ipv6 = make(net.IP, len(globalIPv6Network.IP))
copy(ipv6, globalIPv6Network.IP)
for i, h := range mac { for i, h := range mac {
requestedIPv6[i+10] = h ipv6[i+10] = h
} }
} }
globalIPv6, err = ipAllocator.RequestIP(globalIPv6Network, requestedIPv6) globalIPv6, err = ipAllocator.RequestIP(globalIPv6Network, ipv6)
if err != nil { if err != nil {
logrus.Errorf("Allocator: RequestIP v6: %v", err) logrus.Errorf("Allocator: RequestIP v6: %v", err)
return err return nil, err
} }
logrus.Infof("Allocated IPv6 %s", globalIPv6) logrus.Infof("Allocated IPv6 %s", globalIPv6)
} }
out := engine.Env{} maskSize, _ := bridgeIPv4Network.Mask.Size()
out.Set("IP", ip.String())
out.Set("Mask", bridgeIPv4Network.Mask.String())
out.Set("Gateway", bridgeIPv4Network.IP.String())
out.Set("MacAddress", mac.String())
out.Set("Bridge", bridgeIface)
size, _ := bridgeIPv4Network.Mask.Size()
out.SetInt("IPPrefixLen", size)
// If linklocal IPv6 // If linklocal IPv6
localIPv6Net, err := linkLocalIPv6FromMac(mac.String()) localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
if err != nil { if err != nil {
return err return nil, err
} }
localIPv6, _, _ := net.ParseCIDR(localIPv6Net) localIPv6, _, _ := net.ParseCIDR(localIPv6Net)
out.Set("LinkLocalIPv6", localIPv6.String())
out.Set("MacAddress", mac.String()) networkSettings := &network.Settings{
IPAddress: ip.String(),
Gateway: bridgeIPv4Network.IP.String(),
MacAddress: mac.String(),
Bridge: bridgeIface,
IPPrefixLen: maskSize,
LinkLocalIPv6Address: localIPv6.String(),
}
if globalIPv6Network != nil { if globalIPv6Network != nil {
out.Set("GlobalIPv6", globalIPv6.String()) networkSettings.GlobalIPv6Address = globalIPv6.String()
sizev6, _ := globalIPv6Network.Mask.Size() maskV6Size, _ := globalIPv6Network.Mask.Size()
out.SetInt("GlobalIPv6PrefixLen", sizev6) networkSettings.GlobalIPv6PrefixLen = maskV6Size
out.Set("IPv6Gateway", bridgeIPv6Addr.String()) networkSettings.IPv6Gateway = bridgeIPv6Addr.String()
} }
currentInterfaces.Set(id, &networkInterface{ currentInterfaces.Set(id, &networkInterface{
@ -584,20 +574,15 @@ func Allocate(job *engine.Job) error {
IPv6: globalIPv6, IPv6: globalIPv6,
}) })
out.WriteTo(job.Stdout) return networkSettings, nil
return nil
} }
// Release an interface for a select ip // Release an interface for a select ip
func Release(job *engine.Job) error { func Release(id string) {
var ( var containerInterface = currentInterfaces.Get(id)
id = job.Args[0]
containerInterface = currentInterfaces.Get(id)
)
if containerInterface == nil { if containerInterface == nil {
return fmt.Errorf("No network information to release for %s", id) logrus.Warnf("No network information to release for %s", id)
} }
for _, nat := range containerInterface.PortMappings { for _, nat := range containerInterface.PortMappings {
@ -614,27 +599,21 @@ func Release(job *engine.Job) error {
logrus.Infof("Unable to release IPv6 %s", err) logrus.Infof("Unable to release IPv6 %s", err)
} }
} }
return nil
} }
// Allocate an external port and map it to the interface // Allocate an external port and map it to the interface
func AllocatePort(job *engine.Job) error { func AllocatePort(id string, port nat.Port, binding nat.PortBinding) (nat.PortBinding, error) {
var ( var (
err error
ip = defaultBindingIP ip = defaultBindingIP
id = job.Args[0] proto = port.Proto()
hostIP = job.Getenv("HostIP") containerPort = port.Int()
hostPort = job.GetenvInt("HostPort")
containerPort = job.GetenvInt("ContainerPort")
proto = job.Getenv("Proto")
network = currentInterfaces.Get(id) network = currentInterfaces.Get(id)
) )
if hostIP != "" { if binding.HostIp != "" {
ip = net.ParseIP(hostIP) ip = net.ParseIP(binding.HostIp)
if ip == nil { if ip == nil {
return fmt.Errorf("Bad parameter: invalid host ip %s", hostIP) return nat.PortBinding{}, fmt.Errorf("Bad parameter: invalid host ip %s", binding.HostIp)
} }
} }
@ -646,7 +625,7 @@ func AllocatePort(job *engine.Job) error {
case "udp": case "udp":
container = &net.UDPAddr{IP: network.IP, Port: containerPort} container = &net.UDPAddr{IP: network.IP, Port: containerPort}
default: default:
return fmt.Errorf("unsupported address type %s", proto) return nat.PortBinding{}, fmt.Errorf("unsupported address type %s", proto)
} }
// //
@ -656,7 +635,14 @@ func AllocatePort(job *engine.Job) error {
// yields. // yields.
// //
var host net.Addr var (
host net.Addr
err error
)
hostPort, err := nat.ParsePort(binding.HostPort)
if err != nil {
return nat.PortBinding{}, err
}
for i := 0; i < MaxAllocatedPortAttempts; i++ { for i := 0; i < MaxAllocatedPortAttempts; i++ {
if host, err = portMapper.Map(container, ip, hostPort); err == nil { if host, err = portMapper.Map(container, ip, hostPort); err == nil {
break break
@ -671,36 +657,24 @@ func AllocatePort(job *engine.Job) error {
} }
if err != nil { if err != nil {
return err return nat.PortBinding{}, err
} }
network.PortMappings = append(network.PortMappings, host) network.PortMappings = append(network.PortMappings, host)
out := engine.Env{}
switch netAddr := host.(type) { switch netAddr := host.(type) {
case *net.TCPAddr: case *net.TCPAddr:
out.Set("HostIP", netAddr.IP.String()) return nat.PortBinding{HostIp: netAddr.IP.String(), HostPort: strconv.Itoa(netAddr.Port)}, nil
out.SetInt("HostPort", netAddr.Port)
case *net.UDPAddr: case *net.UDPAddr:
out.Set("HostIP", netAddr.IP.String()) return nat.PortBinding{HostIp: netAddr.IP.String(), HostPort: strconv.Itoa(netAddr.Port)}, nil
out.SetInt("HostPort", netAddr.Port) default:
return nat.PortBinding{}, fmt.Errorf("unsupported address type %T", netAddr)
} }
if _, err := out.WriteTo(job.Stdout); err != nil {
return err
}
return nil
} }
func LinkContainers(job *engine.Job) error { //TODO: should it return something more than just an error?
var ( func LinkContainers(action, parentIP, childIP string, ports []nat.Port, ignoreErrors bool) error {
action = job.Args[0] var nfAction iptables.Action
nfAction iptables.Action
childIP = job.Getenv("ChildIP")
parentIP = job.Getenv("ParentIP")
ignoreErrors = job.GetenvBool("IgnoreErrors")
ports = job.GetenvList("Ports")
)
switch action { switch action {
case "-A": case "-A":
@ -723,8 +697,7 @@ func LinkContainers(job *engine.Job) error {
} }
chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface} chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface}
for _, p := range ports { for _, port := range ports {
port := nat.Port(p)
if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil { if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil {
return err return err
} }

View file

@ -6,8 +6,9 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/docker/docker/daemon/network"
"github.com/docker/docker/daemon/networkdriver/portmapper" "github.com/docker/docker/daemon/networkdriver/portmapper"
"github.com/docker/docker/engine" "github.com/docker/docker/nat"
"github.com/docker/docker/pkg/iptables" "github.com/docker/docker/pkg/iptables"
) )
@ -16,7 +17,7 @@ func init() {
portmapper.NewProxy = portmapper.NewMockProxyCommand portmapper.NewProxy = portmapper.NewMockProxyCommand
} }
func findFreePort(t *testing.T) int { func findFreePort(t *testing.T) string {
l, err := net.Listen("tcp", ":0") l, err := net.Listen("tcp", ":0")
if err != nil { if err != nil {
t.Fatal("Failed to find a free port") t.Fatal("Failed to find a free port")
@ -27,143 +28,85 @@ func findFreePort(t *testing.T) int {
if err != nil { if err != nil {
t.Fatal("Failed to resolve address to identify free port") t.Fatal("Failed to resolve address to identify free port")
} }
return result.Port return strconv.Itoa(result.Port)
}
func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
strPort := strconv.Itoa(port)
job = eng.Job("allocate_port", "container_id")
job.Setenv("HostIP", "127.0.0.1")
job.Setenv("HostPort", strPort)
job.Setenv("Proto", "tcp")
job.Setenv("ContainerPort", strPort)
return
}
func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) {
strPort := strconv.Itoa(port)
job = eng.Job("allocate_port", "container_id")
job.Setenv("HostIP", "localhost")
job.Setenv("HostPort", strPort)
job.Setenv("Proto", "tcp")
job.Setenv("ContainerPort", strPort)
return
} }
func TestAllocatePortDetection(t *testing.T) { func TestAllocatePortDetection(t *testing.T) {
eng := engine.New()
eng.Logging = false
freePort := findFreePort(t) freePort := findFreePort(t)
// Init driver if err := InitDriver(new(Config)); err != nil {
job := eng.Job("initdriver")
if res := InitDriver(job); res != nil {
t.Fatal("Failed to initialize network driver") t.Fatal("Failed to initialize network driver")
} }
// Allocate interface // Allocate interface
job = eng.Job("allocate_interface", "container_id") if _, err := Allocate("container_id", "", "", ""); err != nil {
if res := Allocate(job); res != nil {
t.Fatal("Failed to allocate network interface") t.Fatal("Failed to allocate network interface")
} }
port := nat.Port(freePort + "/tcp")
binding := nat.PortBinding{HostIp: "127.0.0.1", HostPort: freePort}
// Allocate same port twice, expect failure on second call // Allocate same port twice, expect failure on second call
job = newPortAllocationJob(eng, freePort) if _, err := AllocatePort("container_id", port, binding); err != nil {
if res := AllocatePort(job); res != nil {
t.Fatal("Failed to find a free port to allocate") t.Fatal("Failed to find a free port to allocate")
} }
if res := AllocatePort(job); res == nil { if _, err := AllocatePort("container_id", port, binding); err == nil {
t.Fatal("Duplicate port allocation granted by AllocatePort") t.Fatal("Duplicate port allocation granted by AllocatePort")
} }
} }
func TestHostnameFormatChecking(t *testing.T) { func TestHostnameFormatChecking(t *testing.T) {
eng := engine.New()
eng.Logging = false
freePort := findFreePort(t) freePort := findFreePort(t)
// Init driver if err := InitDriver(new(Config)); err != nil {
job := eng.Job("initdriver")
if res := InitDriver(job); res != nil {
t.Fatal("Failed to initialize network driver") t.Fatal("Failed to initialize network driver")
} }
// Allocate interface // Allocate interface
job = eng.Job("allocate_interface", "container_id") if _, err := Allocate("container_id", "", "", ""); err != nil {
if res := Allocate(job); res != nil {
t.Fatal("Failed to allocate network interface") t.Fatal("Failed to allocate network interface")
} }
// Allocate port with invalid HostIP, expect failure with Bad Request http status port := nat.Port(freePort + "/tcp")
job = newPortAllocationJobWithInvalidHostIP(eng, freePort) binding := nat.PortBinding{HostIp: "localhost", HostPort: freePort}
if res := AllocatePort(job); res == nil {
if _, err := AllocatePort("container_id", port, binding); err == nil {
t.Fatal("Failed to check invalid HostIP") t.Fatal("Failed to check invalid HostIP")
} }
} }
func newInterfaceAllocation(t *testing.T, input engine.Env) (output engine.Env) { func newInterfaceAllocation(t *testing.T, globalIPv6 *net.IPNet, requestedMac, requestedIP, requestedIPv6 string, expectFail bool) *network.Settings {
eng := engine.New()
eng.Logging = false
done := make(chan bool)
// set IPv6 global if given // set IPv6 global if given
if input.Exists("globalIPv6Network") { if globalIPv6 != nil {
_, globalIPv6Network, _ = net.ParseCIDR(input.Get("globalIPv6Network")) globalIPv6Network = globalIPv6
} }
job := eng.Job("allocate_interface", "container_id") networkSettings, err := Allocate("container_id", requestedMac, requestedIP, requestedIPv6)
job.Env().Init(&input) if err == nil && expectFail {
reader, _ := job.Stdout.AddPipe() t.Fatal("Doesn't fail to allocate network interface")
go func() { } else if err != nil && !expectFail {
output.Decode(reader) t.Fatal("Failed to allocate network interface")
done <- true
}()
res := Allocate(job)
job.Stdout.Close()
<-done
if input.Exists("expectFail") && input.GetBool("expectFail") {
if res == nil {
t.Fatal("Doesn't fail to allocate network interface")
}
} else {
if res != nil {
t.Fatal("Failed to allocate network interface")
}
} }
if input.Exists("globalIPv6Network") { if globalIPv6 != nil {
// check for bug #11427 // check for bug #11427
_, subnet, _ := net.ParseCIDR(input.Get("globalIPv6Network")) if globalIPv6Network.IP.String() != globalIPv6.IP.String() {
if globalIPv6Network.IP.String() != subnet.IP.String() {
t.Fatal("globalIPv6Network was modified during allocation") t.Fatal("globalIPv6Network was modified during allocation")
} }
// clean up IPv6 global // clean up IPv6 global
globalIPv6Network = nil globalIPv6Network = nil
} }
return return networkSettings
} }
func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) { func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) {
input := engine.Env{}
_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/81") _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/81")
networkSettings := newInterfaceAllocation(t, subnet, "", "", "", false)
// set global ipv6
input.Set("globalIPv6Network", subnet.String())
output := newInterfaceAllocation(t, input)
// ensure low manually assigend global ip // ensure low manually assigend global ip
ip := net.ParseIP(output.Get("GlobalIPv6")) ip := net.ParseIP(networkSettings.GlobalIPv6Address)
_, subnet, _ = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet.IP.String(), 120)) _, subnet, _ = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet.IP.String(), 120))
if !subnet.Contains(ip) { if !subnet.Contains(ip) {
t.Fatalf("Error ip %s not in subnet %s", ip.String(), subnet.String()) t.Fatalf("Error ip %s not in subnet %s", ip.String(), subnet.String())
@ -171,26 +114,18 @@ func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) {
} }
func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) { func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) {
input := engine.Env{}
_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80")
networkSettings := newInterfaceAllocation(t, subnet, "ab:cd:ab:cd:ab:cd", "", "", false)
// set global ipv6
input.Set("globalIPv6Network", subnet.String())
input.Set("RequestedMac", "ab:cd:ab:cd:ab:cd")
output := newInterfaceAllocation(t, input)
// ensure global ip with mac // ensure global ip with mac
ip := net.ParseIP(output.Get("GlobalIPv6")) ip := net.ParseIP(networkSettings.GlobalIPv6Address)
expectedIP := net.ParseIP("2001:db8:1234:1234:1234:abcd:abcd:abcd") expectedIP := net.ParseIP("2001:db8:1234:1234:1234:abcd:abcd:abcd")
if ip.String() != expectedIP.String() { if ip.String() != expectedIP.String() {
t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP.String()) t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP.String())
} }
// ensure link local format // ensure link local format
ip = net.ParseIP(output.Get("LinkLocalIPv6")) ip = net.ParseIP(networkSettings.LinkLocalIPv6Address)
expectedIP = net.ParseIP("fe80::a9cd:abff:fecd:abcd") expectedIP = net.ParseIP("fe80::a9cd:abff:fecd:abcd")
if ip.String() != expectedIP.String() { if ip.String() != expectedIP.String() {
t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP.String()) t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP.String())
@ -199,27 +134,19 @@ func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) {
} }
func TestIPv6InterfaceAllocationRequest(t *testing.T) { func TestIPv6InterfaceAllocationRequest(t *testing.T) {
input := engine.Env{}
_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80") _, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80")
expectedIP := net.ParseIP("2001:db8:1234:1234:1234::1328") expectedIP := "2001:db8:1234:1234:1234::1328"
// set global ipv6 networkSettings := newInterfaceAllocation(t, subnet, "", "", expectedIP, false)
input.Set("globalIPv6Network", subnet.String())
input.Set("RequestedIPv6", expectedIP.String())
output := newInterfaceAllocation(t, input)
// ensure global ip with mac // ensure global ip with mac
ip := net.ParseIP(output.Get("GlobalIPv6")) ip := net.ParseIP(networkSettings.GlobalIPv6Address)
if ip.String() != expectedIP.String() { if ip.String() != expectedIP {
t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP.String()) t.Fatalf("Error ip %s should be %s", ip.String(), expectedIP)
} }
// retry -> fails for duplicated address // retry -> fails for duplicated address
input.SetBool("expectFail", true) _ = newInterfaceAllocation(t, subnet, "", "", expectedIP, true)
output = newInterfaceAllocation(t, input)
} }
func TestMacAddrGeneration(t *testing.T) { func TestMacAddrGeneration(t *testing.T) {
@ -239,40 +166,27 @@ func TestMacAddrGeneration(t *testing.T) {
} }
func TestLinkContainers(t *testing.T) { func TestLinkContainers(t *testing.T) {
eng := engine.New()
eng.Logging = false
// Init driver // Init driver
job := eng.Job("initdriver") if err := InitDriver(new(Config)); err != nil {
if res := InitDriver(job); res != nil {
t.Fatal("Failed to initialize network driver") t.Fatal("Failed to initialize network driver")
} }
// Allocate interface // Allocate interface
job = eng.Job("allocate_interface", "container_id") if _, err := Allocate("container_id", "", "", ""); err != nil {
if res := Allocate(job); res != nil {
t.Fatal("Failed to allocate network interface") t.Fatal("Failed to allocate network interface")
} }
job.Args[0] = "-I"
job.Setenv("ChildIP", "172.17.0.2")
job.Setenv("ParentIP", "172.17.0.1")
job.SetenvBool("IgnoreErrors", false)
job.SetenvList("Ports", []string{"1234"})
bridgeIface = "lo" bridgeIface = "lo"
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if res := LinkContainers(job); res != nil { if err := LinkContainers("-I", "172.17.0.1", "172.17.0.2", []nat.Port{nat.Port("1234")}, false); err != nil {
t.Fatalf("LinkContainers failed") t.Fatal("LinkContainers failed")
} }
// flush rules // flush rules
if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { if _, err := iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -18,6 +18,7 @@ import (
"github.com/docker/docker/builtins" "github.com/docker/docker/builtins"
"github.com/docker/docker/daemon" "github.com/docker/docker/daemon"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine" "github.com/docker/docker/engine"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
@ -185,9 +186,11 @@ func newTestEngine(t Fataler, autorestart bool, root string) *engine.Engine {
ExecDriver: "native", ExecDriver: "native",
// Either InterContainerCommunication or EnableIptables must be set, // Either InterContainerCommunication or EnableIptables must be set,
// otherwise NewDaemon will fail because of conflicting settings. // otherwise NewDaemon will fail because of conflicting settings.
InterContainerCommunication: true, Bridge: bridge.Config{
TrustKeyPath: filepath.Join(root, "key.json"), InterContainerCommunication: true,
LogConfig: runconfig.LogConfig{Type: "json-file"}, },
TrustKeyPath: filepath.Join(root, "key.json"),
LogConfig: runconfig.LogConfig{Type: "json-file"},
} }
d, err := daemon.NewDaemon(cfg, eng, registry.NewService(nil)) d, err := daemon.NewDaemon(cfg, eng, registry.NewService(nil))
if err != nil { if err != nil {

View file

@ -2,10 +2,12 @@ package links
import ( import (
"fmt" "fmt"
"github.com/docker/docker/engine"
"github.com/docker/docker/nat"
"path" "path"
"strings" "strings"
"github.com/docker/docker/daemon/networkdriver/bridge"
"github.com/docker/docker/engine"
"github.com/docker/docker/nat"
) )
type Link struct { type Link struct {
@ -158,21 +160,5 @@ func (l *Link) Disable() {
} }
func (l *Link) toggle(action string, ignoreErrors bool) error { func (l *Link) toggle(action string, ignoreErrors bool) error {
job := l.eng.Job("link", action) return bridge.LinkContainers(action, l.ParentIP, l.ChildIP, l.Ports, ignoreErrors)
job.Setenv("ParentIP", l.ParentIP)
job.Setenv("ChildIP", l.ChildIP)
job.SetenvBool("IgnoreErrors", ignoreErrors)
out := make([]string, len(l.Ports))
for i, p := range l.Ports {
out[i] = string(p)
}
job.SetenvList("Ports", out)
if err := job.Run(); err != nil {
// TODO: get ouput from job
return err
}
return nil
} }

View file

@ -34,6 +34,9 @@ func NewPort(proto, port string) Port {
} }
func ParsePort(rawPort string) (int, error) { func ParsePort(rawPort string) (int, error) {
if len(rawPort) == 0 {
return 0, nil
}
port, err := strconv.ParseUint(rawPort, 10, 16) port, err := strconv.ParseUint(rawPort, 10, 16)
if err != nil { if err != nil {
return 0, err return 0, err