Documentation
¶
Overview ¶
Package ptpv2 decodes PTPv2 (Precision Time Protocol version 2) packets per IEEE 1588-2008. PTPv2 is the de-facto wire-time synchronisation protocol for modern networks that need sub- microsecond clock alignment across hosts — well beyond what NTP can deliver.
PTPv2 is operationally relevant in:
- **5G / telecom fronthaul** (eCPRI radio units require ±1.5 µs TAE per O-RAN, met via PTP boundary clocks + SyncE).
- **Finance** (MiFID II RTS 25 mandates ≤100 µs traceable to UTC for HFT venues; exchanges and broker-dealers run PTP grandmaster hardware fed by GPS).
- **Industrial automation** (IEEE 802.1AS — PTP profile gPTP — is the time base for TSN traffic shaping; used in robotics, motion control, autonomous-vehicle in-cabin networks).
- **Power grid telemetry** (IEC 61850-9-3 power profile mandates PTP for sampled-values + GOOSE timestamping inside substations).
- **Broadcast media** (SMPTE ST 2110 IP video needs PTP for frame-locked playout across switcher/router fabrics).
Wrap-vs-native judgement
Native. IEEE 1588-2008 is a fully public spec; PTPv2 has a tight 34-byte common header followed by a per-messageType body and (rarely) a TLV suffix. No crypto at the parse layer (the authentication TLVs in IEEE 1588-2019 are out of scope for v2). The decoder is host-side — operators feed PTP bytes from a UDP/319 (event) or UDP/320 (general) packet or from an IEEE 802.3 EtherType 0x88F7 frame.
What this package covers
**Common header** (IEEE 1588-2008 §13.3, 34 bytes):
byte 0: 4-bit transportSpecific + 4-bit messageType.
byte 1: 4-bit Reserved + 4-bit versionPTP (= 2).
bytes 2-3: messageLength (uint16 BE; total bytes including header, body, and any suffix TLVs).
byte 4: domainNumber (0 = default; multiple PTP domains can co-exist on the same network).
byte 5: Reserved.
bytes 6-7: flagField (uint16 BE; per-message bits like PTP_LI_61, PTP_LI_59, PTP_UTC_REASONABLE, PTP_TIMESCALE, TIME_TRACEABLE, FREQUENCY_TRACEABLE, alternateMaster, twoStep, unicast — surfaced as hex plus a decoded comma-separated set of well-known flag names).
bytes 8-15: correctionField (int64 BE; scaled- nanoseconds — high 48 bits are nanoseconds, low 16 bits are sub-nanosecond fractional; used by transparent clocks to accumulate residence time).
bytes 16-19: Reserved.
bytes 20-29: sourcePortIdentity = 8-byte clockIdentity (typically EUI-64 derived from MAC) + 2-byte portNumber.
bytes 30-31: sequenceId (uint16 BE; per-portIdentity monotonic counter used to pair Sync/Follow_Up, Delay_Req/Delay_Resp, Pdelay_Req/Resp/Resp_Follow_Up).
byte 32: controlField (deprecated in v2 but still transmitted; historically encoded messageType for v1-compat receivers).
byte 33: logMessageInterval (int8; log base-2 of mean inter-message interval in seconds — e.g. -3 = 125 ms, 0 = 1 s, 1 = 2 s).
**10-entry messageType name table** (IEEE 1588-2008 §13.3.2.2): 0x0 Sync / 0x1 Delay_Req / 0x2 Pdelay_Req / 0x3 Pdelay_Resp / 0x8 Follow_Up / 0x9 Delay_Resp / 0xA Pdelay_Resp_Follow_Up / 0xB Announce / 0xC Signaling / 0xD Management. (Event messages 0x0–0x3 travel on UDP/319 and are hardware-timestamped on entry/ exit; general messages 0x8–0xD travel on UDP/320.)
**Per-messageType body decoders** (IEEE 1588-2008 §13.6-13.13):
**Sync, Delay_Req, Follow_Up, Delay_Resp**: 10-byte PTP-timestamp (6-byte secondsField + 4-byte nanosecondsField). Sync carries the originTimestamp (one-step) or is paired with Follow_Up carrying the preciseOriginTimestamp (two-step, indicated by the twoStep flag). Delay_Resp additionally carries the requestingPortIdentity (10 bytes after the timestamp).
**Pdelay_Req**: 10-byte originTimestamp + 10-byte Reserved (preserves length symmetry with Pdelay_Resp).
**Pdelay_Resp**: 10-byte requestReceiptTimestamp + 10- byte requestingPortIdentity.
**Pdelay_Resp_Follow_Up**: 10-byte responseOriginTimestamp + 10-byte requestingPortIdentity.
**Announce**: 10-byte originTimestamp + 2-byte currentUtcOffset (seconds) + 1-byte Reserved + 1-byte grandmasterPriority1 + 4-byte grandmasterClockQuality (1-byte clockClass + 1-byte clockAccuracy + 2-byte offsetScaledLogVariance) + 1-byte grandmasterPriority2
8-byte grandmasterIdentity + 2-byte stepsRemoved + 1-byte timeSource. Announce is the Best Master Clock Algorithm (BMCA) input — every clock compares incoming Announce records and elects the best grandmaster.
**9-entry timeSource name table** (IEEE 1588-2008 §7.6.2.6): 0x10 ATOMIC_CLOCK / 0x20 GPS / 0x30 TERRESTRIAL_RADIO / 0x40 PTP / 0x50 NTP / 0x60 HAND_SET / 0x90 OTHER / 0xA0 INTERNAL_OSCILLATOR (plus uncatalogued).
**8-entry clockAccuracy name table** (IEEE 1588-2008 §7.6.2.5): selected high-runner values 0x20 within 25ns / 0x21 within 100ns / 0x22 within 250ns / 0x23 within 1µs / 0x24 within 2.5µs / 0x25 within 10µs / 0x31 within 1s / 0xFE UNKNOWN.
What this package does NOT cover (deliberately out of scope)
- **Network framing** — UDP/319 (event), UDP/320 (general), or IEEE 802.3 EtherType 0x88F7. Feed PTP bytes after the transport-header strip.
- **TLV suffix walker** — PTPv2 messages may carry trailing TLVs (organisation-specific extensions, management responses, authentication for IEEE 1588-2019). messageLength surfaces the total bytes and the per-type body decoder consumes the standard portion; remaining bytes are surfaced as `tlv_suffix_hex` for future per-TLV decoders.
- **Signaling / Management body decoders** — Signaling (0xC) and Management (0xD) carry a 10-byte targetPortIdentity followed by tlv records; the targetPortIdentity is decoded and the rest is surfaced as raw hex. Per-action TLV decoders (REQUEST_UNICAST_TRANSMISSION, GET / SET responses, etc.) are future work.
- **BMCA reasoning** — the decoder surfaces every Announce field needed to drive BMCA (priority1, clockQuality, grandmasterIdentity, stepsRemoved, priority2) but does not itself compare records or pick a winner.
- **gPTP (IEEE 802.1AS) profile validation** — gPTP forbids several PTP message subtypes (Delay_Req / Delay_Resp; only P2P delay via Pdelay_* is allowed) and pins specific flag combinations; the decoder surfaces the raw values without profile-conformance checks.
- **Cryptographic authentication** — the IEEE 1588-2019 (v2.1) AUTHENTICATION_TLV is out of scope (this package targets v2-2008 bare-wire deployments).
- **Clock state-machine reasoning** — slave-side servo loop, transparent-clock residence-time accumulation, boundary-clock port-state changes; higher-level analysis.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AnnounceBody ¶
type AnnounceBody struct {
OriginTimestamp PTPTimestamp `json:"origin_timestamp"`
CurrentUtcOffsetSeconds int16 `json:"current_utc_offset_seconds"`
GrandmasterPriority1 int `json:"grandmaster_priority1"`
GrandmasterClockClass int `json:"grandmaster_clock_class"`
GrandmasterClockAccuracy int `json:"grandmaster_clock_accuracy"`
GrandmasterClockAccuracyName string `json:"grandmaster_clock_accuracy_name"`
GrandmasterOffsetScaledLogVar int `json:"grandmaster_offset_scaled_log_variance"`
GrandmasterPriority2 int `json:"grandmaster_priority2"`
GrandmasterIdentity string `json:"grandmaster_identity"`
StepsRemoved int `json:"steps_removed"`
TimeSource int `json:"time_source"`
TimeSourceName string `json:"time_source_name"`
}
AnnounceBody carries the Best Master Clock Algorithm inputs.
type PTPTimestamp ¶
type PTPTimestamp struct {
Seconds uint64 `json:"seconds"`
Nanoseconds uint32 `json:"nanoseconds"`
}
PTPTimestamp is the 10-byte PTP-timestamp (6-byte secondsField + 4-byte nanosecondsField).
type PortIdentity ¶
type PortIdentity struct {
ClockIdentity string `json:"clock_identity"`
PortNumber int `json:"port_number"`
}
PortIdentity is the 10-byte clockIdentity + portNumber pair.
type Result ¶
type Result struct {
TotalBytes int `json:"total_bytes"`
// Common header
TransportSpecific int `json:"transport_specific"`
MessageType int `json:"message_type"`
MessageTypeName string `json:"message_type_name"`
VersionPTP int `json:"version_ptp"`
MessageLength int `json:"message_length"`
DomainNumber int `json:"domain_number"`
FlagFieldHex string `json:"flag_field_hex"`
FlagsDecoded string `json:"flags_decoded,omitempty"`
CorrectionField int64 `json:"correction_field_scaled_ns"`
ClockIdentity string `json:"clock_identity"`
PortNumber int `json:"port_number"`
SequenceID int `json:"sequence_id"`
ControlField int `json:"control_field"`
LogMessageInterval int `json:"log_message_interval"`
// Per-type bodies (only one set populated)
OriginTimestamp *PTPTimestamp `json:"origin_timestamp,omitempty"`
PreciseOriginTimestamp *PTPTimestamp `json:"precise_origin_timestamp,omitempty"`
ReceiveTimestamp *PTPTimestamp `json:"receive_timestamp,omitempty"`
RequestReceiptTimestamp *PTPTimestamp `json:"request_receipt_timestamp,omitempty"`
ResponseOriginTimestamp *PTPTimestamp `json:"response_origin_timestamp,omitempty"`
RequestingPortIdentity *PortIdentity `json:"requesting_port_identity,omitempty"`
TargetPortIdentity *PortIdentity `json:"target_port_identity,omitempty"`
// Announce
AnnounceBody *AnnounceBody `json:"announce_body,omitempty"`
// Trailing TLV bytes (not decoded; surfaced as hex for
// post-processing or future per-TLV walkers).
TLVSuffixHex string `json:"tlv_suffix_hex,omitempty"`
}
Result is the structured decode of a PTPv2 packet. Optional fields are pointer-typed so they only appear in JSON for the messageType that populates them.