Simplify MTU setup and allow big packets

Signed-off-by: Adrien Gallouët <adrien@gallouet.fr>
This commit is contained in:
Adrien Gallouët
2018-03-26 13:02:54 +00:00
parent 09acdee3e1
commit c63c94d7c8

116
mud.c
View File

@@ -45,12 +45,12 @@
#define MUD_PKTINFO_SIZE sizeof(struct in_addr) #define MUD_PKTINFO_SIZE sizeof(struct in_addr)
#endif #endif
#if defined IP_DONTFRAG #if defined IP_MTU_DISCOVER
#define MUD_DFRAG IP_MTU_DISCOVER
#define MUD_DFRAG_OPT IP_PMTUDISC_PROBE
#elif defined IP_DONTFRAG
#define MUD_DFRAG IP_DONTFRAG #define MUD_DFRAG IP_DONTFRAG
#define MUD_DFRAG_OPT 1 #define MUD_DFRAG_OPT 1
#elif defined IP_MTU_DISCOVER
#define MUD_DFRAG IP_MTU_DISCOVER
#define MUD_DFRAG_OPT IP_PMTUDISC_DO
#endif #endif
#define MUD_ONE_MSEC (UINT64_C(1000)) #define MUD_ONE_MSEC (UINT64_C(1000))
@@ -68,13 +68,15 @@
#define MUD_PACKET_MARK(X) ((X) | UINT64_C(1)) #define MUD_PACKET_MARK(X) ((X) | UINT64_C(1))
#define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE) #define MUD_PACKET_MIN_SIZE (MUD_U48_SIZE + MUD_MAC_SIZE)
#define MUD_PACKET_MAX_SIZE (1472U) #define MUD_PACKET_MAX_SIZE (9000U)
#define MUD_PACKET_TC (192) // CS6 #define MUD_PACKET_TC (192) // CS6
#define MUD_PACKET_SIZE(X) \ #define MUD_PACKET_SIZE(X) \
(sizeof(((struct mud_packet *)0)->hdr) + (X) + MUD_MAC_SIZE) (sizeof(((struct mud_packet *)0)->hdr) + (X) + MUD_MAC_SIZE)
#define MUD_MTU (1280U + MUD_PACKET_MIN_SIZE)
#define MUD_STAT_TIMEOUT (100 * MUD_ONE_MSEC) #define MUD_STAT_TIMEOUT (100 * MUD_ONE_MSEC)
#define MUD_KEYX_TIMEOUT (60 * MUD_ONE_MIN) #define MUD_KEYX_TIMEOUT (60 * MUD_ONE_MIN)
#define MUD_SEND_TIMEOUT (MUD_ONE_SEC) #define MUD_SEND_TIMEOUT (MUD_ONE_SEC)
@@ -520,7 +522,7 @@ mud_get_path(struct mud *mud, struct sockaddr_storage *local_addr,
memcpy(&path->local_addr, local_addr, sizeof(*local_addr)); memcpy(&path->local_addr, local_addr, sizeof(*local_addr));
memcpy(&path->addr, addr, sizeof(*addr)); memcpy(&path->addr, addr, sizeof(*addr));
path->mtu.ok = mud->mtu; path->mtu.ok = MUD_MTU;
path->mtu.probe = mud->mtu; path->mtu.probe = mud->mtu;
return path; return path;
@@ -562,6 +564,27 @@ mud_peer(struct mud *mud, struct sockaddr *peer)
return 0; return 0;
} }
static void
mud_update_mtu(struct mud *mud)
{
size_t mtu = MUD_PACKET_MAX_SIZE;
size_t count = 0;
for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->state <= MUD_DOWN)
continue;
count++;
if (mtu > path->mtu.ok)
mtu = path->mtu.ok;
}
mud->mtu = count ? mtu : MUD_MTU;
}
int int
mud_get_key(struct mud *mud, unsigned char *key, size_t *size) mud_get_key(struct mud *mud, unsigned char *key, size_t *size)
{ {
@@ -697,6 +720,7 @@ mud_set_state(struct mud *mud, struct sockaddr *addr, enum mud_state state)
return -1; return -1;
path->state = state; path->state = state;
mud_update_mtu(mud);
return 0; return 0;
} }
@@ -704,55 +728,13 @@ mud_set_state(struct mud *mud, struct sockaddr *addr, enum mud_state state)
size_t size_t
mud_get_mtu(struct mud *mud) mud_get_mtu(struct mud *mud)
{ {
size_t mtu = MUD_PACKET_MAX_SIZE; return mud->mtu - MUD_PACKET_MIN_SIZE;
unsigned count = 0;
for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->state <= MUD_DOWN)
continue;
count++;
if (mtu > path->mtu.ok)
mtu = path->mtu.ok;
}
if (!count)
mtu = mud->mtu;
if (mtu > MUD_PACKET_MAX_SIZE)
mtu = MUD_PACKET_MAX_SIZE;
if (mtu < sizeof(struct mud_packet))
mtu = sizeof(struct mud_packet);
return mtu - MUD_PACKET_MIN_SIZE;
} }
void void
mud_set_mtu(struct mud *mud, size_t mtu) mud_set_mtu(struct mud *mud, size_t mtu)
{ {
if (mtu > MUD_PACKET_MAX_SIZE + 28U) { mud->mtu = mtu + MUD_PACKET_MIN_SIZE;
mtu = MUD_PACKET_MAX_SIZE;
} else if (mtu < sizeof(struct mud_packet) + 28U) {
mtu = sizeof(struct mud_packet);
} else {
mtu -= 28U;
}
for (unsigned i = 0; i < mud->count; i++) {
struct mud_path *path = &mud->paths[i];
if (path->state == MUD_EMPTY)
continue;
path->mtu.ok = mtu;
path->mtu.probe = mtu;
}
mud->mtu = mtu;
} }
static int static int
@@ -912,7 +894,7 @@ mud_create(struct sockaddr *addr)
mud->time_tolerance = MUD_TIME_TOLERANCE; mud->time_tolerance = MUD_TIME_TOLERANCE;
mud->keyx_timeout = MUD_KEYX_TIMEOUT; mud->keyx_timeout = MUD_KEYX_TIMEOUT;
mud->tc = MUD_PACKET_TC; mud->tc = MUD_PACKET_TC;
mud->mtu = sizeof(struct mud_packet); mud->mtu = MUD_MTU;
memcpy(&mud->addr, addr, addrlen); memcpy(&mud->addr, addr, addrlen);
@@ -1055,7 +1037,7 @@ mud_localaddr(struct sockaddr_storage *addr, struct msghdr *msg)
return 0; return 0;
} }
static void static int
mud_packet_send(struct mud *mud, enum mud_packet_code code, mud_packet_send(struct mud *mud, enum mud_packet_code code,
struct mud_path *path, uint64_t now, int flags) struct mud_path *path, uint64_t now, int flags)
{ {
@@ -1079,7 +1061,8 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
memcpy(packet->hdr.addr.port, memcpy(packet->hdr.addr.port,
&((struct sockaddr_in6 *)&path->addr)->sin6_port, 2); &((struct sockaddr_in6 *)&path->addr)->sin6_port, 2);
} else { } else {
return; errno = EINVAL;
return -1;
} }
packet->hdr.state = (unsigned char)path->state; packet->hdr.state = (unsigned char)path->state;
@@ -1116,7 +1099,10 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
}; };
mud_encrypt_opt(&mud->crypto.private, &opt); mud_encrypt_opt(&mud->crypto.private, &opt);
mud_send_path(mud, path, now, packet, MUD_PACKET_SIZE(size), mud->tc, flags);
return mud_send_path(mud, path, now,
packet, MUD_PACKET_SIZE(size),
mud->tc, flags);
} }
static void static void
@@ -1242,6 +1228,8 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
default: default:
break; break;
} }
mud_update_mtu(mud);
} }
int int
@@ -1317,8 +1305,10 @@ mud_recv(struct mud *mud, void *data, size_t size)
if (path->recv_max <= packet_size) { if (path->recv_max <= packet_size) {
path->recv_max = packet_size; path->recv_max = packet_size;
path->recv_max_time = send_time; path->recv_max_time = send_time;
if (path->mtu.ok < path->recv_max) if (path->mtu.ok < path->recv_max) {
path->mtu.ok = path->recv_max; path->mtu.ok = path->recv_max;
mud_update_mtu(mud);
}
} }
if (MUD_PACKET(send_time)) { if (MUD_PACKET(send_time)) {
@@ -1335,19 +1325,25 @@ static void
mud_probe_mtu(struct mud *mud, struct mud_path *path, uint64_t now) mud_probe_mtu(struct mud *mud, struct mud_path *path, uint64_t now)
{ {
if ((!path->rtt) || if ((!path->rtt) ||
(!mud_timeout(now, path->mtu.time, path->rtt)) || (!mud_timeout(now, path->mtu.time, path->rtt)))
(path->mtu.probe == path->r_rms + 1) ||
(path->r_rms == MUD_PACKET_MAX_SIZE))
return; return;
while ((path->mtu.probe != path->r_rms + 1) &&
(path->r_rms != MUD_PACKET_MAX_SIZE)) {
if (path->mtu.probe > path->mtu.ok) { if (path->mtu.probe > path->mtu.ok) {
path->mtu.probe = (path->mtu.probe + path->mtu.ok) >> 1; path->mtu.probe = (path->mtu.probe + path->mtu.ok) >> 1;
} else { } else {
path->mtu.probe = (MUD_PACKET_MAX_SIZE + path->mtu.ok + 1) >> 1; path->mtu.probe = (MUD_PACKET_MAX_SIZE + path->mtu.ok + 1) >> 1;
} }
mud_packet_send(mud, mud_fake, path, now, 0);
path->mtu.time = now; path->mtu.time = now;
if ((path->mtu.probe == MUD_MTU) ||
(mud_packet_send(mud, mud_fake, path, now, 0) != -1) ||
(errno != EMSGSIZE))
break;
}
} }
static void static void
@@ -1394,7 +1390,7 @@ mud_send(struct mud *mud, const void *data, size_t size, int tc)
if (!size) if (!size)
return 0; return 0;
if (size > mud_get_mtu(mud)) { if (size > sizeof(packet) - MUD_PACKET_MIN_SIZE) {
errno = EMSGSIZE; errno = EMSGSIZE;
return -1; return -1;
} }