Implement the synchronization uncertain flag.

IEEE 1588 v2.1 and ITU G.8275.1/2 call for an optional "synchronization
uncertain" flag passed in Announce messages along with the other flags
from the time properties data set.  The value of the flag depends is a
logical OR function of the inputs from the remote master and the local
process.  This patch adds background support for handling the flag.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
master
Richard Cochran 2020-05-05 12:27:42 -07:00
parent 7df88afab9
commit b8194a177a
5 changed files with 61 additions and 12 deletions

50
clock.c
View File

@ -103,6 +103,7 @@ struct clock {
int sde; int sde;
int free_running; int free_running;
int freq_est_interval; int freq_est_interval;
int local_sync_uncertain;
int write_phase_mode; int write_phase_mode;
int grand_master_capable; /* for 802.1AS only */ int grand_master_capable; /* for 802.1AS only */
int utc_timescale; int utc_timescale;
@ -137,6 +138,7 @@ struct clock the_clock;
static void handle_state_decision_event(struct clock *c); static void handle_state_decision_event(struct clock *c);
static int clock_resize_pollfd(struct clock *c, int new_nports); static int clock_resize_pollfd(struct clock *c, int new_nports);
static void clock_remove_port(struct clock *c, struct port *p); static void clock_remove_port(struct clock *c, struct port *p);
static void clock_stats_display(struct clock_stats *s);
static void remove_subscriber(struct clock_subscriber *s) static void remove_subscriber(struct clock_subscriber *s)
{ {
@ -446,6 +448,11 @@ static int clock_management_fill_response(struct clock *c, struct port *p,
clock_get_subscription(c, req, sen->bitmask, &sen->duration); clock_get_subscription(c, req, sen->bitmask, &sen->duration);
datalen = sizeof(*sen); datalen = sizeof(*sen);
break; break;
case TLV_SYNCHRONIZATION_UNCERTAIN_NP:
mtd = (struct management_tlv_datum *) tlv->data;
mtd->val = c->local_sync_uncertain;
datalen = sizeof(*mtd);
break;
default: default:
/* The caller should *not* respond to this message. */ /* The caller should *not* respond to this message. */
tlv_extra_recycle(extra); tlv_extra_recycle(extra);
@ -519,6 +526,21 @@ static int clock_management_set(struct clock *c, struct port *p,
clock_update_subscription(c, req, sen->bitmask, sen->duration); clock_update_subscription(c, req, sen->bitmask, sen->duration);
respond = 1; respond = 1;
break; break;
case TLV_SYNCHRONIZATION_UNCERTAIN_NP:
mtd = (struct management_tlv_datum *) tlv->data;
switch (mtd->val) {
case SYNC_UNCERTAIN_DONTCARE:
case SYNC_UNCERTAIN_FALSE:
case SYNC_UNCERTAIN_TRUE:
/* Display stats on change of local_sync_uncertain */
if (c->local_sync_uncertain != mtd->val
&& stats_get_num_values(c->stats.offset))
clock_stats_display(&c->stats);
c->local_sync_uncertain = mtd->val;
respond = 1;
break;
}
break;
} }
if (respond && !clock_management_get_response(c, p, id, req)) if (respond && !clock_management_get_response(c, p, id, req))
pr_err("failed to send management set response"); pr_err("failed to send management set response");
@ -528,14 +550,19 @@ static int clock_management_set(struct clock *c, struct port *p,
static void clock_stats_update(struct clock_stats *s, static void clock_stats_update(struct clock_stats *s,
double offset, double freq) double offset, double freq)
{ {
struct stats_result offset_stats, freq_stats, delay_stats;
stats_add_value(s->offset, offset); stats_add_value(s->offset, offset);
stats_add_value(s->freq, freq); stats_add_value(s->freq, freq);
if (stats_get_num_values(s->offset) < s->max_count) if (stats_get_num_values(s->offset) < s->max_count)
return; return;
clock_stats_display(s);
}
static void clock_stats_display(struct clock_stats *s)
{
struct stats_result offset_stats, freq_stats, delay_stats;
stats_get_result(s->offset, &offset_stats); stats_get_result(s->offset, &offset_stats);
stats_get_result(s->freq, &freq_stats); stats_get_result(s->freq, &freq_stats);
@ -1030,6 +1057,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
c->config = config; c->config = config;
c->free_running = config_get_int(config, NULL, "free_running"); c->free_running = config_get_int(config, NULL, "free_running");
c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval"); c->freq_est_interval = config_get_int(config, NULL, "freq_est_interval");
c->local_sync_uncertain = SYNC_UNCERTAIN_DONTCARE;
c->write_phase_mode = config_get_int(config, NULL, "write_phase_mode"); c->write_phase_mode = config_get_int(config, NULL, "write_phase_mode");
c->grand_master_capable = config_get_int(config, NULL, "gmCapable"); c->grand_master_capable = config_get_int(config, NULL, "gmCapable");
c->kernel_leap = config_get_int(config, NULL, "kernel_leap"); c->kernel_leap = config_get_int(config, NULL, "kernel_leap");
@ -1429,6 +1457,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg)
case TLV_TIME_STATUS_NP: case TLV_TIME_STATUS_NP:
case TLV_GRANDMASTER_SETTINGS_NP: case TLV_GRANDMASTER_SETTINGS_NP:
case TLV_SUBSCRIBE_EVENTS_NP: case TLV_SUBSCRIBE_EVENTS_NP:
case TLV_SYNCHRONIZATION_UNCERTAIN_NP:
clock_management_send_error(p, msg, TLV_NOT_SUPPORTED); clock_management_send_error(p, msg, TLV_NOT_SUPPORTED);
break; break;
default: default:
@ -1751,9 +1780,22 @@ void clock_sync_interval(struct clock *c, int n)
servo_sync_interval(c->servo, n < 0 ? 1.0 / (1 << -n) : 1 << n); servo_sync_interval(c->servo, n < 0 ? 1.0 / (1 << -n) : 1 << n);
} }
struct timePropertiesDS *clock_time_properties(struct clock *c) struct timePropertiesDS clock_time_properties(struct clock *c)
{ {
return &c->tds; struct timePropertiesDS tds = c->tds;
switch (c->local_sync_uncertain) {
case SYNC_UNCERTAIN_DONTCARE:
tds.flags &= ~SYNC_UNCERTAIN;
break;
case SYNC_UNCERTAIN_FALSE:
/* Pass the upstream value, if any. */
break;
case SYNC_UNCERTAIN_TRUE:
tds.flags |= SYNC_UNCERTAIN;
break;
}
return tds;
} }
void clock_update_time_properties(struct clock *c, struct timePropertiesDS tds) void clock_update_time_properties(struct clock *c, struct timePropertiesDS tds)

View File

@ -320,9 +320,9 @@ void clock_sync_interval(struct clock *c, int n);
/** /**
* Obtain a clock's time properties data set. * Obtain a clock's time properties data set.
* @param c The clock instance. * @param c The clock instance.
* @return A pointer to the time properties data set of the clock. * @return A copy of the clock's time properties data set.
*/ */
struct timePropertiesDS *clock_time_properties(struct clock *c); struct timePropertiesDS clock_time_properties(struct clock *c);
/** /**
* Update a clock's time properties data set. * Update a clock's time properties data set.

1
msg.h
View File

@ -56,6 +56,7 @@
#define PTP_TIMESCALE (1<<3) #define PTP_TIMESCALE (1<<3)
#define TIME_TRACEABLE (1<<4) #define TIME_TRACEABLE (1<<4)
#define FREQ_TRACEABLE (1<<5) #define FREQ_TRACEABLE (1<<5)
#define SYNC_UNCERTAIN (1<<6)
/* /*
* Signaling interval special values. For more info look at 802.1AS table 10-11 * Signaling interval special values. For more info look at 802.1AS table 10-11

12
port.c
View File

@ -412,7 +412,7 @@ static int follow_up_info_append(struct ptp_message *m)
static int net_sync_resp_append(struct port *p, struct ptp_message *m) static int net_sync_resp_append(struct port *p, struct ptp_message *m)
{ {
struct timePropertiesDS *tp = clock_time_properties(p->clock); struct timePropertiesDS tp = clock_time_properties(p->clock);
struct ClockIdentity cid = clock_identity(p->clock), pid; struct ClockIdentity cid = clock_identity(p->clock), pid;
struct currentDS *cds = clock_current_dataset(p->clock); struct currentDS *cds = clock_current_dataset(p->clock);
struct parent_ds *dad = clock_parent_ds(p->clock); struct parent_ds *dad = clock_parent_ds(p->clock);
@ -468,7 +468,7 @@ static int net_sync_resp_append(struct port *p, struct ptp_message *m)
memcpy(&extra->foot->parent, &dad->pds, sizeof(extra->foot->parent)); memcpy(&extra->foot->parent, &dad->pds, sizeof(extra->foot->parent));
memcpy(&extra->foot->current, cds, sizeof(extra->foot->current)); memcpy(&extra->foot->current, cds, sizeof(extra->foot->current));
memcpy(&extra->foot->timeprop, tp, sizeof(extra->foot->timeprop)); memcpy(&extra->foot->timeprop, &tp, sizeof(extra->foot->timeprop));
memcpy(&extra->foot->lastsync, &last_sync, sizeof(extra->foot->lastsync)); memcpy(&extra->foot->lastsync, &last_sync, sizeof(extra->foot->lastsync));
return 0; return 0;
@ -1407,7 +1407,7 @@ out:
int port_tx_announce(struct port *p, struct address *dst) int port_tx_announce(struct port *p, struct address *dst)
{ {
struct timePropertiesDS *tp = clock_time_properties(p->clock); struct timePropertiesDS tp = clock_time_properties(p->clock);
struct parent_ds *dad = clock_parent_ds(p->clock); struct parent_ds *dad = clock_parent_ds(p->clock);
struct ptp_message *msg; struct ptp_message *msg;
int err; int err;
@ -1434,19 +1434,19 @@ int port_tx_announce(struct port *p, struct address *dst)
msg->header.control = CTL_OTHER; msg->header.control = CTL_OTHER;
msg->header.logMessageInterval = p->logAnnounceInterval; msg->header.logMessageInterval = p->logAnnounceInterval;
msg->header.flagField[1] = tp->flags; msg->header.flagField[1] = tp.flags;
if (dst) { if (dst) {
msg->address = *dst; msg->address = *dst;
msg->header.flagField[0] |= UNICAST; msg->header.flagField[0] |= UNICAST;
} }
msg->announce.currentUtcOffset = tp->currentUtcOffset; msg->announce.currentUtcOffset = tp.currentUtcOffset;
msg->announce.grandmasterPriority1 = dad->pds.grandmasterPriority1; msg->announce.grandmasterPriority1 = dad->pds.grandmasterPriority1;
msg->announce.grandmasterClockQuality = dad->pds.grandmasterClockQuality; msg->announce.grandmasterClockQuality = dad->pds.grandmasterClockQuality;
msg->announce.grandmasterPriority2 = dad->pds.grandmasterPriority2; msg->announce.grandmasterPriority2 = dad->pds.grandmasterPriority2;
msg->announce.grandmasterIdentity = dad->pds.grandmasterIdentity; msg->announce.grandmasterIdentity = dad->pds.grandmasterIdentity;
msg->announce.stepsRemoved = clock_steps_removed(p->clock); msg->announce.stepsRemoved = clock_steps_removed(p->clock);
msg->announce.timeSource = tp->timeSource; msg->announce.timeSource = tp.timeSource;
if (p->path_trace_enabled && path_trace_append(p, msg, dad)) { if (p->path_trace_enabled && path_trace_append(p, msg, dad)) {
pr_err("port %hu: append path trace failed", portnum(p)); pr_err("port %hu: append path trace failed", portnum(p));

6
tlv.h
View File

@ -84,6 +84,7 @@ enum management_action {
#define TLV_TIME_STATUS_NP 0xC000 #define TLV_TIME_STATUS_NP 0xC000
#define TLV_GRANDMASTER_SETTINGS_NP 0xC001 #define TLV_GRANDMASTER_SETTINGS_NP 0xC001
#define TLV_SUBSCRIBE_EVENTS_NP 0xC003 #define TLV_SUBSCRIBE_EVENTS_NP 0xC003
#define TLV_SYNCHRONIZATION_UNCERTAIN_NP 0xC006
/* Port management ID values */ /* Port management ID values */
#define TLV_NULL_MANAGEMENT 0x0000 #define TLV_NULL_MANAGEMENT 0x0000
@ -116,6 +117,11 @@ enum management_action {
#define TLV_NOT_SUPPORTED 0x0006 #define TLV_NOT_SUPPORTED 0x0006
#define TLV_GENERAL_ERROR 0xFFFE #define TLV_GENERAL_ERROR 0xFFFE
/* Values for the SYNCHRONIZATION_UNCERTAIN_NP management TLV */
#define SYNC_UNCERTAIN_DONTCARE 0xff
#define SYNC_UNCERTAIN_FALSE 0
#define SYNC_UNCERTAIN_TRUE 1
#define CANCEL_UNICAST_MAINTAIN_REQUEST (1 << 0) #define CANCEL_UNICAST_MAINTAIN_REQUEST (1 << 0)
#define CANCEL_UNICAST_MAINTAIN_GRANT (1 << 1) #define CANCEL_UNICAST_MAINTAIN_GRANT (1 << 1)
#define GRANT_UNICAST_RENEWAL_INVITED (1 << 0) #define GRANT_UNICAST_RENEWAL_INVITED (1 << 0)