From 535ca64bba35c7fd3386d1d1967631a9e3c0706b Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 25 Nov 2016 15:02:35 +0100 Subject: [PATCH] cmdmon: add ntpdata command --- candm.h | 45 +++++++++++++++++++++++++++++++++++++++++++-- cmdmon.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ ntp_core.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ ntp_core.h | 1 + ntp_sources.c | 20 ++++++++++++++++++++ ntp_sources.h | 2 ++ pktlength.c | 2 ++ reports.h | 29 +++++++++++++++++++++++++++++ sourcestats.c | 8 ++++++++ sourcestats.h | 2 ++ stubs.c | 6 ++++++ 11 files changed, 205 insertions(+), 2 deletions(-) diff --git a/candm.h b/candm.h index 19ed7c9..5016fdb 100644 --- a/candm.h +++ b/candm.h @@ -94,7 +94,8 @@ #define REQ_SERVER_STATS 54 #define REQ_CLIENT_ACCESSES_BY_INDEX2 55 #define REQ_LOCAL2 56 -#define N_REQUEST_TYPES 57 +#define REQ_NTP_DATA 57 +#define N_REQUEST_TYPES 58 /* Structure used to exchange timespecs independent of time_t size */ typedef struct { @@ -310,6 +311,11 @@ typedef struct { int32_t EOR; } REQ_SmoothTime; +typedef struct { + IPAddr ip_addr; + int32_t EOR; +} REQ_NTPData; + /* ================================================== */ #define PKT_TYPE_CMD_REQUEST 1 @@ -410,6 +416,7 @@ typedef struct { REQ_ManualDelete manual_delete; REQ_ReselectDistance reselect_distance; REQ_SmoothTime smoothtime; + REQ_NTPData ntp_data; } data; /* Command specific parameters */ /* Padding used to prevent traffic amplification. It only defines the @@ -443,7 +450,8 @@ typedef struct { #define RPY_SMOOTHING 13 #define RPY_SERVER_STATS 14 #define RPY_CLIENT_ACCESSES_BY_INDEX2 15 -#define N_REPLY_TYPES 16 +#define RPY_NTP_DATA 16 +#define N_REPLY_TYPES 17 /* Status codes */ #define STT_SUCCESS 0 @@ -625,6 +633,38 @@ typedef struct { int32_t EOR; } RPY_Smoothing; +#define RPY_NTP_FLAGS_TESTS 0x3ff +#define RPY_NTP_FLAG_INTERLEAVED 0x4000 +#define RPY_NTP_FLAG_AUTHENTICATED 0x8000 + +typedef struct { + IPAddr remote_addr; + IPAddr local_addr; + uint16_t remote_port; + uint8_t leap; + uint8_t version; + uint8_t mode; + uint8_t stratum; + int8_t poll; + int8_t precision; + Float root_delay; + Float root_dispersion; + uint32_t ref_id; + Timespec ref_time; + Float offset; + Float peer_delay; + Float peer_dispersion; + Float response_time; + Float jitter_asymmetry; + uint16_t flags; + uint8_t tx_tss_char; + uint8_t rx_tss_char; + uint32_t total_tx_count; + uint32_t total_rx_count; + uint32_t total_valid_count; + int32_t EOR; +} RPY_NTPData; + typedef struct { uint8_t version; uint8_t pkt_type; @@ -653,6 +693,7 @@ typedef struct { RPY_ManualList manual_list; RPY_Activity activity; RPY_Smoothing smoothing; + RPY_NTPData ntp_data; } data; /* Reply specific parameters */ } CMD_Reply; diff --git a/cmdmon.c b/cmdmon.c index ab3d8a4..3a284aa 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -133,6 +133,7 @@ static const char permissions[] = { PERMIT_AUTH, /* SERVER_STATS */ PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX2 */ PERMIT_AUTH, /* LOCAL2 */ + PERMIT_AUTH, /* NTP_DATA */ }; /* ================================================== */ @@ -1186,6 +1187,49 @@ handle_server_stats(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.server_stats.log_drops = htonl(report.log_drops); } +/* ================================================== */ + +static void +handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message) +{ + RPT_NTPReport report; + + UTI_IPNetworkToHost(&rx_message->data.ntp_data.ip_addr, &report.remote_addr); + + if (!NSR_GetNTPReport(&report)) { + tx_message->status = htons(STT_NOSUCHSOURCE); + return; + } + + tx_message->reply = htons(RPY_NTP_DATA); + UTI_IPHostToNetwork(&report.remote_addr, &tx_message->data.ntp_data.remote_addr); + UTI_IPHostToNetwork(&report.local_addr, &tx_message->data.ntp_data.local_addr); + tx_message->data.ntp_data.remote_port = htons(report.remote_port); + tx_message->data.ntp_data.leap = report.leap; + tx_message->data.ntp_data.version = report.version; + tx_message->data.ntp_data.mode = report.mode; + tx_message->data.ntp_data.stratum = report.stratum; + tx_message->data.ntp_data.poll = report.poll; + tx_message->data.ntp_data.precision = report.precision; + tx_message->data.ntp_data.root_delay = UTI_FloatHostToNetwork(report.root_delay); + tx_message->data.ntp_data.root_dispersion = UTI_FloatHostToNetwork(report.root_dispersion); + tx_message->data.ntp_data.ref_id = htonl(report.ref_id); + UTI_TimespecHostToNetwork(&report.ref_time, &tx_message->data.ntp_data.ref_time); + tx_message->data.ntp_data.offset = UTI_FloatHostToNetwork(report.offset); + tx_message->data.ntp_data.peer_delay = UTI_FloatHostToNetwork(report.peer_delay); + tx_message->data.ntp_data.peer_dispersion = UTI_FloatHostToNetwork(report.peer_dispersion); + tx_message->data.ntp_data.response_time = UTI_FloatHostToNetwork(report.response_time); + tx_message->data.ntp_data.jitter_asymmetry = UTI_FloatHostToNetwork(report.jitter_asymmetry); + tx_message->data.ntp_data.flags = htons((report.tests & RPY_NTP_FLAGS_TESTS) | + (report.interleaved ? RPY_NTP_FLAG_INTERLEAVED : 0) | + (report.authenticated ? RPY_NTP_FLAG_AUTHENTICATED : 0)); + tx_message->data.ntp_data.tx_tss_char = report.tx_tss_char; + tx_message->data.ntp_data.rx_tss_char = report.rx_tss_char; + tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count); + tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count); + tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count); +} + /* ================================================== */ /* Read a packet and process it */ @@ -1573,6 +1617,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything) handle_server_stats(&rx_message, &tx_message); break; + case REQ_NTP_DATA: + handle_ntp_data(&rx_message, &tx_message); + break; + default: DEBUG_LOG(LOGF_CmdMon, "Unhandled command %d", rx_command); tx_message.status = htons(STT_FAILED); diff --git a/ntp_core.c b/ntp_core.c index 2ee3958..a0b55df 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -186,6 +186,8 @@ struct NCR_Instance_Record { int burst_good_samples_to_go; int burst_total_samples_to_go; + /* Report from last valid response */ + RPT_NTPReport report; }; typedef struct { @@ -558,6 +560,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar result->local_tx.source = NTP_TS_DAEMON; result->burst_good_samples_to_go = 0; result->burst_total_samples_to_go = 0; + memset(&result->report, 0, sizeof (result->report)); NCR_ResetInstance(result); @@ -1073,6 +1076,8 @@ transmit_timeout(void *arg) ++inst->tx_count; inst->valid_rx = 0; inst->updated_timestamps = 0; + if (sent) + inst->report.total_tx_count++; /* If the source loses connectivity and our packets are still being sent, back off the sampling rate to reduce the network traffic. If it's the @@ -1284,6 +1289,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr, stats = SRC_GetSourcestats(inst->source); + inst->report.total_rx_count++; + pkt_leap = NTP_LVM_TO_LEAP(message->lvm); pkt_refid = ntohl(message->reference_id); pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay); @@ -1585,6 +1592,35 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr, assert(inst->tx_timeout_id); restart_timeout(inst, delay_time); } + + /* Update the NTP report */ + inst->report.remote_addr = inst->remote_addr.ip_addr; + inst->report.local_addr = inst->local_addr.ip_addr; + inst->report.remote_port = inst->remote_addr.port; + inst->report.leap = NTP_LVM_TO_LEAP(message->lvm); + inst->report.version = NTP_LVM_TO_VERSION(message->lvm); + inst->report.mode = NTP_LVM_TO_MODE(message->lvm); + inst->report.stratum = message->stratum; + inst->report.poll = message->poll; + inst->report.precision = message->precision; + inst->report.root_delay = pkt_root_delay; + inst->report.root_dispersion = pkt_root_dispersion; + inst->report.ref_id = pkt_refid; + UTI_Ntp64ToTimespec(&message->reference_ts, &inst->report.ref_time); + inst->report.offset = offset; + inst->report.peer_delay = delay; + inst->report.peer_dispersion = dispersion; + inst->report.response_time = server_interval; + inst->report.jitter_asymmetry = SST_GetJitterAsymmetry(stats); + inst->report.tests = ((((((((test1 << 1 | test2) << 1 | test3) << 1 | + test5) << 1 | test6) << 1 | test7) << 1 | + testA) << 1 | testB) << 1 | testC) << 1 | testD; + inst->report.interleaved = interleaved_packet; + inst->report.authenticated = inst->auth_mode != AUTH_NONE; + inst->report.tx_tss_char = tss_chars[inst->local_tx.source]; + inst->report.rx_tss_char = tss_chars[sample_rx_tss]; + + inst->report.total_valid_count++; } /* Do measurement logging */ @@ -2140,6 +2176,14 @@ NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *n /* ================================================== */ +void +NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report) +{ + *report = inst->report; +} + +/* ================================================== */ + int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all) { diff --git a/ntp_core.h b/ntp_core.h index 699cb83..f788d68 100644 --- a/ntp_core.h +++ b/ntp_core.h @@ -123,6 +123,7 @@ extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target); extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples); extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now); +extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report); extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all); extern int NCR_CheckAccessRestriction(IPAddr *ip_addr); diff --git a/ntp_sources.c b/ntp_sources.c index 835599f..5024a42 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -1120,6 +1120,26 @@ NSR_ReportSource(RPT_SourceReport *report, struct timespec *now) } } +/* ================================================== */ +/* The ip address is assumed to be completed on input, that is how we + identify the source record. */ + +int +NSR_GetNTPReport(RPT_NTPReport *report) +{ + NTP_Remote_Address rem_addr; + int slot, found; + + rem_addr.ip_addr = report->remote_addr; + rem_addr.port = 0; + find_slot(&rem_addr, &slot, &found); + if (!found) + return 0; + + NCR_GetNTPReport(get_record(slot)->data, report); + return 1; +} + /* ================================================== */ void diff --git a/ntp_sources.h b/ntp_sources.h index 424eab6..23e9612 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -129,6 +129,8 @@ extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAd extern void NSR_ReportSource(RPT_SourceReport *report, struct timespec *now); +extern int NSR_GetNTPReport(RPT_NTPReport *report); + extern void NSR_GetActivityReport(RPT_ActivityReport *report); #endif /* GOT_NTP_SOURCES_H */ diff --git a/pktlength.c b/pktlength.c index 7366e51..459b79c 100644 --- a/pktlength.c +++ b/pktlength.c @@ -113,6 +113,7 @@ static const struct request_length request_lengths[] = { REQ_LENGTH_ENTRY(client_accesses_by_index, client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */ REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */ + REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */ }; static const uint16_t reply_lengths[] = { @@ -132,6 +133,7 @@ static const uint16_t reply_lengths[] = { RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */ RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */ RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */ + RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */ }; /* ================================================== */ diff --git a/reports.h b/reports.h index 20fd32c..6a24670 100644 --- a/reports.h +++ b/reports.h @@ -131,4 +131,33 @@ typedef struct { double remaining_time; } RPT_SmoothingReport; +typedef struct { + IPAddr remote_addr; + IPAddr local_addr; + uint16_t remote_port; + uint8_t leap; + uint8_t version; + uint8_t mode; + uint8_t stratum; + int8_t poll; + int8_t precision; + double root_delay; + double root_dispersion; + uint32_t ref_id; + struct timespec ref_time; + double offset; + double peer_delay; + double peer_dispersion; + double response_time; + double jitter_asymmetry; + uint16_t tests; + int interleaved; + int authenticated; + char tx_tss_char; + char rx_tss_char; + uint32_t total_tx_count; + uint32_t total_rx_count; + uint32_t total_valid_count; +} RPT_NTPReport; + #endif /* GOT_REPORTS_H */ diff --git a/sourcestats.c b/sourcestats.c index d8a6987..09f1aef 100644 --- a/sourcestats.c +++ b/sourcestats.c @@ -994,3 +994,11 @@ SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct ti } /* ================================================== */ + +double +SST_GetJitterAsymmetry(SST_Stats inst) +{ + return inst->asymmetry; +} + +/* ================================================== */ diff --git a/sourcestats.h b/sourcestats.h index 0c1f209..48f73b3 100644 --- a/sourcestats.h +++ b/sourcestats.h @@ -139,5 +139,7 @@ extern void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *repor extern int SST_Samples(SST_Stats inst); +extern double SST_GetJitterAsymmetry(SST_Stats inst); + #endif /* GOT_SOURCESTATS_H */ diff --git a/stubs.c b/stubs.c index 1479117..9bc127c 100644 --- a/stubs.c +++ b/stubs.c @@ -297,6 +297,12 @@ NSR_ReportSource(RPT_SourceReport *report, struct timespec *now) memset(report, 0, sizeof (*report)); } +int +NSR_GetNTPReport(RPT_NTPReport *report) +{ + return 0; +} + void NSR_GetActivityReport(RPT_ActivityReport *report) {