diff --git a/pkg/ip/link_linux.go b/pkg/ip/link_linux.go index e353f4be6..94e14f228 100644 --- a/pkg/ip/link_linux.go +++ b/pkg/ip/link_linux.go @@ -32,14 +32,16 @@ var ( ErrLinkNotFound = errors.New("link not found") ) -func makeVethPair(name, peer string, mtu int, mac string) (netlink.Link, error) { +// makeVethPair is called from within the container's network namespace +func makeVethPair(name, peer string, mtu int, mac string, hostNS ns.NetNS) (netlink.Link, error) { veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{ Name: name, Flags: net.FlagUp, MTU: mtu, }, - PeerName: peer, + PeerName: peer, + PeerNamespace: netlink.NsFd(int(hostNS.Fd())), } if mac != "" { m, err := net.ParseMAC(mac) @@ -51,7 +53,7 @@ func makeVethPair(name, peer string, mtu int, mac string) (netlink.Link, error) if err := netlink.LinkAdd(veth); err != nil { return nil, err } - // Re-fetch the link to get its creation-time parameters, e.g. index and mac + // Re-fetch the container link to get its creation-time parameters, e.g. index and mac veth2, err := netlink.LinkByName(name) if err != nil { netlink.LinkDel(veth) // try and clean up the link if possible. @@ -68,7 +70,7 @@ func peerExists(name string) bool { return true } -func makeVeth(name, vethPeerName string, mtu int, mac string) (peerName string, veth netlink.Link, err error) { +func makeVeth(name, vethPeerName string, mtu int, mac string, hostNS ns.NetNS) (peerName string, veth netlink.Link, err error) { for i := 0; i < 10; i++ { if vethPeerName != "" { peerName = vethPeerName @@ -79,7 +81,7 @@ func makeVeth(name, vethPeerName string, mtu int, mac string) (peerName string, } } - veth, err = makeVethPair(name, peerName, mtu, mac) + veth, err = makeVethPair(name, peerName, mtu, mac, hostNS) switch { case err == nil: return @@ -139,7 +141,7 @@ func ifaceFromNetlinkLink(l netlink.Link) net.Interface { // hostVethName: If hostVethName is not specified, the host-side veth name will use a random string. // On success, SetupVethWithName returns (hostVeth, containerVeth, nil) func SetupVethWithName(contVethName, hostVethName string, mtu int, contVethMac string, hostNS ns.NetNS) (net.Interface, net.Interface, error) { - hostVethName, contVeth, err := makeVeth(contVethName, hostVethName, mtu, contVethMac) + hostVethName, contVeth, err := makeVeth(contVethName, hostVethName, mtu, contVethMac, hostNS) if err != nil { return net.Interface{}, net.Interface{}, err } @@ -148,15 +150,7 @@ func SetupVethWithName(contVethName, hostVethName string, mtu int, contVethMac s return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err) } - hostVeth, err := netlink.LinkByName(hostVethName) - if err != nil { - return net.Interface{}, net.Interface{}, fmt.Errorf("failed to lookup %q: %v", hostVethName, err) - } - - if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil { - return net.Interface{}, net.Interface{}, fmt.Errorf("failed to move veth to host netns: %v", err) - } - + var hostVeth netlink.Link err = hostNS.Do(func(_ ns.NetNS) error { hostVeth, err = netlink.LinkByName(hostVethName) if err != nil { diff --git a/pkg/ip/link_linux_test.go b/pkg/ip/link_linux_test.go index b260f4711..c57f9369e 100644 --- a/pkg/ip/link_linux_test.go +++ b/pkg/ip/link_linux_test.go @@ -188,8 +188,8 @@ var _ = Describe("Link", func() { _ = containerNetNS.Do(func(ns.NetNS) error { defer GinkgoRecover() _, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS) - Expect(err.Error()).To(HavePrefix("failed to move veth to host netns: ")) - + Expect(err.Error()).To(HavePrefix("container veth name provided")) + Expect(err.Error()).To(HaveSuffix("already exists")) return nil }) })