From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:08:51 +0000 (+0000) Subject: When a timing peer list is provided, wait for 0.5 sec for a FollowUp message from... X-Git-Tag: 1.2~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=05dfb5be1100753fbf16a6a538e1f6d2df479412;p=thirdparty%2Fnqptp.git When a timing peer list is provided, wait for 0.5 sec for a FollowUp message from one of the peers. If none, send out bogus Announce messages to waken up any clocks out there. This is a hacky workaround for an Apple Silicon PTP bug/feature -- not sure which, but definitely not compatible with the IEEE PTP standard. --- diff --git a/nqptp-clock-sources.c b/nqptp-clock-sources.c index 0300639..ef95bdd 100644 --- a/nqptp-clock-sources.c +++ b/nqptp-clock-sources.c @@ -125,7 +125,7 @@ void manage_clock_sources(uint64_t reception_time, clock_source_private_data *cl if (old_flags != 0) update_master(); else - debug_log_nqptp_status(1); + debug_log_nqptp_status(2); } } } @@ -372,5 +372,5 @@ void update_master() { clocks_private[best_so_far].flags |= (1 << clock_is_master); } } - debug_log_nqptp_status(1); + debug_log_nqptp_status(2); } diff --git a/nqptp-clock-sources.h b/nqptp-clock-sources.h index 53b1bce..3b30ff7 100644 --- a/nqptp-clock-sources.h +++ b/nqptp-clock-sources.h @@ -44,7 +44,6 @@ typedef struct { char ip[64]; // 64 is nicely aligned and bigger than INET6_ADDRSTRLEN (46) int family; // AF_INET or AF_INET6 int announcements_sent; // number of announce messages returned to this clock - int followup_seen; // set to true when a followup has come from this clock uint64_t clock_id; uint64_t local_time; // the local time when the offset was calculated uint64_t source_time; diff --git a/nqptp-message-handlers.c b/nqptp-message-handlers.c index 39e6dc6..ce4cf88 100644 --- a/nqptp-message-handlers.c +++ b/nqptp-message-handlers.c @@ -26,7 +26,8 @@ #include "nqptp-utilities.h" void handle_control_port_messages(char *buf, ssize_t recv_len, - clock_source_private_data *clock_private_info) { + clock_source_private_data *clock_private_info, + uint64_t reception_time) { if (recv_len != -1) { buf[recv_len - 1] = 0; // make sure there's a null in it! debug(2, "New timing peer list: \"%s\".", buf); @@ -52,10 +53,12 @@ void handle_control_port_messages(char *buf, ssize_t recv_len, t = create_clock_source_record(new_ip, clock_private_info); clock_private_info[t].flags |= (1 << clock_is_a_timing_peer); clock_private_info[t].announcements_sent = 0; - clock_private_info[t].followup_seen = 0; // no followup seen while a timing peer } } + timing_peer_list_creation_time = reception_time; + timing_peer_list_followup_seen = 0; + // now find and mark the best clock in the timing peer list as the master update_master(); @@ -238,8 +241,14 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, // update our sample information - clock_private_info->followup_seen = - 1; // say we've seen a follow_up -- suppresses announcements_sent + if ((timing_peer_list_followup_seen == 0) && + ((clock_private_info->flags & (1 << clock_is_a_timing_peer)) != 0)) { + debug(2, "Follow_Up from: %" PRIx64 " at %s.", clock_private_info->clock_id, + clock_private_info->ip); + } + + timing_peer_list_followup_seen = + 1; // say we've seen a follow_up (to suppress sending an Announce message) clock_private_info->samples[clock_private_info->next_sample_goes_here].local_time = reception_time; @@ -351,7 +360,7 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, clock_private_info->flags &= ~(1 << clock_is_becoming_master); clock_private_info->flags |= 1 << clock_is_master; clock_private_info->previous_offset_time = 0; - debug_log_nqptp_status(1); + debug_log_nqptp_status(2); } else if (clock_private_info->previous_offset_time != 0) { // i.e. if it's not becoming a master and there has been a previous follow_up int64_t time_since_last_sync = reception_time - clock_private_info->last_sync_time; @@ -388,9 +397,10 @@ void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, // 125 ms is 100 ppm. offset = clock_private_info->previous_offset + jitter; } - } else if ((clock_private_info->flags & (1 << clock_is_master)) != 0) { - debug(1, "Lost sync with clock %" PRIx64 " at %s. Resynchronising.", - clock_private_info->clock_id, clock_private_info->ip); + } else { + if ((clock_private_info->flags & (1 << clock_is_master)) != 0) + debug(1, "Resynchronising master clock %" PRIx64 " at %s.", clock_private_info->clock_id, + clock_private_info->ip); // leave the offset as it was coming in and take it as a sync time clock_private_info->last_sync_time = reception_time; } diff --git a/nqptp-message-handlers.h b/nqptp-message-handlers.h index a0e2865..9fb158e 100644 --- a/nqptp-message-handlers.h +++ b/nqptp-message-handlers.h @@ -35,6 +35,7 @@ void handle_delay_resp(char *buf, ssize_t recv_len, clock_source_private_data *c uint64_t reception_time); void handle_control_port_messages(char *buf, ssize_t recv_len, - clock_source_private_data *clock_private_info); + clock_source_private_data *clock_private_info, + uint64_t reception_time); #endif \ No newline at end of file diff --git a/nqptp.c b/nqptp.c index 801c2f7..ec89c50 100644 --- a/nqptp.c +++ b/nqptp.c @@ -65,6 +65,12 @@ sockets_open_bundle sockets_open_stuff; int master_clock_index = -1; +uint64_t timing_peer_list_creation_time; +int timing_peer_list_followup_seen; // set to true when a followup has come into one of the timing + // peers +int timing_peer_list_announcement_sent; // set to true when an announce message has been sent to all + // relevant timing peers + typedef struct { uint64_t trigger_time; uint64_t (*task)(uint64_t nominal_call_time, void *private_data); @@ -338,8 +344,8 @@ int main(int argc, char **argv) { // check if it's a control port message before checking for the length of the // message. } else if (receiver_port == NQPTP_CONTROL_PORT) { - handle_control_port_messages(buf, recv_len, - (clock_source_private_data *)&clocks_private); + handle_control_port_messages( + buf, recv_len, (clock_source_private_data *)&clocks_private, reception_time); } else if (recv_len >= (ssize_t)sizeof(struct ptp_common_message_header)) { debug_print_buffer(2, buf, recv_len); @@ -374,7 +380,8 @@ int main(int argc, char **argv) { int the_clock = find_clock_source_record( sender_string, (clock_source_private_data *)&clocks_private); // not sure about requiring a Sync before creating it... - if ((the_clock == -1) && ((buf[0] & 0xF) == Sync)) { + // if ((the_clock == -1) && ((buf[0] & 0xF) == Sync)) { + if (the_clock == -1) { the_clock = create_clock_source_record( sender_string, (clock_source_private_data *)&clocks_private); } @@ -419,130 +426,143 @@ int main(int argc, char **argv) { return 0; } +uint64_t timing_peer_list_creation_time = 0; +int followup_seen = 0; + uint64_t broadcasting_task(uint64_t call_time, __attribute__((unused)) void *private_data) { - clock_source_private_data *clocks_private = (clock_source_private_data *)private_data; - // for every clock in the timing peer list - int i; - uint32_t acceptance_mask = - // (1 << clock_is_qualified) | (1 << clock_is_a_timing_peer) | (1 << clock_is_valid); - // (1 << clock_is_a_timing_peer) | (1 << clock_is_valid); - - // (1 << clock_is_a_timing_peer); - 0; - - for (i = 0; i < MAX_CLOCKS; i++) { - if (((clocks_private[i].flags & acceptance_mask) == acceptance_mask) && -// (clocks_private[i].is_one_of_ours == 0) && (clocks_private[i].announcements_sent < 1) && -// (clocks_private[i].followup_seen == 0)) { - (clocks_private[i].is_one_of_ours == 0)) { - - // create the message - /* - struct ptp_announce_message msg; - memset((void *)&msg, 0, sizeof(msg)); - uint64_t my_clock_id = get_self_clock_id(); - msg.header.transportSpecificAndMessageID = 0x10 + Announce; - msg.header.reservedAndVersionPTP = 0x02; - msg.header.messageLength = htons(sizeof(struct ptp_announce_message)); - msg.header.flags = htons(0x0408); - hcton64(my_clock_id, &msg.header.clockIdentity[0]); - msg.header.sourcePortID = htons(32776); - msg.header.controlOtherMessage = 0x05; - msg.header.logMessagePeriod = 0xFE; - msg.announce.currentUtcOffset = htons(37); - hcton64(my_clock_id, &msg.announce.grandmasterIdentity[0]); - uint32_t my_clock_quality = 0xf8fe436a; - msg.announce.grandmasterClockQuality = htonl(my_clock_quality); - msg.announce.grandmasterPriority1 = 248; - msg.announce.grandmasterPriority2 = 248; - msg.announce.timeSource = 160; - */ - - // Organizational Unique Identifier for Apple is 00:0D:93; - uint8_t appl_oui[] = {0x00,0x0D,0x93}; - - uint8_t tlv1SubType[] = {00,00,01}; - uint8_t tlv1Data[] = {0x00,0x07,0x03,0x03,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x1B,0x1F,0xD0}; - // uint8_t tlv1Data[] = {0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - - uint8_t tlv2SubType[] = {00,00,05}; - uint8_t tlv2Data[] = {0x00,0x1F,0x03,0x03,0x00,0x00,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x1B,0x1F,0xD0}; - // uint8_t tlv2Data[] = {0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - - struct ptp_signaling_message *msg; - size_t msg_length = sizeof(struct ptp_signaling_message)+ 2 * sizeof(struct ptp_tlv) + sizeof(tlv1Data) + sizeof(tlv2Data); - msg = malloc(msg_length); - memset((void *)msg, 0, msg_length); - uint64_t my_clock_id = get_self_clock_id(); - msg->header.transportSpecificAndMessageID = 0x10 + Signaling; - msg->header.reservedAndVersionPTP = 0x02; - msg->header.messageLength = htons(msg_length); - msg->header.flags = htons(0x0408); - hcton64(my_clock_id, &msg->header.clockIdentity[0]); - msg->header.sourcePortID = htons(32776); - msg->header.controlOtherMessage = 0x05; - msg->header.logMessagePeriod = 0x80; - struct ptp_tlv *tlvp = (void *)msg + sizeof(struct ptp_signaling_message); - tlvp->tlvType = htons(ORGANIZATION_EXTENSION); - tlvp->lengthField = htons(sizeof(tlv1Data) + 6); - memcpy(&tlvp->organizationId, &appl_oui, sizeof(appl_oui)); - memcpy(&tlvp->organizationSubType, &tlv1SubType, sizeof(tlv1SubType)); - memcpy(&tlvp->dataField, &tlv1Data, sizeof(tlv1Data)); - - tlvp = (void *)msg + sizeof(struct ptp_signaling_message) + sizeof(struct ptp_tlv) + sizeof(tlv1Data); - tlvp->tlvType = htons(ORGANIZATION_EXTENSION); - tlvp->lengthField = htons(sizeof(tlv2Data) + 6); - memcpy(&tlvp->organizationId, &appl_oui, sizeof(appl_oui)); - memcpy(&tlvp->organizationSubType, &tlv2SubType, sizeof(tlv2SubType)); - memcpy(&tlvp->dataField, &tlv2Data, sizeof(tlv2Data)); - - - - // get the socket for the correct port -- 320 -- and family -- IPv4 or IPv6 -- to send it - // from. - - int s = 0; - unsigned t; - for (t = 0; t < sockets_open_stuff.sockets_open; t++) { - if ((sockets_open_stuff.sockets[t].port == 320) && - (sockets_open_stuff.sockets[t].family == clocks_private[i].family)) - s = sockets_open_stuff.sockets[t].number; - } - if (s == 0) { - debug(3, "sending socket not found!"); - } else { - // debug(1, "Send message from socket %d.", s); - - const char *portname = "320"; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - hints.ai_flags = AI_ADDRCONFIG; - struct addrinfo *res = NULL; - int err = getaddrinfo(clocks_private[i].ip, portname, &hints, &res); - if (err != 0) { - debug(1, "failed to resolve remote socket address (err=%d)", err); - } else { - // here, we have the destination, so send it - - // if (clocks_private[i].family == AF_INET6) { - debug(1,"Sending a Signaling message..."); - debug_print_buffer(1, (char *)msg, msg_length); - int ret = sendto(s, msg, msg_length, 0, res->ai_addr, res->ai_addrlen); - if (ret == -1) - debug(1, "result of sendto is %d.", ret); - clocks_private[i].announcements_sent++; - debug(2, "message clock \"%" PRIx64 "\" at %s on %s, iteration: %d.", + int64_t time_since_timing_list_creation = call_time - timing_peer_list_creation_time; + if ((time_since_timing_list_creation > 250000000) && (timing_peer_list_followup_seen == 0)) { + clock_source_private_data *clocks_private = (clock_source_private_data *)private_data; + int i; + uint32_t acceptance_mask = + // (1 << clock_is_qualified) | (1 << clock_is_a_timing_peer) | (1 << clock_is_valid); + // (1 << clock_is_a_timing_peer) | (1 << clock_is_valid); + + // (1 << clock_is_a_timing_peer); + //(1 << clock_is_qualified); + // 0; + (1 << clock_is_a_timing_peer); + for (i = 0; i < MAX_CLOCKS; i++) { + if (((clocks_private[i].flags & acceptance_mask) == acceptance_mask) && + (clocks_private[i].announcements_sent == 0) && (clocks_private[i].is_one_of_ours == 0)) { + + // create a message to attempt to waken this silent PTP clock by + // getting it to negotiate with an apparently better clock + // that then disappears + + struct ptp_announce_message *msg; + size_t msg_length = sizeof(struct ptp_announce_message); + msg = malloc(msg_length); + memset((void *)msg, 0, msg_length); + + uint64_t my_clock_id = get_self_clock_id(); + msg->header.transportSpecificAndMessageID = 0x10 + Announce; + msg->header.reservedAndVersionPTP = 0x02; + msg->header.messageLength = htons(sizeof(struct ptp_announce_message)); + msg->header.flags = htons(0x0408); + hcton64(my_clock_id, &msg->header.clockIdentity[0]); + msg->header.sourcePortID = htons(32776); + msg->header.controlOtherMessage = 0x05; + msg->header.logMessagePeriod = 0xFE; + msg->announce.currentUtcOffset = htons(37); + hcton64(my_clock_id, &msg->announce.grandmasterIdentity[0]); + uint32_t my_clock_quality = 0xf8fe436a; + msg->announce.grandmasterClockQuality = htonl(my_clock_quality); + msg->announce.grandmasterPriority1 = 248; + msg->announce.grandmasterPriority2 = 248; + msg->announce.timeSource = 160; + + /* + // Organizational Unique Identifier for Apple is 00:0D:93; + uint8_t appl_oui[] = {0x00,0x0D,0x93}; + + uint8_t tlv1SubType[] = {00,00,01}; + uint8_t tlv1Data[] = + {0x00,0x07,0x03,0x03,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x1B,0x1F,0xD0}; + // uint8_t tlv1Data[] = + {0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + uint8_t tlv2SubType[] = {00,00,05}; + uint8_t tlv2Data[] = + {0x00,0x1F,0x03,0x03,0x00,0x00,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x00,0x27,0x10,0x00,0x1B,0x1F,0xD0}; + // uint8_t tlv2Data[] = + {0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + + struct ptp_signaling_message *msg; + size_t msg_length = sizeof(struct ptp_signaling_message)+ 2 * sizeof(struct ptp_tlv) + + sizeof(tlv1Data) + sizeof(tlv2Data); msg = malloc(msg_length); memset((void *)msg, 0, + msg_length); uint64_t my_clock_id = get_self_clock_id(); + msg->header.transportSpecificAndMessageID = 0x10 + Signaling; + msg->header.reservedAndVersionPTP = 0x02; + msg->header.messageLength = htons(msg_length); + msg->header.flags = htons(0x0408); + hcton64(my_clock_id, &msg->header.clockIdentity[0]); + msg->header.sourcePortID = htons(32776); + msg->header.controlOtherMessage = 0x05; + msg->header.logMessagePeriod = 0x80; + struct ptp_tlv *tlvp = (void *)msg + sizeof(struct ptp_signaling_message); + tlvp->tlvType = htons(ORGANIZATION_EXTENSION); + tlvp->lengthField = htons(sizeof(tlv1Data) + 6); + memcpy(&tlvp->organizationId, &appl_oui, sizeof(appl_oui)); + memcpy(&tlvp->organizationSubType, &tlv1SubType, sizeof(tlv1SubType)); + memcpy(&tlvp->dataField, &tlv1Data, sizeof(tlv1Data)); + + tlvp = (void *)msg + sizeof(struct ptp_signaling_message) + sizeof(struct ptp_tlv) + + sizeof(tlv1Data); tlvp->tlvType = htons(ORGANIZATION_EXTENSION); tlvp->lengthField = + htons(sizeof(tlv2Data) + 6); memcpy(&tlvp->organizationId, &appl_oui, sizeof(appl_oui)); + memcpy(&tlvp->organizationSubType, &tlv2SubType, sizeof(tlv2SubType)); + memcpy(&tlvp->dataField, &tlv2Data, sizeof(tlv2Data)); + */ + + // get the socket for the correct port -- 320 -- and family -- IPv4 or IPv6 -- to send it + // from. + + int s = 0; + unsigned t; + for (t = 0; t < sockets_open_stuff.sockets_open; t++) { + if ((sockets_open_stuff.sockets[t].port == 320) && + (sockets_open_stuff.sockets[t].family == clocks_private[i].family)) + s = sockets_open_stuff.sockets[t].number; + } + if (s == 0) { + debug(1, "sending socket not found for clock %" PRIx64 " at %s, family %s.", clocks_private[i].clock_id, clocks_private[i].ip, - clocks_private[i].family == AF_INET6 ? "IPv6" : "IPv4", - clocks_private[i].announcements_sent); - // } - freeaddrinfo(res); + clocks_private[i].family == AF_INET + ? "IPv4" + : clocks_private[i].family == AF_INET6 ? "IPv6" : "Unknown"); + } else { + // debug(1, "Send message from socket %d.", s); + + const char *portname = "320"; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_flags = AI_ADDRCONFIG; + struct addrinfo *res = NULL; + int err = getaddrinfo(clocks_private[i].ip, portname, &hints, &res); + if (err != 0) { + debug(1, "failed to resolve remote socket address (err=%d)", err); + } else { + // here, we have the destination, so send it + + // if (clocks_private[i].family == AF_INET6) { + debug(1, "Sending an Announce message to %" PRIx64 "at %s...", + clocks_private[i].clock_id, clocks_private[i].ip); + // debug_print_buffer(1, (char *)msg, msg_length); + int ret = sendto(s, msg, msg_length, 0, res->ai_addr, res->ai_addrlen); + if (ret == -1) + debug(1, "result of sendto is %d.", ret); + clocks_private[i].announcements_sent++; + debug(2, "message clock \"%" PRIx64 "\" at %s on %s.", clocks_private[i].clock_id, + clocks_private[i].ip, clocks_private[i].family == AF_INET6 ? "IPv6" : "IPv4"); + // } + freeaddrinfo(res); + } } + free(msg); } - free(msg); } } @@ -550,6 +570,6 @@ uint64_t broadcasting_task(uint64_t call_time, __attribute__((unused)) void *pri announce_interval = announce_interval << (8 + aPTPinitialLogAnnounceInterval); announce_interval = announce_interval * 1000000000; announce_interval = announce_interval >> 8; // nanoseconds - return call_time + 1000000000; + return call_time + 50000000; // return call_time + announce_interval; } diff --git a/nqptp.h b/nqptp.h index 327aba9..9d488cf 100644 --- a/nqptp.h +++ b/nqptp.h @@ -33,6 +33,11 @@ extern int master_clock_index; extern struct shm_structure *shared_memory; +extern uint64_t timing_peer_list_creation_time; +extern int timing_peer_list_announcement_sent; // set to true when an announce message has been sent + // to all relevant timing peers +extern int timing_peer_list_followup_seen; // set to true when a followup has come into one of the + // timing peers void update_master_clock_info(uint64_t master_clock_id, const char *ip, uint64_t local_time, uint64_t local_to_master_offset, uint64_t mastership_start_time);