File: interface.go

package info (click to toggle)
golang-github-containers-common 0.64.1%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 5,932 kB
  • sloc: makefile: 132; sh: 111
file content (149 lines) | stat: -rw-r--r-- 4,977 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//go:build linux || freebsd

package network

import (
	"errors"
	"fmt"
	"os"
	"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/ioutils"
	"github.com/containers/storage/pkg/unshare"
	"github.com/sirupsen/logrus"
)

const (
	// defaultNetworkBackendFileName is the file name for sentinel file to store the backend
	defaultNetworkBackendFileName = "defaultNetworkBackend"

	// netavarkBinary is the name of the netavark binary
	netavarkBinary = "netavark"
	// aardvarkBinary is the name of the aardvark binary
	aardvarkBinary = "aardvark-dns"
)

// NetworkBackend returns the network backend name and interface
// It returns either the CNI or netavark backend depending on what is set in the config.
// If the backend is set to "" we will automatically assign the backend on the following conditions:
//  1. read ${graphroot}/defaultNetworkBackend
//  2. find netavark binary (if not installed use CNI)
//  3. check containers, images and CNI networks and if there are some we have an existing install and should continue to use CNI
//
// revive does not like the name because the package is already called network
//
//nolint:revive
func NetworkBackend(store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) {
	backend := types.NetworkBackend(conf.Network.NetworkBackend)
	if backend == "" {
		var err error
		backend, err = defaultNetworkBackend(store, conf)
		if err != nil {
			return "", nil, fmt.Errorf("failed to get default network backend: %w", err)
		}
	}

	return backendFromType(backend, store, conf, syslog)
}

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
}

func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) {
	err = nil

	file := filepath.Join(store.GraphRoot(), defaultNetworkBackendFileName)

	writeBackendToFile := func(backendT types.NetworkBackend) {
		// only write when there is no error
		if err == nil {
			if err := ioutils.AtomicWriteFile(file, []byte(backendT), 0o644); err != nil {
				logrus.Errorf("could not write network backend to file: %v", err)
			}
		}
	}

	// read defaultNetworkBackend file
	b, err := os.ReadFile(file)
	if err == nil {
		val := string(b)

		// if the network backend has been already set previously,
		// handle the values depending on whether CNI is supported and
		// whether the network backend is explicitly configured
		if val == string(types.Netavark) {
			// netavark is always good
			return types.Netavark, nil
		} else if val == string(types.CNI) {
			if cniSupported {
				return types.CNI, nil
			}
			// the user has *not* configured a network
			// backend explicitly but used CNI in the past
			// => we upgrade them in this case to netavark only
			writeBackendToFile(types.Netavark)
			logrus.Info("Migrating network backend to netavark as no backend has been configured previously")
			return types.Netavark, nil
		}
		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)
	}

	backend, err = networkBackendFromStore(store, conf)
	if err != nil {
		return "", err
	}
	// cache the network backend to make sure always the same one will be used
	writeBackendToFile(backend)

	return backend, nil
}

// getDefaultNetavarkConfigDir return the netavark config dir. For rootful it will
// use "/etc/containers/networks" and for rootless "$graphroot/networks". We cannot
// use the graphroot for rootful since the network namespace is shared for all
// libpod instances.
func getDefaultNetavarkConfigDir(store storage.Store) string {
	if !unshare.IsRootless() {
		return netavarkConfigDir
	}
	return filepath.Join(store.GraphRoot(), "networks")
}