14. Final Boss
This test throws the lab into its darkest scene. Subscribers begin alive and moving real traffic. Then, one by one, three pillars fall:
- the
OLT -> BNG MASTERaccess link - the
Carrier1 -> BNG2link, exactly whenBNG2has already becomemaster - the
RADIUSserver
The question is not whether the network gets hit. The question is whether it survives.
14.1 Goal
Validate that the lab maintains subscriber service for IPoE, PPPoE, and delegated LAN behind the ONT during a chained failure sequence.
In this real execution, we observed:
- a successful SRRP switchover to
SLAVE - loss of
Carrier1on the active node without collapsing the tested traffic - complete loss of
radiuswithout evicting already authenticated subscribers - a single traffic gap during the first switchover, roughly 7.6 to 8.1 seconds depending on the probe
14.2 Prerequisites
Validate before starting:
show srrp
show service active-subscribers
show router 9999 bgp summary
Expected baseline:
MASTER: SRRPmasterSLAVE: SRRPbackupShuntONT-001andONT-002present inshow service active-subscribersCarrier1andCarrier2up on the active node
14.3 Determine the current source IPs
Optional shortcut:
bash configs/cbot/scripts/subscriber-failover-probes.sh final-boss start
If you use this helper, you can skip 14.3 and 14.4 and continue directly with 14.5. The script detects the current source IPs and launches all ATP probes.
To view the ping sequence during the test, leave a second terminal open with:
bash configs/cbot/scripts/subscriber-failover-probes.sh final-boss watch
This lets you watch the latest reply from each ping probe live while you trigger each failure from the main terminal.
Before starting the probes, identify the current lab addresses. These IPs may vary between runs, so fixed values should not be used.
Run from the host:
docker exec ont1 sh -lc "ip -6 addr show dev eth1.150 scope global"
docker exec ont1 sh -lc "ip -6 addr show dev eth3.200 scope global"
docker exec ont1 sh -lc "ip -4 addr show dev eth3.200 scope global"
docker exec ont2 sh -lc "ip -6 addr show dev ppp0 scope global"
Use these IPs in the next steps:
ONT1_WAN1_V6: global IPv6 oneth1.150ONT1_WAN2_V6: global IPv6 oneth3.200ONT1_WAN2_V4: global IPv4 oneth3.200ONT2_PPP_V6: global IPv6 onppp0
Example from a real run:
ONT1_WAN1_V6=2001:db8:100::5
ONT1_WAN2_V6=2001:db8:cccc::1
ONT1_WAN2_V4=100.80.0.4
ONT2_PPP_V6=2001:db8:100::4
14.4 Act I: The Calm Before the Storm
Launch the continuous probes:
docker exec ont1 sh -lc 'rm -f /tmp/final_boss_*; nohup ping -D -n -i 0.2 -W 1 -I <ONT1_WAN1_V6> 2001:db8:aaaa::2 > /tmp/final_boss_ont1_wan1_v6.log 2>&1 & echo $! > /tmp/final_boss_ont1_wan1_v6.pid; nohup ping -D -n -i 0.2 -W 1 -I <ONT1_WAN2_V6> 2001:db8:aaaa::2 > /tmp/final_boss_ont1_wan2_v6.log 2>&1 & echo $! > /tmp/final_boss_ont1_wan2_v6.pid; nohup ping -D -n -i 0.2 -W 1 -I <ONT1_WAN2_V4> 99.99.99.99 > /tmp/final_boss_ont1_wan2_v4.log 2>&1 & echo $! > /tmp/final_boss_ont1_wan2_v4.pid'
docker exec ont2 sh -lc 'rm -f /tmp/final_boss_*; nohup ping -D -n -i 0.2 -W 1 -I <ONT2_PPP_V6> 2001:db8:aaaa::2 > /tmp/final_boss_ont2_ppp_v6.log 2>&1 & echo $! > /tmp/final_boss_ont2_ppp_v6.pid'
docker exec pc1 sh -lc 'rm -f /tmp/final_boss_*; nohup ping -D -n -i 0.2 -W 1 2001:db8:aaaa::2 > /tmp/final_boss_pc1_lan_v6.log 2>&1 & echo $! > /tmp/final_boss_pc1_lan_v6.pid'
Replace <ONT1_WAN1_V6>, <ONT1_WAN2_V6>, <ONT1_WAN2_V4>, and <ONT2_PPP_V6> with the values discovered in 14.3.
These probes cover:
ONT1 WAN1 IPv6-only -> DNS64ONT1 WAN2 IPv6 -> DNS64ONT1 WAN2 IPv4 -> 99.99.99.99ONT2 PPPoE IPv6 -> DNS64PC1 behind PD -> DNS64
To inspect the logs generated by the probes:
Option 1, helper:
bash configs/cbot/scripts/subscriber-failover-probes.sh final-boss tail
Option 2, manual commands:
docker exec ont1 sh -lc 'tail -n 12 /tmp/final_boss_ont1_wan1_v6.log'
docker exec ont1 sh -lc 'tail -n 12 /tmp/final_boss_ont1_wan2_v6.log'
docker exec ont1 sh -lc 'tail -n 12 /tmp/final_boss_ont1_wan2_v4.log'
docker exec ont2 sh -lc 'tail -n 12 /tmp/final_boss_ont2_ppp_v6.log'
docker exec pc1 sh -lc 'tail -n 12 /tmp/final_boss_pc1_lan_v6.log'
Observed baseline samples:
[1773326051.535098] 64 bytes from 2001:db8:aaaa::2: icmp_seq=43 ttl=62 time=3.97 ms
[1773326051.543326] 64 bytes from 99.99.99.99: icmp_seq=43 ttl=63 time=11.2 ms
[1773326051.648545] 64 bytes from 2001:db8:aaaa::2: icmp_seq=43 ttl=62 time=1.73 ms
[1773326051.667407] 64 bytes from 2001:db8:aaaa::2: icmp_seq=43 ttl=61 time=1.83 ms
14.5 Act II: The First Impact
Cut OLT -> BNG MASTER:
docker exec containerbot sh -lc '/app/scripts/olt-to-bng1-down.sh'
Validate:
show srrp
show service active-subscribers
Observed result:
A:admin@MASTER# show srrp
2 9998 dual-stack Up initialize
1 9998 ipv6-only Up initialize
3 9998 vip Up initialize
A:admin@SLAVE# show srrp
2 9998 dual-stack Up master
1 9998 ipv6-only Up master
3 9998 vip Up master
A:admin@MASTER# show service active-subscribers
...
00:d0:f6:01:01:01 IPoE DHCP6 9998 N
00:d0:f6:01:01:02 IPoE DHCP 9998 N
00:d0:f6:01:01:04 PPP 1 DHCP6 9998 N
A:admin@SLAVE# show service active-subscribers
...
00:d0:f6:01:01:01 IPoE DHCP6 9998 Y
00:d0:f6:01:01:02 IPoE DHCP 9998 Y
00:d0:f6:01:01:04 PPP 1 DHCP6 9998 Y
This was the hardest hit. The probes did not die, but there was a real pause during the switchover.
Observed example on ONT1 WAN1:
[1773326055.947060] 64 bytes from 2001:db8:aaaa::2: icmp_seq=65 ttl=62 time=3.00 ms
[1773326063.996298] 64 bytes from 2001:db8:aaaa::2: icmp_seq=103 ttl=63 time=1.92 ms
Interpretation:
- there was a single gap of roughly 8 seconds during the first failover
- when traffic returned,
ttl=62becamettl=63, proving the path had moved throughSLAVE
14.6 Act III: Progressive Isolation
With SLAVE already acting as master, cut Carrier1 -> BNG2:
docker exec containerbot sh -lc '/app/scripts/carrier1-to-bng2-down.sh'
Validate on SLAVE:
show router 9999 bgp summary
show srrp
Observed result:
A:admin@SLAVE# show router 9999 bgp summary
...
172.16.1.3
to_CARRIER1
65501 0 0 00h00m01s Connect
0 0
172.16.2.3
to_CARRIER2
65502 181 0 01h27m08s 2/2/3 (IPv4)
191 0 2/2/4 (IPv6)
A:admin@SLAVE# show srrp
2 9998 dual-stack Up master
1 9998 ipv6-only Up master
3 9998 vip Up master
Observed probe signals:
- no new
icmp_seqgaps appeared ONT1 WAN2 IPv4 -> 99.99.99.99kept replying- internal IPv6 flows (
ONT1,ONT2,PC1) remained alive
Real sample after this second failure:
[1773326087.851562] 64 bytes from 99.99.99.99: icmp_seq=222 ttl=63 time=16.3 ms
[1773326088.052683] 64 bytes from 99.99.99.99: icmp_seq=223 ttl=63 time=16.8 ms
14.7 Act IV: Brain Death
Stop RADIUS:
docker stop radius
Validate:
docker ps -a --format '{{.Names}}\t{{.Status}}' | rg '^radius\b'
show service active-subscribers
Observed result:
radius Exited (0) 32 seconds ago
Already active subscribers remained present and forwarding on the active node:
A:admin@SLAVE# show service active-subscribers
...
2001:db8:100::5/128
00:d0:f6:01:01:01 IPoE DHCP6 9998 Y
100.80.0.4
00:d0:f6:01:01:02 IPoE DHCP 9998 Y
2001:db8:100::4/128
00:d0:f6:01:01:04 PPP 1 DHCP6 9998 Y
And the probes kept moving:
[1773326125.789863] 64 bytes from 99.99.99.99: icmp_seq=411 ttl=63 time=6.39 ms
[1773326125.737325] 64 bytes from 2001:db8:aaaa::2: icmp_seq=410 ttl=63 time=1.79 ms
[1773326125.757919] 64 bytes from 2001:db8:aaaa::2: icmp_seq=410 ttl=62 time=1.85 ms
Operational note:
- with
Test accountdisabled in the health-check policy,show aaa radius-server-policy "radius_policy"may take time to declare the server down even if the container is already gone - this test did not force new authentication; it validated continuity for already established sessions
14.8 Verdict
The lab survives the “Final Boss”.
But the truth matters:
- it was not hitless
- the first switchover (
OLT -> BNG MASTERdown) caused a visible interruption of around 8 seconds - after that initial blow, the network absorbed the loss of
Carrier1on the active node and the loss ofRADIUSwithout losing the tested flows
Conclusion:
- if the criterion is service survival, the test passes
- if the criterion is zero loss during the first failover, the test does not pass yet
14.9 Restore the realm
docker exec containerbot sh -lc '/app/scripts/carrier1-to-bng2-up.sh'
docker exec containerbot sh -lc '/app/scripts/olt-to-bng1-up.sh'
docker start radius
Note:
carrier1-to-bng2-up.shmust enableethernet-1/2onCarrier1, which is the interface affected by the failure step
Validate nominal state:
show srrp
show router 9999 bgp summary
Expected state:
MASTERreturns tomasterSLAVEreturns tobackupShuntCarrier1andCarrier2returnradiusreturns toUp
14.10 Clean up the probes
Use only one of these two options:
- if you started the probes with the optional helper, stop them with the helper
- if you started the probes manually with
docker exec, stop them manually with thekillcommands
There is no need to run both options. If you use the helper first and then run the manual kill commands, you may see No such process because the probes were already stopped.
Option 1, helper:
bash configs/cbot/scripts/subscriber-failover-probes.sh final-boss stop
Option 2, manual commands:
docker exec ont1 sh -lc 'kill -INT $(cat /tmp/final_boss_ont1_wan1_v6.pid) $(cat /tmp/final_boss_ont1_wan2_v6.pid) $(cat /tmp/final_boss_ont1_wan2_v4.pid)'
docker exec ont2 sh -lc 'kill -INT $(cat /tmp/final_boss_ont2_ppp_v6.pid)'
docker exec pc1 sh -lc 'kill -INT $(cat /tmp/final_boss_pc1_lan_v6.pid)'