From 7212e13585536500c61c458e6d55e723183e4a5b Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 29 Mar 2020 19:33:18 +0200 Subject: [PATCH] Propagate the discovered PMTU between nodes to UTCP. --- src/meshlink++.h | 11 +++++++++++ src/meshlink.c | 15 +++++++++++++++ src/meshlink.h | 11 +++++++++++ src/net.h | 15 +++++++++------ src/net_packet.c | 6 +++--- 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/meshlink++.h b/src/meshlink++.h index 8493c1ed..93020661 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -993,6 +993,17 @@ public: return meshlink_channel_get_recvq(handle, channel); } + /// Get the maximum segment size of a channel. + /** This returns the amount of bytes that can be sent at once for channels with UDP semantics. + * + * @param channel A handle for the channel. + * + * @return The amount of bytes in the receive buffer. + */ + size_t channel_get_mss(channel *channel) { + return meshlink_channel_get_mss(handle, channel); + }; + /// Enable or disable zeroconf discovery of local peers /** This controls whether zeroconf discovery using the Catta library will be * enabled to search for peers on the local network. By default, it is enabled. diff --git a/src/meshlink.c b/src/meshlink.c index 747bd3b5..38ef5750 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -3672,6 +3672,7 @@ void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_ac for splay_each(node_t, n, mesh->nodes) { if(!n->utcp && n != mesh->self) { n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t)); } } @@ -3720,6 +3721,7 @@ meshlink_channel_t *meshlink_channel_open_ex(meshlink_handle_t *mesh, meshlink_n if(!n->utcp) { n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t)); mesh->receive_cb = channel_receive; if(!n->utcp) { @@ -4007,6 +4009,15 @@ size_t meshlink_channel_get_recvq(meshlink_handle_t *mesh, meshlink_channel_t *c return utcp_get_recvq(channel->c); } +size_t meshlink_channel_get_mss(meshlink_handle_t *mesh, meshlink_channel_t *channel) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return -1; + } + + return utcp_get_mss(channel->node->utcp); +} + void meshlink_set_node_channel_timeout(meshlink_handle_t *mesh, meshlink_node_t *node, int timeout) { if(!mesh || !node) { meshlink_errno = MESHLINK_EINVAL; @@ -4019,6 +4030,7 @@ void meshlink_set_node_channel_timeout(meshlink_handle_t *mesh, meshlink_node_t if(!n->utcp) { n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t)); } utcp_set_user_timeout(n->utcp, timeout); @@ -4029,6 +4041,7 @@ void meshlink_set_node_channel_timeout(meshlink_handle_t *mesh, meshlink_node_t void update_node_status(meshlink_handle_t *mesh, node_t *n) { if(n->status.reachable && mesh->channel_accept_cb && !n->utcp) { n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t)); } if(mesh->node_status_cb) { @@ -4041,6 +4054,8 @@ void update_node_status(meshlink_handle_t *mesh, node_t *n) { } void update_node_pmtu(meshlink_handle_t *mesh, node_t *n) { + utcp_set_mtu(n->utcp, (n->minmtu > MINMTU ? n->minmtu : MINMTU) - sizeof(meshlink_packethdr_t)); + if(mesh->node_pmtu_cb && !n->status.blacklisted) { mesh->node_pmtu_cb(mesh, (meshlink_node_t *)n, n->minmtu); } diff --git a/src/meshlink.h b/src/meshlink.h index 13976266..5390c4e8 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -1504,6 +1504,17 @@ extern size_t meshlink_channel_get_sendq(struct meshlink_handle *mesh, struct me */ extern size_t meshlink_channel_get_recvq(struct meshlink_handle *mesh, struct meshlink_channel *channel) __attribute__((__warn_unused_result__)); +/// Get the maximum segment size of a channel. +/** This returns the amount of bytes that can be sent at once for channels with UDP semantics. + * + * \memberof meshlink_channel + * @param mesh A handle which represents an instance of MeshLink. + * @param channel A handle for the channel. + * + * @return The amount of bytes in the receive buffer. + */ +extern size_t meshlink_channel_get_mss(struct meshlink_handle *mesh, struct meshlink_channel *channel) __attribute__((__warn_unused_result__)); + /// Set the connection timeout used for channels to the given node. /** This sets the timeout after which unresponsive channels will be reported as closed. * The timeout is set for all current and future channels to the given node. diff --git a/src/net.h b/src/net.h index cae63bf1..38727c28 100644 --- a/src/net.h +++ b/src/net.h @@ -23,17 +23,20 @@ #include "event.h" #include "sockaddr.h" +/* Maximum size of SPTPS payload */ #ifdef ENABLE_JUMBOGRAMS -#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ +#define MTU 8951 /* 9000 bytes payload - 28 bytes IP+UDP header - 21 bytes SPTPS header+MAC */ #else -#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */ +#define MTU 1451 /* 1500 bytes payload - 28 bytes IP+UDP - 21 bytes SPTPS header+MAC */ #endif -/* MAXSIZE is the maximum size of an encapsulated packet: MTU + seqno + HMAC + compressor overhead */ -#define MAXSIZE (MTU + 4 + 32 + MTU/64 + 20) +#define MINMTU 527 /* 576 minimum recommended Internet MTU - 28 bytes IP+UDP - 21 bytes SPTPS header+MAC */ -/* MAXBUFSIZE is the maximum size of a request: enough for a MAXSIZEd packet or a 8192 bits RSA key */ -#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) +/* MAXSIZE is the maximum size of an encapsulated packet */ +#define MAXSIZE (MTU + 64) + +/* MAXBUFSIZE is the maximum size of a request: enough for a base64 encoded MAXSIZEd packet plus request header */ +#define MAXBUFSIZE ((MAXSIZE * 8) / 6 + 128) typedef struct vpn_packet_t { uint16_t probe: 1; diff --git a/src/net_packet.c b/src/net_packet.c index 7dae0fe0..8aca6aa5 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -370,7 +370,7 @@ bool send_sptps_data(void *handle, uint8_t type, const void *data, size_t len) { /* Send it via TCP if it is a handshake packet, TCPOnly is in use, or this packet is larger than the MTU. */ - if(type >= SPTPS_HANDSHAKE || (type != PKT_PROBE && len > to->minmtu)) { + if(type >= SPTPS_HANDSHAKE || (type != PKT_PROBE && (len - 21) > to->minmtu)) { char buf[len * 4 / 3 + 5]; b64encode(data, buf, len); @@ -433,8 +433,8 @@ bool receive_sptps_record(void *handle, uint8_t type, const void *data, uint16_t return true; } - if(len > MTU) { - logger(mesh, MESHLINK_ERROR, "Packet from %s larger than maximum supported size (%d > %d)", from->name, len, MTU); + if(len > MAXSIZE) { + logger(mesh, MESHLINK_ERROR, "Packet from %s larger than maximum supported size (%d > %d)", from->name, len, MAXSIZE); return false; } -- 2.39.2