mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-27 03:03:02 +02:00
166 lines
5.0 KiB
Python
Executable File
166 lines
5.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
r"""Ling Aggregation Basic
|
|
|
|
Verify communication over a link aggregate in static and LACP operating
|
|
modes during basic failure scenarios.
|
|
|
|
.Internal network setup, PC verifies connectivity with dut2 via dut1
|
|
image::lag-basic.svg[align=center, scaledwidth=75%]
|
|
|
|
The host verifies connectivity with dut2 via dut1 over the aggregate for
|
|
each test step using the `mon` interface.
|
|
|
|
"""
|
|
from time import sleep, time
|
|
from datetime import datetime
|
|
import infamy
|
|
import infamy.lag
|
|
from infamy.util import parallel, until
|
|
|
|
class DumbLinkBreaker:
|
|
"""Encapsulates basic, dumb link-breaking ops over SSH."""
|
|
|
|
def __init__(self, sys, dut, netns):
|
|
self.env = sys
|
|
self.dut = dut
|
|
self.net = netns
|
|
self.tgt = {}
|
|
for i, (name, _) in dut.items():
|
|
self.tgt[i] = env.attach(name, "mgmt", "ssh")
|
|
|
|
def set_link(self, link, updown):
|
|
"""Set link up or down, verify before returning."""
|
|
def set_and_verify(i):
|
|
name, dut = self.dut[i]
|
|
|
|
cmd = self.tgt[i].runsh(f"sudo ip link set {dut[link]} {updown}")
|
|
if cmd.returncode:
|
|
for out in [cmd.stdout, cmd.stderr]:
|
|
if out:
|
|
print(f"{name}: {out.rstrip()}")
|
|
raise RuntimeError(f"{name}: failed setting {link} {updown}")
|
|
|
|
for _ in range(10):
|
|
sleep(0.1)
|
|
check = self.tgt[i].runsh(f"ip link show {dut[link]}")
|
|
if f"state {updown.upper()}" in check.stdout:
|
|
break
|
|
else:
|
|
raise RuntimeError(f"{name}: {dut[link]} did not go {updown}")
|
|
|
|
parallel(*[lambda i=i: set_and_verify(i) for i in self.dut])
|
|
|
|
def fail_check(self, peer):
|
|
"""Verify connectivity with peer during link failure."""
|
|
sequence = [
|
|
[("link1", "up"), ("link2", "up")],
|
|
[("link1", "down"), ("link2", "up")],
|
|
[("link1", "up"), ("link2", "down")],
|
|
[("link1", "up"), ("link2", "up")]
|
|
]
|
|
|
|
total_start = time()
|
|
for state in sequence:
|
|
state_start = time()
|
|
print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} {state}")
|
|
|
|
for link, updown in state:
|
|
self.set_link(link, updown)
|
|
self.net.must_reach(peer, timeout=10)
|
|
|
|
print(f"Completed in {time() - state_start:.2f}s")
|
|
|
|
print(f"Total time: {time() - total_start:.2f}s")
|
|
|
|
|
|
def lag_init(mode):
|
|
"""Set up mode specific attributes for the LAG"""
|
|
if mode == "lacp":
|
|
lag = [{
|
|
"name": "lag0",
|
|
"lag": {"lacp": {"rate": "fast"}}
|
|
}]
|
|
else:
|
|
lag = []
|
|
return lag
|
|
|
|
|
|
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",
|
|
}, {
|
|
"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, mode, addr):
|
|
"""Set up link aggregate on dut"""
|
|
net = net_init(dut["mon"], addr)
|
|
lag = lag_init(mode)
|
|
|
|
dut.put_config_dicts({"ietf-interfaces": {
|
|
"interfaces": {
|
|
"interface": [{
|
|
"name": "lag0",
|
|
"type": "infix-if-type:lag",
|
|
"lag": {
|
|
"mode": mode,
|
|
"link-monitor": {"interval": 100}
|
|
}
|
|
}, {
|
|
"name": dut["link1"],
|
|
"lag-port": {"lag": "lag0"}
|
|
}, {
|
|
"name": dut["link2"],
|
|
"lag-port": {"lag": "lag0"}
|
|
}] + net + lag
|
|
}
|
|
}})
|
|
|
|
|
|
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", "mgmt")
|
|
dut2 = env.attach("dut2", "mgmt")
|
|
|
|
_, mon = env.ltop.xlate("host", "mon")
|
|
with infamy.IsolatedMacVlan(mon) as ns:
|
|
dm = {
|
|
'1': ("dut1", dut1),
|
|
'2': ("dut2", dut2)
|
|
}
|
|
lb = DumbLinkBreaker(env, dm, ns)
|
|
ns.addip("192.168.2.1")
|
|
|
|
with test.step("Set up LACP link aggregate, lag0, on dut1 and dut2"):
|
|
parallel(lambda: dut_init(dut1, "lacp", None),
|
|
lambda: dut_init(dut2, "lacp", "192.168.2.42"))
|
|
|
|
with test.step("Verify failure modes for lacp mode"):
|
|
lb.fail_check("192.168.2.42")
|
|
|
|
with test.step("Set up static link aggregate, lag0, on dut1 and dut2"):
|
|
parallel(lambda: dut_init(dut1, "static", None),
|
|
lambda: dut_init(dut2, "static", "192.168.2.42"))
|
|
|
|
with test.step("Verify failure modes for static mode"):
|
|
lb.fail_check("192.168.2.42")
|
|
|
|
test.succeed()
|