Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ version at the top when it merges.

## Unreleased

- `TCPGROWRTT=<ms>` in an interface file sets the handshake round trip
(1 to 65,535 ms) at or above which a TCP receive window on that interface
grows to its maximum. Unset, every device keeps 10 ms. The key adds 100
bytes, bringing the resident `bsdsocket.library` image to 365,416 bytes;
its budget is 366,000 bytes.
- TCP ACK batching can be set per interface with `TCPACKMAX`. WiFiPi defaults
to an 11,680-byte ceiling when the setting is absent; other devices retain
the 50,176-byte port default. This changes ACK cadence, not the unresolved
Expand Down
10 changes: 10 additions & 0 deletions docs/user/AmiNetXDuo.guide
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,16 @@
interface is next attached. This is a TCP stack setting,
not a SANA-II driver command.

@{b}TCPGROWRTT@{ub}
Handshake round trip in milliseconds, 1 to 65535, at or
above which a TCP receive window on this interface grows
from its starting size to the largest the socket may
use. Both sizes depend on the packet pool and on window
scaling. Leave it out for 10 on every device. A smaller value grows the window on shorter
paths, including a local network. The value applies to
this interface only; editing the file takes effect when
the interface is next attached.

Interface files written for Roadshow usually carry other keywords:
COPYMODE, ALIAS, METRIC, LEASE, DHCPUNICAST, LINKSTATUSCOMMAND,
MULTICAST, POINTTOPOINT, DESTINATION and BROADCASTADDRESS among
Expand Down
4 changes: 4 additions & 0 deletions include/aminetxduo/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ extern "C" {
#endif
#define AMI_CFG_WRITEREQUESTS_MAX AMINETXDUO_TX_SLOTS
#define AMI_CFG_TCP_ACK_MAX 65535UL
#define AMI_CFG_TCP_GROW_RTT_MAX 65535UL
#define AMI_CFG_PATH_LEN 128

/* The default domain gets its own cap: SetDefaultDomainName()'s autodoc says
Expand Down Expand Up @@ -203,6 +204,9 @@ typedef struct AmiIfConfig {
/* TCPACKMAX: maximum unacknowledged receive bytes before an ACK is
requested on connections using this interface. 0 = device default. */
ULONG tcp_ack_max;
/* TCPGROWRTT: handshake round trip in ms at or above which a socket on
this interface grows its receive window. 0 = BSD_TCP_WINDOW_GROW_RTT_MS. */
UWORD tcp_grow_rtt;
BYTE priority; /* PRIORITY=, -128..127, 0 unset: the
highest wins a route two
interfaces could carry */
Expand Down
1 change: 1 addition & 0 deletions include/aminetxduo/config_advice.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@
#define AMI_CFG_ADVICE_PRIORITY_IS_A_SMALL 50
#define AMI_CFG_ADVICE_FILTER_IS_LOCAL_IPANDARP 51
#define AMI_CFG_ADVICE_TCPACKMAX_IS_ACK_BYTES 52
#define AMI_CFG_ADVICE_TCPGROWRTT_IS_MILLISECONDS 53

#endif /* AMINETXDUO_CONFIG_ADVICE_H */
3 changes: 3 additions & 0 deletions include/aminetxduo/sana2.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ ULONG ami_sana2_get_bps(const AmiSana2If *iface);
/* Bytes the card holds from the wire with nobody draining it, 0 = not
stated (aminetxduo/anxs2ext.h, ANXD_CMD_RX_CAPACITY). */
ULONG ami_sana2_get_hw_rx_bytes(const AmiSana2If *iface);
/* The interface file's TCPGROWRTT in ms, 0 = not set (bsdsocket_window.h,
BSD_TCP_WINDOW_GROW_RTT_MS). */
ULONG ami_sana2_get_tcp_grow_rtt(const AmiSana2If *iface);
BOOL ami_sana2_is_online(const AmiSana2If *iface);

/*
Expand Down
2 changes: 2 additions & 0 deletions install/Install-AmiNetXDuo
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,8 @@
(append "; nothing asks it anything.\n")
(append "; TCPACKMAX= caps received TCP bytes between requested ACKs.\n")
(append "; Leave it out for this device's default.\n")
(append "; TCPGROWRTT= is the handshake round trip in ms at which a\n")
(append "; TCP receive window grows. Leave it out for 10.\n")
(append ";\n")
(append "; An IPv6 build also understands CONFIGURE6 (OFF, LINKLOCAL,\n")
(append "; AUTO, DHCP or STATIC), ADDRESS6 and GATEWAY6. A build\n")
Expand Down
16 changes: 12 additions & 4 deletions src/bsdsocket/bsdsocket_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,18 @@ ULONG ami_bsd_tcp_window_fit(ULONG window, ULONG hw_bytes, ULONG mss)
return (fit < window) ? fit : window;
}

/* TCPGROWRTT, or the built-in line where the interface sets none. */
static ULONG bsd_grow_rtt(ULONG grow_rtt_ms)
{
return (grow_rtt_ms != 0UL) ? grow_rtt_ms
: (ULONG)BSD_TCP_WINDOW_GROW_RTT_MS;
}

ULONG ami_bsd_tcp_window_settle(ULONG created, ULONG maximum, ULONG bps,
ULONG rtt_ms)
ULONG rtt_ms, ULONG grow_rtt_ms)
{
/* A long path: the window is the rate, bursts are paced far away. */
if (rtt_ms >= (ULONG)BSD_TCP_WINDOW_GROW_RTT_MS)
if (rtt_ms >= bsd_grow_rtt(grow_rtt_ms))
return (maximum > created) ? maximum : created;

/* A short path on a link that can put the whole window on the wire at
Expand All @@ -97,9 +104,10 @@ ULONG ami_bsd_tcp_window_settle(ULONG created, ULONG maximum, ULONG bps,
return created;
}

BOOL ami_bsd_tcp_window_burst_bound(ULONG bps, ULONG rtt_ms)
BOOL ami_bsd_tcp_window_burst_bound(ULONG bps, ULONG rtt_ms,
ULONG grow_rtt_ms)
{
if (rtt_ms >= (ULONG)BSD_TCP_WINDOW_GROW_RTT_MS &&
if (rtt_ms >= bsd_grow_rtt(grow_rtt_ms) &&
bps >= (ULONG)BSD_TCP_WINDOW_FAST_BPS)
return FALSE;

Expand Down
14 changes: 9 additions & 5 deletions src/bsdsocket/bsdsocket_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
* pool: 262,144 on a gigabit LAN is the burst the GENET's ring was measured
* to take, 1 MB on a long path is 300 Mbit/s at 26 ms (below). The 10 ms
* threshold is a coarse but safe line: the real A1200's LAN round trip is
* 1-5 ms, the emulator's under 1, the Internet's 20 and up.
* 1-5 ms, the emulator's under 1, the Internet's 20 and up. An interface
* file's TCPGROWRTT replaces it on that interface alone (#89).
*/
#ifndef BSD_TCP_WINDOW_LAN
#define BSD_TCP_WINDOW_LAN 100352UL /* (512 / 8) * 1568, the old ceiling */
Expand Down Expand Up @@ -143,10 +144,11 @@
* The window a socket settles at once its handshake is done. `created` is
* what it opened with, `maximum` what it may grow to, `bps` the link it came
* up on (0 = unknown), `rtt_ms` the handshake's round trip (0 = not
* measured, which a passive socket cannot). Pure arithmetic, host-tested.
* measured, which a passive socket cannot), `grow_rtt_ms` the interface's
* TCPGROWRTT (0 = BSD_TCP_WINDOW_GROW_RTT_MS). Pure arithmetic, host-tested.
*/
ULONG ami_bsd_tcp_window_settle(ULONG created, ULONG maximum, ULONG bps,
ULONG rtt_ms);
ULONG rtt_ms, ULONG grow_rtt_ms);

