diff --git a/Makefile b/Makefile index 8e9642e979..08e59b5e28 100644 --- a/Makefile +++ b/Makefile @@ -7,13 +7,17 @@ CONFIGDIR := ${PREFIX}/share/containers define go-build CGO_ENABLED=0 \ - GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3)" ./... + GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3)" ./...; + CGO_ENABLED=0 \ + GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3),cni" ./...; endef ifeq ($(shell uname -s),Linux) define go-build-c CGO_ENABLED=1 \ - GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3)" ./... + GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3)" ./...; + CGO_ENABLED=1 \ + GOOS=$(1) GOARCH=$(2) $(GO) build -tags "$(3),cni" ./...; endef else define go-build-c @@ -36,21 +40,31 @@ build-cross: $(call go-build,windows,386,${BUILDTAGS}) .PHONY: all -all: build-amd64 build-386 +all: build-amd64 build-386 build-amd64-cni build-386-cni .PHONY: build -build: build-amd64 build-386 +build: build-amd64 build-386 build-amd64-cni build-386-cni .PHONY: build-amd64 build-amd64: GOARCH=amd64 $(GO_BUILD) -tags $(BUILDTAGS) ./... +.PHONY: build-amd64 +build-amd64-cni: + GOARCH=amd64 $(GO_BUILD) -tags $(BUILDTAGS),cni ./... + .PHONY: build-386 build-386: ifneq ($(shell uname -s), Darwin) GOARCH=386 $(GO_BUILD) -tags $(BUILDTAGS) ./... endif +.PHONY: build-386-cni +build-386-cni: +ifneq ($(shell uname -s), Darwin) + GOARCH=386 $(GO_BUILD) -tags $(BUILDTAGS),cni ./... +endif + .PHONY: bin/netavark-testplugin bin/netavark-testplugin: $(GO_BUILD) -o $@ ./libnetwork/netavark/testplugin/ diff --git a/libnetwork/cni/cni_conversion.go b/libnetwork/cni/cni_conversion.go index 6e4514b992..eb3f0276f2 100644 --- a/libnetwork/cni/cni_conversion.go +++ b/libnetwork/cni/cni_conversion.go @@ -1,5 +1,6 @@ -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/cni_exec.go b/libnetwork/cni/cni_exec.go index 4b7ed8c6d9..d68f169c87 100644 --- a/libnetwork/cni/cni_exec.go +++ b/libnetwork/cni/cni_exec.go @@ -16,8 +16,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/cni_suite_test.go b/libnetwork/cni/cni_suite_test.go index 5fbe798324..8edba7d29b 100644 --- a/libnetwork/cni/cni_suite_test.go +++ b/libnetwork/cni/cni_suite_test.go @@ -1,5 +1,6 @@ -//go:build linux -// +build linux +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni package cni_test diff --git a/libnetwork/cni/cni_types.go b/libnetwork/cni/cni_types.go index 1d48d08056..95aa59cb7b 100644 --- a/libnetwork/cni/cni_types.go +++ b/libnetwork/cni/cni_types.go @@ -1,5 +1,6 @@ -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/config.go b/libnetwork/cni/config.go index a1eeceb72b..2afa77b740 100644 --- a/libnetwork/cni/config.go +++ b/libnetwork/cni/config.go @@ -1,5 +1,6 @@ -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/config_freebsd.go b/libnetwork/cni/config_freebsd.go index ff95c0e17d..2d69b37dd8 100644 --- a/libnetwork/cni/config_freebsd.go +++ b/libnetwork/cni/config_freebsd.go @@ -1,5 +1,6 @@ -//go:build freebsd -// +build freebsd +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/config_linux.go b/libnetwork/cni/config_linux.go index 836fd73bf6..a45768d5a4 100644 --- a/libnetwork/cni/config_linux.go +++ b/libnetwork/cni/config_linux.go @@ -1,5 +1,6 @@ -//go:build linux -// +build linux +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/config_test.go b/libnetwork/cni/config_test.go index 3e80ab8c8a..e7d1f3a407 100644 --- a/libnetwork/cni/config_test.go +++ b/libnetwork/cni/config_test.go @@ -1,5 +1,6 @@ -//go:build linux -// +build linux +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni package cni_test diff --git a/libnetwork/cni/network.go b/libnetwork/cni/network.go index 7d3369af7d..aaa7c13a7d 100644 --- a/libnetwork/cni/network.go +++ b/libnetwork/cni/network.go @@ -1,5 +1,6 @@ -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/run.go b/libnetwork/cni/run.go index 829c127042..2376538b5c 100644 --- a/libnetwork/cni/run.go +++ b/libnetwork/cni/run.go @@ -1,5 +1,6 @@ -//go:build linux || freebsd +//go:build (linux || freebsd) && cni // +build linux freebsd +// +build cni package cni diff --git a/libnetwork/cni/run_test.go b/libnetwork/cni/run_test.go index 498ed6d472..eb19082b94 100644 --- a/libnetwork/cni/run_test.go +++ b/libnetwork/cni/run_test.go @@ -1,5 +1,6 @@ -//go:build linux -// +build linux +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni package cni_test diff --git a/libnetwork/network/cni_interface.go b/libnetwork/network/cni_interface.go new file mode 100644 index 0000000000..ef73c36dd2 --- /dev/null +++ b/libnetwork/network/cni_interface.go @@ -0,0 +1,129 @@ +//go:build (linux || freebsd) && cni +// +build linux freebsd +// +build cni + +package network + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/containers/common/libnetwork/cni" + "github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/machine" + "github.com/containers/storage" + "github.com/containers/storage/pkg/homedir" + "github.com/containers/storage/pkg/unshare" +) + +const ( + // cniConfigDirRootless is the directory in XDG_CONFIG_HOME for cni plugins + cniConfigDirRootless = "cni/net.d/" +) + +func getCniInterface(conf *config.Config) (types.ContainerNetwork, error) { + confDir := conf.Network.NetworkConfigDir + if confDir == "" { + var err error + confDir, err = getDefaultCNIConfigDir() + if err != nil { + return nil, err + } + } + return cni.NewCNINetworkInterface(&cni.InitConfig{ + Config: conf, + CNIConfigDir: confDir, + RunDir: conf.Engine.TmpDir, + IsMachine: machine.IsGvProxyBased(), + }) +} + +func getDefaultCNIConfigDir() (string, error) { + if !unshare.IsRootless() { + return cniConfigDir, nil + } + + configHome, err := homedir.GetConfigHome() + if err != nil { + return "", err + } + + return filepath.Join(configHome, cniConfigDirRootless), nil +} + +func networkBackendFromStore(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) { + _, err = conf.FindHelperBinary("netavark", false) + if err != nil { + // if we cannot find netavark use CNI + return types.CNI, nil + } + + // If there are any containers then return CNI + cons, err := store.Containers() + if err != nil { + return "", err + } + if len(cons) != 0 { + return types.CNI, nil + } + + // If there are any non ReadOnly images then return CNI + imgs, err := store.Images() + if err != nil { + return "", err + } + for _, i := range imgs { + if !i.ReadOnly { + return types.CNI, nil + } + } + + // If there are CNI Networks then return CNI + cniInterface, err := getCniInterface(conf) + if err == nil { + nets, err := cniInterface.NetworkList() + // there is always a default network so check > 1 + if err != nil && !errors.Is(err, os.ErrNotExist) { + return "", err + } + + if len(nets) > 1 { + // we do not have a fresh system so use CNI + return types.CNI, nil + } + } + return types.Netavark, nil +} + +func backendFromName(backend string) types.NetworkBackend { + if backend == string(types.Netavark) { + return types.Netavark + } + if backend == string(types.CNI) { + return types.CNI + } + return "" +} + +func backendFromType(backend types.NetworkBackend, store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { + switch backend { + case types.Netavark: + netInt, err := netavarkBackendFromConf(store, conf, syslog) + if err != nil { + return "", nil, err + } + return types.Netavark, netInt, err + case types.CNI: + netInt, err := getCniInterface(conf) + if err != nil { + return "", nil, err + } + return types.CNI, netInt, err + + default: + return "", nil, fmt.Errorf("unsupported network backend %q, check network_backend in containers.conf", backend) + } +} diff --git a/libnetwork/network/interface.go b/libnetwork/network/interface.go index 4a8290ba74..e07ce59615 100644 --- a/libnetwork/network/interface.go +++ b/libnetwork/network/interface.go @@ -9,13 +9,9 @@ import ( "os" "path/filepath" - "github.com/containers/common/libnetwork/cni" - "github.com/containers/common/libnetwork/netavark" "github.com/containers/common/libnetwork/types" "github.com/containers/common/pkg/config" - "github.com/containers/common/pkg/machine" "github.com/containers/storage" - "github.com/containers/storage/pkg/homedir" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/unshare" "github.com/sirupsen/logrus" @@ -24,8 +20,6 @@ import ( const ( // defaultNetworkBackendFileName is the file name for sentinel file to store the backend defaultNetworkBackendFileName = "defaultNetworkBackend" - // cniConfigDirRootless is the directory in XDG_CONFIG_HOME for cni plugins - cniConfigDirRootless = "cni/net.d/" // netavarkBinary is the name of the netavark binary netavarkBinary = "netavark" @@ -53,45 +47,7 @@ func NetworkBackend(store storage.Store, conf *config.Config, syslog bool) (type } } - switch backend { - case types.Netavark: - netavarkBin, err := conf.FindHelperBinary(netavarkBinary, false) - if err != nil { - return "", nil, err - } - - aardvarkBin, _ := conf.FindHelperBinary(aardvarkBinary, false) - - confDir := conf.Network.NetworkConfigDir - if confDir == "" { - confDir = getDefaultNetavarkConfigDir(store) - } - - // We cannot use the runroot for rootful since the network namespace is shared for all - // libpod instances they also have to share the same ipam db. - // For rootless we have our own network namespace per libpod instances, - // so this is not a problem there. - runDir := netavarkRunDir - if unshare.IsRootless() { - runDir = filepath.Join(store.RunRoot(), "networks") - } - - netInt, err := netavark.NewNetworkInterface(&netavark.InitConfig{ - Config: conf, - NetworkConfigDir: confDir, - NetworkRunDir: runDir, - NetavarkBinary: netavarkBin, - AardvarkBinary: aardvarkBin, - Syslog: syslog, - }) - return types.Netavark, netInt, err - case types.CNI: - netInt, err := getCniInterface(conf) - return types.CNI, netInt, err - - default: - return "", nil, fmt.Errorf("unsupported network backend %q, check network_backend in containers.conf", backend) - } + return backendFromType(backend, store, conf, syslog) } func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) { @@ -99,15 +55,13 @@ func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend ty file := filepath.Join(store.GraphRoot(), defaultNetworkBackendFileName) b, err := os.ReadFile(file) if err == nil { - val := string(b) - if val == string(types.Netavark) { - return types.Netavark, nil - } - if val == string(types.CNI) { - return types.CNI, nil + if val := backendFromName(string(b)); val != "" { + return val, nil + } else { + return "", fmt.Errorf("unknown network backend value %q in %q", val, file) } - return "", fmt.Errorf("unknown network backend value %q in %q", val, file) } + // fail for all errors except ENOENT if !errors.Is(err, os.ErrNotExist) { return "", fmt.Errorf("could not read network backend value: %w", err) @@ -123,76 +77,11 @@ func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend ty } }() - _, err = conf.FindHelperBinary("netavark", false) - if err != nil { - // if we cannot find netavark use CNI - return types.CNI, nil - } - - // If there are any containers then return CNI - cons, err := store.Containers() - if err != nil { - return "", err - } - if len(cons) != 0 { - return types.CNI, nil - } - - // If there are any non ReadOnly images then return CNI - imgs, err := store.Images() - if err != nil { - return "", err - } - for _, i := range imgs { - if !i.ReadOnly { - return types.CNI, nil - } - } - - // If there are CNI Networks then return CNI - cniInterface, err := getCniInterface(conf) - if err == nil { - nets, err := cniInterface.NetworkList() - // there is always a default network so check > 1 - if err != nil && !errors.Is(err, os.ErrNotExist) { - return "", err - } - - if len(nets) > 1 { - // we do not have a fresh system so use CNI - return types.CNI, nil - } - } - return types.Netavark, nil -} - -func getCniInterface(conf *config.Config) (types.ContainerNetwork, error) { - confDir := conf.Network.NetworkConfigDir - if confDir == "" { - var err error - confDir, err = getDefaultCNIConfigDir() - if err != nil { - return nil, err - } - } - return cni.NewCNINetworkInterface(&cni.InitConfig{ - Config: conf, - CNIConfigDir: confDir, - RunDir: conf.Engine.TmpDir, - IsMachine: machine.IsGvProxyBased(), - }) -} - -func getDefaultCNIConfigDir() (string, error) { - if !unshare.IsRootless() { - return cniConfigDir, nil - } - - configHome, err := homedir.GetConfigHome() + backend, err = networkBackendFromStore(store, conf) if err != nil { return "", err } - return filepath.Join(configHome, cniConfigDirRootless), nil + return backend, nil } // getDefaultNetavarkConfigDir return the netavark config dir. For rootful it will diff --git a/libnetwork/network/netavark_interface.go b/libnetwork/network/netavark_interface.go new file mode 100644 index 0000000000..41c3d472e9 --- /dev/null +++ b/libnetwork/network/netavark_interface.go @@ -0,0 +1,47 @@ +//go:build linux || freebsd +// +build linux freebsd + +package network + +import ( + "path/filepath" + + "github.com/containers/common/libnetwork/netavark" + "github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/config" + "github.com/containers/storage" + "github.com/containers/storage/pkg/unshare" +) + +func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bool) (types.ContainerNetwork, error) { + netavarkBin, err := conf.FindHelperBinary(netavarkBinary, false) + if err != nil { + return nil, err + } + + aardvarkBin, _ := conf.FindHelperBinary(aardvarkBinary, false) + + confDir := conf.Network.NetworkConfigDir + if confDir == "" { + confDir = getDefaultNetavarkConfigDir(store) + } + + // We cannot use the runroot for rootful since the network namespace is shared for all + // libpod instances they also have to share the same ipam db. + // For rootless we have our own network namespace per libpod instances, + // so this is not a problem there. + runDir := netavarkRunDir + if unshare.IsRootless() { + runDir = filepath.Join(store.RunRoot(), "networks") + } + + netInt, err := netavark.NewNetworkInterface(&netavark.InitConfig{ + Config: conf, + NetworkConfigDir: confDir, + NetworkRunDir: runDir, + NetavarkBinary: netavarkBin, + AardvarkBinary: aardvarkBin, + Syslog: syslog, + }) + return netInt, err +} diff --git a/libnetwork/network/non_cni_interface.go b/libnetwork/network/non_cni_interface.go new file mode 100644 index 0000000000..9bf05dad4e --- /dev/null +++ b/libnetwork/network/non_cni_interface.go @@ -0,0 +1,35 @@ +//go:build (linux || freebsd) && !cni +// +build linux freebsd +// +build !cni + +package network + +import ( + "fmt" + + "github.com/containers/common/libnetwork/types" + "github.com/containers/common/pkg/config" + "github.com/containers/storage" +) + +func networkBackendFromStore(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) { + return types.Netavark, nil +} + +func backendFromName(backend string) types.NetworkBackend { + if backend == string(types.Netavark) { + return types.Netavark + } + return "" +} + +func backendFromType(backend types.NetworkBackend, store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { + if backend != types.Netavark { + return "", nil, fmt.Errorf("unsupported network backend %q, check network_backend in containers.conf", backend) + } + cn, err := netavarkBackendFromConf(store, conf, syslog) + if err != nil { + return "", nil, err + } + return types.Netavark, cn, err +} diff --git a/libnetwork/types/const.go b/libnetwork/types/const.go index a916182007..13cbee6abe 100644 --- a/libnetwork/types/const.go +++ b/libnetwork/types/const.go @@ -49,8 +49,8 @@ const ( type NetworkBackend string const ( - CNI NetworkBackend = "cni" Netavark NetworkBackend = "netavark" + CNI NetworkBackend = "cni" ) // ValidMacVLANModes is the list of valid mode options for the macvlan driver