Skip to content

Commit a469784

Browse files
DavidCozensclaude
andauthored
docs: S23.22 hold the lwIP page to what the adapters do (#744)
* docs: S23.22 hold the lwIP page to what the adapters do An over-large record has three fates here, decided by IP_FRAG rather than by the adapter, and the page described none of them. Keepalive is enabled but never tuned, so a silent peer goes unnoticed for lwIP's default two hours; #743 tracks giving the library its own tunable. The two resolvers now say which to choose and link each other, rather than leaving the reader to infer it from the setup page's advice to wire both. Part of #708. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: correct the lwIP fragmentation and NULL-Sleep claims IP_FRAG=1 attempts fragmentation and submits best-effort; ip4_frag can fail on allocation and does not propagate output errors, so "fragmented and delivered" overstated it. A NULL Sleep does not fail the Create — it returns the shared Null object, and reports nothing at all, which is the more useful thing to say. The resolver choice now links both API pages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 7d0dc06 commit a469784

4 files changed

Lines changed: 77 additions & 13 deletions

File tree

Platform/LwipRaw/Interface/SolidSyslogLwipRawDnsResolver.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
/** @file
2-
* A by-name DNS resolver for lwIP Raw targets — a superset of the numeric
3-
* resolver (literals, DNS-cache hits, and local-hostlist entries also
4-
* resolve).
2+
* The lwIP Raw resolver for a collector named by name, resolving names and
3+
* numeric addresses alike.
4+
*
5+
* Choosing between the two: this one where the endpoint may be a name, since a
6+
* literal, a DNS-cache hit and a local-hostlist entry all resolve through it
7+
* too; SolidSyslogLwipRawResolver.h where the endpoint is always an address,
8+
* which needs neither LWIP_DNS nor a Sleep and takes no marshal hop. A build
9+
* wires whichever one its deployment needs.
510
*
611
* Resolve wraps lwIP's asynchronous dns_gethostbyname, which touches lwIP core
712
* state and so runs under the SolidSyslogLwipRaw_Marshal hop (unlike the

Platform/LwipRaw/Interface/SolidSyslogLwipRawResolver.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
/** @file
2-
* A numeric-only resolver for lwIP Raw targets with no DNS.
2+
* The lwIP Raw resolver for a collector named by address: it resolves nothing,
3+
* it parses the numeric literal you configured.
34
*
45
* Resolve delegates to lwIP's ipaddr_aton to parse the endpoint host as a
56
* numeric IP literal, writing it into the destination SolidSyslogAddress;
67
* whatever ipaddr_aton accepts is accepted, whatever it rejects (DNS names,
78
* the empty string, and other non-address text) fails the Resolve, so the caller's
89
* unresolved-host error path runs. The transport is ignored. The parse touches
9-
* no lwIP core state, so unlike the DNS sibling it takes no marshal hop. */
10+
* no lwIP core state, so it takes no marshal hop.
11+
*
12+
* Choosing between the two: this one where the endpoint is always an address,
13+
* since it needs neither LWIP_DNS nor a Sleep;
14+
* SolidSyslogLwipRawDnsResolver.h where it may be a name, which resolves names
15+
* and addresses alike. A build wires whichever one its deployment needs. */
1016
#ifndef SOLIDSYSLOGLWIPRAWRESOLVER_H
1117
#define SOLIDSYSLOGLWIPRAWRESOLVER_H
1218

docs/platforms/lwipraw/index.md

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ callback runs, so a mailbox marshal has to wait for completion itself.
3333
## Requirements
3434

3535
The source calls lwIP only — no direct OS calls. The TCP stream's synchronous
36-
Open needs a bounded sleep, injected as a `SolidSyslogSleepFunction`.
36+
Open and the DNS resolver's bounded wait both need a sleep, injected as a
37+
`SolidSyslogSleepFunction`. Create it without one and you get the shared Null
38+
object back, with nothing reported: the wiring looks like it worked and no record
39+
is ever delivered.
3740

3841
Your `lwipopts.h` must enable the features the adapter wraps:
3942

@@ -46,7 +49,10 @@ Your `lwipopts.h` must enable the features the adapter wraps:
4649

4750
Also set `ARP_QUEUEING=1` (else the first datagram to an unresolved peer is
4851
dropped) and `LWIP_TCP_KEEPALIVE=1`, and size `PBUF_POOL_SIZE` /
49-
`MEMP_NUM_TCP_PCB` / `MEMP_NUM_UDP_PCB` to your instance counts.
52+
`MEMP_NUM_TCP_PCB` / `MEMP_NUM_UDP_PCB` to your instance counts. `IP_FRAG`
53+
decides what becomes of a record too large for the path — see
54+
[an over-large record has three possible fates](#an-over-large-record-has-three-possible-fates)
55+
below.
5056

5157
## Security behaviour and obligations
5258

@@ -65,6 +71,49 @@ are read the moment the hop returns. An asynchronous marshal, or none at all,
6571
corrupts lwIP's internal state rather than failing cleanly. Install it once at
6672
boot, before any adapter is created.
6773

74+
### An over-large record has three possible fates
75+
76+
The datagram reports the IPv6-safe payload of 1232 bytes from `MaxPayload` and
77+
cannot tell an over-large datagram from any other send failure, which the
78+
[Datagram](../../api/structSolidSyslogDatagram.md) contract permits. Because the
79+
sender only trims a record after being told it was too large, one over that size
80+
reaches lwIP whole, and what happens next is `IP_FRAG`'s decision rather than the
81+
adapter's:
82+
83+
- **`IP_FRAG=1`**, lwIP's default: lwIP attempts to fragment the datagram and
84+
submits the fragments to your interface. Allocating them can fail, and
85+
submission is not delivery — this is the case RFC 5426 §3.2 warns about, where
86+
a lost fragment costs the whole record and some collectors and middleboxes
87+
drop fragments outright.
88+
- **`IP_FRAG=0`**: lwIP compiles the length check out of its send path
89+
altogether and hands the over-length packet to your driver. A driver that drops
90+
it and answers `ERR_OK` loses the record while the store counts it delivered; a
91+
driver that answers an error fails the send, and a failed send is treated as
92+
transient, so the store re-offers the same record on every pass and nothing
93+
behind it is delivered.
94+
95+
`SOLIDSYSLOG_MAX_MESSAGE_SIZE` defaults to 2048, so this reaches any record over
96+
about 1.2 KB rather than only unusual ones. Keep records on this UDP path inside
97+
the payload it carries — noting that the limit is library-wide rather than
98+
per-transport, so lowering it truncates records on every transport the instance
99+
uses.
100+
101+
### Dead-peer detection runs at lwIP's defaults
102+
103+
The stream enables keepalive and leaves the timings to the stack, so a silent
104+
peer is first probed after lwIP's default two hours and the connection is
105+
declared dead around eleven minutes after that. Those defaults are compile-time
106+
and stack-wide, so changing them means `TCP_KEEPIDLE_DEFAULT` and its siblings in
107+
your `lwipopts.h` — which moves every TCP connection in your system, not only
108+
this one. `LWIP_TCP_KEEPALIVE=1` does not alter the timings; it makes the
109+
interval and probe count per-connection fields, which is what
110+
[#743](https://github.com/cososo-ltd/solid-syslog/issues/743) needs to give the
111+
library its own setting and apply it here.
112+
113+
This governs the idle case only. A connection actually carrying records notices
114+
a dead peer sooner: lwIP's send buffer fills, the write fails, and the stream
115+
closes itself so the sender reconnects.
116+
68117
### Resolution is trusted as the stack returns it
69118

70119
The DNS resolver forwards what lwIP answers. A deployment that cannot trust its
@@ -74,5 +123,7 @@ exists to be poisoned.
74123
### Pool sizing is yours, and exhaustion is silent at the stack
75124

76125
`PBUF_POOL_SIZE`, `MEMP_NUM_TCP_PCB` and `MEMP_NUM_UDP_PCB` must cover the
77-
instances you create alongside everything else using the stack. Under-sizing
78-
shows as dropped records rather than as an error from lwIP.
126+
instances you create alongside everything else using the stack. lwIP reports
127+
nothing when it runs out; what you see is the send failing, which reaches you as
128+
a delivery failure through the error handler rather than as anything naming the
129+
pool that was exhausted.

docs/platforms/lwipraw/setup.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,12 @@ resolves entirely on-device:
149149
{ DNS_LOCAL_HOSTLIST_ELEM("collector", IPADDR4_INIT_BYTES(10, 0, 2, 2)) }
150150
```
151151
152-
Both resolvers draw from one pool, so wiring the numeric and the DNS resolver
153-
together needs `SOLIDSYSLOG_RESOLVER_POOL_SIZE` raised to 2. The pool sizes and
154-
timeouts are in
155-
[Adding it to your build](../../build-integration.md#tunables).
152+
Wire whichever resolver your deployment needs:
153+
[`SolidSyslogLwipRawResolver`](../../api/SolidSyslogLwipRawResolver_8h.md) for an
154+
endpoint given as an address, or
155+
[`SolidSyslogLwipRawDnsResolver`](../../api/SolidSyslogLwipRawDnsResolver_8h.md)
156+
for one that may be a name. Each says which fits. The pool sizes and timeouts are
157+
in [Adding it to your build](../../build-integration.md#tunables).
156158
157159
## Limits
158160

0 commit comments

Comments
 (0)