Skip to content

RFC: realtek/rtl931x stacking support - #25269

Draft
stintel wants to merge 46 commits into
openwrt:mainfrom
stintel:rtl931x/stacking
Draft

stintel wants to merge 46 commits into
openwrt:mainfrom
stintel:rtl931x/stacking

Conversation

@stintel

@stintel stintel commented Sep 19, 2026

Copy link
Copy Markdown
Member

A month ago I acquired 2 Linksys LGS352C units for EUR100 each. Then discover the rtl931x silicon has stacking support. So I launched codex and I now have a single switch stack combining those 2 units.

I am posting this work early, so people know this kind of enterprise feature is possible. It's a very first attempt, and while it works, it's not working how I would want it to work, and will need a lot of work before this can land upstream.

As most active realtek contributors are not active on IRC, this PR also serves as a place to discuss, in public.

Some snippets of the code in action:

`ubus call rtl931x.stack status` on stack leader
root@cs1-0:~# ubus call rtl931x.stack status
{
        "phase": "ready",
        "policy": "wait",
        "interface": "sw0s0p49",
        "interfaces": [
                "sw0s0p49",
                "sw0s0p50"
        ],
        "configured": true,
        "ready": true,
        "fallback": false,
        "member_id": 0,
        "peer_id": 1,
        "master_id": 0,
        "generation": 1,
        "flags": 0,
        "ready_timeout": 60,
        "elapsed": 37323,
        "attempts": 18645,
        "stack_enabled": true,
        "link_up": true,
        "stack_state": 1,
        "local_port_mask": 13792273858822143,
        "local_delegated_port_mask": 0,
        "fabric_port_mask": 1407374883553280,
        "active_fabric_port_mask": 1407374883553280,
        "verified_fabric_port_mask": 1407374883553280,
        "peer_netdevs_desired": true,
        "peer_netdevs_active": true,
        "peer_netdevs_published": true,
        "peer_netdevs_fenced": false,
        "peer_netdevs_recovering": false,
        "peer_netdevs_last_error": 0
}
`ip link` on stack leader
root@cs1-0:~# ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1505 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
3: sw0s0p1@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
4: sw0s0p2@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
5: sw0s0p3@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
6: sw0s0p4@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
7: sw0s0p5@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
8: sw0s0p6@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
9: sw0s0p7@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
10: sw0s0p8@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
11: sw0s0p9@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
12: sw0s0p10@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
13: sw0s0p11@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
14: sw0s0p12@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
15: sw0s0p13@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
16: sw0s0p14@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
17: sw0s0p15@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
18: sw0s0p16@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
19: sw0s0p17@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
20: sw0s0p18@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
21: sw0s0p19@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
22: sw0s0p20@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
23: sw0s0p21@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
24: sw0s0p22@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
25: sw0s0p23@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
26: sw0s0p24@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
27: sw0s0p25@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
28: sw0s0p26@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
29: sw0s0p27@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
30: sw0s0p28@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
31: sw0s0p29@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
32: sw0s0p30@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
33: sw0s0p31@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
34: sw0s0p32@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
35: sw0s0p33@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
36: sw0s0p34@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
37: sw0s0p35@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
38: sw0s0p36@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
39: sw0s0p37@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
40: sw0s0p38@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
41: sw0s0p39@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
42: sw0s0p40@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
43: sw0s0p41@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
44: sw0s0p42@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
45: sw0s0p43@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
46: sw0s0p44@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
47: sw0s0p45@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
48: sw0s0p46@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
49: sw0s0p47@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
50: sw0s0p48@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
51: sw0s0p49@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
52: sw0s0p50@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
53: sw0s0p51@eth0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc noqueue master bond0 state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
54: sw0s0p52@eth0: <NO-CARRIER,BROADCAST,MULTICAST,SLAVE,UP> mtu 1500 qdisc noqueue master bond0 state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
55: stack0@sw0s0p49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master switch state UP mode DEFAULT group default qlen 1000
    link/ether 66:1b:17:b4:fc:b6 brd ff:ff:ff:ff:ff:ff
