mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
114 lines
4.3 KiB
Python
Executable File
114 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""PTP BTCA grandmaster election
|
|
|
|
Verify that the Best TimeTransmitter Clock Algorithm (BTCA) selects the clock
|
|
with the lowest `priority1` as grandmaster, and that a change of `priority1`
|
|
at runtime triggers a new election with the correct result.
|
|
|
|
Two Ordinary Clocks are connected back-to-back. Both announce themselves as
|
|
potential grandmasters. In round one, *alpha* holds `priority1=1` and wins
|
|
the election; *beta* (`priority1=128`) becomes the time receiver. In round
|
|
two, *alpha* is reconfigured to priority1=200 without restarting; the BTCA
|
|
re-runs and beta wins, becoming the new grandmaster. The test verifies that
|
|
alpha's `parent-ds` `grandmaster-identity` changes to beta's `clock-identity`,
|
|
confirming that the re-election is reflected in the operational datastore.
|
|
|
|
Announce intervals are reduced to 250 ms (`log-announce-interval -2`) and the
|
|
announce receipt timeout to 2 intervals (500 ms) to make re-election complete
|
|
in roughly one second rather than the default three.
|
|
|
|
The test is run for both IEEE 1588-2019 (UDP/IPv4, E2E) and IEEE 802.1AS
|
|
(Layer 2, P2P) profiles.
|
|
"""
|
|
|
|
import infamy
|
|
import infamy.ptp as ptp
|
|
from infamy import until
|
|
from infamy.util import parallel
|
|
|
|
|
|
class ArgumentParser(infamy.ArgumentParser):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.args.add_argument("--profile", default="ieee1588",
|
|
choices=["ieee1588", "ieee802-dot1as"])
|
|
|
|
|
|
def configure_oc(iface, priority1, profile, ip=None):
|
|
iface_cfg = {"name": iface, "enabled": True}
|
|
if profile == "ieee1588":
|
|
iface_cfg["ipv4"] = {"address": [{"ip": ip, "prefix-length": 30}]}
|
|
|
|
port_ds = {
|
|
"log-announce-interval": -2,
|
|
"announce-receipt-timeout": 2,
|
|
"log-sync-interval": -2,
|
|
}
|
|
if profile == "ieee1588":
|
|
port_ds["delay-mechanism"] = "e2e"
|
|
|
|
return {
|
|
"ietf-interfaces": {
|
|
"interfaces": {"interface": [iface_cfg]}
|
|
},
|
|
"ieee1588-ptp-tt": {
|
|
"ptp": {
|
|
"instances": {
|
|
"instance": [{
|
|
"instance-index": 0,
|
|
"default-ds": {
|
|
"instance-type": "oc",
|
|
"domain-number": 0,
|
|
"priority1": priority1,
|
|
"priority2": 128,
|
|
"infix-ptp:profile": profile,
|
|
"time-receiver-only": False,
|
|
},
|
|
"ports": {
|
|
"port": [{
|
|
"port-index": 1,
|
|
"underlying-interface": iface,
|
|
"port-ds": port_ds,
|
|
}]
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
with infamy.Test() as test:
|
|
with test.step("Set up topology and attach to DUTs"):
|
|
arg = ArgumentParser()
|
|
env = infamy.Env(args=arg)
|
|
profile = env.args.profile
|
|
alpha = env.attach("alpha", "mgmt")
|
|
beta = env.attach("beta", "mgmt")
|
|
|
|
_, if_alpha = env.ltop.xlate("alpha", "data")
|
|
_, if_beta = env.ltop.xlate("beta", "data")
|
|
|
|
with test.step(f"Configure both DUTs ({profile}); alpha has lower priority1"):
|
|
alpha.put_config_dicts(configure_oc(if_alpha, priority1=1,
|
|
profile=profile, ip="192.168.100.1"))
|
|
beta.put_config_dicts(configure_oc(if_beta, priority1=128,
|
|
profile=profile, ip="192.168.100.2"))
|
|
|
|
with test.step("Verify initial election: alpha is grandmaster, beta is time receiver"):
|
|
parallel(lambda: until(lambda: ptp.is_own_gm(alpha), attempts=60),
|
|
lambda: until(lambda: ptp.is_time_receiver(beta), attempts=60))
|
|
|
|
with test.step("Reconfigure alpha with worse priority1=200"):
|
|
alpha.put_config_dicts(configure_oc(if_alpha, priority1=200,
|
|
profile=profile, ip="192.168.100.1"))
|
|
|
|
with test.step("Verify beta wins re-election (is own grandmaster)"):
|
|
until(lambda: ptp.is_own_gm(beta), attempts=30)
|
|
|
|
with test.step("Verify alpha tracks beta as grandmaster"):
|
|
until(lambda: ptp.grandmaster_identity(alpha) == ptp.clock_identity(beta),
|
|
attempts=30)
|
|
|
|
test.succeed()
|