Skip to content

Commit 13ce021

Browse files
committed
test: add some basic ptp tests
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
1 parent 880f440 commit 13ce021

54 files changed

Lines changed: 2029 additions & 6 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/testing.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,51 @@ $ make test-spec
359359
...
360360
```
361361

362+
### Node and Link Capabilities
363+
364+
Logical topology files (`topology.dot`) declare what each node and link
365+
*requires*; physical topology files declare what each node and link
366+
*provides*. When mapping a logical topology to physical hardware, infamy
367+
only assigns a physical node to a logical node when the physical node's
368+
`provides` set is a superset of the logical node's `requires` set. Tests
369+
are skipped if no matching physical topology can be found.
370+
371+
#### Declaring requirements (logical topology)
372+
373+
```dot
374+
dut [
375+
requires="infix ptp-hwts",
376+
];
377+
378+
host:data -- dut:data [requires="ieee-mc"]
379+
```
380+
381+
#### Declaring capabilities (physical topology)
382+
383+
```dot
384+
switch1 [
385+
provides="infix ptp-hwts",
386+
];
387+
```
388+
389+
#### Node capabilities
390+
391+
| Capability | Meaning |
392+
|-------------------|-------------------------------------------------------------------------|
393+
| `controller` | Reserved for the host/controller node; never assigned to a DUT |
394+
| `infix` | Node runs Infix OS — required by virtually all DUT nodes |
395+
| `infix gps` | Node has a GPS receiver available as a time reference |
396+
| `infix watchdog` | Node has a hardware watchdog device |
397+
| `infix ptp-hwts` | Node has PTP Hardware Clock (PHC) support on its network interfaces, enabling hardware timestamping and sub-microsecond PTP convergence |
398+
399+
#### Link capabilities
400+
401+
| Capability | Meaning |
402+
|-------------------|-------------------------------------------------------------------------|
403+
| `mgmt` | Link is a management path (typically coloured grey in diagrams) |
404+
| `ieee-mc` | Link carries IEEE multicast traffic (required by LAG and some L2 tests) |
405+
| `link-ctrl copper`| Link supports copper speed/duplex control |
406+
362407
### Test Development
363408

364409
For adding a new test to the automated regression test suite, it's best

src/confd/src/ptp.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static const char *instance_type_to_clock_type(const char *type)
3939
* gmCapable, follow_up_info, assume_two_step, path_trace_enabled,
4040
* and the tighter neighborPropDelayThresh.
4141
*/
42-
static bool emit_profile_globals(FILE *fp, const char *profile)
42+
static bool emit_profile_globals(FILE *fp, const char *profile, bool hw_ts)
4343
{
4444
bool dot1as = profile && !strcmp(profile, "ieee802-dot1as");
4545

@@ -53,7 +53,16 @@ static bool emit_profile_globals(FILE *fp, const char *profile)
5353
fprintf(fp, "follow_up_info 1\n");
5454
fprintf(fp, "assume_two_step 1\n");
5555
fprintf(fp, "path_trace_enabled 1\n");
56-
fprintf(fp, "neighborPropDelayThresh 800\n");
56+
/*
57+
* 802.1AS P2P gate: if meanLinkDelay exceeds this threshold the
58+
* port stays asCapable=false and never leaves LISTENING. 800 ns
59+
* is the 802.1AS default and is appropriate only for hardware
60+
* timestamping — software timestamps (QEMU, tap interfaces) can
61+
* easily produce peer delays in the microsecond range, which
62+
* would keep both ports stuck in LISTENING indefinitely.
63+
*/
64+
if (hw_ts)
65+
fprintf(fp, "neighborPropDelayThresh 800\n");
5766
} else {
5867
fprintf(fp, "transportSpecific 0\n");
5968
}
@@ -130,7 +139,7 @@ static const char *instance_time_stamping(struct lyd_node *inst, json_t *root)
130139
static int write_instance_conf(struct lyd_node *inst, json_t *root)
131140
{
132141
struct lyd_node *default_ds, *port, *port_ds;
133-
const char *instance_type, *clock_type, *profile;
142+
const char *instance_type, *clock_type, *profile, *ts;
134143
const char *v;
135144
char path[256];
136145
uint16_t idx;
@@ -154,7 +163,7 @@ static int write_instance_conf(struct lyd_node *inst, json_t *root)
154163

155164
default_ds = lydx_get_child(inst, "default-ds");
156165
instance_type = lydx_get_cattr(default_ds, "instance-type");
157-
profile = lydx_get_cattr(default_ds, "infix-ptp:profile");
166+
profile = lydx_get_cattr(default_ds, "profile");
158167

159168
clock_type = instance_type_to_clock_type(instance_type);
160169
tc = (clock_type != NULL);
@@ -164,10 +173,11 @@ static int write_instance_conf(struct lyd_node *inst, json_t *root)
164173
fprintf(fp, "uds_address /var/run/ptp4l-%u\n", idx);
165174

166175
/* Timestamping mode: hardware if all ports support it, software otherwise */
167-
fprintf(fp, "time_stamping %s\n", instance_time_stamping(inst, root));
176+
ts = instance_time_stamping(inst, root);
177+
fprintf(fp, "time_stamping %s\n", ts);
168178

169179
/* Profile — sets transportSpecific and all protocol-mandatory options */
170-
dot1as = emit_profile_globals(fp, profile);
180+
dot1as = emit_profile_globals(fp, profile, !strcmp(ts, "hardware"));
171181

172182
/* domainNumber */
173183
v = lydx_get_cattr(default_ds, "domain-number");

test/case/all.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
- name: "NTP Server"
3636
suite: ntp/all.yaml
3737

38+
- name: "PTP"
39+
suite: ptp/all.yaml
40+
3841
- name: "Routing"
3942
suite: routing/all.yaml
4043

test/case/ptp/Readme.adoc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
:testgroup:
2+
== PTP Tests
3+
4+
Tests for PTP (IEEE 1588 Precision Time Protocol) functionality across
5+
different clock types and operational scenarios:
6+
7+
- Basic smoke test: full stack end-to-end
8+
- BTCA: grandmaster election and runtime re-election via `priority1`
9+
- Boundary Clock: two-port BC forwarding time with `steps-removed` accounting
10+
- Transparent Clock: E2E and P2P TC on hardware-timestamping nodes
11+
- Port fault recovery: link-down/link-up state machine and re-convergence
12+
13+
The offset convergence threshold in the tests varies with the timestamping
14+
capability of the nodes under test:
15+
16+
[cols="1,1,3",options="header"]
17+
|===
18+
| Timestamping | Default Threshold | Typical scenario
19+
| Software | 100 000 ns | Virtual machines, QEMU tap interfaces
20+
| Hardware | 1 000 ns | Nodes with PHC hardware timestamping
21+
|===
22+
23+
Tests that accept a `--threshold-ns` option may use that value instead.
24+
When no option is given, the threshold is selected automatically based
25+
on the `ptp-hwts` capability of the relevant node in the physical test
26+
system's topology file.
27+
28+
<<<
29+
30+
include::basic/Readme.adoc[]
31+
32+
<<<
33+
34+
include::bmca/Readme.adoc[]
35+
36+
<<<
37+
38+
include::boundary_clock/Readme.adoc[]
39+
40+
<<<
41+
42+
include::transparent_clock/Readme.adoc[]
43+
44+
<<<
45+
46+
include::port_recovery/Readme.adoc[]

test/case/ptp/all.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
- name: PTP basic
3+
suite: basic/test.yaml
4+
5+
- name: PTP BTCA grandmaster election
6+
suite: bmca/test.yaml
7+
8+
- name: PTP boundary clock
9+
suite: boundary_clock/test.yaml
10+
11+
- name: PTP transparent clock
12+
suite: transparent_clock/test.yaml
13+
14+
- name: PTP port fault recovery
15+
case: port_recovery/test.py

test/case/ptp/basic/Readme.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
include::ieee1588.adoc[]
2+
3+
<<<
4+
5+
include::ieee802dot1as.adoc[]
6+

test/case/ptp/basic/ieee1588.adoc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== PTP basic (IEEE 1588)
2+
3+
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ptp/basic]
4+
5+
==== Description
6+
7+
Verify basic PTP operation end-to-end: clock configuration, port state
8+
transitions, and clock servo convergence.
9+
10+
Two Ordinary Clocks are connected back-to-back. The grandmaster is
11+
configured with `priority1=1` so it always wins the BTCA election; the
12+
time receiver is configured with `time-receiver-only` so it never
13+
attempts to become grandmaster. The test is run once per supported
14+
profile, covering both IEEE 1588-2019 (UDP/IPv4, E2E) and IEEE 802.1AS
15+
(Layer 2, P2P).
16+
17+
==== Topology
18+
19+
image::topology.svg[PTP basic (IEEE 1588) topology, align=center, scaledwidth=75%]
20+
21+
==== Sequence
22+
23+
. Set up topology and attach to DUTs
24+
. Configure grandmaster (OC, ieee1588, priority1=1) and time receiver (ieee1588, priority1=128, client-only)
25+
. Wait for grandmaster and time receiver ports to reach active states
26+
. Wait for time receiver offset to converge
27+
28+

test/case/ptp/basic/ieee1588.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test.py
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== PTP basic (IEEE 802.1AS)
2+
3+
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/ptp/basic]
4+
5+
==== Description
6+
7+
Verify basic PTP operation end-to-end: clock configuration, port state
8+
transitions, and clock servo convergence.
9+
10+
Two Ordinary Clocks are connected back-to-back. The grandmaster is
11+
configured with `priority1=1` so it always wins the BTCA election; the
12+
time receiver is configured with `time-receiver-only` so it never
13+
attempts to become grandmaster. The test is run once per supported
14+
profile, covering both IEEE 1588-2019 (UDP/IPv4, E2E) and IEEE 802.1AS
15+
(Layer 2, P2P).
16+
17+
==== Topology
18+
19+
image::topology.svg[PTP basic (IEEE 802.1AS) topology, align=center, scaledwidth=75%]
20+
21+
==== Sequence
22+
23+
. Set up topology and attach to DUTs
24+
. Configure grandmaster (OC, ieee802-dot1as, priority1=1) and time receiver (ieee802-dot1as, priority1=128, client-only)
25+
. Wait for grandmaster and time receiver ports to reach active states
26+
. Wait for time receiver offset to converge
27+
28+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test.py

0 commit comments

Comments
 (0)