Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: PTPv1 support #602

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions statime-linux/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ pub struct PortConfig {
pub delay_mechanism: DelayType,
#[serde(default = "default_delay_interval")]
pub delay_interval: i8,
#[serde(default)]
pub protocol_version: ProtocolVersion,
}

fn deserialize_acceptable_master_list<'de, D>(
Expand Down Expand Up @@ -116,6 +118,10 @@ impl From<PortConfig> for statime::config::PortConfig<Option<Vec<ClockIdentity>>
interval: Interval::from_log_2(pc.delay_interval),
},
},
protocol_version: match pc.protocol_version {
ProtocolVersion::PTPv1 => statime::config::ProtocolVersion::PTPv1,
ProtocolVersion::PTPv2 => statime::config::ProtocolVersion::PTPv2,
},
}
}
}
Expand All @@ -137,6 +143,14 @@ pub enum DelayType {
P2P,
}


#[derive(Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum ProtocolVersion {
PTPv1,
#[default]
PTPv2,
}

impl Config {
/// Parse config from file
pub fn from_file(file: &Path) -> Result<Config, ConfigError> {
Expand Down Expand Up @@ -275,6 +289,7 @@ interface = "enp0s31f6"
delay_asymmetry: 0,
delay_mechanism: crate::config::DelayType::E2E,
delay_interval: 0,
protocol_version: crate::config::ProtocolVersion::PTPv2,
};

let expected = crate::config::Config {
Expand Down
4 changes: 2 additions & 2 deletions statime-linux/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use statime::{
config::{ClockIdentity, InstanceConfig, SdoId, TimePropertiesDS, TimeSource},
filters::{Filter, KalmanConfiguration, KalmanFilter},
port::{
is_message_buffer_compatible, InBmca, Measurement, Port, PortAction, PortActionIterator,
InBmca, Measurement, Port, PortAction, PortActionIterator,
TimestampContext, MAX_DATA_LEN,
},
time::Time,
Expand Down Expand Up @@ -579,7 +579,7 @@ async fn port_task<A: NetworkAddress + PtpTargetAddress>(
let mut actions = tokio::select! {
result = event_socket.recv(&mut event_buffer) => match result {
Ok(packet) => {
if !is_message_buffer_compatible(&event_buffer[..packet.bytes_read]) {
if !port.is_message_buffer_compatible(&event_buffer[..packet.bytes_read]) {
// do not spam with missing timestamp error in mixed-version PTPv1+v2 networks
PortActionIterator::empty()
} else if let Some(timestamp) = packet.timestamp {
Expand Down
103 changes: 73 additions & 30 deletions statime/src/bmc/bmca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ use core::cmp::Ordering;
use super::{
acceptable_master::AcceptableMasterList,
dataset_comparison::{ComparisonDataset, DatasetOrdering},
foreign_master::ForeignMasterList,
foreign_master::{ForeignMasterList, MasterAnnouncement},
};
use crate::{
datastructures::{
config::ClockIdentity, datastructures::{
common::{PortIdentity, TimeInterval},
datasets::InternalDefaultDS,
messages::{AnnounceMessage, Header},
},
port::state::PortState,
time::Duration,
messages::{AnnounceMessage, Header}, messages_v1,
}, port::state::PortState, time::Duration
};

/// Object implementing the Best Master Clock Algorithm
Expand Down Expand Up @@ -76,7 +74,7 @@ impl<A> Bmca<A> {
None => MessageComparison::Better,
Some(best) => {
let dataset =
ComparisonDataset::from_announce_message(&best.message, &best.identity);
ComparisonDataset::from_master_announcement(&best.announcement, &best.identity);

match d0.compare(&dataset).as_ordering() {
Ordering::Less => MessageComparison::Worse(best),
Expand Down Expand Up @@ -137,7 +135,7 @@ impl<A> Bmca<A> {
match Self::compare_d0_best(&d0, best_port_announce_message) {
MessageComparison::Better => RecommendedState::M1(*own_data),
MessageComparison::Same => RecommendedState::M1(*own_data),
MessageComparison::Worse(port) => RecommendedState::P1(port.message),
MessageComparison::Worse(port) => RecommendedState::P1(port.announcement),
}
}

Expand All @@ -152,7 +150,7 @@ impl<A> Bmca<A> {
MessageComparison::Better => RecommendedState::M2(*own_data),
MessageComparison::Same => RecommendedState::M2(*own_data),
MessageComparison::Worse(global_message) => match best_port_announce_message {
None => RecommendedState::M3(global_message.message),
None => RecommendedState::M3(global_message.announcement),
Some(port_message) => Self::compare_global_and_port(global_message, port_message),
},
}
Expand All @@ -164,23 +162,23 @@ impl<A> Bmca<A> {
) -> RecommendedState {
if global_message == port_message {
// effectively, E_best == E_rbest
RecommendedState::S1(global_message.message)
RecommendedState::S1(global_message.announcement)
} else {
let ebest = ComparisonDataset::from_announce_message(
&global_message.message,
let ebest = ComparisonDataset::from_master_announcement(
&global_message.announcement,
&global_message.identity,
);

let erbest = ComparisonDataset::from_announce_message(
&port_message.message,
let erbest = ComparisonDataset::from_master_announcement(
&port_message.announcement,
&port_message.identity,
);

// E_best better by topology than E_rbest
if matches!(ebest.compare(&erbest), DatasetOrdering::BetterByTopology) {
RecommendedState::P2(port_message.message)
RecommendedState::P2(port_message.announcement)
} else {
RecommendedState::M3(global_message.message)
RecommendedState::M3(global_message.announcement)
}
}
}
Expand Down Expand Up @@ -210,6 +208,29 @@ impl<A: AcceptableMasterList> Bmca<A> {
}
}

/// Register a received announce message to the BMC algorithm
pub(crate) fn register_sync_v1_message(
&mut self,
header: &messages_v1::Header,
announce_message: &messages_v1::SyncMessage,
) -> bool {
// Ignore messages comming from the same port
if PortIdentity::from_v1_header(&announce_message.header) != self.own_port_identity
&& self
.acceptable_master_list
.is_acceptable(ClockIdentity::from_mac_address(announce_message.header.source_uuid))
{
self.foreign_master_list.register_sync_v1_message(
header,
announce_message,
Duration::ZERO,
);
true
} else {
false
}
}

pub(crate) fn reregister_announce_message(
&mut self,
header: &Header,
Expand All @@ -227,6 +248,23 @@ impl<A: AcceptableMasterList> Bmca<A> {
}
}

pub(crate) fn reregister_sync_v1_message(
&mut self,
header: &messages_v1::Header,
announce_message: &messages_v1::SyncMessage,
age: Duration,
) {
// Ignore messages comming from the same port
if PortIdentity::from_v1_header(&announce_message.header) != self.own_port_identity
&& self
.acceptable_master_list
.is_acceptable(ClockIdentity::from_mac_address(announce_message.header.source_uuid))
{
self.foreign_master_list
.register_sync_v1_message(header, announce_message, age);
}
}

/// Takes the Erbest from this port
pub(crate) fn take_best_port_announce_message(&mut self) -> Option<BestAnnounceMessage> {
// Find the announce message we want to use from each foreign master that has
Expand All @@ -236,8 +274,7 @@ impl<A: AcceptableMasterList> Bmca<A> {
// The best of the foreign master messages is our erbest
let erbest = Self::find_best_announce_message(announce_messages.map(|message| {
BestAnnounceMessage {
header: message.header,
message: message.message,
announcement: message.message,
age: message.age,
identity: self.own_port_identity,
}
Expand All @@ -247,7 +284,14 @@ impl<A: AcceptableMasterList> Bmca<A> {
// All messages that were considered have been removed from the
// foreignmasterlist. However, the one that has been selected as the
// Erbest must not be removed, so let's just reregister it.
self.reregister_announce_message(&best.header, &best.message, best.age);
match best.announcement {
MasterAnnouncement::PTPv2(message) => {
self.reregister_announce_message(&message.header, &message, best.age);
},
MasterAnnouncement::PTPv1(message) => {
self.reregister_sync_v1_message(&message.header, &message, best.age);
}
}
}

erbest
Expand All @@ -263,8 +307,7 @@ enum MessageComparison {

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) struct BestAnnounceMessage {
header: Header,
message: AnnounceMessage,
announcement: MasterAnnouncement,
age: Duration,
identity: PortIdentity,
}
Expand All @@ -277,8 +320,8 @@ impl BestAnnounceMessage {
}

fn compare_dataset(&self, other: &Self) -> DatasetOrdering {
let data1 = ComparisonDataset::from_announce_message(&self.message, &self.identity);
let data2 = ComparisonDataset::from_announce_message(&other.message, &other.identity);
let data1 = ComparisonDataset::from_master_announcement(&self.announcement, &self.identity);
let data2 = ComparisonDataset::from_master_announcement(&other.announcement, &other.identity);

data1.compare(&data2)
}
Expand All @@ -288,12 +331,13 @@ impl BestAnnounceMessage {
pub(crate) enum RecommendedState {
M1(InternalDefaultDS),
M2(InternalDefaultDS),
M3(AnnounceMessage),
P1(AnnounceMessage),
P2(AnnounceMessage),
S1(AnnounceMessage),
M3(MasterAnnouncement),
P1(MasterAnnouncement),
P2(MasterAnnouncement),
S1(MasterAnnouncement),
}

/* YOLO
#[cfg(test)]

mod tests {
Expand Down Expand Up @@ -343,7 +387,6 @@ mod tests {
}

fn default_best_announce_message() -> BestAnnounceMessage {
let header = default_announce_message_header();
let message = default_announce_message();

let identity = PortIdentity {
Expand All @@ -352,8 +395,7 @@ mod tests {
};

BestAnnounceMessage {
header,
message,
announcement: MasterAnnouncement::PTPv2(message),
age: Duration::ZERO,
identity,
}
Expand Down Expand Up @@ -786,3 +828,4 @@ mod tests {
);
}
}
*/
30 changes: 28 additions & 2 deletions statime/src/bmc/dataset_comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
use core::cmp::Ordering;

use crate::datastructures::{
common::{ClockIdentity, ClockQuality, PortIdentity},
common::{ClockIdentity, ClockQuality, PortIdentity, V2_COMPAT_PRIORITY1, V2_COMPAT_PRIORITY1_PREFERRED, V2_COMPAT_PRIORITY2},
datasets::InternalDefaultDS,
messages::AnnounceMessage,
messages::AnnounceMessage, messages_v1,
};

use super::foreign_master::MasterAnnouncement;

/// A collection of data that is gathered from other sources (mainly announce
/// messages and the DefaultDS). When gathered from two different sources, the
/// [compare](crate::bmc::dataset_comparison::ComparisonDataset) method can be
Expand Down Expand Up @@ -42,6 +44,30 @@ impl ComparisonDataset {
}
}

pub(crate) fn from_sync_v1_message(message: &messages_v1::SyncMessage, port_receiver_identity: &PortIdentity) -> Self {
// TODO: DRY handle_announce_from_v1_sync
Self {
gm_priority_1: if message.grandmaster.preferred { V2_COMPAT_PRIORITY1_PREFERRED } else { V2_COMPAT_PRIORITY1 },
gm_identity: ClockIdentity::from_mac_address(message.grandmaster.clock_uuid),
gm_clock_quality: ClockQuality {
clock_class: 248, /* TODO: is it possible to fill it??? */
clock_accuracy: crate::config::ClockAccuracy::Unknown, /* TODO: is it possible to fill it??? */
offset_scaled_log_variance: message.grandmaster.clock_variance as u16 /* FIXME */
},
gm_priority_2: V2_COMPAT_PRIORITY2,
steps_removed: message.local_steps_removed,
identity_of_senders: ClockIdentity::from_mac_address(message.header.source_uuid),
identity_of_receiver: *port_receiver_identity,
}
}

pub(crate) fn from_master_announcement(announcement: &MasterAnnouncement, port_receiver_identity: &PortIdentity) -> Self {
match announcement {
MasterAnnouncement::PTPv2(message) => Self::from_announce_message(message, port_receiver_identity),
MasterAnnouncement::PTPv1(message) => Self::from_sync_v1_message(message, port_receiver_identity),
}
}

pub(crate) fn from_own_data(data: &InternalDefaultDS) -> Self {
Self {
gm_priority_1: data.priority_1,
Expand Down
Loading
Loading