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 <dcbw@redhat.com>
This commit is contained in:
Dan Williams 2021-07-21 09:39:06 -05:00
parent f14ff6687a
commit a49f908168
2 changed files with 11 additions and 17 deletions

View File

@ -32,14 +32,16 @@ var (
ErrLinkNotFound = errors.New("link not found") 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{ veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{ LinkAttrs: netlink.LinkAttrs{
Name: name, Name: name,
Flags: net.FlagUp, Flags: net.FlagUp,
MTU: mtu, MTU: mtu,
}, },
PeerName: peer, PeerName: peer,
PeerNamespace: netlink.NsFd(int(hostNS.Fd())),
} }
if mac != "" { if mac != "" {
m, err := net.ParseMAC(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 { if err := netlink.LinkAdd(veth); err != nil {
return nil, err 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) veth2, err := netlink.LinkByName(name)
if err != nil { if err != nil {
netlink.LinkDel(veth) // try and clean up the link if possible. netlink.LinkDel(veth) // try and clean up the link if possible.
@ -68,7 +70,7 @@ func peerExists(name string) bool {
return true 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++ { for i := 0; i < 10; i++ {
if vethPeerName != "" { if vethPeerName != "" {
peerName = 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 { switch {
case err == nil: case err == nil:
return 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. // hostVethName: If hostVethName is not specified, the host-side veth name will use a random string.
// On success, SetupVethWithName returns (hostVeth, containerVeth, nil) // On success, SetupVethWithName returns (hostVeth, containerVeth, nil)
func SetupVethWithName(contVethName, hostVethName string, mtu int, contVethMac string, hostNS ns.NetNS) (net.Interface, net.Interface, error) { 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 { if err != nil {
return net.Interface{}, net.Interface{}, err 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) return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err)
} }
hostVeth, err := netlink.LinkByName(hostVethName) var hostVeth netlink.Link
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)
}
err = hostNS.Do(func(_ ns.NetNS) error { err = hostNS.Do(func(_ ns.NetNS) error {
hostVeth, err = netlink.LinkByName(hostVethName) hostVeth, err = netlink.LinkByName(hostVethName)
if err != nil { if err != nil {

View File

@ -188,8 +188,8 @@ var _ = Describe("Link", func() {
_ = containerNetNS.Do(func(ns.NetNS) error { _ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS) _, _, 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 return nil
}) })
}) })