spiegel_podman/libpod/network/netavark/run.go
Paul Holzinger 044edbb9c9
Fix netavark error handling and teardown issue
The return error was not returned by podman , instead a different error
was created. Also make sure to free assigned ips on an error to not leak
them.

Lastly podman container cleanup uses the default network backend instead
of the provided one, we need to add `--network-backend` to the exit
command.

[NO NEW TESTS NEEDED]

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2021-11-22 17:49:55 +01:00

127 lines
3.4 KiB
Go

// +build linux
package netavark
import (
"encoding/json"
"fmt"
"github.com/containers/podman/v3/libpod/network/internal/util"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/pkg/errors"
"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, errors.Wrap(err, "failed to convert net opts")
}
// 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 errors.Wrap(err, "failed to convert net opts")
}
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) 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
}