ptpd: Implement status & stop interfaces

This commit is contained in:
Petteri Aimonen 2023-11-24 10:08:22 +02:00 committed by Xiang Xiao
parent efc6cfddb4
commit 0adce22400
3 changed files with 441 additions and 15 deletions

View File

@ -33,6 +33,66 @@
* Public Types
****************************************************************************/
/* PTPD status information structure */
struct ptpd_status_s
{
/* Is there a valid remote clock source active? */
bool clock_source_valid;
/* Information about selected best clock source */
struct
{
uint8_t id[8]; /* Clock identity */
int utcoffset; /* Offset between clock time and UTC time (seconds) */
int priority1; /* Main priority field */
int class; /* Clock class (IEEE-1588, lower is better) */
int accuracy; /* Clock accuracy (IEEE-1588, lower is better) */
int variance; /* Clock variance (IEEE-1588, lower is better) */
int priority2; /* Secondary priority field */
uint8_t gm_id[8]; /* Grandmaster clock identity */
int stepsremoved; /* How many steps from grandmaster clock */
int timesource; /* Type of time source (IEEE-1588) */
} clock_source_info;
/* When was clock last updated or adjusted (CLOCK_REALTIME).
* Matches last_received_sync but in different clock.
*/
struct timespec last_clock_update;
/* Details of clock adjustment made at last_clock_update */
int64_t last_delta_ns; /* Latest measured clock error */
int64_t last_adjtime_ns; /* Previously applied adjtime() offset */
/* Averaged clock drift estimate (parts per billion).
* Positive means remote clock runs faster than local clock before
* adjustment.
*/
long drift_ppb;
/* Averaged path delay */
long path_delay_ns;
/* Timestamps of latest received packets (CLOCK_MONOTONIC) */
struct timespec last_received_multicast; /* Any multicast packet */
struct timespec last_received_announce; /* Announce from any server */
struct timespec last_received_sync; /* Sync from selected source */
/* Timestamps of latest transmitted packets (CLOCK_MONOTONIC) */
struct timespec last_transmitted_sync;
struct timespec last_transmitted_announce;
struct timespec last_transmitted_delayresp;
struct timespec last_transmitted_delayreq;
};
/****************************************************************************
* Public Data
****************************************************************************/
@ -55,6 +115,9 @@ extern "C"
* Description:
* Start the PTP daemon and bind it to specified interface.
*
* Input Parameters:
* interface - Name of the network interface to bind to, e.g. "eth0"
*
* Returned Value:
* On success, the non-negative task ID of the PTP daemon is returned;
* On failure, a negated errno value is returned.
@ -63,6 +126,41 @@ extern "C"
int ptpd_start(const char *interface);
/****************************************************************************
* Name: ptpd_status
*
* Description:
* Query status from a running PTP daemon.
*
* Input Parameters:
* pid - Process ID previously returned by ptpd_start()
* status - Pointer to storage for status information.
*
* Returned Value:
* On success, returns OK.
* On failure, a negated errno value is returned.
*
****************************************************************************/
int ptpd_status(int pid, struct ptpd_status_s *status);
/****************************************************************************
* Name: ptpd_stop
*
* Description:
* Stop PTP daemon
*
* Input Parameters:
* pid - Process ID previously returned by ptpd_start()
*
* Returned Value:
* On success, returns OK.
* On failure, a negated errno value is returned.
*
****************************************************************************/
int ptpd_stop(int pid);
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -57,9 +57,22 @@
* Private Data
****************************************************************************/
/* Carrier structure for querying PTPD status */
struct ptpd_statusreq_s
{
sem_t *done;
struct ptpd_status_s *dest;
};
/* Main PTPD state storage */
struct ptp_state_s
{
/* Request for PTPD task to stop or report status */
bool stop;
struct ptpd_statusreq_s status_req;
/* Address of network interface we are operating on */
@ -1262,6 +1275,110 @@ static int ptp_process_rx_packet(struct ptp_state_s *state, ssize_t length)
}
}
/* Signal handler for status / stop requests */
static void ptp_signal_handler(int signo, FAR siginfo_t *siginfo,
FAR void *context)
{
struct ptp_state_s *state = (struct ptp_state_s *)siginfo->si_user;
if (signo == SIGHUP)
{
state->stop = true;
}
else if (signo == SIGUSR1 && siginfo->si_value.sival_ptr)
{
state->status_req =
*(struct ptpd_statusreq_s *)siginfo->si_value.sival_ptr;
}
}
static void ptp_setup_sighandlers(struct ptp_state_s *state)
{
struct sigaction act;
act.sa_sigaction = &ptp_signal_handler;
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_user = state;
sigaction(SIGHUP, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
}
/* Process status information request */
static void ptp_process_statusreq(struct ptp_state_s *state)
{
struct ptpd_status_s *status;
if (!state->status_req.dest)
{
return; /* No active request */
}
status = state->status_req.dest;
status->clock_source_valid = state->selected_source_valid;
if (status->clock_source_valid)
{
/* Copy relevant parts of announce info to status struct */
struct ptp_announce_s *s = &state->selected_source;
memcpy(status->clock_source_info.id,
s->header.sourceidentity,
sizeof(status->clock_source_info.id));
status->clock_source_info.utcoffset =
(int16_t)(((uint16_t)s->utcoffset[0] << 8) | s->utcoffset[1]);
status->clock_source_info.priority1 = s->gm_priority1;
status->clock_source_info.class = s->gm_quality[0];
status->clock_source_info.accuracy = s->gm_quality[1];
status->clock_source_info.priority2 = s->gm_priority2;
status->clock_source_info.variance =
((uint16_t)s->gm_quality[2] << 8) | s->gm_quality[3];
memcpy(status->clock_source_info.gm_id,
s->gm_identity,
sizeof(status->clock_source_info.gm_id));
status->clock_source_info.stepsremoved =
((uint16_t)s->stepsremoved[0] << 8) | s->stepsremoved[1];
status->clock_source_info.timesource = s->timesource;
}
/* Copy latest adjustment info */
status->last_clock_update = state->last_delta_timestamp;
status->last_delta_ns = state->last_delta_ns;
status->last_adjtime_ns = state->last_adjtime_ns;
status->drift_ppb = state->drift_ppb;
status->path_delay_ns = state->path_delay_ns;
/* Copy timestamps */
status->last_received_multicast = state->last_received_multicast;
status->last_received_announce = state->last_received_announce;
status->last_received_sync = state->last_received_sync;
status->last_transmitted_sync = state->last_transmitted_sync;
status->last_transmitted_announce = state->last_transmitted_announce;
status->last_transmitted_delayresp = state->last_transmitted_delayresp;
status->last_transmitted_delayreq = state->last_transmitted_delayreq;
/* Post semaphore to inform that we are done */
if (state->status_req.done)
{
sem_post(state->status_req.done);
}
state->status_req.done = NULL;
state->status_req.dest = NULL;
}
/* Main PTPD task */
static int ptp_daemon(int argc, FAR char** argv)
{
const char *interface = "eth0";
@ -1284,9 +1401,15 @@ static int ptp_daemon(int argc, FAR char** argv)
if (ptp_initialize_state(state, interface) != OK)
{
ptperr("Failed to initialize PTP state, exiting\n");
ptp_destroy_state(state);
free(state);
return ERROR;
}
ptp_setup_sighandlers(state);
pollfds[0].events = POLLIN;
pollfds[0].fd = state->event_socket;
pollfds[1].events = POLLIN;
@ -1346,6 +1469,7 @@ static int ptp_daemon(int argc, FAR char** argv)
ptp_periodic_send(state);
state->selected_source_valid = is_selected_source_valid(state);
ptp_process_statusreq(state);
}
ptp_destroy_state(state);
@ -1364,6 +1488,9 @@ static int ptp_daemon(int argc, FAR char** argv)
* Description:
* Start the PTP daemon and bind it to specified interface.
*
* Input Parameters:
* interface - Name of the network interface to bind to, e.g. "eth0"
*
* Returned Value:
* On success, the non-negative task ID of the PTP daemon is returned;
* On failure, a negated errno value is returned.
@ -1388,7 +1515,7 @@ int ptpd_start(const char *interface)
usleep(USEC_PER_TICK);
if (kill(pid, 0) != OK)
{
return -1;
return ERROR;
}
else
{
@ -1396,4 +1523,90 @@ int ptpd_start(const char *interface)
}
}
/* TODO: Implement status and stop interfaces */
/****************************************************************************
* Name: ptpd_status
*
* Description:
* Query status from a running PTP daemon.
*
* Input Parameters:
* pid - Process ID previously returned by ptpd_start()
* status - Pointer to storage for status information.
*
* Returned Value:
* On success, returns OK.
* On failure, a negated errno value is returned.
*
****************************************************************************/
int ptpd_status(int pid, struct ptpd_status_s *status)
{
#ifdef CONFIG_BUILD_PROTECTED
/* TODO: Use SHM memory to pass the status information if processes
* do not share the same memory space.
*/
return -ENOTSUP;
#else
int ret = OK;
sem_t donesem;
struct ptpd_statusreq_s req;
union sigval val;
struct timespec timeout;
/* Fill in the status request */
memset(status, 0, sizeof(struct ptpd_status_s));
sem_init(&donesem, 0, 0);
req.done = &donesem;
req.dest = status;
val.sival_ptr = (void *)&req;
if (sigqueue(pid, SIGUSR1, val) != OK)
{
return -errno;
}
/* Wait for status request to be handled */
clock_gettime(CLOCK_MONOTONIC, &timeout);
timeout.tv_sec += 1;
if (sem_clockwait(&donesem, CLOCK_MONOTONIC, &timeout) != 0)
{
ret = -errno;
}
return ret;
#endif /* CONFIG_BUILD_PROTECTED */
}
/****************************************************************************
* Name: ptpd_stop
*
* Description:
* Stop PTP daemon
*
* Input Parameters:
* pid - Process ID previously returned by ptpd_start()
*
* Returned Value:
* On success, returns OK.
* On failure, a negated errno value is returned.
*
****************************************************************************/
int ptpd_stop(int pid)
{
if (kill(pid, SIGHUP) == OK)
{
return OK;
}
else
{
return -errno;
}
}

