From c6a796675d51cba3a9d858652e7d6b52815769b3 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Tue, 26 Aug 2014 21:05:13 +0100 Subject: [PATCH] pay attention to EMSGSIZE errors when sending pmtu verification packets and drop the pmtu accordingly This way, when we actually *do* get pmtu info from the network/kernel we can discover the correct pmtu much more quickly. Especially in the absence of other traffic, forwarding of which was previously the only place where we'd check for EMSGSIZE. Fixes #12 --- forwarder.go | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/forwarder.go b/forwarder.go index c00631e4..c57d58e4 100644 --- a/forwarder.go +++ b/forwarder.go @@ -70,15 +70,29 @@ func (conn *LocalConnection) forwarderLoop(forwardCh <-chan *ForwardedFrame, sto var pmtuVerifyTick <-chan time.Time var clientPMTU int maxPayload := pmtu - UDPOverhead + calculateClientPMTU := func(ftbe FrameTooBigError) { + maxPayload = ftbe.PMTU - UDPOverhead + clientPMTU = maxPayload - enc.PacketOverhead() - enc.FrameOverhead() - EthernetOverhead + } updateClientPMTU := func() { - conn.setClientPMTU(clientPMTU) - pmtuVerifyFrame := &ForwardedFrame{ - srcPeer: conn.local, - dstPeer: conn.remote, - frame: make([]byte, clientPMTU+EthernetOverhead)} - for cnt := 0; cnt < 10; cnt += 1 { - enc.AppendFrame(pmtuVerifyFrame) - udpSender.Send(enc.Bytes()) + for gotNewPMTU := true; gotNewPMTU; { + conn.setClientPMTU(clientPMTU) + pmtuVerifyFrame := &ForwardedFrame{ + srcPeer: conn.local, + dstPeer: conn.remote, + frame: make([]byte, clientPMTU+EthernetOverhead)} + gotNewPMTU = false + for cnt := 0; cnt < 10; cnt += 1 { + enc.AppendFrame(pmtuVerifyFrame) + err := udpSender.Send(enc.Bytes()) + if err != nil { + if ftbe, ok := err.(FrameTooBigError); ok { + calculateClientPMTU(ftbe) + gotNewPMTU = true + break + } + } + } } pmtuVerifyTick = time.After(PMTUVerifyTimeout) } @@ -94,8 +108,7 @@ func (conn *LocalConnection) forwarderLoop(forwardCh <-chan *ForwardedFrame, sto err := udpSender.Send(enc.Bytes()) if err != nil { if ftbe, ok := err.(FrameTooBigError); ok { - maxPayload = ftbe.PMTU - UDPOverhead - clientPMTU = maxPayload - enc.PacketOverhead() - enc.FrameOverhead() - EthernetOverhead + calculateClientPMTU(ftbe) updateClientPMTU() } else if PosixError(err) == syscall.ENOBUFS { // TODO handle this better