podman

Форк
0
/
networking_freebsd.go 
270 строк · 8.3 Кб
1
//go:build !remote
2

3
package libpod
4

5
import (
6
	"crypto/rand"
7
	jdec "encoding/json"
8
	"errors"
9
	"fmt"
10
	"net"
11
	"os/exec"
12
	"path/filepath"
13

14
	"github.com/containers/buildah/pkg/jail"
15
	"github.com/containers/common/libnetwork/types"
16
	"github.com/containers/podman/v5/libpod/define"
17
	"github.com/containers/storage/pkg/lockfile"
18
	"github.com/sirupsen/logrus"
19
)
20

21
type Netstat struct {
22
	Statistics NetstatInterface `json:"statistics"`
23
}
24

25
type NetstatInterface struct {
26
	Interface []NetstatAddress `json:"interface"`
27
}
28

29
type NetstatAddress struct {
30
	Name    string `json:"name"`
31
	Flags   string `json:"flags"`
32
	Mtu     int    `json:"mtu"`
33
	Network string `json:"network"`
34
	Address string `json:"address"`
35

36
	ReceivedPackets uint64 `json:"received-packets"`
37
	ReceivedBytes   uint64 `json:"received-bytes"`
38
	ReceivedErrors  uint64 `json:"received-errors"`
39

40
	SentPackets uint64 `json:"sent-packets"`
41
	SentBytes   uint64 `json:"sent-bytes"`
42
	SentErrors  uint64 `json:"send-errors"`
43

44
	DroppedPackets uint64 `json:"dropped-packets"`
45

46
	Collisions uint64 `json:"collisions"`
47
}
48

49
type RootlessNetNS struct {
50
	dir  string
51
	Lock *lockfile.LockFile
52
}
53

54
// getPath will join the given path to the rootless netns dir
55
func (r *RootlessNetNS) getPath(path string) string {
56
	return filepath.Join(r.dir, path)
57
}
58

59
// Do - run the given function in the rootless netns.
60
// It does not lock the rootlessCNI lock, the caller
61
// should only lock when needed, e.g. for network operations.
62
func (r *RootlessNetNS) Do(toRun func() error) error {
63
	return errors.New("not supported on freebsd")
64
}
65

66
// Cleanup the rootless network namespace if needed.
67
// It checks if we have running containers with the bridge network mode.
68
// Cleanup() expects that r.Lock is locked
69
func (r *RootlessNetNS) Cleanup(runtime *Runtime) error {
70
	return errors.New("not supported on freebsd")
71
}
72

73
// GetRootlessNetNs returns the rootless netns object. If create is set to true
74
// the rootless network namespace will be created if it does not already exist.
75
// If called as root it returns always nil.
76
// On success the returned RootlessCNI lock is locked and must be unlocked by the caller.
77
func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
78
	return nil, nil
79
}
80

81
func getSlirp4netnsIP(subnet *net.IPNet) (*net.IP, error) {
82
	return nil, errors.New("not implemented GetSlirp4netnsIP")
83
}
84

85
// This is called after the container's jail is created but before its
86
// started. We can use this to initialise the container's vnet when we don't
87
// have a separate vnet jail (which is the case in FreeBSD 13.3 and later).
88
func (r *Runtime) setupNetNS(ctr *Container) error {
89
	networkStatus, err := r.configureNetNS(ctr, ctr.ID())
90
	ctr.state.NetNS = ctr.ID()
91
	ctr.state.NetworkStatus = networkStatus
92
	return err
93
}
94

95
// Create and configure a new network namespace for a container
96
func (r *Runtime) configureNetNS(ctr *Container, ctrNS string) (status map[string]types.StatusBlock, rerr error) {
97
	if err := r.exposeMachinePorts(ctr.config.PortMappings); err != nil {
98
		return nil, err
99
	}
100
	defer func() {
101
		// make sure to unexpose the gvproxy ports when an error happens
102
		if rerr != nil {
103
			if err := r.unexposeMachinePorts(ctr.config.PortMappings); err != nil {
104
				logrus.Errorf("failed to free gvproxy machine ports: %v", err)
105
			}
106
		}
107
	}()
108
	networks, err := ctr.networks()
109
	if err != nil {
110
		return nil, err
111
	}
112
	// All networks have been removed from the container.
113
	// This is effectively forcing net=none.
114
	if len(networks) == 0 {
115
		return nil, nil
116
	}
117

118
	netOpts := ctr.getNetworkOptions(networks)
119
	netStatus, err := r.setUpNetwork(ctrNS, netOpts)
120
	if err != nil {
121
		return nil, err
122
	}
123

124
	return netStatus, err
125
}
126

