diff --git a/clock.c b/clock.c index a6e31e6..11082fe 100644 --- a/clock.c +++ b/clock.c @@ -103,6 +103,7 @@ struct clock { int sde; int free_running; int freq_est_interval; + int local_sync_uncertain; int write_phase_mode; int grand_master_capable; /* for 802.1AS only */ int utc_timescale; @@ -137,6 +138,7 @@ struct clock the_clock; static void handle_state_decision_event(struct clock *c); 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_stats_display(struct clock_stats *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); datalen = sizeof(*sen); break; + case TLV_SYNCHRONIZATION_UNCERTAIN_NP: + mtd = (struct management_tlv_datum *) tlv->data; + mtd->val = c->local_sync_uncertain; + datalen = sizeof(*mtd); + break; default: /* The caller should *not* respond to this message. */ 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); respond = 1; 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)) 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, double offset, double freq) { - struct stats_result offset_stats, freq_stats, delay_stats; - stats_add_value(s->offset, offset); stats_add_value(s->freq, freq); if (stats_get_num_values(s->offset) < s->max_count) 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->freq, &freq_stats); @@ -1030,6 +1057,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, c->config = config; c->free_running = config_get_int(config, NULL, "free_running"); 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->grand_master_capable = config_get_int(config, NULL, "gmCapable"); 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_GRANDMASTER_SETTINGS_NP: case TLV_SUBSCRIBE_EVENTS_NP: + case TLV_SYNCHRONIZATION_UNCERTAIN_NP: clock_management_send_error(p, msg, TLV_NOT_SUPPORTED); break; 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); } -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) diff --git a/clock.h b/clock.h index 9d3133a..1256856 100644 --- a/clock.h +++ b/clock.h @@ -320,9 +320,9 @@ void clock_sync_interval(struct clock *c, int n); /** * Obtain a clock's time properties data set. * @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. diff --git a/msg.h b/msg.h index c1294c2..e71d3ce 100644 --- a/msg.h +++ b/msg.h @@ -56,6 +56,7 @@ #define PTP_TIMESCALE (1<<3) #define TIME_TRACEABLE (1<<4) #define FREQ_TRACEABLE (1<<5) +#define SYNC_UNCERTAIN (1<<6) /* * Signaling interval special values. For more info look at 802.1AS table 10-11 diff --git a/port.c b/port.c index 368c3b8..6104061 100644 --- a/port.c +++ b/port.c @@ -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) { - 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 currentDS *cds = clock_current_dataset(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->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)); return 0; @@ -1407,7 +1407,7 @@ out: 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 ptp_message *msg; int err; @@ -1434,19 +1434,19 @@ int port_tx_announce(struct port *p, struct address *dst) msg->header.control = CTL_OTHER; msg->header.logMessageInterval = p->logAnnounceInterval; - msg->header.flagField[1] = tp->flags; + msg->header.flagField[1] = tp.flags; if (dst) { msg->address = *dst; msg->header.flagField[0] |= UNICAST; } - msg->announce.currentUtcOffset = tp->currentUtcOffset; + msg->announce.currentUtcOffset = tp.currentUtcOffset; msg->announce.grandmasterPriority1 = dad->pds.grandmasterPriority1; msg->announce.grandmasterClockQuality = dad->pds.grandmasterClockQuality; msg->announce.grandmasterPriority2 = dad->pds.grandmasterPriority2; msg->announce.grandmasterIdentity = dad->pds.grandmasterIdentity; 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)) { pr_err("port %hu: append path trace failed", portnum(p)); diff --git a/tlv.h b/tlv.h index faf5742..75aa1de 100644 --- a/tlv.h +++ b/tlv.h @@ -84,6 +84,7 @@ enum management_action { #define TLV_TIME_STATUS_NP 0xC000 #define TLV_GRANDMASTER_SETTINGS_NP 0xC001 #define TLV_SUBSCRIBE_EVENTS_NP 0xC003 +#define TLV_SYNCHRONIZATION_UNCERTAIN_NP 0xC006 /* Port management ID values */ #define TLV_NULL_MANAGEMENT 0x0000 @@ -116,6 +117,11 @@ enum management_action { #define TLV_NOT_SUPPORTED 0x0006 #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_GRANT (1 << 1) #define GRANT_UNICAST_RENEWAL_INVITED (1 << 0)