Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions routeros/sw-core01/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,23 @@ CI never decrypts secrets and never contacts the device.
Run `just plan` before every change, after any RouterOS upgrade, and ad hoc.
There is no CI drift job.

## First apply of lab LACP + VLAN 30
## Applying the lab LACP bonds

RouterOS rejects enslaving an interface that is still a bridge port.
terraform-routeros v1.99.1 bonding Create is a plain REST POST; it does
not unslave first. `depends_on` cannot name the six `sfp-sfpplus1`–`6`
bridge-port resources this change deletes, so OpenTofu will not destroy
those orphans before creating the bonds.

An untargeted plan of this change is **7 to add, 6 to destroy**. Do not
apply that mixed plan: RouterOS will reject the bond creates while the
old port rows still exist.
An untargeted plan of this change mixes the port-row destroys with the
bond creates. Do not apply that mixed plan: RouterOS will reject the
bond creates while the old port rows still exist.

History: the bonds first landed in #14, were replaced with plain tagged
ports in #15 while ice Safe Mode (T48) starved the hosts of LACPDUs, and
were restored once IncusOS `202608242359` shipped the ice DDP package.
The 802.3ad exchange was verified live against lab03 before the restore
(both slaves Collecting/Distributing, sub-second single-link failover).

1. Snapshot, then destroy only the six per-port rows (they are already
absent from this configuration and remain only in state):
Expand All @@ -83,17 +89,23 @@ old port rows still exist.

Expected plan: **6 to destroy**.

2. Create the bonds, their bridge ports, and VLAN 30:
2. Create the bonds and their bridge ports, and update VLAN 30:

```sh
just snapshot
just plan
just apply
```

Expected plan: **7 to add** (3 bonds, 3 bond bridge ports, 1 VLAN 30
row). No changes to `bridge-lab`, port 8, VLAN 10, VLAN 40, or the
mgmt address/route.
Expected plan: **6 to add, 1 to change** (3 bonds, 3 bond bridge
ports; the VLAN 30 row's tagged list moves from the six ports to the
three bonds). No changes to `bridge-lab`, port 8, VLAN 10, VLAN 40,
or the mgmt address/route.

The lab fast datapath is down between step 1 and the host-side converge
(`fleet` flips the host bonds to 802.3ad in the same rollout). Hosts
still on active-backup do not partner with the LAGs, so converge
`GilmanLab/fleet` `cluster/` immediately after step 2.

VLAN 30 is L2-only. It is tagged on `bond-lab01`–`03` and `sfp-sfpplus7`
(nas01). It is not tagged on `bridge-lab` or the gw01 trunk
Expand Down
34 changes: 34 additions & 0 deletions routeros/sw-core01/bonding.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# RouterOS rejects enslaving an interface that is still a bridge port
# ("already added as bridge port"). terraform-routeros v1.99.1 bonding
# Create is a plain REST POST (DefaultCreate); it does not remove the
# slaves from /interface/bridge/port first. depends_on cannot name the
# six sfp-sfpplus1..6 bridge-port resources this change deletes, and
# OpenTofu will not order those orphan destroys before these creates.
# Apply in two steps as described in README.md.

resource "routeros_interface_bonding" "bond_lab01" {
name = "bond-lab01"
slaves = [routeros_interface_ethernet.sfp_sfpplus1.name, routeros_interface_ethernet.sfp_sfpplus2.name]
mode = "802.3ad"
transmit_hash_policy = "layer-3-and-4"
lacp_rate = "30secs"
comment = "lab01 SFP pair (PHY-012 + PHY-013)"
}

resource "routeros_interface_bonding" "bond_lab02" {
name = "bond-lab02"
slaves = [routeros_interface_ethernet.sfp_sfpplus3.name, routeros_interface_ethernet.sfp_sfpplus4.name]
mode = "802.3ad"
transmit_hash_policy = "layer-3-and-4"
lacp_rate = "30secs"
comment = "lab02 SFP pair (PHY-014 + PHY-015)"
}

resource "routeros_interface_bonding" "bond_lab03" {
name = "bond-lab03"
slaves = [routeros_interface_ethernet.sfp_sfpplus5.name, routeros_interface_ethernet.sfp_sfpplus6.name]
mode = "802.3ad"
transmit_hash_policy = "layer-3-and-4"
lacp_rate = "30secs"
comment = "lab03 SFP pair (PHY-016 + PHY-017)"
}
42 changes: 9 additions & 33 deletions routeros/sw-core01/bridge.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,23 @@ resource "routeros_interface_bridge" "lab" {
vlan_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus1" {
resource "routeros_interface_bridge_port" "bond_lab01" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus1.name
interface = routeros_interface_bonding.bond_lab01.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus2" {
resource "routeros_interface_bridge_port" "bond_lab02" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus2.name
interface = routeros_interface_bonding.bond_lab02.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus3" {
resource "routeros_interface_bridge_port" "bond_lab03" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus3.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus4" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus4.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus5" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus5.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}

resource "routeros_interface_bridge_port" "sfp_sfpplus6" {
bridge = routeros_interface_bridge.lab.name
interface = routeros_interface_ethernet.sfp_sfpplus6.name
interface = routeros_interface_bonding.bond_lab03.name
frame_types = "admit-only-vlan-tagged"
ingress_filtering = true
}
Expand Down Expand Up @@ -72,12 +51,9 @@ resource "routeros_interface_bridge_vlan" "vlan30" {
bridge = routeros_interface_bridge.lab.name
vlan_ids = ["30"]
tagged = [
routeros_interface_ethernet.sfp_sfpplus1.name,
routeros_interface_ethernet.sfp_sfpplus2.name,
routeros_interface_ethernet.sfp_sfpplus3.name,
routeros_interface_ethernet.sfp_sfpplus4.name,
routeros_interface_ethernet.sfp_sfpplus5.name,
routeros_interface_ethernet.sfp_sfpplus6.name,
routeros_interface_bonding.bond_lab01.name,
routeros_interface_bonding.bond_lab02.name,
routeros_interface_bonding.bond_lab03.name,
routeros_interface_ethernet.sfp_sfpplus7.name,
]
}
Expand Down
Binary file removed routeros/sw-core01/tfplan-s1
Binary file not shown.