127
// Create and configure a new network namespace for a container
128
func (r *Runtime) createNetNS(ctr *Container) (n string, q map[string]types.StatusBlock, retErr error) {
129
	b := make([]byte, 16)
130
	_, err := rand.Reader.Read(b)
131
	if err != nil {
132
		return "", nil, fmt.Errorf("failed to generate random vnet name: %v", err)
133
	}
134
	netns := fmt.Sprintf("vnet-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
135

136
	jconf := jail.NewConfig()
137
	jconf.Set("name", netns)
138
	jconf.Set("vnet", jail.NEW)
139
	jconf.Set("children.max", 1)
140
	jconf.Set("persist", true)
141
	jconf.Set("enforce_statfs", 0)
142
	jconf.Set("devfs_ruleset", 4)
143
	jconf.Set("allow.raw_sockets", true)
144
	jconf.Set("allow.chflags", true)
145
	jconf.Set("securelevel", -1)
146
	j, err := jail.Create(jconf)
147
	if err != nil {
148
		return "", nil, fmt.Errorf("Failed to create vnet jail %s for container %s: %w", netns, ctr.ID(), err)
149
	}
150

151
	logrus.Debugf("Created vnet jail %s for container %s", netns, ctr.ID())
152

153
	var networkStatus map[string]types.StatusBlock
154
	networkStatus, err = r.configureNetNS(ctr, netns)
155
	if err != nil {
156
		jconf := jail.NewConfig()
157
		jconf.Set("persist", false)
158
		if err := j.Set(jconf); err != nil {
159
			// Log this error and return the error from configureNetNS
160
			logrus.Errorf("failed to destroy vnet jail %s: %w", netns, err)
161
		}
162
	}
163
	return netns, networkStatus, err
164
}
165

166
// Tear down a network namespace, undoing all state associated with it.
167
func (r *Runtime) teardownNetNS(ctr *Container) error {
168
	if err := r.unexposeMachinePorts(ctr.config.PortMappings); err != nil {
169
		// do not return an error otherwise we would prevent network cleanup
170
		logrus.Errorf("failed to free gvproxy machine ports: %v", err)
171
	}
172
	if err := r.teardownNetwork(ctr); err != nil {
173
		return err
174
	}
175

176
	if ctr.state.NetNS != "" {
177
		// If PostConfigureNetNS is false, then we are running with a
178
		// separate vnet jail so we need to clean that up now.
179
		if !ctr.config.PostConfigureNetNS {
180
			// Rather than destroying the jail immediately, reset the
181
			// persist flag so that it will live until the container is
182
			// done.
183
			netjail, err := jail.FindByName(ctr.state.NetNS)
184
			if err != nil {
185
				return fmt.Errorf("finding network jail %s: %w", ctr.state.NetNS, err)
186
			}
187
			jconf := jail.NewConfig()
188
			jconf.Set("persist", false)
189
			if err := netjail.Set(jconf); err != nil {
190
				return fmt.Errorf("releasing network jail %s: %w", ctr.state.NetNS, err)
191
			}
192
		}
193
		ctr.state.NetNS = ""
194
	}
195
	return nil
196
}
197

198
// TODO (5.0): return the statistics per network interface
199
// This would allow better compat with docker.
200
func getContainerNetIO(ctr *Container) (map[string]define.ContainerNetworkStats, error) {
201
	if ctr.state.NetNS == "" {
202
		// If NetNS is nil, it was set as none, and no netNS
203
		// was set up this is a valid state and thus return no
204
		// error, nor any statistics
205
		return nil, nil
206
	}
207

208
	// First try running 'netstat -j' - this lets us retrieve stats from
209
	// containers which don't have a separate vnet jail.
210
	cmd := exec.Command("netstat", "-j", ctr.state.NetNS, "-bi", "--libxo", "json")
211
	out, err := cmd.Output()
212
	if err != nil {
213
		// Fall back to using jexec so that this still works on 13.2
214
		// which does not have the -j flag.
215
		cmd := exec.Command("jexec", ctr.state.NetNS, "netstat", "-bi", "--libxo", "json")
216
		out, err = cmd.Output()
217
	}
218
	if err != nil {
219
		return nil, fmt.Errorf("failed to read network stats: %v", err)
220
	}
221
	stats := Netstat{}
222
	if err := jdec.Unmarshal(out, &stats); err != nil {
223
		return nil, err
224
	}
225

226
	res := make(map[string]define.ContainerNetworkStats)
227

228
	// Sum all the interface stats - in practice only Tx/TxBytes are needed
229
	for _, ifaddr := range stats.Statistics.Interface {
230
		// Each interface has two records, one for link-layer which has
231
		// an MTU field and one for IP which doesn't. We only want the
232
		// link-layer stats.
233
		//
234
		// It's not clear if we should include loopback stats here but
235
		// if we move to per-interface stats in future, this can be
236
		// reported separately.
237
		if ifaddr.Mtu > 0 {
238
			linkStats := define.ContainerNetworkStats{
239
				RxPackets: ifaddr.ReceivedPackets,
240
				TxPackets: ifaddr.SentPackets,
241
				RxBytes:   ifaddr.ReceivedBytes,
242
				TxBytes:   ifaddr.SentBytes,
243
				RxErrors:  ifaddr.ReceivedErrors,
244
				TxErrors:  ifaddr.SentErrors,
245
				RxDropped: ifaddr.DroppedPackets,
246
			}
247
			res[ifaddr.Name] = linkStats
248
		}
249
	}
250

251
	return res, nil
252
}
253

254
func (c *Container) joinedNetworkNSPath() (string, bool) {
255
	return c.state.NetNS, false
256
}
257

258
func (c *Container) inspectJoinedNetworkNS(networkns string) (q types.StatusBlock, retErr error) {
259
	// TODO: extract interface information from the vnet jail
260
	return types.StatusBlock{}, nil
261

262
}
263

264
func (c *Container) reloadRootlessRLKPortMapping() error {
265
	return errors.New("unsupported (*Container).reloadRootlessRLKPortMapping")
266
}
267

268
func (c *Container) setupRootlessNetwork() error {
269
	return nil
270
}
271

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.