56: sw1s0p1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master switch state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
57: sw1s0p2@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
58: sw1s0p3@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
59: sw1s0p4@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
60: sw1s0p5@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
61: sw1s0p6@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
62: sw1s0p7@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
63: sw1s0p8@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
64: sw1s0p9@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
65: sw1s0p10@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
66: sw1s0p11@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
67: sw1s0p12@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
68: sw1s0p13@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
69: sw1s0p14@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
70: sw1s0p15@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
71: sw1s0p16@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
72: sw1s0p17@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
73: sw1s0p18@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
74: sw1s0p19@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
75: sw1s0p20@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
76: sw1s0p21@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
77: sw1s0p22@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
78: sw1s0p23@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
79: sw1s0p24@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
80: sw1s0p25@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
81: sw1s0p26@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
82: sw1s0p27@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
83: sw1s0p28@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
84: sw1s0p29@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
85: sw1s0p30@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
86: sw1s0p31@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
87: sw1s0p32@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
88: sw1s0p33@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
89: sw1s0p34@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
90: sw1s0p35@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
91: sw1s0p36@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
92: sw1s0p37@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
93: sw1s0p38@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
94: sw1s0p39@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
95: sw1s0p40@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
96: sw1s0p41@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
97: sw1s0p42@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
98: sw1s0p43@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
99: sw1s0p44@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
100: sw1s0p45@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
101: sw1s0p46@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
102: sw1s0p47@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
103: sw1s0p48@eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue master switch state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
104: sw1s0p51@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
105: sw1s0p52@eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2d:85 brd ff:ff:ff:ff:ff:ff
106: switch: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
107: switch.30@switch: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
108: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue master switch state UP mode DEFAULT group default qlen 1000
    link/ether 80:69:1a:47:2c:12 brd ff:ff:ff:ff:ff:ff
Details

@openwrt openwrt Bot added add package Introduces a new package Makefile build script core packages pull request/issue for core (in-tree) packages kernel pull request/issue with Linux kernel related changes not following guidelines Pull request does not follow formatting guidelines target/realtek pull request/issue for realtek target labels Sep 19, 2026
@stintel
stintel marked this pull request as draft September 19, 2026 17:55
@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
dsa_switch_shutdown() only disconnects the conduit during system
shutdown. It does not remove the switch from the DSA tree before the
driver releases its private state.

Use dsa_unregister_switch() during probe unwind and driver removal so
DSA tears down the tree first. Make the link-state IRQ device-managed so
it cannot outlive the switch state.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add RTL931x hardware programming for the tested two-member, one-link
topology. Configure switch identities, device routes, the fabric port,
stack trunks and non-unicast forwarding as one transaction.

Snapshot every touched register, preserve unrelated shared fields and
migrate local FDB device IDs when the silicon identity changes. Retain
the snapshot until restoration succeeds so partial failures remain
recoverable.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Expose a versioned generic netlink interface for configuring and
inspecting the fixed two-member, one-link topology.

Validate topology and monotonically increasing generations, serialize
configuration with DSA register accesses and reject unsupported use of
the active fabric port. Preserve explicit error state when hardware
rollback cannot prove that the original configuration was restored.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
The RTL931x CPU tag identifies the original source device and port on RX
and selects a destination switch unit on TX. Carry that information
instead of treating every packet as local device zero.

Extend the software trailer with a device field and cache the local
switch identity in the tagger. Fence RX and drain conduit TX while that
identity changes. Preserve DSA source metadata for exceptional local
CPU-tag copies whose original source port differs from their physical
ingress, while rejecting mismatches during identity changes. Retain
fragmented-frame discard state across NAPI polls.

Use the ratelimit helpers available in the OpenWrt 6.18 kernel when
reporting rejected CPU-tag traffic.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add the RTL931x CPU-tag modes needed for one-hop physical delivery and
routed CPU-to-CPU unicast. Provide a consuming Ethernet helper which
passes private destination metadata to the descriptor-based TX path.

Intercept CPU2CPU receive reason 1 before the ordinary remote-device
drop, preserve its classification across fragments and attach the local
fabric ingress as metadata. Deliver only validated control frames to the
stack protocol handler.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Provisionally reserve the candidate fabric port and exchange CPU Device
Talk PING and PONG messages before changing either switch identity. Bind
the proof and delayed replies to the carrier epoch and CPU-device
generation so a link flap cannot authorize a stale peer.

Apply the RTL931x stack link-up workaround around MAC release, preserve
the pre-arm port-register image for rollback and leave the fabric port
down whenever recovery is uncertain. Reject active LAG configuration
before closing and restarting the selected port.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Separate the common CPU Device Talk fields from the probe-specific body
so later routed messages can share the transport.

