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
|
//go:build linux || freebsd
// +build linux freebsd
package netavark
import (
"encoding/json"
"fmt"
"strconv"
"github.com/containers/common/libnetwork/internal/util"
"github.com/containers/common/libnetwork/types"
"github.com/sirupsen/logrus"
)
type netavarkOptions struct {
types.NetworkOptions
Networks map[string]*types.Network `json:"network_info"`
}
// Setup will setup the container network namespace. It returns
// a map of StatusBlocks, the key is the network name.
func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions) (map[string]types.StatusBlock, error) {
n.lock.Lock()
defer n.lock.Unlock()
err := n.loadNetworks()
if err != nil {
return nil, err
}
err = util.ValidateSetupOptions(n, namespacePath, options)
if err != nil {
return nil, err
}
// allocate IPs in the IPAM db
err = n.allocIPs(&options.NetworkOptions)
if err != nil {
return nil, err
}
netavarkOpts, err := n.convertNetOpts(options.NetworkOptions)
if err != nil {
return nil, fmt.Errorf("failed to convert net opts: %w", err)
}
// Warn users if one or more networks have dns enabled
// but aardvark-dns binary is not configured
for _, network := range netavarkOpts.Networks {
if network != nil && network.DNSEnabled && n.aardvarkBinary == "" {
// this is not a fatal error we can still use container without dns
logrus.Warnf("aardvark-dns binary not found, container dns will not be enabled")
break
}
}
// trace output to get the json
if logrus.IsLevelEnabled(logrus.TraceLevel) {
b, err := json.Marshal(&netavarkOpts)
if err != nil {
return nil, err
}
// show the full netavark command so we can easily reproduce errors from the cli
logrus.Tracef("netavark command: printf '%s' | %s setup %s", string(b), n.netavarkBinary, namespacePath)
}
result := map[string]types.StatusBlock{}
err = n.execNetavark([]string{"setup", namespacePath}, netavarkOpts, &result)
if err != nil {
// lets dealloc ips to prevent leaking
if err := n.deallocIPs(&options.NetworkOptions); err != nil {
logrus.Error(err)
}
return nil, err
}
// make sure that the result makes sense
if len(result) != len(options.Networks) {
logrus.Errorf("unexpected netavark result: %v", result)
return nil, fmt.Errorf("unexpected netavark result length, want (%d), got (%d) networks", len(options.Networks), len(result))
}
return result, err
}
// Teardown will teardown the container network namespace.
func (n *netavarkNetwork) Teardown(namespacePath string, options types.TeardownOptions) error {
n.lock.Lock()
defer n.lock.Unlock()
err := n.loadNetworks()
if err != nil {
return err
}
// get IPs from the IPAM db
err = n.getAssignedIPs(&options.NetworkOptions)
if err != nil {
// when there is an error getting the ips we should still continue
// to call teardown for netavark to prevent leaking network interfaces
logrus.Error(err)
}
netavarkOpts, err := n.convertNetOpts(options.NetworkOptions)
if err != nil {
return fmt.Errorf("failed to convert net opts: %w", err)
}
retErr := n.execNetavark([]string{"teardown", namespacePath}, netavarkOpts, nil)
// when netavark returned an error we still free the used ips
// otherwise we could end up in a state where block the ips forever
err = n.deallocIPs(&netavarkOpts.NetworkOptions)
if err != nil {
if retErr != nil {
logrus.Error(err)
} else {
retErr = err
}
}
return retErr
}
func (n *netavarkNetwork) getCommonNetavarkOptions() []string {
return []string{"--config", n.networkRunDir, "--rootless=" + strconv.FormatBool(n.networkRootless), "--aardvark-binary=" + n.aardvarkBinary}
}
func (n *netavarkNetwork) convertNetOpts(opts types.NetworkOptions) (*netavarkOptions, error) {
netavarkOptions := netavarkOptions{
NetworkOptions: opts,
Networks: make(map[string]*types.Network, len(opts.Networks)),
}
for network := range opts.Networks {
net, err := n.getNetwork(network)
if err != nil {
return nil, err
}
netavarkOptions.Networks[network] = net
}
return &netavarkOptions, nil
}
|