View File

@ -30,24 +30,14 @@
#include "netutils/ptpd.h"
/****************************************************************************
* Public Functions
* Private Functions
****************************************************************************/
/****************************************************************************
* ptpd_main
****************************************************************************/
int main(int argc, FAR char *argv[])
static int do_ptpd_start(const char *interface)
{
int pid;
if (argc != 2)
{
fprintf(stderr, "Usage: ptpd <interface>\n");
return 1;
}
pid = ptpd_start(argv[1]);
pid = ptpd_start(interface);
if (pid < 0)
{
fprintf(stderr, "ERROR: ptpd_start() failed\n");
@ -57,3 +47,128 @@ int main(int argc, FAR char *argv[])
printf("Started the PTP daemon as PID=%d\n", pid);
return EXIT_SUCCESS;
}
static int do_ptpd_status(int pid)
{
struct ptpd_status_s status;
char buf[64];
struct tm time_tm;
struct timespec time_now;
int ret;
ret = ptpd_status(pid, &status);
if (ret != OK)
{
fprintf(stderr, "Failed to query PTPD status: %s\n", strerror(-ret));
return EXIT_FAILURE;
}
printf("PTPD (PID %d) status:\n", pid);
printf("- clock_source_valid: %d\n", (int)status.clock_source_valid);
if (status.clock_source_valid)
{
printf("|- id: %02x %02x %02x %02x %02x %02x %02x %02x\n",
status.clock_source_info.id[0], status.clock_source_info.id[1],
status.clock_source_info.id[2], status.clock_source_info.id[3],
status.clock_source_info.id[4], status.clock_source_info.id[5],
status.clock_source_info.id[6], status.clock_source_info.id[7]
);
printf("|- utcoffset: %d\n", status.clock_source_info.utcoffset);
printf("|- priority1: %d\n", status.clock_source_info.priority1);
printf("|- class: %d\n", status.clock_source_info.class);
printf("|- accuracy: %d\n", status.clock_source_info.accuracy);
printf("|- variance: %d\n", status.clock_source_info.variance);
printf("|- priority2: %d\n", status.clock_source_info.priority2);
printf("|- gm_id: %02x %02x %02x %02x %02x %02x %02x %02x\n",
status.clock_source_info.gm_id[0], status.clock_source_info.gm_id[1],
status.clock_source_info.gm_id[2], status.clock_source_info.gm_id[3],
status.clock_source_info.gm_id[4], status.clock_source_info.gm_id[5],
status.clock_source_info.gm_id[6], status.clock_source_info.gm_id[7]
);
printf("|- stepsremoved: %d\n", status.clock_source_info.stepsremoved);
printf("'- timesource: %d\n", status.clock_source_info.timesource);
}
gmtime_r(&status.last_clock_update.tv_sec, &time_tm);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time_tm);
printf("- last_clock_update: %s.%09ld\n",
buf, (long)status.last_clock_update.tv_nsec);
printf("- last_delta_ns: %lld\n", (long long)status.last_delta_ns);
printf("- last_adjtime_ns: %lld\n", (long long)status.last_adjtime_ns);
printf("- drift_ppb: %ld\n", status.drift_ppb);
printf("- path_delay_ns: %ld\n", status.path_delay_ns);
clock_gettime(CLOCK_MONOTONIC, &time_now);
printf("- last_received_multicast: %d s ago\n",
(int)(time_now.tv_sec - status.last_received_multicast.tv_sec));
printf("- last_received_announce: %d s ago\n",
(int)(time_now.tv_sec - status.last_received_announce.tv_sec));
printf("- last_received_sync: %d s ago\n",
(int)(time_now.tv_sec - status.last_received_sync.tv_sec));
printf("- last_transmitted_sync: %d s ago\n",
(int)(time_now.tv_sec - status.last_transmitted_sync.tv_sec));
printf("- last_transmitted_announce: %d s ago\n",
(int)(time_now.tv_sec - status.last_transmitted_announce.tv_sec));
printf("- last_transmitted_delayresp: %d s ago\n",
(int)(time_now.tv_sec - status.last_transmitted_delayresp.tv_sec));
printf("- last_transmitted_delayreq: %d s ago\n",
(int)(time_now.tv_sec - status.last_transmitted_delayreq.tv_sec));
return EXIT_SUCCESS;
}
int do_ptpd_stop(int pid)
{
int ret;
ret = ptpd_stop(pid);
if (ret == OK)
{
printf("Stopped ptpd\n");
return EXIT_SUCCESS;
}
else
{
printf("Failed to stop ptpd: %s\n", strerror(-ret));
return EXIT_FAILURE;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* ptpd_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
if (argc == 3 && strcmp(argv[1], "start") == 0)
{
return do_ptpd_start(argv[2]);
}
else if (argc == 3 && strcmp(argv[1], "status") == 0)
{
return do_ptpd_status(atoi(argv[2]));
}
else if (argc == 3 && strcmp(argv[1], "stop") == 0)
{
return do_ptpd_stop(atoi(argv[2]));
}
else
{
fprintf(stderr, "Usage: \n"
"ptpd start <interface>\n"
"ptpd status <pid>\n"
"ptpd stop <pid>\n");
return EXIT_FAILURE;
}
}