Keep the version 1 PING and PONG layout byte-for-byte unchanged,
including its fixed zero padding.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Split common and probe validation and teach the transmitter to carry
bounded typed bodies. Enforce canonical lengths and zero padding so each
message has one wire representation.

Preserve the existing PING and PONG protocol and keep transmission
serialized against CPU identity changes.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Allow the RTL931x CPU port to address a physical port on an explicit
remote stack device. On RX, route a validated remote source device and
port tuple through an RCU-published peer-netdevice map.

Make the exported peer-port TX buffer contract explicit. Unshare and
linearize each skb before appending the destination trailer because the
MAC reads that trailer through skb->data and maps one contiguous DMA
buffer.

Retain the tuple across fragmented frames and resolve the destination
only at the real packet tail. This lets map teardown synchronize against
the complete receive operation and prevents stale netdevice access.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add a typed CPU Device Talk RPC for querying a configured peer's switch
inventory and per-port state. Fence every request with both boot nonces,
the stack generation and the routed source and destination identities.

Keep the initial operations read-only so retries with one transaction ID
do not require a mutation replay cache. Expose only explicit
administrative generic netlink queries instead of a raw register tunnel.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Some switch fabrics represent ports of a peer switch using netdevices
owned by one control-plane switch. The peer's DSA user netdevice must
stop being a data and configuration endpoint while phylink keeps the
physical port running.

Add an RTNL-serialized delegation API. Fence RX, TX, upper changes and
DSA configuration while delegated, but preserve the host address and
phylink state required by the replacement data path. On undelegation,
restore normal DSA ownership before reattaching the user netdevice.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add an absolute, master-only CPU Device Talk operation for transferring
the follower user ports to the stack leader. Apply the DSA delegation
API under RTNL and roll back every port if the full set cannot be
transferred.

Track the resulting mask for idempotent retries and lifecycle cleanup.
Keep follower phylinks running while preventing their local DSA
netdevices from carrying traffic or changing switch configuration.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Extend the peer switch query with user, administrative, carrier and
delegated-port masks plus the peer topology and protocol capabilities.

Return one coherent inventory snapshot so the leader can validate the
entire follower before publishing replacement netdevices. Keep the
per-port query for details which cannot be represented in the masks.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add exact RTL931x SRAM and CAM lookup helpers for CPU host FDB entries.
Claim or create each plain host entry, move its destination between the
follower and leader CPU ports and restore or remove it when delegation
ends.

Handle both hash banks correctly, use the RTL931x maximum age of seven
and disable background aging on CPU port 56. Recognize the exact aged
static-entry shape produced by the hardware and canonicalize it before
changing ownership, while rejecting duplicate or special entries.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Create ordinary Ethernet netdevices on the stack leader for the
follower's user ports. Transmit through the leader conduit with an
explicit remote device and physical port, and publish an immutable RCU
map for the matching receive path.

Delegate all follower ports before making the replacements visible.
Fence and unpublish them before identity changes, link teardown or
unregistration, and retain netdevice references until all RCU readers
and conduit transmissions are drained.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Add a target-gated libnl-tiny client for the RTL931x stack generic
netlink family. Support status, Device Talk arm and probe, two-member
configuration, peer inventory and peer-netdevice control operations.

Print typed replies as key-value records and include kernel extended ACK
messages on failure. Enable GNU libc extensions because libnl-tiny's
credential declarations require struct ucred from the system headers.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Remove the assumption that every follower user port has one common MAC
address. Report each address through GET_PORT_STATE and have the leader
query every advertised port before creating its replacement netdevice.

Track a deduplicated set of follower host addresses for FDB ownership,
so shared addresses are moved once while unique addresses retain their
individual destinations. Bump the private and generic netlink protocol
versions to reject peers and clients with the old address semantics.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Validate the complete follower port set before changing ownership.
Require each transitioning DSA user netdevice to be administratively up,
present and free of bridge, LAG, HSR or other upper devices. Reject any
disagreement between the tracked and generic DSA delegation state.

Report the failing port or host FDB operation on the follower and map
permission conflicts separately from retryable busy conditions in the
Device Talk result. This gives the leader an actionable extended ACK.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Fence leader-owned peer ports immediately when the fabric link goes
down. Track the desired publication state and a monotonic link epoch so
a down and up cycle during activation cannot publish stale inventory.