/*
* The window a card can absorb: `hw_bytes` is what the driver holds from
Expand Down Expand Up @@ -174,9 +176,11 @@ ULONG ami_bsd_tcp_window_fit(ULONG window, ULONG hw_bytes, ULONG mss);
* path is still burst-bound -- the Internet is faster than a 100 Mbit card,
* so its bursts arrive at the card's own line rate and a 25 MHz 68030
* behind a 13 KB ring cannot take them (anxs2ext.h, ANXD_CMD_RX_CAPACITY).
* Pure arithmetic, host-tested.
* `grow_rtt_ms` as for ami_bsd_tcp_window_settle(). Pure arithmetic,
* host-tested.
*/
BOOL ami_bsd_tcp_window_burst_bound(ULONG bps, ULONG rtt_ms);
BOOL ami_bsd_tcp_window_burst_bound(ULONG bps, ULONG rtt_ms,
ULONG grow_rtt_ms);

#ifndef BSD_TCP_WINDOW_CEILING
#ifdef AMINETXDUO_TCP_WINDOW_SCALING
Expand Down
5 changes: 3 additions & 2 deletions src/bsdsocket/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,18 @@ VOID bsd_tcp_window_settle(NX_TCP_SOCKET *tcp, ULONG rtt_ms)
? (AmiSana2If *)nxif->nx_interface_additional_link_info
: NULL;
ULONG bps = (sana != NULL) ? ami_sana2_get_bps(sana) : 0UL;
ULONG grow = ami_sana2_get_tcp_grow_rtt(sana); /* 0 = built-in line */
ULONG cur = tcp->nx_tcp_socket_rx_window_default;
ULONG want = ami_bsd_tcp_window_settle(cur, bsd_tcp_window_top(tcp), bps,
rtt_ms);
rtt_ms, grow);

