From 8ef3239b0b55d50a4714cf7985fe11661d652221 Mon Sep 17 00:00:00 2001 From: Jing Chen Date: Mon, 24 Jun 2024 16:54:47 -0700 Subject: [PATCH] Add SetMTU to change the mtu of device. The method will be primarily used with RTM_[NEW|SET]LINK when IFLA_MTU is present. PiperOrigin-RevId: 646264847 --- pkg/tcpip/link/channel/channel.go | 15 ++++++++-- pkg/tcpip/link/channel/channel_test.go | 14 ++++++++++ pkg/tcpip/link/fdbased/endpoint.go | 19 +++++++++---- pkg/tcpip/link/fdbased/endpoint_test.go | 13 +++++++++ pkg/tcpip/link/loopback/loopback.go | 3 ++ pkg/tcpip/link/muxed/injectable.go | 7 +++++ pkg/tcpip/link/muxed/injectable_test.go | 13 +++++++++ pkg/tcpip/link/nested/nested.go | 5 ++++ pkg/tcpip/link/nested/nested_test.go | 26 +++++++++++++++++ .../link/packetsocket/packetsocket_test.go | 1 + pkg/tcpip/link/pipe/pipe.go | 12 +++++++- pkg/tcpip/link/pipe/pipe_test.go | 14 ++++++++++ pkg/tcpip/link/sharedmem/sharedmem.go | 18 ++++++++---- pkg/tcpip/link/sharedmem/sharedmem_server.go | 18 ++++++++---- .../link/sharedmem/sharedmem_server_test.go | 28 +++++++++++++++++++ pkg/tcpip/link/sharedmem/sharedmem_test.go | 14 ++++++++++ pkg/tcpip/link/veth/veth.go | 15 ++++++++-- pkg/tcpip/link/veth/veth_test.go | 14 ++++++++++ pkg/tcpip/link/waitable/waitable.go | 6 ++++ pkg/tcpip/link/waitable/waitable_test.go | 4 +++ pkg/tcpip/link/xdp/endpoint.go | 3 ++ .../network/internal/testutil/testutil.go | 3 ++ pkg/tcpip/network/ip_test.go | 2 ++ pkg/tcpip/stack/bridge.go | 12 +++++++- pkg/tcpip/stack/bridge_test.go | 12 ++++++++ pkg/tcpip/stack/forwarding_test.go | 8 ++++-- pkg/tcpip/stack/registration.go | 3 ++ pkg/tcpip/transport/datagram_test.go | 1 + 28 files changed, 276 insertions(+), 27 deletions(-) diff --git a/pkg/tcpip/link/channel/channel.go b/pkg/tcpip/link/channel/channel.go index 334dc542c..39529cab9 100644 --- a/pkg/tcpip/link/channel/channel.go +++ b/pkg/tcpip/link/channel/channel.go @@ -139,7 +139,6 @@ var _ stack.GSOEndpoint = (*Endpoint)(nil) // // +stateify savable type Endpoint struct { - mtu uint32 LinkEPCapabilities stack.LinkEndpointCapabilities SupportedGSOKind stack.SupportedGSO @@ -148,6 +147,8 @@ type Endpoint struct { dispatcher stack.NetworkDispatcher // +checklocks:mu linkAddr tcpip.LinkAddress + // +checklocks:mu + mtu uint32 // Outbound packet queue. q *queue @@ -223,12 +224,20 @@ func (e *Endpoint) IsAttached() bool { return e.dispatcher != nil } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *Endpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +// SetMTU implements stack.LinkEndpoint.SetMTU. +func (e *Endpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { return e.LinkEPCapabilities diff --git a/pkg/tcpip/link/channel/channel_test.go b/pkg/tcpip/link/channel/channel_test.go index 5d5139157..548891e1d 100644 --- a/pkg/tcpip/link/channel/channel_test.go +++ b/pkg/tcpip/link/channel/channel_test.go @@ -32,3 +32,17 @@ func TestSetLinkAddress(t *testing.T) { } } } + +func TestSetMTU(t *testing.T) { + expectedMTU := []uint32{1000, 3000} + size, mtu := 10, uint32(2000) + e := New(size, mtu, tcpip.LinkAddress("xyz")) + defer e.Close() + for _, mtu := range expectedMTU { + e.SetMTU(mtu) + + if want, v := mtu, e.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index bfe2e7a70..431c0fdeb 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -120,9 +120,6 @@ type endpoint struct { // hash outbound packets to specific channels based on the packet hash. fds []fdInfo - // mtu (maximum transmission unit) is the maximum size of a packet. - mtu uint32 - // hdrSize specifies the link-layer header size. If set to 0, no header // is added/removed; otherwise an ethernet header is used. hdrSize int @@ -172,6 +169,10 @@ type endpoint struct { // // +checklocks:mu addr tcpip.LinkAddress + + // mtu (maximum transmission unit) is the maximum size of a packet. + // +checklocks:mu + mtu uint32 } // Options specify the details about the fd-based endpoint to be created. @@ -454,12 +455,20 @@ func (e *endpoint) IsAttached() bool { return e.dispatcher != nil } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *endpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +// SetMTU implements stack.LinkEndpoint.SetMTU. +func (e *endpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities { return e.caps diff --git a/pkg/tcpip/link/fdbased/endpoint_test.go b/pkg/tcpip/link/fdbased/endpoint_test.go index 975b5571e..601a6308e 100644 --- a/pkg/tcpip/link/fdbased/endpoint_test.go +++ b/pkg/tcpip/link/fdbased/endpoint_test.go @@ -194,6 +194,19 @@ func TestSetAddress(t *testing.T) { } } +func TestMTU(t *testing.T) { + mtus := []uint32{200, 300} + c := newContext(t, &Options{MTU: mtu}) + defer c.cleanup() + for _, m := range mtus { + c.ep.SetMTU(m) + + if want, v := m, c.ep.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash uint32) { c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: eth, GSOMaxSize: gsoMaxSize}) defer c.cleanup() diff --git a/pkg/tcpip/link/loopback/loopback.go b/pkg/tcpip/link/loopback/loopback.go index 3ebf4acbc..cfcd6a87d 100644 --- a/pkg/tcpip/link/loopback/loopback.go +++ b/pkg/tcpip/link/loopback/loopback.go @@ -62,6 +62,9 @@ func (*endpoint) MTU() uint32 { return 65536 } +// SetMTU implements stack.LinkEndpoint.SetMTU. It has no impact. +func (*endpoint) SetMTU(uint32) {} + // Capabilities implements stack.LinkEndpoint.Capabilities. Loopback advertises // itself as supporting checksum offload, but in reality it's just omitted. func (*endpoint) Capabilities() stack.LinkEndpointCapabilities { diff --git a/pkg/tcpip/link/muxed/injectable.go b/pkg/tcpip/link/muxed/injectable.go index 1a5f3aa70..aafc3ac02 100644 --- a/pkg/tcpip/link/muxed/injectable.go +++ b/pkg/tcpip/link/muxed/injectable.go @@ -49,6 +49,13 @@ func (m *InjectableEndpoint) MTU() uint32 { return minMTU } +// SetMTU implements stack.LinkEndpoint. +func (m *InjectableEndpoint) SetMTU(mtu uint32) { + for _, endpoint := range m.routes { + endpoint.SetMTU(mtu) + } +} + // Capabilities implements stack.LinkEndpoint. func (m *InjectableEndpoint) Capabilities() stack.LinkEndpointCapabilities { minCapabilities := stack.LinkEndpointCapabilities(^uint(0)) diff --git a/pkg/tcpip/link/muxed/injectable_test.go b/pkg/tcpip/link/muxed/injectable_test.go index c53bb721e..4d545dd6b 100644 --- a/pkg/tcpip/link/muxed/injectable_test.go +++ b/pkg/tcpip/link/muxed/injectable_test.go @@ -29,6 +29,19 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/stack" ) +func TestInjectableEndpointMTU(t *testing.T) { + endpoint, _, _ := makeTestInjectableEndpoint(t) + + mtus := []uint32{100, 200} + for _, mtu := range mtus { + endpoint.SetMTU(mtu) + + if want, v := mtu, endpoint.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func TestInjectableEndpointRawDispatch(t *testing.T) { endpoint, sock, dstIP := makeTestInjectableEndpoint(t) diff --git a/pkg/tcpip/link/nested/nested.go b/pkg/tcpip/link/nested/nested.go index 9b35513d5..78f5a0305 100644 --- a/pkg/tcpip/link/nested/nested.go +++ b/pkg/tcpip/link/nested/nested.go @@ -99,6 +99,11 @@ func (e *Endpoint) MTU() uint32 { return e.child.MTU() } +// SetMTU implements stack.LinkEndpoint. +func (e *Endpoint) SetMTU(mtu uint32) { + e.child.SetMTU(mtu) +} + // Capabilities implements stack.LinkEndpoint. func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { return e.child.Capabilities() diff --git a/pkg/tcpip/link/nested/nested_test.go b/pkg/tcpip/link/nested/nested_test.go index 77e1bb74b..90887833a 100644 --- a/pkg/tcpip/link/nested/nested_test.go +++ b/pkg/tcpip/link/nested/nested_test.go @@ -33,6 +33,7 @@ var _ stack.LinkEndpoint = (*parentEndpoint)(nil) var _ stack.NetworkDispatcher = (*parentEndpoint)(nil) type childEndpoint struct { + mtu uint32 addr tcpip.LinkAddress stack.LinkEndpoint dispatcher stack.NetworkDispatcher @@ -56,6 +57,14 @@ func (c *childEndpoint) SetLinkAddress(addr tcpip.LinkAddress) { c.addr = addr } +func (c *childEndpoint) MTU() uint32 { + return c.mtu +} + +func (c *childEndpoint) SetMTU(mtu uint32) { + c.mtu = mtu +} + type counterDispatcher struct { count int } @@ -141,6 +150,23 @@ func TestSetLinkAddress(t *testing.T) { } } +func TestMTU(t *testing.T) { + var ( + childEP childEndpoint + ep parentEndpoint + disp counterDispatcher + ) + mtus := []uint32{1500, 2000} + ep.Endpoint.Init(&childEP, &disp) + for _, mtu := range mtus { + ep.Endpoint.SetMTU(mtu) + + if want, v := mtu, ep.MTU(); want != v { + t.Errorf("LinkAddress() = %v, want %v", v, want) + } + } +} + func TestMain(m *testing.M) { refs.SetLeakMode(refs.LeaksPanic) code := m.Run() diff --git a/pkg/tcpip/link/packetsocket/packetsocket_test.go b/pkg/tcpip/link/packetsocket/packetsocket_test.go index 5c7f69a49..ba1462d64 100644 --- a/pkg/tcpip/link/packetsocket/packetsocket_test.go +++ b/pkg/tcpip/link/packetsocket/packetsocket_test.go @@ -35,6 +35,7 @@ type nullEndpoint struct { func (*nullEndpoint) MTU() uint32 { return math.MaxUint32 } +func (*nullEndpoint) SetMTU(uint32) {} func (*nullEndpoint) Capabilities() stack.LinkEndpointCapabilities { return 0 } diff --git a/pkg/tcpip/link/pipe/pipe.go b/pkg/tcpip/link/pipe/pipe.go index 06df08633..5152803d0 100644 --- a/pkg/tcpip/link/pipe/pipe.go +++ b/pkg/tcpip/link/pipe/pipe.go @@ -46,13 +46,14 @@ func New(linkAddr1, linkAddr2 tcpip.LinkAddress, mtu uint32) (*Endpoint, *Endpoi // +stateify savable type Endpoint struct { linked *Endpoint - mtu uint32 mu sync.RWMutex `state:"nosave"` // +checklocks:mu dispatcher stack.NetworkDispatcher // +checklocks:mu linkAddr tcpip.LinkAddress + // +checklocks:mu + mtu uint32 } func (e *Endpoint) deliverPackets(pkts stack.PacketBufferList) { @@ -101,9 +102,18 @@ func (*Endpoint) Wait() {} // MTU implements stack.LinkEndpoint. func (e *Endpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +// SetMTU implements stack.LinkEndpoint. +func (e *Endpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint. func (*Endpoint) Capabilities() stack.LinkEndpointCapabilities { return 0 diff --git a/pkg/tcpip/link/pipe/pipe_test.go b/pkg/tcpip/link/pipe/pipe_test.go index cd19d1c89..d66b12fff 100644 --- a/pkg/tcpip/link/pipe/pipe_test.go +++ b/pkg/tcpip/link/pipe/pipe_test.go @@ -33,3 +33,17 @@ func TestSetAddress(t *testing.T) { } } } + +func TestMTU(t *testing.T) { + mtus := []uint32{1000, 2000} + e := &Endpoint{ + mtu: 10, + } + for _, mtu := range mtus { + e.SetMTU(mtu) + + if want, v := mtu, e.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} diff --git a/pkg/tcpip/link/sharedmem/sharedmem.go b/pkg/tcpip/link/sharedmem/sharedmem.go index 7a619d4dd..3c6845fb2 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem.go +++ b/pkg/tcpip/link/sharedmem/sharedmem.go @@ -148,10 +148,6 @@ var _ stack.GSOEndpoint = (*endpoint)(nil) // +stateify savable type endpoint struct { - // mtu (maximum transmission unit) is the maximum size of a packet. - // mtu is immutable. - mtu uint32 - // bufferSize is the size of each individual buffer. // bufferSize is immutable. bufferSize uint32 @@ -206,6 +202,9 @@ type endpoint struct { // // +checklocks:mu addr tcpip.LinkAddress + // mtu (maximum transmission unit) is the maximum size of a packet. + // +checklocks:mu + mtu uint32 } // New creates a new shared-memory-based endpoint. Buffers will be broken up @@ -323,12 +322,19 @@ func (e *endpoint) IsAttached() bool { return e.workerStarted } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *endpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +func (e *endpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities { return e.caps diff --git a/pkg/tcpip/link/sharedmem/sharedmem_server.go b/pkg/tcpip/link/sharedmem/sharedmem_server.go index 9a72f6ad9..82f8d452a 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_server.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_server.go @@ -28,10 +28,6 @@ import ( ) type serverEndpoint struct { - // mtu (maximum transmission unit) is the maximum size of a packet. - // mtu is immutable. - mtu uint32 - // bufferSize is the size of each individual buffer. // bufferSize is immutable. bufferSize uint32 @@ -80,6 +76,9 @@ type serverEndpoint struct { // // +checklocks:mu addr tcpip.LinkAddress + // mtu (maximum transmission unit) is the maximum size of a packet. + // +checklocks:mu + mtu uint32 } // NewServerEndpoint creates a new shared-memory-based endpoint. Buffers will be @@ -180,12 +179,19 @@ func (e *serverEndpoint) IsAttached() bool { return e.workerStarted } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *serverEndpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +func (e *serverEndpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e *serverEndpoint) Capabilities() stack.LinkEndpointCapabilities { return e.caps diff --git a/pkg/tcpip/link/sharedmem/sharedmem_server_test.go b/pkg/tcpip/link/sharedmem/sharedmem_server_test.go index 29e623bb4..2422e95c9 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_server_test.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_server_test.go @@ -431,6 +431,34 @@ func TestSetLinkAddress(t *testing.T) { } } +func TestMTU(t *testing.T) { + q, err := sharedmem.NewQueuePair(sharedmem.QueueOptions{}) + if err != nil { + q.Close() + t.Fatalf("failed to create sharedmem queue: %s", err) + } + defer q.Close() + ep, err := sharedmem.NewServerEndpoint(sharedmem.Options{ + MTU: defaultMTU, + BufferSize: defaultBufferSize, + LinkAddress: remoteLinkAddr, + TX: q.TXQueueConfig(), + RX: q.RXQueueConfig(), + PeerFD: 123, + }) + if err != nil { + t.Fatalf("failed to create sharedmem endpoint: %s", err) + } + mtus := []uint32{1000, 2000} + for _, mtu := range mtus { + ep.SetMTU(mtu) + + if want, v := mtu, ep.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func TestMain(m *testing.M) { refs.SetLeakMode(refs.LeaksPanic) code := m.Run() diff --git a/pkg/tcpip/link/sharedmem/sharedmem_test.go b/pkg/tcpip/link/sharedmem/sharedmem_test.go index 1fc12bdcc..2f4d0b051 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_test.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_test.go @@ -835,6 +835,20 @@ func TestSetLinkAddress(t *testing.T) { } } +func TestMTU(t *testing.T) { + c := newTestContext(t, 20000, 1500, "") + defer c.cleanup() + + mtus := []uint32{1000, 2000} + for _, mtu := range mtus { + c.ep.SetMTU(mtu) + + if want, v := mtu, c.ep.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func TestMain(m *testing.M) { refs.SetLeakMode(refs.LeaksPanic) code := m.Run() diff --git a/pkg/tcpip/link/veth/veth.go b/pkg/tcpip/link/veth/veth.go index 2e8daa09b..fca5391b2 100644 --- a/pkg/tcpip/link/veth/veth.go +++ b/pkg/tcpip/link/veth/veth.go @@ -39,7 +39,6 @@ const backlogQueueSize = 64 // +stateify savable type Endpoint struct { pair *Endpoint - mtu uint32 backlogQueue *chan vethPacket @@ -55,6 +54,8 @@ type Endpoint struct { // // +checklocks:mu linkAddr tcpip.LinkAddress + // +checklocks:mu + mtu uint32 } // NewPair creates a new veth pair. @@ -143,12 +144,20 @@ func (e *Endpoint) IsAttached() bool { return e.dispatcher != nil } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *Endpoint) MTU() uint32 { + e.mu.RLock() + defer e.mu.RUnlock() return e.mtu } +// SetMTU implements stack.LinkEndpoint.SetMTU. +func (e *Endpoint) SetMTU(mtu uint32) { + e.mu.Lock() + defer e.mu.Unlock() + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { return stack.CapabilityRXChecksumOffload | stack.CapabilityTXChecksumOffload | stack.CapabilitySaveRestore diff --git a/pkg/tcpip/link/veth/veth_test.go b/pkg/tcpip/link/veth/veth_test.go index 1da4ee0bc..b50d994f8 100644 --- a/pkg/tcpip/link/veth/veth_test.go +++ b/pkg/tcpip/link/veth/veth_test.go @@ -129,6 +129,20 @@ func TestDestroyDevices(t *testing.T) { } } +func TestMTU(t *testing.T) { + mtus := []uint32{100, 200} + e, e2 := veth.NewPair(1500) + defer e.Close() + defer e2.Close() + for _, mtu := range mtus { + e.SetMTU(mtu) + + if want, v := mtu, e.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func TestMain(m *testing.M) { refs.SetLeakMode(refs.LeaksPanic) code := m.Run() diff --git a/pkg/tcpip/link/waitable/waitable.go b/pkg/tcpip/link/waitable/waitable.go index 46bd0b617..b78ccbf25 100644 --- a/pkg/tcpip/link/waitable/waitable.go +++ b/pkg/tcpip/link/waitable/waitable.go @@ -108,6 +108,12 @@ func (e *Endpoint) MTU() uint32 { return e.lower.MTU() } +// SetMTU implements stack.LinkEndpoint.SetMTU. It just forwards the request to +// the lower endpoint. +func (e *Endpoint) SetMTU(mtu uint32) { + e.lower.SetMTU(mtu) +} + // Capabilities implements stack.LinkEndpoint.Capabilities. It just forwards the // request to the lower endpoint. func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { diff --git a/pkg/tcpip/link/waitable/waitable_test.go b/pkg/tcpip/link/waitable/waitable_test.go index 5f6ebbeb4..36a96e1b6 100644 --- a/pkg/tcpip/link/waitable/waitable_test.go +++ b/pkg/tcpip/link/waitable/waitable_test.go @@ -61,6 +61,10 @@ func (e *countedEndpoint) MTU() uint32 { return e.mtu } +func (e *countedEndpoint) SetMTU(mtu uint32) { + e.mtu = mtu +} + func (e *countedEndpoint) Capabilities() stack.LinkEndpointCapabilities { return e.capabilities } diff --git a/pkg/tcpip/link/xdp/endpoint.go b/pkg/tcpip/link/xdp/endpoint.go index 0ccbcf502..a9edc966f 100644 --- a/pkg/tcpip/link/xdp/endpoint.go +++ b/pkg/tcpip/link/xdp/endpoint.go @@ -226,6 +226,9 @@ func (ep *endpoint) MTU() uint32 { return MTU } +// SetMTU implements stack.LinkEndpoint.SetMTU. It has no impact. +func (*endpoint) SetMTU(uint32) {} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (ep *endpoint) Capabilities() stack.LinkEndpointCapabilities { return ep.caps diff --git a/pkg/tcpip/network/internal/testutil/testutil.go b/pkg/tcpip/network/internal/testutil/testutil.go index 8647db95a..067ed4a7e 100644 --- a/pkg/tcpip/network/internal/testutil/testutil.go +++ b/pkg/tcpip/network/internal/testutil/testutil.go @@ -56,6 +56,9 @@ func NewMockLinkEndpoint(mtu uint32, err tcpip.Error, allowPackets int) *MockLin // MTU implements LinkEndpoint.MTU. func (ep *MockLinkEndpoint) MTU() uint32 { return ep.mtu } +// SetMTU implements LinkEndpoint.SetMTU. +func (ep *MockLinkEndpoint) SetMTU(mtu uint32) { ep.mtu = mtu } + // Capabilities implements LinkEndpoint.Capabilities. func (*MockLinkEndpoint) Capabilities() stack.LinkEndpointCapabilities { return 0 } diff --git a/pkg/tcpip/network/ip_test.go b/pkg/tcpip/network/ip_test.go index 2ba467bfa..c8e17457d 100644 --- a/pkg/tcpip/network/ip_test.go +++ b/pkg/tcpip/network/ip_test.go @@ -177,6 +177,8 @@ func (*testObject) MTU() uint32 { return 65536 } +func (*testObject) SetMTU(uint32) {} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (*testObject) Capabilities() stack.LinkEndpointCapabilities { return 0 diff --git a/pkg/tcpip/stack/bridge.go b/pkg/tcpip/stack/bridge.go index f7bfcacf9..0f03ee8ce 100644 --- a/pkg/tcpip/stack/bridge.go +++ b/pkg/tcpip/stack/bridge.go @@ -84,7 +84,8 @@ type BridgeEndpoint struct { // +checklocks:mu addr tcpip.LinkAddress // +checklocks:mu - attached bool + attached bool + // +checklocks:mu mtu uint32 maxHeaderLength atomicbitops.Uint32 } @@ -146,12 +147,21 @@ func (b *BridgeEndpoint) DelNIC(nic *nic) tcpip.Error { // MTU implements stack.LinkEndpoint.MTU. func (b *BridgeEndpoint) MTU() uint32 { + b.mu.RLock() + defer b.mu.RUnlock() if b.mtu > header.EthernetMinimumSize { return b.mtu - header.EthernetMinimumSize } return 0 } +// SetMTU implements stack.LinkEndpoint.SetMTU. +func (b *BridgeEndpoint) SetMTU(mtu uint32) { + b.mu.Lock() + defer b.mu.Unlock() + b.mtu = mtu +} + // MaxHeaderLength implements stack.LinkEndpoint. func (b *BridgeEndpoint) MaxHeaderLength() uint16 { return uint16(b.maxHeaderLength.Load()) diff --git a/pkg/tcpip/stack/bridge_test.go b/pkg/tcpip/stack/bridge_test.go index 4b9511ed7..1aa70410f 100644 --- a/pkg/tcpip/stack/bridge_test.go +++ b/pkg/tcpip/stack/bridge_test.go @@ -152,6 +152,18 @@ func TestWritePacketBetweenDevices(t *testing.T) { } } +func TestMTU(t *testing.T) { + e := stack.NewBridgeEndpoint(1500) + mtus := []uint32{1000, 2000} + for _, mtu := range mtus { + e.SetMTU(mtu) + + if want, v := mtu-header.EthernetMinimumSize, e.MTU(); want != v { + t.Errorf("MTU() = %v, want %v", v, want) + } + } +} + func TestMain(m *testing.M) { refs.SetLeakMode(refs.LeaksPanic) code := m.Run() diff --git a/pkg/tcpip/stack/forwarding_test.go b/pkg/tcpip/stack/forwarding_test.go index 07bec92dc..64159eaea 100644 --- a/pkg/tcpip/stack/forwarding_test.go +++ b/pkg/tcpip/stack/forwarding_test.go @@ -282,12 +282,16 @@ func (e *fwdTestLinkEndpoint) IsAttached() bool { return e.dispatcher != nil } -// MTU implements stack.LinkEndpoint.MTU. It returns the value initialized -// during construction. +// MTU implements stack.LinkEndpoint.MTU. func (e *fwdTestLinkEndpoint) MTU() uint32 { return e.mtu } +// SetMTU implements stack.LinkEndpoint.SetMTU. +func (e *fwdTestLinkEndpoint) SetMTU(mtu uint32) { + e.mtu = mtu +} + // Capabilities implements stack.LinkEndpoint.Capabilities. func (e fwdTestLinkEndpoint) Capabilities() LinkEndpointCapabilities { caps := LinkEndpointCapabilities(0) diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go index 27e7cc270..b0bba0c59 100644 --- a/pkg/tcpip/stack/registration.go +++ b/pkg/tcpip/stack/registration.go @@ -1090,6 +1090,9 @@ type NetworkLinkEndpoint interface { // includes the maximum size of an IP packet. MTU() uint32 + // SetMTU update the maximum transmission unit for the endpoint. + SetMTU(mtu uint32) + // MaxHeaderLength returns the maximum size the data link (and // lower level layers combined) headers can have. Higher levels use this // information to reserve space in the front of the packets they're diff --git a/pkg/tcpip/transport/datagram_test.go b/pkg/tcpip/transport/datagram_test.go index 7e73a40d3..cdbc89fdf 100644 --- a/pkg/tcpip/transport/datagram_test.go +++ b/pkg/tcpip/transport/datagram_test.go @@ -142,6 +142,7 @@ type mockEndpoint struct { func (*mockEndpoint) MTU() uint32 { return math.MaxUint32 } +func (*mockEndpoint) SetMTU(uint32) {} func (*mockEndpoint) Capabilities() stack.LinkEndpointCapabilities { return 0 }