After link recovery, rerun peer inventory and absolute delegation before
reattaching the netdevices. Retry transient failures with bounded
delayed work, and synchronize work cancellation with stack teardown so
recovery cannot outlive its context.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Allow leader-owned peer ports to join one VLAN-aware Linux software
bridge without claiming switchdev offload. Program only the hardware
transport needed to carry those VLANs over the hidden fabric port while
the leader bridge remains the forwarding authority.

Add typed, absolute Device Talk operations for follower bridge-port and
VLAN state. Keep peer learning disabled, redirect BPDUs to the master
CPU, maintain tagged fabric membership on both switches and restore
exact saved state during leave or rollback. Reject unsupported bridge
flags, MST, VLAN protocols and multicast-offload modes.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Extend the stack status reply with the local user-port mask and the mask
currently delegated to a remote leader. Exclude the selected fabric port
while stacking is configured or provisionally armed.

This lets an early boot manager distinguish hardware configuration from
complete follower ownership transfer before releasing normal networking.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Replace the monolithic diagnostic source with a shared generic netlink
client used by both the command-line utility and a new full-C daemon.

Read the stack topology and boot policy from UCI. Bring up the fabric
and required follower ports, verify the peer, configure both members and
either publish leader peer netdevices or wait for follower delegation.
Expose status and recovery methods through ubus and publish a separate
readiness object only after the complete transaction is verified.

Start the daemon before the network service and make the existing switch
setup hook wait for that readiness object. Support indefinite waiting,
fail-closed timeout and rollback-to-standalone policies, restoring the
original administrative port state after a successful fallback.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
A member can remain configured while its peer is rebooted and upgraded.
The surviving member then retains the old peer boot nonce. Routed
PING/PONG continues to work after the peer returns, but RPC requests are
silently rejected because their session validation uses the stale nonce.
This leaves stackd waiting for peer inventory indefinitely.

Treat a successful routed probe as an explicit session
re-establishment. Before accepting it, require the configured peer and
master IDs, generation, physical stack port, and all configured/route
status bits to match. If the boot nonce changed, invalidate the old
session, reset mutation and replay state, and publish the new nonce.

Keep the one-hop verification path using the same session publication
helper. This allows independently rebooted members to converge again
without disabling an otherwise operational stack.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Leader representor open and stop currently only change the local queue.
The delegated follower netdevice remains physically enabled, so a down
representor can continue to learn and emit traffic.

Extend DSA delegation with an explicit physical administrative state.
Keep the original user netdevice detached while the owner starts or
stops the port, and restore its current state when delegation ends.

Add an absolute full-bitmap Device Talk v9 mutation. Apply it
transactionally on the follower, preserve down-port isolation through
bridge replay, and verify the resulting inventory before activation.

Drive the bitmap from representor IFF_UP state. Fence and recover all
peer ports after an uncertain mutation. Replay the desired state during
recovery, and detect later divergence during periodic inventory
synchronization.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Peer netdevices expose a narrow remote bridge interface, but the current
documentation does not clearly distinguish them from DSA user ports.

Document the supported data, administrative, carrier and bridge surface.
List unsupported PHY, ethtool and offload operations, and explain the
existing Device Talk capability negotiation.

Defer a permanent per-netdevice feature ABI unless representors survive
the planned cascaded-DSA work.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
The generic delegation patch is a driver-shaped experimental API. Normal
DSA cascading does not model two switches owned by separate kernels, but
the current boolean is not yet a general ownership abstraction.

Document the ownership, lifetime, phylink, suspend, removal and feature
semantics that need an RFC before the API grows or is submitted.

Also record that the independent RTL83xx switch-unregister correction is
already a separate commit and must remain outside that series.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Automatic fallback must not reclaim follower ports while a former
leader may still own them. That prevents split-brain forwarding, but
leaves no supported recovery after an unrecoverable leader failure.

Add an explicit local recovery command. Require the single fabric
link to have no carrier and a newer generation. Close it before
changing ownership, invalidate the peer session, restore delegated
ports and saved switch state, and leave recovered ports down.

Keep the operation out of Device Talk and stackd automatic fallback.
Bump the generic netlink API to version 6, add matching CLI support
and document the recovery procedure.
The proof-of-concept stack has exercised its principal data paths on
hardware, but the protocol, recovery and rollback logic lacks automated
coverage. Record that limitation explicitly rather than allowing
successful bench tests to imply production readiness.

