veth: allow configuring peer attributes beyond namespace and address

Signed-off-by: Gwendolyn <me@gwendolyn.dev>
This commit is contained in:
Gwendolyn
2025-04-27 21:06:13 +02:00
committed by Alessandro Boch
parent 9d88d8385b
commit a2e4b9a6ec
3 changed files with 163 additions and 24 deletions

11
link.go
View File

@@ -426,6 +426,17 @@ type Veth struct {
PeerName string // veth on create only PeerName string // veth on create only
PeerHardwareAddr net.HardwareAddr PeerHardwareAddr net.HardwareAddr
PeerNamespace interface{} PeerNamespace interface{}
PeerTxQLen int
PeerNumTxQueues uint32
PeerNumRxQueues uint32
PeerMTU uint32
}
func NewVeth(attr LinkAttrs) *Veth {
return &Veth{
LinkAttrs: attr,
PeerTxQLen: -1,
}
} }
func (veth *Veth) Attrs() *LinkAttrs { func (veth *Veth) Attrs() *LinkAttrs {

View File

@@ -1696,16 +1696,25 @@ func (h *Handle) linkModify(link Link, flags int) error {
peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil) peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC) nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
if base.TxQLen >= 0 {
if link.PeerTxQLen >= 0 {
peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(link.PeerTxQLen)))
} else if base.TxQLen >= 0 {
peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
} }
if base.NumTxQueues > 0 { if link.PeerNumTxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(link.PeerNumTxQueues))
} else if base.NumTxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues))) peer.AddRtAttr(unix.IFLA_NUM_TX_QUEUES, nl.Uint32Attr(uint32(base.NumTxQueues)))
} }
if base.NumRxQueues > 0 { if link.PeerNumRxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(link.PeerNumRxQueues))
} else if base.NumRxQueues > 0 {
peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues))) peer.AddRtAttr(unix.IFLA_NUM_RX_QUEUES, nl.Uint32Attr(uint32(base.NumRxQueues)))
} }
if base.MTU > 0 { if link.PeerMTU > 0 {
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(link.PeerMTU))
} else if base.MTU > 0 {
peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
} }
if link.PeerHardwareAddr != nil { if link.PeerHardwareAddr != nil {

View File

@@ -1123,17 +1123,16 @@ func TestLinkAddDelVeth(t *testing.T) {
peerMAC, _ := net.ParseMAC("00:12:34:56:78:02") peerMAC, _ := net.ParseMAC("00:12:34:56:78:02")
veth := &Veth{ veth := NewVeth(LinkAttrs{
LinkAttrs: LinkAttrs{ Name: "foo",
Name: "foo", TxQLen: testTxQLen,
TxQLen: testTxQLen, MTU: 1400,
MTU: 1400, NumTxQueues: testTxQueues,
NumTxQueues: testTxQueues, NumRxQueues: testRxQueues,
NumRxQueues: testRxQueues, })
},
PeerName: "bar", veth.PeerName = "bar"
PeerHardwareAddr: peerMAC, veth.PeerHardwareAddr = peerMAC
}
testLinkAddDel(t, veth) testLinkAddDel(t, veth)
} }
@@ -1168,7 +1167,8 @@ func TestLinkAddVethWithDefaultTxQLen(t *testing.T) {
la := NewLinkAttrs() la := NewLinkAttrs()
la.Name = "foo" la.Name = "foo"
veth := &Veth{LinkAttrs: la, PeerName: "bar"} veth := NewVeth(la)
veth.PeerName = "bar"
if err := LinkAdd(veth); err != nil { if err := LinkAdd(veth); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1203,7 +1203,8 @@ func TestLinkAddVethWithZeroTxQLen(t *testing.T) {
la.Name = "foo" la.Name = "foo"
la.TxQLen = 0 la.TxQLen = 0
veth := &Veth{LinkAttrs: la, PeerName: "bar"} veth := NewVeth(la)
veth.PeerName = "bar"
if err := LinkAdd(veth); err != nil { if err := LinkAdd(veth); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1231,6 +1232,124 @@ func TestLinkAddVethWithZeroTxQLen(t *testing.T) {
} }
} }
func TestLinkAddVethWithPeerAttrs(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
la := NewLinkAttrs()
la.Name = "foo"
la.MTU = 1500
la.TxQLen = 500
la.NumRxQueues = 2
la.NumTxQueues = 3
veth := NewVeth(la)
veth.PeerName = "bar"
veth.PeerMTU = 1400
veth.PeerTxQLen = 1000
veth.PeerNumRxQueues = 4
veth.PeerNumTxQueues = 5
if err := LinkAdd(veth); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if veth, ok := link.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.MTU != 1500 {
t.Fatalf("MTU is %d, should be %d", veth.MTU, 1500)
}
if veth.TxQLen != 500 {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 500)
}
if veth.NumRxQueues != 2 {
t.Fatalf("NumRxQueues is %d, should be %d", veth.NumRxQueues, 2)
}
if veth.NumTxQueues != 3 {
t.Fatalf("NumTxQueues is %d, should be %d", veth.NumTxQueues, 3)
}
}
peer, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if veth, ok := peer.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.MTU != 1400 {
t.Fatalf("Peer MTU is %d, should be %d", veth.MTU, 1400)
}
if veth.TxQLen != 1000 {
t.Fatalf("Peer TxQLen is %d, should be %d", veth.TxQLen, 1000)
}
if veth.NumRxQueues != 4 {
t.Fatalf("Peer NumRxQueues is %d, should be %d", veth.NumRxQueues, 4)
}
if veth.NumTxQueues != 5 {
t.Fatalf("Peer NumTxQueues is %d, should be %d", veth.NumTxQueues, 5)
}
}
}
func TestLinkAddVethWithoutPeerAttrs(t *testing.T) {
tearDown := setUpNetlinkTest(t)
defer tearDown()
la := NewLinkAttrs()
la.Name = "foo"
la.MTU = 1500
la.TxQLen = 500
la.NumRxQueues = 2
la.NumTxQueues = 3
veth := NewVeth(la)
veth.PeerName = "bar"
if err := LinkAdd(veth); err != nil {
t.Fatal(err)
}
link, err := LinkByName("foo")
if err != nil {
t.Fatal(err)
}
if veth, ok := link.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.MTU != 1500 {
t.Fatalf("MTU is %d, should be %d", veth.MTU, 1500)
}
if veth.TxQLen != 500 {
t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 500)
}
if veth.NumRxQueues != 2 {
t.Fatalf("NumRxQueues is %d, should be %d", veth.NumRxQueues, 2)
}
if veth.NumTxQueues != 3 {
t.Fatalf("NumTxQueues is %d, should be %d", veth.NumTxQueues, 3)
}
}
peer, err := LinkByName("bar")
if err != nil {
t.Fatal(err)
}
if veth, ok := peer.(*Veth); !ok {
t.Fatalf("unexpected link type: %T", link)
} else {
if veth.MTU != 1500 {
t.Fatalf("Peer MTU is %d, should be %d", veth.MTU, 1500)
}
if veth.TxQLen != 500 {
t.Fatalf("Peer TxQLen is %d, should be %d", veth.TxQLen, 500)
}
if veth.NumRxQueues != 2 {
t.Fatalf("Peer NumRxQueues is %d, should be %d", veth.NumRxQueues, 2)
}
if veth.NumTxQueues != 3 {
t.Fatalf("Peer NumTxQueues is %d, should be %d", veth.NumTxQueues, 3)
}
}
}
func TestLinkAddDelDummyWithGSO(t *testing.T) { func TestLinkAddDelDummyWithGSO(t *testing.T) {
const ( const (
gsoMaxSegs = 16 gsoMaxSegs = 16
@@ -1449,7 +1568,7 @@ func TestLinkSetNs(t *testing.T) {
} }
defer newns.Close() defer newns.Close()
link := &Veth{LinkAttrs{Name: "foo"}, "bar", nil, nil} link := &Veth{LinkAttrs: LinkAttrs{Name: "foo"}, PeerName: "bar"}
if err := LinkAdd(link); err != nil { if err := LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1520,7 +1639,7 @@ func TestVethPeerNs(t *testing.T) {
} }
defer newns.Close() defer newns.Close()
link := &Veth{LinkAttrs{Name: "foo"}, "bar", nil, NsFd(basens)} link := &Veth{LinkAttrs: LinkAttrs{Name: "foo"}, PeerName: "bar", PeerNamespace: NsFd(basens)}
if err := LinkAdd(link); err != nil { if err := LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -1573,7 +1692,7 @@ func TestVethPeerNs2(t *testing.T) {
} }
defer twons.Close() defer twons.Close()
link := &Veth{LinkAttrs{Name: "foo", Namespace: NsFd(onens)}, "bar", nil, NsFd(basens)} link := &Veth{LinkAttrs: LinkAttrs{Name: "foo", Namespace: NsFd(onens)}, PeerName: "bar", PeerNamespace: NsFd(basens)}
if err := LinkAdd(link); err != nil { if err := LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -2132,7 +2251,7 @@ func TestLinkSubscribe(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} link := &Veth{LinkAttrs: LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, PeerName: "bar"}
if err := LinkAdd(link); err != nil { if err := LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -2179,7 +2298,7 @@ func TestLinkSubscribeWithOptions(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
link := &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} link := &Veth{LinkAttrs: LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, PeerName: "bar"}
if err := LinkAdd(link); err != nil { if err := LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -2213,7 +2332,7 @@ func TestLinkSubscribeAt(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} link := &Veth{LinkAttrs: LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, PeerName: "bar"}
if err := nh.LinkAdd(link); err != nil { if err := nh.LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -2255,7 +2374,7 @@ func TestLinkSubscribeListExisting(t *testing.T) {
} }
defer nh.Close() defer nh.Close()
link := &Veth{LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, "bar", nil, nil} link := &Veth{LinkAttrs: LinkAttrs{Name: "test", TxQLen: testTxQLen, MTU: 1400}, PeerName: "bar"}
if err := nh.LinkAdd(link); err != nil { if err := nh.LinkAdd(link); err != nil {
t.Fatal(err) t.Fatal(err)
} }