mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-30 04:33:00 +02:00
145 lines
4.4 KiB
Python
Executable File
145 lines
4.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
r"""LACP Aggregate w/ Degraded Link
|
|
|
|
Verify communication over an LACP link aggregate when individual member
|
|
links stop forwarding traffic, without carrier loss.
|
|
|
|
.Logical network setup, link breakers (lb1 & lb2) here managed by host PC
|
|
image::lag-failure.svg[align=center, scaledwidth=75%]
|
|
|
|
The host verifies connectivity with dut2 via dut1 over the aggregate for
|
|
each failure mode step using the `mon` interface.
|
|
|
|
"""
|
|
from time import time
|
|
import infamy
|
|
import infamy.lag
|
|
from infamy.netns import TPMR
|
|
from infamy.util import parallel
|
|
|
|
IPH = "192.168.2.1"
|
|
IP1 = "192.168.2.41"
|
|
IP2 = "192.168.2.42"
|
|
|
|
|
|
class LinkBreaker:
|
|
"""Encapsulates TPMR based link-breakers."""
|
|
|
|
def __init__(self, sys, netns):
|
|
self.net = netns
|
|
self.lb1 = TPMR(sys.ltop.xlate("host", "lb1a")[1],
|
|
sys.ltop.xlate("host", "lb1b")[1]).start()
|
|
self.lb2 = TPMR(sys.ltop.xlate("host", "lb2a")[1],
|
|
sys.ltop.xlate("host", "lb2b")[1]).start()
|
|
|
|
def forward(self, lb1, lb2):
|
|
"""Set link breakers in forwarding or blocking state."""
|
|
getattr(self.lb1, lb1)()
|
|
getattr(self.lb2, lb2)()
|
|
|
|
def fail_check(self, peer):
|
|
"""Verify connectivity with a given peer during failure."""
|
|
sequence = [
|
|
("forward", "forward"),
|
|
("forward", "block"),
|
|
("block", "forward"),
|
|
("forward", "forward")
|
|
]
|
|
|
|
total_start = time()
|
|
print(f"{'LB1':<8} | {'LB2':<8} | {'Status':<8}")
|
|
print("---------|----------|---------")
|
|
|
|
for lb1, lb2 in sequence:
|
|
state_start = time()
|
|
try:
|
|
print(f"{lb1:<8} | {lb2:<8} | {'...':<8}", end="\r# ")
|
|
self.forward(lb1, lb2)
|
|
self.net.must_reach(peer, timeout=30)
|
|
print(f"{lb1:<8} | {lb2:<8} | {'OK':<8} in "
|
|
f"{time() - state_start:.2f}s")
|
|
except Exception as e:
|
|
print(f"{lb1:<8} | {lb2:<8} | {'FAIL':<8} after "
|
|
f"{time() - state_start:.2f}s")
|
|
print(f"\nError encountered: {e}")
|
|
print(f"Link breakers were in state: LB1='{lb1}', LB2='{lb2}'")
|
|
raise
|
|
|
|
print(f"Total time: {time() - total_start:.2f}s")
|
|
|
|
|
|
def net_init(host, addr):
|
|
"""Set up DUT network, dut1 bridges host port with lag0"""
|
|
if host:
|
|
net = [{
|
|
"name": "br0",
|
|
"type": "infix-if-type:bridge",
|
|
"ipv4": {
|
|
"address": [{"ip": addr, "prefix-length": 24}]
|
|
}
|
|
}, {
|
|
"name": host,
|
|
"bridge-port": {"bridge": "br0"}
|
|
}, {
|
|
"name": "lag0",
|
|
"bridge-port": {"bridge": "br0"}
|
|
}]
|
|
else:
|
|
net = [{
|
|
"name": "lag0",
|
|
"ipv4": {
|
|
"address": [{"ip": addr, "prefix-length": 24}]
|
|
}
|
|
}]
|
|
return net
|
|
|
|
|
|
def dut_init(dut, addr, peer):
|
|
"""Configure each DUT specific according to LAG mode and peer"""
|
|
net = net_init(dut["mon"], addr)
|
|
|
|
dut.put_config_dicts({"ietf-interfaces": {
|
|
"interfaces": {
|
|
"interface": [{
|
|
"name": "lag0",
|
|
"type": "infix-if-type:lag",
|
|
"lag": {
|
|
"mode": "lacp",
|
|
"lacp": {"rate": "fast"},
|
|
"link-monitor": {"interval": 100}
|
|
}
|
|
}, {
|
|
"name": dut["link1"],
|
|
"lag-port": {"lag": "lag0"}
|
|
}, {
|
|
"name": dut["link2"],
|
|
"lag-port": {"lag": "lag0"}
|
|
}] + net
|
|
}
|
|
}})
|
|
|
|
|
|
with infamy.Test() as test:
|
|
with test.step("Set up topology and attach to target DUTs"):
|
|
env = infamy.Env(edge_mappings=infamy.lag.edge_mappings)
|
|
dut1 = env.attach("dut1")
|
|
dut2 = env.attach("dut2")
|
|
|
|
_, mon = env.ltop.xlate("host", "mon")
|
|
with infamy.IsolatedMacVlan(mon) as ns:
|
|
lb = LinkBreaker(env, ns)
|
|
ns.addip(IPH)
|
|
|
|
print(f"Setting up lag0 in LACP mode between {dut1} and {dut2}")
|
|
with test.step("Set up link aggregate, lag0, between dut1 and dut2"):
|
|
parallel(lambda: dut_init(dut1, IP1, IP2),
|
|
lambda: dut_init(dut2, IP2, IP1))
|
|
|
|
with test.step("Initial connectivity check ..."):
|
|
ns.must_reach(IP2, timeout=30)
|
|
|
|
with test.step("Verify failure modes"):
|
|
lb.fail_check(IP2)
|
|
|
|
test.succeed()
|