doc: lacp: shorten, point to stp.md for the trap

The trap is described with STP, so the LACP page only says that it is
used. The LACP sections leave link_aggregation.md, which now points to
lacp.md, and the timing section gives the values in seconds and the
802.3ad requirements without the test history.
This commit is contained in:
d00f committed 2026-10-12 22:05:56 +02:00
1 parent 73b23808cf
commit d525229b42
2 files changed
+50 -124

No files matched your search

+46 -124
View File
@@ -1,79 +1,23 @@
# LACP (Link Aggregation Control Protocol, IEEE 802.3ad) # LACP (Link Aggregation Control Protocol, IEEE 802.3ad)
A static link aggregation group works only if both ends agree about it in A static link aggregation group works only if both ends are configured for the
advance. Nothing checks that they do: cable a member to the wrong neighbour and same links, and nothing checks that they are. LACP lets the two ends agree on
the group keeps hashing frames onto a link that goes somewhere else. LACP is the which links reach the same partner, aggregates only those, and takes a link out
protocol that makes the two ends agree, and keeps agreeing — it discovers which of the group when the partner stops answering.
links reach the same partner, aggregates only those, and drops a link out of the
group when the partner stops answering.
The switch runs LACP in software on the 8051. Frames are the Slow Protocols The switch runs LACP in software on the 8051. LACP frames belong to the Slow
group: destination `01:80:C2:00:00:02`, ethertype `0x8809`, subtype 1. The Protocols, with destination `01:80:C2:00:00:02` and ethertype `0x8809`; the
implementation covers the parts that decide whether an aggregate forms: subtype of LACP frames is 1. The implementation has the Receive, Selection and
the Receive machine and the Selection and Mux machines of 802.3ad clause 43, Mux machines of 802.3ad clause 43 and does not aggregate links whose partners
`recordPDU` and `update_NTT`, and the mis-cabling protection that refuses to differ. Up to `LACP_NUM_LAGS` (4) groups can run LACP; the others stay static.
aggregate links whose partners differ. It does not implement the Churn Detection
machines or the Marker protocol, and the Mux machine is the coupled variant, so
collecting and distributing are enabled together rather than in sequence.
Up to `LACP_NUM_LAGS` (4) groups can be placed under LACP; the rest stay static.
## Getting the frames to the CPU ## Getting the frames to the CPU
Reserved multicast addresses are handled by the RMA block before the L2 lookup While LACP runs, the reserved multicast action for `01:80:C2:00:00:02` is
happens. Each address has its own register and the action field sits in bits *trap*, the same mechanism STP uses for its BPDUs, see [stp.md](stp.md). A
[5:4]: 0 forward, 1 trap to CPU, 2 drop, 3 forward excluding the CPU. The trapped LACPDU has no VLAN tag after the RTL tag, and `TRAP_RX_BODY()` gives the
registers are packed and consecutive by *entry* rather than by address byte, so offset of the LACPDU in the received frame. When the last group leaves LACP,
the step of 4 counts entries, not bytes of the address: `...:00` sits at the action goes back to *drop*.
`0x4ecc` and `...:02` at `0x4ed4`, but `...:08` sits at `0x4ee0`.
```
#define RTL837X_RMA0_CONF 0x4ecc /* 01:80:C2:00:00:00, entry 0 */
#define RTL837X_RMA2_CONF 0x4ed4 /* 01:80:C2:00:00:02, Slow Protocols */
#define RTL837X_RMA_ACT_MASK 0x30
#define RTL837X_RMA_ACT_TRAP 0x10
#define RTL837X_RMA_ACT_DROP 0x20
```
The engine puts this address on *trap* while it runs. A trap takes the frame
out of the forwarding path and hands it to the port named in `EXT_CPU_CTRL`
(`0x6724`), whose reset value names no port at all: the destination is meant to
be an *external* CPU on a physical port, which these boards do not have. That
is why the trap first looked like a dead end - the receive counters stayed
frozen while the partner kept sending, and the ingress discard counter grew
instead. `trap_init()` points the register at the CPU port once at startup, and
the same frames then arrive.
`FORWARD` reaches the CPU too, because the CPU port is in the forwarding
domain, but a forwarded frame is subject to the L2 lookup and on its own floods
to every other port in the VLAN. That leaks a neighbour's LACPDUs to hosts that
must not see them and, with two bonds on one switch, poisons both; a reserved
link-local group must not be forwarded at all. Containing it takes a static L2
multicast entry with a CPU-only member mask, and because lookups are IVL on
this chip, one entry per distinct pvid over all front panel ports - a VID 0
entry is never matched, and a port outside the LACP groups needs its pvid
covered as well, or a LACPDU arriving there misses the lookup and is flooded
through its VLAN.
The trap needs none of that and reaches further, because it acts on the address
before the VLAN lookup and before the ingress filters. An untagged LACPDU is
delivered on a port that admits tagged frames only, where a forwarded one is
dropped by the acceptable-frame-type filter; and it is delivered on a port STP
holds in blocking, so a group converges without waiting out the forward delay.
Both were measured against forward on the same ports of an SWTGW218AS.
A trapped frame arrives without the VLAN tag the hardware inserts into a
forwarded one, so the LACPDU body sits four bytes earlier. `TRAP_RX_BODY()`
gives the offset of the body for either form, and `lacp_in()` reads the PDU
from there.
Neighbouring addresses in the same block still differ in other respects -
`...:00` is exempt from the ingress STP-state check and `...:02` is not, which
the trap makes moot only because it acts before that check - so measure before
carrying a conclusion about one of them across to another.
When LACP is switched off the action goes to `DROP`, which acts before the L2
lookup, so there is nothing to undo.
## What has to match across the members ## What has to match across the members
@@ -92,42 +36,30 @@ mismatch should be rejected or applied to the whole group.
## Protocol timing ## Protocol timing
``` The timer values are in units of the LACP timer, which steps every four ticks
#define LACP_FAST_PERIODIC 0x0032 /* fast TX 1 s; partner expires at 3 s */ of the system clock, 50 times per second:
#define LACP_SLOW_PERIODIC 0x05dc /* slow TX 30 s; partner expires at 90 s */
#define LACP_SHORT_TIMEOUT 0x00c8 /* silent partner dropped after 4 s (802.3ad: 3 s) */
```
One unit is one step of the LACP timers, taken every four system ticks, so 50 | Constant | Value | Time |
per second whatever the pace of the main loop; 50 units came out as 1.00 s on |----------------------|-------|------|
the wire in all 116 intervals of a two minute capture. | `LACP_FAST_PERIODIC` | 50 | 1 s |
| `LACP_SLOW_PERIODIC` | 1500 | 30 s |
| `LACP_SHORT_TIMEOUT` | 200 | 4 s |
The two transmit periods are worth a word, because they are the one thing here 802.3ad specifies a fast periodic time of 1 s with a short timeout of 3 s, and a
that is not ours to choose freely. Our own timeouts only decide how patient we slow periodic time of 30 s with a long timeout of 90 s. The switch transmits at
are with a partner that has gone quiet, and being slow there costs nobody the rate the partner asks for with its TIMEOUT bit. Its own timeout is always
anything. The transmit period is the opposite: it decides when the *partner* the short one, one second above the standard, so a partner that stops sending
gives up on us. 802.3ad pairs a 1 s fast period with a 3 s short timeout, and a while its link stays up leaves the trunk after 4 s.
30 s slow period with a 90 s long timeout, and the ratio is the whole point.
Getting that wrong does not break the aggregate, which is what makes it easy to The Partner block of a transmitted LACPDU repeats the partner's actor
miss. An earlier version of this code transmitted every 2 to 3 s while the information as it was last received: system priority, system, key, port
partner was asking for the fast rate. The links still aggregated and still priority, port and state. A Linux partner sets our SYNC only when this block
carried traffic, but every time a gap crossed 3 s the partner's receive machine matches what it sent.
timed us out and recovered: 13 of its 93 LACPDUs came back carrying `EXPIRED`
and reporting our SYNC as cleared. Since a received actor state is recorded
verbatim as the partner state and sent back out, the flap was visible from both
ends, and the bond's churn machines never settled. With the periods above, the
same capture shows no expiry at all and both churn states read `none`.
Our own timeouts sit one period above the standard's 3 s and 90 s, which
absorbs a single lost LACPDU plus the tick jitter. A partner whose LACP has
stopped while its link stayed up is out of the trunk after that; anything
longer keeps hashing traffic onto a member that no longer agrees to carry it.
## LACP API ## LACP API
``` ```
void lacp_init(void) __banked; /* boot init: clear per-LAG state */ void lacp_init(void) __banked;
void lacp_off(void) __banked; void lacp_off(void) __banked;
void lacp_lag_set(uint8_t lag, __xdata uint16_t ports) __banked; void lacp_lag_set(uint8_t lag, __xdata uint16_t ports) __banked;
void lacp_in(void) __banked; void lacp_in(void) __banked;
@@ -193,35 +125,25 @@ On the switch, with those two ports as the group:
lag 1 lacp 7 8 lag 1 lacp 7 8
``` ```
`lacp show` should then give both ports an actor state of `0x3f`, which is `lacp show` should then give both ports an actor state of `0x3f` (ACTIVITY,
ACTIVITY, TIMEOUT, AGGREGATION, SYNC, COLLECTING and DISTRIBUTING together, a TIMEOUT, AGGREGATION, SYNC, COLLECTING and DISTRIBUTING), a partner state with
partner state with SYNC in it, and the partner's system MAC. `lag show` should SYNC set, and the partner's system MAC. `lag show` lists the trunk members as
list both ports as trunk members, since that reads the hardware rather than the programmed in the hardware and should show both ports.
protocol's opinion of itself.
The host's view is the one worth trusting, in `/proc/net/bonding/bond0`. Both On the host, `/proc/net/bonding/bond0` should show the same `Aggregator ID` for
slaves want the **same `Aggregator ID`**; two different numbers mean the bond both slaves; different IDs mean that each link is in a group of its own. Both
has not aggregated anything and each link is sitting in its own group, which churn states should read `none`.
looks healthy at a glance and is not. Both churn states should read `none`.
`monitoring` that never settles is the signature of our transmit period being
too slow for the rate the partner asked for.
Three things are worth checking past convergence, because each of them has been Further checks:
broken here at some point:
* `tcpdump -i enp1s0 ether proto 0x8809` on each slave should show the switch's * `tcpdump -i enp1s0 ether proto 0x8809` on each slave shows the LACPDUs of the
LACPDUs and that slave's own, and never the other slave's. A sibling leak is switch and of that slave, never those of the other slave.
what the trap prevents: the PDU never enters the forwarding path at all. * The host log has no `illegal loopback`.
* No `illegal loopback` in the host's log. * The three reserved bytes after the actor state in a LACPDU from the switch
* In a hex dump of a frame from the switch, the three reserved bytes after the are zero.
actor state should be zero. They used to carry whatever the transmit buffer
held from the previous frame.
Pulling one slave down and putting it back is the cheapest failure test. The When one slave goes down, the group narrows to the remaining member, and the
group narrows to the surviving member and comes back within tens of seconds, slave rejoins after it comes back.
and traffic across the transition loses a few percent at the edges rather than
half of everything, which is what it would lose if the ASIC kept hashing onto
the dead member.
## Known limits ## Known limits
+4
View File
@@ -227,3 +227,7 @@ iperf Done.
``` ```
As you can see, the total throughput was 4.71 GBit/sec which is close to the As you can see, the total throughput was 4.71 GBit/sec which is close to the
maximum possible with a single 5GBit link. maximum possible with a single 5GBit link.
## LACP
Dynamic aggregation with LACP is described in [lacp.md](lacp.md).