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

Windows: Enable NAT port mapping

Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
John Howard 2015-08-06 19:21:00 -07:00
parent b9094633f3
commit 4393be7100
8 changed files with 126 additions and 53 deletions

View file

@ -55,19 +55,23 @@ func (container *Container) setupWorkingDirectory() error {
func populateCommand(c *Container, env []string) error { func populateCommand(c *Container, env []string) error {
en := &execdriver.Network{ en := &execdriver.Network{
Mtu: c.daemon.config.Mtu,
Interface: nil, Interface: nil,
} }
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
switch parts[0] { switch parts[0] {
case "none": case "none":
case "default", "": // empty string to support existing containers case "default", "": // empty string to support existing containers
if !c.Config.NetworkDisabled { if !c.Config.NetworkDisabled {
en.Interface = &execdriver.NetworkInterface{ en.Interface = &execdriver.NetworkInterface{
MacAddress: c.Config.MacAddress, MacAddress: c.Config.MacAddress,
Bridge: c.daemon.config.Bridge.VirtualSwitchName, Bridge: c.daemon.config.Bridge.VirtualSwitchName,
PortBindings: c.hostConfig.PortBindings,
// TODO Windows. Include IPAddress. There already is a
// property IPAddress on execDrive.CommonNetworkInterface,
// but there is no CLI option in docker to pass through
// an IPAddress on docker run.
} }
} }
default: default:

View file

@ -91,15 +91,6 @@ type Driver interface {
Stats(id string) (*ResourceStats, error) Stats(id string) (*ResourceStats, error)
} }
// Network settings of the container
type Network struct {
Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
Mtu int `json:"mtu"`
ContainerID string `json:"container_id"` // id of the container to join network.
NamespacePath string `json:"namespace_path"`
HostNetworking bool `json:"host_networking"`
}
// Ipc settings of the container // Ipc settings of the container
// It is for IPC namespace setting. Usually different containers // It is for IPC namespace setting. Usually different containers
// have their own IPC namespace, however this specifies to use // have their own IPC namespace, however this specifies to use
@ -130,20 +121,6 @@ type UTS struct {
HostUTS bool `json:"host_uts"` HostUTS bool `json:"host_uts"`
} }
// NetworkInterface contains all network configs for a driver
type NetworkInterface struct {
Gateway string `json:"gateway"`
IPAddress string `json:"ip"`
IPPrefixLen int `json:"ip_prefix_len"`
MacAddress string `json:"mac"`
Bridge string `json:"bridge"`
GlobalIPv6Address string `json:"global_ipv6"`
LinkLocalIPv6Address string `json:"link_local_ipv6"`
GlobalIPv6PrefixLen int `json:"global_ipv6_prefix_len"`
IPv6Gateway string `json:"ipv6_gateway"`
HairpinMode bool `json:"hairpin_mode"`
}
// Resources contains all resource configs for a driver. // Resources contains all resource configs for a driver.
// Currently these are all for cgroup configs. // Currently these are all for cgroup configs.
// TODO Windows: Factor out ulimit.Rlimit // TODO Windows: Factor out ulimit.Rlimit

View file

@ -1,3 +1,5 @@
// +build !windows
package execdriver package execdriver
import ( import (
@ -15,6 +17,14 @@ import (
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
) )
// Network settings of the container
type Network struct {
Mtu int `json:"mtu"`
ContainerID string `json:"container_id"` // id of the container to join network.
NamespacePath string `json:"namespace_path"`
HostNetworking bool `json:"host_networking"`
}
// InitContainer is the initialization of a container config. // InitContainer is the initialization of a container config.
// It returns the initial configs for a container. It's mostly // It returns the initial configs for a container. It's mostly
// defined by the default template. // defined by the default template.

View file

@ -0,0 +1,20 @@
package execdriver
import "github.com/docker/docker/pkg/nat"
// Network settings of the container
type Network struct {
Interface *NetworkInterface `json:"interface"`
ContainerID string `json:"container_id"` // id of the container to join network.
}
// NetworkInterface contains network configs for a driver
type NetworkInterface struct {
MacAddress string `json:"mac"`
Bridge string `json:"bridge"`
IPAddress string `json:"ip"`
// PortBindings is the port mapping between the exposed port in the
// container and the port on the host.
PortBindings nat.PortMap `json:"port_bindings"`
}

View file

@ -128,17 +128,6 @@ lxc.{{$value}}
{{end}} {{end}}
{{end}} {{end}}
{{if .Network.Interface}}
{{if .Network.Interface.IPAddress}}
lxc.network.ipv4 = {{.Network.Interface.IPAddress}}/{{.Network.Interface.IPPrefixLen}}
{{end}}
{{if .Network.Interface.Gateway}}
lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
{{end}}
{{if .Network.Interface.MacAddress}}
lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
{{end}}
{{end}}
{{if .ProcessConfig.Env}} {{if .ProcessConfig.Env}}
lxc.utsname = {{getHostname .ProcessConfig.Env}} lxc.utsname = {{getHostname .ProcessConfig.Env}}
{{end}} {{end}}

View file

@ -50,8 +50,7 @@ func TestLXCConfig(t *testing.T) {
CPUShares: int64(cpu), CPUShares: int64(cpu),
}, },
Network: &execdriver.Network{ Network: &execdriver.Network{
Mtu: 1500, Mtu: 1500,
Interface: nil,
}, },
AllowedDevices: make([]*configs.Device, 0), AllowedDevices: make([]*configs.Device, 0),
ProcessConfig: execdriver.ProcessConfig{}, ProcessConfig: execdriver.ProcessConfig{},
@ -90,8 +89,7 @@ func TestCustomLxcConfig(t *testing.T) {
"lxc.cgroup.cpuset.cpus = 0,1", "lxc.cgroup.cpuset.cpus = 0,1",
}, },
Network: &execdriver.Network{ Network: &execdriver.Network{
Mtu: 1500, Mtu: 1500,
Interface: nil,
}, },
ProcessConfig: processConfig, ProcessConfig: processConfig,
} }
@ -222,8 +220,7 @@ func TestCustomLxcConfigMounts(t *testing.T) {
"lxc.cgroup.cpuset.cpus = 0,1", "lxc.cgroup.cpuset.cpus = 0,1",
}, },
Network: &execdriver.Network{ Network: &execdriver.Network{
Mtu: 1500, Mtu: 1500,
Interface: nil,
}, },
Mounts: mounts, Mounts: mounts,
ProcessConfig: processConfig, ProcessConfig: processConfig,
@ -264,8 +261,7 @@ func TestCustomLxcConfigMisc(t *testing.T) {
"lxc.cgroup.cpuset.cpus = 0,1", "lxc.cgroup.cpuset.cpus = 0,1",
}, },
Network: &execdriver.Network{ Network: &execdriver.Network{
Mtu: 1500, Mtu: 1500,
Interface: nil,
}, },
ProcessConfig: processConfig, ProcessConfig: processConfig,
CapAdd: []string{"net_admin", "syslog"}, CapAdd: []string{"net_admin", "syslog"},
@ -317,8 +313,7 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
"lxc.network.ipv4 = 172.0.0.1", "lxc.network.ipv4 = 172.0.0.1",
}, },
Network: &execdriver.Network{ Network: &execdriver.Network{
Mtu: 1500, Mtu: 1500,
Interface: nil,
}, },
ProcessConfig: processConfig, ProcessConfig: processConfig,
CapAdd: []string{"NET_ADMIN", "SYSLOG"}, CapAdd: []string{"NET_ADMIN", "SYSLOG"},

