From 657929f8ec8fe7483c8e857d2aa3ba80ce8c4410 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 27 Nov 2015 15:25:24 +0100 Subject: [PATCH] cmdmon: update CLIENT_ACCESSES_BY_INDEX command Add new fields from clientlog to the report and print them in chronyc. Rework the code to skip empty records in the hash table. The reply no longer has variable length, all client fields are filled even if some are empty. Reply with RPY_NULL when the facility is disabled. --- candm.h | 17 ++++---- client.c | 116 ++++++++++++++++++++-------------------------------- clientlog.c | 35 +++++++++++----- clientlog.h | 14 +------ cmdmon.c | 72 ++++++++++++++++---------------- pktlength.c | 12 +----- reports.h | 13 ++++-- 7 files changed, 128 insertions(+), 151 deletions(-) diff --git a/candm.h b/candm.h index e4eafb7..a740aa2 100644 --- a/candm.h +++ b/candm.h @@ -284,7 +284,7 @@ typedef struct { typedef struct { uint32_t first_index; - uint32_t n_indices; + uint32_t n_clients; int32_t EOR; } REQ_ClientAccessesByIndex; @@ -351,7 +351,7 @@ typedef struct { #define PROTO_VERSION_PADDING 6 /* The maximum length of padding in request packet, currently - defined by CLIENT_ACCESSES_BY_INDEX and MANUAL_LIST */ + defined by MANUAL_LIST */ #define MAX_PADDING_LENGTH 396 /* ================================================== */ @@ -545,11 +545,14 @@ typedef struct { typedef struct { IPAddr ip; - uint32_t client_hits; - uint32_t peer_hits; - uint32_t cmd_hits_auth; - uint32_t cmd_hits_normal; - uint32_t cmd_hits_bad; + uint32_t ntp_hits; + uint32_t cmd_hits; + uint16_t ntp_drops; + uint16_t cmd_drops; + int8_t ntp_interval; + int8_t cmd_interval; + int8_t ntp_timeout_interval; + int8_t pad; uint32_t last_ntp_hit_ago; uint32_t last_cmd_hit_ago; } RPY_ClientAccesses_Client; diff --git a/client.c b/client.c index cd0977c..f8f2ecf 100644 --- a/client.c +++ b/client.c @@ -2047,87 +2047,61 @@ process_cmd_clients(char *line) { CMD_Request request; CMD_Reply reply; - unsigned long next_index; - int j; IPAddr ip; - unsigned long client_hits; - unsigned long peer_hits; - unsigned long cmd_hits_auth; - unsigned long cmd_hits_normal; - unsigned long cmd_hits_bad; - unsigned long last_ntp_hit_ago; - unsigned long last_cmd_hit_ago; - char hostname_buf[50]; - - int n_replies; - int n_indices_in_table; + uint32_t i, n_clients, next_index, n_indices; + RPY_ClientAccesses_Client *client; + char hostname[26]; next_index = 0; - printf("Hostname Client Peer CmdAuth CmdNorm CmdBad LstN LstC\n" - "========================= ====== ====== ====== ====== ====== ==== ====\n"); - - do { + printf("Hostname NTP Drop Int IntL Last Cmd Drop Int Last\n" + "===============================================================================\n"); + while (1) { request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX); request.data.client_accesses_by_index.first_index = htonl(next_index); - request.data.client_accesses_by_index.n_indices = htonl(MAX_CLIENT_ACCESSES); + request.data.client_accesses_by_index.n_clients = htonl(MAX_CLIENT_ACCESSES); - if (request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX, 0)) { - n_replies = ntohl(reply.data.client_accesses_by_index.n_clients); - n_indices_in_table = ntohl(reply.data.client_accesses_by_index.n_indices); - if (n_replies == 0) { - goto finished; - } - for (j=0; j= n_indices_in_table) { - goto finished; - } - } else { + if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX, 0)) return 0; - } - } while (1); /* keep going until all subnets have been expanded, - down to single nodes */ -finished: + n_clients = ntohl(reply.data.client_accesses_by_index.n_clients); + n_indices = ntohl(reply.data.client_accesses_by_index.n_indices); + + for (i = 0; i < n_clients && i < MAX_CLIENT_ACCESSES; i++) { + client = &reply.data.client_accesses_by_index.clients[i]; + + UTI_IPNetworkToHost(&client->ip, &ip); + + /* UNSPEC means the record could not be found in the daemon's tables. + We shouldn't ever generate this case, but ignore it if we do. */ + if (ip.family == IPADDR_UNSPEC) + continue; + + if (no_dns) + snprintf(hostname, sizeof (hostname), "%s", UTI_IPToString(&ip)); + else + DNS_IPAddress2Name(&ip, hostname, sizeof (hostname)); + + printf("%-25s", hostname); + printf(" %6"PRIu32" %5"PRIu16" %2d %2d ", + ntohl(client->ntp_hits), ntohs(client->ntp_drops), + client->ntp_interval, client->ntp_timeout_interval); + print_seconds(ntohl(client->last_ntp_hit_ago)); + printf(" %6"PRIu32" %5"PRIu16" %2d ", + ntohl(client->cmd_hits), ntohs(client->cmd_drops), + client->cmd_interval); + print_seconds(ntohl(client->last_cmd_hit_ago)); + printf("\n"); + } + + /* Set the next index to probe based on what the server tells us */ + next_index = ntohl(reply.data.client_accesses_by_index.next_index); + + if (next_index >= n_indices || n_clients < MAX_CLIENT_ACCESSES) + break; + } + return 1; } diff --git a/clientlog.c b/clientlog.c index 6f66738..66da722 100644 --- a/clientlog.c +++ b/clientlog.c @@ -481,26 +481,41 @@ CLG_LimitCommandResponseRate(int index) /* ================================================== */ -CLG_Status -CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, - time_t now, unsigned long *n_indices) +extern int +CLG_GetNumberOfIndices(void) +{ + if (!active) + return -1; + + return ARR_GetSize(records); +} + +/* ================================================== */ + +int +CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, time_t now) { Record *record; - if (!active) - return CLG_INACTIVE; + if (!active || index < 0 || index >= ARR_GetSize(records)) + return 0; - *n_indices = ARR_GetSize(records); - if (index < 0 || index >= *n_indices) - return CLG_INDEXTOOLARGE; - record = ARR_GetElement(records, index); + if (record->ip_addr.family == IPADDR_UNSPEC) + return 0; + report->ip_addr = record->ip_addr; report->ntp_hits = record->ntp_hits; report->cmd_hits = record->cmd_hits; + report->ntp_drops = record->ntp_drops; + report->cmd_drops = record->cmd_drops; + report->ntp_interval = (record->ntp_rate - RATE_SCALE / 2) / -RATE_SCALE; + report->cmd_interval = (record->cmd_rate - RATE_SCALE / 2) / -RATE_SCALE; + report->ntp_timeout_interval = + (record->ntp_timeout_rate - RATE_SCALE / 2) / -RATE_SCALE; report->last_ntp_hit_ago = now - record->last_ntp_hit; report->last_cmd_hit_ago = now - record->last_cmd_hit; - return CLG_SUCCESS; + return 1; } diff --git a/clientlog.h b/clientlog.h index a4a429f..f604676 100644 --- a/clientlog.h +++ b/clientlog.h @@ -39,18 +39,8 @@ extern int CLG_LimitNTPResponseRate(int index); extern int CLG_LimitCommandResponseRate(int index); /* And some reporting functions, for use by chronyc. */ -/* TBD */ -typedef enum { - CLG_SUCCESS, /* All is well */ - CLG_EMPTYSUBNET, /* No hosts logged in requested subnet */ - CLG_BADSUBNET, /* Subnet requested is not 0, 8, 16 or 24 bits */ - CLG_INACTIVE, /* Facility not active */ - CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */ -} CLG_Status; - -CLG_Status -CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, - time_t now, unsigned long *n_indices); +extern int CLG_GetNumberOfIndices(void); +extern int CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, time_t now); #endif /* GOT_CLIENTLOG_H */ diff --git a/cmdmon.c b/cmdmon.c index b71b657..b246900 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -1017,50 +1017,50 @@ handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message) static void handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message) { - CLG_Status result; RPT_ClientAccessByIndex_Report report; - unsigned long first_index, n_indices, n_indices_in_table; - int i, j; + RPY_ClientAccesses_Client *client; + int n_indices; + uint32_t i, j, req_first_index, req_n_clients; struct timeval now; SCH_GetLastEventTime(&now, NULL, NULL); - first_index = ntohl(rx_message->data.client_accesses_by_index.first_index); - n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices); - if (n_indices > MAX_CLIENT_ACCESSES) - n_indices = MAX_CLIENT_ACCESSES; + req_first_index = ntohl(rx_message->data.client_accesses_by_index.first_index); + req_n_clients = ntohl(rx_message->data.client_accesses_by_index.n_clients); + if (req_n_clients > MAX_CLIENT_ACCESSES) + req_n_clients = MAX_CLIENT_ACCESSES; - tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX); - - for (i = 0, j = 0; i < n_indices; i++) { - result = CLG_GetClientAccessReportByIndex(first_index + i, &report, - now.tv_sec, &n_indices_in_table); - tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices_in_table); - - switch (result) { - case CLG_SUCCESS: - UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.client_accesses_by_index.clients[j].ip); - tx_message->data.client_accesses_by_index.clients[j].client_hits = htonl(report.ntp_hits); - tx_message->data.client_accesses_by_index.clients[j].peer_hits = htonl(0); - tx_message->data.client_accesses_by_index.clients[j].cmd_hits_auth = htonl(0); - tx_message->data.client_accesses_by_index.clients[j].cmd_hits_normal = htonl(report.cmd_hits); - tx_message->data.client_accesses_by_index.clients[j].cmd_hits_bad = htonl(0); - tx_message->data.client_accesses_by_index.clients[j].last_ntp_hit_ago = htonl(report.last_ntp_hit_ago); - tx_message->data.client_accesses_by_index.clients[j].last_cmd_hit_ago = htonl(report.last_cmd_hit_ago); - j++; - break; - case CLG_INDEXTOOLARGE: - break; /* ignore this index */ - case CLG_INACTIVE: - tx_message->status = htons(STT_INACTIVE); - return; - default: - assert(0); - break; - } + n_indices = CLG_GetNumberOfIndices(); + if (n_indices < 0) { + tx_message->status = htons(STT_INACTIVE); + return; } - tx_message->data.client_accesses_by_index.next_index = htonl(first_index + i); + tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX); + tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices); + + memset(tx_message->data.client_accesses_by_index.clients, 0, + sizeof (tx_message->data.client_accesses_by_index.clients)); + + for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) { + if (!CLG_GetClientAccessReportByIndex(i, &report, now.tv_sec)) + continue; + + client = &tx_message->data.client_accesses_by_index.clients[j++]; + + UTI_IPHostToNetwork(&report.ip_addr, &client->ip); + client->ntp_hits = htonl(report.ntp_hits); + client->cmd_hits = htonl(report.cmd_hits); + client->ntp_drops = htons(report.ntp_drops); + client->cmd_drops = htons(report.cmd_drops); + client->ntp_interval = report.ntp_interval; + client->cmd_interval = report.cmd_interval; + client->ntp_timeout_interval = report.ntp_timeout_interval; + client->last_ntp_hit_ago = htonl(report.last_ntp_hit_ago); + client->last_cmd_hit_ago = htonl(report.last_cmd_hit_ago); + } + + tx_message->data.client_accesses_by_index.next_index = htonl(i); tx_message->data.client_accesses_by_index.n_clients = htonl(j); } diff --git a/pktlength.c b/pktlength.c index e123ef4..a853465 100644 --- a/pktlength.c +++ b/pktlength.c @@ -346,17 +346,7 @@ PKL_ReplyLength(CMD_Reply *r) /* No longer supported */ return 0; case RPY_CLIENT_ACCESSES_BY_INDEX: - { - unsigned long nc = ntohl(r->data.client_accesses_by_index.n_clients); - if (r->status == htons(STT_SUCCESS)) { - if (nc > MAX_CLIENT_ACCESSES) - return 0; - return (offsetof(CMD_Reply, data.client_accesses_by_index.clients) + - nc * sizeof(RPY_ClientAccesses_Client)); - } else { - return offsetof(CMD_Reply, data); - } - } + return offsetof(CMD_Reply, data.client_accesses_by_index.EOR); case RPY_MANUAL_LIST: { unsigned long ns = ntohl(r->data.manual_list.n_samples); diff --git a/reports.h b/reports.h index b124083..24881df 100644 --- a/reports.h +++ b/reports.h @@ -88,10 +88,15 @@ typedef struct { typedef struct { IPAddr ip_addr; - unsigned long ntp_hits; - unsigned long cmd_hits; - unsigned long last_ntp_hit_ago; - unsigned long last_cmd_hit_ago; + uint32_t ntp_hits; + uint32_t cmd_hits; + uint16_t ntp_drops; + uint16_t cmd_drops; + int8_t ntp_interval; + int8_t cmd_interval; + int8_t ntp_timeout_interval; + uint32_t last_ntp_hit_ago; + uint32_t last_cmd_hit_ago; } RPT_ClientAccessByIndex_Report; typedef struct {