List the unit, fault-injection and hardware validation areas that need
coverage before wider deployment.
The Realtek Otto watchdog restart handler runs through an atomic
notifier after MIPS has stopped the secondary CPUs. disable_irq() may
sleep while synchronizing an active handler. If that handler was
running on a stopped CPU, reboot deadlocks before the watchdog reset is
armed.

Backport a change to disable_irq_nosync(). Waiting for an old phase 1
handler is unnecessary when the watchdog is immediately reprogrammed
to reset the SoC.
DSA assisted learning treats bridge ports outside its own tree as
foreign and installs their learned addresses on the CPU port. This is
incorrect for switchdev representors sharing the DSA switch parent ID:
it overwrites the ASIC-learned remote destination and breaks hardware
forwarding.

Treat same-parent bridge ports as part of the local offload domain
while retaining assisted learning for genuinely foreign ports. Include
the RTL931x device ID in the debugfs L2 table output so distributed FDB
destinations can be verified directly.
The current PCS attachment selection treats 10GBASE-R as fibre. Test
the existing long-DAC analogue and TX settings against the observed
one-sided and unstable links with FS SFPP-PC03 3 m passive cables.

Override the attachment in the RTL931x configuration path only, before
programming and recording it. Log the experimental override whenever
the SerDes is reconfigured. Other families and interface modes retain
their existing attachment selection, with no generic phylink changes.

This deliberately forces DAC_LONG for all RTL931x 10GBASE-R links,
including short DACs and optical modules. It does not identify the
inserted medium or cable length and is not a general-purpose fix.

DAC RX calibration remains unimplemented, so this selects the existing
DAC path without running the fibre RX calibration. An absent fibre
calibration warning is not evidence that the link is working correctly.

No build was run. Hardware validation is pending with the 3 m DAC to
Huawei and the 1 m DAC between the two Linksys switches.
Implement the missing DAC LEQ/DFE receive-training sequence after
selecting the DAC attachment profile. Validate the PCS link and symbol
errors before reporting carrier instead of trusting the forced MAC
status mirror.

Advance calibration through PCS polling with bounded checks and
per-lane retry backoff. Retrain after link loss or replacement and
stop calibration when the PCS is disabled. Preserve the working
sibling lane by avoiding shared PLL reconfiguration during retries.

Keep the experimental DAC_LONG override and leave generic phylink
and DTS unchanged. Validate with checkpatch, git diff --check,
and interpreted C state-machine tests with mocked register access,
including one-shot errors at 52 I/O/helper operations. No compilation
was run; hardware validation remains pending.
Extend the fixed two-member RTL931x stack from one fabric link to a
hardware stack trunk containing up to four physical links. This allows a
48-port switch pair to use the full four-port SFP+ block as a 40 Gbit/s
fabric while retaining operation after individual member failures.

The Realtek Mango hardware provides 16 stack-port slots and eight
stack-trunk groups. Reserve one slot for each configured link. Place
live slots in stack trunk 0 and route the peer over the same slot
bitmap.
Enable stack-hash recalculation and link-down avoidance only while the
route has multiple members. Preserve the proven direct slot route when
exactly one member is live.

Arm every configured link but require only one successful one-hop Device
Talk exchange before committing the stack identity. Keep unverified
links out of the hardware route. Verify late or restored links directly
before admitting them. Require the configured peer identity and boot
nonce, and invalidate that verification whenever carrier is lost. This
lets a stack boot with any non-empty subset of its configured fabric
without allowing a cable moved to another switch into the trunk.

Track configured, verified and active fabric masks separately. Program
hardware routing from the live verified subset and refresh the stack
trunk whenever that subset changes. Keep peer representors usable while
at least one member remains active, but fence them when the final member
goes down.

Apply delegation baselines, distributed bridge isolation matrices and
VLAN membership only to the routed fabric subset. Configured but
unverified links remain available for one-hop Device Talk without
carrying ordinary data. Apply data policy before admitting a link to the
route, remove the route before withdrawing policy, and fail closed to an
empty route after an uncertain update. Continue probing missing
configured members after the daemon reaches ready state so late and
restored links can join automatically.

Make disabled-state daemon convergence replace the complete provisional
topology before arming the configured UCI ports. This discards stale
armed members and carrier snapshots after a failed attempt or topology
change. Validate and prune the verified subset before administratively
closing fabric netdevs for the hardware transition; preserve that
snapshot while the ports are intentionally down. Otherwise stackd can
enter a one-second close, stale-verification failure and reopen loop.

