commit
284c1713e8
18 changed files with 506 additions and 351 deletions
6
libnetwork/Godeps/Godeps.json
generated
6
libnetwork/Godeps/Godeps.json
generated
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/docker/vendor/src/github.com/docker/libnetwork",
|
"ImportPath": "github.com/docker/libnetwork",
|
||||||
"GoVersion": "go1.4.2",
|
"GoVersion": "go1.4.2",
|
||||||
"Packages": [
|
"Packages": [
|
||||||
"./..."
|
"./..."
|
||||||
|
@ -52,8 +52,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/docker/libcontainer/user",
|
"ImportPath": "github.com/docker/libcontainer/user",
|
||||||
"Comment": "v1.4.0",
|
"Comment": "v1.4.0-495-g3e66118",
|
||||||
"Rev": "53eca435e63db58b06cf796d3a9326db5fd42253"
|
"Rev": "3e661186ba24f259d3860f067df052c7f6904bee"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/vishvananda/netlink",
|
"ImportPath": "github.com/vishvananda/netlink",
|
||||||
|
|
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
|
@ -1,93 +0,0 @@
|
||||||
package kernel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type KernelVersionInfo struct {
|
|
||||||
Kernel int
|
|
||||||
Major int
|
|
||||||
Minor int
|
|
||||||
Flavor string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k *KernelVersionInfo) String() string {
|
|
||||||
return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, k.Flavor)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare two KernelVersionInfo struct.
|
|
||||||
// Returns -1 if a < b, 0 if a == b, 1 it a > b
|
|
||||||
func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
|
||||||
if a.Kernel < b.Kernel {
|
|
||||||
return -1
|
|
||||||
} else if a.Kernel > b.Kernel {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Major < b.Major {
|
|
||||||
return -1
|
|
||||||
} else if a.Major > b.Major {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Minor < b.Minor {
|
|
||||||
return -1
|
|
||||||
} else if a.Minor > b.Minor {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetKernelVersion() (*KernelVersionInfo, error) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
uts, err := uname()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
release := make([]byte, len(uts.Release))
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
for _, c := range uts.Release {
|
|
||||||
release[i] = byte(c)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the \x00 from the release for Atoi to parse correctly
|
|
||||||
release = release[:bytes.IndexByte(release, 0)]
|
|
||||||
|
|
||||||
return ParseRelease(string(release))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseRelease(release string) (*KernelVersionInfo, error) {
|
|
||||||
var (
|
|
||||||
kernel, major, minor, parsed int
|
|
||||||
flavor, partial string
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ignore error from Sscanf to allow an empty flavor. Instead, just
|
|
||||||
// make sure we got all the version numbers.
|
|
||||||
parsed, _ = fmt.Sscanf(release, "%d.%d%s", &kernel, &major, &partial)
|
|
||||||
if parsed < 2 {
|
|
||||||
return nil, errors.New("Can't parse kernel version " + release)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sometimes we have 3.12.25-gentoo, but sometimes we just have 3.12-1-amd64
|
|
||||||
parsed, _ = fmt.Sscanf(partial, ".%d%s", &minor, &flavor)
|
|
||||||
if parsed < 1 {
|
|
||||||
flavor = partial
|
|
||||||
}
|
|
||||||
|
|
||||||
return &KernelVersionInfo{
|
|
||||||
Kernel: kernel,
|
|
||||||
Major: major,
|
|
||||||
Minor: minor,
|
|
||||||
Flavor: flavor,
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
package kernel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, result int) {
|
|
||||||
var (
|
|
||||||
a *KernelVersionInfo
|
|
||||||
)
|
|
||||||
a, _ = ParseRelease(release)
|
|
||||||
|
|
||||||
if r := CompareKernelVersion(a, b); r != result {
|
|
||||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
|
||||||
}
|
|
||||||
if a.Flavor != b.Flavor {
|
|
||||||
t.Fatalf("Unexpected parsed kernel flavor. Found %s, expected %s", a.Flavor, b.Flavor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseRelease(t *testing.T) {
|
|
||||||
assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
|
||||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
|
||||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
|
||||||
assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
|
||||||
assertParseRelease(t, "3.12.8tag", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
|
||||||
assertParseRelease(t, "3.12-1-amd64", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
|
||||||
if r := CompareKernelVersion(a, b); r != result {
|
|
||||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompareKernelVersion(t *testing.T) {
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
0)
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
-1)
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
|
||||||
1)
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
0)
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
1)
|
|
||||||
assertKernelVersion(t,
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
|
||||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
|
||||||
-1)
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package kernel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Utsname syscall.Utsname
|
|
||||||
|
|
||||||
func uname() (*syscall.Utsname, error) {
|
|
||||||
uts := &syscall.Utsname{}
|
|
||||||
|
|
||||||
if err := syscall.Uname(uts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return uts, nil
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package kernel
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Utsname struct {
|
|
||||||
Release [65]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func uname() (*Utsname, error) {
|
|
||||||
return nil, errors.New("Kernel version detection is available only on linux")
|
|
||||||
}
|
|
1
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/MAINTAINERS
generated
vendored
1
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/MAINTAINERS
generated
vendored
|
@ -1 +1,2 @@
|
||||||
Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
Tianon Gravi <admwiggin@gmail.com> (@tianon)
|
||||||
|
Aleksa Sarai <cyphar@cyphar.com> (@cyphar)
|
||||||
|
|
16
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/lookup_unix.go
generated
vendored
16
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/lookup_unix.go
generated
vendored
|
@ -9,22 +9,22 @@ import (
|
||||||
|
|
||||||
// Unix-specific path to the passwd and group formatted files.
|
// Unix-specific path to the passwd and group formatted files.
|
||||||
const (
|
const (
|
||||||
unixPasswdFile = "/etc/passwd"
|
unixPasswdPath = "/etc/passwd"
|
||||||
unixGroupFile = "/etc/group"
|
unixGroupPath = "/etc/group"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPasswdFile() (string, error) {
|
func GetPasswdPath() (string, error) {
|
||||||
return unixPasswdFile, nil
|
return unixPasswdPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPasswd() (io.ReadCloser, error) {
|
func GetPasswd() (io.ReadCloser, error) {
|
||||||
return os.Open(unixPasswdFile)
|
return os.Open(unixPasswdPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupFile() (string, error) {
|
func GetGroupPath() (string, error) {
|
||||||
return unixGroupFile, nil
|
return unixGroupPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroup() (io.ReadCloser, error) {
|
func GetGroup() (io.ReadCloser, error) {
|
||||||
return os.Open(unixGroupFile)
|
return os.Open(unixGroupPath)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ package user
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
func GetPasswdFile() (string, error) {
|
func GetPasswdPath() (string, error) {
|
||||||
return "", ErrUnsupported
|
return "", ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ func GetPasswd() (io.ReadCloser, error) {
|
||||||
return nil, ErrUnsupported
|
return nil, ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroupFile() (string, error) {
|
func GetGroupPath() (string, error) {
|
||||||
return "", ErrUnsupported
|
return "", ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/user.go
generated
vendored
4
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/user/user.go
generated
vendored
|
@ -197,11 +197,11 @@ type ExecUser struct {
|
||||||
Home string
|
Home string
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExecUserFile is a wrapper for GetExecUser. It reads data from each of the
|
// GetExecUserPath is a wrapper for GetExecUser. It reads data from each of the
|
||||||
// given file paths and uses that data as the arguments to GetExecUser. If the
|
// given file paths and uses that data as the arguments to GetExecUser. If the
|
||||||
// files cannot be opened for any reason, the error is ignored and a nil
|
// files cannot be opened for any reason, the error is ignored and a nil
|
||||||
// io.Reader is passed instead.
|
// io.Reader is passed instead.
|
||||||
func GetExecUserFile(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
||||||
passwd, err := os.Open(passwdPath)
|
passwd, err := os.Open(passwdPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
passwd = nil
|
passwd = nil
|
||||||
|
|
|
@ -20,6 +20,7 @@ const (
|
||||||
vethPrefix = "veth"
|
vethPrefix = "veth"
|
||||||
vethLen = 7
|
vethLen = 7
|
||||||
containerVeth = "eth0"
|
containerVeth = "eth0"
|
||||||
|
maxAllocatePortAttempts = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -42,11 +43,13 @@ type Configuration struct {
|
||||||
Mtu int
|
Mtu int
|
||||||
DefaultGatewayIPv4 net.IP
|
DefaultGatewayIPv4 net.IP
|
||||||
DefaultGatewayIPv6 net.IP
|
DefaultGatewayIPv6 net.IP
|
||||||
|
DefaultBindingIP net.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointConfiguration represents the user specified configuration for the sandbox endpoint
|
// EndpointConfiguration represents the user specified configuration for the sandbox endpoint
|
||||||
type EndpointConfiguration struct {
|
type EndpointConfiguration struct {
|
||||||
MacAddress net.HardwareAddr
|
MacAddress net.HardwareAddr
|
||||||
|
PortBindings []netutils.PortBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerConfiguration represents the user specified configuration for a container
|
// ContainerConfiguration represents the user specified configuration for a container
|
||||||
|
@ -58,6 +61,7 @@ type bridgeEndpoint struct {
|
||||||
id types.UUID
|
id types.UUID
|
||||||
port *sandbox.Interface
|
port *sandbox.Interface
|
||||||
config *EndpointConfiguration // User specified parameters
|
config *EndpointConfiguration // User specified parameters
|
||||||
|
portMapping []netutils.PortBinding // Operation port bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
type bridgeNetwork struct {
|
type bridgeNetwork struct {
|
||||||
|
@ -343,7 +347,6 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interf
|
||||||
// Try to convert the options to endpoint configuration
|
// Try to convert the options to endpoint configuration
|
||||||
epConfig, err := parseEndpointOptions(epOptions)
|
epConfig, err := parseEndpointOptions(epOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.Unlock()
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,12 +407,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interf
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
mac := netutils.GenerateRandomMAC()
|
// Set the sbox's MAC. If specified, use the one configured by user, otherwise use a random one
|
||||||
// Add user specified attributes
|
mac := electMacAddress(epConfig)
|
||||||
if epConfig != nil && epConfig.MacAddress != nil {
|
|
||||||
mac = epConfig.MacAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
err = netlink.LinkSetHardwareAddr(sbox, mac)
|
err = netlink.LinkSetHardwareAddr(sbox, mac)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -466,14 +465,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interf
|
||||||
ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask}
|
ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the sandbox side pipe interface
|
// Create the sandbox side pipe interface
|
||||||
// This is needed for cleanup on DeleteEndpoint()
|
|
||||||
intf := &sandbox.Interface{}
|
intf := &sandbox.Interface{}
|
||||||
intf.SrcName = name2
|
intf.SrcName = name2
|
||||||
intf.DstName = containerVeth
|
intf.DstName = containerVeth
|
||||||
intf.Address = ipv4Addr
|
intf.Address = ipv4Addr
|
||||||
|
|
||||||
// Update endpoint with the sandbox interface info
|
// Store the interface in endpoint, this is needed for cleanup on DeleteEndpoint()
|
||||||
endpoint.port = intf
|
endpoint.port = intf
|
||||||
|
|
||||||
// Generate the sandbox info to return
|
// Generate the sandbox info to return
|
||||||
|
@ -486,6 +484,12 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epOptions map[string]interf
|
||||||
sinfo.GatewayIPv6 = n.bridge.gatewayIPv6
|
sinfo.GatewayIPv6 = n.bridge.gatewayIPv6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Program any required port mapping and store them in the endpoint
|
||||||
|
endpoint.portMapping, err = allocatePorts(epConfig, sinfo, config.DefaultBindingIP)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return sinfo, nil
|
return sinfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,6 +539,9 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Remove port mappings. Do not stop endpoint delete on unmap failure
|
||||||
|
releasePorts(ep)
|
||||||
|
|
||||||
// Release the v4 address allocated to this endpoint's sandbox interface
|
// Release the v4 address allocated to this endpoint's sandbox interface
|
||||||
err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.port.Address.IP)
|
err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.port.Address.IP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -577,22 +584,26 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
|
||||||
if epOptions == nil {
|
if epOptions == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
genericData := epOptions[options.GenericData]
|
|
||||||
if genericData == nil {
|
ec := &EndpointConfiguration{}
|
||||||
return nil, nil
|
|
||||||
}
|
if opt, ok := epOptions[options.MacAddress]; ok {
|
||||||
switch opt := genericData.(type) {
|
if mac, ok := opt.(net.HardwareAddr); ok {
|
||||||
case options.Generic:
|
ec.MacAddress = mac
|
||||||
opaqueConfig, err := options.GenerateFromModel(opt, &EndpointConfiguration{})
|
} else {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return opaqueConfig.(*EndpointConfiguration), nil
|
|
||||||
case *EndpointConfiguration:
|
|
||||||
return opt, nil
|
|
||||||
default:
|
|
||||||
return nil, ErrInvalidEndpointConfig
|
return nil, ErrInvalidEndpointConfig
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt, ok := epOptions[options.PortMap]; ok {
|
||||||
|
if bs, ok := opt.([]netutils.PortBinding); ok {
|
||||||
|
ec.PortBindings = bs
|
||||||
|
} else {
|
||||||
|
return nil, ErrInvalidEndpointConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseContainerOptions(cOptions interface{}) (*ContainerConfiguration, error) {
|
func parseContainerOptions(cOptions interface{}) (*ContainerConfiguration, error) {
|
||||||
|
@ -613,6 +624,13 @@ func parseContainerOptions(cOptions interface{}) (*ContainerConfiguration, error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func electMacAddress(epConfig *EndpointConfiguration) net.HardwareAddr {
|
||||||
|
if epConfig != nil && epConfig.MacAddress != nil {
|
||||||
|
return epConfig.MacAddress
|
||||||
|
}
|
||||||
|
return netutils.GenerateRandomMAC()
|
||||||
|
}
|
||||||
|
|
||||||
// Generates a name to be used for a virtual ethernet
|
// Generates a name to be used for a virtual ethernet
|
||||||
// interface. The name is constructed by 'veth' appended
|
// interface. The name is constructed by 'veth' appended
|
||||||
// by a randomly generated hex value. (example: veth0f60e2c)
|
// by a randomly generated hex value. (example: veth0f60e2c)
|
||||||
|
|
|
@ -74,10 +74,10 @@ func TestCreateLinkWithOptions(t *testing.T) {
|
||||||
_, d := New()
|
_, d := New()
|
||||||
|
|
||||||
config := &Configuration{BridgeName: DefaultBridgeName}
|
config := &Configuration{BridgeName: DefaultBridgeName}
|
||||||
genericOption := make(map[string]interface{})
|
driverOptions := make(map[string]interface{})
|
||||||
genericOption[options.GenericData] = config
|
driverOptions[options.GenericData] = config
|
||||||
|
|
||||||
if err := d.Config(genericOption); err != nil {
|
if err := d.Config(driverOptions); err != nil {
|
||||||
t.Fatalf("Failed to setup driver config: %v", err)
|
t.Fatalf("Failed to setup driver config: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ func TestCreateLinkWithOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
|
mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
|
||||||
epConf := &EndpointConfiguration{MacAddress: mac}
|
epOptions := make(map[string]interface{})
|
||||||
genericOption[options.GenericData] = epConf
|
epOptions[options.MacAddress] = mac
|
||||||
|
|
||||||
sinfo, err := d.CreateEndpoint("net1", "ep", genericOption)
|
sinfo, err := d.CreateEndpoint("net1", "ep", epOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a link: %s", err.Error())
|
t.Fatalf("Failed to create a link: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,31 @@ var (
|
||||||
// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
|
// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
|
||||||
ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
|
ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
|
||||||
|
|
||||||
// ErrInvalidMtu is returned when the user provided MTU is not valid
|
// ErrInvalidMtu is returned when the user provided MTU is not valid.
|
||||||
ErrInvalidMtu = errors.New("invalid MTU number")
|
ErrInvalidMtu = errors.New("invalid MTU number")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
|
||||||
|
type ErrInvalidPort string
|
||||||
|
|
||||||
|
func (ip ErrInvalidPort) Error() string {
|
||||||
|
return fmt.Sprintf("invalid transport port: %s", string(ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnsupportedAddressType is returned when the specified address type is not supported.
|
||||||
|
type ErrUnsupportedAddressType string
|
||||||
|
|
||||||
|
func (uat ErrUnsupportedAddressType) Error() string {
|
||||||
|
return fmt.Sprintf("unsupported address type: %s", string(uat))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidAddressBinding is returned when the host address specfied in the port binding is not valid.
|
||||||
|
type ErrInvalidAddressBinding string
|
||||||
|
|
||||||
|
func (iab ErrInvalidAddressBinding) Error() string {
|
||||||
|
return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
|
||||||
|
}
|
||||||
|
|
||||||
// ActiveEndpointsError is returned when there are
|
// ActiveEndpointsError is returned when there are
|
||||||
// still active endpoints in the network being deleted.
|
// still active endpoints in the network being deleted.
|
||||||
type ActiveEndpointsError string
|
type ActiveEndpointsError string
|
||||||
|
|
124
libnetwork/drivers/bridge/port_mapping.go
Normal file
124
libnetwork/drivers/bridge/port_mapping.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package bridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/libnetwork/netutils"
|
||||||
|
"github.com/docker/libnetwork/sandbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
func allocatePorts(epConfig *EndpointConfiguration, sinfo *sandbox.Info, reqDefBindIP net.IP) ([]netutils.PortBinding, error) {
|
||||||
|
if epConfig == nil || epConfig.PortBindings == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defHostIP := defaultBindingIP
|
||||||
|
if reqDefBindIP != nil {
|
||||||
|
defHostIP = reqDefBindIP
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocatePortsInternal(epConfig.PortBindings, sinfo.Interfaces[0].Address.IP, defHostIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHostIP net.IP) ([]netutils.PortBinding, error) {
|
||||||
|
bs := make([]netutils.PortBinding, 0, len(bindings))
|
||||||
|
for _, c := range bindings {
|
||||||
|
b := c.GetCopy()
|
||||||
|
if err := allocatePort(&b, containerIP, defHostIP); err != nil {
|
||||||
|
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
||||||
|
if cuErr := releasePortsInternal(bs); cuErr != nil {
|
||||||
|
logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bs = append(bs, b)
|
||||||
|
}
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func allocatePort(bnd *netutils.PortBinding, containerIP, defHostIP net.IP) error {
|
||||||
|
var (
|
||||||
|
host net.Addr
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store the container interface address in the operational binding
|
||||||
|
bnd.IP = containerIP
|
||||||
|
|
||||||
|
// Adjust the host address in the operational binding
|
||||||
|
if len(bnd.HostIP) == 0 {
|
||||||
|
bnd.HostIP = defHostIP
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the container side transport address
|
||||||
|
container, err := bnd.ContainerAddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
||||||
|
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||||
|
if host, err = portMapper.Map(container, bnd.HostIP, int(bnd.HostPort)); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// There is no point in immediately retrying to map an explicitly chosen port.
|
||||||
|
if bnd.HostPort != 0 {
|
||||||
|
logrus.Warnf("Failed to allocate and map port %d: %s", bnd.HostPort, err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the host port (regardless it was or not specified in the binding)
|
||||||
|
switch netAddr := host.(type) {
|
||||||
|
case *net.TCPAddr:
|
||||||
|
bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
|
||||||
|
return nil
|
||||||
|
case *net.UDPAddr:
|
||||||
|
bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
// For completeness
|
||||||
|
return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func releasePorts(ep *bridgeEndpoint) error {
|
||||||
|
return releasePortsInternal(ep.portMapping)
|
||||||
|
}
|
||||||
|
|
||||||
|
func releasePortsInternal(bindings []netutils.PortBinding) error {
|
||||||
|
var errorBuf bytes.Buffer
|
||||||
|
|
||||||
|
// Attempt to release all port bindings, do not stop on failure
|
||||||
|
for _, m := range bindings {
|
||||||
|
if err := releasePort(m); err != nil {
|
||||||
|
errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errorBuf.Len() != 0 {
|
||||||
|
return errors.New(errorBuf.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func releasePort(bnd netutils.PortBinding) error {
|
||||||
|
// Construct the host side transport address
|
||||||
|
host, err := bnd.HostAddr()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return portMapper.Unmap(host)
|
||||||
|
}
|
72
libnetwork/drivers/bridge/port_mapping_test.go
Normal file
72
libnetwork/drivers/bridge/port_mapping_test.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package bridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/reexec"
|
||||||
|
"github.com/docker/libnetwork/netutils"
|
||||||
|
"github.com/docker/libnetwork/pkg/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPortMappingConfig(t *testing.T) {
|
||||||
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
_, d := New()
|
||||||
|
|
||||||
|
binding1 := netutils.PortBinding{Proto: netutils.UDP, Port: uint16(400), HostPort: uint16(54000)}
|
||||||
|
binding2 := netutils.PortBinding{Proto: netutils.TCP, Port: uint16(500), HostPort: uint16(65000)}
|
||||||
|
portBindings := []netutils.PortBinding{binding1, binding2}
|
||||||
|
|
||||||
|
epOptions := make(map[string]interface{})
|
||||||
|
epOptions[options.PortMap] = portBindings
|
||||||
|
|
||||||
|
driverConfig := &Configuration{
|
||||||
|
BridgeName: DefaultBridgeName,
|
||||||
|
EnableIPTables: true,
|
||||||
|
}
|
||||||
|
driverOptions := make(map[string]interface{})
|
||||||
|
driverOptions[options.GenericData] = driverConfig
|
||||||
|
|
||||||
|
if err := d.Config(driverOptions); err != nil {
|
||||||
|
t.Fatalf("Failed to setup driver config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := d.CreateNetwork("dummy", nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create bridge: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = d.CreateEndpoint("dummy", "ep1", epOptions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create the endpoint: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
dd := d.(*driver)
|
||||||
|
ep, _ := dd.network.endpoints["ep1"]
|
||||||
|
if len(ep.portMapping) != 2 {
|
||||||
|
t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
|
||||||
|
}
|
||||||
|
if ep.portMapping[0].Proto != binding1.Proto || ep.portMapping[0].Port != binding1.Port ||
|
||||||
|
ep.portMapping[1].Proto != binding2.Proto || ep.portMapping[1].Port != binding2.Port {
|
||||||
|
t.Fatalf("bridgeEndpoint has incorrect port mapping values")
|
||||||
|
}
|
||||||
|
if ep.portMapping[0].HostIP == nil || ep.portMapping[0].HostPort == 0 ||
|
||||||
|
ep.portMapping[1].HostIP == nil || ep.portMapping[1].HostPort == 0 {
|
||||||
|
t.Fatalf("operational port mapping data not found on bridgeEndpoint")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\nendpoint: %v\n", ep.portMapping)
|
||||||
|
|
||||||
|
err = releasePorts(ep)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to release mapped ports: %v", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/etchosts"
|
"github.com/docker/docker/pkg/etchosts"
|
||||||
|
"github.com/docker/libnetwork/netutils"
|
||||||
|
"github.com/docker/libnetwork/pkg/options"
|
||||||
"github.com/docker/libnetwork/sandbox"
|
"github.com/docker/libnetwork/sandbox"
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
)
|
)
|
||||||
|
@ -23,11 +25,11 @@ type Endpoint interface {
|
||||||
// Join creates a new sandbox for the given container ID and populates the
|
// Join creates a new sandbox for the given container ID and populates the
|
||||||
// network resources allocated for the endpoint and joins the sandbox to
|
// network resources allocated for the endpoint and joins the sandbox to
|
||||||
// the endpoint. It returns the sandbox key to the caller
|
// the endpoint. It returns the sandbox key to the caller
|
||||||
Join(containerID string, options ...JoinOption) (*ContainerData, error)
|
Join(containerID string, options ...EndpointOption) (*ContainerData, error)
|
||||||
|
|
||||||
// Leave removes the sandbox associated with container ID and detaches
|
// Leave removes the sandbox associated with container ID and detaches
|
||||||
// the network resources populated in the sandbox
|
// the network resources populated in the sandbox
|
||||||
Leave(containerID string, options ...LeaveOption) error
|
Leave(containerID string, options ...EndpointOption) error
|
||||||
|
|
||||||
// SandboxInfo returns the sandbox information for this endpoint.
|
// SandboxInfo returns the sandbox information for this endpoint.
|
||||||
SandboxInfo() *sandbox.Info
|
SandboxInfo() *sandbox.Info
|
||||||
|
@ -36,32 +38,27 @@ type Endpoint interface {
|
||||||
Delete() error
|
Delete() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EndpointOption is a option setter function type used to pass varios options to Network
|
||||||
|
// and Endpoint interfaces methods. The various setter functions of type EndpointOption are
|
||||||
|
// provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
|
||||||
|
type EndpointOption func(ep *endpoint)
|
||||||
|
|
||||||
// ContainerData is a set of data returned when a container joins an endpoint.
|
// ContainerData is a set of data returned when a container joins an endpoint.
|
||||||
type ContainerData struct {
|
type ContainerData struct {
|
||||||
SandboxKey string
|
SandboxKey string
|
||||||
HostsPath string
|
HostsPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinOption is a option setter function type used to pass varios options to
|
|
||||||
// endpoint Join method. The various setter functions of type JoinOption are
|
|
||||||
// provided by libnetwork, they look like JoinOption[...](...)
|
|
||||||
type JoinOption func(ep *endpoint)
|
|
||||||
|
|
||||||
// LeaveOption is a option setter function type used to pass varios options to
|
|
||||||
// endpoint Leave method. The various setter functions of type LeaveOption are
|
|
||||||
// provided by libnetwork, they look like LeaveOptionXXXX(...)
|
|
||||||
type LeaveOption func(ep *endpoint)
|
|
||||||
|
|
||||||
type containerConfig struct {
|
type containerConfig struct {
|
||||||
Hostname string
|
hostName string
|
||||||
Domainname string
|
domainName string
|
||||||
generic map[string]interface{}
|
generic map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type containerInfo struct {
|
type containerInfo struct {
|
||||||
ID string
|
id string
|
||||||
Config containerConfig
|
config containerConfig
|
||||||
Data ContainerData
|
data ContainerData
|
||||||
}
|
}
|
||||||
|
|
||||||
type endpoint struct {
|
type endpoint struct {
|
||||||
|
@ -71,6 +68,7 @@ type endpoint struct {
|
||||||
sandboxInfo *sandbox.Info
|
sandboxInfo *sandbox.Info
|
||||||
sandBox sandbox.Sandbox
|
sandBox sandbox.Sandbox
|
||||||
container *containerInfo
|
container *containerInfo
|
||||||
|
exposedPorts []netutils.TransportPort
|
||||||
generic map[string]interface{}
|
generic map[string]interface{}
|
||||||
context map[string]interface{}
|
context map[string]interface{}
|
||||||
}
|
}
|
||||||
|
@ -96,19 +94,6 @@ func (ep *endpoint) SandboxInfo() *sandbox.Info {
|
||||||
return ep.sandboxInfo.GetCopy()
|
return ep.sandboxInfo.GetCopy()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointOption is a option setter function type used to pass various options to
|
|
||||||
// CreateEndpoint method. The various setter functions of type EndpointOption are
|
|
||||||
// provided by libnetwork, they look like EndpointOptionXXXX(...)
|
|
||||||
type EndpointOption func(ep *endpoint)
|
|
||||||
|
|
||||||
// EndpointOptionGeneric function returns an option setter for a Generic option defined
|
|
||||||
// in a Dictionary of Key-Value pair
|
|
||||||
func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
|
||||||
return func(ep *endpoint) {
|
|
||||||
ep.generic = generic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ep *endpoint) processOptions(options ...EndpointOption) {
|
func (ep *endpoint) processOptions(options ...EndpointOption) {
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
|
@ -143,7 +128,7 @@ func createHostsFile(path string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerData, error) {
|
func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*ContainerData, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if containerID == "" {
|
if containerID == "" {
|
||||||
|
@ -161,10 +146,10 @@ func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerD
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ep.processJoinOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
||||||
ep.container.Data.HostsPath = prefix + "/" + containerID + "/hosts"
|
ep.container.data.HostsPath = prefix + "/" + containerID + "/hosts"
|
||||||
err = createHostsFile(ep.container.Data.HostsPath)
|
err = createHostsFile(ep.container.data.HostsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -186,7 +171,7 @@ func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerD
|
||||||
}()
|
}()
|
||||||
|
|
||||||
n := ep.network
|
n := ep.network
|
||||||
err = n.driver.Join(n.id, ep.id, sboxKey, ep.container.Config.generic)
|
err = n.driver.Join(n.id, ep.id, sboxKey, ep.container.config.generic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -211,28 +196,28 @@ func (ep *endpoint) Join(containerID string, options ...JoinOption) (*ContainerD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.container.ID = containerID
|
ep.container.id = containerID
|
||||||
ep.container.Data.SandboxKey = sb.Key()
|
ep.container.data.SandboxKey = sb.Key()
|
||||||
|
|
||||||
cData := ep.container.Data
|
cData := ep.container.data
|
||||||
return &cData, nil
|
return &cData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Leave(containerID string, options ...LeaveOption) error {
|
func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
|
||||||
if ep.container == nil || ep.container.ID == "" ||
|
if ep.container == nil || ep.container.id == "" ||
|
||||||
containerID == "" || ep.container.ID != containerID {
|
containerID == "" || ep.container.id != containerID {
|
||||||
return InvalidContainerIDError(containerID)
|
return InvalidContainerIDError(containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
n := ep.network
|
ep.processOptions(options...)
|
||||||
ep.processLeaveOptions(options...)
|
|
||||||
|
|
||||||
|
n := ep.network
|
||||||
err := n.driver.Leave(n.id, ep.id, ep.context)
|
err := n.driver.Leave(n.id, ep.id, ep.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.network.ctrlr.sandboxRm(ep.container.Data.SandboxKey)
|
ep.network.ctrlr.sandboxRm(ep.container.data.SandboxKey)
|
||||||
ep.container = nil
|
ep.container = nil
|
||||||
ep.context = nil
|
ep.context = nil
|
||||||
return nil
|
return nil
|
||||||
|
@ -266,9 +251,9 @@ func (ep *endpoint) Delete() error {
|
||||||
func (ep *endpoint) buildHostsFiles() error {
|
func (ep *endpoint) buildHostsFiles() error {
|
||||||
var extraContent []etchosts.Record
|
var extraContent []etchosts.Record
|
||||||
|
|
||||||
name := ep.container.Config.Hostname
|
name := ep.container.config.hostName
|
||||||
if ep.container.Config.Domainname != "" {
|
if ep.container.config.domainName != "" {
|
||||||
name = name + "." + ep.container.Config.Domainname
|
name = name + "." + ep.container.config.domainName
|
||||||
}
|
}
|
||||||
|
|
||||||
IP := ""
|
IP := ""
|
||||||
|
@ -277,56 +262,64 @@ func (ep *endpoint) buildHostsFiles() error {
|
||||||
IP = ep.sandboxInfo.Interfaces[0].Address.IP.String()
|
IP = ep.sandboxInfo.Interfaces[0].Address.IP.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return etchosts.Build(ep.container.Data.HostsPath, IP, ep.container.Config.Hostname,
|
return etchosts.Build(ep.container.data.HostsPath, IP, ep.container.config.hostName,
|
||||||
ep.container.Config.Domainname, extraContent)
|
ep.container.config.domainName, extraContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointOptionGeneric function returns an option setter for a Generic option defined
|
||||||
|
// in a Dictionary of Key-Value pair
|
||||||
|
func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
||||||
|
return func(ep *endpoint) {
|
||||||
|
for k, v := range generic {
|
||||||
|
ep.generic[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinOptionHostname function returns an option setter for hostname option to
|
// JoinOptionHostname function returns an option setter for hostname option to
|
||||||
// be passed to endpoint Join method.
|
// be passed to endpoint Join method.
|
||||||
func JoinOptionHostname(name string) JoinOption {
|
func JoinOptionHostname(name string) EndpointOption {
|
||||||
return func(ep *endpoint) {
|
return func(ep *endpoint) {
|
||||||
ep.container.Config.Hostname = name
|
ep.container.config.hostName = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinOptionDomainname function returns an option setter for domainname option to
|
// JoinOptionDomainname function returns an option setter for domainname option to
|
||||||
// be passed to endpoint Join method.
|
// be passed to endpoint Join method.
|
||||||
func JoinOptionDomainname(name string) JoinOption {
|
func JoinOptionDomainname(name string) EndpointOption {
|
||||||
return func(ep *endpoint) {
|
return func(ep *endpoint) {
|
||||||
ep.container.Config.Domainname = name
|
ep.container.config.domainName = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptionPortMapping function returns an option setter for the container exposed
|
||||||
|
// ports option to be passed to network.CreateEndpoint() method.
|
||||||
|
func CreateOptionPortMapping(portBindings []netutils.PortBinding) EndpointOption {
|
||||||
|
return func(ep *endpoint) {
|
||||||
|
// Store endpoint label
|
||||||
|
ep.generic[options.PortMap] = portBindings
|
||||||
|
// Extract exposed ports as this is the only concern of libnetwork endpoint
|
||||||
|
ep.exposedPorts = make([]netutils.TransportPort, 0, len(portBindings))
|
||||||
|
for _, b := range portBindings {
|
||||||
|
ep.exposedPorts = append(ep.exposedPorts, netutils.TransportPort{Proto: b.Proto, Port: b.Port})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinOptionGeneric function returns an option setter for Generic configuration
|
// JoinOptionGeneric function returns an option setter for Generic configuration
|
||||||
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
||||||
// endpoint join method. Container Labels are a good example.
|
// endpoint join method. Container Labels are a good example.
|
||||||
func JoinOptionGeneric(generic map[string]interface{}) JoinOption {
|
func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
|
||||||
return func(ep *endpoint) {
|
return func(ep *endpoint) {
|
||||||
ep.container.Config.generic = generic
|
ep.container.config.generic = generic
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ep *endpoint) processJoinOptions(options ...JoinOption) {
|
|
||||||
for _, opt := range options {
|
|
||||||
if opt != nil {
|
|
||||||
opt(ep)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveOptionGeneric function returns an option setter for Generic configuration
|
// LeaveOptionGeneric function returns an option setter for Generic configuration
|
||||||
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
||||||
// endpoint leave method. Container Labels are a good example.
|
// endpoint leave method. Container Labels are a good example.
|
||||||
func LeaveOptionGeneric(context map[string]interface{}) JoinOption {
|
func LeaveOptionGeneric(context map[string]interface{}) EndpointOption {
|
||||||
return func(ep *endpoint) {
|
return func(ep *endpoint) {
|
||||||
ep.context = context
|
ep.context = context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) processLeaveOptions(options ...LeaveOption) {
|
|
||||||
for _, opt := range options {
|
|
||||||
if opt != nil {
|
|
||||||
opt(ep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,19 +2,28 @@ package libnetwork_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
"github.com/docker/libnetwork/pkg/options"
|
"github.com/docker/libnetwork/pkg/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
netType = "bridge"
|
bridgeNetType = "bridge"
|
||||||
bridgeName = "dockertest0"
|
bridgeName = "docker0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
func createTestNetwork(networkType, networkName string, option options.Generic) (libnetwork.Network, error) {
|
func createTestNetwork(networkType, networkName string, option options.Generic) (libnetwork.Network, error) {
|
||||||
controller := libnetwork.New()
|
controller := libnetwork.New()
|
||||||
genericOption := make(map[string]interface{})
|
genericOption := make(map[string]interface{})
|
||||||
|
@ -39,6 +48,14 @@ func getEmptyGenericOption() map[string]interface{} {
|
||||||
return genericOption
|
return genericOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPortMapping() []netutils.PortBinding {
|
||||||
|
return []netutils.PortBinding{
|
||||||
|
netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
||||||
|
netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
||||||
|
netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNull(t *testing.T) {
|
func TestNull(t *testing.T) {
|
||||||
network, err := createTestNetwork("null", "testnetwork", options.Generic{})
|
network, err := createTestNetwork("null", "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -104,12 +121,12 @@ func TestBridge(t *testing.T) {
|
||||||
"EnableIPForwarding": true,
|
"EnableIPForwarding": true,
|
||||||
"AllowNonDefaultBridge": true}
|
"AllowNonDefaultBridge": true}
|
||||||
|
|
||||||
network, err := createTestNetwork(netType, "testnetwork", option)
|
network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, err := network.CreateEndpoint("testep")
|
ep, err := network.CreateEndpoint("testep", libnetwork.CreateOptionPortMapping(getPortMapping()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -171,17 +188,17 @@ func TestDuplicateNetwork(t *testing.T) {
|
||||||
genericOption := make(map[string]interface{})
|
genericOption := make(map[string]interface{})
|
||||||
genericOption[options.GenericData] = options.Generic{}
|
genericOption[options.GenericData] = options.Generic{}
|
||||||
|
|
||||||
err := controller.ConfigureNetworkDriver(netType, genericOption)
|
err := controller.ConfigureNetworkDriver(bridgeNetType, genericOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = controller.NewNetwork(netType, "testnetwork", nil)
|
_, err = controller.NewNetwork(bridgeNetType, "testnetwork", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = controller.NewNetwork(netType, "testnetwork")
|
_, err = controller.NewNetwork(bridgeNetType, "testnetwork")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Expected to fail. But instead succeeded")
|
t.Fatal("Expected to fail. But instead succeeded")
|
||||||
}
|
}
|
||||||
|
@ -192,9 +209,10 @@ func TestDuplicateNetwork(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNetworkName(t *testing.T) {
|
func TestNetworkName(t *testing.T) {
|
||||||
|
defer netutils.SetupTestNetNS(t)()
|
||||||
networkName := "testnetwork"
|
networkName := "testnetwork"
|
||||||
|
|
||||||
n, err := createTestNetwork(netType, networkName, options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, networkName, options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -205,22 +223,21 @@ func TestNetworkName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNetworkType(t *testing.T) {
|
func TestNetworkType(t *testing.T) {
|
||||||
networkType := netType
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
n, err := createTestNetwork(networkType, "testnetwork", options.Generic{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Type() != networkType {
|
if n.Type() != bridgeNetType {
|
||||||
t.Fatalf("Expected network type %s, got %s", networkType, n.Type())
|
t.Fatalf("Expected network type %s, got %s", bridgeNetType, n.Type())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNetworkID(t *testing.T) {
|
func TestNetworkID(t *testing.T) {
|
||||||
networkType := netType
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
|
||||||
n, err := createTestNetwork(networkType, "testnetwork", options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -236,7 +253,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
|
||||||
"BridgeName": bridgeName,
|
"BridgeName": bridgeName,
|
||||||
"AllowNonDefaultBridge": true}
|
"AllowNonDefaultBridge": true}
|
||||||
|
|
||||||
network, err := createTestNetwork(netType, "testnetwork", option)
|
network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -271,7 +288,7 @@ func TestUnknownNetwork(t *testing.T) {
|
||||||
"BridgeName": bridgeName,
|
"BridgeName": bridgeName,
|
||||||
"AllowNonDefaultBridge": true}
|
"AllowNonDefaultBridge": true}
|
||||||
|
|
||||||
network, err := createTestNetwork(netType, "testnetwork", option)
|
network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -304,7 +321,7 @@ func TestUnknownEndpoint(t *testing.T) {
|
||||||
"AddressIPv4": subnet,
|
"AddressIPv4": subnet,
|
||||||
"AllowNonDefaultBridge": true}
|
"AllowNonDefaultBridge": true}
|
||||||
|
|
||||||
network, err := createTestNetwork(netType, "testnetwork", option)
|
network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -337,15 +354,14 @@ func TestUnknownEndpoint(t *testing.T) {
|
||||||
func TestNetworkEndpointsWalkers(t *testing.T) {
|
func TestNetworkEndpointsWalkers(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
controller := libnetwork.New()
|
controller := libnetwork.New()
|
||||||
netType := "bridge"
|
|
||||||
|
|
||||||
err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
|
err := controller.ConfigureNetworkDriver(bridgeNetType, getEmptyGenericOption())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create network 1 and add 2 endpoint: ep11, ep12
|
// Create network 1 and add 2 endpoint: ep11, ep12
|
||||||
net1, err := controller.NewNetwork(netType, "network1")
|
net1, err := controller.NewNetwork(bridgeNetType, "network1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -416,15 +432,14 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
|
||||||
func TestControllerQuery(t *testing.T) {
|
func TestControllerQuery(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
controller := libnetwork.New()
|
controller := libnetwork.New()
|
||||||
netType := "bridge"
|
|
||||||
|
|
||||||
err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
|
err := controller.ConfigureNetworkDriver(bridgeNetType, getEmptyGenericOption())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create network 1
|
// Create network 1
|
||||||
net1, err := controller.NewNetwork(netType, "network1")
|
net1, err := controller.NewNetwork(bridgeNetType, "network1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -461,15 +476,14 @@ func TestControllerQuery(t *testing.T) {
|
||||||
func TestNetworkQuery(t *testing.T) {
|
func TestNetworkQuery(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
controller := libnetwork.New()
|
controller := libnetwork.New()
|
||||||
netType := "bridge"
|
|
||||||
|
|
||||||
err := controller.ConfigureNetworkDriver(netType, getEmptyGenericOption())
|
err := controller.ConfigureNetworkDriver(bridgeNetType, getEmptyGenericOption())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create network 1 and add 2 endpoint: ep11, ep12
|
// Create network 1 and add 2 endpoint: ep11, ep12
|
||||||
net1, err := controller.NewNetwork(netType, "network1")
|
net1, err := controller.NewNetwork(bridgeNetType, "network1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -514,7 +528,7 @@ const containerID = "valid_container"
|
||||||
func TestEndpointJoin(t *testing.T) {
|
func TestEndpointJoin(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
|
||||||
n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -540,7 +554,7 @@ func TestEndpointJoin(t *testing.T) {
|
||||||
func TestEndpointJoinInvalidContainerId(t *testing.T) {
|
func TestEndpointJoinInvalidContainerId(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
|
||||||
n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -563,7 +577,7 @@ func TestEndpointJoinInvalidContainerId(t *testing.T) {
|
||||||
func TestEndpointMultipleJoins(t *testing.T) {
|
func TestEndpointMultipleJoins(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
|
||||||
n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -599,7 +613,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
|
||||||
func TestEndpointInvalidLeave(t *testing.T) {
|
func TestEndpointInvalidLeave(t *testing.T) {
|
||||||
defer netutils.SetupTestNetNS(t)()
|
defer netutils.SetupTestNetNS(t)()
|
||||||
|
|
||||||
n, err := createTestNetwork("bridge", "testnetwork", options.Generic{})
|
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
@ -25,6 +26,102 @@ var (
|
||||||
networkGetRoutesFct = netlink.RouteList
|
networkGetRoutesFct = netlink.RouteList
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
|
||||||
|
type ErrInvalidProtocolBinding string
|
||||||
|
|
||||||
|
func (ipb ErrInvalidProtocolBinding) Error() string {
|
||||||
|
return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransportPort represent a local Layer 4 endpoint
|
||||||
|
type TransportPort struct {
|
||||||
|
Proto Protocol
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortBinding represent a port binding between the container an the host
|
||||||
|
type PortBinding struct {
|
||||||
|
Proto Protocol
|
||||||
|
IP net.IP
|
||||||
|
Port uint16
|
||||||
|
HostIP net.IP
|
||||||
|
HostPort uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostAddr returns the host side tranport address
|
||||||
|
func (p PortBinding) HostAddr() (net.Addr, error) {
|
||||||
|
switch p.Proto {
|
||||||
|
case UDP:
|
||||||
|
return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
||||||
|
case TCP:
|
||||||
|
return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
||||||
|
default:
|
||||||
|
return nil, ErrInvalidProtocolBinding(p.Proto.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerAddr returns the container side tranport address
|
||||||
|
func (p PortBinding) ContainerAddr() (net.Addr, error) {
|
||||||
|
switch p.Proto {
|
||||||
|
case UDP:
|
||||||
|
return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
||||||
|
case TCP:
|
||||||
|
return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
||||||
|
default:
|
||||||
|
return nil, ErrInvalidProtocolBinding(p.Proto.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCopy returns a copy of this PortBinding structure instance
|
||||||
|
func (p *PortBinding) GetCopy() PortBinding {
|
||||||
|
return PortBinding{
|
||||||
|
Proto: p.Proto,
|
||||||
|
IP: GetIPCopy(p.IP),
|
||||||
|
Port: p.Port,
|
||||||
|
HostIP: GetIPCopy(p.HostIP),
|
||||||
|
HostPort: p.HostPort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ICMP is for the ICMP ip protocol
|
||||||
|
ICMP = 1
|
||||||
|
// TCP is for the TCP ip protocol
|
||||||
|
TCP = 6
|
||||||
|
// UDP is for the UDP ip protocol
|
||||||
|
UDP = 17
|
||||||
|
)
|
||||||
|
|
||||||
|
// Protocol represents a IP protocol number
|
||||||
|
type Protocol uint8
|
||||||
|
|
||||||
|
func (p Protocol) String() string {
|
||||||
|
switch p {
|
||||||
|
case 1:
|
||||||
|
return "icmp"
|
||||||
|
case 6:
|
||||||
|
return "tcp"
|
||||||
|
case 17:
|
||||||
|
return "udp"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%d", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseProtocol returns the respective Protocol type for the passed string
|
||||||
|
func ParseProtocol(s string) Protocol {
|
||||||
|
switch strings.ToLower(s) {
|
||||||
|
case "icmp":
|
||||||
|
return 1
|
||||||
|
case "udp":
|
||||||
|
return 6
|
||||||
|
case "tcp":
|
||||||
|
return 17
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers
|
// CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers
|
||||||
func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
||||||
if len(nameservers) > 0 {
|
if len(nameservers) > 0 {
|
||||||
|
|
|
@ -127,7 +127,7 @@ func (n *network) Delete() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
|
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
|
||||||
ep := &endpoint{name: name}
|
ep := &endpoint{name: name, generic: make(map[string]interface{})}
|
||||||
ep.id = types.UUID(stringid.GenerateRandomID())
|
ep.id = types.UUID(stringid.GenerateRandomID())
|
||||||
ep.network = n
|
ep.network = n
|
||||||
ep.processOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
Loading…
Add table
Reference in a new issue