View file

@ -8,6 +8,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"os"
"strconv"
"strings" "strings"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
@ -16,6 +18,10 @@ import (
"github.com/natefinch/npipe" "github.com/natefinch/npipe"
) )
// defaultContainerNAT is the default name of the container NAT device that is
// preconfigured on the server.
const defaultContainerNAT = "ContainerNAT"
type layer struct { type layer struct {
ID string ID string
Path string Path string
@ -25,9 +31,23 @@ type defConfig struct {
DefFile string DefFile string
} }
type portBinding struct {
Protocol string
InternalPort int
ExternalPort int
}
type natSettings struct {
Name string
PortBindings []portBinding
}
type networkConnection struct { type networkConnection struct {
NetworkName string NetworkName string
EnableNat bool // TODO Windows: Add Ip4Address string to this structure when hooked up in
// docker CLI. This is present in the HCS JSON handler.
EnableNat bool
Nat natSettings
} }
type networkSettings struct { type networkSettings struct {
MacAddress string MacAddress string
@ -81,12 +101,72 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
}) })
} }
// TODO Windows. At some point, when there is CLI on docker run to
// enable the IP Address of the container to be passed into docker run,
// the IP Address needs to be wired through to HCS in the JSON. It
// would be present in c.Network.Interface.IPAddress. See matching
// TODO in daemon\container_windows.go, function populateCommand.
if c.Network.Interface != nil { if c.Network.Interface != nil {
var pbs []portBinding
// Enumerate through the port bindings specified by the user and convert
// them into the internal structure matching the JSON blob that can be
// understood by the HCS.
for i, v := range c.Network.Interface.PortBindings {
proto := strings.ToUpper(i.Proto())
if proto != "TCP" && proto != "UDP" {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid protocol %s", i.Proto())
}
if len(v) > 1 {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("Windows does not support more than one host port in NAT settings")
}
for _, v2 := range v {
var (
iPort, ePort int
err error
)
if len(v2.HostIP) != 0 {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
}
if ePort, err = strconv.Atoi(v2.HostPort); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid container port %s: %s", v2.HostPort, err)
}
if iPort, err = strconv.Atoi(i.Port()); err != nil {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("invalid internal port %s: %s", i.Port(), err)
}
if iPort < 0 || iPort > 65535 || ePort < 0 || ePort > 65535 {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("specified NAT port is not in allowed range")
}
pbs = append(pbs,
portBinding{ExternalPort: ePort,
InternalPort: iPort,
Protocol: proto})
}
}
// TODO Windows: TP3 workaround. Allow the user to override the name of
// the Container NAT device through an environment variable. This will
// ultimately be a global daemon parameter on Windows, similar to -b
// for the name of the virtual switch (aka bridge).
cn := os.Getenv("DOCKER_CONTAINER_NAT")
if len(cn) == 0 {
cn = defaultContainerNAT
}
dev := device{ dev := device{
DeviceType: "Network", DeviceType: "Network",
Connection: &networkConnection{ Connection: &networkConnection{
NetworkName: c.Network.Interface.Bridge, NetworkName: c.Network.Interface.Bridge,
EnableNat: false, // TODO Windows: Fixme, next line. Needs HCS fix.
EnableNat: false,
Nat: natSettings{
Name: cn,
PortBindings: pbs,
},
}, },
} }
@ -97,9 +177,6 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
MacAddress: windowsStyleMAC, MacAddress: windowsStyleMAC,
} }
} }
logrus.Debugf("Virtual switch '%s', mac='%s'", c.Network.Interface.Bridge, c.Network.Interface.MacAddress)
cu.Devices = append(cu.Devices, dev) cu.Devices = append(cu.Devices, dev)
} else { } else {
logrus.Debugln("No network interface") logrus.Debugln("No network interface")

View file

@ -9,6 +9,7 @@ type Address struct {
} }
// Settings stores configuration details about the daemon network config // Settings stores configuration details about the daemon network config
// TODO Windows. Many of these fields can be factored out.,
type Settings struct { type Settings struct {
Bridge string Bridge string
EndpointID string EndpointID string