]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
cmdmon: add offset command
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 Mar 2024 15:20:27 +0000 (16:20 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 7 Mar 2024 15:20:27 +0000 (16:20 +0100)
Add a new command to modify the offset option of NTP sources and
reference clocks.

candm.h
client.c
cmdmon.c
doc/chronyc.adoc
pktlength.c
test/simulation/110-chronyc
test/system/007-cmdmon

diff --git a/candm.h b/candm.h
index 65daedfcfce86446f1581328b97413c3569efc3a..0894ad573cb8567ea2e6f51c3ceb042a7e0f4355 100644 (file)
--- a/candm.h
+++ b/candm.h
 #define REQ_RELOAD_SOURCES 70
 #define REQ_DOFFSET2 71
 #define REQ_MODIFY_SELECTOPTS 72
-#define N_REQUEST_TYPES 73
+#define REQ_MODIFY_OFFSET 73
+#define N_REQUEST_TYPES 74
 
 /* Structure used to exchange timespecs independent of time_t size */
 typedef struct {
@@ -390,6 +391,13 @@ typedef struct {
   int32_t EOR;
 } REQ_Modify_SelectOpts;
 
+typedef struct {
+  IPAddr address;
+  uint32_t ref_id;
+  Float new_offset;
+  int32_t EOR;
+} REQ_Modify_Offset;
+
 /* ================================================== */
 
 #define PKT_TYPE_CMD_REQUEST 1
@@ -497,6 +505,7 @@ typedef struct {
     REQ_AuthData auth_data;
     REQ_SelectData select_data;
     REQ_Modify_SelectOpts modify_select_opts;
+    REQ_Modify_Offset modify_offset;
   } data; /* Command specific parameters */
 
   /* Padding used to prevent traffic amplification.  It only defines the
index 5ead2b0aa1528c255dd6691782540ba97f80e000..0231b9e925932c6f9ba6c0567d724fc9a6145ecb 100644 (file)
--- a/client.c
+++ b/client.c
@@ -344,6 +344,24 @@ parse_source_address(char *word, IPAddr *address)
 
 /* ================================================== */
 
+static int
+parse_source_address_or_refid(char *s, IPAddr *address, uint32_t *ref_id)
+{
+  address->family = IPADDR_UNSPEC;
+  *ref_id = 0;
+
+  /* Don't allow hostnames to avoid conflicts with reference IDs */
+  if (UTI_StringToIdIP(s, address) || UTI_StringToIP(s, address))
+    return 1;
+
+  if (CPS_ParseRefid(s, ref_id) > 0)
+    return 1;
+
+  return 0;
+}
+
+/* ================================================== */
+
 static int
 read_mask_address(char *line, IPAddr *mask, IPAddr *address)
 {
@@ -1031,6 +1049,7 @@ give_help(void)
     "selectopts <address|refid> <+|-options>\0Modify selection options\0"
     "reselect\0Force reselecting synchronisation source\0"
     "reselectdist <dist>\0Modify reselection distance\0"
+    "offset <address|refid> <offset>\0Modify offset correction\0"
     "\0\0"
     "NTP sources:\0\0"
     "activity\0Check how many NTP sources are online/offline\0"
@@ -1141,7 +1160,8 @@ command_name_generator(const char *text, int state)
     "clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete",
     "deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep",
     "manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
-    "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline",
+    "maxupdateskew", "minpoll", "minstratum", "ntpdata",
+    "offline", "offset", "online", "onoffline",
     "polltarget", "quit", "refresh", "rekey", "reload", "reselect", "reselectdist", "reset",
     "retries", "rtcdata", "selectdata", "selectopts", "serverstats", "settime",
     "shutdown", "smoothing", "smoothtime", "sourcename", "sources", "sourcestats",
@@ -2858,6 +2878,34 @@ process_cmd_activity(const char *line)
 
 /* ================================================== */
 
+static int
+process_cmd_offset(CMD_Request *msg, char *line)
+{
+  uint32_t ref_id;
+  IPAddr ip_addr;
+  double offset;
+  char *src;
+
+  src = line;
+  line = CPS_SplitWord(line);
+
+  if (!parse_source_address_or_refid(src, &ip_addr, &ref_id) ||
+      sscanf(line, "%lf", &offset) != 1) {
+    LOG(LOGS_ERR, "Invalid syntax for offset command");
+    return 0;
+  }
+
+  UTI_IPHostToNetwork(&ip_addr, &msg->data.modify_offset.address);
+  msg->data.modify_offset.ref_id = htonl(ref_id);
+  msg->data.modify_offset.new_offset = UTI_FloatHostToNetwork(offset);
+
+  msg->command = htons(REQ_MODIFY_OFFSET);
+
+  return 1;
+}
+
+/* ================================================== */
+
 static int
 process_cmd_reselectdist(CMD_Request *msg, char *line)
 {
@@ -2939,15 +2987,10 @@ process_cmd_selectopts(CMD_Request *msg, char *line)
 
   src = line;
   line = CPS_SplitWord(line);
-  ref_id = 0;
 
-  /* Don't allow hostnames to avoid conflicts with reference IDs */
-  if (!UTI_StringToIdIP(src, &ip_addr) && !UTI_StringToIP(src, &ip_addr)) {
-    ip_addr.family = IPADDR_UNSPEC;
-    if (CPS_ParseRefid(src, &ref_id) == 0) {
-      LOG(LOGS_ERR, "Invalid syntax for selectopts command");
-      return 0;
-    }
+  if (!parse_source_address_or_refid(src, &ip_addr, &ref_id)) {
+    LOG(LOGS_ERR, "Invalid syntax for selectopts command");
+    return 0;
   }
 
   mask = options = 0;
@@ -3249,6 +3292,8 @@ process_line(char *line)
     ret = process_cmd_ntpdata(line);
   } else if (!strcmp(command, "offline")) {
     do_normal_submit = process_cmd_offline(&tx_message, line);
+  } else if (!strcmp(command, "offset")) {
+    do_normal_submit = process_cmd_offset(&tx_message, line);
   } else if (!strcmp(command, "online")) {
     do_normal_submit = process_cmd_online(&tx_message, line);
   } else if (!strcmp(command, "onoffline")) {
index 0a0193b1d79ef5828c44b0597fd55a836fb51534..716775f6f348c90e63474573cf3105f2b788cb93 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -145,6 +145,7 @@ static const char permissions[] = {
   PERMIT_AUTH, /* RELOAD_SOURCES */
   PERMIT_AUTH, /* DOFFSET2 */
   PERMIT_AUTH, /* MODIFY_SELECTOPTS */
+  PERMIT_AUTH, /* MODIFY_OFFSET */
 };
 
 /* ================================================== */
@@ -1418,6 +1419,24 @@ handle_modify_selectopts(CMD_Request *rx_message, CMD_Reply *tx_message)
     tx_message->status = htons(STT_NOSUCHSOURCE);
 }
 
+/* ================================================== */
+
+static void
+handle_modify_offset(CMD_Request *rx_message, CMD_Reply *tx_message)
+{
+  uint32_t ref_id;
+  IPAddr ip_addr;
+  double offset;
+
+  UTI_IPNetworkToHost(&rx_message->data.modify_offset.address, &ip_addr);
+  ref_id = ntohl(rx_message->data.modify_offset.ref_id);
+  offset = UTI_FloatNetworkToHost(rx_message->data.modify_offset.new_offset);
+
+  if ((ip_addr.family != IPADDR_UNSPEC && !NSR_ModifyOffset(&ip_addr, offset)) ||
+      (ip_addr.family == IPADDR_UNSPEC && !RCL_ModifyOffset(ref_id, offset)))
+    tx_message->status = htons(STT_NOSUCHSOURCE);
+}
+
 /* ================================================== */
 /* Read a packet and process it */
 
@@ -1818,6 +1837,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
           handle_modify_selectopts(&rx_message, &tx_message);
           break;
 
+        case REQ_MODIFY_OFFSET:
+          handle_modify_offset(&rx_message, &tx_message);
+          break;
+
         default:
           DEBUG_LOG("Unhandled command %d", rx_command);
           tx_message.status = htons(STT_FAILED);
index 8e0d426e56eb62d2a7156321d9f8eaee1eafc3fe..1386e002a91ea16e066433c9c26165dd6e1e8a0b 100644 (file)
@@ -556,6 +556,13 @@ The *reselectdist* command sets the reselection distance. It is equivalent to
 the <<chrony.conf.adoc#reselectdist,*reselectdist*>> directive in the
 configuration file.
 
+[[offset]]*offset* _address|refid_ _offset_::
+The *offset* command modifies the offset correction of an NTP source specified
+by IP address (or the _ID#XXXXXXXXXX_ identifier used for unknown addresses),
+or a reference clock specified by reference ID as a string. It is equivalent to
+the *offset* option in the <<chrony.conf.adoc#server,*server*>> or
+<<chrony.conf.adoc#refclock,*refclock*>> directive respectively.
+
 === NTP sources
 
 [[activity]]*activity*::
index 3e0b319d209ce7498a8c2c71a07cff6d5f5e285d..3cca306834fd76a47ec67e94efc12151bed3f535 100644 (file)
@@ -130,6 +130,7 @@ static const struct request_length request_lengths[] = {
   REQ_LENGTH_ENTRY(null, null),                 /* RELOAD_SOURCES */
   REQ_LENGTH_ENTRY(doffset, null),              /* DOFFSET2 */
   REQ_LENGTH_ENTRY(modify_select_opts, null),   /* MODIFY_SELECTOPTS */
+  REQ_LENGTH_ENTRY(modify_offset, null),        /* MODIFY_OFFSET */
 };
 
 static const uint16_t reply_lengths[] = {
index a261e7a0a9a18001c3fe4d40921f00dab7541db3..a4f486a1520529a0e6aa3b3f15a3e3d2e2ca42f0 100755 (executable)
@@ -165,6 +165,7 @@ for chronyc_conf in \
        "offline" \
        "offline 255.255.255.0/1.2.3.0" \
        "offline 1.2.3.0/24" \
+       "offset 1.2.3.4 1.0" \
        "online" \
        "online 1.2.3.0/24" \
        "onoffline" \
@@ -351,6 +352,7 @@ maxpoll 192.168.123.1 5
 maxupdateskew 192.168.123.1 10.0
 minpoll 192.168.123.1 3
 minstratum 192.168.123.1 1
+offset 192.168.123.1 -1.0
 polltarget 192.168.123.1 10
 selectopts 192.168.123.1 +trust +prefer -require
 selectdata
@@ -375,6 +377,7 @@ check_chronyc_output "^200 OK
 200 OK
 200 OK
 200 OK
+200 OK
 S Name/IP Address        Auth COpts EOpts Last Score     Interval  Leap
 =======================================================================
 M node1\.net1\.clk            N \-PT\-\- \-PT\-\-    0   1\.0    \+0ns    \+0ns  \?
index 859950324e930a7fc44c17edb268a605fdd17474..953b4f356137a21e41f3f792e61ce653db8be0e0 100755 (executable)
@@ -28,6 +28,7 @@ for command in \
        "local" \
        "online" \
        "onoffline" \
+       "offset $server 0.0" \
        "maxdelay $server 1e-1" \
        "maxdelaydevratio $server 5.0" \
        "maxdelayratio $server 3.0" \