clock_source_private_data clocks_private[MAX_CLOCKS];
-int find_clock_source_record(char *sender_string, clock_source *clocks_shared_info,
+int find_clock_source_record(char *sender_string,
clock_source_private_data *clocks_private_info) {
// return the index of the clock in the clock information arrays or -1
int response = -1;
int found = 0;
while ((found == 0) && (i < MAX_CLOCKS)) {
if ((clocks_private_info[i].in_use != 0) &&
- (strcasecmp(sender_string, (const char *)&clocks_shared_info[i].ip) == 0))
+ (strcasecmp(sender_string, (const char *)&clocks_private_info[i].ip) == 0))
found = 1;
else
i++;
return response;
}
-int create_clock_source_record(char *sender_string, clock_source *clocks_shared_info,
- clock_source_private_data *clocks_private_info, int use_lock) {
+int create_clock_source_record(char *sender_string,
+ clock_source_private_data *clocks_private_info) {
// sometimes, the mutex will already be locked
// return the index of a clock entry in the clock information arrays or -1 if full
// initialise the entries in the shared and private arrays
if (found == 1) {
response = i;
- if (use_lock != 0) {
- if (pthread_mutex_lock(&shared_memory->shm_mutex) != 0)
- warn("Can't acquire mutex to activate a new clock!");
- }
- memset(&clocks_shared_info[i], 0, sizeof(clock_source));
- strncpy((char *)&clocks_shared_info[i].ip, sender_string, FIELD_SIZEOF(clock_source, ip) - 1);
- if (use_lock != 0) {
- if (pthread_mutex_unlock(&shared_memory->shm_mutex) != 0)
- warn("Can't release mutex after activating a new clock!");
- }
memset(&clocks_private_info[i], 0, sizeof(clock_source_private_data));
+ strncpy((char *)&clocks_private_info[i].ip, sender_string, FIELD_SIZEOF(clock_source_private_data, ip) - 1);
clocks_private_info[i].in_use = 1;
clocks_private_info[i].t2 = 0;
clocks_private_info[i].current_stage = waiting_for_sync;
clocks_private_info[i].vacant_samples = MAX_TIMING_SAMPLES;
debug(2, "activated source %d with clock_id %" PRIx64 " on ip: %s.", i,
- clocks_shared_info[i].clock_id, &clocks_shared_info[i].ip);
+ clocks_private_info[i].clock_id, &clocks_private_info[i].ip);
} else {
die("Clock tables full!");
}
return response;
}
-void manage_clock_sources(uint64_t reception_time, clock_source *clocks_shared_info,
+void manage_clock_sources(uint64_t reception_time,
clock_source_private_data *clocks_private_info) {
debug(3, "manage_clock_sources");
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
// only if its in use and not a timing peer... don't need a mutex to check
if ((clocks_private_info[i].in_use != 0) &&
- ((clocks_shared_info[i].flags & (1 << clock_is_a_timing_peer)) == 0)) {
+ ((clocks_private_info[i].flags & (1 << clock_is_a_timing_peer)) == 0)) {
int64_t time_since_last_use = reception_time - clocks_private_info[i].time_of_last_use;
// using a sync timeout to determine when to drop the record...
// the following give the sync receipt time in whole seconds
syncTimeout = syncTimeout * 1000000000;
if (time_since_last_use > syncTimeout) {
debug(2, "deactivated source %d with clock_id %" PRIx64 " on ip: %s.", i,
- clocks_shared_info[i].clock_id, &clocks_shared_info[i].ip);
- int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
- if (rc != 0)
- warn("Can't acquire mutex to deactivate a clock!");
- memset(&clocks_shared_info[i], 0, sizeof(clock_source));
- rc = pthread_mutex_unlock(&shared_memory->shm_mutex);
- if (rc != 0)
- warn("Can't release mutex after deactivating a clock!");
+ clocks_private_info[i].clock_id, &clocks_private_info[i].ip);
memset(&clocks_private_info[i], 0, sizeof(clock_source_private_data));
}
}
// check all the entries in the clock array and mark all those that
// belong to ourselves
-void update_clock_self_identifications(clock_source *clocks_shared_info,
- clock_source_private_data *clocks_private_info) {
+void update_clock_self_identifications(clock_source_private_data *clocks_private_info) {
// first, turn off all the self-id flags
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
if (strlen(ip_string) != 0) {
// now set the is_one_of_ours flag of any clock with this ip
for (i = 0; i < MAX_CLOCKS; i++) {
- if (strcasecmp(ip_string, clocks_shared_info[i].ip) == 0) {
+ if (strcasecmp(ip_string, clocks_private_info[i].ip) == 0) {
debug(2, "found an entry for one of our clocks");
clocks_private_info[i].is_one_of_ours = 1;
}
sync_seen,
};
+typedef enum {
+ clock_is_valid,
+ clock_is_a_timing_peer,
+ clock_is_qualified,
+ clock_is_master
+} clock_flags;
+
#define MAX_TIMING_SAMPLES 11
typedef struct {
uint16_t sequence_number;
uint64_t local, local_to_remote_offset;
} timing_samples;
-// private information -- not for putting in shared memory -- about each clock source
+// information about each clock source
typedef struct {
+ char ip[64]; // 64 is nicely aligned and bigger than INET6_ADDRSTRLEN (46)
+ uint64_t clock_id;
+ uint64_t local_time; // the local time when the offset was calculated
+ uint64_t local_to_source_time_offset; // add this to the local time to get source time
+ uint32_t flags;
uint16_t sequence_number;
uint16_t in_use;
enum stage current_stage;
} clock_source_private_data;
-int find_clock_source_record(char *sender_string, clock_source *clocks_shared_info,
+int find_clock_source_record(char *sender_string,
clock_source_private_data *clocks_private_info);
-int create_clock_source_record(char *sender_string, clock_source *clocks_shared_info,
- clock_source_private_data *clocks_private_info, int use_lock);
+int create_clock_source_record(char *sender_string,
+ clock_source_private_data *clocks_private_info);
-void update_clock_self_identifications(clock_source *clocks_shared_info,
- clock_source_private_data *clocks_private_info);
+void update_clock_self_identifications(clock_source_private_data *clocks_private_info);
-void manage_clock_sources(uint64_t reception_time, clock_source *clocks_shared_info,
+void manage_clock_sources(uint64_t reception_time,
clock_source_private_data *clocks_private_info);
extern clock_source_private_data clocks_private[MAX_CLOCKS];
#include "debug.h"
#include "general-utilities.h"
-void update_master_old(clock_source *clock_info, clock_source_private_data *clock_private_info) {
+void update_master_old(clock_source_private_data *clock_private_info) {
int old_master = -1;
// find the current master clock if there is one and turn off all mastership
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
- if ((clock_info[i].flags & (1 << clock_is_master)) != 0)
+ if ((clock_private_info[i].flags & (1 << clock_is_master)) != 0)
if (old_master == -1)
old_master = i; // find old master
- clock_info[i].flags &= ~(1 << clock_is_master); // turn them all off
+ clock_private_info[i].flags &= ~(1 << clock_is_master); // turn them all off
}
int best_so_far = -1;
uint32_t acceptance_mask =
(1 << clock_is_valid) | (1 << clock_is_qualified) | (1 << clock_is_a_timing_peer);
for (i = 0; i < MAX_CLOCKS; i++) {
- if ((clock_info[i].flags & acceptance_mask) == acceptance_mask) {
+ if ((clock_private_info[i].flags & acceptance_mask) == acceptance_mask) {
// found a possible clock candidate
timing_peer_count++;
if (best_so_far == -1) {
}
if (best_so_far != -1) {
// we found a master clock
- clock_info[best_so_far].flags |= (1 << clock_is_master);
+ clock_private_info[best_so_far].flags |= (1 << clock_is_master);
// master_clock_index = best_so_far;
- if (old_master != best_so_far)
- debug(1, "Master clock is now: %" PRIx64 " at: %s, index: %d.", clock_info[best_so_far].clock_id, &clock_info[best_so_far].ip, best_so_far);
- } else {
+ if (old_master != best_so_far) {
+ update_master_clock_info(clock_private_info[best_so_far].clock_id, clock_private_info[best_so_far].local_time, clock_private_info[best_so_far].local_to_source_time_offset);
+ }
+ } else {
if (timing_peer_count == 0)
debug(1, "No timing peer list found");
else
// check
for (i = 0; i < MAX_CLOCKS; i++) {
- if ((clock_info[i].flags & (1 << clock_is_master)) != 0)
+ if ((clock_private_info[i].flags & (1 << clock_is_master)) != 0)
debug(2,"leaving with %d as master", i);
}
}
void update_master() {
- update_master_old((clock_source *) &shared_memory->clocks, clocks_private);
+ update_master_old(clocks_private);
}
-void handle_control_port_messages(char *buf, ssize_t recv_len, clock_source *clock_info,
+void handle_control_port_messages(char *buf, ssize_t recv_len,
clock_source_private_data *clock_private_info) {
if (recv_len != -1) {
buf[recv_len - 1] = 0; // make sure there's a null in it!
debug(1,"Received a new timing peer list message: \"%s\".", buf);
- if ((buf[0] == new_timing_peer_list) || (buf[0] == update_timing_peer_list)){
+ if (buf[0] == 'T') {
char *ip_list = buf + 1;
if (*ip_list == ' ')
ip_list++;
- int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
- if (rc != 0)
- warn("Can't acquire mutex to set timing peers!");
- // turn off all is_timing_peer
+ // turn off all is_timing_peer flags
int i;
for (i = 0; i < MAX_CLOCKS; i++) {
- clock_info[i].flags &= ~(1 << clock_is_a_timing_peer); // turn off peer flag (but not the master flag!)
+ clock_private_info[i].flags &= ~(1 << clock_is_a_timing_peer); // turn off peer flag (but not the master flag!)
}
while (ip_list != NULL) {
char *new_ip = strsep(&ip_list, " ");
// look for the IP in the list of clocks, and create an inert entry if not there
if ((new_ip != NULL) && (new_ip[0] != 0)) {
- int t = find_clock_source_record(new_ip, clock_info, clock_private_info);
+ int t = find_clock_source_record(new_ip, clock_private_info);
if (t == -1)
- t = create_clock_source_record(new_ip, clock_info, clock_private_info,
- 0); // don't use the mutex
+ t = create_clock_source_record(new_ip, clock_private_info);
// if it is just about to become a timing peer, reset its sample count
clock_private_info[t].vacant_samples = MAX_TIMING_SAMPLES;
clock_private_info[t].next_sample_goes_here = 0;
- clock_info[t].flags |= (1 << clock_is_a_timing_peer);
+ clock_private_info[t].flags |= (1 << clock_is_a_timing_peer);
}
}
// now find and mark the best clock in the timing peer list as the master
update_master();
- rc = pthread_mutex_unlock(&shared_memory->shm_mutex);
-
- if (rc != 0)
- warn("Can't release mutex after set timing peers!");
debug(2, "Timing group start");
for (i = 0; i < MAX_CLOCKS; i++) {
- if ((clock_info[i].flags & (1 << clock_is_a_timing_peer)) != 0)
- debug(2, "%s.", &clock_info[i].ip);
+ if ((clock_private_info[i].flags & (1 << clock_is_a_timing_peer)) != 0)
+ debug(2, "%s.", &clock_private_info[i].ip);
}
debug(2, "Timing group end");
}
}
-void handle_announce(char *buf, ssize_t recv_len, clock_source *clock_info,
+void handle_announce(char *buf, ssize_t recv_len,
clock_source_private_data *clock_private_info, uint64_t reception_time) {
// reject Announce messages from self
if (clock_private_info->is_one_of_ours == 0) {
uint8_t clockAccuracy = (clockQuality >> 16) & 0xff;
uint16_t offsetScaledLogVariance = clockQuality & 0xffff;
int best_clock_update_needed = 0;
- if (((clock_info->flags & (1 << clock_is_qualified)) == 0) &&
+ if (((clock_private_info->flags & (1 << clock_is_qualified)) == 0) &&
(msg->announce.stepsRemoved < 255)) {
// if it's just becoming qualified
clock_private_info->grandmasterIdentity = grandmaster_clock_id;
debug(2,
"clock_id %" PRIx64
" at: %s, \"Announce\" message is %sQualified -- See 9.3.2.5.",
- clock_info->clock_id, clock_info->ip,
+ clock_private_info->clock_id, clock_private_info->ip,
clock_private_info->stepsRemoved < 255 ? "" : "not ");
debug(2, " grandmasterIdentity: %" PRIx64 ".", grandmaster_clock_id);
debug(2, " grandmasterPriority1: %u.", msg->announce.grandmasterPriority1);
debug(2, " grandmasterPriority2: %u.", msg->announce.grandmasterPriority2);
debug(2, " stepsRemoved: %u.", msg->announce.stepsRemoved);
- if (pthread_mutex_lock(&shared_memory->shm_mutex) != 0)
- warn("Can't acquire mutex to mark best clock!");
// now go and re-mark the best clock in the timing peer list
if (clock_private_info->stepsRemoved >= 255) // 9.3.2.5 (d)
- clock_info->flags &= ~(1 << clock_is_qualified);
+ clock_private_info->flags &= ~(1 << clock_is_qualified);
else
- clock_info->flags |= (1 << clock_is_qualified);
+ clock_private_info->flags |= (1 << clock_is_qualified);
update_master();
- if (pthread_mutex_unlock(&shared_memory->shm_mutex) != 0)
- warn("Can't release mutex after marking best clock!");
}
} else {
- if ((clock_info->flags & (1 << clock_is_qualified)) !=
+ if ((clock_private_info->flags & (1 << clock_is_qualified)) !=
0) // if it was qualified, but now isn't
debug(2,
"clock_id %" PRIx64
" on ip: %s \"Announce\" message is not Qualified -- See 9.3.2.5.",
- clock_info->clock_id, clock_info->ip);
- if (pthread_mutex_lock(&shared_memory->shm_mutex) != 0)
- warn("Can't acquire mutex to mark unqualified clock!");
- clock_info->flags &= ~(1 << clock_is_qualified);
- if (pthread_mutex_unlock(&shared_memory->shm_mutex) != 0)
- warn("Can't release mutex after marking unqualified clock!");
+ clock_private_info->clock_id, clock_private_info->ip);
+ clock_private_info->flags &= ~(1 << clock_is_qualified);
}
}
}
}
-void handle_sync(char *buf, __attribute__((unused)) ssize_t recv_len, __attribute__((unused)) clock_source *clock_info,
+void handle_sync(char *buf, __attribute__((unused)) ssize_t recv_len,
clock_source_private_data *clock_private_info, uint64_t reception_time) {
struct ptp_sync_message *msg = (struct ptp_sync_message *)buf;
}
}
-void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len, clock_source *clock_info,
- clock_source_private_data *clock_private_info, __attribute__((unused)) uint64_t reception_time,
- pthread_mutex_t *shm_mutex) {
+void handle_follow_up(char *buf, __attribute__((unused)) ssize_t recv_len,
+ clock_source_private_data *clock_private_info, __attribute__((unused)) uint64_t reception_time) {
struct ptp_follow_up_message *msg = (struct ptp_follow_up_message *)buf;
if ((clock_private_info->current_stage == sync_seen) &&
// now, if there was a valid offset previously,
// check if the offset should be clamped
- if ((clock_info->flags & (1 << clock_is_valid)) &&
+ if ((clock_private_info->flags & (1 << clock_is_valid)) &&
(clock_private_info->vacant_samples != MAX_TIMING_SAMPLES)) {
/*
clock_private_info->previous_estimated_offset = estimated_offset;
- int rc = pthread_mutex_lock(shm_mutex);
- if (rc != 0)
- warn("Can't acquire mutex to update a clock!");
- // update/set the clock_id
-
- clock_info->clock_id = packet_clock_id;
- clock_info->flags |= (1 << clock_is_valid);
- clock_info->local_time = clock_private_info->t2;
- clock_info->local_to_source_time_offset = estimated_offset;
-
- if ((clock_info->flags & (1 << clock_is_master)) != 0) {
- shared_memory->clock_id = clock_info->clock_id;
- shared_memory->local_time = clock_info->local_time;
- //uint64_t new_ptp_offset = clock_info->local_to_source_time_offset;
- //new_ptp_offset += master_clock_to_ptp_offset;
- //shared_memory->local_to_ptp_time_offset = new_ptp_offset;
- shared_memory->local_to_ptp_time_offset = clock_info->local_to_source_time_offset;
- debug(1,"clock: %" PRIx64 ", local_to_ptp_time_offset: %" PRIx64 ".", shared_memory->clock_id, shared_memory->local_to_ptp_time_offset);
+
+ clock_private_info->clock_id = packet_clock_id;
+ clock_private_info->flags |= (1 << clock_is_valid);
+ clock_private_info->local_time = clock_private_info->t2;
+ clock_private_info->local_to_source_time_offset = estimated_offset;
+
+ if ((clock_private_info->flags & (1 << clock_is_master)) != 0) {
+ update_master_clock_info(clock_private_info->clock_id, clock_private_info->local_time, clock_private_info->local_to_source_time_offset);
}
- rc = pthread_mutex_unlock(shm_mutex);
- if (rc != 0)
- warn("Can't release mutex after updating a clock!");
clock_private_info->next_sample_goes_here++;
"Follow_Up %u expecting to be in state sync_seen (%u). Stage error -- "
"current state is %u, sequence %u. Ignoring it. %s",
ntohs(msg->header.sequenceId), sync_seen, clock_private_info->current_stage,
- clock_private_info->sequence_number, clock_info->ip);
+ clock_private_info->sequence_number, clock_private_info->ip);
}
}
\ No newline at end of file
#include "nqptp-clock-sources.h"
#include "nqptp-shm-structures.h"
-void handle_announce(char *buf, ssize_t recv_len, clock_source *clock_info,
+void handle_announce(char *buf, ssize_t recv_len,
clock_source_private_data *clock_private_info, uint64_t reception_time);
-void handle_sync(char *buf, ssize_t recv_len, clock_source *clock_info,
+void handle_sync(char *buf, ssize_t recv_len,
clock_source_private_data *clock_private_info, uint64_t reception_time);
-void handle_follow_up(char *buf, ssize_t recv_len, clock_source *clock_info,
- clock_source_private_data *clock_private_info, uint64_t reception_time,
- pthread_mutex_t *shm_mutex);
+void handle_follow_up(char *buf, ssize_t recv_len,
+ clock_source_private_data *clock_private_info, uint64_t reception_time);
-void handle_control_port_messages(char *buf, ssize_t recv_len, clock_source *clock_info,
+void handle_control_port_messages(char *buf, ssize_t recv_len,
clock_source_private_data *clock_private_info);
#endif
\ No newline at end of file
#define STORAGE_ID "/nqptp"
#define MAX_CLOCKS 32
-#define NQPTP_SHM_STRUCTURES_VERSION 2
+#define NQPTP_SHM_STRUCTURES_VERSION 3
#define NQPTP_CONTROL_PORT 9000
-// the control port will accept a packet with the first letter being:
-// "N" or "U" followed by a space and then a space-delimited
+// the control port will accept a UDP packet with the first letter being:
+// "T", followed by a space and then a space-delimited
// list of ip numbers, either IPv4 or IPv6
// the whole not to exceed 4096 characters in total
+// The IPs will become the new list of timing peers, replacing any previous
#include <inttypes.h>
#include <netinet/in.h>
#include <pthread.h>
-// most of this will probably become private when
-// the master clock selection stuff works automatically
-
-typedef enum {
- clock_is_valid,
- clock_is_a_timing_peer,
- clock_is_qualified,
- clock_is_master
-} clock_flags;
-
-typedef enum {
- new_timing_peer_list = 'N', // followed by a (possibly empty) space-separated list of IPs
- update_timing_peer_list = 'U'
-} control_port_command;
-
-typedef struct {
- char ip[64]; // 64 is nicely aligned and bigger than INET6_ADDRSTRLEN (46)
- uint64_t clock_id;
- uint64_t local_time; // the local time when the offset was calculated
- uint64_t local_to_source_time_offset; // add this to the local time to get source time
- uint32_t flags;
-} clock_source;
-
struct shm_structure {
pthread_mutex_t shm_mutex; // for safely accessing the structure
- uint16_t size_of_clock_array; // deprecated -- check this is equal to MAX_SHARED_CLOCKS
uint16_t version; // deprecated -- check this is equal to NQPTP_SHM_STRUCTURES_VERSION
uint32_t flags; // unused
+ uint64_t master_clock_id; // the current master clock
uint64_t local_time; // the time when the offset was calculated
- uint64_t local_to_ptp_time_offset; // add this to the local time to get PTP time
- uint64_t clock_id; // for information only
- clock_source clocks[MAX_CLOCKS]; // deprecated
+ uint64_t local_to_master_time_offset; // add this to the local time to get master clock time
};
#endif
struct shm_structure *shared_memory = NULL; // this is where public clock info is available
int epoll_fd;
+void update_master_clock_info(uint64_t master_clock_id, uint64_t local_time, uint64_t local_to_master_offset) {
+ if (shared_memory->master_clock_id != master_clock_id)
+ debug(1,"Master clock is: %" PRIx64 ", local_to_ptp_time_offset: %" PRIx64 ".", shared_memory->master_clock_id, shared_memory->local_to_master_time_offset);
+ int rc = pthread_mutex_lock(&shared_memory->shm_mutex);
+ if (rc != 0)
+ warn("Can't acquire mutex to update master clock!");
+ shared_memory->master_clock_id = master_clock_id;
+ shared_memory->local_time = local_time;
+ shared_memory->local_to_master_time_offset = local_to_master_offset;
+ rc = pthread_mutex_unlock(&shared_memory->shm_mutex);
+ if (rc != 0)
+ warn("Can't release mutex after updating master clock!");
+}
+
void goodbye(void) {
// close any open sockets
unsigned int i;
// zero it
memset(shared_memory, 0, sizeof(struct shm_structure));
- shared_memory->size_of_clock_array = MAX_CLOCKS;
shared_memory->version = NQPTP_SHM_STRUCTURES_VERSION;
/*create mutex attr */
}
// 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 *)&shared_memory->clocks,
+ handle_control_port_messages(buf, recv_len,
(clock_source_private_data *)&clocks_private);
} else if (recv_len >= (ssize_t)sizeof(struct ptp_common_message_header)) {
debug_print_buffer(2, buf, recv_len);
inet_ntop(connection_ip_family, sender_addr, sender_string, sizeof(sender_string));
// now, find or create a record for this ip
int the_clock =
- find_clock_source_record(sender_string, (clock_source *)&shared_memory->clocks,
+ 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)) {
the_clock = create_clock_source_record(
- sender_string, (clock_source *)&shared_memory->clocks,
- (clock_source_private_data *)&clocks_private, 1); // the "1" means use mutexes
+ sender_string,
+ (clock_source_private_data *)&clocks_private);
}
if (the_clock != -1) {
clocks_private[the_clock].time_of_last_use =
switch (buf[0] & 0xF) {
case Announce:
// needed to reject messages coming from self
- update_clock_self_identifications((clock_source *)&shared_memory->clocks,
+ update_clock_self_identifications(
(clock_source_private_data *)&clocks_private);
- handle_announce(buf, recv_len, &shared_memory->clocks[the_clock],
+ handle_announce(buf, recv_len,
&clocks_private[the_clock], reception_time);
break;
case Sync: { // if it's a sync
- handle_sync(buf, recv_len, &shared_memory->clocks[the_clock],
+ handle_sync(buf, recv_len,
&clocks_private[the_clock], reception_time);
} break;
case Follow_Up: {
- handle_follow_up(buf, recv_len, &shared_memory->clocks[the_clock],
- &clocks_private[the_clock], reception_time,
- &shared_memory->shm_mutex);
+ handle_follow_up(buf, recv_len,
+ &clocks_private[the_clock], reception_time);
} break;
default:
break;
}
}
}
- manage_clock_sources(reception_time, (clock_source *)&shared_memory->clocks,
+ manage_clock_sources(reception_time,
(clock_source_private_data *)&clocks_private);
}
}
// When a new timing peer group is created, one of the clocks in the
-// group becomes the master and its "native" time becomes the clock's "PTP time".
+// group becomes the master and its native time becomes the "master time".
// This is what is provided to the client.
-// If another clock becomes the new master, then its "native" time will
-// generally be different from PTP time.
-// The offset from the new master's time to PTP time
-// will be added to the master's time to translate it to PTP time.
-
-// You can create a _new_ timing peer group, which starts with a zero
-// master_clock_to_ptp_offset and thus sets the PTP time to the native time
-// of the first clock master of the group, as nature intended.
-
-// Alternatively, you can _update_ an existing timing peer group, which calculates an
-// appropriate master_clock_to_ptp_offset to preserve timing relative to
-// the existing PTP time, ensuring that PTP time remain consistent even
-// when the clock master changes.
-
extern int master_clock_index;
extern struct shm_structure *shared_memory;
+void update_master_clock_info(uint64_t master_clock_id, uint64_t local_time, uint64_t local_to_master_offset);
+
#endif
\ No newline at end of file