/* ... and never more than the card behind this interface can hold from
the wire at once (bsdsocket_window.h, ami_bsd_tcp_window_fit), where
the whole window can arrive at once -- a LAN, or a card slower than
the path (ami_bsd_tcp_window_burst_bound). The segment size is the
one the handshake settled: nx_tcp_socket_mss is what the application
asked for and stays 0 on an accepted socket. */
if (sana != NULL && ami_bsd_tcp_window_burst_bound(bps, rtt_ms))
if (sana != NULL && ami_bsd_tcp_window_burst_bound(bps, rtt_ms, grow))
want = ami_bsd_tcp_window_fit(want, ami_sana2_get_hw_rx_bytes(sana),
tcp->nx_tcp_socket_connect_mss);

Expand Down
1 change: 1 addition & 0 deletions src/config/config_advice.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ static const char *const ami_cfg_advice_text[] =
"TCPACKMAX is the maximum number of received TCP bytes to wait "
"before requesting an ACK, 1 to 65535. Leave it out for the "
"device default; smaller values send more ACKs.",
"TCPGROWRTT is milliseconds, 1 to 65535. Leave it out for 10.",
};

const char *ami_cfg_advice(UWORD code)
Expand Down
17 changes: 17 additions & 0 deletions src/config/config_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ typedef enum
IF_KEY_WRITEREQUESTS,
IF_KEY_RXBUFFER,
IF_KEY_TCPACKMAX,
IF_KEY_TCPGROWRTT,
IF_KEY_PRIORITY
} IfKey;

Expand Down Expand Up @@ -78,6 +79,7 @@ ami_if_keywords[] =
{ "writerequests", IF_KEY_WRITEREQUESTS },
{ "rxbuffer", IF_KEY_RXBUFFER },
{ "tcpackmax", IF_KEY_TCPACKMAX },
{ "tcpgrowrtt", IF_KEY_TCPGROWRTT },
{ "priority", IF_KEY_PRIORITY }, /* Roadshow's, and PRI */
{ "pri", IF_KEY_PRIORITY },

Expand Down Expand Up @@ -780,6 +782,21 @@ LONG ami_cfg_parse_interface(const char *name, char *buf, AmiIfConfig *out)
}
break;

case IF_KEY_TCPGROWRTT:
if (ami_cfg_parse_ulong(value, &n) &&
n != 0 && n <= AMI_CFG_TCP_GROW_RTT_MAX)
{
out->tcp_grow_rtt = (UWORD)n;
}
else
{
AMI_WARN("config: %s: bad TCPGROWRTT '%s'", out->name, value);
report_bad_value(lineno, AMI_CFG_PROBLEM_WARN,
"TCPGROWRTT", value,
AMI_CFG_ADVICE_TCPGROWRTT_IS_MILLISECONDS);
}
break;

case IF_KEY_IPREQUESTS:
case IF_KEY_ARPREQUESTS:
case IF_KEY_WRITEREQUESTS:
Expand Down
53 changes: 53 additions & 0 deletions src/config/test/test_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,58 @@ static void test_interface_tcp_ack_max(void)
ami_config_set_reporter(NULL, NULL);
}

