From a49f908168cbd71d0ef0c6e59f374bf5b6fa852d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Jul 2021 09:39:06 -0500 Subject: [PATCH] ip: place veth peer in host namspace directly Instead of moving the host side of the veth peer into the host network namespace later, just create it in the host namespace directly. Signed-off-by: Dan Williams --- pkg/ip/link_linux.go | 24 +++++++++--------------- pkg/ip/link_linux_test.go | 4 ++-- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/pkg/ip/link_linux.go b/pkg/ip/link_linux.go index e353f4be..94e14f22 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 b260f471..c57f9369 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 }) })