summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJared Hancock <jared.hancock@centeredsolutions.com>2024-03-18 16:38:15 -0500
committerDamien George <damien@micropython.org>2024-05-23 22:25:06 +1000
commitb1e960270213a88eb02219d85201198c4a8671c6 (patch)
tree5d175c3f8c353e756b76b1be359a4b43ce66d99c
parentd532f960a4c40e4e6661ddc1d9eced18c37e3377 (diff)
extmod/modlwip: Use Nagle algorithm and add support for TCP_NODELAY.
This adds support to use the Nagle algorithm implemented already in lwIP to determine when TCP data should be sent. As currently written, MicroPython will only create packets if there is <25% remaining in the send buffer. Using it, sending a small message of ~50 bytes will not trigger output of the message on the network. So it will remained queued until the TCP interval timer expires, which can be up to 500ms. Using Nagle's algorithm, the first write, no matter how small, will generate a packet on the network. And sending lots of data still makes efficient use of the link. In addition to this, an application designer may choose to always create packets for every write by setting the TCP_NODELAY socket option. That's also implemented in this commit.
-rw-r--r--extmod/modlwip.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index d4e25917a..afac512e8 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -69,6 +69,8 @@
#define IP_ADD_MEMBERSHIP 0x400
#define IP_DROP_MEMBERSHIP 0x401
+#define TCP_NODELAY TF_NODELAY
+
// For compatibilily with older lwIP versions.
#ifndef ip_set_option
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
@@ -76,6 +78,12 @@
#ifndef ip_reset_option
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#endif
+#ifndef tcp_set_flags
+#define tcp_set_flags(pcb, set_flags) do { (pcb)->flags |= (set_flags); } while (0)
+#endif
+#ifndef tcp_clear_flags
+#define tcp_clear_flags(pcb, clear_flags) do { (pcb)->flags &= ~(clear_flags); } while (0)
+#endif
// A port can define these hooks to provide concurrency protection
#ifndef MICROPY_PY_LWIP_ENTER
@@ -742,9 +750,10 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
MICROPY_PY_LWIP_REENTER
}
- // If the output buffer is getting full then send the data to the lower layers
- if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) {
- err = tcp_output(socket->pcb.tcp);
+ // Use nagle algorithm to determine when to send segment buffer (can be
+ // disabled with TCP_NODELAY socket option)
+ if (err == ERR_OK) {
+ err = tcp_output_nagle(socket->pcb.tcp);
}
MICROPY_PY_LWIP_EXIT
@@ -1440,6 +1449,17 @@ static mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
break;
}
+ // level: IPPROTO_TCP
+ case TCP_NODELAY: {
+ mp_int_t val = mp_obj_get_int(args[3]);
+ if (val) {
+ tcp_set_flags(socket->pcb.tcp, opt);
+ } else {
+ tcp_clear_flags(socket->pcb.tcp, opt);
+ }
+ break;
+ }
+
default:
printf("Warning: lwip.setsockopt() not implemented\n");
}
@@ -1829,6 +1849,9 @@ static const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
{ MP_ROM_QSTR(MP_QSTR_IP_DROP_MEMBERSHIP), MP_ROM_INT(IP_DROP_MEMBERSHIP) },
+
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IP_PROTO_TCP) },
+ { MP_ROM_QSTR(MP_QSTR_TCP_NODELAY), MP_ROM_INT(TCP_NODELAY) },
};
static MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);