From d3381741026ae2b3770c10fc5fa3e628942324e0 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 08:54:20 +0800 Subject: [PATCH 01/16] VENDOR: Ensure dbus/transport_unix.go implements the SendNullByte method ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/libcontainerd .gopath/src/github.com/docker/docker/libcontainerd/client.go:13: undefined: container .gopath/src/github.com/docker/docker/libcontainerd/types.go:32: undefined: StateInfo # github.com/docker/docker/vendor/github.com/godbus/dbus .gopath/src/github.com/docker/docker/vendor/github.com/godbus/dbus/transport_unix.go:51: cannot use t (type *unixTransport) as type transport in return argument: *unixTransport does not implement transport (missing SendNullByte method) .gopath/src/github.com/docker/docker/vendor/github.com/godbus/dbus/transport_unix.go:57: cannot use t (type *unixTransport) as type transport in return argument: *unixTransport does not implement transport (missing SendNullByte method) Signed-off-by: R Tyler Croy --- vendor/github.com/godbus/dbus/transport_unix.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vendor/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/godbus/dbus/transport_unix.go index a1d00cbc1247f..064582a860481 100644 --- a/vendor/github.com/godbus/dbus/transport_unix.go +++ b/vendor/github.com/godbus/dbus/transport_unix.go @@ -194,3 +194,8 @@ func (t *unixTransport) SendMessage(msg *Message) error { func (t *unixTransport) SupportsUnixFDs() bool { return true } + +func (t *unixTransport) SendNullByte() error { + _, err := t.Write([]byte{0}) + return err +} From b193b2ac817756bc78d27a94dd52c2bcb344672b Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:00:31 +0800 Subject: [PATCH 02/16] Allow libcontainer/container_unix to build on FreeBSD ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/libcontainerd .gopath/src/github.com/docker/docker/libcontainerd/client.go:13: undefined: container .gopath/src/github.com/docker/docker/libcontainerd/types.go:32: undefined: StateInfo Signed-off-by: R Tyler Croy --- libcontainerd/container_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcontainerd/container_unix.go b/libcontainerd/container_unix.go index 61bab145f2a29..c9e1d0b8dc9de 100644 --- a/libcontainerd/container_unix.go +++ b/libcontainerd/container_unix.go @@ -1,4 +1,4 @@ -// +build linux solaris +// +build linux solaris freebsd package libcontainerd From 43556eb98d7925048e906f8d1b65283c029bb2e2 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:02:08 +0800 Subject: [PATCH 03/16] VENDOR: Avoid building netlink/filter and correct some invalid function references # github.com/docker/docker/vendor/github.com/vishvananda/netlink .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/filter.go:189: undefined: nl.TC_U32_TERMINAL .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/filter.go:190: undefined: nl.TC_U32_OFFSET .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/filter.go:191: undefined: nl.TC_U32_VAROFFSET .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/filter.go:192: undefined: nl.TC_U32_EAT # github.com/docker/docker/vendor/github.com/vishvananda/netlink .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/handle_unspecified.go:184: undefined: Filter .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/handle_unspecified.go:188: undefined: Filter .gopath/src/github.com/docker/docker/vendor/github.com/vishvananda/netlink/handle_unspecified.go:192: undefined: Filter Signed-off-by: R Tyler Croy --- vendor/github.com/vishvananda/netlink/filter.go | 2 ++ .../vishvananda/netlink/handle_unspecified.go | 12 ------------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/vendor/github.com/vishvananda/netlink/filter.go b/vendor/github.com/vishvananda/netlink/filter.go index 938b28b0b03bd..a6b7b637c77be 100644 --- a/vendor/github.com/vishvananda/netlink/filter.go +++ b/vendor/github.com/vishvananda/netlink/filter.go @@ -1,3 +1,5 @@ +// +build linux + package netlink import ( diff --git a/vendor/github.com/vishvananda/netlink/handle_unspecified.go b/vendor/github.com/vishvananda/netlink/handle_unspecified.go index 32cf022732de4..2d33aabb3adb9 100644 --- a/vendor/github.com/vishvananda/netlink/handle_unspecified.go +++ b/vendor/github.com/vishvananda/netlink/handle_unspecified.go @@ -181,18 +181,6 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { return nil, ErrNotImplemented } -func (h *Handle) FilterDel(filter Filter) error { - return ErrNotImplemented -} - -func (h *Handle) FilterAdd(filter Filter) error { - return ErrNotImplemented -} - -func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) { - return nil, ErrNotImplemented -} - func (h *Handle) NeighAdd(neigh *Neigh) error { return ErrNotImplemented } From 6ee77b525471fa93b8b72cfdca4666e06a28c52b Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:11:23 +0800 Subject: [PATCH 04/16] Ensure libcontainerd/process_unix builds on FreeBSD ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/libcontainerd .gopath/src/github.com/docker/docker/libcontainerd/container.go:11: undefined: process .gopath/src/github.com/docker/docker/libcontainerd/container.go:12: undefined: process Signed-off-by: R Tyler Croy --- libcontainerd/process_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcontainerd/process_unix.go b/libcontainerd/process_unix.go index 506fca6e11c74..f45da6f5614e9 100644 --- a/libcontainerd/process_unix.go +++ b/libcontainerd/process_unix.go @@ -1,4 +1,4 @@ -// +build linux solaris +// +build linux solaris freebsd package libcontainerd From 0a240a5fe7010740163f50b7415a0eae8a82e1ec Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:12:30 +0800 Subject: [PATCH 05/16] VENDOR: Allow tonistiigi/fifo to build properly on FreeBSD This /might/ cause some issues further down the line, we'll see. But it appears that some stat_t data structures are differently sized on Linux vs. FreeBSD ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/vendor/github.com/tonistiigi/fifo .gopath/src/github.com/docker/docker/vendor/github.com/tonistiigi/fifo/handle_nolinux.go:26: cannot use stat.Ino (type uint32) as type uint64 in field value .gopath/src/github.com/docker/docker/vendor/github.com/tonistiigi/fifo/handle_nolinux.go:37: invalid operation: stat.Ino != h.ino (mismatched types uint32 and uint64) Signed-off-by: R Tyler Croy --- vendor/github.com/tonistiigi/fifo/handle_nolinux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/github.com/tonistiigi/fifo/handle_nolinux.go b/vendor/github.com/tonistiigi/fifo/handle_nolinux.go index d9648d8bfa26d..5dbc716be18e9 100644 --- a/vendor/github.com/tonistiigi/fifo/handle_nolinux.go +++ b/vendor/github.com/tonistiigi/fifo/handle_nolinux.go @@ -11,7 +11,7 @@ import ( type handle struct { fn string dev uint64 - ino uint64 + ino uint32 } func getHandle(fn string) (*handle, error) { From c3c988bc0a3ee146013071f9b877ec7b1acc30cf Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:13:59 +0800 Subject: [PATCH 06/16] Allow libcontainerd/client to build properly on FreeBSD ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/libcontainerd .gopath/src/github.com/docker/docker/libcontainerd/process.go:7: undefined: client Signed-off-by: R Tyler Croy --- libcontainerd/client_unix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcontainerd/client_unix.go b/libcontainerd/client_unix.go index 21e8fea666bb6..9aedd44f47a24 100644 --- a/libcontainerd/client_unix.go +++ b/libcontainerd/client_unix.go @@ -1,4 +1,4 @@ -// +build linux solaris +// +build linux solaris freebsd package libcontainerd From ed1efb503de5d835b60b751aab3db41dbf3302c2 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:34:31 +0800 Subject: [PATCH 07/16] Allow libcontainerd to build properly on FreeBSD This includes some changes where the libcontainer code is simply running the same stubs that it would have previously been running on Solaris Signed-off-by: R Tyler Croy --- libcontainerd/client_freebsd.go | 104 ++++++++++++++++++ libcontainerd/{oom_solaris.go => oom_unix.go} | 2 + libcontainerd/queue_unix.go | 2 +- libcontainerd/remote_unix.go | 2 +- libcontainerd/types_freebsd.go | 43 ++++++++ .../{utils_solaris.go => utils_unix.go} | 2 + 6 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 libcontainerd/client_freebsd.go rename libcontainerd/{oom_solaris.go => oom_unix.go} (65%) create mode 100644 libcontainerd/types_freebsd.go rename libcontainerd/{utils_solaris.go => utils_unix.go} (92%) diff --git a/libcontainerd/client_freebsd.go b/libcontainerd/client_freebsd.go new file mode 100644 index 0000000000000..b9206ab511226 --- /dev/null +++ b/libcontainerd/client_freebsd.go @@ -0,0 +1,104 @@ +package libcontainerd + +import ( + "golang.org/x/net/context" + containerd "github.com/docker/containerd/api/grpc/types" +) + +type client struct { + clientCommon + + // Platform specific properties below here. + remote *remote + q queue + exitNotifiers map[string]*exitNotifier + liveRestore bool +} + +// GetServerVersion returns the connected server version information +func (clnt *client) GetServerVersion(ctx context.Context) (*ServerVersion, error) { + resp, err := clnt.remote.apiClient.GetServerVersion(ctx, &containerd.GetServerVersionRequest{}) + if err != nil { + return nil, err + } + + sv := &ServerVersion{ + GetServerVersionResponse: *resp, + } + + return sv, nil +} + +func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendlyName string, specp Process, attachStdio StdioCallback) (int, error) { + return -1, nil +} + +func (clnt *client) SignalProcess(containerID string, pid string, sig int) error { + return nil +} + +func (clnt *client) Resize(containerID, processFriendlyName string, width, height int) error { + return nil +} + +func (clnt *client) Pause(containerID string) error { + return nil +} + +func (clnt *client) Resume(containerID string) error { + return nil +} + +func (clnt *client) Stats(containerID string) (*Stats, error) { + return nil, nil +} + +func (clnt *client) getExitNotifier(containerID string) *exitNotifier { + clnt.mapMutex.RLock() + defer clnt.mapMutex.RUnlock() + return clnt.exitNotifiers[containerID] +} + +func (clnt *client) getOrCreateExitNotifier(containerID string) *exitNotifier { + clnt.mapMutex.Lock() + defer clnt.mapMutex.Unlock() + w, ok := clnt.exitNotifiers[containerID] + if !ok { + w = &exitNotifier{c: make(chan struct{}), client: clnt} + clnt.exitNotifiers[containerID] = w + } + return w +} + +// Restore is the handler for restoring a container +func (clnt *client) Restore(containerID string, attachStdio StdioCallback, options ...CreateOption) error { + return nil +} + +func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) { + return nil, nil +} + +// Summary returns a summary of the processes running in a container. +func (clnt *client) Summary(containerID string) ([]Summary, error) { + return nil, nil +} + +// UpdateResources updates resources for a running container. +func (clnt *client) UpdateResources(containerID string, resources Resources) error { + // Updating resource isn't supported on Solaris + // but we should return nil for enabling updating container + return nil +} + +func (clnt *client) CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error { + return nil +} + +func (clnt *client) DeleteCheckpoint(containerID string, checkpointID string, checkpointDir string) error { + return nil +} + +func (clnt *client) ListCheckpoints(containerID string, checkpointDir string) (*Checkpoints, error) { + return nil, nil +} diff --git a/libcontainerd/oom_solaris.go b/libcontainerd/oom_unix.go similarity index 65% rename from libcontainerd/oom_solaris.go rename to libcontainerd/oom_unix.go index 2ebe5e87cf23f..6b66a53cc043d 100644 --- a/libcontainerd/oom_solaris.go +++ b/libcontainerd/oom_unix.go @@ -1,3 +1,5 @@ +// +build solaris,freebsd +build !linux + package libcontainerd func setOOMScore(pid, score int) error { diff --git a/libcontainerd/queue_unix.go b/libcontainerd/queue_unix.go index b848b9872b9e5..dae16897cb66a 100644 --- a/libcontainerd/queue_unix.go +++ b/libcontainerd/queue_unix.go @@ -1,4 +1,4 @@ -// +build linux solaris +// +build linux solaris freebsd package libcontainerd diff --git a/libcontainerd/remote_unix.go b/libcontainerd/remote_unix.go index eebbc886c69c1..a5b93715038b8 100644 --- a/libcontainerd/remote_unix.go +++ b/libcontainerd/remote_unix.go @@ -1,4 +1,4 @@ -// +build linux solaris +// +build linux solaris freebsd package libcontainerd diff --git a/libcontainerd/types_freebsd.go b/libcontainerd/types_freebsd.go new file mode 100644 index 0000000000000..dbafef669fe03 --- /dev/null +++ b/libcontainerd/types_freebsd.go @@ -0,0 +1,43 @@ +package libcontainerd + +import ( + containerd "github.com/docker/containerd/api/grpc/types" + "github.com/opencontainers/runtime-spec/specs-go" +) + +// Process contains information to start a specific application inside the container. +type Process struct { + // Terminal creates an interactive terminal for the container. + Terminal bool `json:"terminal"` + // User specifies user information for the process. + User *specs.User `json:"user"` + // Args specifies the binary and arguments for the application to execute. + Args []string `json:"args"` + // Env populates the process environment for the process. + Env []string `json:"env,omitempty"` + // Cwd is the current working directory for the process and must be + // relative to the container's root. + Cwd *string `json:"cwd"` + // Capabilities are linux capabilities that are kept for the container. + Capabilities []string `json:"capabilities,omitempty"` +} + +// Stats contains a stats properties from containerd. +type Stats struct{} + +// Summary contains a container summary from containerd +type Summary struct{} + +// StateInfo contains description about the new state container has entered. +type StateInfo struct { + CommonStateInfo + + // Platform specific StateInfo + OOMKilled bool +} + +// Resources defines updatable container resource values. +type Resources struct{} + +// Checkpoints contains the details of a checkpoint +type Checkpoints containerd.ListCheckpointResponse diff --git a/libcontainerd/utils_solaris.go b/libcontainerd/utils_unix.go similarity index 92% rename from libcontainerd/utils_solaris.go rename to libcontainerd/utils_unix.go index 49632b45e544f..153c5e393f71d 100644 --- a/libcontainerd/utils_solaris.go +++ b/libcontainerd/utils_unix.go @@ -1,3 +1,5 @@ +// +build solaris,freebsd +build !linux + package libcontainerd import ( From 56e66bcdf4de9c3a4f37d9727943a27d1b3bfe3c Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 09:37:27 +0800 Subject: [PATCH 08/16] Re-use the plugin/manager stubs for Solaris on FreeBSD as well ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/plugin .gopath/src/github.com/docker/docker/plugin/manager.go:37: pm.restore undefined (type *Manager has no field or method restore) .gopath/src/github.com/docker/docker/plugin/manager.go:157: pm.enable undefined (type *Manager has no field or method enable, but does have Enable) .gopath/src/github.com/docker/docker/plugin/manager.go:238: pm.enable undefined (type *Manager has no field or method enable, but does have Enable) Signed-off-by: R Tyler Croy --- plugin/{manager_solaris.go => manager_unix.go} | 2 ++ 1 file changed, 2 insertions(+) rename plugin/{manager_solaris.go => manager_unix.go} (93%) diff --git a/plugin/manager_solaris.go b/plugin/manager_unix.go similarity index 93% rename from plugin/manager_solaris.go rename to plugin/manager_unix.go index 72ccae72d3208..455b68d62f411 100644 --- a/plugin/manager_solaris.go +++ b/plugin/manager_unix.go @@ -1,3 +1,5 @@ +// +build solaris,freebsd +build !linux + package plugin import ( From d9d105446bf9c797cca0c5dcf366971c265823fe Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 15 Aug 2017 10:52:44 +0800 Subject: [PATCH 09/16] Vendor my fork of libnetwork at the current HEAD of freebsd-compat-17.05 That branch has the FreeBSD patches picked on top of the 17.05.0-ce vendored libnetwork commit: 9af8d173c7e95e432e4af19e584e8a9a40a9a054 --- .../drivers/freebsd/bridge/bridge.go | 1094 +++++++++++++++++ .../drivers/freebsd/bridge/bridge_store.go | 384 ++++++ .../drivers/freebsd/bridge/errors.go | 120 ++ .../drivers/freebsd/bridge/port_mapping.go | 235 ++++ .../docker/libnetwork/drivers_freebsd.go | 2 + .../docker/libnetwork/iptables/conntrack.go | 2 + .../libnetwork/netutils/utils_freebsd.go | 32 +- .../docker/libnetwork/ns/init_unspecified.go | 1 + .../portallocator/portallocator_freebsd.go | 42 + .../{proxy_solaris.go => proxy_unix.go} | 2 + .../docker/libnetwork/resolver_freebsd.go | 6 + .../docker/libnetwork/resolver_unix.go | 2 +- .../docker/libnetwork/service_unsupported.go | 20 + 13 files changed, 1940 insertions(+), 2 deletions(-) create mode 100644 vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge.go create mode 100644 vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge_store.go create mode 100644 vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/errors.go create mode 100644 vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/port_mapping.go create mode 100644 vendor/github.com/docker/libnetwork/ns/init_unspecified.go create mode 100644 vendor/github.com/docker/libnetwork/portallocator/portallocator_freebsd.go rename vendor/github.com/docker/libnetwork/portmapper/{proxy_solaris.go => proxy_unix.go} (94%) create mode 100644 vendor/github.com/docker/libnetwork/resolver_freebsd.go diff --git a/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge.go b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge.go new file mode 100644 index 0000000000000..0c435c96e2d50 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge.go @@ -0,0 +1,1094 @@ +// +build freebsd + +package bridge + +import ( + //"bufio" + "errors" + "fmt" + "net" + //"os" + "os/exec" + "strconv" + //"strings" + "sync" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/driverapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/options" + //"github.com/docker/libnetwork/portmapper" // ==> iptables ==> netlink + "github.com/docker/libnetwork/types" +) + +const ( + networkType = "bridge" + + // DefaultBridgeName is the default name for the bridge interface managed + // by the driver when unspecified by the caller. + DefaultBridgeName = "bridge0" + + // BridgeName label for bridge driver + BridgeName = "com.docker.network.bridge.name" + + // EnableIPMasquerade label for bridge driver + EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade" + + // EnableICC label + EnableICC = "com.docker.network.bridge.enable_icc" + + // DefaultBindingIP label + DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4" + + // DefaultBridge label + DefaultBridge = "com.docker.network.bridge.default_bridge" + + // DefaultGatewayV4AuxKey represents the default-gateway configured by the user + DefaultGatewayV4AuxKey = "DefaultGatewayIPv4" + + // DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user + DefaultGatewayV6AuxKey = "DefaultGatewayIPv6" +) + +// configuration info for the "bridge" driver. +type configuration struct { + EnableIPForwarding bool + EnableIPTables bool + EnableUserlandProxy bool +} + +// networkConfiguration for network specific configuration +type networkConfiguration struct { + ID string + BridgeName string + BridgeNameInternal string + EnableIPv6 bool + EnableIPMasquerade bool + EnableICC bool + Mtu int + DefaultBindingIntf string + DefaultBindingIP net.IP + DefaultBridge bool + // Internal fields set after ipam data parsing + AddressIPv4 *net.IPNet + AddressIPv6 *net.IPNet + DefaultGatewayIPv4 net.IP + DefaultGatewayIPv6 net.IP + dbIndex uint64 + dbExists bool + Internal bool +} + +// endpointConfiguration represents the user specified configuration for the sandbox endpoint +type endpointConfiguration struct { + MacAddress net.HardwareAddr + PortBindings []types.PortBinding + ExposedPorts []types.TransportPort +} + +// containerConfiguration represents the user specified configuration for a container +type containerConfiguration struct { + ParentEndpoints []string + ChildEndpoints []string +} + +// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity +type connectivityConfiguration struct { + PortBindings []types.PortBinding + ExposedPorts []types.TransportPort +} + +type bridgeEndpoint struct { + id string + nid string + srcName string + addr *net.IPNet + addrv6 *net.IPNet + macAddress net.HardwareAddr + config *endpointConfiguration // User specified parameters + containerConfig *containerConfiguration + extConnConfig *connectivityConfiguration + portMapping []types.PortBinding // Operation port bindings + dbIndex uint64 + dbExists bool +} + +type bridgeInterface struct { + bridgeIPv4 *net.IPNet + bridgeIPv6 *net.IPNet + gatewayIPv4 net.IP + gatewayIPv6 net.IP +} + +type bridgeNetwork struct { + id string + bridge *bridgeInterface + config *networkConfiguration + endpoints map[string]*bridgeEndpoint // key: endpoint id + //portMapper *portmapper.PortMapper + driver *driver // The network's driver + sync.Mutex +} + +type driver struct { + config *configuration + network *bridgeNetwork + //natChain *iptables.ChainInfo + //filterChain *iptables.ChainInfo + //isolationChain *iptables.ChainInfo + networks map[string]*bridgeNetwork + store datastore.DataStore + sync.Mutex + defrouteIP net.IP +} + +// New constructs a new bridge driver +func newDriver() *driver { + return &driver{networks: map[string]*bridgeNetwork{}} +} + +// Init registers a new instance of bridge driver +func Init(dc driverapi.DriverCallback, config map[string]interface{}) error { + d := newDriver() + if err := d.configure(config); err != nil { + return err + } + + c := driverapi.Capability{ + DataScope: datastore.LocalScope, + } + return dc.RegisterDriver(networkType, d, c) +} + +func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { + return nil, types.NotImplementedErrorf("not implemented") +} + +func (d *driver) NetworkFree(id string) error { + return types.NotImplementedErrorf("not implemented") +} + +func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { +} + +func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) { + return "", nil +} + +func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { + if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" { + return types.BadRequestErrorf("ipv4 pool is empty") + } + // Sanity checks + d.Lock() + if _, ok := d.networks[id]; ok { + d.Unlock() + return types.ForbiddenErrorf("network %s exists", id) + } + d.Unlock() + + // Parse and validate the config. It should not conflict with existing networks' config + config, err := parseNetworkOptions(d, id, option) + if err != nil { + return err + } + + err = config.processIPAM(id, ipV4Data, ipV6Data) + if err != nil { + return err + } + + if err = d.createNetwork(config); err != nil { + return err + } + + return d.storeUpdate(config) +} + +func newInterface(config *networkConfiguration) *bridgeInterface { + i := &bridgeInterface{} + + i.bridgeIPv4 = config.AddressIPv4 + i.gatewayIPv4 = config.AddressIPv4.IP + if config.BridgeName == "" { + config.BridgeName = DefaultBridgeName + } + return i +} + +// This function prunes the pf.conf for the firewall +// that enable the service successfully. +func fixPFConf() error { + return nil +} + +func (d *driver) initFirewall() error { + return nil +} + +func (d *driver) initRouting() error { + return nil +} + +func (d *driver) configure(option map[string]interface{}) error { + var err error + + if err = d.initFirewall(); err != nil { + return fmt.Errorf("failed to configure firewall: %v", err) + } + if err = d.initRouting(); err != nil { + return fmt.Errorf("failed to configure routing: %v", err) + } + if err = d.initStore(option); err != nil { + return fmt.Errorf("failed to initialize datastore: %v", err) + } + + return nil +} + +func (d *driver) getNetwork(id string) (*bridgeNetwork, error) { + d.Lock() + defer d.Unlock() + + if id == "" { + return nil, types.BadRequestErrorf("invalid network id: %s", id) + } + + if nw, ok := d.networks[id]; ok { + return nw, nil + } + + return nil, types.NotFoundErrorf("network not found: %s", id) +} + +// Return a slice of networks over which caller can iterate safely +func (d *driver) getNetworks() []*bridgeNetwork { + d.Lock() + defer d.Unlock() + + ls := make([]*bridgeNetwork, 0, len(d.networks)) + for _, nw := range d.networks { + ls = append(ls, nw) + } + return ls +} + +func bridgeSetup(config *networkConfiguration) error { + return nil +} + +func bridgeCleanup(config *networkConfiguration, logErr bool) { + var err error + + bridgeName := config.BridgeName + tableName := "bridge_nw_subnets" + gwName := fmt.Sprintf("%s_gw0", bridgeName) + gwIP := config.AddressIPv4.String() + pfAnchor := fmt.Sprintf("_auto/docker/%s", bridgeName) + tableAnchor := fmt.Sprintf("_auto/docker/%s", tableName) + + err = exec.Command("/usr/sbin/pfctl", "-a", pfAnchor, "-F", "all").Run() + if err != nil && logErr { + logrus.Warn("cannot flush firewall rules") + } + err = exec.Command("/usr/sbin/ifconfig", gwName, "unplumb").Run() + if err != nil && logErr { + logrus.Warn("cannot remove gateway interface") + } + err = exec.Command("/usr/sbin/dladm", "delete-vnic", + "-t", gwName).Run() + if err != nil && logErr { + logrus.Warn("cannot delete vnic") + } + err = exec.Command("/usr/sbin/dladm", "delete-etherstub", + "-t", config.BridgeNameInternal).Run() + if err != nil && logErr { + logrus.Warn("cannot delete etherstub") + } + err = exec.Command("/usr/sbin/pfctl", "-a", tableAnchor, "-t", tableName, "-T", "delete", gwIP).Run() + if err != nil && logErr { + logrus.Warnf("cannot remove bridge network '%s' from PF table", bridgeName) + } +} + +func (d *driver) createNetwork(config *networkConfiguration) error { + var err error + + logrus.Infof("Creating bridge network: %s %s %s", config.ID, + config.BridgeName, config.AddressIPv4) + + networkList := d.getNetworks() + for i, nw := range networkList { + nw.Lock() + nwConfig := nw.config + nw.Unlock() + if err := nwConfig.Conflicts(config); err != nil { + if config.DefaultBridge { + // We encountered and identified a stale default network + // We must delete it as libnetwork is the source of thruth + // The default network being created must be the only one + // This can happen only from docker 1.12 on ward + logrus.Infof("Removing stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName) + if err := d.DeleteNetwork(nwConfig.ID); err != nil { + logrus.Warnf("Failed to remove stale default network: %s (%s): %v. Will remove from store.", nwConfig.ID, nwConfig.BridgeName, err) + d.storeDelete(nwConfig) + } + networkList = append(networkList[:i], networkList[i+1:]...) + } else { + return types.ForbiddenErrorf( + "cannot create network %s (%s): "+ + "conflicts with network %s (%s): %s", + nwConfig.BridgeName, config.ID, nw.id, + nw.config.BridgeName, err.Error()) + } + } + } + if config.DefaultBindingIP == nil || + config.DefaultBindingIP.IsUnspecified() { + config.DefaultBindingIP = d.defrouteIP + } + + // Create and set network handler in driver + network := &bridgeNetwork{ + id: config.ID, + endpoints: make(map[string]*bridgeEndpoint), + config: config, + //portMapper: portmapper.New(""), + driver: d, + } + + d.Lock() + d.networks[config.ID] = network + d.Unlock() + + // On failure make sure to reset driver network handler to nil + defer func() { + if err != nil { + d.Lock() + delete(d.networks, config.ID) + d.Unlock() + } + }() + + // Create or retrieve the bridge L3 interface + bridgeIface := newInterface(config) + network.bridge = bridgeIface + + // Verify the network configuration does not conflict with previously installed + // networks. This step is needed now because driver might have now set the bridge + // name on this config struct. And because we need to check for possible address + // conflicts, so we need to check against operational networks. + if err = config.conflictsWithNetworks(config.ID, networkList); err != nil { + return err + } + + // We only attempt to create the bridge when the requested device name is + // the default one. + if config.BridgeName != DefaultBridgeName && config.DefaultBridge { + return NonDefaultBridgeExistError(config.BridgeName) + } + + bridgeCleanup(config, false) + err = bridgeSetup(config) + if err != nil { + return err + } + return nil +} + +func (d *driver) DeleteNetwork(nid string) error { + var err error + // Get network handler and remove it from driver + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.InternalMaskableErrorf("network %s does not exist", nid) + } + d.Lock() + delete(d.networks, nid) + d.Unlock() + + // On failure set network handler back in driver, but + // only if is not already taken over by some other thread + defer func() { + if err != nil { + d.Lock() + if _, ok := d.networks[nid]; !ok { + d.networks[nid] = n + } + d.Unlock() + } + }() + + // Sanity check + if n == nil { + err = driverapi.ErrNoNetwork(nid) + return err + } + + // Cannot remove network if endpoints are still present + if len(n.endpoints) != 0 { + err = ActiveEndpointsError(n.id) + return err + } + bridgeCleanup(n.config, true) + logrus.Infof("Deleting bridge network: %s", nid[:12]) + return d.storeDelete(n.config) +} + +func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { + if ifInfo == nil { + return errors.New("invalid interface passed") + } + + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.NotFoundErrorf("network %s does not exist", nid) + } + if n == nil { + return driverapi.ErrNoNetwork(nid) + } + + // Sanity check + n.Lock() + if n.id != nid { + n.Unlock() + return InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check if endpoint id is good and retrieve correspondent endpoint + ep, err := n.getEndpoint(eid) + if err != nil { + return err + } + + // Endpoint with that id exists either on desired or other sandbox + if ep != nil { + return driverapi.ErrEndpointExists(eid) + } + + // Try to convert the options to endpoint configuration + epConfig, err := parseEndpointOptions(epOptions) + if err != nil { + return err + } + + // Create and add the endpoint + n.Lock() + endpoint := &bridgeEndpoint{id: eid, config: epConfig} + n.endpoints[eid] = endpoint + n.Unlock() + + // On failure make sure to remove the endpoint + defer func() { + if err != nil { + n.Lock() + delete(n.endpoints, eid) + n.Unlock() + } + }() + + // Create the sandbox side pipe interface + if ifInfo.MacAddress() == nil { + // No MAC address assigned to interface. Generate a random MAC to assign + endpoint.macAddress = netutils.GenerateRandomMAC() + if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil { + logrus.Warnf("Unable to set mac address: %s to endpoint: %s", + endpoint.macAddress.String(), endpoint.id) + return err + } + } else { + endpoint.macAddress = ifInfo.MacAddress() + } + endpoint.addr = ifInfo.Address() + endpoint.addrv6 = ifInfo.AddressIPv6() + c := n.config + + // Program any required port mapping and store them in the endpoint + endpoint.portMapping, err = n.allocatePorts(endpoint, c.DefaultBindingIntf, c.DefaultBindingIP, true) + if err != nil { + return err + } + + return nil +} + +func (d *driver) DeleteEndpoint(nid, eid string) error { + var err error + + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + + if !ok { + return types.InternalMaskableErrorf("network %s does not exist", nid) + } + if n == nil { + return driverapi.ErrNoNetwork(nid) + } + + // Sanity Check + n.Lock() + if n.id != nid { + n.Unlock() + return InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check endpoint id and if an endpoint is actually there + ep, err := n.getEndpoint(eid) + if err != nil { + return err + } + if ep == nil { + return EndpointNotFoundError(eid) + } + + // Remove it + n.Lock() + delete(n.endpoints, eid) + n.Unlock() + + // On failure make sure to set back ep in n.endpoints, but only + // if it hasn't been taken over already by some other thread. + defer func() { + if err != nil { + n.Lock() + if _, ok := n.endpoints[eid]; !ok { + n.endpoints[eid] = ep + } + n.Unlock() + } + }() + + err = n.releasePorts(ep) + if err != nil { + logrus.Warn(err) + } + + return nil +} + +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { + // Get the network handler and make sure it exists + d.Lock() + n, ok := d.networks[nid] + d.Unlock() + if !ok { + return nil, types.NotFoundErrorf("network %s does not exist", nid) + } + if n == nil { + return nil, driverapi.ErrNoNetwork(nid) + } + + // Sanity check + n.Lock() + if n.id != nid { + n.Unlock() + return nil, InvalidNetworkIDError(nid) + } + n.Unlock() + + // Check if endpoint id is good and retrieve correspondent endpoint + ep, err := n.getEndpoint(eid) + if err != nil { + return nil, err + } + if ep == nil { + return nil, driverapi.ErrNoEndpoint(eid) + } + + m := make(map[string]interface{}) + + if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil { + // Return a copy of the config data + epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts)) + for _, tp := range ep.extConnConfig.ExposedPorts { + epc = append(epc, tp.GetCopy()) + } + m[netlabel.ExposedPorts] = epc + } + + if ep.portMapping != nil { + // Return a copy of the operational data + pmc := make([]types.PortBinding, 0, len(ep.portMapping)) + for _, pm := range ep.portMapping { + pmc = append(pmc, pm.GetCopy()) + } + m[netlabel.PortMap] = pmc + } + + if len(ep.macAddress) != 0 { + m[netlabel.MacAddress] = ep.macAddress + } + return m, nil +} + +// Join method is invoked when a Sandbox is attached to an endpoint. +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + endpoint.containerConfig, err = parseContainerOptions(options) + if err != nil { + return err + } + + err = jinfo.SetGateway(network.bridge.gatewayIPv4) + if err != nil { + return err + } + + err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6) + if err != nil { + return err + } + + return nil +} + +func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error { + return nil +} + +// Leave method is invoked when a Sandbox detaches from an endpoint. +func (d *driver) Leave(nid, eid string) error { + network, err := d.getNetwork(nid) + if err != nil { + return types.InternalMaskableErrorf("%s", err) + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + return nil +} + +func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + endpoint.extConnConfig, err = parseConnectivityOptions(options) + if err != nil { + return err + } + + // Program any required port mapping and store them in the endpoint + endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIntf, network.config.DefaultBindingIP, true) + if err != nil { + return err + } + + if !network.config.EnableICC { + return d.link(network, endpoint, true) + } + + return nil +} + +func (d *driver) RevokeExternalConnectivity(nid, eid string) error { + network, err := d.getNetwork(nid) + if err != nil { + return err + } + + endpoint, err := network.getEndpoint(eid) + if err != nil { + return err + } + + if endpoint == nil { + return EndpointNotFoundError(eid) + } + + err = network.releasePorts(endpoint) + if err != nil { + logrus.Warn(err) + } + + return nil +} + +func (d *driver) Type() string { + return networkType +} + +func (d *driver) IsBuiltIn() bool { + return true +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { + return nil +} + +// Validate performs a static validation on the network configuration parameters. +// Whatever can be assessed a priori before attempting any programming. +func (c *networkConfiguration) Validate() error { + if c.Mtu < 0 { + return ErrInvalidMtu(c.Mtu) + } + + // If bridge v4 subnet is specified + if c.AddressIPv4 != nil { + // If default gw is specified, it must be part of bridge subnet + if c.DefaultGatewayIPv4 != nil { + if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) { + return &ErrInvalidGateway{} + } + } + } + + // If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet + if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil { + if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) { + return &ErrInvalidGateway{} + } + } + return nil +} + +// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks +func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error { + for _, nw := range others { + + nw.Lock() + nwID := nw.id + nwConfig := nw.config + nwBridge := nw.bridge + nw.Unlock() + + if nwID == id { + continue + } + // Verify the name (which may have been set by newInterface()) does not conflict with + // existing bridge interfaces. Ironically the system chosen name gets stored in the config... + // Basically we are checking if the two original configs were both empty. + if nwConfig.BridgeName == c.BridgeName { + return types.ForbiddenErrorf("conflicts with network %s (%s) by bridge name", nwID, nwConfig.BridgeName) + } + // If this network config specifies the AddressIPv4, we need + // to make sure it does not conflict with any previously allocated + // bridges. This could not be completely caught by the config conflict + // check, because networks which config does not specify the AddressIPv4 + // get their address and subnet selected by the driver (see electBridgeIPv4()) + if c.AddressIPv4 != nil { + if nwBridge.bridgeIPv4.Contains(c.AddressIPv4.IP) || + c.AddressIPv4.Contains(nwBridge.bridgeIPv4.IP) { + return types.ForbiddenErrorf("conflicts with network %s (%s) by ip network", nwID, nwConfig.BridgeName) + } + } + } + + return nil +} + +// Conflicts check if two NetworkConfiguration objects overlap +func (c *networkConfiguration) Conflicts(o *networkConfiguration) error { + if o == nil { + return fmt.Errorf("same configuration") + } + + // Also empty, because only one network with empty name is allowed + if c.BridgeName == o.BridgeName { + return fmt.Errorf("networks have same bridge name") + } + + // They must be in different subnets + if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) && + (c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) { + return fmt.Errorf("networks have overlapping IPv4") + } + + // They must be in different v6 subnets + if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) && + (c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) { + return fmt.Errorf("networks have overlapping IPv6") + } + + return nil +} + +func (c *networkConfiguration) fromLabels(labels map[string]string) error { + var err error + for label, value := range labels { + switch label { + case BridgeName: + c.BridgeName = value + case netlabel.DriverMTU: + if c.Mtu, err = strconv.Atoi(value); err != nil { + return parseErr(label, value, err.Error()) + } + case netlabel.EnableIPv6: + if c.EnableIPv6, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case EnableIPMasquerade: + if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case EnableICC: + if c.EnableICC, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case DefaultBridge: + if c.DefaultBridge, err = strconv.ParseBool(value); err != nil { + return parseErr(label, value, err.Error()) + } + case DefaultBindingIP: + if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil { + return parseErr(label, value, "nil ip") + } + } + } + + return nil +} + +func parseErr(label, value, errString string) error { + return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString) +} + +func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) { + var ( + err error + config *networkConfiguration + ) + + switch opt := data.(type) { + case *networkConfiguration: + config = opt + case map[string]string: + config = &networkConfiguration{ + EnableICC: true, + EnableIPMasquerade: true, + } + err = config.fromLabels(opt) + case options.Generic: + var opaqueConfig interface{} + if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil { + config = opaqueConfig.(*networkConfiguration) + } + default: + err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt) + } + + return config, err +} + +func parseNetworkOptions(d *driver, id string, option options.Generic) (*networkConfiguration, error) { + var ( + err error + config = &networkConfiguration{} + ) + + // Parse generic label first, config will be re-assigned + if genData, ok := option[netlabel.GenericData]; ok && genData != nil { + if config, err = parseNetworkGenericOptions(genData); err != nil { + return nil, err + } + } + + // Process well-known labels next + if val, ok := option[netlabel.EnableIPv6]; ok { + config.EnableIPv6 = val.(bool) + } + + if val, ok := option[netlabel.Internal]; ok { + if internal, ok := val.(bool); ok && internal { + config.Internal = true + } + } + + // Finally validate the configuration + if err = config.Validate(); err != nil { + return nil, err + } + + if config.BridgeName == "" && config.DefaultBridge == false { + config.BridgeName = "br_" + id[:12] + "_0" + } + + lastChar := config.BridgeName[len(config.BridgeName)-1:] + if _, err = strconv.Atoi(lastChar); err != nil { + config.BridgeNameInternal = config.BridgeName + "_0" + } else { + config.BridgeNameInternal = config.BridgeName + } + + config.ID = id + return config, nil +} + +func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { + if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 { + return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets") + } + + if len(ipamV4Data) == 0 { + return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id) + } + + if ipamV4Data[0].Gateway != nil { + c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway) + } + + if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok { + c.DefaultGatewayIPv4 = gw.IP + } + + if len(ipamV6Data) > 0 { + c.AddressIPv6 = ipamV6Data[0].Pool + + if ipamV6Data[0].Gateway != nil { + c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway) + } + + if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok { + c.DefaultGatewayIPv6 = gw.IP + } + } + + return nil +} + +func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) { + n.Lock() + defer n.Unlock() + + if eid == "" { + return nil, InvalidEndpointIDError(eid) + } + + if ep, ok := n.endpoints[eid]; ok { + return ep, nil + } + + return nil, nil +} + +func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { + if epOptions == nil { + return nil, nil + } + + ec := &endpointConfiguration{} + + if opt, ok := epOptions[netlabel.MacAddress]; ok { + if mac, ok := opt.(net.HardwareAddr); ok { + ec.MacAddress = mac + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + if opt, ok := epOptions[netlabel.PortMap]; ok { + if bs, ok := opt.([]types.PortBinding); ok { + ec.PortBindings = bs + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + if opt, ok := epOptions[netlabel.ExposedPorts]; ok { + if ports, ok := opt.([]types.TransportPort); ok { + ec.ExposedPorts = ports + } else { + return nil, &ErrInvalidEndpointConfig{} + } + } + + return ec, nil +} + +func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) { + if cOptions == nil { + return nil, nil + } + genericData := cOptions[netlabel.GenericData] + if genericData == nil { + return nil, nil + } + switch opt := genericData.(type) { + case options.Generic: + opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{}) + if err != nil { + return nil, err + } + return opaqueConfig.(*containerConfiguration), nil + case *containerConfiguration: + return opt, nil + default: + return nil, nil + } +} + +func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) { + if cOptions == nil { + return nil, nil + } + + cc := &connectivityConfiguration{} + + if opt, ok := cOptions[netlabel.PortMap]; ok { + if pb, ok := opt.([]types.PortBinding); ok { + cc.PortBindings = pb + } else { + return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt) + } + } + + if opt, ok := cOptions[netlabel.ExposedPorts]; ok { + if ports, ok := opt.([]types.TransportPort); ok { + cc.ExposedPorts = ports + } else { + return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt) + } + } + + return cc, nil +} diff --git a/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge_store.go b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge_store.go new file mode 100644 index 0000000000000..5beaf232b573c --- /dev/null +++ b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge_store.go @@ -0,0 +1,384 @@ +// +build freebsd + +package bridge + +import ( + "encoding/json" + "fmt" + "net" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/datastore" + "github.com/docker/libnetwork/discoverapi" + "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/types" +) + +const ( + // network config prefix was not specific enough. + // To be backward compatible, need custom endpoint + // prefix with different root + bridgePrefix = "bridge" + bridgeEndpointPrefix = "bridge-endpoint" +) + +func (d *driver) initStore(option map[string]interface{}) error { + if data, ok := option[netlabel.LocalKVClient]; ok { + var err error + dsc, ok := data.(discoverapi.DatastoreConfigData) + if !ok { + return types.InternalErrorf("incorrect data in datastore configuration: %v", data) + } + d.store, err = datastore.NewDataStoreFromConfig(dsc) + if err != nil { + return types.InternalErrorf("bridge driver failed to initialize data store: %v", err) + } + + err = d.populateNetworks() + if err != nil { + return err + } + + err = d.populateEndpoints() + if err != nil { + return err + } + } + + return nil +} + +func (d *driver) populateNetworks() error { + kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to get bridge network configurations from store: %v", err) + } + + // It's normal for network configuration state to be empty. Just return. + if err == datastore.ErrKeyNotFound { + return nil + } + + for _, kvo := range kvol { + ncfg := kvo.(*networkConfiguration) + if err = d.createNetwork(ncfg); err != nil { + logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state: %v", ncfg.ID, ncfg.BridgeName, err) + } + logrus.Debugf("Network (%s) restored", ncfg.ID[0:7]) + } + + return nil +} + +func (d *driver) populateEndpoints() error { + kvol, err := d.store.List(datastore.Key(bridgeEndpointPrefix), &bridgeEndpoint{}) + if err != nil && err != datastore.ErrKeyNotFound { + return fmt.Errorf("failed to get bridge endpoints from store: %v", err) + } + + if err == datastore.ErrKeyNotFound { + return nil + } + + for _, kvo := range kvol { + ep := kvo.(*bridgeEndpoint) + n, ok := d.networks[ep.nid] + if !ok { + logrus.Debugf("Network (%s) not found for restored bridge endpoint (%s)", ep.nid[0:7], ep.id[0:7]) + logrus.Debugf("Deleting stale bridge endpoint (%s) from store", ep.nid[0:7]) + if err := d.storeDelete(ep); err != nil { + logrus.Debugf("Failed to delete stale bridge endpoint (%s) from store", ep.nid[0:7]) + } + continue + } + n.endpoints[ep.id] = ep + n.restorePortAllocations(ep) + logrus.Debugf("Endpoint (%s) restored to network (%s)", ep.id[0:7], ep.nid[0:7]) + } + + return nil +} + +func (d *driver) storeUpdate(kvObject datastore.KVObject) error { + if d.store == nil { + logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...)) + return nil + } + + if err := d.store.PutObjectAtomic(kvObject); err != nil { + return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err) + } + + return nil +} + +func (d *driver) storeDelete(kvObject datastore.KVObject) error { + if d.store == nil { + logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...)) + return nil + } + +retry: + if err := d.store.DeleteObjectAtomic(kvObject); err != nil { + if err == datastore.ErrKeyModified { + if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil { + return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err) + } + goto retry + } + return err + } + + return nil +} + +func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) { + nMap := make(map[string]interface{}) + nMap["ID"] = ncfg.ID + nMap["BridgeName"] = ncfg.BridgeName + nMap["BridgeNameInternal"] = ncfg.BridgeNameInternal + nMap["EnableIPv6"] = ncfg.EnableIPv6 + nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade + nMap["EnableICC"] = ncfg.EnableICC + nMap["Mtu"] = ncfg.Mtu + nMap["Internal"] = ncfg.Internal + nMap["DefaultBridge"] = ncfg.DefaultBridge + nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String() + nMap["DefaultBindingIntf"] = ncfg.DefaultBindingIntf + nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String() + nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String() + + if ncfg.AddressIPv4 != nil { + nMap["AddressIPv4"] = ncfg.AddressIPv4.String() + } + + if ncfg.AddressIPv6 != nil { + nMap["AddressIPv6"] = ncfg.AddressIPv6.String() + } + + return json.Marshal(nMap) +} + +func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error { + var ( + err error + nMap map[string]interface{} + ) + + if err = json.Unmarshal(b, &nMap); err != nil { + return err + } + + if v, ok := nMap["AddressIPv4"]; ok { + if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string)) + } + } + + if v, ok := nMap["AddressIPv6"]; ok { + if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string)) + } + } + + ncfg.DefaultBridge = nMap["DefaultBridge"].(bool) + ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string)) + ncfg.DefaultBindingIntf = nMap["DefaultBindingIntf"].(string) + ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string)) + ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string)) + ncfg.ID = nMap["ID"].(string) + ncfg.BridgeName = nMap["BridgeName"].(string) + ncfg.BridgeNameInternal = nMap["BridgeNameInternal"].(string) + ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool) + ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool) + ncfg.EnableICC = nMap["EnableICC"].(bool) + ncfg.Mtu = int(nMap["Mtu"].(float64)) + if v, ok := nMap["Internal"]; ok { + ncfg.Internal = v.(bool) + } + + return nil +} + +func (ncfg *networkConfiguration) Key() []string { + return []string{bridgePrefix, ncfg.ID} +} + +func (ncfg *networkConfiguration) KeyPrefix() []string { + return []string{bridgePrefix} +} + +func (ncfg *networkConfiguration) Value() []byte { + b, err := json.Marshal(ncfg) + if err != nil { + return nil + } + return b +} + +func (ncfg *networkConfiguration) SetValue(value []byte) error { + return json.Unmarshal(value, ncfg) +} + +func (ncfg *networkConfiguration) Index() uint64 { + return ncfg.dbIndex +} + +func (ncfg *networkConfiguration) SetIndex(index uint64) { + ncfg.dbIndex = index + ncfg.dbExists = true +} + +func (ncfg *networkConfiguration) Exists() bool { + return ncfg.dbExists +} + +func (ncfg *networkConfiguration) Skip() bool { + return false +} + +func (ncfg *networkConfiguration) New() datastore.KVObject { + return &networkConfiguration{} +} + +func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error { + dstNcfg := o.(*networkConfiguration) + *dstNcfg = *ncfg + return nil +} + +func (ncfg *networkConfiguration) DataScope() string { + return datastore.LocalScope +} + +func (ep *bridgeEndpoint) MarshalJSON() ([]byte, error) { + epMap := make(map[string]interface{}) + epMap["id"] = ep.id + epMap["nid"] = ep.nid + epMap["SrcName"] = ep.srcName + epMap["MacAddress"] = ep.macAddress.String() + epMap["Addr"] = ep.addr.String() + if ep.addrv6 != nil { + epMap["Addrv6"] = ep.addrv6.String() + } + epMap["Config"] = ep.config + epMap["ContainerConfig"] = ep.containerConfig + epMap["ExternalConnConfig"] = ep.extConnConfig + epMap["PortMapping"] = ep.portMapping + + return json.Marshal(epMap) +} + +func (ep *bridgeEndpoint) UnmarshalJSON(b []byte) error { + var ( + err error + epMap map[string]interface{} + ) + + if err = json.Unmarshal(b, &epMap); err != nil { + return fmt.Errorf("Failed to unmarshal to bridge endpoint: %v", err) + } + + if v, ok := epMap["MacAddress"]; ok { + if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint MAC address (%s) after json unmarshal: %v", v.(string), err) + } + } + if v, ok := epMap["Addr"]; ok { + if ep.addr, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err) + } + } + if v, ok := epMap["Addrv6"]; ok { + if ep.addrv6, err = types.ParseCIDR(v.(string)); err != nil { + return types.InternalErrorf("failed to decode bridge endpoint IPv6 address (%s) after json unmarshal: %v", v.(string), err) + } + } + ep.id = epMap["id"].(string) + ep.nid = epMap["nid"].(string) + ep.srcName = epMap["SrcName"].(string) + d, _ := json.Marshal(epMap["Config"]) + if err := json.Unmarshal(d, &ep.config); err != nil { + logrus.Warnf("Failed to decode endpoint config %v", err) + } + d, _ = json.Marshal(epMap["ContainerConfig"]) + if err := json.Unmarshal(d, &ep.containerConfig); err != nil { + logrus.Warnf("Failed to decode endpoint container config %v", err) + } + d, _ = json.Marshal(epMap["ExternalConnConfig"]) + if err := json.Unmarshal(d, &ep.extConnConfig); err != nil { + logrus.Warnf("Failed to decode endpoint external connectivity configuration %v", err) + } + d, _ = json.Marshal(epMap["PortMapping"]) + if err := json.Unmarshal(d, &ep.portMapping); err != nil { + logrus.Warnf("Failed to decode endpoint port mapping %v", err) + } + + return nil +} + +func (ep *bridgeEndpoint) Key() []string { + return []string{bridgeEndpointPrefix, ep.id} +} + +func (ep *bridgeEndpoint) KeyPrefix() []string { + return []string{bridgeEndpointPrefix} +} + +func (ep *bridgeEndpoint) Value() []byte { + b, err := json.Marshal(ep) + if err != nil { + return nil + } + return b +} + +func (ep *bridgeEndpoint) SetValue(value []byte) error { + return json.Unmarshal(value, ep) +} + +func (ep *bridgeEndpoint) Index() uint64 { + return ep.dbIndex +} + +func (ep *bridgeEndpoint) SetIndex(index uint64) { + ep.dbIndex = index + ep.dbExists = true +} + +func (ep *bridgeEndpoint) Exists() bool { + return ep.dbExists +} + +func (ep *bridgeEndpoint) Skip() bool { + return false +} + +func (ep *bridgeEndpoint) New() datastore.KVObject { + return &bridgeEndpoint{} +} + +func (ep *bridgeEndpoint) CopyTo(o datastore.KVObject) error { + dstEp := o.(*bridgeEndpoint) + *dstEp = *ep + return nil +} + +func (ep *bridgeEndpoint) DataScope() string { + return datastore.LocalScope +} + +func (n *bridgeNetwork) restorePortAllocations(ep *bridgeEndpoint) { + if ep.extConnConfig == nil || + ep.extConnConfig.ExposedPorts == nil || + ep.extConnConfig.PortBindings == nil { + return + } + tmp := ep.extConnConfig.PortBindings + ep.extConnConfig.PortBindings = ep.portMapping + _, err := n.allocatePorts(ep, n.config.DefaultBindingIntf, n.config.DefaultBindingIP, n.driver.config.EnableUserlandProxy) + if err != nil { + logrus.Warnf("Failed to reserve existing port mapping for endpoint %s:%v", ep.id[0:7], err) + } + ep.extConnConfig.PortBindings = tmp +} diff --git a/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/errors.go b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/errors.go new file mode 100644 index 0000000000000..f72cd9b7a1610 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/errors.go @@ -0,0 +1,120 @@ +// +build freebsd +package bridge + +import "fmt" + +// ErrInvalidEndpointConfig error is returned when an endpoint create is attempted with an invalid endpoint configuration. +type ErrInvalidEndpointConfig struct{} + +func (eiec *ErrInvalidEndpointConfig) Error() string { + return "trying to create an endpoint with an invalid endpoint configuration" +} + +// BadRequest denotes the type of this error +func (eiec *ErrInvalidEndpointConfig) BadRequest() {} + +// ErrNoIPAddr error is returned when bridge has no IPv4 address configured. +type ErrNoIPAddr struct{} + +func (enip *ErrNoIPAddr) Error() string { + return "bridge has no IPv4 address configured" +} + +// InternalError denotes the type of this error +func (enip *ErrNoIPAddr) InternalError() {} + +// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid. +type ErrInvalidGateway struct{} + +func (eig *ErrInvalidGateway) Error() string { + return "default gateway ip must be part of the network" +} + +// BadRequest denotes the type of this error +func (eig *ErrInvalidGateway) BadRequest() {} + +// ErrInvalidMtu is returned when the user provided MTU is not valid. +type ErrInvalidMtu int + +func (eim ErrInvalidMtu) Error() string { + return fmt.Sprintf("invalid MTU number: %d", int(eim)) +} + +// BadRequest denotes the type of this error +func (eim ErrInvalidMtu) BadRequest() {} + +// 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)) +} + +// BadRequest denotes the type of this error +func (uat ErrUnsupportedAddressType) BadRequest() {} + +// ActiveEndpointsError is returned when there are +// still active endpoints in the network being deleted. +type ActiveEndpointsError string + +func (aee ActiveEndpointsError) Error() string { + return fmt.Sprintf("network %s has active endpoint", string(aee)) +} + +// Forbidden denotes the type of this error +func (aee ActiveEndpointsError) Forbidden() {} + +// InvalidNetworkIDError is returned when the passed +// network id for an existing network is not a known id. +type InvalidNetworkIDError string + +func (inie InvalidNetworkIDError) Error() string { + return fmt.Sprintf("invalid network id %s", string(inie)) +} + +// NotFound denotes the type of this error +func (inie InvalidNetworkIDError) NotFound() {} + +// InvalidEndpointIDError is returned when the passed +// endpoint id is not valid. +type InvalidEndpointIDError string + +func (ieie InvalidEndpointIDError) Error() string { + return fmt.Sprintf("invalid endpoint id: %s", string(ieie)) +} + +// BadRequest denotes the type of this error +func (ieie InvalidEndpointIDError) BadRequest() {} + +// EndpointNotFoundError is returned when the no endpoint +// with the passed endpoint id is found. +type EndpointNotFoundError string + +func (enfe EndpointNotFoundError) Error() string { + return fmt.Sprintf("endpoint not found: %s", string(enfe)) +} + +// NotFound denotes the type of this error +func (enfe EndpointNotFoundError) NotFound() {} + +// NonDefaultBridgeExistError is returned when a non-default +// bridge config is passed but it does not already exist. +type NonDefaultBridgeExistError string + +func (ndbee NonDefaultBridgeExistError) Error() string { + return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee)) +} + +// Forbidden denotes the type of this error +func (ndbee NonDefaultBridgeExistError) Forbidden() {} + +// NonDefaultBridgeNeedsIPError is returned when a non-default +// bridge config is passed but it has no ip configured +type NonDefaultBridgeNeedsIPError string + +func (ndbee NonDefaultBridgeNeedsIPError) Error() string { + return fmt.Sprintf("bridge device with non default name %s must have a valid IP address", string(ndbee)) +} + +// Forbidden denotes the type of this error +func (ndbee NonDefaultBridgeNeedsIPError) Forbidden() {} diff --git a/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/port_mapping.go b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/port_mapping.go new file mode 100644 index 0000000000000..6736c0736f449 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/port_mapping.go @@ -0,0 +1,235 @@ +// +build freebsd + +package bridge + +import ( + "bytes" + "errors" + "fmt" + "net" + //"os" + "os/exec" + + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/types" +) + +var ( + defaultBindingIP = net.IPv4(0, 0, 0, 0) +) + +const ( + maxAllocatePortAttempts = 10 +) + +func addPFRules(epid, bindIntf string, bs []types.PortBinding) { + /* + var id string + + if len(epid) > 12 { + id = epid[:12] + } else { + id = epid + } + + fname := "/var/lib/docker/network/files/pf." + id + + f, err := os.OpenFile(fname, + os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) + if err != nil { + logrus.Warn("cannot open temp pf file") + return + } + for _, b := range bs { + r := fmt.Sprintf( + "pass in on %s proto %s from any to (%s) "+ + "port %d rdr-to %s port %d\n", bindIntf, + b.Proto.String(), bindIntf, b.HostPort, + b.IP.String(), b.Port) + _, err = f.WriteString(r) + if err != nil { + logrus.Warnf("cannot write firewall rules to %s: %v", fname, err) + } + } + f.Close() + + anchor := fmt.Sprintf("_auto/docker/ep%s", id) + err = exec.Command("/usr/sbin/pfctl", "-a", anchor, "-f", fname).Run() + if err != nil { + logrus.Warnf("failed to add firewall rules: %v", err) + } + os.Remove(fname) + */ +} + +func removePFRules(epid string) { + var id string + + if len(epid) > 12 { + id = epid[:12] + } else { + id = epid + } + + anchor := fmt.Sprintf("_auto/docker/ep%s", id) + err := exec.Command("/usr/sbin/pfctl", "-a", anchor, "-F", "all").Run() + if err != nil { + logrus.Warnf("failed to remove firewall rules: %v", err) + } +} + +func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, bindIntf string, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { + if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil { + return nil, nil + } + + defHostIP := defaultBindingIP + if reqDefBindIP != nil { + defHostIP = reqDefBindIP + } + + bs, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, bindIntf, ep.addr.IP, defHostIP, ulPxyEnabled) + if err != nil { + return nil, err + } + + // Add PF rules for port bindings, if any + if len(bs) > 0 { + addPFRules(ep.id, bindIntf, bs) + } + + return bs, err +} + +func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, bindIntf string, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { + bs := make([]types.PortBinding, 0, len(bindings)) + for _, c := range bindings { + b := c.GetCopy() + if err := n.allocatePort(&b, containerIP, defHostIP); err != nil { + // On allocation failure,release previously + // allocated ports. On cleanup error, just log + // a warning message + if cuErr := n.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 (n *bridgeNetwork) allocatePort(bnd *types.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 + } + + // Adjust HostPortEnd if this is not a range. + if bnd.HostPortEnd == 0 { + bnd.HostPortEnd = bnd.HostPort + } + + /* TODO + // 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++ { + /* + TODO + if host, err = n.portMapper.MapRange(container, bnd.HostIP, + int(bnd.HostPort), int(bnd.HostPortEnd), false); 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-%d: %s", + bnd.HostPort, bnd.HostPortEnd, 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 (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error { + err := n.releasePortsInternal(ep.portMapping) + if err != nil { + return nil + } + + // remove rules if there are any port mappings + if len(ep.portMapping) > 0 { + removePFRules(ep.id) + } + + return nil + +} + +func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error { + var errorBuf bytes.Buffer + + // Attempt to release all port bindings, do not stop on failure + for _, m := range bindings { + if err := n.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 (n *bridgeNetwork) releasePort(bnd types.PortBinding) error { + /* + // Construct the host side transport address + host, err := bnd.HostAddr() + if err != nil { + return err + } + // TODO + return n.portMapper.Unmap(host) + */ + return nil +} diff --git a/vendor/github.com/docker/libnetwork/drivers_freebsd.go b/vendor/github.com/docker/libnetwork/drivers_freebsd.go index d117c25780c23..8dca2c3418225 100644 --- a/vendor/github.com/docker/libnetwork/drivers_freebsd.go +++ b/vendor/github.com/docker/libnetwork/drivers_freebsd.go @@ -1,12 +1,14 @@ package libnetwork import ( + "github.com/docker/libnetwork/drivers/freebsd/bridge" "github.com/docker/libnetwork/drivers/null" "github.com/docker/libnetwork/drivers/remote" ) func getInitializers(experimental bool) []initializer { return []initializer{ + {bridge.Init, "bridge"}, {null.Init, "null"}, {remote.Init, "remote"}, } diff --git a/vendor/github.com/docker/libnetwork/iptables/conntrack.go b/vendor/github.com/docker/libnetwork/iptables/conntrack.go index 5731c53c0403e..5784fcb18f453 100644 --- a/vendor/github.com/docker/libnetwork/iptables/conntrack.go +++ b/vendor/github.com/docker/libnetwork/iptables/conntrack.go @@ -1,3 +1,5 @@ +// +build !freebsd + package iptables import ( diff --git a/vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go b/vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go index 02bcd32aa8e23..393c67c889163 100644 --- a/vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go +++ b/vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go @@ -1,7 +1,10 @@ package netutils import ( + "fmt" "net" + "os/exec" + "strings" "github.com/docker/libnetwork/types" ) @@ -19,5 +22,32 @@ func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) { // FindAvailableNetwork returns a network from the passed list which does not // overlap with existing interfaces in the system func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) { - return nil, types.NotImplementedErrorf("not supported on freebsd") + for _, avail := range list { + cidr := strings.Split(avail.String(), "/") + ipitems := strings.Split(cidr[0], ".") + ip := ipitems[0] + "." + + ipitems[1] + "." + + ipitems[2] + "." + "1" + + out, err := exec.Command("/sbin/route", "get", ip).Output() + if err != nil { + fmt.Println("failed to run route get command") + return nil, err + } + lines := strings.Split(string(out), "\n") + for _, l := range lines { + s := strings.Split(string(l), ":") + if len(s) == 2 { + k, v := s[0], strings.TrimSpace(s[1]) + if k == "destination" { + if v == "default" { + return avail, nil + } + break + } + } + } + } + return nil, fmt.Errorf("no available network") + //types.NotImplementedErrorf("not supported on freebsd") } diff --git a/vendor/github.com/docker/libnetwork/ns/init_unspecified.go b/vendor/github.com/docker/libnetwork/ns/init_unspecified.go new file mode 100644 index 0000000000000..216d969761945 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/ns/init_unspecified.go @@ -0,0 +1 @@ +package ns diff --git a/vendor/github.com/docker/libnetwork/portallocator/portallocator_freebsd.go b/vendor/github.com/docker/libnetwork/portallocator/portallocator_freebsd.go new file mode 100644 index 0000000000000..97d7fbb49d8c3 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/portallocator/portallocator_freebsd.go @@ -0,0 +1,42 @@ +package portallocator + +import ( + "bytes" + "fmt" + "os/exec" +) + +func getDynamicPortRange() (start int, end int, err error) { + portRangeKernelSysctl := []string{"net.inet.ip.portrange.hifirst", "net.ip.portrange.hilast"} + portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd) + portRangeLowCmd := exec.Command("/sbin/sysctl", portRangeKernelSysctl[0]) + var portRangeLowOut bytes.Buffer + portRangeLowCmd.Stdout = &portRangeLowOut + cmdErr := portRangeLowCmd.Run() + if cmdErr != nil { + return 0, 0, fmt.Errorf("port allocator - sysctl net.inet.ip.portrange.hifirst failed - %s: %v", portRangeFallback, err) + } + n, err := fmt.Sscanf(portRangeLowOut.String(), "%d", &start) + if n != 1 || err != nil { + if err == nil { + err = fmt.Errorf("unexpected count of parsed numbers (%d)", n) + } + return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range start from %s - %s: %v", portRangeLowOut.String(), portRangeFallback, err) + } + + portRangeHighCmd := exec.Command("/sbin/sysctl", portRangeKernelSysctl[1]) + var portRangeHighOut bytes.Buffer + portRangeHighCmd.Stdout = &portRangeHighOut + cmdErr = portRangeHighCmd.Run() + if cmdErr != nil { + return 0, 0, fmt.Errorf("port allocator - sysctl net.inet.ip.portrange.hilast failed - %s: %v", portRangeFallback, err) + } + n, err = fmt.Sscanf(portRangeHighOut.String(), "%d", &end) + if n != 1 || err != nil { + if err == nil { + err = fmt.Errorf("unexpected count of parsed numbers (%d)", n) + } + return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range end from %s - %s: %v", portRangeHighOut.String(), portRangeFallback, err) + } + return start, end, nil +} diff --git a/vendor/github.com/docker/libnetwork/portmapper/proxy_solaris.go b/vendor/github.com/docker/libnetwork/portmapper/proxy_unix.go similarity index 94% rename from vendor/github.com/docker/libnetwork/portmapper/proxy_solaris.go rename to vendor/github.com/docker/libnetwork/portmapper/proxy_unix.go index dc70b5edcebc0..5e7a51fcda92a 100644 --- a/vendor/github.com/docker/libnetwork/portmapper/proxy_solaris.go +++ b/vendor/github.com/docker/libnetwork/portmapper/proxy_unix.go @@ -1,3 +1,5 @@ +// +build solaris,freebsd +build !linux + package portmapper import ( diff --git a/vendor/github.com/docker/libnetwork/resolver_freebsd.go b/vendor/github.com/docker/libnetwork/resolver_freebsd.go new file mode 100644 index 0000000000000..b9c663f984e92 --- /dev/null +++ b/vendor/github.com/docker/libnetwork/resolver_freebsd.go @@ -0,0 +1,6 @@ +package libnetwork + + +func (r *resolver) setupIPTable() error { + return nil +} diff --git a/vendor/github.com/docker/libnetwork/resolver_unix.go b/vendor/github.com/docker/libnetwork/resolver_unix.go index 5fcc6b9fa9cf3..53cdc0bf7f62e 100644 --- a/vendor/github.com/docker/libnetwork/resolver_unix.go +++ b/vendor/github.com/docker/libnetwork/resolver_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build !windows,!freebsd package libnetwork diff --git a/vendor/github.com/docker/libnetwork/service_unsupported.go b/vendor/github.com/docker/libnetwork/service_unsupported.go index 37b9828191808..5f0d38d2cb52c 100644 --- a/vendor/github.com/docker/libnetwork/service_unsupported.go +++ b/vendor/github.com/docker/libnetwork/service_unsupported.go @@ -18,6 +18,26 @@ func (c *controller) rmServiceBinding(name, sid, nid, eid string, vip net.IP, in return fmt.Errorf("not supported") } +func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int { + skey := serviceKey{ + id: sid, + ports: portConfigs(ingressPorts).String(), + } + c.Lock() + s, ok := c.serviceBindings[skey] + c.Unlock() + + if !ok { + return 0 + } + + s.Lock() + lb := s.loadBalancers[nid] + s.Unlock() + + return int(lb.fwMark) +} + func (sb *sandbox) populateLoadbalancers(ep *endpoint) { } From 1966b95f790bcd8c38a944a7e91c3f998a26d1e9 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Wed, 16 Aug 2017 09:55:36 +0800 Subject: [PATCH 10/16] Remove duplicative definitions of functions in container_notlinux.go ---> Making bundle: binary (in bundles/17.05.0-ce/binary) Building: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Created binary: bundles/17.05.0-ce/binary-client/docker-17.05.0-ce Building: bundles/17.05.0-ce/binary-daemon/dockerd-17.05.0-ce # github.com/docker/docker/container .gopath/src/github.com/docker/docker/container/container_unix.go:257: (*Container).SecretMount redeclared in this block previous declaration at .gopath/src/github.com/docker/docker/container/container_notlinux.go:16 .gopath/src/github.com/docker/docker/container/container_unix.go:270: (*Container).UnmountSecrets redeclared in this block previous declaration at .gopath/src/github.com/docker/docker/container/container_notlinux.go Signed-off-by: R Tyler Croy --- container/container_notlinux.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/container/container_notlinux.go b/container/container_notlinux.go index f65653e992d7d..c9774fd5b9e14 100644 --- a/container/container_notlinux.go +++ b/container/container_notlinux.go @@ -11,13 +11,3 @@ func detachMounted(path string) error { // Therefore there are separate definitions for this. return unix.Unmount(path, 0) } - -// SecretMount returns the mount for the secret path -func (container *Container) SecretMount() *Mount { - return nil -} - -// UnmountSecrets unmounts the fs for secrets -func (container *Container) UnmountSecrets() error { - return nil -} From 03da82a86f7352ed7de6484692a41655d1efd43b Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Wed, 16 Aug 2017 10:39:14 +0800 Subject: [PATCH 11/16] Prevent building the libnetwork bridge driver on non-Linux Signed-off-by: R Tyler Croy --- vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/bridge_store.go | 2 ++ vendor/github.com/docker/libnetwork/drivers/bridge/interface.go | 2 ++ vendor/github.com/docker/libnetwork/drivers/bridge/link.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/port_mapping.go | 2 ++ vendor/github.com/docker/libnetwork/drivers/bridge/setup.go | 2 ++ .../libnetwork/drivers/bridge/setup_bridgenetfiltering.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/setup_device.go | 2 ++ .../docker/libnetwork/drivers/bridge/setup_firewalld.go | 2 ++ .../docker/libnetwork/drivers/bridge/setup_ip_tables.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go | 2 ++ .../github.com/docker/libnetwork/drivers/bridge/setup_verify.go | 2 ++ 13 files changed, 26 insertions(+) diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go index e681b8f7c4668..423ceb710fe60 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go b/vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go index c7c83d8369873..f488b97a31ed8 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/interface.go b/vendor/github.com/docker/libnetwork/drivers/bridge/interface.go index 9b20900416dc8..5ab6a38fb7ab8 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/interface.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/interface.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/link.go b/vendor/github.com/docker/libnetwork/drivers/bridge/link.go index 53e9eeef990e6..734fbbb048229 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/link.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/link.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go b/vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go index 965cc9a039cce..b69a630e85a46 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup.go index eeb3611b78e56..dd781cf1d003a 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup.go @@ -1,3 +1,5 @@ +// +build linux + package bridge type setupStep func(*networkConfiguration, *bridgeInterface) error diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go index 884c7115eccec..a094d19ede9eb 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go index 0961bea55d89d..db9845a0d1484 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go index fc45a7e983a26..4bac1dde213eb 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import "github.com/docker/libnetwork/iptables" diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go index 839e16f8ffef4..862d419b4405e 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go index 7f8707266d5fb..02eeea60ce0f2 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go index ee3d753ac11ed..8e0be446d7318 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( diff --git a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go index 330a5b4560c41..01e57e6a348d9 100644 --- a/vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go +++ b/vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go @@ -1,3 +1,5 @@ +// +build linux + package bridge import ( From d737378b346d931e97ae115287e2c4c1a5858403 Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Thu, 24 Aug 2017 20:37:23 -0700 Subject: [PATCH 12/16] Add a basic Jenkinsfile --- Jenkinsfile | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000..9ba08aea9e305 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,10 @@ +pipeline { + agent { label 'freebsd' } + stages { + stage('Build') { + steps { + sh 'AUTO_GOPATH=1 ./hack/make.sh binary' + } + } + } +} From 2db2aeeb12cd6499c319e909f332ca105919a091 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 5 Sep 2017 04:35:53 +0800 Subject: [PATCH 13/16] Move the container operations code around to allow stubs on FreeBSD --- daemon/container_operations_freebsd.go | 44 +++++++++++++++++++ ..._unix.go => container_operations_linux.go} | 2 +- daemon/container_operations_solaris.go | 2 - 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 daemon/container_operations_freebsd.go rename daemon/{container_operations_unix.go => container_operations_linux.go} (99%) diff --git a/daemon/container_operations_freebsd.go b/daemon/container_operations_freebsd.go new file mode 100644 index 0000000000000..c9bc1c6c79578 --- /dev/null +++ b/daemon/container_operations_freebsd.go @@ -0,0 +1,44 @@ +package daemon + +import ( + "github.com/docker/docker/container" + "github.com/docker/docker/runconfig" + "github.com/docker/libnetwork" +) + +func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) { + return nil, nil +} + +func (daemon *Daemon) setupIpcDirs(container *container.Container) error { + return nil +} + +func killProcessDirectly(container *container.Container) error { + return nil +} + +func detachMounted(path string) error { + return nil +} + +func isLinkable(child *container.Container) bool { + // A container is linkable only if it belongs to the default network + _, ok := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()] + return ok +} + +func enableIPOnPredefinedNetwork() bool { + return false +} + +func (daemon *Daemon) isNetworkHotPluggable() bool { + return false +} + +func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error { + return nil +} + +func initializeNetworkingPaths(container *container.Container, nc *container.Container) { +} diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_linux.go similarity index 99% rename from daemon/container_operations_unix.go rename to daemon/container_operations_linux.go index 17d5a061dd5a6..33bc2417274e7 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_linux.go @@ -1,4 +1,4 @@ -// +build linux freebsd +// +build linux package daemon diff --git a/daemon/container_operations_solaris.go b/daemon/container_operations_solaris.go index 1653948de1547..c9bc1c6c79578 100644 --- a/daemon/container_operations_solaris.go +++ b/daemon/container_operations_solaris.go @@ -1,5 +1,3 @@ -// +build solaris - package daemon import ( From 7e78b15f5902541883cd02b99d30f003d29d8fae Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 5 Sep 2017 04:36:29 +0800 Subject: [PATCH 14/16] Re-ordering LInux specific functions out of daemon_linux.go --- daemon/daemon_freebsd.go | 37 ++++++ daemon/daemon_linux.go | 240 ++++++++++++++++++++++++++++++++++++++ daemon/daemon_unix.go | 242 --------------------------------------- 3 files changed, 277 insertions(+), 242 deletions(-) create mode 100644 daemon/daemon_freebsd.go diff --git a/daemon/daemon_freebsd.go b/daemon/daemon_freebsd.go new file mode 100644 index 0000000000000..7b7d7f3046d5c --- /dev/null +++ b/daemon/daemon_freebsd.go @@ -0,0 +1,37 @@ +package daemon + +import ( + "github.com/docker/libnetwork" + "github.com/docker/docker/api/types" + "github.com/docker/docker/container" + "github.com/docker/docker/daemon/config" +) +func getPluginExecRoot(root string) string { + return "/run/docker/plugins" +} + +func (daemon *Daemon) cleanupMountsByID(id string) error { + return nil +} + +// cleanupMounts umounts shm/mqueue mounts for old containers +func (daemon *Daemon) cleanupMounts() error { + return nil +} + +func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error { + // TODO + return nil +} + +func removeDefaultBridgeInterface() { +} + +func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { + s := &types.StatsJSON{} + return s, nil +} + +func (daemon *Daemon) initCgroupsPath(path string) error { + return nil +} diff --git a/daemon/daemon_linux.go b/daemon/daemon_linux.go index 5faf533fdeffd..37fd5a8e974ed 100644 --- a/daemon/daemon_linux.go +++ b/daemon/daemon_linux.go @@ -10,6 +10,11 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/mount" + "github.com/docker/libnetwork/drivers/bridge" + "github.com/docker/docker/api/types" + "github.com/golang/protobuf/ptypes" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/vishvananda/netlink" ) // On Linux, plugins use a static path for storing execution state, @@ -86,3 +91,238 @@ func getCleanPatterns(id string) (regexps []*regexp.Regexp) { } return } + +func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error { + bridgeName := bridge.DefaultBridgeName + if config.BridgeConfig.Iface != "" { + bridgeName = config.BridgeConfig.Iface + } + netOption := map[string]string{ + bridge.BridgeName: bridgeName, + bridge.DefaultBridge: strconv.FormatBool(true), + netlabel.DriverMTU: strconv.Itoa(config.Mtu), + bridge.EnableIPMasquerade: strconv.FormatBool(config.BridgeConfig.EnableIPMasq), + bridge.EnableICC: strconv.FormatBool(config.BridgeConfig.InterContainerCommunication), + } + + // --ip processing + if config.BridgeConfig.DefaultIP != nil { + netOption[bridge.DefaultBindingIP] = config.BridgeConfig.DefaultIP.String() + } + + var ( + ipamV4Conf *libnetwork.IpamConf + ipamV6Conf *libnetwork.IpamConf + ) + + ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} + + nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) + if err != nil { + return errors.Wrap(err, "list bridge addresses failed") + } + + nw := nwList[0] + if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" { + _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) + if err != nil { + return errors.Wrap(err, "parse CIDR failed") + } + // Iterate through in case there are multiple addresses for the bridge + for _, entry := range nwList { + if fCIDR.Contains(entry.IP) { + nw = entry + break + } + } + } + + ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() + hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) + if hip.IsGlobalUnicast() { + ipamV4Conf.Gateway = nw.IP.String() + } + + if config.BridgeConfig.IP != "" { + ipamV4Conf.PreferredPool = config.BridgeConfig.IP + ip, _, err := net.ParseCIDR(config.BridgeConfig.IP) + if err != nil { + return err + } + ipamV4Conf.Gateway = ip.String() + } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { + logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) + } + + if config.BridgeConfig.FixedCIDR != "" { + _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) + if err != nil { + return err + } + + ipamV4Conf.SubPool = fCIDR.String() + } + + if config.BridgeConfig.DefaultGatewayIPv4 != nil { + ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.BridgeConfig.DefaultGatewayIPv4.String() + } + + var deferIPv6Alloc bool + if config.BridgeConfig.FixedCIDRv6 != "" { + _, fCIDRv6, err := net.ParseCIDR(config.BridgeConfig.FixedCIDRv6) + if err != nil { + return err + } + + // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has + // at least 48 host bits, we need to guarantee the current behavior where the containers' + // IPv6 addresses will be constructed based on the containers' interface MAC address. + // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints + // on this network until after the driver has created the endpoint and returned the + // constructed address. Libnetwork will then reserve this address with the ipam driver. + ones, _ := fCIDRv6.Mask.Size() + deferIPv6Alloc = ones <= 80 + + if ipamV6Conf == nil { + ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} + } + ipamV6Conf.PreferredPool = fCIDRv6.String() + + // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 + // address belongs to the same network, we need to inform libnetwork about it, so + // that it can be reserved with IPAM and it will not be given away to somebody else + for _, nw6 := range nw6List { + if fCIDRv6.Contains(nw6.IP) { + ipamV6Conf.Gateway = nw6.IP.String() + break + } + } + } + + if config.BridgeConfig.DefaultGatewayIPv6 != nil { + if ipamV6Conf == nil { + ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} + } + ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.BridgeConfig.DefaultGatewayIPv6.String() + } + + v4Conf := []*libnetwork.IpamConf{ipamV4Conf} + v6Conf := []*libnetwork.IpamConf{} + if ipamV6Conf != nil { + v6Conf = append(v6Conf, ipamV6Conf) + } + // Initialize default network on "bridge" with the same name + _, err = controller.NewNetwork("bridge", "bridge", "", + libnetwork.NetworkOptionEnableIPv6(config.BridgeConfig.EnableIPv6), + libnetwork.NetworkOptionDriverOpts(netOption), + libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), + libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) + if err != nil { + return fmt.Errorf("Error creating default \"bridge\" network: %v", err) + } + return nil +} + + +// Remove default bridge interface if present (--bridge=none use case) +func removeDefaultBridgeInterface() { + if lnk, err := netlink.LinkByName(bridge.DefaultBridgeName); err == nil { + if err := netlink.LinkDel(lnk); err != nil { + logrus.Warnf("Failed to remove bridge interface (%s): %v", bridge.DefaultBridgeName, err) + } + } +} + +func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { + if !c.IsRunning() { + return nil, errNotRunning{c.ID} + } + stats, err := daemon.containerd.Stats(c.ID) + if err != nil { + return nil, err + } + s := &types.StatsJSON{} + cgs := stats.CgroupStats + if cgs != nil { + s.BlkioStats = types.BlkioStats{ + IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive), + IoServicedRecursive: copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive), + IoQueuedRecursive: copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive), + IoServiceTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive), + IoWaitTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive), + IoMergedRecursive: copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive), + IoTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive), + SectorsRecursive: copyBlkioEntry(cgs.BlkioStats.SectorsRecursive), + } + cpu := cgs.CpuStats + s.CPUStats = types.CPUStats{ + CPUUsage: types.CPUUsage{ + TotalUsage: cpu.CpuUsage.TotalUsage, + PercpuUsage: cpu.CpuUsage.PercpuUsage, + UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode, + UsageInUsermode: cpu.CpuUsage.UsageInUsermode, + }, + ThrottlingData: types.ThrottlingData{ + Periods: cpu.ThrottlingData.Periods, + ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods, + ThrottledTime: cpu.ThrottlingData.ThrottledTime, + }, + } + mem := cgs.MemoryStats.Usage + s.MemoryStats = types.MemoryStats{ + Usage: mem.Usage, + MaxUsage: mem.MaxUsage, + Stats: cgs.MemoryStats.Stats, + Failcnt: mem.Failcnt, + Limit: mem.Limit, + } + // if the container does not set memory limit, use the machineMemory + if mem.Limit > daemon.machineMemory && daemon.machineMemory > 0 { + s.MemoryStats.Limit = daemon.machineMemory + } + if cgs.PidsStats != nil { + s.PidsStats = types.PidsStats{ + Current: cgs.PidsStats.Current, + } + } + } + s.Read, err = ptypes.Timestamp(stats.Timestamp) + if err != nil { + return nil, err + } + return s, nil +} + +func (daemon *Daemon) initCgroupsPath(path string) error { + if path == "/" || path == "." { + return nil + } + + if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 { + return nil + } + + // Recursively create cgroup to ensure that the system and all parent cgroups have values set + // for the period and runtime as this limits what the children can be set to. + daemon.initCgroupsPath(filepath.Dir(path)) + + mnt, root, err := cgroups.FindCgroupMountpointAndRoot("cpu") + if err != nil { + return err + } + // When docker is run inside docker, the root is based of the host cgroup. + // Should this be handled in runc/libcontainer/cgroups ? + if strings.HasPrefix(root, "/docker/") { + root = "/" + } + + path = filepath.Join(mnt, root, path) + sysinfo := sysinfo.New(true) + if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimePeriod, daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil { + return err + } + if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimeRuntime, daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path); err != nil { + return err + } + return nil +} diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 0f342bcfdab7d..7f686d5d82159 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -7,7 +7,6 @@ import ( "bytes" "fmt" "io/ioutil" - "net" "os" "path/filepath" "runtime" @@ -34,18 +33,11 @@ import ( "github.com/docker/docker/volume" "github.com/docker/libnetwork" nwconfig "github.com/docker/libnetwork/config" - "github.com/docker/libnetwork/drivers/bridge" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" - lntypes "github.com/docker/libnetwork/types" - "github.com/golang/protobuf/ptypes" - "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/label" rsystem "github.com/opencontainers/runc/libcontainer/system" specs "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/vishvananda/netlink" ) const ( @@ -786,146 +778,6 @@ func driverOptions(config *config.Config) []nwconfig.Option { return dOptions } -func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error { - bridgeName := bridge.DefaultBridgeName - if config.BridgeConfig.Iface != "" { - bridgeName = config.BridgeConfig.Iface - } - netOption := map[string]string{ - bridge.BridgeName: bridgeName, - bridge.DefaultBridge: strconv.FormatBool(true), - netlabel.DriverMTU: strconv.Itoa(config.Mtu), - bridge.EnableIPMasquerade: strconv.FormatBool(config.BridgeConfig.EnableIPMasq), - bridge.EnableICC: strconv.FormatBool(config.BridgeConfig.InterContainerCommunication), - } - - // --ip processing - if config.BridgeConfig.DefaultIP != nil { - netOption[bridge.DefaultBindingIP] = config.BridgeConfig.DefaultIP.String() - } - - var ( - ipamV4Conf *libnetwork.IpamConf - ipamV6Conf *libnetwork.IpamConf - ) - - ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} - - nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) - if err != nil { - return errors.Wrap(err, "list bridge addresses failed") - } - - nw := nwList[0] - if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" { - _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) - if err != nil { - return errors.Wrap(err, "parse CIDR failed") - } - // Iterate through in case there are multiple addresses for the bridge - for _, entry := range nwList { - if fCIDR.Contains(entry.IP) { - nw = entry - break - } - } - } - - ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() - hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) - if hip.IsGlobalUnicast() { - ipamV4Conf.Gateway = nw.IP.String() - } - - if config.BridgeConfig.IP != "" { - ipamV4Conf.PreferredPool = config.BridgeConfig.IP - ip, _, err := net.ParseCIDR(config.BridgeConfig.IP) - if err != nil { - return err - } - ipamV4Conf.Gateway = ip.String() - } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { - logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) - } - - if config.BridgeConfig.FixedCIDR != "" { - _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR) - if err != nil { - return err - } - - ipamV4Conf.SubPool = fCIDR.String() - } - - if config.BridgeConfig.DefaultGatewayIPv4 != nil { - ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.BridgeConfig.DefaultGatewayIPv4.String() - } - - var deferIPv6Alloc bool - if config.BridgeConfig.FixedCIDRv6 != "" { - _, fCIDRv6, err := net.ParseCIDR(config.BridgeConfig.FixedCIDRv6) - if err != nil { - return err - } - - // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has - // at least 48 host bits, we need to guarantee the current behavior where the containers' - // IPv6 addresses will be constructed based on the containers' interface MAC address. - // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints - // on this network until after the driver has created the endpoint and returned the - // constructed address. Libnetwork will then reserve this address with the ipam driver. - ones, _ := fCIDRv6.Mask.Size() - deferIPv6Alloc = ones <= 80 - - if ipamV6Conf == nil { - ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} - } - ipamV6Conf.PreferredPool = fCIDRv6.String() - - // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 - // address belongs to the same network, we need to inform libnetwork about it, so - // that it can be reserved with IPAM and it will not be given away to somebody else - for _, nw6 := range nw6List { - if fCIDRv6.Contains(nw6.IP) { - ipamV6Conf.Gateway = nw6.IP.String() - break - } - } - } - - if config.BridgeConfig.DefaultGatewayIPv6 != nil { - if ipamV6Conf == nil { - ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} - } - ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.BridgeConfig.DefaultGatewayIPv6.String() - } - - v4Conf := []*libnetwork.IpamConf{ipamV4Conf} - v6Conf := []*libnetwork.IpamConf{} - if ipamV6Conf != nil { - v6Conf = append(v6Conf, ipamV6Conf) - } - // Initialize default network on "bridge" with the same name - _, err = controller.NewNetwork("bridge", "bridge", "", - libnetwork.NetworkOptionEnableIPv6(config.BridgeConfig.EnableIPv6), - libnetwork.NetworkOptionDriverOpts(netOption), - libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), - libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) - if err != nil { - return fmt.Errorf("Error creating default \"bridge\" network: %v", err) - } - return nil -} - -// Remove default bridge interface if present (--bridge=none use case) -func removeDefaultBridgeInterface() { - if lnk, err := netlink.LinkByName(bridge.DefaultBridgeName); err == nil { - if err := netlink.LinkDel(lnk); err != nil { - logrus.Warnf("Failed to remove bridge interface (%s): %v", bridge.DefaultBridgeName, err) - } - } -} - func (daemon *Daemon) getLayerInit() func(string) error { return daemon.setupInitLayer } @@ -1152,66 +1004,6 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container return daemon.Unmount(container) } -func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { - if !c.IsRunning() { - return nil, errNotRunning{c.ID} - } - stats, err := daemon.containerd.Stats(c.ID) - if err != nil { - return nil, err - } - s := &types.StatsJSON{} - cgs := stats.CgroupStats - if cgs != nil { - s.BlkioStats = types.BlkioStats{ - IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive), - IoServicedRecursive: copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive), - IoQueuedRecursive: copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive), - IoServiceTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive), - IoWaitTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive), - IoMergedRecursive: copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive), - IoTimeRecursive: copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive), - SectorsRecursive: copyBlkioEntry(cgs.BlkioStats.SectorsRecursive), - } - cpu := cgs.CpuStats - s.CPUStats = types.CPUStats{ - CPUUsage: types.CPUUsage{ - TotalUsage: cpu.CpuUsage.TotalUsage, - PercpuUsage: cpu.CpuUsage.PercpuUsage, - UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode, - UsageInUsermode: cpu.CpuUsage.UsageInUsermode, - }, - ThrottlingData: types.ThrottlingData{ - Periods: cpu.ThrottlingData.Periods, - ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods, - ThrottledTime: cpu.ThrottlingData.ThrottledTime, - }, - } - mem := cgs.MemoryStats.Usage - s.MemoryStats = types.MemoryStats{ - Usage: mem.Usage, - MaxUsage: mem.MaxUsage, - Stats: cgs.MemoryStats.Stats, - Failcnt: mem.Failcnt, - Limit: mem.Limit, - } - // if the container does not set memory limit, use the machineMemory - if mem.Limit > daemon.machineMemory && daemon.machineMemory > 0 { - s.MemoryStats.Limit = daemon.machineMemory - } - if cgs.PidsStats != nil { - s.PidsStats = types.PidsStats{ - Current: cgs.PidsStats.Current, - } - } - } - s.Read, err = ptypes.Timestamp(stats.Timestamp) - if err != nil { - return nil, err - } - return s, nil -} - // setDefaultIsolation determines the default isolation mode for the // daemon to run in. This is only applicable on Windows func (daemon *Daemon) setDefaultIsolation() error { @@ -1256,40 +1048,6 @@ func setupOOMScoreAdj(score int) error { return err } -func (daemon *Daemon) initCgroupsPath(path string) error { - if path == "/" || path == "." { - return nil - } - - if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 { - return nil - } - - // Recursively create cgroup to ensure that the system and all parent cgroups have values set - // for the period and runtime as this limits what the children can be set to. - daemon.initCgroupsPath(filepath.Dir(path)) - - mnt, root, err := cgroups.FindCgroupMountpointAndRoot("cpu") - if err != nil { - return err - } - // When docker is run inside docker, the root is based of the host cgroup. - // Should this be handled in runc/libcontainer/cgroups ? - if strings.HasPrefix(root, "/docker/") { - root = "/" - } - - path = filepath.Join(mnt, root, path) - sysinfo := sysinfo.New(true) - if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimePeriod, daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil { - return err - } - if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimeRuntime, daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path); err != nil { - return err - } - return nil -} - func maybeCreateCPURealTimeFile(sysinfoPresent bool, configValue int64, file string, path string) error { if sysinfoPresent && configValue != 0 { if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) { From e4e803970b7b5f28cf9918a83bdc261ccb801730 Mon Sep 17 00:00:00 2001 From: R Tyler Croy Date: Tue, 5 Sep 2017 05:07:13 +0800 Subject: [PATCH 15/16] Add a stubbed execSetPlatformOpt for FreeBSD This is essentially the same thing Solaris has --- daemon/exec_freebsd.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 daemon/exec_freebsd.go diff --git a/daemon/exec_freebsd.go b/daemon/exec_freebsd.go new file mode 100644 index 0000000000000..7003355d9118a --- /dev/null +++ b/daemon/exec_freebsd.go @@ -0,0 +1,11 @@ +package daemon + +import ( + "github.com/docker/docker/container" + "github.com/docker/docker/daemon/exec" + "github.com/docker/docker/libcontainerd" +) + +func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainerd.Process) error { + return nil +} From 25cb15bc7a4db36d078c9807b70969a23ae134d2 Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Tue, 5 Sep 2017 06:18:54 +0800 Subject: [PATCH 16/16] Add the remainder of the FreeBSD go files to get the daemon to compile --- daemon/container_freebsd.go | 9 ++++ daemon/monitor_freebsd.go | 18 ++++++++ daemon/oci_freebsd.go | 74 ++++++++++++++++++++++++++++++ daemon/update_freebsd.go | 11 +++++ oci/defaults_freebsd.go | 20 ++++++++ pkg/mount/sharedsubtree_freebsd.go | 67 +++++++++++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 daemon/container_freebsd.go create mode 100644 daemon/monitor_freebsd.go create mode 100644 daemon/oci_freebsd.go create mode 100644 daemon/update_freebsd.go create mode 100644 oci/defaults_freebsd.go create mode 100644 pkg/mount/sharedsubtree_freebsd.go diff --git a/daemon/container_freebsd.go b/daemon/container_freebsd.go new file mode 100644 index 0000000000000..6db130ab05f3f --- /dev/null +++ b/daemon/container_freebsd.go @@ -0,0 +1,9 @@ +package daemon + +import ( + "github.com/docker/docker/container" +) + +func (daemon *Daemon) saveApparmorConfig(container *container.Container) error { + return nil +} diff --git a/daemon/monitor_freebsd.go b/daemon/monitor_freebsd.go new file mode 100644 index 0000000000000..5ccfada76ac3c --- /dev/null +++ b/daemon/monitor_freebsd.go @@ -0,0 +1,18 @@ +package daemon + +import ( + "github.com/docker/docker/container" + "github.com/docker/docker/libcontainerd" +) + +// platformConstructExitStatus returns a platform specific exit status structure +func platformConstructExitStatus(e libcontainerd.StateInfo) *container.ExitStatus { + return &container.ExitStatus{ + ExitCode: int(e.ExitCode), + } +} + +// postRunProcessing perfoms any processing needed on the container after it has stopped. +func (daemon *Daemon) postRunProcessing(container *container.Container, e libcontainerd.StateInfo) error { + return nil +} diff --git a/daemon/oci_freebsd.go b/daemon/oci_freebsd.go new file mode 100644 index 0000000000000..0e8ddbdc128c4 --- /dev/null +++ b/daemon/oci_freebsd.go @@ -0,0 +1,74 @@ +package daemon + +import ( + "fmt" + "sort" + + containertypes "github.com/docker/docker/api/types/container" + "github.com/docker/docker/container" + "github.com/docker/docker/oci" + "github.com/opencontainers/runtime-spec/specs-go" +) + +func setResources(s *specs.Spec, r containertypes.Resources) error { + return nil +} + +func setUser(s *specs.Spec, c *container.Container) error { + return nil +} + +func getUser(c *container.Container, username string) (uint32, uint32, []uint32, error) { + return 0, 0, nil, nil +} + +// mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig +// It will do nothing on non-Linux platform +func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) { + return +} + +func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) { + s := oci.DefaultSpec() + if err := daemon.populateCommonSpec(&s, c); err != nil { + return nil, err + } + + if err := setResources(&s, c.HostConfig.Resources); err != nil { + return nil, fmt.Errorf("runtime spec resources: %v", err) + } + + if err := setUser(&s, c); err != nil { + return nil, fmt.Errorf("spec user: %v", err) + } + + if err := daemon.setNetworkInterface(&s, c); err != nil { + return nil, err + } + + if err := daemon.setupIpcDirs(c); err != nil { + return nil, err + } + + ms, err := daemon.setupMounts(c) + if err != nil { + return nil, err + } + ms = append(ms, c.IpcMounts()...) + tmpfsMounts, err := c.TmpfsMounts() + if err != nil { + return nil, err + } + ms = append(ms, tmpfsMounts...) + sort.Sort(mounts(ms)) + + return (*specs.Spec)(&s), nil +} + +func (daemon *Daemon) setNetworkInterface(s *specs.Spec, c *container.Container) error { + return nil +} + +func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error { + return nil +} diff --git a/daemon/update_freebsd.go b/daemon/update_freebsd.go new file mode 100644 index 0000000000000..f3b545c5f01ef --- /dev/null +++ b/daemon/update_freebsd.go @@ -0,0 +1,11 @@ +package daemon + +import ( + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/libcontainerd" +) + +func toContainerdResources(resources container.Resources) libcontainerd.Resources { + var r libcontainerd.Resources + return r +} diff --git a/oci/defaults_freebsd.go b/oci/defaults_freebsd.go new file mode 100644 index 0000000000000..85c8b68e16e9c --- /dev/null +++ b/oci/defaults_freebsd.go @@ -0,0 +1,20 @@ +package oci + +import ( + "runtime" + + "github.com/opencontainers/runtime-spec/specs-go" +) + +// DefaultSpec returns default oci spec used by docker. +func DefaultSpec() specs.Spec { + s := specs.Spec{ + Version: "0.6.0", + Platform: specs.Platform{ + OS: "SunOS", + Arch: runtime.GOARCH, + }, + } + s.Solaris = &specs.Solaris{} + return s +} diff --git a/pkg/mount/sharedsubtree_freebsd.go b/pkg/mount/sharedsubtree_freebsd.go new file mode 100644 index 0000000000000..f3c13e5a16ce8 --- /dev/null +++ b/pkg/mount/sharedsubtree_freebsd.go @@ -0,0 +1,67 @@ +package mount + +// MakeShared ensures a mounted filesystem has the SHARED mount option enabled. +// See the supported options in flags.go for further reference. +func MakeShared(mountPoint string) error { + return ensureMountedAs(mountPoint, "shared") +} + +// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled. +// See the supported options in flags.go for further reference. +func MakeRShared(mountPoint string) error { + return ensureMountedAs(mountPoint, "rshared") +} + +// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled. +// See the supported options in flags.go for further reference. +func MakePrivate(mountPoint string) error { + return ensureMountedAs(mountPoint, "private") +} + +// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option +// enabled. See the supported options in flags.go for further reference. +func MakeRPrivate(mountPoint string) error { + return ensureMountedAs(mountPoint, "rprivate") +} + +// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled. +// See the supported options in flags.go for further reference. +func MakeSlave(mountPoint string) error { + return ensureMountedAs(mountPoint, "slave") +} + +// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled. +// See the supported options in flags.go for further reference. +func MakeRSlave(mountPoint string) error { + return ensureMountedAs(mountPoint, "rslave") +} + +// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option +// enabled. See the supported options in flags.go for further reference. +func MakeUnbindable(mountPoint string) error { + return ensureMountedAs(mountPoint, "unbindable") +} + +// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount +// option enabled. See the supported options in flags.go for further reference. +func MakeRUnbindable(mountPoint string) error { + return ensureMountedAs(mountPoint, "runbindable") +} + +func ensureMountedAs(mountPoint, options string) error { + mounted, err := Mounted(mountPoint) + if err != nil { + return err + } + + if !mounted { + if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { + return err + } + } + if _, err = Mounted(mountPoint); err != nil { + return err + } + + return ForceMount("", mountPoint, "none", options) +}