Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F141134189
D21570.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
204 KB
Referenced Files
None
Subscribers
None
D21570.diff
View Options
Index: sysutils/docker-freebsd/Makefile
===================================================================
--- sysutils/docker-freebsd/Makefile
+++ sysutils/docker-freebsd/Makefile
@@ -1,41 +1,28 @@
-# Created by: kmoore@FreeBSD.org
# $FreeBSD$
PORTNAME= docker-freebsd
-PORTVERSION= 20150625
-PORTREVISION= 2
+DISTVERSIONPREFIX= v
+DISTVERSION= 19.03.13
CATEGORIES= sysutils
MAINTAINER= joneum@FreeBSD.org
-COMMENT= Docker containment system
+COMMENT= Docker Engine based on moby
LICENSE= APACHE20
LICENSE_FILE= ${WRKSRC}/LICENSE
-BROKEN= fails to build
-DEPRECATED= Broken for more than 9 months
-EXPIRATION_DATE= 2020-01-10
+BUILD_DEPENDS= bash:shells/bash
-BUILD_DEPENDS= bash:shells/bash \
- sqlite3:databases/sqlite3
-RUN_DEPENDS= bash:shells/bash \
- sqlite3:databases/sqlite3
+USES= go
-USES= go:run
-
USE_GITHUB= yes
-GH_ACCOUNT= kvasdopil
-GH_PROJECT= docker
-GH_TAGNAME= 582db78
+GH_ACCOUNT= moby
+GH_PROJECT= moby
+GH_SUBDIR= src/github.com/docker/docker
-PLIST_FILES= bin/docker
-USE_RC_SUBR= docker
+GO_TARGET= ./cmd/dockerd
do-build:
- @cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} AUTO_GOPATH=1 DOCKER_GITCOMMIT=${GH_TAGNAME} ./hack/make.sh binary
-
-do-install:
- @${MKDIR} ${STAGEDIR}${PREFIX}/bin
- ${INSTALL_PROGRAM} ${WRKSRC}/bundles/latest/binary/docker ${STAGEDIR}${PREFIX}/bin/
+ @cd ${GO_WRKSRC} && export DOCKER_GITCOMMIT=${GH_TAGNAME} && ${SETENV} ${GO_ENV} ./hack/make.sh binary
.include <bsd.port.mk>
Index: sysutils/docker-freebsd/distinfo
===================================================================
--- sysutils/docker-freebsd/distinfo
+++ sysutils/docker-freebsd/distinfo
@@ -1,2 +1,3 @@
-SHA256 (kvasdopil-docker-20150625-582db78_GH0.tar.gz) = a750d344af4af3d30b1a3373f382ab597a2a7aa4a0bb5c22d650d0c5cc9ac506
-SIZE (kvasdopil-docker-20150625-582db78_GH0.tar.gz) = 7292884
+TIMESTAMP = 1602853279
+SHA256 (moby-moby-v19.03.13_GH0.tar.gz) = f43331fef1d24e31f43392fc1fed72b48fc17fd432d341d6eb1f68ca11383406
+SIZE (moby-moby-v19.03.13_GH0.tar.gz) = 10406691
Index: sysutils/docker-freebsd/files/patch-FreeBSD.adoc
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-FreeBSD.adoc
@@ -0,0 +1,268 @@
+--- FreeBSD.adoc.orig 2020-09-04 14:57:27 UTC
++++ FreeBSD.adoc
+@@ -0,0 +1,265 @@
++= Docker on FreeBSD
++
++The FreeBSD port of Docker requires ZFS and FreeBSD 11.1-RELEASE or greater.
++
++[NOTE]
++====
++The current `freebsd-compat` branch is based off of the `v17.05.0-ce` tag from
++upstream.
++====
++
++== Participate
++
++
++Chat for this effort can be found in the `#freebsd-docker` chanenl on
++link:http://freenode.net[Freenode].
++
++== Running
++
++[[prereqs]]
++== Prerequisites
++
++Please ensure the following packages are installed in order to build from
++source:
++
++* `go`
++* `git`
++* `bash`
++* `ca_root_nss`
++* `libepoll-shim`
++
++[source,bash]
++----
++sudo pkg install ca_root_nss bash git go libepoll-shim
++----
++
++
++[[zfs]]
++=== Setting up ZFS
++
++In order to provide storage for containers running on FreeBSD, Docker relies on
++ZFS underneath the hood. This means the FreeBSD system must have ZFS loaded,
++and active.
++
++==== Systems without ZFS-based disks
++
++[source,bash]
++----
++kldload zfs && \
++ dd if=/dev/zero of=/usr/local/dockerfs bs=1024K count=4000 && \
++ zpool create -f zroot /usr/local/dockerfs && \
++ zfs create -o mountpoint=/usr/docker zroot/docker
++----
++
++==== Systems with ZFS-based disks
++
++[source,bash]
++----
++zfs create -o mountpoint=/usr/docker zroot/docker
++----
++
++
++
++[[networking]]
++=== Setting up networking
++
++
++[[pf]]
++==== Setting up Packet Filer
++
++In order to provide networking for containers, Docker must have access to
++Packet Filter (`pf`).
++
++* `sudo kldload pf`
++
++
++The example below provides a bridged network for Docker. If you installed
++FreeBSD/Docker via the `sysutils/docker-freebsd` port, this will already be
++configured for you.
++
++[source,bash]
++----
++echo "nat on {yout-external-interface} from 172.17.0.0/16 to any -> ({your-external-interface})" > /etc/pf.conf
++pfctl -f /etc/pf.conf
++pfctl -e
++----
++
++
++=== Progress
++
++.Features
++|===
++| Feature | Status
++
++| Image loading
++| :white_check_mark:
++
++| Container creationg
++| :white_check_mark:
++
++| Container start/stop
++| :white_check_mark:
++
++| Shared Networking
++| partial support
++
++| Port forwarding
++| :white_check_mark:
++
++| Volumes
++| :x:
++
++| Links
++| :x:
++
++| Virtual networking
++| :x:
++
++| Limits
++| :x:
++
++|===
++
++.Commands
++|===
++| Command | Status
++
++| attach
++| :white_check_mark:
++
++| build
++|
++
++| commit
++| :white_check_mark:
++
++| cp
++| :white_check_mark:
++
++| create
++| :white_check_mark:
++
++| diff
++| :white_check_mark:
++
++| events
++| :white_check_mark:
++
++| exec
++| :white_check_mark:
++
++| export
++| :white_check_mark:
++
++| history
++| :white_check_mark:
++
++| images
++| :white_check_mark:
++
++| import
++| :white_check_mark:
++
++| info
++| :bug:
++
++| inspect
++| :white_check_mark:
++
++| kill
++| :white_check_mark:
++
++| load
++| :bug:
++
++| login
++| :white_check_mark:
++
++| logout
++| :white_check_mark:
++
++| logs
++| :white_check_mark:
++
++| pause
++| :x:
++
++| port
++| :white_check_mark:
++
++| ps
++| :white_check_mark:
++
++| pull
++| :white_check_mark:
++
++| push
++| :white_check_mark:
++
++| rename
++| :white_check_mark:
++
++| restart
++| :white_check_mark:
++
++| rm
++| :white_check_mark:
++
++| rmi
++| :white_check_mark:
++
++| run
++| :white_check_mark:
++
++| save
++| :white_check_mark:
++
++| search
++| :white_check_mark:
++
++| start
++| :white_check_mark:
++
++| stats
++| :bug:
++
++| stop
++| :white_check_mark:
++
++| tag
++| :white_check_mark:
++
++| top
++| :white_check_mark:
++
++| unpause
++| :x:
++
++| version
++| :white_check_mark:
++
++| wait
++| :white_check_mark:
++
++|===
++
++== Hacking
++
++To build on 11.1-RELEASE, assuming the <<prereqs>> have been installed:
++
++[source,bash]
++----
++gmake -f Makefile.freebsd
++----
++
++This should create the `docker` and `dockerd` executables in
++`./bundles/latest/`. Please ensure that <<zfs, ZFS>> and <<networking,
++Networking>> are set up properly.
++
++=== References
++
++Below are a list of useful references for understanding both Docker and
++Docker/FreeBSD.
++
++* link:https://blog.docker.com/2017/08/what-is-containerd-runtime/[What is containerd].
++* link:https://docs.docker.com/engine/userguide/storagedriver/zfs-driver/[Using the ZFS storage driver].
Index: sysutils/docker-freebsd/files/patch-Makefile.freebsd
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-Makefile.freebsd
@@ -0,0 +1,71 @@
+--- Makefile.freebsd.orig 2020-09-04 14:57:27 UTC
++++ Makefile.freebsd
+@@ -0,0 +1,68 @@
++# This file exists to support the non-Docker-based build requirements for
++# FreeBSD/Docker
++#
++# Hacking GOPATH to take the first directory in the list and use that to clone
++# our dependencies
++export GO_PATH=$(firstword $(subst :, ,$(GOPATH)))
++export AUTO_GO_PATH=1
++export DEST_DIR=$(PWD)/bundles/bin
++export RUNC_PATH="${GO_PATH}/src/github.com/opencontainers/runc"
++export CONTAINERD_PATH="${GO_PATH}/src/github.com/containerd/containerd"
++export CONTAINERD_REFSPEC=freebsd-compat-0.2
++export LIBNETWORK_PATH="${GO_PATH}/src/github.com/docker/libnetwork"
++export TINI_PATH="${GO_PATH}/src/tini"
++
++all: binary
++
++binary: $(DEST_DIR)/docker-containerd $(DEST_DIR)/docker-proxy
++ ./hack/make.sh binary
++ # Copy into bundles/bin for packaging
++ for f in bundles/latest/*/*; do \
++ [ -L "$$f" ] || continue; \
++ cp -f "$$(readlink -f $$f)" "$(DEST_DIR)/$${f##*/}"; \
++ done
++
++$(DEST_DIR)/docker-containerd: prepare
++ if [ ! -d $(CONTAINERD_PATH) ]; then \
++ git clone https://github.com/freebsd-docker/containerd.git $(CONTAINERD_PATH) && \
++ cd $(CONTAINERD_PATH) && \
++ git checkout $(CONTAINERD_REFSPEC); \
++ fi;
++ cd $(CONTAINERD_PATH) && \
++ $(MAKE) && \
++ cp bin/containerd $(DEST_DIR)/docker-containerd && \
++ cp bin/containerd-shim $(DEST_DIR)/docker-containerd-shim && \
++ cp bin/ctr $(DEST_DIR)/docker-containerd-ctr
++
++$(DEST_DIR)/docker-proxy: prepare
++ if [ ! -d $(LIBNETWORK_PATH) ]; then \
++ git clone https://github.com/freebsd-docker/libnetwork.git $(LIBNETWORK_PATH); \
++ fi;
++ cd $(LIBNETWORK_PATH) && \
++ go build -o $(DEST_DIR)/docker-proxy github.com/docker/libnetwork/cmd/proxy
++
++
++runc:
++ if [ ! -d $(RUNC_PATH) ]; then \
++ git clone https://github.com/freebsd-docker/runc.git $(RUNC_PATH); \
++ fi;
++ cd $(RUNC_PATH) && \
++ $(MAKE)
++
++tini: check-depends
++ if [ ! -d $(TINI_PATH) ]; then \
++ git clone https://github.com/krallin/tini.git $(TINI_PATH); \
++ fi;
++ cd $(TINI_PATH) && \
++ cmake . && \
++ $(MAKE) tini-static
++
++check-depends:
++ echo ">> Verify that you have CMake installed"
++
++prepare: bundles/bin
++
++bundles/bin:
++ mkdir -p bundles/bin
++
++.PHONY: check-depends prepare all binary
Index: sysutils/docker-freebsd/files/patch-builder_dockerfile_internals__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-builder_dockerfile_internals__freebsd.go
@@ -0,0 +1,95 @@
+Fix build on FreeBSD by copying linux implementation:
+
+builder/dockerfile/internals.go:193:19: undefined: parseChownFlag
+
+--- builder/dockerfile/internals_freebsd.go.orig 2019-03-08 14:02:51 UTC
++++ builder/dockerfile/internals_freebsd.go
+@@ -0,0 +1,88 @@
++package dockerfile // import "github.com/docker/docker/builder/dockerfile"
++
++import (
++ "path/filepath"
++ "strconv"
++ "strings"
++
++ "github.com/docker/docker/pkg/idtools"
++ "github.com/docker/docker/pkg/symlink"
++ lcUser "github.com/opencontainers/runc/libcontainer/user"
++ "github.com/pkg/errors"
++)
++
++func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
++ var userStr, grpStr string
++ parts := strings.Split(chown, ":")
++ if len(parts) > 2 {
++ return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
++ }
++ if len(parts) == 1 {
++ // if no group specified, use the user spec as group as well
++ userStr, grpStr = parts[0], parts[0]
++ } else {
++ userStr, grpStr = parts[0], parts[1]
++ }
++
++ passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
++ if err != nil {
++ return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
++ }
++ groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
++ if err != nil {
++ return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
++ }
++ uid, err := lookupUser(userStr, passwdPath)
++ if err != nil {
++ return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
++ }
++ gid, err := lookupGroup(grpStr, groupPath)
++ if err != nil {
++ return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
++ }
++
++ // convert as necessary because of user namespaces
++ chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
++ if err != nil {
++ return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
++ }
++ return chownPair, nil
++}
++
++func lookupUser(userStr, filepath string) (int, error) {
++ // if the string is actually a uid integer, parse to int and return
++ // as we don't need to translate with the help of files
++ uid, err := strconv.Atoi(userStr)
++ if err == nil {
++ return uid, nil
++ }
++ users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
++ return u.Name == userStr
++ })
++ if err != nil {
++ return 0, err
++ }
++ if len(users) == 0 {
++ return 0, errors.New("no such user: " + userStr)
++ }
++ return users[0].Uid, nil
++}
++
++func lookupGroup(groupStr, filepath string) (int, error) {
++ // if the string is actually a gid integer, parse to int and return
++ // as we don't need to translate with the help of files
++ gid, err := strconv.Atoi(groupStr)
++ if err == nil {
++ return gid, nil
++ }
++ groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
++ return g.Name == groupStr
++ })
++ if err != nil {
++ return 0, err
++ }
++ if len(groups) == 0 {
++ return 0, errors.New("no such group: " + groupStr)
++ }
++ return groups[0].Gid, nil
++}
Index: sysutils/docker-freebsd/files/patch-daemon_container__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_container__freebsd.go
@@ -0,0 +1,12 @@
+--- daemon/container_freebsd.go.orig 2020-09-18 09:01:00 UTC
++++ 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
++}
Index: sysutils/docker-freebsd/files/patch-daemon_container__operations.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_container__operations.go
@@ -0,0 +1,33 @@
+--- daemon/container_operations.go.orig 2020-09-04 14:54:50 UTC
++++ daemon/container_operations.go
+@@ -68,7 +68,7 @@ func (daemon *Daemon) buildSandboxOptions(container *c
+ sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
+ }
+
+- if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
++ if err = setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
+ return nil, err
+ }
+
+@@ -618,9 +618,9 @@ func validateNetworkingConfig(n libnetwork.Network, ep
+ if hasUserDefinedIPAddress(epConfig.IPAMConfig) && !enableIPOnPredefinedNetwork() {
+ return runconfig.ErrUnsupportedNetworkAndIP
+ }
+- if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() {
+- return runconfig.ErrUnsupportedNetworkAndAlias
+- }
++ // if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() {
++ // return runconfig.ErrUnsupportedNetworkAndAlias
++ // }
+ }
+ if !hasUserDefinedIPAddress(epConfig.IPAMConfig) {
+ return nil
+@@ -935,7 +935,7 @@ func (daemon *Daemon) initializeNetworking(container *
+ return err
+ }
+
+- err = daemon.initializeNetworkingPaths(container, nc)
++ err = initializeNetworkingPaths(container, nc)
+ if err != nil {
+ return err
+ }
Index: sysutils/docker-freebsd/files/patch-daemon_container__operations__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_container__operations__freebsd.go
@@ -0,0 +1,48 @@
+--- daemon/container_operations_freebsd.go.orig 2020-09-04 14:57:27 UTC
++++ daemon/container_operations_freebsd.go
+@@ -0,0 +1,45 @@
++package daemon // import "github.com/docker/docker/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) error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-daemon_container__operations__linux.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_container__operations__linux.go
@@ -0,0 +1,418 @@
+--- daemon/container_operations_linux.go.orig 2020-09-04 14:57:27 UTC
++++ daemon/container_operations_linux.go
+@@ -0,0 +1,415 @@
++// +build linux
++
++package daemon // import "github.com/docker/docker/daemon"
++
++import (
++ "context"
++ "fmt"
++ "io/ioutil"
++ "os"
++ "path/filepath"
++ "strconv"
++ "time"
++
++ "github.com/docker/docker/container"
++ "github.com/docker/docker/daemon/links"
++ "github.com/docker/docker/errdefs"
++ "github.com/docker/docker/pkg/idtools"
++ "github.com/docker/docker/pkg/mount"
++ "github.com/docker/docker/pkg/stringid"
++ "github.com/docker/docker/runconfig"
++ "github.com/docker/libnetwork"
++ "github.com/opencontainers/selinux/go-selinux/label"
++ "github.com/pkg/errors"
++ "github.com/sirupsen/logrus"
++ "golang.org/x/sys/unix"
++)
++
++func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
++ var env []string
++ children := daemon.children(container)
++
++ bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
++ if bridgeSettings == nil || bridgeSettings.EndpointSettings == nil {
++ return nil, nil
++ }
++
++ for linkAlias, child := range children {
++ if !child.IsRunning() {
++ return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
++ }
++
++ childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
++ if childBridgeSettings == nil || childBridgeSettings.EndpointSettings == nil {
++ return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
++ }
++
++ link := links.NewLink(
++ bridgeSettings.IPAddress,
++ childBridgeSettings.IPAddress,
++ linkAlias,
++ child.Config.Env,
++ child.Config.ExposedPorts,
++ )
++
++ env = append(env, link.ToEnv()...)
++ }
++
++ return env, nil
++}
++
++func (daemon *Daemon) getIpcContainer(id string) (*container.Container, error) {
++ errMsg := "can't join IPC of container " + id
++ // Check the container exists
++ container, err := daemon.GetContainer(id)
++ if err != nil {
++ return nil, errors.Wrap(err, errMsg)
++ }
++ // Check the container is running and not restarting
++ if err := daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting); err != nil {
++ return nil, errors.Wrap(err, errMsg)
++ }
++ // Check the container ipc is shareable
++ if st, err := os.Stat(container.ShmPath); err != nil || !st.IsDir() {
++ if err == nil || os.IsNotExist(err) {
++ return nil, errors.New(errMsg + ": non-shareable IPC (hint: use IpcMode:shareable for the donor container)")
++ }
++ // stat() failed?
++ return nil, errors.Wrap(err, errMsg+": unexpected error from stat "+container.ShmPath)
++ }
++
++ return container, nil
++}
++
++func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) {
++ containerID := container.HostConfig.PidMode.Container()
++ container, err := daemon.GetContainer(containerID)
++ if err != nil {
++ return nil, errors.Wrapf(err, "cannot join PID of a non running container: %s", containerID)
++ }
++ return container, daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting)
++}
++
++func containerIsRunning(c *container.Container) error {
++ if !c.IsRunning() {
++ return errdefs.Conflict(errors.Errorf("container %s is not running", c.ID))
++ }
++ return nil
++}
++
++func containerIsNotRestarting(c *container.Container) error {
++ if c.IsRestarting() {
++ return errContainerIsRestarting(c.ID)
++ }
++ return nil
++}
++
++func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
++ ipcMode := c.HostConfig.IpcMode
++
++ switch {
++ case ipcMode.IsContainer():
++ ic, err := daemon.getIpcContainer(ipcMode.Container())
++ if err != nil {
++ return err
++ }
++ c.ShmPath = ic.ShmPath
++
++ case ipcMode.IsHost():
++ if _, err := os.Stat("/dev/shm"); err != nil {
++ return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
++ }
++ c.ShmPath = "/dev/shm"
++
++ case ipcMode.IsPrivate(), ipcMode.IsNone():
++ // c.ShmPath will/should not be used, so make it empty.
++ // Container's /dev/shm mount comes from OCI spec.
++ c.ShmPath = ""
++
++ case ipcMode.IsEmpty():
++ // A container was created by an older version of the daemon.
++ // The default behavior used to be what is now called "shareable".
++ fallthrough
++
++ case ipcMode.IsShareable():
++ rootIDs := daemon.idMapping.RootPair()
++ if !c.HasMountFor("/dev/shm") {
++ shmPath, err := c.ShmResourcePath()
++ if err != nil {
++ return err
++ }
++
++ if err := idtools.MkdirAllAndChown(shmPath, 0700, rootIDs); err != nil {
++ return err
++ }
++
++ shmproperty := "mode=1777,size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
++ if err := unix.Mount("shm", shmPath, "tmpfs", uintptr(unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil {
++ return fmt.Errorf("mounting shm tmpfs: %s", err)
++ }
++ if err := os.Chown(shmPath, rootIDs.UID, rootIDs.GID); err != nil {
++ return err
++ }
++ c.ShmPath = shmPath
++ }
++
++ default:
++ return fmt.Errorf("invalid IPC mode: %v", ipcMode)
++ }
++
++ return nil
++}
++
++func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
++ if len(c.SecretReferences) == 0 && len(c.ConfigReferences) == 0 {
++ return nil
++ }
++
++ if err := daemon.createSecretsDir(c); err != nil {
++ return err
++ }
++ defer func() {
++ if setupErr != nil {
++ daemon.cleanupSecretDir(c)
++ }
++ }()
++
++ if c.DependencyStore == nil {
++ return fmt.Errorf("secret store is not initialized")
++ }
++
++ // retrieve possible remapped range start for root UID, GID
++ rootIDs := daemon.idMapping.RootPair()
++
++ for _, s := range c.SecretReferences {
++ // TODO (ehazlett): use type switch when more are supported
++ if s.File == nil {
++ logrus.Error("secret target type is not a file target")
++ continue
++ }
++
++ // secrets are created in the SecretMountPath on the host, at a
++ // single level
++ fPath, err := c.SecretFilePath(*s)
++ if err != nil {
++ return errors.Wrap(err, "error getting secret file path")
++ }
++ if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
++ return errors.Wrap(err, "error creating secret mount path")
++ }
++
++ logrus.WithFields(logrus.Fields{
++ "name": s.File.Name,
++ "path": fPath,
++ }).Debug("injecting secret")
++ secret, err := c.DependencyStore.Secrets().Get(s.SecretID)
++ if err != nil {
++ return errors.Wrap(err, "unable to get secret from secret store")
++ }
++ if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil {
++ return errors.Wrap(err, "error injecting secret")
++ }
++
++ uid, err := strconv.Atoi(s.File.UID)
++ if err != nil {
++ return err
++ }
++ gid, err := strconv.Atoi(s.File.GID)
++ if err != nil {
++ return err
++ }
++
++ if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
++ return errors.Wrap(err, "error setting ownership for secret")
++ }
++ if err := os.Chmod(fPath, s.File.Mode); err != nil {
++ return errors.Wrap(err, "error setting file mode for secret")
++ }
++ }
++
++ for _, ref := range c.ConfigReferences {
++ // TODO (ehazlett): use type switch when more are supported
++ if ref.File == nil {
++ // Runtime configs are not mounted into the container, but they're
++ // a valid type of config so we should not error when we encounter
++ // one.
++ if ref.Runtime == nil {
++ logrus.Error("config target type is not a file or runtime target")
++ }
++ // However, in any case, this isn't a file config, so we have no
++ // further work to do
++ continue
++ }
++
++ fPath, err := c.ConfigFilePath(*ref)
++ if err != nil {
++ return errors.Wrap(err, "error getting config file path for container")
++ }
++ if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
++ return errors.Wrap(err, "error creating config mount path")
++ }
++
++ logrus.WithFields(logrus.Fields{
++ "name": ref.File.Name,
++ "path": fPath,
++ }).Debug("injecting config")
++ config, err := c.DependencyStore.Configs().Get(ref.ConfigID)
++ if err != nil {
++ return errors.Wrap(err, "unable to get config from config store")
++ }
++ if err := ioutil.WriteFile(fPath, config.Spec.Data, ref.File.Mode); err != nil {
++ return errors.Wrap(err, "error injecting config")
++ }
++
++ uid, err := strconv.Atoi(ref.File.UID)
++ if err != nil {
++ return err
++ }
++ gid, err := strconv.Atoi(ref.File.GID)
++ if err != nil {
++ return err
++ }
++
++ if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
++ return errors.Wrap(err, "error setting ownership for config")
++ }
++ if err := os.Chmod(fPath, ref.File.Mode); err != nil {
++ return errors.Wrap(err, "error setting file mode for config")
++ }
++ }
++
++ return daemon.remountSecretDir(c)
++}
++
++// createSecretsDir is used to create a dir suitable for storing container secrets.
++// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
++func (daemon *Daemon) createSecretsDir(c *container.Container) error {
++ // retrieve possible remapped range start for root UID, GID
++ rootIDs := daemon.idMapping.RootPair()
++ dir, err := c.SecretMountPath()
++ if err != nil {
++ return errors.Wrap(err, "error getting container secrets dir")
++ }
++
++ // create tmpfs
++ if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
++ return errors.Wrap(err, "error creating secret local mount path")
++ }
++
++ tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
++ if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
++ return errors.Wrap(err, "unable to setup secret mount")
++ }
++ return nil
++}
++
++func (daemon *Daemon) remountSecretDir(c *container.Container) error {
++ dir, err := c.SecretMountPath()
++ if err != nil {
++ return errors.Wrap(err, "error getting container secrets path")
++ }
++ if err := label.Relabel(dir, c.MountLabel, false); err != nil {
++ logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
++ }
++ rootIDs := daemon.idMapping.RootPair()
++ tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
++
++ // remount secrets ro
++ if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
++ return errors.Wrap(err, "unable to remount dir as readonly")
++ }
++
++ return nil
++}
++
++func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
++ dir, err := c.SecretMountPath()
++ if err != nil {
++ logrus.WithError(err).WithField("container", c.ID).Warn("error getting secrets mount path for container")
++ }
++ if err := mount.RecursiveUnmount(dir); err != nil {
++ logrus.WithField("dir", dir).WithError(err).Warn("Error while attempting to unmount dir, this may prevent removal of container.")
++ }
++ if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
++ logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
++ }
++}
++
++func killProcessDirectly(cntr *container.Container) error {
++ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
++ defer cancel()
++
++ // Block until the container to stops or timeout.
++ status := <-cntr.Wait(ctx, container.WaitConditionNotRunning)
++ if status.Err() != nil {
++ // Ensure that we don't kill ourselves
++ if pid := cntr.GetPID(); pid != 0 {
++ logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(cntr.ID))
++ if err := unix.Kill(pid, 9); err != nil {
++ if err != unix.ESRCH {
++ return err
++ }
++ e := errNoSuchProcess{pid, 9}
++ logrus.Debug(e)
++ return e
++ }
++ }
++ }
++ 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
++}
++
++// serviceDiscoveryOnDefaultNetwork indicates if service discovery is supported on the default network
++func serviceDiscoveryOnDefaultNetwork() bool {
++ return false
++}
++
++func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
++ var err error
++
++ if container.HostConfig.NetworkMode.IsHost() {
++ // Point to the host files, so that will be copied into the container running in host mode
++ *sboxOptions = append(*sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
++ }
++
++ // Copy the host's resolv.conf for the container (/etc/resolv.conf or /run/systemd/resolve/resolv.conf)
++ *sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath(daemon.configStore.GetResolvConf()))
++
++ container.HostsPath, err = container.GetRootResourcePath("hosts")
++ if err != nil {
++ return err
++ }
++ *sboxOptions = append(*sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
++
++ container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
++ if err != nil {
++ return err
++ }
++ *sboxOptions = append(*sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
++ return nil
++}
++
++func (daemon *Daemon) initializeNetworkingPaths(container *container.Container, nc *container.Container) error {
++ container.HostnamePath = nc.HostnamePath
++ container.HostsPath = nc.HostsPath
++ container.ResolvConfPath = nc.ResolvConfPath
++ return nil
++}
++
++func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
++ // get the root mount path so we can make it unbindable
++ p, err := c.MountsResourcePath("")
++ if err != nil {
++ return err
++ }
++ return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
++}
Index: sysutils/docker-freebsd/files/patch-daemon_container__operations__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_container__operations__unix.go
@@ -0,0 +1,418 @@
+--- daemon/container_operations_unix.go.orig 2020-09-04 14:54:50 UTC
++++ daemon/container_operations_unix.go
+@@ -1,415 +0,0 @@
+-// +build linux freebsd
+-
+-package daemon // import "github.com/docker/docker/daemon"
+-
+-import (
+- "context"
+- "fmt"
+- "io/ioutil"
+- "os"
+- "path/filepath"
+- "strconv"
+- "time"
+-
+- "github.com/docker/docker/container"
+- "github.com/docker/docker/daemon/links"
+- "github.com/docker/docker/errdefs"
+- "github.com/docker/docker/pkg/idtools"
+- "github.com/docker/docker/pkg/mount"
+- "github.com/docker/docker/pkg/stringid"
+- "github.com/docker/docker/runconfig"
+- "github.com/docker/libnetwork"
+- "github.com/opencontainers/selinux/go-selinux/label"
+- "github.com/pkg/errors"
+- "github.com/sirupsen/logrus"
+- "golang.org/x/sys/unix"
+-)
+-
+-func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
+- var env []string
+- children := daemon.children(container)
+-
+- bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
+- if bridgeSettings == nil || bridgeSettings.EndpointSettings == nil {
+- return nil, nil
+- }
+-
+- for linkAlias, child := range children {
+- if !child.IsRunning() {
+- return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
+- }
+-
+- childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
+- if childBridgeSettings == nil || childBridgeSettings.EndpointSettings == nil {
+- return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
+- }
+-
+- link := links.NewLink(
+- bridgeSettings.IPAddress,
+- childBridgeSettings.IPAddress,
+- linkAlias,
+- child.Config.Env,
+- child.Config.ExposedPorts,
+- )
+-
+- env = append(env, link.ToEnv()...)
+- }
+-
+- return env, nil
+-}
+-
+-func (daemon *Daemon) getIpcContainer(id string) (*container.Container, error) {
+- errMsg := "can't join IPC of container " + id
+- // Check the container exists
+- container, err := daemon.GetContainer(id)
+- if err != nil {
+- return nil, errors.Wrap(err, errMsg)
+- }
+- // Check the container is running and not restarting
+- if err := daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting); err != nil {
+- return nil, errors.Wrap(err, errMsg)
+- }
+- // Check the container ipc is shareable
+- if st, err := os.Stat(container.ShmPath); err != nil || !st.IsDir() {
+- if err == nil || os.IsNotExist(err) {
+- return nil, errors.New(errMsg + ": non-shareable IPC (hint: use IpcMode:shareable for the donor container)")
+- }
+- // stat() failed?
+- return nil, errors.Wrap(err, errMsg+": unexpected error from stat "+container.ShmPath)
+- }
+-
+- return container, nil
+-}
+-
+-func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) {
+- containerID := container.HostConfig.PidMode.Container()
+- container, err := daemon.GetContainer(containerID)
+- if err != nil {
+- return nil, errors.Wrapf(err, "cannot join PID of a non running container: %s", containerID)
+- }
+- return container, daemon.checkContainer(container, containerIsRunning, containerIsNotRestarting)
+-}
+-
+-func containerIsRunning(c *container.Container) error {
+- if !c.IsRunning() {
+- return errdefs.Conflict(errors.Errorf("container %s is not running", c.ID))
+- }
+- return nil
+-}
+-
+-func containerIsNotRestarting(c *container.Container) error {
+- if c.IsRestarting() {
+- return errContainerIsRestarting(c.ID)
+- }
+- return nil
+-}
+-
+-func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
+- ipcMode := c.HostConfig.IpcMode
+-
+- switch {
+- case ipcMode.IsContainer():
+- ic, err := daemon.getIpcContainer(ipcMode.Container())
+- if err != nil {
+- return err
+- }
+- c.ShmPath = ic.ShmPath
+-
+- case ipcMode.IsHost():
+- if _, err := os.Stat("/dev/shm"); err != nil {
+- return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
+- }
+- c.ShmPath = "/dev/shm"
+-
+- case ipcMode.IsPrivate(), ipcMode.IsNone():
+- // c.ShmPath will/should not be used, so make it empty.
+- // Container's /dev/shm mount comes from OCI spec.
+- c.ShmPath = ""
+-
+- case ipcMode.IsEmpty():
+- // A container was created by an older version of the daemon.
+- // The default behavior used to be what is now called "shareable".
+- fallthrough
+-
+- case ipcMode.IsShareable():
+- rootIDs := daemon.idMapping.RootPair()
+- if !c.HasMountFor("/dev/shm") {
+- shmPath, err := c.ShmResourcePath()
+- if err != nil {
+- return err
+- }
+-
+- if err := idtools.MkdirAllAndChown(shmPath, 0700, rootIDs); err != nil {
+- return err
+- }
+-
+- shmproperty := "mode=1777,size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
+- if err := unix.Mount("shm", shmPath, "tmpfs", uintptr(unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil {
+- return fmt.Errorf("mounting shm tmpfs: %s", err)
+- }
+- if err := os.Chown(shmPath, rootIDs.UID, rootIDs.GID); err != nil {
+- return err
+- }
+- c.ShmPath = shmPath
+- }
+-
+- default:
+- return fmt.Errorf("invalid IPC mode: %v", ipcMode)
+- }
+-
+- return nil
+-}
+-
+-func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
+- if len(c.SecretReferences) == 0 && len(c.ConfigReferences) == 0 {
+- return nil
+- }
+-
+- if err := daemon.createSecretsDir(c); err != nil {
+- return err
+- }
+- defer func() {
+- if setupErr != nil {
+- daemon.cleanupSecretDir(c)
+- }
+- }()
+-
+- if c.DependencyStore == nil {
+- return fmt.Errorf("secret store is not initialized")
+- }
+-
+- // retrieve possible remapped range start for root UID, GID
+- rootIDs := daemon.idMapping.RootPair()
+-
+- for _, s := range c.SecretReferences {
+- // TODO (ehazlett): use type switch when more are supported
+- if s.File == nil {
+- logrus.Error("secret target type is not a file target")
+- continue
+- }
+-
+- // secrets are created in the SecretMountPath on the host, at a
+- // single level
+- fPath, err := c.SecretFilePath(*s)
+- if err != nil {
+- return errors.Wrap(err, "error getting secret file path")
+- }
+- if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
+- return errors.Wrap(err, "error creating secret mount path")
+- }
+-
+- logrus.WithFields(logrus.Fields{
+- "name": s.File.Name,
+- "path": fPath,
+- }).Debug("injecting secret")
+- secret, err := c.DependencyStore.Secrets().Get(s.SecretID)
+- if err != nil {
+- return errors.Wrap(err, "unable to get secret from secret store")
+- }
+- if err := ioutil.WriteFile(fPath, secret.Spec.Data, s.File.Mode); err != nil {
+- return errors.Wrap(err, "error injecting secret")
+- }
+-
+- uid, err := strconv.Atoi(s.File.UID)
+- if err != nil {
+- return err
+- }
+- gid, err := strconv.Atoi(s.File.GID)
+- if err != nil {
+- return err
+- }
+-
+- if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
+- return errors.Wrap(err, "error setting ownership for secret")
+- }
+- if err := os.Chmod(fPath, s.File.Mode); err != nil {
+- return errors.Wrap(err, "error setting file mode for secret")
+- }
+- }
+-
+- for _, ref := range c.ConfigReferences {
+- // TODO (ehazlett): use type switch when more are supported
+- if ref.File == nil {
+- // Runtime configs are not mounted into the container, but they're
+- // a valid type of config so we should not error when we encounter
+- // one.
+- if ref.Runtime == nil {
+- logrus.Error("config target type is not a file or runtime target")
+- }
+- // However, in any case, this isn't a file config, so we have no
+- // further work to do
+- continue
+- }
+-
+- fPath, err := c.ConfigFilePath(*ref)
+- if err != nil {
+- return errors.Wrap(err, "error getting config file path for container")
+- }
+- if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
+- return errors.Wrap(err, "error creating config mount path")
+- }
+-
+- logrus.WithFields(logrus.Fields{
+- "name": ref.File.Name,
+- "path": fPath,
+- }).Debug("injecting config")
+- config, err := c.DependencyStore.Configs().Get(ref.ConfigID)
+- if err != nil {
+- return errors.Wrap(err, "unable to get config from config store")
+- }
+- if err := ioutil.WriteFile(fPath, config.Spec.Data, ref.File.Mode); err != nil {
+- return errors.Wrap(err, "error injecting config")
+- }
+-
+- uid, err := strconv.Atoi(ref.File.UID)
+- if err != nil {
+- return err
+- }
+- gid, err := strconv.Atoi(ref.File.GID)
+- if err != nil {
+- return err
+- }
+-
+- if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
+- return errors.Wrap(err, "error setting ownership for config")
+- }
+- if err := os.Chmod(fPath, ref.File.Mode); err != nil {
+- return errors.Wrap(err, "error setting file mode for config")
+- }
+- }
+-
+- return daemon.remountSecretDir(c)
+-}
+-
+-// createSecretsDir is used to create a dir suitable for storing container secrets.
+-// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
+-func (daemon *Daemon) createSecretsDir(c *container.Container) error {
+- // retrieve possible remapped range start for root UID, GID
+- rootIDs := daemon.idMapping.RootPair()
+- dir, err := c.SecretMountPath()
+- if err != nil {
+- return errors.Wrap(err, "error getting container secrets dir")
+- }
+-
+- // create tmpfs
+- if err := idtools.MkdirAllAndChown(dir, 0700, rootIDs); err != nil {
+- return errors.Wrap(err, "error creating secret local mount path")
+- }
+-
+- tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
+- if err := mount.Mount("tmpfs", dir, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
+- return errors.Wrap(err, "unable to setup secret mount")
+- }
+- return nil
+-}
+-
+-func (daemon *Daemon) remountSecretDir(c *container.Container) error {
+- dir, err := c.SecretMountPath()
+- if err != nil {
+- return errors.Wrap(err, "error getting container secrets path")
+- }
+- if err := label.Relabel(dir, c.MountLabel, false); err != nil {
+- logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
+- }
+- rootIDs := daemon.idMapping.RootPair()
+- tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
+-
+- // remount secrets ro
+- if err := mount.Mount("tmpfs", dir, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
+- return errors.Wrap(err, "unable to remount dir as readonly")
+- }
+-
+- return nil
+-}
+-
+-func (daemon *Daemon) cleanupSecretDir(c *container.Container) {
+- dir, err := c.SecretMountPath()
+- if err != nil {
+- logrus.WithError(err).WithField("container", c.ID).Warn("error getting secrets mount path for container")
+- }
+- if err := mount.RecursiveUnmount(dir); err != nil {
+- logrus.WithField("dir", dir).WithError(err).Warn("Error while attempting to unmount dir, this may prevent removal of container.")
+- }
+- if err := os.RemoveAll(dir); err != nil && !os.IsNotExist(err) {
+- logrus.WithField("dir", dir).WithError(err).Error("Error removing dir.")
+- }
+-}
+-
+-func killProcessDirectly(cntr *container.Container) error {
+- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+- defer cancel()
+-
+- // Block until the container to stops or timeout.
+- status := <-cntr.Wait(ctx, container.WaitConditionNotRunning)
+- if status.Err() != nil {
+- // Ensure that we don't kill ourselves
+- if pid := cntr.GetPID(); pid != 0 {
+- logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(cntr.ID))
+- if err := unix.Kill(pid, 9); err != nil {
+- if err != unix.ESRCH {
+- return err
+- }
+- e := errNoSuchProcess{pid, 9}
+- logrus.Debug(e)
+- return e
+- }
+- }
+- }
+- 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
+-}
+-
+-// serviceDiscoveryOnDefaultNetwork indicates if service discovery is supported on the default network
+-func serviceDiscoveryOnDefaultNetwork() bool {
+- return false
+-}
+-
+-func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
+- var err error
+-
+- if container.HostConfig.NetworkMode.IsHost() {
+- // Point to the host files, so that will be copied into the container running in host mode
+- *sboxOptions = append(*sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
+- }
+-
+- // Copy the host's resolv.conf for the container (/etc/resolv.conf or /run/systemd/resolve/resolv.conf)
+- *sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath(daemon.configStore.GetResolvConf()))
+-
+- container.HostsPath, err = container.GetRootResourcePath("hosts")
+- if err != nil {
+- return err
+- }
+- *sboxOptions = append(*sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
+-
+- container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
+- if err != nil {
+- return err
+- }
+- *sboxOptions = append(*sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
+- return nil
+-}
+-
+-func (daemon *Daemon) initializeNetworkingPaths(container *container.Container, nc *container.Container) error {
+- container.HostnamePath = nc.HostnamePath
+- container.HostsPath = nc.HostsPath
+- container.ResolvConfPath = nc.ResolvConfPath
+- return nil
+-}
+-
+-func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
+- // get the root mount path so we can make it unbindable
+- p, err := c.MountsResourcePath("")
+- if err != nil {
+- return err
+- }
+- return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
+-}
Index: sysutils/docker-freebsd/files/patch-daemon_daemon__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_daemon__freebsd.go
@@ -0,0 +1,142 @@
+--- daemon/daemon_freebsd.go.orig 2020-10-16 13:57:41 UTC
++++ daemon/daemon_freebsd.go
+@@ -0,0 +1,139 @@
++package daemon // import "github.com/docker/docker/daemon"
++
++// based on daemon_linux
++
++import (
++ "bufio"
++ "fmt"
++ "io"
++ "os"
++ "path/filepath"
++ "regexp"
++ "strings"
++
++ "github.com/docker/docker/daemon/config"
++ "github.com/docker/docker/pkg/fileutils"
++ "github.com/docker/docker/pkg/mount"
++ "github.com/docker/libnetwork/resolvconf"
++ "github.com/pkg/errors"
++ "github.com/sirupsen/logrus"
++)
++
++func getPluginExecRoot(root string) string {
++ return filepath.Join(root, "plugins")
++}
++
++func (daemon *Daemon) cleanupMountsByID(id string) error {
++ return nil
++}
++
++func (daemon *Daemon) cleanupMountsFromReaderByID(reader io.Reader, id string, unmount func(target string) error) error {
++ if daemon.root == "" {
++ return nil
++ }
++ var errors []string
++
++ regexps := getCleanPatterns(id)
++ sc := bufio.NewScanner(reader)
++ for sc.Scan() {
++ if fields := strings.Fields(sc.Text()); len(fields) >= 4 {
++ if mnt := fields[4]; strings.HasPrefix(mnt, daemon.root) {
++ for _, p := range regexps {
++ if p.MatchString(mnt) {
++ if err := unmount(mnt); err != nil {
++ logrus.Error(err)
++ errors = append(errors, err.Error())
++ }
++ }
++ }
++ }
++ }
++ }
++
++ if err := sc.Err(); err != nil {
++ return err
++ }
++
++ if len(errors) > 0 {
++ return fmt.Errorf("Error cleaning up mounts:\n%v", strings.Join(errors, "\n"))
++ }
++
++ logrus.Debugf("Cleaning up old mountid %v: done.", id)
++ return nil
++}
++
++// cleanupMounts umounts used by container resources and the daemon root mount
++func (daemon *Daemon) cleanupMounts() error {
++ if err := daemon.cleanupMountsByID(""); err != nil {
++ return err
++ }
++
++ info, err := mount.GetMounts(mount.SingleEntryFilter(daemon.root))
++ if err != nil {
++ return errors.Wrap(err, "error reading mount table for cleanup")
++ }
++
++ if len(info) < 1 {
++ // no mount found, we're done here
++ return nil
++ }
++
++ // `info.Root` here is the root mountpoint of the passed in path (`daemon.root`).
++ // The ony cases that need to be cleaned up is when the daemon has performed a
++ // `mount --bind /daemon/root /daemon/root && mount --make-shared /daemon/root`
++ // This is only done when the daemon is started up and `/daemon/root` is not
++ // already on a shared mountpoint.
++ //if !shouldUnmountRoot(daemon.root, info[0]) {
++ // return nil
++ //}
++
++ unmountFile := getUnmountOnShutdownPath(daemon.configStore)
++ if _, err := os.Stat(unmountFile); err != nil {
++ return nil
++ }
++
++ logrus.WithField("mountpoint", daemon.root).Debug("unmounting daemon root")
++ if err := mount.Unmount(daemon.root); err != nil {
++ return err
++ }
++ return os.Remove(unmountFile)
++}
++
++func getCleanPatterns(id string) (regexps []*regexp.Regexp) {
++ var patterns []string
++ if id == "" {
++ id = "[0-9a-f]{64}"
++ patterns = append(patterns, "containers/"+id+"/shm")
++ }
++ patterns = append(patterns, "aufs/mnt/"+id+"$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$")
++ for _, p := range patterns {
++ r, err := regexp.Compile(p)
++ if err == nil {
++ regexps = append(regexps, r)
++ }
++ }
++ return
++}
++
++func getRealPath(path string) (string, error) {
++ return fileutils.ReadSymlinkedDirectory(path)
++}
++
++//func shouldUnmountRoot(root string, info *mount.Info) bool {
++// if !strings.HasSuffix(root, info.Root) {
++// return false
++// }
++// return hasMountinfoOption(info.Optional, sharedPropagationOption)
++//}
++
++// setupResolvConf sets the appropriate resolv.conf file if not specified
++// When systemd-resolved is running the default /etc/resolv.conf points to
++// localhost. In this case fetch the alternative config file that is in a
++// different path so that containers can use it
++// In all the other cases fallback to the default one
++func setupResolvConf(config *config.Config) {
++ if config.ResolvConf != "" {
++ return
++ }
++ config.ResolvConf = resolvconf.Path()
++}
Index: sysutils/docker-freebsd/files/patch-daemon_daemon__linux.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_daemon__linux.go
@@ -0,0 +1,46 @@
+--- daemon/daemon_linux.go.orig 2020-09-04 14:54:51 UTC
++++ daemon/daemon_linux.go
+@@ -145,3 +145,43 @@ func setupResolvConf(config *config.Config) {
+ }
+ config.ResolvConf = resolvconf.Path()
+ }
++
++// setupDaemonProcess sets various settings for the daemon's process
++func setupDaemonProcess(config *config.Config) error {
++ // setup the daemons oom_score_adj
++ return setupOOMScoreAdj(config.OOMScoreAdjust)
++}
++
++func setupOOMScoreAdj(score int) error {
++ f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
++ if err != nil {
++ return err
++ }
++ defer f.Close()
++ stringScore := strconv.Itoa(score)
++ _, err = f.WriteString(stringScore)
++ if os.IsPermission(err) {
++ // Setting oom_score_adj does not work in an
++ // unprivileged container. Ignore the error, but log
++ // it if we appear not to be in that situation.
++ if !rsystem.RunningInUserNS() {
++ logrus.Debugf("Permission denied writing %q to /proc/self/oom_score_adj", stringScore)
++ }
++ return nil
++ }
++
++ return err
++}
++
++func (daemon *Daemon) setupSeccompProfile() error {
++ if daemon.configStore.SeccompProfile != "" {
++ daemon.seccompProfilePath = daemon.configStore.SeccompProfile
++ b, err := ioutil.ReadFile(daemon.configStore.SeccompProfile)
++ if err != nil {
++ return fmt.Errorf("opening seccomp profile (%s) failed: %v", daemon.configStore.SeccompProfile, err)
++ }
++ daemon.seccompProfile = b
++ }
++ return nil
++}
++
Index: sysutils/docker-freebsd/files/patch-daemon_daemon__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_daemon__unix.go
@@ -0,0 +1,382 @@
+--- daemon/daemon_unix.go.orig 2020-10-23 18:37:16 UTC
++++ daemon/daemon_unix.go
+@@ -29,7 +29,8 @@ import (
+ "github.com/docker/docker/pkg/containerfs"
+ "github.com/docker/docker/pkg/idtools"
+ "github.com/docker/docker/pkg/ioutils"
+- "github.com/docker/docker/pkg/mount"
++
++ //"github.com/docker/docker/pkg/mount"
+ "github.com/docker/docker/pkg/parsers"
+ "github.com/docker/docker/pkg/parsers/kernel"
+ "github.com/docker/docker/pkg/sysinfo"
+@@ -37,18 +38,18 @@ import (
+ volumemounts "github.com/docker/docker/volume/mounts"
+ "github.com/docker/libnetwork"
+ nwconfig "github.com/docker/libnetwork/config"
+- "github.com/docker/libnetwork/drivers/bridge"
++ "github.com/docker/libnetwork/drivers/freebsd/bridge"
+ "github.com/docker/libnetwork/netlabel"
+ "github.com/docker/libnetwork/netutils"
+ "github.com/docker/libnetwork/options"
+ lntypes "github.com/docker/libnetwork/types"
+- "github.com/opencontainers/runc/libcontainer/cgroups"
++
++ // "github.com/opencontainers/runc/libcontainer/cgroups"
+ rsystem "github.com/opencontainers/runc/libcontainer/system"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux/label"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+- "github.com/vishvananda/netlink"
+ "golang.org/x/sys/unix"
+ )
+
+@@ -874,11 +875,11 @@ func (daemon *Daemon) initNetworkController(config *co
+ }
+
+ // Initialize default network on "host"
+- if n, _ := controller.NetworkByName("host"); n == nil {
+- if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
+- return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
+- }
+- }
++ // if n, _ := controller.NetworkByName("host"); n == nil {
++ // if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
++ // return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
++ // }
++ // }
+
+ // Clear stale bridge network
+ if n, err := controller.NetworkByName("bridge"); err == nil {
+@@ -1043,16 +1044,13 @@ func initBridgeDriver(controller libnetwork.NetworkCon
+ 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 removeDefaultBridgeInterface() error {
++ return fmt.Errorf("Bridge network driver not supported on FreeBSD (yet)")
+ }
+
+ func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
+@@ -1260,45 +1258,45 @@ func setupDaemonRoot(config *config.Config, rootDir st
+ }
+
+ func setupDaemonRootPropagation(cfg *config.Config) error {
+- rootParentMount, options, err := getSourceMount(cfg.Root)
+- if err != nil {
+- return errors.Wrap(err, "error getting daemon root's parent mount")
+- }
++ // rootParentMount, options, err := getSourceMount(cfg.Root)
++ // if err != nil {
++ // return errors.Wrap(err, "error getting daemon root's parent mount")
++ // }
+
+- var cleanupOldFile bool
+- cleanupFile := getUnmountOnShutdownPath(cfg)
+- defer func() {
+- if !cleanupOldFile {
+- return
+- }
+- if err := os.Remove(cleanupFile); err != nil && !os.IsNotExist(err) {
+- logrus.WithError(err).WithField("file", cleanupFile).Warn("could not clean up old root propagation unmount file")
+- }
+- }()
++ // var cleanupOldFile bool
++ // cleanupFile := getUnmountOnShutdownPath(cfg)
++ // defer func() {
++ // if !cleanupOldFile {
++ // return
++ // }
++ // if err := os.Remove(cleanupFile); err != nil && !os.IsNotExist(err) {
++ // logrus.WithError(err).WithField("file", cleanupFile).Warn("could not clean up old root propagation unmount file")
++ // }
++ // }()
+
+- if hasMountinfoOption(options, sharedPropagationOption, slavePropagationOption) {
+- cleanupOldFile = true
+- return nil
+- }
++ // if hasMountinfoOption(options, sharedPropagationOption, slavePropagationOption) {
++ // cleanupOldFile = true
++ // return nil
++ // }
+
+- if err := mount.MakeShared(cfg.Root); err != nil {
+- return errors.Wrap(err, "could not setup daemon root propagation to shared")
+- }
++ // if err := mount.MakeShared(cfg.Root); err != nil {
++ // return errors.Wrap(err, "could not setup daemon root propagation to shared")
++ // }
+
+- // check the case where this may have already been a mount to itself.
+- // If so then the daemon only performed a remount and should not try to unmount this later.
+- if rootParentMount == cfg.Root {
+- cleanupOldFile = true
+- return nil
+- }
++ // // check the case where this may have already been a mount to itself.
++ // // If so then the daemon only performed a remount and should not try to unmount this later.
++ // if rootParentMount == cfg.Root {
++ // cleanupOldFile = true
++ // return nil
++ // }
+
+- if err := os.MkdirAll(filepath.Dir(cleanupFile), 0700); err != nil {
+- return errors.Wrap(err, "error creating dir to store mount cleanup file")
+- }
++ // if err := os.MkdirAll(filepath.Dir(cleanupFile), 0700); err != nil {
++ // return errors.Wrap(err, "error creating dir to store mount cleanup file")
++ // }
+
+- if err := ioutil.WriteFile(cleanupFile, nil, 0600); err != nil {
+- return errors.Wrap(err, "error writing file to signal mount cleanup on shutdown")
+- }
++ // if err := ioutil.WriteFile(cleanupFile, nil, 0600); err != nil {
++ // return errors.Wrap(err, "error writing file to signal mount cleanup on shutdown")
++ // }
+ return nil
+ }
+
+@@ -1387,7 +1385,7 @@ func (daemon *Daemon) stats(c *container.Container) (*
+ if !c.IsRunning() {
+ return nil, errNotRunning(c.ID)
+ }
+- cs, err := daemon.containerd.Stats(context.Background(), c.ID)
++ _, err := daemon.containerd.Stats(context.Background(), c.ID)
+ if err != nil {
+ if strings.Contains(err.Error(), "container not found") {
+ return nil, containerNotFound(c.ID)
+@@ -1395,97 +1393,97 @@ func (daemon *Daemon) stats(c *container.Container) (*
+ return nil, err
+ }
+ s := &types.StatsJSON{}
+- s.Read = cs.Read
+- stats := cs.Metrics
+- if stats.Blkio != nil {
+- s.BlkioStats = types.BlkioStats{
+- IoServiceBytesRecursive: copyBlkioEntry(stats.Blkio.IoServiceBytesRecursive),
+- IoServicedRecursive: copyBlkioEntry(stats.Blkio.IoServicedRecursive),
+- IoQueuedRecursive: copyBlkioEntry(stats.Blkio.IoQueuedRecursive),
+- IoServiceTimeRecursive: copyBlkioEntry(stats.Blkio.IoServiceTimeRecursive),
+- IoWaitTimeRecursive: copyBlkioEntry(stats.Blkio.IoWaitTimeRecursive),
+- IoMergedRecursive: copyBlkioEntry(stats.Blkio.IoMergedRecursive),
+- IoTimeRecursive: copyBlkioEntry(stats.Blkio.IoTimeRecursive),
+- SectorsRecursive: copyBlkioEntry(stats.Blkio.SectorsRecursive),
+- }
+- }
+- if stats.CPU != nil {
+- s.CPUStats = types.CPUStats{
+- CPUUsage: types.CPUUsage{
+- TotalUsage: stats.CPU.Usage.Total,
+- PercpuUsage: stats.CPU.Usage.PerCPU,
+- UsageInKernelmode: stats.CPU.Usage.Kernel,
+- UsageInUsermode: stats.CPU.Usage.User,
+- },
+- ThrottlingData: types.ThrottlingData{
+- Periods: stats.CPU.Throttling.Periods,
+- ThrottledPeriods: stats.CPU.Throttling.ThrottledPeriods,
+- ThrottledTime: stats.CPU.Throttling.ThrottledTime,
+- },
+- }
+- }
++ // s.Read = cs.Read
++ // stats := cs.Metrics
++ // if stats.Blkio != nil {
++ // s.BlkioStats = types.BlkioStats{
++ // IoServiceBytesRecursive: copyBlkioEntry(stats.Blkio.IoServiceBytesRecursive),
++ // IoServicedRecursive: copyBlkioEntry(stats.Blkio.IoServicedRecursive),
++ // IoQueuedRecursive: copyBlkioEntry(stats.Blkio.IoQueuedRecursive),
++ // IoServiceTimeRecursive: copyBlkioEntry(stats.Blkio.IoServiceTimeRecursive),
++ // IoWaitTimeRecursive: copyBlkioEntry(stats.Blkio.IoWaitTimeRecursive),
++ // IoMergedRecursive: copyBlkioEntry(stats.Blkio.IoMergedRecursive),
++ // IoTimeRecursive: copyBlkioEntry(stats.Blkio.IoTimeRecursive),
++ // SectorsRecursive: copyBlkioEntry(stats.Blkio.SectorsRecursive),
++ // }
++ // }
++ // if stats.CPU != nil {
++ // s.CPUStats = types.CPUStats{
++ // CPUUsage: types.CPUUsage{
++ // TotalUsage: stats.CPU.Usage.Total,
++ // PercpuUsage: stats.CPU.Usage.PerCPU,
++ // UsageInKernelmode: stats.CPU.Usage.Kernel,
++ // UsageInUsermode: stats.CPU.Usage.User,
++ // },
++ // ThrottlingData: types.ThrottlingData{
++ // Periods: stats.CPU.Throttling.Periods,
++ // ThrottledPeriods: stats.CPU.Throttling.ThrottledPeriods,
++ // ThrottledTime: stats.CPU.Throttling.ThrottledTime,
++ // },
++ // }
++ // }
+
+- if stats.Memory != nil {
+- raw := make(map[string]uint64)
+- raw["cache"] = stats.Memory.Cache
+- raw["rss"] = stats.Memory.RSS
+- raw["rss_huge"] = stats.Memory.RSSHuge
+- raw["mapped_file"] = stats.Memory.MappedFile
+- raw["dirty"] = stats.Memory.Dirty
+- raw["writeback"] = stats.Memory.Writeback
+- raw["pgpgin"] = stats.Memory.PgPgIn
+- raw["pgpgout"] = stats.Memory.PgPgOut
+- raw["pgfault"] = stats.Memory.PgFault
+- raw["pgmajfault"] = stats.Memory.PgMajFault
+- raw["inactive_anon"] = stats.Memory.InactiveAnon
+- raw["active_anon"] = stats.Memory.ActiveAnon
+- raw["inactive_file"] = stats.Memory.InactiveFile
+- raw["active_file"] = stats.Memory.ActiveFile
+- raw["unevictable"] = stats.Memory.Unevictable
+- raw["hierarchical_memory_limit"] = stats.Memory.HierarchicalMemoryLimit
+- raw["hierarchical_memsw_limit"] = stats.Memory.HierarchicalSwapLimit
+- raw["total_cache"] = stats.Memory.TotalCache
+- raw["total_rss"] = stats.Memory.TotalRSS
+- raw["total_rss_huge"] = stats.Memory.TotalRSSHuge
+- raw["total_mapped_file"] = stats.Memory.TotalMappedFile
+- raw["total_dirty"] = stats.Memory.TotalDirty
+- raw["total_writeback"] = stats.Memory.TotalWriteback
+- raw["total_pgpgin"] = stats.Memory.TotalPgPgIn
+- raw["total_pgpgout"] = stats.Memory.TotalPgPgOut
+- raw["total_pgfault"] = stats.Memory.TotalPgFault
+- raw["total_pgmajfault"] = stats.Memory.TotalPgMajFault
+- raw["total_inactive_anon"] = stats.Memory.TotalInactiveAnon
+- raw["total_active_anon"] = stats.Memory.TotalActiveAnon
+- raw["total_inactive_file"] = stats.Memory.TotalInactiveFile
+- raw["total_active_file"] = stats.Memory.TotalActiveFile
+- raw["total_unevictable"] = stats.Memory.TotalUnevictable
++ // if stats.Memory != nil {
++ // raw := make(map[string]uint64)
++ // raw["cache"] = stats.Memory.Cache
++ // raw["rss"] = stats.Memory.RSS
++ // raw["rss_huge"] = stats.Memory.RSSHuge
++ // raw["mapped_file"] = stats.Memory.MappedFile
++ // raw["dirty"] = stats.Memory.Dirty
++ // raw["writeback"] = stats.Memory.Writeback
++ // raw["pgpgin"] = stats.Memory.PgPgIn
++ // raw["pgpgout"] = stats.Memory.PgPgOut
++ // raw["pgfault"] = stats.Memory.PgFault
++ // raw["pgmajfault"] = stats.Memory.PgMajFault
++ // raw["inactive_anon"] = stats.Memory.InactiveAnon
++ // raw["active_anon"] = stats.Memory.ActiveAnon
++ // raw["inactive_file"] = stats.Memory.InactiveFile
++ // raw["active_file"] = stats.Memory.ActiveFile
++ // raw["unevictable"] = stats.Memory.Unevictable
++ // raw["hierarchical_memory_limit"] = stats.Memory.HierarchicalMemoryLimit
++ // raw["hierarchical_memsw_limit"] = stats.Memory.HierarchicalSwapLimit
++ // raw["total_cache"] = stats.Memory.TotalCache
++ // raw["total_rss"] = stats.Memory.TotalRSS
++ // raw["total_rss_huge"] = stats.Memory.TotalRSSHuge
++ // raw["total_mapped_file"] = stats.Memory.TotalMappedFile
++ // raw["total_dirty"] = stats.Memory.TotalDirty
++ // raw["total_writeback"] = stats.Memory.TotalWriteback
++ // raw["total_pgpgin"] = stats.Memory.TotalPgPgIn
++ // raw["total_pgpgout"] = stats.Memory.TotalPgPgOut
++ // raw["total_pgfault"] = stats.Memory.TotalPgFault
++ // raw["total_pgmajfault"] = stats.Memory.TotalPgMajFault
++ // raw["total_inactive_anon"] = stats.Memory.TotalInactiveAnon
++ // raw["total_active_anon"] = stats.Memory.TotalActiveAnon
++ // raw["total_inactive_file"] = stats.Memory.TotalInactiveFile
++ // raw["total_active_file"] = stats.Memory.TotalActiveFile
++ // raw["total_unevictable"] = stats.Memory.TotalUnevictable
+
+- if stats.Memory.Usage != nil {
+- s.MemoryStats = types.MemoryStats{
+- Stats: raw,
+- Usage: stats.Memory.Usage.Usage,
+- MaxUsage: stats.Memory.Usage.Max,
+- Limit: stats.Memory.Usage.Limit,
+- Failcnt: stats.Memory.Usage.Failcnt,
+- }
+- } else {
+- s.MemoryStats = types.MemoryStats{
+- Stats: raw,
+- }
+- }
++ // if stats.Memory.Usage != nil {
++ // s.MemoryStats = types.MemoryStats{
++ // Stats: raw,
++ // Usage: stats.Memory.Usage.Usage,
++ // MaxUsage: stats.Memory.Usage.Max,
++ // Limit: stats.Memory.Usage.Limit,
++ // Failcnt: stats.Memory.Usage.Failcnt,
++ // }
++ // } else {
++ // s.MemoryStats = types.MemoryStats{
++ // Stats: raw,
++ // }
++ // }
+
+- // if the container does not set memory limit, use the machineMemory
+- if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
+- s.MemoryStats.Limit = daemon.machineMemory
+- }
+- }
++ // // if the container does not set memory limit, use the machineMemory
++ // if s.MemoryStats.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
++ // s.MemoryStats.Limit = daemon.machineMemory
++ // }
++ // }
+
+- if stats.Pids != nil {
+- s.PidsStats = types.PidsStats{
+- Current: stats.Pids.Current,
+- Limit: stats.Pids.Limit,
+- }
+- }
++ // if stats.Pids != nil {
++ // s.PidsStats = types.PidsStats{
++ // Current: stats.Pids.Current,
++ // Limit: stats.Pids.Limit,
++ // }
++ // }
+
+ return s, nil
+ }
+@@ -1538,24 +1536,7 @@ func setMayDetachMounts() error {
+ }
+
+ func setupOOMScoreAdj(score int) error {
+- f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
+- if err != nil {
+- return err
+- }
+- defer f.Close()
+- stringScore := strconv.Itoa(score)
+- _, err = f.WriteString(stringScore)
+- if os.IsPermission(err) {
+- // Setting oom_score_adj does not work in an
+- // unprivileged container. Ignore the error, but log
+- // it if we appear not to be in that situation.
+- if !rsystem.RunningInUserNS() {
+- logrus.Debugf("Permission denied writing %q to /proc/self/oom_score_adj", stringScore)
+- }
+- return nil
+- }
+-
+- return err
++ return nil
+ }
+
+ func (daemon *Daemon) initCgroupsPath(path string) error {
+@@ -1571,7 +1552,10 @@ func (daemon *Daemon) initCgroupsPath(path string) err
+ // 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")
++ mnt := ""
++ root := ""
++ var err error = nil
++ //mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu")
+ if err != nil {
+ return err
+ }
Index: sysutils/docker-freebsd/files/patch-daemon_exec__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_exec__freebsd.go
@@ -0,0 +1,14 @@
+--- daemon/exec_freebsd.go.orig 2020-09-18 09:01:00 UTC
++++ daemon/exec_freebsd.go
+@@ -0,0 +1,11 @@
++package daemon
++
++import (
++ "github.com/docker/docker/container"
++ "github.com/docker/docker/daemon/exec"
++ specs "github.com/opencontainers/runtime-spec/specs-go"
++)
++
++func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config, p *specs.Process) error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-daemon_graphdriver_driver__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_graphdriver_driver__freebsd.go
@@ -0,0 +1,67 @@
+Fix build error on FreeBSD:
+
+daemon/graphdriver/driver_freebsd.go:17:38: cannot use &buf (type *unix.Statfs_t) as type *syscall.Statfs_t in argument to syscall.Statfs
+
+--- daemon/graphdriver/driver_freebsd.go.orig 2019-02-26 00:29:56 UTC
++++ daemon/graphdriver/driver_freebsd.go
+@@ -1,8 +1,7 @@
+ package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
+
+ import (
+- "syscall"
+-
++ "github.com/docker/docker/pkg/mount"
+ "golang.org/x/sys/unix"
+ )
+
+@@ -11,10 +10,49 @@ var (
+ priority = "zfs"
+ )
+
++// GetFSMagic returns the filesystem id given the path.
++func GetFSMagic(rootpath string) (FsMagic, error) {
++ var buf unix.Statfs_t
++ if err := unix.Statfs(rootpath, &buf); err != nil {
++ return 0, err
++ }
++ return FsMagic(buf.Type), nil
++}
++
++// NewFsChecker returns a checker configured for the provided FsMagic
++func NewFsChecker(t FsMagic) Checker {
++ return &fsChecker{
++ t: t,
++ }
++}
++
++type fsChecker struct {
++ t FsMagic
++}
++
++func (c *fsChecker) IsMounted(path string) bool {
++ m, _ := Mounted(c.t, path)
++ return m
++}
++
++// NewDefaultChecker returns a check that parses /proc/mountinfo to check
++// if the specified path is mounted.
++func NewDefaultChecker() Checker {
++ return &defaultChecker{}
++}
++
++type defaultChecker struct {
++}
++
++func (c *defaultChecker) IsMounted(path string) bool {
++ m, _ := mount.Mounted(path)
++ return m
++}
++
+ // Mounted checks if the given path is mounted as the fs type
+ func Mounted(fsType FsMagic, mountPath string) (bool, error) {
+ var buf unix.Statfs_t
+- if err := syscall.Statfs(mountPath, &buf); err != nil {
++ if err := unix.Statfs(mountPath, &buf); err != nil {
+ return false, err
+ }
+ return FsMagic(buf.Type) == fsType, nil
Index: sysutils/docker-freebsd/files/patch-daemon_graphdriver_zfs_zfs.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_graphdriver_zfs_zfs.go
@@ -0,0 +1,11 @@
+--- daemon/graphdriver/zfs/zfs.go.orig 2019-10-07 21:12:15 UTC
++++ daemon/graphdriver/zfs/zfs.go
+@@ -414,7 +414,7 @@ func (d *Driver) Put(id string) error {
+
+ logger.Debugf(`unmount("%s")`, mountpoint)
+
+- if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil {
++ if err := unix.Unmount(mountpoint, 0); err != nil {
+ logger.Warnf("Failed to unmount %s mount %s: %v", id, mountpoint, err)
+ }
+ if err := unix.Rmdir(mountpoint); err != nil && !os.IsNotExist(err) {
Index: sysutils/docker-freebsd/files/patch-daemon_inspect.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_inspect.go
@@ -0,0 +1,20 @@
+--- daemon/inspect.go.orig 2019-10-07 21:12:15 UTC
++++ daemon/inspect.go
+@@ -22,7 +22,7 @@ import (
+ func (daemon *Daemon) ContainerInspect(name string, size bool, version string) (interface{}, error) {
+ switch {
+ case versions.LessThan(version, "1.20"):
+- return daemon.containerInspectPre120(name)
++ return nil, errors.New("Port pre-1.20 not supported on freeBSD")
+ case versions.Equal(version, "1.20"):
+ return daemon.containerInspect120(name)
+ }
+@@ -135,7 +135,7 @@ func (daemon *Daemon) getInspectData(container *contai
+ }
+
+ // We merge the Ulimits from hostConfig with daemon default
+- daemon.mergeUlimits(&hostConfig)
++ // daemon.mergeUlimits(&hostConfig)
+
+ var containerHealth *types.Health
+ if container.State.Health != nil {
Index: sysutils/docker-freebsd/files/patch-daemon_inspect__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_inspect__freebsd.go
@@ -0,0 +1,76 @@
+--- daemon/inspect_freebsd.go.orig 2020-09-04 09:13:42 UTC
++++ daemon/inspect_freebsd.go
+@@ -0,0 +1,73 @@
++package daemon // import "github.com/docker/docker/daemon"
++
++import (
++ "github.com/docker/docker/api/types"
++ "github.com/docker/docker/api/types/backend"
++ "github.com/docker/docker/api/types/versions/v1p19"
++ "github.com/docker/docker/container"
++ "github.com/docker/docker/daemon/exec"
++)
++
++// This sets platform-specific fields
++func setPlatformSpecificContainerFields(container *container.Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
++ contJSONBase.AppArmorProfile = container.AppArmorProfile
++ contJSONBase.ResolvConfPath = container.ResolvConfPath
++ contJSONBase.HostnamePath = container.HostnamePath
++ contJSONBase.HostsPath = container.HostsPath
++
++ return contJSONBase
++}
++
++// containerInspectPre120 gets containers for pre 1.20 APIs.
++func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON, error) {
++ container, err := daemon.GetContainer(name)
++ if err != nil {
++ return nil, err
++ }
++
++ container.Lock()
++ defer container.Unlock()
++
++ base, err := daemon.getInspectData(container)
++ if err != nil {
++ return nil, err
++ }
++
++ volumes := make(map[string]string)
++ volumesRW := make(map[string]bool)
++ for _, m := range container.MountPoints {
++ volumes[m.Destination] = m.Path()
++ volumesRW[m.Destination] = m.RW
++ }
++
++ config := &v1p19.ContainerConfig{
++ Config: container.Config,
++ MacAddress: container.Config.MacAddress,
++ NetworkDisabled: container.Config.NetworkDisabled,
++ ExposedPorts: container.Config.ExposedPorts,
++ VolumeDriver: container.HostConfig.VolumeDriver,
++ Memory: container.HostConfig.Memory,
++ MemorySwap: container.HostConfig.MemorySwap,
++ CPUShares: container.HostConfig.CPUShares,
++ CPUSet: container.HostConfig.CpusetCpus,
++ }
++ networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
++
++ return &v1p19.ContainerJSON{
++ ContainerJSONBase: base,
++ Volumes: volumes,
++ VolumesRW: volumesRW,
++ Config: config,
++ NetworkSettings: networkSettings,
++ }, nil
++}
++
++func inspectExecProcessConfig(e *exec.Config) *backend.ExecProcessConfig {
++ return &backend.ExecProcessConfig{
++ Tty: e.Tty,
++ Entrypoint: e.Entrypoint,
++ Arguments: e.Args,
++ Privileged: &e.Privileged,
++ User: e.User,
++ }
++}
Index: sysutils/docker-freebsd/files/patch-daemon_listeners_listeners__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_listeners_listeners__freebsd.go
@@ -0,0 +1,110 @@
+--- daemon/listeners/listeners_freebsd.go.orig 2020-09-04 09:13:42 UTC
++++ daemon/listeners/listeners_freebsd.go
+@@ -0,0 +1,107 @@
++package listeners // import "github.com/docker/docker/daemon/listeners"
++
++import (
++ "crypto/tls"
++ "fmt"
++ "net"
++ "os"
++ "strconv"
++
++ "github.com/coreos/go-systemd/activation"
++ "github.com/docker/docker/pkg/homedir"
++ "github.com/docker/go-connections/sockets"
++ "github.com/sirupsen/logrus"
++)
++
++// Init creates new listeners for the server.
++// TODO: Clean up the fact that socketGroup and tlsConfig aren't always used.
++func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) ([]net.Listener, error) {
++ ls := []net.Listener{}
++
++ switch proto {
++ case "fd":
++ fds, err := listenFD(addr, tlsConfig)
++ if err != nil {
++ return nil, err
++ }
++ ls = append(ls, fds...)
++ case "tcp":
++ l, err := sockets.NewTCPSocket(addr, tlsConfig)
++ if err != nil {
++ return nil, err
++ }
++ ls = append(ls, l)
++ case "unix":
++ gid, err := lookupGID(socketGroup)
++ if err != nil {
++ if socketGroup != "" {
++ if socketGroup != defaultSocketGroup {
++ return nil, err
++ }
++ logrus.Warnf("could not change group %s to %s: %v", addr, defaultSocketGroup, err)
++ }
++ gid = os.Getgid()
++ }
++ l, err := sockets.NewUnixSocket(addr, gid)
++ if err != nil {
++ return nil, fmt.Errorf("can't create unix socket %s: %v", addr, err)
++ }
++ if _, err := homedir.StickRuntimeDirContents([]string{addr}); err != nil {
++ // StickRuntimeDirContents returns nil error if XDG_RUNTIME_DIR is just unset
++ logrus.WithError(err).Warnf("cannot set sticky bit on socket %s under XDG_RUNTIME_DIR", addr)
++ }
++ ls = append(ls, l)
++ default:
++ return nil, fmt.Errorf("invalid protocol format: %q", proto)
++ }
++
++ return ls, nil
++}
++
++// listenFD returns the specified socket activated files as a slice of
++// net.Listeners or all of the activated files if "*" is given.
++func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) {
++ var (
++ err error
++ listeners []net.Listener
++ )
++ // socket activation
++ if tlsConfig != nil {
++ listeners, err = activation.TLSListeners(tlsConfig)
++ } else {
++ listeners, err = activation.Listeners()
++ }
++ if err != nil {
++ return nil, err
++ }
++
++ if len(listeners) == 0 {
++ return nil, fmt.Errorf("no sockets found via socket activation: make sure the service was started by systemd")
++ }
++
++ // default to all fds just like unix:// and tcp://
++ if addr == "" || addr == "*" {
++ return listeners, nil
++ }
++
++ fdNum, err := strconv.Atoi(addr)
++ if err != nil {
++ return nil, fmt.Errorf("failed to parse systemd fd address: should be a number: %v", addr)
++ }
++ fdOffset := fdNum - 3
++ if len(listeners) < fdOffset+1 {
++ return nil, fmt.Errorf("too few socket activated files passed in by systemd")
++ }
++ if listeners[fdOffset] == nil {
++ return nil, fmt.Errorf("failed to listen on systemd activated file: fd %d", fdOffset+3)
++ }
++ for i, ls := range listeners {
++ if i == fdOffset || ls == nil {
++ continue
++ }
++ if err := ls.Close(); err != nil {
++ return nil, fmt.Errorf("failed to close systemd activated file: fd %d: %v", fdOffset+3, err)
++ }
++ }
++ return []net.Listener{listeners[fdOffset]}, nil
++}
Index: sysutils/docker-freebsd/files/patch-daemon_monitor__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_monitor__freebsd.go
@@ -0,0 +1,21 @@
+--- daemon/monitor_freebsd.go.orig 2020-09-04 14:57:27 UTC
++++ daemon/monitor_freebsd.go
+@@ -0,0 +1,18 @@
++package daemon
++
++import (
++ "github.com/docker/docker/container"
++ "github.com/docker/docker/libcontainerd/types"
++)
++
++// platformConstructExitStatus returns a platform specific exit status structure
++func platformConstructExitStatus(e types.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 types.StateInfo) error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-daemon_network.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_network.go
@@ -0,0 +1,17 @@
+--- daemon/network.go.orig 2020-09-04 14:54:50 UTC
++++ daemon/network.go
+@@ -796,10 +796,10 @@ func buildCreateEndpointOptions(c *container.Container
+
+ defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
+
+- if (!serviceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
+- c.NetworkSettings.IsAnonymousEndpoint {
+- createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
+- }
++ // if (!serviceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
++ // c.NetworkSettings.IsAnonymousEndpoint {
++ // createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
++ // }
+
+ if epConfig != nil {
+ ipam := epConfig.IPAMConfig
Index: sysutils/docker-freebsd/files/patch-daemon_oci__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_oci__freebsd.go
@@ -0,0 +1,77 @@
+--- daemon/oci_freebsd.go.orig 2020-09-18 09:01:00 UTC
++++ 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
++}
Index: sysutils/docker-freebsd/files/patch-daemon_stats_collector__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_stats_collector__unix.go
@@ -0,0 +1,30 @@
+--- daemon/stats/collector_unix.go.orig 2019-10-07 21:12:15 UTC
++++ daemon/stats/collector_unix.go
+@@ -7,15 +7,11 @@ import (
+ "os"
+ "strconv"
+ "strings"
+-
+- "github.com/opencontainers/runc/libcontainer/system"
+- "golang.org/x/sys/unix"
+ )
+
+ // platformNewStatsCollector performs platform specific initialisation of the
+ // Collector structure.
+ func platformNewStatsCollector(s *Collector) {
+- s.clockTicksPerSecond = uint64(system.GetClockTicks())
+ }
+
+ const nanoSecondsPerSecond = 1e9
+@@ -66,10 +62,5 @@ func (s *Collector) getSystemCPUUsage() (uint64, error
+ }
+
+ func (s *Collector) getNumberOnlineCPUs() (uint32, error) {
+- var cpuset unix.CPUSet
+- err := unix.SchedGetaffinity(0, &cpuset)
+- if err != nil {
+- return 0, err
+- }
+- return uint32(cpuset.Count()), nil
++ return 0, nil
+ }
Index: sysutils/docker-freebsd/files/patch-daemon_update__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_update__freebsd.go
@@ -0,0 +1,14 @@
+--- daemon/update_freebsd.go.orig 2020-09-18 09:01:00 UTC
++++ daemon/update_freebsd.go
+@@ -0,0 +1,11 @@
++package daemon
++
++import (
++ "github.com/docker/docker/api/types/container"
++ libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
++)
++
++func toContainerdResources(resources container.Resources) *libcontainerdtypes.Resources {
++ var r *libcontainerdtypes.Resources
++ return r
++}
Index: sysutils/docker-freebsd/files/patch-daemon_volumes__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-daemon_volumes__freebsd.go
@@ -0,0 +1,12 @@
+--- daemon/volumes_freebsd.go.orig 2020-09-04 09:13:42 UTC
++++ daemon/volumes_freebsd.go
+@@ -0,0 +1,9 @@
++package daemon // import "github.com/docker/docker/daemon"
++
++import (
++ "github.com/docker/docker/api/types/mount"
++)
++
++func (daemon *Daemon) validateBindDaemonRoot(m mount.Mount) (bool, error) {
++ return false, nil
++}
Index: sysutils/docker-freebsd/files/patch-hack_make.sh
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-hack_make.sh
@@ -0,0 +1,19 @@
+--- hack/make.sh.orig 2020-09-18 09:00:53 UTC
++++ hack/make.sh
+@@ -120,7 +120,6 @@ BUILDFLAGS=( ${BUILDFLAGS} "${ORIG_BUILDFLAGS[@]}" )
+
+ LDFLAGS_STATIC_DOCKER="
+ $LDFLAGS_STATIC
+- -extldflags \"$EXTLDFLAGS_STATIC\"
+ "
+
+ if [ "$(uname -s)" = 'FreeBSD' ]; then
+@@ -130,7 +129,7 @@ if [ "$(uname -s)" = 'FreeBSD' ]; then
+
+ # "-extld clang" is a workaround for
+ # https://code.google.com/p/go/issues/detail?id=6845
+- LDFLAGS="$LDFLAGS -extld clang"
++ LDFLAGS="$LDFLAGS -extld clang -extldflags -Wl,-z,notext"
+ fi
+
+ bundle() {
Index: sysutils/docker-freebsd/files/patch-libcontainerd_libcontainerd__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_libcontainerd__freebsd.go
@@ -0,0 +1,19 @@
+This is a copy from libcontainerd_linux.go
+
+--- libcontainerd/libcontainerd_freebsd.go.orig 2019-06-24 09:47:19 UTC
++++ libcontainerd/libcontainerd_freebsd.go
+@@ -0,0 +1,14 @@
++package libcontainerd // import "github.com/docker/docker/libcontainerd"
++
++import (
++ "context"
++
++ "github.com/containerd/containerd"
++ "github.com/docker/docker/libcontainerd/remote"
++ libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
++)
++
++// NewClient creates a new libcontainerd client from a containerd client
++func NewClient(ctx context.Context, cli *containerd.Client, stateDir, ns string, b libcontainerdtypes.Backend) (libcontainerdtypes.Client, error) {
++ return remote.NewClient(ctx, cli, stateDir, ns, b)
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_oom__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_oom__unix.go
@@ -0,0 +1,10 @@
+--- libcontainerd/oom_unix.go.orig 2020-09-04 14:57:27 UTC
++++ libcontainerd/oom_unix.go
+@@ -0,0 +1,7 @@
++// +build solaris,freebsd +build !linux
++
++package libcontainerd
++
++func setOOMScore(pid, score int) error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_remote_client__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_remote_client__freebsd.go
@@ -0,0 +1,129 @@
+--- libcontainerd/remote/client_freebsd.go.orig 2019-06-24 18:09:27 UTC
++++ libcontainerd/remote/client_freebsd.go
+@@ -0,0 +1,126 @@
++package remote // import "github.com/docker/docker/libcontainerd/remote"
++
++import (
++ "context"
++ "fmt"
++ "os"
++ "path/filepath"
++ "strings"
++
++ "github.com/containerd/containerd"
++ "github.com/containerd/containerd/cio"
++ "github.com/containerd/containerd/containers"
++ libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
++ "github.com/docker/docker/pkg/idtools"
++ "github.com/opencontainers/runtime-spec/specs-go"
++ "github.com/sirupsen/logrus"
++)
++
++const runtimeName = "io.containerd.runtime.v1.linux"
++
++func summaryFromInterface(i interface{}) (*libcontainerdtypes.Summary, error) {
++ return &libcontainerdtypes.Summary{}, nil
++}
++
++func (c *client) UpdateResources(ctx context.Context, containerID string, resources *libcontainerdtypes.Resources) error {
++ p, err := c.getProcess(ctx, containerID, libcontainerdtypes.InitProcessName)
++ if err != nil {
++ return err
++ }
++
++ // go doesn't like the alias in 1.8, this means this need to be
++ // platform specific
++ return p.(containerd.Task).Update(ctx, containerd.WithResources((*specs.LinuxResources)(resources)))
++}
++
++func hostIDFromMap(id uint32, mp []specs.LinuxIDMapping) int {
++ for _, m := range mp {
++ if id >= m.ContainerID && id <= m.ContainerID+m.Size-1 {
++ return int(m.HostID + id - m.ContainerID)
++ }
++ }
++ return 0
++}
++
++func getSpecUser(ociSpec *specs.Spec) (int, int) {
++ var (
++ uid int
++ gid int
++ )
++
++ for _, ns := range ociSpec.Linux.Namespaces {
++ if ns.Type == specs.UserNamespace {
++ uid = hostIDFromMap(0, ociSpec.Linux.UIDMappings)
++ gid = hostIDFromMap(0, ociSpec.Linux.GIDMappings)
++ break
++ }
++ }
++
++ return uid, gid
++}
++
++// WithBundle creates the bundle for the container
++func WithBundle(bundleDir string, ociSpec *specs.Spec) containerd.NewContainerOpts {
++ return func(ctx context.Context, client *containerd.Client, c *containers.Container) error {
++ if c.Labels == nil {
++ c.Labels = make(map[string]string)
++ }
++ uid, gid := getSpecUser(ociSpec)
++ if uid == 0 && gid == 0 {
++ c.Labels[DockerContainerBundlePath] = bundleDir
++ return idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
++ }
++
++ p := string(filepath.Separator)
++ components := strings.Split(bundleDir, string(filepath.Separator))
++ for _, d := range components[1:] {
++ p = filepath.Join(p, d)
++ fi, err := os.Stat(p)
++ if err != nil && !os.IsNotExist(err) {
++ return err
++ }
++ if os.IsNotExist(err) || fi.Mode()&1 == 0 {
++ p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
++ if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
++ return err
++ }
++ }
++ }
++ if c.Labels == nil {
++ c.Labels = make(map[string]string)
++ }
++ c.Labels[DockerContainerBundlePath] = p
++ return nil
++ }
++}
++
++func newFIFOSet(bundleDir, processID string, withStdin, withTerminal bool) *cio.FIFOSet {
++ config := cio.Config{
++ Terminal: withTerminal,
++ Stdout: filepath.Join(bundleDir, processID+"-stdout"),
++ }
++ paths := []string{config.Stdout}
++
++ if withStdin {
++ config.Stdin = filepath.Join(bundleDir, processID+"-stdin")
++ paths = append(paths, config.Stdin)
++ }
++ if !withTerminal {
++ config.Stderr = filepath.Join(bundleDir, processID+"-stderr")
++ paths = append(paths, config.Stderr)
++ }
++ closer := func() error {
++ for _, path := range paths {
++ if err := os.RemoveAll(path); err != nil {
++ logrus.Warnf("libcontainerd: failed to remove fifo %v: %v", path, err)
++ }
++ }
++ return nil
++ }
++
++ return cio.NewFIFOSet(config, closer)
++}
++
++func (c *client) newDirectIO(ctx context.Context, fifos *cio.FIFOSet) (*cio.DirectIO, error) {
++ return cio.NewDirectIO(ctx, fifos)
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_remote__daemon__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_remote__daemon__freebsd.go
@@ -0,0 +1,72 @@
+--- libcontainerd/supervisor/remote_daemon_freebsd.go.orig 2019-06-24 18:36:48 UTC
++++ libcontainerd/supervisor/remote_daemon_freebsd.go
+@@ -0,0 +1,69 @@
++package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"
++
++import (
++ "os"
++ "path/filepath"
++ "syscall"
++ "time"
++
++ "github.com/containerd/containerd/defaults"
++ "github.com/docker/docker/pkg/system"
++)
++
++const (
++ sockFile = "containerd.sock"
++ debugSockFile = "containerd-debug.sock"
++)
++
++func (r *remote) setDefaults() {
++ if r.GRPC.Address == "" {
++ r.GRPC.Address = filepath.Join(r.stateDir, sockFile)
++ }
++ if r.GRPC.MaxRecvMsgSize == 0 {
++ r.GRPC.MaxRecvMsgSize = defaults.DefaultMaxRecvMsgSize
++ }
++ if r.GRPC.MaxSendMsgSize == 0 {
++ r.GRPC.MaxSendMsgSize = defaults.DefaultMaxSendMsgSize
++ }
++ if r.Debug.Address == "" {
++ r.Debug.Address = filepath.Join(r.stateDir, debugSockFile)
++ }
++ if r.OOMScore == 0 {
++ r.OOMScore = -999
++ }
++
++ for key, conf := range r.pluginConfs.Plugins {
++ if conf == nil {
++ r.DisabledPlugins = append(r.DisabledPlugins, key)
++ delete(r.pluginConfs.Plugins, key)
++ }
++ }
++}
++
++func (r *remote) stopDaemon() {
++ // Ask the daemon to quit
++ syscall.Kill(r.daemonPid, syscall.SIGTERM)
++ // Wait up to 15secs for it to stop
++ for i := time.Duration(0); i < shutdownTimeout; i += time.Second {
++ if !system.IsProcessAlive(r.daemonPid) {
++ break
++ }
++ time.Sleep(time.Second)
++ }
++
++ if system.IsProcessAlive(r.daemonPid) {
++ r.logger.WithField("pid", r.daemonPid).Warn("daemon didn't stop within 15 secs, killing it")
++ syscall.Kill(r.daemonPid, syscall.SIGKILL)
++ }
++}
++
++func (r *remote) killDaemon() {
++ // Try to get a stack trace
++ syscall.Kill(r.daemonPid, syscall.SIGUSR1)
++ <-time.After(100 * time.Millisecond)
++ system.KillProcess(r.daemonPid)
++}
++
++func (r *remote) platformCleanup() {
++ os.Remove(filepath.Join(r.stateDir, sockFile))
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_remote__daemon__options__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_remote__daemon__options__freebsd.go
@@ -0,0 +1,12 @@
+--- libcontainerd/supervisor/remote_daemon_options_freebsd.go.orig 2020-09-04 09:13:43 UTC
++++ libcontainerd/supervisor/remote_daemon_options_freebsd.go
+@@ -0,0 +1,9 @@
++package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"
++
++// WithOOMScore defines the oom_score_adj to set for the containerd process.
++func WithOOMScore(score int) DaemonOpt {
++ return func(r *remote) error {
++ r.OOMScore = score
++ return nil
++ }
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_utils__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_supervisor_utils__freebsd.go
@@ -0,0 +1,14 @@
+--- libcontainerd/supervisor/utils_freebsd.go.orig 2019-06-24 18:38:41 UTC
++++ libcontainerd/supervisor/utils_freebsd.go
+@@ -0,0 +1,11 @@
++package supervisor // import "github.com/docker/docker/libcontainerd/supervisor"
++
++import "syscall"
++
++// containerdSysProcAttr returns the SysProcAttr to use when exec'ing
++// containerd
++func containerdSysProcAttr() *syscall.SysProcAttr {
++ return &syscall.SysProcAttr{
++ Setsid: true,
++ }
++}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_types_types__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_types_types__freebsd.go
@@ -0,0 +1,36 @@
+--- libcontainerd/types/types_freebsd.go.orig 2020-09-04 14:57:27 UTC
++++ libcontainerd/types/types_freebsd.go
+@@ -0,0 +1,33 @@
++package types
++
++import (
++ "time"
++
++ "github.com/opencontainers/runtime-spec/specs-go"
++)
++
++// Summary is not used on FreeBSD
++type Summary struct{}
++
++// Stats holds metrics properties as returned by containerd
++type Stats struct {}
++
++// InterfaceToStats returns a stats object from the platform-specific interface.
++func InterfaceToStats(read time.Time, v interface{}) *Stats {
++ return &Stats{}
++}
++
++// StateInfo contains description about the new state container has entered.
++type StateInfo struct {
++ //CommonStateInfo
++
++ // Platform specific StateInfo
++ OOMKilled bool
++ ExitCode int
++}
++
++// Resources defines updatable container resource values. TODO: it must match containerd upcoming API
++type Resources specs.LinuxResources
++
++// Checkpoints contains the details of a checkpoint
++type Checkpoints struct{}
Index: sysutils/docker-freebsd/files/patch-libcontainerd_utils__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-libcontainerd_utils__unix.go
@@ -0,0 +1,21 @@
+--- libcontainerd/utils_unix.go.orig 2020-09-04 14:57:27 UTC
++++ libcontainerd/utils_unix.go
+@@ -0,0 +1,18 @@
++// +build solaris,freebsd +build !linux
++
++package libcontainerd
++
++import (
++ "syscall"
++
++ "github.com/opencontainers/runtime-spec/specs-go"
++)
++
++func getRootIDs(s specs.Spec) (int, int, error) {
++ return 0, 0, nil
++}
++
++// setPDeathSig sets the parent death signal to SIGKILL
++func setSysProcAttr(sid bool) *syscall.SysProcAttr {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-pkg_archive_archive__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_archive_archive__unix.go
@@ -0,0 +1,11 @@
+--- pkg/archive/archive_unix.go.orig 2019-06-24 10:21:29 UTC
++++ pkg/archive/archive_unix.go
+@@ -96,7 +96,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path
+ mode |= unix.S_IFIFO
+ }
+
+- return system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
++ return system.Mknod(path, mode, uint64(system.Mkdev(hdr.Devmajor, hdr.Devminor)))
+ }
+
+ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
Index: sysutils/docker-freebsd/files/patch-pkg_archive_changes__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_archive_changes__unix.go
@@ -0,0 +1,11 @@
+--- pkg/archive/changes_unix.go.orig 2019-06-18 21:30:11 UTC
++++ pkg/archive/changes_unix.go
+@@ -35,7 +35,7 @@ func (info *FileInfo) isDir() bool {
+ }
+
+ func getIno(fi os.FileInfo) uint64 {
+- return fi.Sys().(*syscall.Stat_t).Ino
++ return uint64(fi.Sys().(*syscall.Stat_t).Ino)
+ }
+
+ func hasHardlinks(fi os.FileInfo) bool {
Index: sysutils/docker-freebsd/files/patch-pkg_mount_mountinfo__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_mount_mountinfo__freebsd.go
@@ -0,0 +1,11 @@
+--- pkg/mount/mountinfo_freebsd.go.orig 2019-02-06 23:39:49 UTC
++++ pkg/mount/mountinfo_freebsd.go
+@@ -37,7 +37,7 @@ func parseMountTable(filter FilterFunc) ([]*Info, erro
+
+ if filter != nil {
+ // filter out entries we're not interested in
+- skip, stop = filter(p)
++ skip, stop = filter(&mountinfo)
+ if skip {
+ continue
+ }
Index: sysutils/docker-freebsd/files/patch-pkg_mount_sharedsubtree__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_mount_sharedsubtree__freebsd.go
@@ -0,0 +1,70 @@
+--- pkg/mount/sharedsubtree_freebsd.go.orig 2020-09-04 14:57:27 UTC
++++ 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)
++}
Index: sysutils/docker-freebsd/files/patch-pkg_parsers_operatingsystem_operatingsystem__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_parsers_operatingsystem_operatingsystem__freebsd.go
@@ -0,0 +1,34 @@
+--- pkg/parsers/operatingsystem/operatingsystem_freebsd.go.orig 2020-09-04 14:57:27 UTC
++++ pkg/parsers/operatingsystem/operatingsystem_freebsd.go
+@@ -0,0 +1,31 @@
++// +build freebsd
++
++package operatingsystem
++
++import (
++ "errors"
++ "os/exec"
++ "syscall"
++)
++
++// GetOperatingSystem gets the name of the current operating system.
++func GetOperatingSystem() (string, error) {
++ cmd := exec.Command("uname", "-s")
++ osName, err := cmd.Output()
++ if err != nil {
++ return "", err
++ }
++ return string(osName), nil
++}
++
++// IsContainerized returns true if we are running inside a container.
++func IsContainerized() (bool, error) {
++ jailed, err := syscall.Sysctl("security.jail.jailed")
++ if err != nil {
++ return false, errors.New("Cannot detect if we are in a jail")
++ }
++ if jailed[0] == 1 {
++ return true, nil
++ }
++ return false, nil
++}
Index: sysutils/docker-freebsd/files/patch-pkg_parsers_operatingsystem_operatingsystem__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_parsers_operatingsystem_operatingsystem__unix.go
@@ -0,0 +1,15 @@
+--- pkg/parsers/operatingsystem/operatingsystem_unix.go.orig 2020-09-04 14:54:52 UTC
++++ pkg/parsers/operatingsystem/operatingsystem_unix.go
+@@ -1,4 +1,4 @@
+-// +build freebsd darwin
++// +build darwin
+
+ package operatingsystem // import "github.com/docker/docker/pkg/parsers/operatingsystem"
+
+@@ -20,6 +20,5 @@ func GetOperatingSystem() (string, error) {
+ // IsContainerized returns true if we are running inside a container.
+ // No-op on FreeBSD and Darwin, always returns false.
+ func IsContainerized() (bool, error) {
+- // TODO: Implement jail detection for freeBSD
+ return false, errors.New("Cannot detect if we are in container")
+ }
Index: sysutils/docker-freebsd/files/patch-pkg_system_mknod.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-pkg_system_mknod.go
@@ -0,0 +1,11 @@
+--- pkg/system/mknod.go.orig 2019-06-18 21:30:11 UTC
++++ pkg/system/mknod.go
+@@ -8,7 +8,7 @@ import (
+
+ // Mknod creates a filesystem node (file, device special file or named pipe) named path
+ // with attributes specified by mode and dev.
+-func Mknod(path string, mode uint32, dev int) error {
++func Mknod(path string, mode uint32, dev uint64) error {
+ return unix.Mknod(path, mode, dev)
+ }
+
Index: sysutils/docker-freebsd/files/patch-plugin_manager__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-plugin_manager__freebsd.go
@@ -0,0 +1,33 @@
+Fix build on FreeBSD by copying Windows stub
+
+--- plugin/manager_freebsd.go.orig 2019-03-08 09:00:07 UTC
++++ plugin/manager_freebsd.go
+@@ -0,0 +1,28 @@
++package plugin // import "github.com/docker/docker/plugin"
++
++import (
++ "fmt"
++
++ "github.com/docker/docker/plugin/v2"
++ specs "github.com/opencontainers/runtime-spec/specs-go"
++)
++
++func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
++ return fmt.Errorf("Not implemented")
++}
++
++func (pm *Manager) initSpec(p *v2.Plugin) (*specs.Spec, error) {
++ return nil, fmt.Errorf("Not implemented")
++}
++
++func (pm *Manager) disable(p *v2.Plugin, c *controller) error {
++ return fmt.Errorf("Not implemented")
++}
++
++func (pm *Manager) restore(p *v2.Plugin, c *controller) error {
++ return fmt.Errorf("Not implemented")
++}
++
++// Shutdown plugins
++func (pm *Manager) Shutdown() {
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_cgroups_memory.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_cgroups_memory.go
@@ -0,0 +1,11 @@
+--- vendor/github.com/containerd/cgroups/memory.go.orig 2020-09-18 09:00:55 UTC
++++ vendor/github.com/containerd/cgroups/memory.go
+@@ -208,7 +208,7 @@ func (m *memoryController) OOMEventFD(path string) (ui
+ return 0, err
+ }
+ defer f.Close()
+- fd, _, serr := unix.RawSyscall(unix.SYS_EVENTFD2, 0, unix.EFD_CLOEXEC, 0)
++ fd, _, serr := unix.RawSyscall(0, 0, 0, 0)//unix.RawSyscall(unix.SYS_EVENTFD2, 0, unix.EFD_CLOEXEC, 0)
+ if serr != 0 {
+ return 0, serr
+ }
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_archive_tar__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_archive_tar__unix.go
@@ -0,0 +1,11 @@
+--- vendor/github.com/containerd/containerd/archive/tar_unix.go.orig 2019-06-18 21:30:11 UTC
++++ vendor/github.com/containerd/containerd/archive/tar_unix.go
+@@ -122,7 +122,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path
+ mode |= unix.S_IFIFO
+ }
+
+- return unix.Mknod(path, mode, int(unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor))))
++ return unix.Mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))
+ }
+
+ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_bundle.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_bundle.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/containerd/containerd/runtime/v1/linux/bundle.go.orig 2019-02-26 21:02:47 UTC
++++ vendor/github.com/containerd/containerd/runtime/v1/linux/bundle.go
+@@ -1,4 +1,4 @@
+-// +build linux
++// +build linux freebsd
+
+ /*
+ Copyright The containerd Authors.
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_process.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_process.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/containerd/containerd/runtime/v1/linux/process.go.orig 2019-02-06 23:39:49 UTC
++++ vendor/github.com/containerd/containerd/runtime/v1/linux/process.go
+@@ -1,4 +1,4 @@
+-// +build linux
++// +build linux freebsd
+
+ /*
+ Copyright The containerd Authors.
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_runtime.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_runtime.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go.orig 2019-02-06 23:39:49 UTC
++++ vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go
+@@ -1,4 +1,4 @@
+-// +build linux
++// +build linux freebsd
+
+ /*
+ Copyright The containerd Authors.
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_task.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_containerd_runtime_v1_linux_task.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/containerd/containerd/runtime/v1/linux/task.go.orig 2019-02-06 23:39:49 UTC
++++ vendor/github.com/containerd/containerd/runtime/v1/linux/task.go
+@@ -1,4 +1,4 @@
+-// +build linux
++// +build linux freebsd
+
+ /*
+ Copyright The containerd Authors.
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_continuity_devices_devices__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_continuity_devices_devices__unix.go
@@ -0,0 +1,11 @@
+--- vendor/github.com/containerd/continuity/devices/devices_unix.go.orig 2019-06-18 21:30:11 UTC
++++ vendor/github.com/containerd/continuity/devices/devices_unix.go
+@@ -55,7 +55,7 @@ func Mknod(p string, mode os.FileMode, maj, min int) e
+ m |= unix.S_IFIFO
+ }
+
+- return unix.Mknod(p, m, int(dev))
++ return unix.Mknod(p, m, dev)
+ }
+
+ // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_continuity_fs_copy__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_containerd_continuity_fs_copy__unix.go
@@ -0,0 +1,9 @@
+--- vendor/github.com/containerd/continuity/fs/copy_unix.go.orig 2019-06-18 21:30:11 UTC
++++ vendor/github.com/containerd/continuity/fs/copy_unix.go
+@@ -108,5 +108,5 @@ func copyDevice(dst string, fi os.FileInfo) error {
+ if !ok {
+ return errors.New("unsupported stat type")
+ }
+- return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
++ return unix.Mknod(dst, uint32(fi.Mode()), st.Rdev)
+ }
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers__freebsd.go
@@ -0,0 +1,17 @@
+--- vendor/github.com/docker/libnetwork/drivers_freebsd.go.orig 2020-09-04 14:54:57 UTC
++++ 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"},
+ }
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_bridge.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_bridge.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_bridge__store.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_bridge__store.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/bridge_store.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_interface.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_interface.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/interface.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/interface.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_link.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_link.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/link.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/link.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_port__mapping.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_port__mapping.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ type setupStep func(*networkConfiguration, *bridgeInterface) error
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__bridgenetfiltering.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__bridgenetfiltering.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__device.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__device.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_device.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__firewalld.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__firewalld.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import "github.com/docker/libnetwork/iptables"
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ip__tables.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ip__tables.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ipv4.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ipv4.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ipv6.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__ipv6.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__verify.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_bridge_setup__verify.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/drivers/bridge/setup_verify.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package bridge
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_bridge.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_bridge.go
@@ -0,0 +1,1097 @@
+--- vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge.go.orig 2020-09-04 14:57:27 UTC
++++ 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
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_bridge__store.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_bridge__store.go
@@ -0,0 +1,387 @@
+--- vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/bridge_store.go.orig 2020-09-04 14:57:27 UTC
++++ 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
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_errors.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_errors.go
@@ -0,0 +1,123 @@
+--- vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/errors.go.orig 2020-09-04 14:57:27 UTC
++++ 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() {}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_port__mapping.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_drivers_freebsd_bridge_port__mapping.go
@@ -0,0 +1,238 @@
+--- vendor/github.com/docker/libnetwork/drivers/freebsd/bridge/port_mapping.go.orig 2020-09-04 14:57:27 UTC
++++ 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
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_iptables_conntrack.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_iptables_conntrack.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/iptables/conntrack.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/iptables/conntrack.go
+@@ -1,3 +1,5 @@
++// +build !freebsd
++
+ package iptables
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_netutils_utils__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_netutils_utils__freebsd.go
@@ -0,0 +1,96 @@
+--- vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go.orig 2020-10-23 18:37:21 UTC
++++ vendor/github.com/docker/libnetwork/netutils/utils_freebsd.go
+@@ -1,9 +1,15 @@
+ package netutils
+
+ import (
++ "fmt"
+ "net"
++ "os/exec"
++ "strings"
+
+- "github.com/docker/libnetwork/types"
++ "github.com/docker/libnetwork/ipamutils"
++ "github.com/docker/libnetwork/ns"
++ "github.com/docker/libnetwork/osl"
++ "github.com/pkg/errors"
+ )
+
+ // ElectInterfaceAddresses looks for an interface on the OS with the specified name
+@@ -13,11 +19,74 @@ import (
+ // list the first IPv4 address which does not conflict with other
+ // interfaces on the system.
+ func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
+- return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
++ var (
++ v4Nets []*net.IPNet
++ v6Nets []*net.IPNet
++ )
++
++ defer osl.InitOSContext()()
++
++ link, _ := ns.NlHandle().LinkByName(name)
++ // disabled on freebsd for now
++ // if link != nil {
++ // v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
++ // if err != nil {
++ // return nil, nil, err
++ // }
++ // v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
++ // if err != nil {
++ // return nil, nil, err
++ // }
++ // for _, nlAddr := range v4addr {
++ // v4Nets = append(v4Nets, nlAddr.IPNet)
++ // }
++ // for _, nlAddr := range v6addr {
++ // v6Nets = append(v6Nets, nlAddr.IPNet)
++ // }
++ // }
++
++ if link == nil || len(v4Nets) == 0 {
++ // Choose from predefined local scope networks
++ v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
++ if err != nil {
++ return nil, nil, errors.Wrapf(err, "PredefinedLocalScopeDefaultNetworks List: %+v",
++ ipamutils.PredefinedLocalScopeDefaultNetworks)
++ }
++ v4Nets = append(v4Nets, v4Net)
++ }
++
++ return v4Nets, v6Nets, nil
+ }
+
+ // 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")
+ }
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_ns_init__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_ns_init__freebsd.go
@@ -0,0 +1,100 @@
+--- vendor/github.com/docker/libnetwork/ns/init_freebsd.go.orig 2020-10-23 18:37:27 UTC
++++ vendor/github.com/docker/libnetwork/ns/init_freebsd.go
+@@ -0,0 +1,97 @@
++package ns
++
++import (
++ "fmt"
++ "os/exec"
++ "strings"
++ "sync"
++ "time"
++
++ "github.com/sirupsen/logrus"
++ "github.com/vishvananda/netlink"
++ "github.com/vishvananda/netns"
++)
++
++var (
++ initNs netns.NsHandle
++ initNl *netlink.Handle
++ initOnce sync.Once
++ // NetlinkSocketsTimeout represents the default timeout duration for the sockets
++ NetlinkSocketsTimeout = 3 * time.Second
++)
++
++// Init initializes a new network namespace
++func Init() {
++ var err error
++ initNs, err = netns.Get()
++ if err != nil {
++ logrus.Errorf("could not get initial namespace: %v", err)
++ }
++ initNl, err = netlink.NewHandle(getSupportedNlFamilies()...)
++ if err != nil {
++ logrus.Errorf("could not create netlink handle on initial namespace: %v", err)
++ }
++ err = initNl.SetSocketTimeout(NetlinkSocketsTimeout)
++ if err != nil {
++ logrus.Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err)
++ }
++}
++
++// SetNamespace sets the initial namespace handler
++func SetNamespace() error {
++ initOnce.Do(Init)
++ if err := netns.Set(initNs); err != nil {
++ linkInfo, linkErr := getLink()
++ if linkErr != nil {
++ linkInfo = linkErr.Error()
++ }
++ return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err)
++ }
++ return nil
++}
++
++// ParseHandlerInt transforms the namespace handler into an integer
++func ParseHandlerInt() int {
++ return int(getHandler())
++}
++
++// GetHandler returns the namespace handler
++func getHandler() netns.NsHandle {
++ initOnce.Do(Init)
++ return initNs
++}
++
++func getLink() (string, error) {
++ return "", fmt.Errorf("getLink not implemented on freebsd")
++}
++
++// NlHandle returns the netlink handler
++func NlHandle() *netlink.Handle {
++ initOnce.Do(Init)
++ return initNl
++}
++
++func getSupportedNlFamilies() []int {
++ // not implemented on freebsd
++ return []int{}
++}
++
++// API check on required xfrm modules (xfrm_user, xfrm_algo)
++func checkXfrmSocket() error {
++ return fmt.Errorf("checkXfrmSocket not implemented on freebsd")
++}
++
++func loadNfConntrackModules() error {
++ if out, err := exec.Command("modprobe", "-va", "nf_conntrack").CombinedOutput(); err != nil {
++ return fmt.Errorf("Running modprobe nf_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
++ }
++ if out, err := exec.Command("modprobe", "-va", "nf_conntrack_netlink").CombinedOutput(); err != nil {
++ return fmt.Errorf("Running modprobe nf_conntrack_netlink failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
++ }
++ return nil
++}
++
++// API check on required nf_conntrack* modules (nf_conntrack, nf_conntrack_netlink)
++func checkNfSocket() error {
++ return fmt.Errorf("checkNfSocket not implemented on freebsd")
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_ns_init__unspecified.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_ns_init__unspecified.go
@@ -0,0 +1,4 @@
+--- vendor/github.com/docker/libnetwork/ns/init_unspecified.go.orig 2020-09-04 14:57:27 UTC
++++ vendor/github.com/docker/libnetwork/ns/init_unspecified.go
+@@ -0,0 +1 @@
++package ns
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_mapper__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_mapper__freebsd.go
@@ -0,0 +1,34 @@
+--- vendor/github.com/docker/libnetwork/portmapper/mapper_freebsd.go.orig 2019-06-24 18:33:51 UTC
++++ vendor/github.com/docker/libnetwork/portmapper/mapper_freebsd.go
+@@ -0,0 +1,31 @@
++package portmapper
++
++import (
++ "net"
++ "sync"
++
++ "github.com/docker/libnetwork/portallocator"
++)
++
++// PortMapper manages the network address translation
++type PortMapper struct {
++ bridgeName string
++
++ // udp:ip:port
++ currentMappings map[string]*mapping
++ lock sync.Mutex
++
++ proxyPath string
++
++ Allocator *portallocator.PortAllocator
++}
++
++// AppendForwardingTableEntry adds a port mapping to the forwarding table
++func (pm *PortMapper) AppendForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
++ return nil
++}
++
++// DeleteForwardingTableEntry removes a port mapping from the forwarding table
++func (pm *PortMapper) DeleteForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_proxy__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_proxy__freebsd.go
@@ -0,0 +1,41 @@
+--- vendor/github.com/docker/libnetwork/portmapper/proxy_freebsd.go.orig 2019-06-24 18:17:46 UTC
++++ vendor/github.com/docker/libnetwork/portmapper/proxy_freebsd.go
+@@ -0,0 +1,38 @@
++package portmapper
++
++import (
++ "net"
++ "os/exec"
++ "strconv"
++ "syscall"
++)
++
++func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
++ path := proxyPath
++ if proxyPath == "" {
++ cmd, err := exec.LookPath(userlandProxyCommandName)
++ if err != nil {
++ return nil, err
++ }
++ path = cmd
++ }
++
++ args := []string{
++ path,
++ "-proto", proto,
++ "-host-ip", hostIP.String(),
++ "-host-port", strconv.Itoa(hostPort),
++ "-container-ip", containerIP.String(),
++ "-container-port", strconv.Itoa(containerPort),
++ }
++
++ return &proxyCommand{
++ cmd: &exec.Cmd{
++ Path: path,
++ Args: args,
++ SysProcAttr: &syscall.SysProcAttr{
++ Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
++ },
++ },
++ }, nil
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_proxy__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_portmapper_proxy__unix.go
@@ -0,0 +1,39 @@
+--- vendor/github.com/docker/libnetwork/portmapper/proxy_unix.go.orig 2020-09-04 14:57:27 UTC
++++ vendor/github.com/docker/libnetwork/portmapper/proxy_unix.go
+@@ -0,0 +1,36 @@
++// +build solaris,freebsd +build !linux
++
++package portmapper
++
++import (
++ "net"
++ "os/exec"
++ "strconv"
++)
++
++func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
++ path := proxyPath
++ if proxyPath == "" {
++ cmd, err := exec.LookPath(userlandProxyCommandName)
++ if err != nil {
++ return nil, err
++ }
++ path = cmd
++ }
++
++ args := []string{
++ path,
++ "-proto", proto,
++ "-host-ip", hostIP.String(),
++ "-host-port", strconv.Itoa(hostPort),
++ "-container-ip", containerIP.String(),
++ "-container-port", strconv.Itoa(containerPort),
++ }
++
++ return &proxyCommand{
++ cmd: &exec.Cmd{
++ Path: path,
++ Args: args,
++ },
++ }, nil
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_resolver__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_resolver__freebsd.go
@@ -0,0 +1,9 @@
+--- vendor/github.com/docker/libnetwork/resolver_freebsd.go.orig 2020-09-18 09:01:00 UTC
++++ vendor/github.com/docker/libnetwork/resolver_freebsd.go
+@@ -0,0 +1,6 @@
++package libnetwork
++
++
++func (r *resolver) setupIPTable() error {
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_resolver__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_resolver__unix.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/resolver_unix.go.orig 2020-09-18 09:00:58 UTC
++++ vendor/github.com/docker/libnetwork/resolver_unix.go
+@@ -1,4 +1,4 @@
+-// +build !windows
++// +build !windows,!freebsd
+
+ package libnetwork
+
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__common.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__common.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/docker/libnetwork/service_common.go.orig 2019-10-07 21:12:15 UTC
++++ vendor/github.com/docker/libnetwork/service_common.go
+@@ -1,5 +1,3 @@
+-// +build linux windows
+-
+ package libnetwork
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__freebsd.go
@@ -0,0 +1,305 @@
+--- vendor/github.com/docker/libnetwork/service_freebsd.go.orig 2020-09-04 09:13:43 UTC
++++ vendor/github.com/docker/libnetwork/service_freebsd.go
+@@ -0,0 +1,302 @@
++package libnetwork
++
++import (
++ "fmt"
++ "io"
++ "io/ioutil"
++ "net"
++ "os"
++ "os/exec"
++ "strings"
++ "sync"
++
++ "github.com/docker/docker/pkg/reexec"
++ "github.com/gogo/protobuf/proto"
++ "github.com/ishidawataru/sctp"
++ "github.com/sirupsen/logrus"
++)
++
++func init() {
++ reexec.Register("fwmarker", fwMarker)
++ reexec.Register("redirector", redirector)
++}
++
++// Populate all loadbalancers on the network that the passed endpoint
++// belongs to, into this sandbox.
++func (sb *sandbox) populateLoadBalancers(ep *endpoint) {
++ // This is an interface less endpoint. Nothing to do.
++ if ep.Iface() == nil {
++ return
++ }
++
++ n := ep.getNetwork()
++ eIP := ep.Iface().Address()
++
++ if n.ingress {
++ if err := addRedirectRules(sb.Key(), eIP, ep.ingressPorts); err != nil {
++ logrus.Errorf("Failed to add redirect rules for ep %s (%.7s): %v", ep.Name(), ep.ID(), err)
++ }
++ }
++}
++
++func (n *network) findLBEndpointSandbox() (*endpoint, *sandbox, error) {
++ // TODO: get endpoint from store? See EndpointInfo()
++ var ep *endpoint
++ // Find this node's LB sandbox endpoint: there should be exactly one
++ for _, e := range n.Endpoints() {
++ epi := e.Info()
++ if epi != nil && epi.LoadBalancer() {
++ ep = e.(*endpoint)
++ break
++ }
++ }
++ if ep == nil {
++ return nil, nil, fmt.Errorf("Unable to find load balancing endpoint for network %s", n.ID())
++ }
++ // Get the load balancer sandbox itself as well
++ sb, ok := ep.getSandbox()
++ if !ok {
++ return nil, nil, fmt.Errorf("Unable to get sandbox for %s(%s) in for %s", ep.Name(), ep.ID(), n.ID())
++ }
++ ep = sb.getEndpoint(ep.ID())
++ if ep == nil {
++ return nil, nil, fmt.Errorf("Load balancing endpoint %s(%s) removed from %s", ep.Name(), ep.ID(), n.ID())
++ }
++ return ep, sb, nil
++}
++
++// Searches the OS sandbox for the name of the endpoint interface
++// within the sandbox. This is required for adding/removing IP
++// aliases to the interface.
++func findIfaceDstName(sb *sandbox, ep *endpoint) string {
++ srcName := ep.Iface().SrcName()
++ for _, i := range sb.osSbox.Info().Interfaces() {
++ if i.SrcName() == srcName {
++ return i.DstName()
++ }
++ }
++ return ""
++}
++
++// Add loadbalancer backend to the loadbalncer sandbox for the network.
++// If needed add the service as well.
++func (n *network) addLBBackend(ip net.IP, lb *loadBalancer) {
++ //return fmt.Errorf("not supported")
++}
++
++// Remove loadbalancer backend the load balancing endpoint for this
++// network. If 'rmService' is true, then remove the service entry as well.
++// If 'fullRemove' is true then completely remove the entry, otherwise
++// just deweight it for now.
++func (n *network) rmLBBackend(ip net.IP, lb *loadBalancer, rmService bool, fullRemove bool) {
++ //return fmt.Errorf("not supported")
++}
++
++const ingressChain = "DOCKER-INGRESS"
++
++var (
++ ingressOnce sync.Once
++ ingressMu sync.Mutex // lock for operations on ingress
++ ingressProxyTbl = make(map[string]io.Closer)
++ portConfigMu sync.Mutex
++ portConfigTbl = make(map[PortConfig]int)
++)
++
++func filterPortConfigs(ingressPorts []*PortConfig, isDelete bool) []*PortConfig {
++ portConfigMu.Lock()
++ iPorts := make([]*PortConfig, 0, len(ingressPorts))
++ for _, pc := range ingressPorts {
++ if isDelete {
++ if cnt, ok := portConfigTbl[*pc]; ok {
++ // This is the last reference to this
++ // port config. Delete the port config
++ // and add it to filtered list to be
++ // plumbed.
++ if cnt == 1 {
++ delete(portConfigTbl, *pc)
++ iPorts = append(iPorts, pc)
++ continue
++ }
++
++ portConfigTbl[*pc] = cnt - 1
++ }
++
++ continue
++ }
++
++ if cnt, ok := portConfigTbl[*pc]; ok {
++ portConfigTbl[*pc] = cnt + 1
++ continue
++ }
++
++ // We are adding it for the first time. Add it to the
++ // filter list to be plumbed.
++ portConfigTbl[*pc] = 1
++ iPorts = append(iPorts, pc)
++ }
++ portConfigMu.Unlock()
++
++ return iPorts
++}
++
++func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
++ return fmt.Errorf("not supported")
++}
++
++// In the filter table FORWARD chain the first rule should be to jump to
++// DOCKER-USER so the user is able to filter packet first.
++// The second rule should be jump to INGRESS-CHAIN.
++// This chain has the rules to allow access to the published ports for swarm tasks
++// from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
++func arrangeIngressFilterRule() {
++ //return fmt.Errorf("not supported")
++}
++
++func findOIFName(ip net.IP) (string, error) {
++ return "", fmt.Errorf("not supported")
++}
++
++func plumbProxy(iPort *PortConfig, isDelete bool) error {
++ var (
++ err error
++ l io.Closer
++ )
++
++ portSpec := fmt.Sprintf("%d/%s", iPort.PublishedPort, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]))
++ if isDelete {
++ if listener, ok := ingressProxyTbl[portSpec]; ok {
++ if listener != nil {
++ listener.Close()
++ }
++ }
++
++ return nil
++ }
++
++ switch iPort.Protocol {
++ case ProtocolTCP:
++ l, err = net.ListenTCP("tcp", &net.TCPAddr{Port: int(iPort.PublishedPort)})
++ case ProtocolUDP:
++ l, err = net.ListenUDP("udp", &net.UDPAddr{Port: int(iPort.PublishedPort)})
++ case ProtocolSCTP:
++ l, err = sctp.ListenSCTP("sctp", &sctp.SCTPAddr{Port: int(iPort.PublishedPort)})
++ default:
++ err = fmt.Errorf("unknown protocol %v", iPort.Protocol)
++ }
++
++ if err != nil {
++ return err
++ }
++
++ ingressProxyTbl[portSpec] = l
++
++ return nil
++}
++
++func writePortsToFile(ports []*PortConfig) (string, error) {
++ f, err := ioutil.TempFile("", "port_configs")
++ if err != nil {
++ return "", err
++ }
++ defer f.Close()
++
++ buf, _ := proto.Marshal(&EndpointRecord{
++ IngressPorts: ports,
++ })
++
++ n, err := f.Write(buf)
++ if err != nil {
++ return "", err
++ }
++
++ if n < len(buf) {
++ return "", io.ErrShortWrite
++ }
++
++ return f.Name(), nil
++}
++
++func readPortsFromFile(fileName string) ([]*PortConfig, error) {
++ buf, err := ioutil.ReadFile(fileName)
++ if err != nil {
++ return nil, err
++ }
++
++ var epRec EndpointRecord
++ err = proto.Unmarshal(buf, &epRec)
++ if err != nil {
++ return nil, err
++ }
++
++ return epRec.IngressPorts, nil
++}
++
++// Invoke fwmarker reexec routine to mark vip destined packets with
++// the passed firewall mark.
++func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, isDelete bool, lbMode string) error {
++ var ingressPortsFile string
++
++ if len(ingressPorts) != 0 {
++ var err error
++ ingressPortsFile, err = writePortsToFile(ingressPorts)
++ if err != nil {
++ return err
++ }
++
++ defer os.Remove(ingressPortsFile)
++ }
++
++ addDelOpt := "-A"
++ if isDelete {
++ addDelOpt = "-D"
++ }
++
++ cmd := &exec.Cmd{
++ Path: reexec.Self(),
++ Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String(), lbMode),
++ Stdout: os.Stdout,
++ Stderr: os.Stderr,
++ }
++
++ if err := cmd.Run(); err != nil {
++ return fmt.Errorf("reexec failed: %v", err)
++ }
++
++ return nil
++}
++
++// Firewall marker reexec function.
++func fwMarker() {
++ //return fmt.Errorf("not supported")
++}
++
++func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) error {
++ var ingressPortsFile string
++
++ if len(ingressPorts) != 0 {
++ var err error
++ ingressPortsFile, err = writePortsToFile(ingressPorts)
++ if err != nil {
++ return err
++ }
++ defer os.Remove(ingressPortsFile)
++ }
++
++ cmd := &exec.Cmd{
++ Path: reexec.Self(),
++ Args: append([]string{"redirector"}, path, eIP.String(), ingressPortsFile),
++ Stdout: os.Stdout,
++ Stderr: os.Stderr,
++ }
++
++ if err := cmd.Run(); err != nil {
++ return fmt.Errorf("reexec failed: %v", err)
++ }
++
++ return nil
++}
++
++// Redirector reexec function.
++func redirector() {
++ //return fmt.Errorf("not supported")
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__unsupported.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_libnetwork_service__unsupported.go
@@ -0,0 +1,17 @@
+--- vendor/github.com/docker/libnetwork/service_unsupported.go.orig 2020-09-04 14:54:57 UTC
++++ vendor/github.com/docker/libnetwork/service_unsupported.go
+@@ -1,4 +1,4 @@
+-// +build !linux,!windows
++// +build !linux,!windows,!freebsd
+
+ package libnetwork
+
+@@ -18,7 +18,7 @@ func (c *controller) rmServiceBinding(name, sid, nid,
+ return fmt.Errorf("not supported")
+ }
+
+-func (sb *sandbox) populateLoadBalancers(ep *endpoint) {
++func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
+ }
+
+ func arrangeIngressFilterRule() {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_swarmkit_manager_allocator_cnmallocator_drivers__unsupported.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_swarmkit_manager_allocator_cnmallocator_drivers__unsupported.go
@@ -0,0 +1,15 @@
+Fix build error on FreeBSD
+
+swarmkit/manager/allocator/cnmallocator/drivers_unsupported.go:9:7: const initializer cannot be nil
+
+--- vendor/github.com/docker/swarmkit/manager/allocator/cnmallocator/drivers_unsupported.go.orig 2019-03-08 08:00:27 UTC
++++ vendor/github.com/docker/swarmkit/manager/allocator/cnmallocator/drivers_unsupported.go
+@@ -6,7 +6,7 @@ import (
+ "github.com/docker/swarmkit/manager/allocator/networkallocator"
+ )
+
+-const initializers = nil
++var initializers = []initializer{}
+
+ // PredefinedNetworks returns the list of predefined network structures
+ func PredefinedNetworks() []networkallocator.PredefinedNetworkData {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_docker_swarmkit_node_node.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_docker_swarmkit_node_node.go
@@ -0,0 +1,23 @@
+--- vendor/github.com/docker/swarmkit/node/node.go.orig 2019-10-07 21:12:15 UTC
++++ vendor/github.com/docker/swarmkit/node/node.go
+@@ -21,7 +21,6 @@ import (
+
+ "github.com/docker/docker/pkg/plugingetter"
+ "github.com/docker/go-metrics"
+- "github.com/docker/libnetwork/drivers/overlay/overlayutils"
+ "github.com/docker/swarmkit/agent"
+ "github.com/docker/swarmkit/agent/exec"
+ "github.com/docker/swarmkit/api"
+@@ -274,11 +273,7 @@ func (n *Node) currentRole() api.NodeRole {
+
+ // configVXLANUDPPort sets vxlan port in libnetwork
+ func configVXLANUDPPort(ctx context.Context, vxlanUDPPort uint32) {
+- if err := overlayutils.ConfigVXLANUDPPort(vxlanUDPPort); err != nil {
+- log.G(ctx).WithError(err).Error("failed to configure VXLAN UDP port")
+- return
+- }
+- logrus.Infof("initialized VXLAN UDP port to %d ", vxlanUDPPort)
++ logrus.Infof("VXLAN UDP not supported on FreeBSD")
+ }
+
+ func (n *Node) run(ctx context.Context) (err error) {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_godbus_dbus_transport__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_godbus_dbus_transport__freebsd.go
@@ -0,0 +1,9 @@
+--- vendor/github.com/godbus/dbus/transport_freebsd.go.orig 2019-02-26 21:19:13 UTC
++++ vendor/github.com/godbus/dbus/transport_freebsd.go
+@@ -0,0 +1,6 @@
++package dbus
++
++func (t *unixTransport) SendNullByte() error {
++ _, err := t.Write([]byte{0})
++ return err
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_executor_oci_spec__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_executor_oci_spec__unix.go
@@ -0,0 +1,20 @@
+--- vendor/github.com/moby/buildkit/executor/oci/spec_unix.go.orig 2019-08-22 20:57:25 UTC
++++ vendor/github.com/moby/buildkit/executor/oci/spec_unix.go
+@@ -8,7 +8,6 @@ import (
+ "sync"
+
+ "github.com/containerd/containerd/containers"
+- "github.com/containerd/containerd/contrib/seccomp"
+ "github.com/containerd/containerd/mount"
+ "github.com/containerd/containerd/namespaces"
+ "github.com/containerd/containerd/oci"
+@@ -40,7 +39,8 @@ func GenerateSpec(ctx context.Context, meta executor.M
+ if meta.SecurityMode == pb.SecurityMode_INSECURE {
+ opts = append(opts, entitlements.WithInsecureSpec())
+ } else if system.SeccompSupported() && meta.SecurityMode == pb.SecurityMode_SANDBOX {
+- opts = append(opts, seccomp.WithDefaultProfile())
++ // TODO
++ return nil, nil, errors.New("TODO Seccomp Sandbox not supported on FreeBSD")
+ }
+
+ switch processMode {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_executor_runcexecutor_executor.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_executor_runcexecutor_executor.go
@@ -0,0 +1,21 @@
+--- vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go.orig 2019-08-22 20:57:25 UTC
++++ vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
+@@ -22,7 +22,6 @@ import (
+ "github.com/moby/buildkit/identity"
+ "github.com/moby/buildkit/solver/pb"
+ "github.com/moby/buildkit/util/network"
+- rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ )
+@@ -246,9 +245,7 @@ func (w *runcExecutor) Exec(ctx context.Context, meta
+
+ spec.Process.OOMScoreAdj = w.oomScoreAdj
+ if w.rootless {
+- if err := rootlessspecconv.ToRootless(spec); err != nil {
+- return err
+- }
++ return errors.New("TODO: Rootless not implemented in FreeBSD!")
+ }
+
+ if err := json.NewEncoder(f).Encode(spec); err != nil {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_snapshot_localmounter__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_snapshot_localmounter__freebsd.go
@@ -0,0 +1,29 @@
+--- vendor/github.com/moby/buildkit/snapshot/localmounter_freebsd.go.orig 2019-03-06 19:37:34 UTC
++++ vendor/github.com/moby/buildkit/snapshot/localmounter_freebsd.go
+@@ -0,0 +1,26 @@
++package snapshot
++
++import (
++ "os"
++
++ "github.com/containerd/containerd/mount"
++)
++
++func (lm *localMounter) Unmount() error {
++ lm.mu.Lock()
++ defer lm.mu.Unlock()
++
++ if lm.target != "" {
++ if err := mount.Unmount(lm.target, 0); err != nil {
++ return err
++ }
++ os.RemoveAll(lm.target)
++ lm.target = ""
++ }
++
++ if lm.release != nil {
++ return lm.release()
++ }
++
++ return nil
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_snapshot_localmounter__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_snapshot_localmounter__unix.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/moby/buildkit/snapshot/localmounter_unix.go.orig 2019-02-26 00:29:56 UTC
++++ vendor/github.com/moby/buildkit/snapshot/localmounter_unix.go
+@@ -1,4 +1,4 @@
+-// +build !windows
++// +build !windows,!freebsd
+
+ package snapshot
+
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_util_entitlements_security__freebsd.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_moby_buildkit_util_entitlements_security__freebsd.go
@@ -0,0 +1,70 @@
+--- vendor/github.com/moby/buildkit/util/entitlements/security_freebsd.go.orig 2019-06-24 18:24:33 UTC
++++ vendor/github.com/moby/buildkit/util/entitlements/security_freebsd.go
+@@ -0,0 +1,67 @@
++package entitlements
++
++import (
++ "context"
++
++ "github.com/containerd/containerd/containers"
++ "github.com/containerd/containerd/oci"
++ specs "github.com/opencontainers/runtime-spec/specs-go"
++)
++
++// WithInsecureSpec sets spec with All capability.
++func WithInsecureSpec() oci.SpecOpts {
++ return func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
++ addCaps := []string{
++ "CAP_FSETID",
++ "CAP_KILL",
++ "CAP_FOWNER",
++ "CAP_MKNOD",
++ "CAP_CHOWN",
++ "CAP_DAC_OVERRIDE",
++ "CAP_NET_RAW",
++ "CAP_SETGID",
++ "CAP_SETUID",
++ "CAP_SETPCAP",
++ "CAP_SETFCAP",
++ "CAP_NET_BIND_SERVICE",
++ "CAP_SYS_CHROOT",
++ "CAP_AUDIT_WRITE",
++ "CAP_MAC_ADMIN",
++ "CAP_MAC_OVERRIDE",
++ "CAP_DAC_READ_SEARCH",
++ "CAP_SYS_PTRACE",
++ "CAP_SYS_MODULE",
++ "CAP_SYSLOG",
++ "CAP_SYS_RAWIO",
++ "CAP_SYS_ADMIN",
++ "CAP_LINUX_IMMUTABLE",
++ "CAP_SYS_BOOT",
++ "CAP_SYS_NICE",
++ "CAP_SYS_PACCT",
++ "CAP_SYS_TTY_CONFIG",
++ "CAP_SYS_TIME",
++ "CAP_WAKE_ALARM",
++ "CAP_AUDIT_READ",
++ "CAP_AUDIT_CONTROL",
++ "CAP_SYS_RESOURCE",
++ "CAP_BLOCK_SUSPEND",
++ "CAP_IPC_LOCK",
++ "CAP_IPC_OWNER",
++ "CAP_LEASE",
++ "CAP_NET_ADMIN",
++ "CAP_NET_BROADCAST",
++ }
++ for _, cap := range addCaps {
++ s.Process.Capabilities.Bounding = append(s.Process.Capabilities.Bounding, cap)
++ s.Process.Capabilities.Ambient = append(s.Process.Capabilities.Ambient, cap)
++ s.Process.Capabilities.Effective = append(s.Process.Capabilities.Effective, cap)
++ s.Process.Capabilities.Inheritable = append(s.Process.Capabilities.Inheritable, cap)
++ s.Process.Capabilities.Permitted = append(s.Process.Capabilities.Permitted, cap)
++ }
++ s.Linux.ReadonlyPaths = []string{}
++ s.Linux.MaskedPaths = []string{}
++ s.Process.ApparmorProfile = ""
++
++ return nil
++ }
++}
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_copy_copy__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_copy_copy__unix.go
@@ -0,0 +1,45 @@
+--- vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go.orig 2020-09-18 09:00:57 UTC
++++ vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go
+@@ -3,6 +3,7 @@
+ package fs
+
+ import (
++ "io"
+ "os"
+ "syscall"
+
+@@ -52,10 +53,33 @@ func (c *copier) copyFileInfo(fi os.FileInfo, name str
+ return nil
+ }
+
++func copyFile(source, target string) error {
++ src, err := os.Open(source)
++ if err != nil {
++ return errors.Wrapf(err, "failed to open source %s", source)
++ }
++ defer src.Close()
++ tgt, err := os.Create(target)
++ if err != nil {
++ return errors.Wrapf(err, "failed to open target %s", target)
++ }
++ defer tgt.Close()
++
++ return copyFileContent(tgt, src)
++}
++
++func copyFileContent(dst, src *os.File) error {
++ _, err := io.Copy(dst, src)
++ if(err != nil) {
++ return err
++ }
++ return nil
++}
++
+ func copyDevice(dst string, fi os.FileInfo) error {
+ st, ok := fi.Sys().(*syscall.Stat_t)
+ if !ok {
+ return errors.New("unsupported stat type")
+ }
+- return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
++ return unix.Mknod(dst, uint32(fi.Mode()), st.Rdev)
+ }
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_diskwriter__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_diskwriter__unix.go
@@ -0,0 +1,11 @@
+--- vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go.orig 2019-02-26 00:29:56 UTC
++++ vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go
+@@ -45,7 +45,7 @@ func handleTarTypeBlockCharFifo(path string, stat *typ
+ mode |= syscall.S_IFBLK
+ }
+
+- if err := syscall.Mknod(path, mode, int(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
++ if err := syscall.Mknod(path, mode, uint64(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
+ return err
+ }
+ return nil
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_stat__unix.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_tonistiigi_fsutil_stat__unix.go
@@ -0,0 +1,11 @@
+--- vendor/github.com/tonistiigi/fsutil/stat_unix.go.orig 2019-06-18 21:30:11 UTC
++++ vendor/github.com/tonistiigi/fsutil/stat_unix.go
+@@ -45,7 +45,7 @@ func setUnixOpt(fi os.FileInfo, stat *types.Stat, path
+ stat.Devminor = int64(minor(uint64(s.Rdev)))
+ }
+
+- ino := s.Ino
++ ino := uint64(s.Ino)
+ linked := false
+ if seenFiles != nil {
+ if s.Nlink > 1 {
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_vishvananda_netlink_filter.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_vishvananda_netlink_filter.go
@@ -0,0 +1,8 @@
+--- vendor/github.com/vishvananda/netlink/filter.go.orig 2020-09-04 14:54:59 UTC
++++ vendor/github.com/vishvananda/netlink/filter.go
+@@ -1,3 +1,5 @@
++// +build linux
++
+ package netlink
+
+ import (
Index: sysutils/docker-freebsd/files/patch-vendor_github.com_vishvananda_netlink_handle__unspecified.go
===================================================================
--- /dev/null
+++ sysutils/docker-freebsd/files/patch-vendor_github.com_vishvananda_netlink_handle__unspecified.go
@@ -0,0 +1,21 @@
+--- vendor/github.com/vishvananda/netlink/handle_unspecified.go.orig 2020-10-23 18:37:22 UTC
++++ vendor/github.com/vishvananda/netlink/handle_unspecified.go
+@@ -185,18 +185,6 @@ func (h *Handle) ClassList(link Link, parent uint32) (
+ 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
+ }
Index: sysutils/docker-freebsd/pkg-descr
===================================================================
--- sysutils/docker-freebsd/pkg-descr
+++ sysutils/docker-freebsd/pkg-descr
@@ -1,12 +1,4 @@
-Docker is an open source project to pack, ship and run any
-application as a lightweight container.
+Moby is an open-source project created by Docker to enable and accelerate
+software containerization.
-Docker containers are both hardware-agnostic and platform-agnostic.
-This means they can run anywhere, from your laptop to the largest
-EC2 compute instance and everything in between - and they don't
-require you to use a particular language, framework or packaging
-system. That makes them great building blocks for deploying and
-scaling web apps, databases, and backend services without depending
-on a particular stack or provider.
-
-WWW: https://github.com/kvasdopil/docker
+WWW: https://github.com/docker/engine
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 2, 7:57 AM (13 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27453536
Default Alt Text
D21570.diff (204 KB)
Attached To
Mode
D21570: Update sysutils/docker-freebsd to new version
Attached
Detach File
Event Timeline
Log In to Comment