Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Support different IPv4 and IPv6 MTUs.
Closes #688.
  • Loading branch information
cgull committed Nov 29, 2015
1 parent b742e95 commit 3fa42cb
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/crypto/crypto.h
Expand Up @@ -132,6 +132,8 @@ namespace Crypto {

public:
static const int RECEIVE_MTU = 2048;
/* Overhead (not counting the nonce, which is handled by network transport) */
static const int ADDED_BYTES = 16 /* final OCB block */;

Session( Base64Key s_key );
~Session();
Expand Down
19 changes: 18 additions & 1 deletion src/network/network.cc
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 )
Expand All @@ -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 */
}
}

Expand Down
35 changes: 33 additions & 2 deletions src/network/network.h
Expand Up @@ -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 */

Expand Down Expand Up @@ -139,7 +165,7 @@ namespace Network {

bool server;

int MTU;
int MTU; /* application datagram MTU */

Base64Key key;
Session session;
Expand Down Expand Up @@ -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 */

Expand Down
9 changes: 5 additions & 4 deletions src/network/transportfragment.cc
Expand Up @@ -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())
Expand All @@ -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();
Expand Down
9 changes: 3 additions & 6 deletions src/network/transportfragment.h
Expand Up @@ -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;
Expand Down Expand Up @@ -94,15 +91,15 @@ 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 )
{
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(); }
};

Expand Down
5 changes: 3 additions & 2 deletions src/network/transportsender.cc
Expand Up @@ -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++ ) {
Expand Down

0 comments on commit 3fa42cb

Please sign in to comment.