port: read a trunk's members through one function - #347
Merged
Conversation
vDorst
reviewed
Aug 15, 2026
Comment on lines
+742
to
+746
| uint16_t port_lag_members_get(__xdata uint8_t lag) __banked | ||
| { | ||
| reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2)); | ||
| return ((uint16_t)sfr_data[2] << 8) | sfr_data[3]; | ||
| } |
Collaborator
There was a problem hiding this comment.
Need lag to be on __xdata?
Maybe this is micro-optimization but we can skip the write&read to/from sfr_data.
uint16_t port_lag_members_get(uint8_t lag) __banked
{
reg_read(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2));
return ((uint16_t)SFR_DATA_8 << 8) | SFR_DATA_0;
}The member mask of an aggregation group is decoded by hand in two places, the lag command and the JSON behind the aggregation page, and every branch that touches trunks adds another copy. port_lag_members_get() sits next to port_lag_members_set() and both readers call it. It answers from the hardware, so it covers a group configured with lag and one a protocol brought up, without either having to say so. It reads through reg_read() rather than reg_read_m(), so sfr_data is left alone. Neither caller looked at it afterwards; both read the hash register next.
Contributor
Author
|
Both in, thanks. The parameter loses |
DrDoof
force-pushed
the
feat/lag-members-get
branch
from
August 15, 2026 19:02
f201687 to
f2c6ac0
Compare
Collaborator
|
Thanks! |
This was referenced Aug 15, 2026
vDorst
pushed a commit
that referenced
this pull request
Aug 31, 2026
VLAN membership, PVID, egress tagging, isolation and MTU are all per physical port in this ASIC, so nothing stopped a member of a working aggregation group being given a different PVID from its peers. The group then forwards asymmetrically depending on which member the hash picks, and no part of the firmware says a word about it. port_lag_of() answers which group a port belongs to, reading the membership through the shared reader rather than a fourth private copy. port_pvid_set() expands to the whole group when the port it is given is a member, and ports outside a group keep the path they had. This is the second and third of the three steps set out in #347. I said there that the lookup would come when something needed it, which had it the wrong way round: nothing in the tree asks which group a port is in, so the lookup only earns its place alongside a caller. PVID is the smallest such caller, and the rest of the per port settings can follow the same shape once this one is agreed. Built for SWTGW218AS and KP_9000_6XHML_X2 on sdcc 4.5.0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Small on its own, and the first piece of something larger, so let me say where it is going as well as what it does.
The member mask of an aggregation group lives in four registers at
RTL837X_TRK_MBR_CTRL_BASE. Two places decode it by hand today, thelagcommand and the JSON behind the aggregation page, with the same two lines each, and a third writes it. My Spanning Tree work in #325 has a fourth copy of the decode, which is what made me look.port_lag_members_get()now sits next toport_lag_members_set(), the two readers call it, and the writer is untouched.It answers from the hardware, so it covers a group configured with
lagand a group a protocol brought up without either having to declare itself, which matters for the direction below.No behaviour change. The expression is the one that was already written in both places, and neither caller depended on what the read left in
sfr_data, since both go on to read the hash register next. 26 bytes of BANK1, 34 fewer of BANK2 and one byte of xdata for the banked parameter, so eight bytes less code in total. I read the generated assembly rather than assuming: the address still comes out as0x4f38plus the group shifted twice.What it does not give is worth being blunt about, because the title could be read as more than it is. There is still no way to configure an aggregate as one interface. VLAN membership, PVID, egress tagging, ingress filtering, isolation, the learning constraint and MTU are all per physical port in this ASIC: the VLAN table holds a bitmask of physical ports, PVID sits at
PVID_BASE + ((port >> 1) << 2), the egress tag bits atport << 1, isolation and the learning constraint at+ (port << 2). Nothing about a trunk exists at that level, so a trunk interface has to be a software layer, not a register.Nor does this add a port to group map.
port_lag_members_get()answers "who is in group N", not "which group is port N in".The practical consequence of both, today: nothing stops a member of a working aggregate being given a different VLAN from its peers. The group then forwards asymmetrically depending on which member the hash picks, and no part of the firmware says a word about it.
As for how I would like to continue, there are three steps of which this is the first, and I would rather agree the shape with you than turn up with all of it at once.
Second, a port to group lookup, added when there is a consumer for it rather than before. #325 is that consumer: it keeps a private membership map and a private port to entity array purely because there was nothing shared to use. When that lands, it drops both and gets smaller.
Third, the expansion layer, which is the part that actually delivers a trunk interface. A command naming a group expands to the member mask before touching any register, membership changes re-apply the group's configuration to the port that joined or left, and the saved configuration stores the group form rather than one line per member. #325 already establishes that last pattern for the STP commands in
config.js, so generalising it is extending something rather than inventing it. The open question there is what happens when a member is configured individually: refuse it, or accept it and re-sync the group.If you would rather that whole direction stayed out of the tree, say so and I will keep it on my side and leave this PR as the plain deduplication it is, which stands on its own either way.