Skip to content

Commit b1e9602

Browse files
greezybacondpgeorge
authored andcommitted
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.
1 parent d532f96 commit b1e9602

File tree

1 file changed

+26
-3
lines changed

1 file changed

+26
-3
lines changed

extmod/modlwip.c

+26-3
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,21 @@
6969
#define IP_ADD_MEMBERSHIP 0x400
7070
#define IP_DROP_MEMBERSHIP 0x401
7171

72+
#define TCP_NODELAY TF_NODELAY
73+
7274
// For compatibilily with older lwIP versions.
7375
#ifndef ip_set_option
7476
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
7577
#endif
7678
#ifndef ip_reset_option
7779
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
7880
#endif
81+
#ifndef tcp_set_flags
82+
#define tcp_set_flags(pcb, set_flags) do { (pcb)->flags |= (set_flags); } while (0)
83+
#endif
84+
#ifndef tcp_clear_flags
85+
#define tcp_clear_flags(pcb, clear_flags) do { (pcb)->flags &= ~(clear_flags); } while (0)
86+
#endif
7987

8088
// A port can define these hooks to provide concurrency protection
8189
#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
742750
MICROPY_PY_LWIP_REENTER
743751
}
744752

745-
// If the output buffer is getting full then send the data to the lower layers
746-
if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) {
747-
err = tcp_output(socket->pcb.tcp);
753+
// Use nagle algorithm to determine when to send segment buffer (can be
754+
// disabled with TCP_NODELAY socket option)
755+
if (err == ERR_OK) {
756+
err = tcp_output_nagle(socket->pcb.tcp);
748757
}
749758

750759
MICROPY_PY_LWIP_EXIT
@@ -1440,6 +1449,17 @@ static mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
14401449
break;
14411450
}
14421451

1452+
// level: IPPROTO_TCP
1453+
case TCP_NODELAY: {
1454+
mp_int_t val = mp_obj_get_int(args[3]);
1455+
if (val) {
1456+
tcp_set_flags(socket->pcb.tcp, opt);
1457+
} else {
1458+
tcp_clear_flags(socket->pcb.tcp, opt);
1459+
}
1460+
break;
1461+
}
1462+
14431463
default:
14441464
printf("Warning: lwip.setsockopt() not implemented\n");
14451465
}
@@ -1829,6 +1849,9 @@ static const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
18291849
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) },
18301850
{ MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
18311851
{ MP_ROM_QSTR(MP_QSTR_IP_DROP_MEMBERSHIP), MP_ROM_INT(IP_DROP_MEMBERSHIP) },
1852+
1853+
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IP_PROTO_TCP) },
1854+
{ MP_ROM_QSTR(MP_QSTR_TCP_NODELAY), MP_ROM_INT(TCP_NODELAY) },
18321855
};
18331856

18341857
static MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);

0 commit comments

Comments
 (0)