Bump the private Device Talk protocol to version 10 and generic netlink
to version 7 for the incompatible inventory and status changes. Accept a
UCI list of one to four interfaces, reject duplicates, validate every
configured interface against the active kernel trunk, and report all
three masks through the CLI and ubus status.

Add a read-only stack_routes debugfs dump covering stack identities,
slot assignments, device routes and stack-trunk groups. It provides the
register evidence needed for bench diagnosis without requiring /dev/mem.

This remains a hardware-test WIP. No build was run while preparing this
commit. Bench validation still needs to prove flow distribution,
failed-member avoidance and restoration, degraded bootstrap,
all-links-down recovery, bridge/VLAN state replay, and rollback while
individual trunk members flap.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Reuse complete and partial provisional fabric sets instead of disarming
them on every convergence attempt. Repeated disarm and reopen cycles
restart PCS calibration and can prevent DAC links from reaching
carrier while flooding the console.

Only replace a disabled provisional set when it contains unwanted
ports. Preserve armed ports after a daemon restart, partial setup
or lost netlink reply, and propagate errors without resetting the
fabric. Document the behavior and bump the package release.

Validated with diff checks and interpreted C control-flow tests for
partial setups, retries, lost arm replies and failed status reads. No
compilation or hardware validation was performed.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Replace the blanket LAG/stack exclusion with checks for overlapping
fabric ports and delegated ownership. A leader-local LACP uplink
can be created before or after the native stack trunk without netifd
ordering changes.

Use the current hardware device ID in normal LAG entries and
source-port mapping keys. Rebind existing groups when stack identity
changes and when returning to standalone mode. Keep link-down avoidance
enabled during fabric route changes. Correct LAG membership bookkeeping
and primary-port reelection.

Mirror leader-local LAG membership and selected TX candidates to
the delegated follower using session-checked, sequenced Device Talk
mutations. Preserve original table rows for cleanup, retain restoration
state across failed updates, flush obsolete dynamic learning, and
replay current groups before restoring peer bridge forwarding. Peer
synchronization failures schedule representor recovery without
rejecting the local uplink change.

Bump the private Device Talk protocol to version 11, advertise local
LAG synchronization, and document its scope and pending hardware
tests. Both stack members require matching firmware; remote representor
bonds and cross-chassis LACP remain unsupported.

Validated with checkpatch, diff checks, C syntax parsing and
interpreted tests using mocked tables, including membership updates,
device-ID rebinding, peer-update failures and cleanup retries. No
compilation or hardware validation was performed.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
Name local ports and peer representors sw<member>s<slot>p<panel-port>.
Use the configured member identity and front-panel numbering, reserving
slot zero for built-in ports. Keep hardware indices and stack0
unchanged.

Resolve local port locations from existing device-tree labels without
DTS changes. Apply names before network startup, accept board labels as
fabric configuration aliases, and refuse to rename live or enslaved
ports. Roll back completed renames if a subsequent rename fails.

Add an optional read-only Device Talk port-location request without a
wire-version bump. Use peer-provided locations for representor names,
falling back to legacy names when the peer lacks the request.

Document the naming scheme, configuration migration and reboot
requirements. Bump the package release.

Validated with diff checks, shell syntax checks and interpreted C tests
using mocked sysfs, ioctls and RPCs. No compilation or hardware
validation was performed.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
@stintel

stintel commented Sep 19, 2026

Copy link
Copy Markdown
Member Author

I will keep deleting openwrt[bot] comments as long as this is in draft status. It gravely pollutes the discussion. Could we maybe somehow make it ignoring this PR? Or draft PRs in general?

@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
@plappermaul

Copy link
Copy Markdown
Contributor

make "realtek: rtl83xx: unregister DSA switch on driver removal" and "realtek: watchdog: avoid synchronous IRQ disable during restart" a pre-PR

@jonasjelonek

jonasjelonek commented Sep 19, 2026

Copy link
Copy Markdown
Member

the PCS related stuff should also be moved out to a separate PR, needs to be discussed in my opinion. If I see correctly those target issues I also somewhere have on my ToDo, but solved quite complicated here. I'll have a closer look soon.

EDIT: Overall, it really bad IMO that DSA starts to include any PCS header, this needs to be designed differently

