Support different IPv4 and IPv6 MTUs.

Closes #688.
This commit is contained in:
John Hood
2015-11-16 02:35:18 -05:00
parent b742e958b6
commit 3fa42cb8bb
6 changed files with 64 additions and 15 deletions
+18 -1
View File
@@ -203,6 +203,20 @@ const std::vector< int > Connection::fds( void ) const
return ret;
}
void Connection::set_MTU( int family )
{
switch ( family ) {
case AF_INET:
MTU = DEFAULT_IPV4_MTU - IPV4_HEADER_LEN;
break;
case AF_INET6:
MTU = DEFAULT_IPV6_MTU - IPV6_HEADER_LEN;
break;
default:
throw NetworkException( "Unknown address family", 0 );
}
}
class AddrInfo {
public:
struct addrinfo *res;
@@ -319,6 +333,7 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
}
if ( bind( sock(), &local_addr.sa, local_addr_len ) == 0 ) {
set_MTU( local_addr.sa.sa_family );
return true;
} else if ( i == search_high ) { /* last port to search */
int saved_errno = errno;
@@ -379,6 +394,8 @@ Connection::Connection( const char *key_str, const char *ip, const char *port )
has_remote_addr = true;
socks.push_back( Socket( remote_addr.sa.sa_family ) );
set_MTU( remote_addr.sa.sa_family );
}
void Connection::send( string s )
@@ -404,7 +421,7 @@ void Connection::send( string s )
send_exception = NetworkException( "sendto", errno );
if ( errno == EMSGSIZE ) {
MTU = 500; /* payload MTU of last resort */
MTU = DEFAULT_SEND_MTU; /* payload MTU of last resort */
}
}
+33 -2
View File
@@ -101,7 +101,33 @@ namespace Network {
class Connection {
private:
static const int DEFAULT_SEND_MTU = 1300;
/*
* For IPv4, guess the typical (minimum) header length;
* fragmentation is not dangerous, just inefficient.
*/
static const int IPV4_HEADER_LEN = 20 /* base IP header */
+ 8 /* UDP */;
/*
* For IPv6, we don't want to ever have MTU issues, so make a
* conservative guess about header size.
*/
static const int IPV6_HEADER_LEN = 40 /* base IPv6 header */
+ 16 /* 2 minimum-sized extension headers */
+ 8 /* UDP */;
/* Application datagram MTU. For constructors and fallback. */
static const int DEFAULT_SEND_MTU = 500;
/*
* IPv4 MTU. Don't use full Ethernet-derived MTU,
* mobile networks have high tunneling overhead.
*
* About 95% of IPv4 TCP MSS I see are >= 1360.
* An IP MTU is 20 bytes larger.
* We let smaller MTUs fragment.
*/
static const int DEFAULT_IPV4_MTU = 1380;
/* IPv6 MTU. Use the guaranteed minimum to avoid fragmentation. */
static const int DEFAULT_IPV6_MTU = 1280;
static const uint64_t MIN_RTO = 50; /* ms */
static const uint64_t MAX_RTO = 1000; /* ms */
@@ -139,7 +165,7 @@ namespace Network {
bool server;
int MTU;
int MTU; /* application datagram MTU */
Base64Key key;
Session session;
@@ -175,7 +201,12 @@ namespace Network {
string recv_one( int sock_to_recv, bool nonblocking );
void set_MTU( int family );
public:
/* Network transport overhead. */
static const int ADDED_BYTES = 8 /* seqno/nonce */ + 4 /* timestamps */;
Connection( const char *desired_ip, const char *desired_port ); /* server */
Connection( const char *key_str, const char *ip, const char *port ); /* client */
+5 -4
View File
@@ -154,8 +154,9 @@ bool Fragment::operator==( const Fragment &x ) const
&& ( initialized == x.initialized ) && ( contents == x.contents );
}
vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, int MTU )
vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, size_t MTU )
{
MTU -= Fragment::frag_header_len;
if ( (inst.old_num() != last_instruction.old_num())
|| (inst.new_num() != last_instruction.new_num())
|| (inst.ack_num() != last_instruction.ack_num())
@@ -182,9 +183,9 @@ vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, int MTU )
string this_fragment;
bool final = false;
if ( int( payload.size() + HEADER_LEN ) > MTU ) {
this_fragment = string( payload.begin(), payload.begin() + MTU - HEADER_LEN );
payload = string( payload.begin() + MTU - HEADER_LEN, payload.end() );
if ( payload.size() > MTU ) {
this_fragment = string( payload.begin(), payload.begin() + MTU );
payload = string( payload.begin() + MTU, payload.end() );
} else {
this_fragment = payload;
payload.clear();
+3 -6
View File
@@ -44,14 +44,11 @@ using std::string;
using namespace TransportBuffers;
namespace Network {
static const int HEADER_LEN = 66;
class Fragment
{
private:
public:
static const size_t frag_header_len = sizeof( uint64_t ) + sizeof( uint16_t );
public:
uint64_t id;
uint16_t fragment_num;
bool final;
@@ -94,7 +91,7 @@ namespace Network {
private:
uint64_t next_instruction_id;
Instruction last_instruction;
int last_MTU;
size_t last_MTU;
public:
Fragmenter() : next_instruction_id( 0 ), last_instruction(), last_MTU( -1 )
@@ -102,7 +99,7 @@ namespace Network {
last_instruction.set_old_num( -1 );
last_instruction.set_new_num( -1 );
}
vector<Fragment> make_fragments( const Instruction &inst, int MTU );
vector<Fragment> make_fragments( const Instruction &inst, size_t MTU );
uint64_t last_ack_sent( void ) const { return last_instruction.ack_num(); }
};
+3 -2
View File
@@ -320,8 +320,9 @@ void TransportSender<MyState>::send_in_fragments( string diff, uint64_t new_num
shutdown_tries++;
}
vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU() );
vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU()
- Network::Connection::ADDED_BYTES
- Crypto::Session::ADDED_BYTES );
for ( vector<Fragment>::iterator i = fragments.begin();
i != fragments.end();
i++ ) {