From 02c6e8791b645d7e547b563102a4c1a6c8460955 Mon Sep 17 00:00:00 2001 From: Thomas Lefebvre Date: Fri, 20 May 2022 22:17:20 +0000 Subject: [PATCH] When encountering an error while deleting an ip in sandbox networking mode, check the ip is still on the interface When multiple ipv4 ips are added on interfaces, gvisor fails to delete the additional ips from the interface in sandbox networking mode with the following error: starting container: setting up network: creating interfaces from net namespace "/proc/909056/ns/net": removing address 10.0.2.101/24 from device "tun0": cannot assign requested address This is due to the fact that additional ips on these interfaces are tagged as secondary ips. When gvisor deletes the primary ip, secondary ips get deleted at the same time and cease to exist on the interface. --- runsc/sandbox/network.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/runsc/sandbox/network.go b/runsc/sandbox/network.go index 4d8dc6be8..613f6cdec 100644 --- a/runsc/sandbox/network.go +++ b/runsc/sandbox/network.go @@ -264,6 +264,13 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG // Steal IP address from NIC. if err := removeAddress(ifaceLink, addr.String()); err != nil { + // If we encounter an error while deleting the ip, + // verify the ip is still present on the interface. + if present, err := isAddressOnInterface(iface.Name, addr); err != nil { + return fmt.Errorf("checking if address %v is on interface %q: %w", addr, iface.Name, err) + } else if !present { + continue + } return fmt.Errorf("removing address %v from device %q: %w", addr, iface.Name, err) } } @@ -278,6 +285,29 @@ func createInterfacesAndRoutesFromNS(conn *urpc.Client, nsPath string, hardwareG return nil } +// isAddressOnInterface checks if an address is on an interface +func isAddressOnInterface(ifaceName string, addr *net.IPNet) (bool, error) { + iface, err := net.InterfaceByName(ifaceName) + if err != nil { + return false, fmt.Errorf("getting interface by name %q: %w", ifaceName, err) + } + ifaceAddrs, err := iface.Addrs() + if err != nil { + return false, fmt.Errorf("fetching interface addresses for %q: %w", iface.Name, err) + } + for _, ifaceAddr := range ifaceAddrs { + ipNet, ok := ifaceAddr.(*net.IPNet) + if !ok { + log.Warningf("Can't cast address to *net.IPNet, skipping: %+v", ifaceAddr) + continue + } + if ipNet.String() == addr.String() { + return true, nil + } + } + return false, nil +} + type socketEntry struct { deviceFile *os.File gsoMaxSize uint32