Comment on lines +214 to +216
if (priv->family_id == RTL9310_FAMILY_ID)
sw_w32_mask(BIT(priv->r->cpu_port & 0x1f), 0,
RTL931X_L2_PORT_AGE_CTRL_REG(priv->r->cpu_port));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After long and hard work we are close to decomission the family_id. Please use other implementation (maybe via config structure).

@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
The stacking support adds family_id checks while the driver is moving
variant-specific behavior into its configuration structure.

Add a stacking capability and a device-ID callback to the variant
configuration. Select separate RTL930x and RTL931x MAC callbacks and
reuse the configured force-mode mask when bringing links down.

Move the CPU-port aging workaround into RTL931x learning setup. Keep
the existing link-up sequence and failure recovery unchanged.

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
@openwrt openwrt deleted a comment from openwrt Bot Sep 19, 2026
Comment on lines +298 to +302
static bool rteth_931x_decode_tag(struct rteth_frag *frag,
struct rteth_dsa_tag *t)
{
u16 spn = frag->cpu_tag[2] & RTETH_931X_TAG2_SPN;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mak the ethernet tx/rx header coding/decoding split and signature enhancment a separate PR.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit checks

  • Missing Signed-off-by: on 10 commits: b69df4be, f1daa607, e269eede, 63422d6c, e444ab08, 1c4cc770, 27485b4b, 5fbf7d90, 6488d719, 144cb5d1.
  • 2e1ee866 "WIP: realtek: rtl83xx: add multi-link stack trunk" — WIP: subject on a 1020-line commit; either finish it or drop it from the series.
  • 5fbf7d90 "net: dsa: preserve same-parent switchdev FDB entries" — uses the upstream kernel subject prefix; the sibling patch commit 1e5f2c17 correctly uses generic: 6.18: ... for the same directory.
  • 27485b4b "realtek: watchdog: avoid synchronous IRQ disable during restart" — body calls it a backport, but the change is authored in this series and is not in v6.18.52.

Generated by Claude Code

@@ -0,0 +1,514 @@
From ffd3885e66b0f65bd123ecd46c4154543149b3de Mon Sep 17 00:00:00 2001

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

netifd carries no patches today and is still at PKG_RELEASE:=1, which this PR leaves untouched. Bump it so the rebuilt package is actually reinstalled on upgrade.


Generated by Claude Code

Comment on lines +106 to +108
+ while ((len = read(fd, buf, sizeof(buf))) != 0) {
+ if (len < 0)
+ return -1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No EINTR retry here, although the waitpid() below has one. netifd reaps proto-shell helpers constantly, so a SIGCHLD landing mid-read() makes an otherwise healthy selector look failed, and config_select_profile() then aborts the entire config_init_all(). Continue on EINTR instead of returning -1 (and re-count the hunk when regenerating).


Generated by Claude Code

Comment on lines +183 to +186
+ read_error = config_selector_read(pfds[0], profile, size);
+ close(pfds[0]);
+ if (read_error)
+ kill(pid, SIGKILL);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no deadline on this blocking read/wait pair, and config_select_profile() runs synchronously from config_init_all() — which is also reached from the reload ubus method inside uloop_run(). A selector that hangs, or one that forks a child keeping the pipe write end open, stalls netifd's whole event loop forever, which contradicts the commit message's "without ... delaying process startup". An alarm/deadline with SIGKILL on expiry would make the fail-closed contract hold.


Generated by Claude Code

config_free_vlans();
config_init_ip();
config_init_rules();
@@ -839,7 +900,8 @@ config_init_all(void)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hunk's old range 839–845 overlaps the previous hunk's 834–841 (and 900–907 overlaps 894–902) — no valid diff can do that, so these headers were hand-edited. Against the pinned netifd the two netifd_ucode_config_load() calls are 14 lines apart, not 5, and the whole config.c part currently applies only with offsets up to 9. Regenerate with make package/netifd/refresh.


Generated by Claude Code

@@ -0,0 +1,547 @@
From: Stijn Tintel <stijn@linux-ipv6.be>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

704- is already used in this directory by 704-net-dsa-support-EPROBE_DEFER-when-reading-the-port-M.patch.`` Renumber to a free slot — 709 is unused.


Generated by Claude Code

@@ -0,0 +1,34 @@
From: Stijn Tintel <stijn@linux-ipv6.be>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upstream still has disable_irq(ctrl->irq_phase1) at realtek_otto_wdt.c:186 in v6.18.52 and this patch is authored here, so the commit body's "Backport a change to disable_irq_nosync()" is inaccurate. Every other 0xx- patch in this directory carries a -vX.Y- upstream marker; a not-yet-accepted change belongs in the 3xx/7xx/8xx range the other local patches use.


Generated by Claude Code

@plappermaul

Copy link
Copy Markdown
Contributor

Please provide the ethernet commits as separate PR. Thanks

@openwrt

openwrt Bot commented Sep 21, 2026

Copy link
Copy Markdown

Formality Check: Failed

We checked this pull request against the contribution guidelines. Here is what needs your attention:

🛑 CRITICAL ERRORS

Commit b69df4b - realtek: rtl931x: index port isolation by stack device:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit f1daa60 - realtek: rtl931x: add a stack CPU link:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit e269eed - netifd: add restricted UCI profiles:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 63422d6 - realtek: rtl931x: restrict follower network setup:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit e444ab0 - realtek: rtl931x: add isolated follower recovery:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 1c4cc77 - rtl931x-stack: document validation gaps:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 27485b4 - realtek: watchdog: avoid synchronous IRQ disable during restart:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 5fbf7d9 - net: dsa: preserve same-parent switchdev FDB entries:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 6488d71 - realtek: rtl931x: force DAC_LONG tuning for 10GBASE-R tests:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Commit 144cb5d - realtek: rtl931x: calibrate DAC receivers with bounded retries:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Pull Request Overall Diff:

  • New OpenWrt package is missing the mandatory parameter: 'PKG_MAINTAINER'
  • New OpenWrt package is missing the mandatory parameter: 'PKG_LICENSE_FILES'

⚠️ STYLISTIC WARNINGS & SUGGESTIONS

Pull Request Overall Diff:

  • ⚠️ - Embedded patch file 'target/linux/generic/pending-6.18/704-net-dsa-allow-drivers-to-delegate-user-ports.patch' violates standard guidelines. Missing required Git header parameters ('From Mon Sep 17 00:00:00 2001' / 'From:' / 'Date:' / 'Subject:') to ensure 'git am' application compatibility
  • ⚠️ - Embedded patch file 'target/linux/generic/pending-6.18/704-net-dsa-allow-drivers-to-delegate-user-ports.patch' violates standard guidelines. Missing required Git header parameters ('From Mon Sep 17 00:00:00 2001' / 'From:' / 'Date:' / 'Subject:') to ensure 'git am' application compatibility
  • ⚠️ - Embedded patch file 'target/linux/realtek/patches-6.18/039-watchdog-realtek-otto-avoid-synchronous-irq-disable.patch' violates standard guidelines. Missing required Git header parameters ('From Mon Sep 17 00:00:00 2001' / 'From:' / 'Date:' / 'Subject:') to ensure 'git am' application compatibility
  • ⚠️ - Embedded patch file 'target/linux/generic/pending-6.18/708-net-dsa-do-not-assist-learning-between-same-parent-ports.patch' violates standard guidelines. Missing required Git header parameters ('From Mon Sep 17 00:00:00 2001' / 'From:' / 'Date:' / 'Subject:') to ensure 'git am' application compatibility

Package Release Audit:

  • ⚠️ Content changed in these packages, but without a PKG_RELEASE or version bump:

    • package/network/config/netifd

    Increment PKG_RELEASE by 1 (or bump PKG_VERSION/PKG_SOURCE_DATE and reset PKG_RELEASE to 1) so users receive the update.

  • ⚠️ New package package/network/config/rtl931x-stack must start with PKG_RELEASE set to 1 (currently: '6')

Do not increment release for minor changes. Cosmetic edits (e.g., typos in comments, copyright updates, formatting/whitespace), changing the package maintainer (PKG_MAINTAINER), or updating source download info (PKG_SOURCE_URL / PKG_HASH) do not require incrementing PKG_RELEASE.

Tip

Do not close this pull request to make corrections. Instead, modify your existing commits (e.g. git commit --amend) and update the branch using git push --force-with-lease --force-if-includes. The checks will re-run automatically.


Something broken? Consider reporting an issue.
Running version 26ec621 deployed on 2026-09-20 09:46:35 CEST

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

add package Introduces a new package Makefile build script core packages pull request/issue for core (in-tree) packages kernel pull request/issue with Linux kernel related changes not following guidelines Pull request does not follow formatting guidelines target/realtek pull request/issue for realtek target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants