Page MenuHomeFreeBSD

D21570.diff
No OneTemporary

D21570.diff

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

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)

Event Timeline