* SSU MTU (ticket #682):

- Use local MTU detection
   - i2np.udp.mtu now sets max MTU, not initial MTU
   - Put local MTU in netDb 
   - Fix receive MTU calculations
   - Track remote MTU based on actual received packet size
   - Display local MTU on peers page
This commit is contained in:
zzz
2012-08-11 11:27:28 +00:00
parent a6a0228ef8
commit c70e3727be
6 changed files with 89 additions and 37 deletions

View File

@@ -146,7 +146,7 @@ class EstablishmentManager {
RemoteHostId to = null;
InetAddress remAddr = addr.getHostAddress();
int port = addr.getPort();
if ( (remAddr != null) && (port > 0) ) {
if (remAddr != null && port > 0 && port <= 65535) {
to = new RemoteHostId(remAddr.getAddress(), port);
if (!_transport.isValid(to.getIP())) {

View File

@@ -152,9 +152,11 @@ class PeerState {
* we can use to publish that fact.
*/
private long _theyRelayToUsAs;
/** what is the largest packet we can send to the peer? */
/** what is the largest packet we can currently send to the peer? */
private int _mtu;
private int _mtuReceive;
/** what is the largest packet we will ever send to the peer? */
private final int _largeMTU;
/* how many consecutive packets at or under the min MTU have been received */
private long _consecutiveSmall;
/** when did we last check the MTU? */
@@ -259,8 +261,6 @@ class PeerState {
private static final int MIN_RTO = 100 + ACKSender.ACK_FREQUENCY;
private static final int MAX_RTO = 3000; // 5000;
/** override the default MTU */
private static final String PROP_DEFAULT_MTU = "i2np.udp.mtu";
public PeerState(RouterContext ctx, UDPTransport transport,
byte[] remoteIP, int remotePort, Hash remotePeer, boolean isInbound) {
@@ -281,8 +281,9 @@ class PeerState {
_receivePeriodBegin = now;
_lastCongestionOccurred = -1;
_remotePort = remotePort;
_mtu = getDefaultMTU();
_mtu = DEFAULT_MTU;
_mtuReceive = _mtu;
_largeMTU = transport.getMTU();
//_mtuLastChecked = -1;
_lastACKSend = -1;
_rto = MIN_RTO;
@@ -297,10 +298,6 @@ class PeerState {
_remoteHostId = new RemoteHostId(remoteIP, remotePort);
}
private int getDefaultMTU() {
return _context.getProperty(PROP_DEFAULT_MTU, DEFAULT_MTU);
}
/**
* The peer are we talking to. This should be set as soon as this
* state is created if we are initiating a connection, but if we are
@@ -1025,13 +1022,13 @@ class PeerState {
if (_packetsTransmitted > 10) {
retransPct = (double)_packetsRetransmitted/(double)_packetsTransmitted;
boolean wantLarge = retransPct < .30d; // heuristic to allow fairly lossy links to use large MTUs
if (wantLarge && _mtu != LARGE_MTU) {
if (wantLarge && _mtu != _largeMTU) {
if (_context.random().nextLong(_mtuDecreases) <= 0) {
_mtu = LARGE_MTU;
_mtu = _largeMTU;
_mtuIncreases++;
_context.statManager().addRateData("udp.mtuIncrease", _mtuIncreases, _mtuDecreases);
}
} else if (!wantLarge && _mtu == LARGE_MTU) {
} else if (!wantLarge && _mtu == _largeMTU) {
_mtu = MIN_MTU;
_mtuDecreases++;
_context.statManager().addRateData("udp.mtuDecrease", _mtuDecreases, _mtuIncreases);
@@ -1060,6 +1057,7 @@ class PeerState {
adjustMTU();
//_rto *= 2;
}
public void packetsTransmitted(int packets) {
//long now = _context.clock().now();
_packetsTransmitted += packets;
@@ -1073,6 +1071,7 @@ class PeerState {
}
*****/
}
/** how long does it usually take to get a message ACKed? */
public int getRTT() { return _rtt; }
/** how soon should we retransmit an unacked packet? */
@@ -1092,23 +1091,25 @@ class PeerState {
public long getPacketsReceivedDuplicate() { return _packetsReceivedDuplicate; }
private static final int MTU_RCV_DISPLAY_THRESHOLD = 20;
/** 60 */
private static final int OVERHEAD_SIZE = PacketBuilder.IP_HEADER_SIZE + PacketBuilder.UDP_HEADER_SIZE +
UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
/**
* @param size not including IP header, UDP header, MAC or IV
*/
public void packetReceived(int size) {
_packetsReceived++;
size += OVERHEAD_SIZE;
if (size <= MIN_MTU) {
_consecutiveSmall++;
if (_consecutiveSmall >= MTU_RCV_DISPLAY_THRESHOLD)
_mtuReceive = MIN_MTU;
} else {
_consecutiveSmall = 0;
_mtuReceive = LARGE_MTU;
return;
if (size > _mtuReceive)
_mtuReceive = size;
}
if (_packetsReceived > MTU_RCV_DISPLAY_THRESHOLD) {
if (_consecutiveSmall < MTU_RCV_DISPLAY_THRESHOLD)
_mtuReceive = LARGE_MTU;
else
_mtuReceive = MIN_MTU;
}
}
/**

View File

@@ -21,10 +21,12 @@ public class UDPAddress {
private int _introPorts[];
private byte[] _introKeys[];
private long _introTags[];
private int _mtu;
public static final String PROP_PORT = "port";
public static final String PROP_HOST = "host";
public static final String PROP_INTRO_KEY = "key";
public static final String PROP_MTU = "mtu";
public static final String PROP_CAPACITY = "caps";
public static final char CAPACITY_TESTING = 'B';
@@ -72,6 +74,11 @@ public class UDPAddress {
} catch (NumberFormatException nfe) {
_port = -1;
}
try {
String mtu = addr.getOption(PROP_MTU);
if (mtu != null)
_mtu = MTU.rectify(Integer.parseInt(mtu));
} catch (NumberFormatException nfe) {}
String key = addr.getOption(PROP_INTRO_KEY);
if (key != null)
_introKey = Base64.decode(key.trim());
@@ -91,7 +98,7 @@ public class UDPAddress {
int p = -1;
try {
p = Integer.parseInt(port);
if (p <= 0) continue;
if (p <= 0 || p > 65535) continue;
} catch (NumberFormatException nfe) {
continue;
}
@@ -161,7 +168,12 @@ public class UDPAddress {
}
return _hostAddress;
}
/**
* @return 0 if unset; -1 if invalid
*/
public int getPort() { return _port; }
byte[] getIntroKey() { return _introKey; }
int getIntroducerCount() { return (_introAddresses == null ? 0 : _introAddresses.length); }
@@ -179,4 +191,11 @@ public class UDPAddress {
byte[] getIntroducerKey(int i) { return _introKeys[i]; }
long getIntroducerTag(int i) { return _introTags[i]; }
/**
* @return 0 if unset or invalid; recitified via MTU.rectify()
* @since 0.9.2
*/
int getMTU() {
return _introPorts[i];
}
}

View File

@@ -154,15 +154,4 @@ class UDPEndpoint {
return null;
return _receiver.receiveNext();
}
/**
* The MTU for the socket interface, if available.
* Not available for Java 5.
* @return 0 if Java 5, or if bound to an address;
* limited to range MIN_MTU to LARGE_MTU.
* @since 0.9.2
*/
public int getMTU() {
return MTU.getMTU(_bindAddress);
}
}

View File

@@ -257,7 +257,12 @@ class UDPPacketReader {
/** parse out the data message */
public class DataReader {
/**
* @return the data size, NOT including IP header, UDP header, IV, or MAC
*/
public int getPacketSize() { return _payloadLength; }
public boolean readACKsIncluded() {
return flagSet(UDPPacket.DATA_FLAG_EXPLICIT_ACK);
}

View File

@@ -71,6 +71,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
private long _introducersSelectedOn;
private long _lastInboundReceivedOn;
private final DHSessionKeyBuilder.Factory _dhFactory;
private int _mtu;
/** do we need to rebuild our external router address asap? */
private boolean _needsRebuild;
@@ -141,6 +142,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public static final String PROP_ALLOW_DIRECT = "i2np.udp.allowDirect";
/** this is rarely if ever used, default is to bind to wildcard address */
public static final String PROP_BIND_INTERFACE = "i2np.udp.bindInterface";
/** override the "large" (max) MTU, default is PeerState.LARGE_MTU */
private static final String PROP_DEFAULT_MTU = "i2np.udp.mtu";
/** how many relays offered to us will we use at a time? */
public static final int PUBLIC_RELAY_COUNT = 3;
@@ -213,6 +216,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_introManager = new IntroductionManager(_context, this);
_introducersSelectedOn = -1;
_lastInboundReceivedOn = -1;
_mtu = PeerState.LARGE_MTU;
_needsRebuild = true;
_context.statManager().createRateStat("udp.alreadyConnected", "What is the lifetime of a reestablished session", "udp", RATES);
@@ -307,6 +311,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// todo, set bind address too
_endpoint.setListenPort(port);
}
setMTU(bindToAddr);
if (_establisher == null)
_establisher = new EstablishmentManager(_context, this);
@@ -403,6 +408,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
return _context.getProperty(PROP_INTERNAL_PORT, -1);
}
/**
* Set the MTU for the socket interface at addr.
* @param addr null ok
* @since 0.9.2
*/
private void setMTU(InetAddress addr) {
String p = _context.getProperty(PROP_DEFAULT_MTU);
if (p != null) {
try {
_mtu = MTU.rectify(Integer.parseInt(p));
return;
} catch (NumberFormatException nfe) {}
}
int mtu = MTU.getMTU(addr);
if (mtu <= 0)
mtu = PeerState.LARGE_MTU;
_mtu = mtu;
}
/**
* The MTU for the socket interface.
* To be used as the "large" MTU.
* @return limited to range PeerState.MIN_MTU to PeerState.LARGE_MTU.
* @since 0.9.2
*/
public int getMTU() {
return _mtu;
}
/**
* If we have received an inbound connection in the last 2 minutes, don't allow
* our IP to change.
@@ -1331,6 +1365,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
else
options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER);
// MTU since 0.9.2
if (_mtu < PeerState.LARGE_MTU)
options.setProperty(UDPAddress.PROP_MTU, Integer.toString(_mtu));
if (directIncluded || introducersIncluded) {
// This is called via TransportManager.configTransports() before startup(), prevent NPE
if (_introKey != null)
@@ -2171,7 +2209,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
// buf.append("<tr><td colspan=\"16\"><hr></td></tr>\n");
buf.append("<tr class=\"tablefooter\"> <td colspan=\"3\" align=\"left\"><b>").append(_("SUMMARY")).append("</b></td>" +
buf.append("<tr class=\"tablefooter\"><td colspan=\"3\" align=\"left\"><b>").append(_("SUMMARY")).append("</b></td>" +
"<td align=\"center\" nowrap><b>");
buf.append(formatKBps(bpsIn)).append(THINSP).append(formatKBps(bpsOut));
long x = numPeers > 0 ? uptimeMsTotal/numPeers : 0;
@@ -2184,10 +2222,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
buf.append("</b></td><td>&nbsp;</td>\n" +
"<td align=\"center\"><b>");
buf.append(numPeers > 0 ? DataHelper.formatDuration2(rttTotal/numPeers) : '0');
buf.append("</b></td><td>&nbsp;</td> <td align=\"center\"><b>");
buf.append("</b></td><td>&nbsp;</td><td align=\"center\"><b>");
buf.append(numPeers > 0 ? DataHelper.formatDuration2(rtoTotal/numPeers) : '0');
buf.append("</b></td><td>&nbsp;</td> <td align=\"center\"><b>");
buf.append(sendTotal).append("</b></td> <td align=\"center\"><b>").append(recvTotal).append("</b></td>\n" +
buf.append("</b></td><td align=\"center\"><b>").append(_mtu).append("</b></td><td align=\"center\"><b>");
buf.append(sendTotal).append("</b></td><td align=\"center\"><b>").append(recvTotal).append("</b></td>\n" +
"<td align=\"center\"><b>").append(resentTotal);
buf.append("</b></td><td align=\"center\"><b>").append(dupRecvTotal).append("</b></td>\n" +
"</tr></table>\n");