#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 {
int32_t EOR;
} REQ_SmoothTime;
+typedef struct {
+ IPAddr ip_addr;
+ int32_t EOR;
+} REQ_NTPData;
+
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
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
#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
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;
RPY_ManualList manual_list;
RPY_Activity activity;
RPY_Smoothing smoothing;
+ RPY_NTPData ntp_data;
} data; /* Reply specific parameters */
} CMD_Reply;
PERMIT_AUTH, /* SERVER_STATS */
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX2 */
PERMIT_AUTH, /* LOCAL2 */
+ PERMIT_AUTH, /* NTP_DATA */
};
/* ================================================== */
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 */
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);
int burst_good_samples_to_go;
int burst_total_samples_to_go;
+ /* Report from last valid response */
+ RPT_NTPReport report;
};
typedef struct {
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);
++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
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);
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 */
/* ================================================== */
+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)
{
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);
}
}
+/* ================================================== */
+/* 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
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 */
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[] = {
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 */
};
/* ================================================== */
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 */
}
/* ================================================== */
+
+double
+SST_GetJitterAsymmetry(SST_Stats inst)
+{
+ return inst->asymmetry;
+}
+
+/* ================================================== */
extern int SST_Samples(SST_Stats inst);
+extern double SST_GetJitterAsymmetry(SST_Stats inst);
+
#endif /* GOT_SOURCESTATS_H */
memset(report, 0, sizeof (*report));
}
+int
+NSR_GetNTPReport(RPT_NTPReport *report)
+{
+ return 0;
+}
+
void
NSR_GetActivityReport(RPT_ActivityReport *report)
{