static void test_interface_tcp_grow_rtt(void)
{
AmiIfConfig iface;
char *buf;

printf("interface: TCPGROWRTT is optional and bounded per interface\n");

buf = dup_text("device = anxwifipi.device\nconfigure = dhcp\n");
CHECK(ami_cfg_parse_interface("wifipi", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 0);
free(buf);

buf = dup_text("device = anxwifipi.device\nconfigure = dhcp\n"
"tcpgrowrtt = 2\n");
CHECK(ami_cfg_parse_interface("wifipi", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 2UL);
free(buf);

buf = dup_text("device = genet.device\nconfigure = dhcp\n"
"TCPGROWRTT=65535\n");
CHECK(ami_cfg_parse_interface("eth", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 65535UL);
free(buf);

seen_count = 0;
ami_config_set_reporter(collect, NULL);
ami_cfg_problem_file("DEVS:NetInterfaces/wifipi");
buf = dup_text("device = anxwifipi.device\nconfigure = dhcp\n"
"tcpgrowrtt = 0\n");
CHECK(ami_cfg_parse_interface("wifipi", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 0);
CHECK(seen_count == 1 && seen[0].line == 3);
free(buf);

seen_count = 0;
buf = dup_text("device = anxwifipi.device\nconfigure = dhcp\n"
"tcpgrowrtt = 65536\n");
CHECK(ami_cfg_parse_interface("wifipi", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 0);
CHECK(seen_count == 1 && seen[0].line == 3);
free(buf);

seen_count = 0;
buf = dup_text("device = anxwifipi.device\nconfigure = dhcp\n"
"tcpgrowrtt = fast\n");
CHECK(ami_cfg_parse_interface("wifipi", buf, &iface) == AMI_CFG_OK);
CHECK(iface.tcp_grow_rtt == 0);
CHECK(seen_count == 1 && seen[0].line == 3);
free(buf);
ami_config_set_reporter(NULL, NULL);
}

static void test_interface_priority(void)
{
AmiIfConfig iface;
Expand Down Expand Up @@ -2968,6 +3020,7 @@ int main(int argc, char **argv)
test_inert_keywords_are_notes();
test_request_counts_have_ceilings();
test_interface_tcp_ack_max();
test_interface_tcp_grow_rtt();
test_interface_priority();
test_interface_ipv6_only();
#ifdef AMINETXDUO_IPV6
Expand Down
6 changes: 6 additions & 0 deletions src/sana2/sana2_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -1320,6 +1320,7 @@ AmiSana2If *ami_sana2_open(const AmiIfConfig *cfg, LONG *err)
* ask for); then a vendor driver whose hardware is known gets its number
* by name. 0 is no cap.
*/
iface->tcp_grow_rtt = cfg->tcp_grow_rtt;
if (cfg->rx_buffer != 0)
iface->hw_rx_bytes = cfg->rx_buffer;
else if ((iface->extension.Accepted & ANXD_S2F_RX_CAPACITY) != 0)
Expand Down Expand Up @@ -1607,6 +1608,11 @@ ULONG ami_sana2_get_hw_rx_bytes(const AmiSana2If *iface)
return (iface != NULL) ? iface->hw_rx_bytes : 0;
}

ULONG ami_sana2_get_tcp_grow_rtt(const AmiSana2If *iface)
{
return (iface != NULL) ? iface->tcp_grow_rtt : 0;
}

/*
* What a vendor driver's card holds from the wire, by the driver's name,
* for the drivers whose hardware is known: they cannot be asked. The
Expand Down
2 changes: 2 additions & 0 deletions src/sana2/sana2_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,8 @@ struct AmiSana2If
nobody draining it, 0 = not stated. The TCP window a socket on this
interface settles at stays inside it (bsdsocket_window.h). */
ULONG hw_rx_bytes;
/* TCPGROWRTT in ms, 0 = BSD_TCP_WINDOW_GROW_RTT_MS (bsdsocket_window.h). */
UWORD tcp_grow_rtt;

/* The interface file's IPREQUESTS, ARPREQUESTS (0 = the plan decides)
and WRITEREQUESTS (1..AMI_SANA2_TX_SLOTS: how many of tx[] are
Expand Down
Loading
Loading