diff --git a/link.go b/link.go index 06ce290..c9d960d 100644 --- a/link.go +++ b/link.go @@ -341,6 +341,7 @@ type Veth struct { LinkAttrs PeerName string // veth on create only PeerHardwareAddr net.HardwareAddr + PeerNamespace interface{} } func (veth *Veth) Attrs() *LinkAttrs { diff --git a/link_linux.go b/link_linux.go index f855950..53cc08e 100644 --- a/link_linux.go +++ b/link_linux.go @@ -1345,6 +1345,16 @@ func (h *Handle) linkModify(link Link, flags int) error { if link.PeerHardwareAddr != nil { peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr)) } + if link.PeerNamespace != nil { + switch ns := link.PeerNamespace.(type) { + case NsPid: + val := nl.Uint32Attr(uint32(ns)) + peer.AddRtAttr(unix.IFLA_NET_NS_PID, val) + case NsFd: + val := nl.Uint32Attr(uint32(ns)) + peer.AddRtAttr(unix.IFLA_NET_NS_FD, val) + } + } case *Vxlan: addVxlanAttrs(link, linkInfo) case *Bond: diff --git a/link_test.go b/link_test.go index af52a6a..8911af8 100644 --- a/link_test.go +++ b/link_test.go @@ -1024,7 +1024,7 @@ func TestLinkSetNs(t *testing.T) { } defer newns.Close() - link := &Veth{LinkAttrs{Name: "foo"}, "bar", nil} + link := &Veth{LinkAttrs{Name: "foo"}, "bar", nil, nil} if err := LinkAdd(link); err != nil { t.Fatal(err) } @@ -1079,6 +1079,111 @@ func TestLinkAddDelWireguard(t *testing.T) { testLinkAddDel(t, &Wireguard{LinkAttrs: LinkAttrs{Name: "wg0"}}) } +func TestVethPeerNs(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + basens, err := netns.Get() + if err != nil { + t.Fatal("Failed to get basens") + } + defer basens.Close() + + newns, err := netns.New() + if err != nil { + t.Fatal("Failed to create newns") + } + defer newns.Close() + + link := &Veth{LinkAttrs{Name: "foo"}, "bar", nil, NsFd(basens)} + if err := LinkAdd(link); err != nil { + t.Fatal(err) + } + + _, err = LinkByName("bar") + if err == nil { + t.Fatal("Link bar is in newns") + } + + err = netns.Set(basens) + if err != nil { + t.Fatal("Failed to set basens") + } + + _, err = LinkByName("bar") + if err != nil { + t.Fatal("Link bar is not in basens") + } + + err = netns.Set(newns) + if err != nil { + t.Fatal("Failed to set newns") + } + + _, err = LinkByName("foo") + if err != nil { + t.Fatal("Link foo is not in newns") + } +} + +func TestVethPeerNs2(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + + basens, err := netns.Get() + if err != nil { + t.Fatal("Failed to get basens") + } + defer basens.Close() + + onens, err := netns.New() + if err != nil { + t.Fatal("Failed to create newns") + } + defer onens.Close() + + twons, err := netns.New() + if err != nil { + t.Fatal("Failed to create twons") + } + defer twons.Close() + + link := &Veth{LinkAttrs{Name: "foo", Namespace: NsFd(onens)}, "bar", nil, NsFd(basens)} + if err := LinkAdd(link); err != nil { + t.Fatal(err) + } + + _, err = LinkByName("foo") + if err == nil { + t.Fatal("Link foo is in twons") + } + + _, err = LinkByName("bar") + if err == nil { + t.Fatal("Link bar is in twons") + } + + err = netns.Set(basens) + if err != nil { + t.Fatal("Failed to set basens") + } + + _, err = LinkByName("bar") + if err != nil { + t.Fatal("Link bar is not in basens") + } + + err = netns.Set(onens) + if err != nil { + t.Fatal("Failed to set onens") + } + + _, err = LinkByName("foo") + if err != nil { + t.Fatal("Link foo is not in onens") + } +} + func TestLinkAddDelVxlan(t *testing.T) { tearDown := setUpNetlinkTest(t) defer tearDown() @@ -1468,7 +1573,7 @@ func TestLinkSubscribe(t *testing.T) { t.Fatal(err) } - link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil} + link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} if err := LinkAdd(link); err != nil { t.Fatal(err) } @@ -1515,7 +1620,7 @@ func TestLinkSubscribeWithOptions(t *testing.T) { t.Fatal(err) } - link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil} + link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} if err := LinkAdd(link); err != nil { t.Fatal(err) } @@ -1549,7 +1654,7 @@ func TestLinkSubscribeAt(t *testing.T) { t.Fatal(err) } - link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil} + link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} if err := nh.LinkAdd(link); err != nil { t.Fatal(err) } @@ -1591,7 +1696,7 @@ func TestLinkSubscribeListExisting(t *testing.T) { } defer nh.Delete() - link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil} + link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} if err := nh.LinkAdd(link); err != nil { t.Fatal(err) }