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 {
en := &execdriver.Network{
Mtu: c.daemon.config.Mtu,
Interface: nil,
}
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
switch parts[0] {
case "none":
case "default", "": // empty string to support existing containers
if !c.Config.NetworkDisabled {
en.Interface = &execdriver.NetworkInterface{
MacAddress: c.Config.MacAddress,
Bridge: c.daemon.config.Bridge.VirtualSwitchName,
MacAddress: c.Config.MacAddress,
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:

View File

@ -91,15 +91,6 @@ type Driver interface {
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
// It is for IPC namespace setting. Usually different containers
// have their own IPC namespace, however this specifies to use
@ -130,20 +121,6 @@ type UTS struct {
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.
// Currently these are all for cgroup configs.
// TODO Windows: Factor out ulimit.Rlimit

View File

@ -1,3 +1,5 @@
// +build !windows
package execdriver
import (
@ -15,6 +17,14 @@ import (
"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.
// It returns the initial configs for a container. It's mostly
// 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}}
{{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}}
lxc.utsname = {{getHostname .ProcessConfig.Env}}
{{end}}

View File

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

View File

@ -8,6 +8,8 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"strconv"
"strings"
"github.com/Sirupsen/logrus"
@ -16,6 +18,10 @@ import (
"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 {
ID string
Path string
@ -25,9 +31,23 @@ type defConfig struct {
DefFile string
}
type portBinding struct {
Protocol string
InternalPort int
ExternalPort int
}
type natSettings struct {
Name string
PortBindings []portBinding
}
type networkConnection struct {
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 {
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 {
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{
DeviceType: "Network",
Connection: &networkConnection{
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,
}
}
logrus.Debugf("Virtual switch '%s', mac='%s'", c.Network.Interface.Bridge, c.Network.Interface.MacAddress)
cu.Devices = append(cu.Devices, dev)
} else {
logrus.Debugln("No network interface")

View File

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