diff --git a/candm.h b/candm.h index 3071828..e742323 100644 --- a/candm.h +++ b/candm.h @@ -109,7 +109,8 @@ #define REQ_SELECT_DATA 69 #define REQ_RELOAD_SOURCES 70 #define REQ_DOFFSET2 71 -#define N_REQUEST_TYPES 72 +#define REQ_MODIFY_SELECTOPTS 72 +#define N_REQUEST_TYPES 73 /* Structure used to exchange timespecs independent of time_t size */ typedef struct { @@ -371,6 +372,15 @@ typedef struct { int32_t EOR; } REQ_SelectData; +/* Mask and options reuse the REQ_ADDSRC flags */ +typedef struct { + IPAddr address; + uint32_t ref_id; + uint32_t mask; + uint32_t options; + int32_t EOR; +} REQ_Modify_SelectOpts; + /* ================================================== */ #define PKT_TYPE_CMD_REQUEST 1 @@ -477,6 +487,7 @@ typedef struct { REQ_NTPSourceName ntp_source_name; REQ_AuthData auth_data; REQ_SelectData select_data; + REQ_Modify_SelectOpts modify_select_opts; } data; /* Command specific parameters */ /* Padding used to prevent traffic amplification. It only defines the diff --git a/client.c b/client.c index e15747d..ad731b0 100644 --- a/client.c +++ b/client.c @@ -1021,6 +1021,7 @@ give_help(void) "sources [-a] [-v]\0Display information about current sources\0" "sourcestats [-a] [-v]\0Display statistics about collected measurements\0" "selectdata [-a] [-v]\0Display information about source selection\0" + "selectopts <+|-options>\0Modify selection options\0" "reselect\0Force reselecting synchronisation source\0" "reselectdist \0Modify reselection distance\0" "\0\0" @@ -1135,8 +1136,8 @@ command_name_generator(const char *text, int state) "manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll", "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline", "polltarget", "quit", "refresh", "rekey", "reload", "reselect", "reselectdist", "reset", - "retries", "rtcdata", "selectdata", "serverstats", "settime", "shutdown", "smoothing", - "smoothtime", "sourcename", "sources", "sourcestats", + "retries", "rtcdata", "selectdata", "selectopts", "serverstats", "settime", + "shutdown", "smoothing", "smoothtime", "sourcename", "sources", "sourcestats", "timeout", "tracking", "trimrtc", "waitsync", "writertc", NULL }; @@ -2899,6 +2900,55 @@ process_cmd_reset(CMD_Request *msg, char *line) /* ================================================== */ +static int +process_cmd_selectopts(CMD_Request *msg, char *line) +{ + int mask, options, option; + uint32_t ref_id; + IPAddr ip_addr; + char *src, *opt; + + 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; + } + } + + mask = options = 0; + + while (*line != '\0') { + opt = line; + line = CPS_SplitWord(line); + + if ((opt[0] != '+' && opt[0] != '-') || (option = CPS_GetSelectOption(opt + 1)) == 0) { + LOG(LOGS_ERR, "Invalid syntax for selectopts command"); + return 0; + } + + mask |= option; + if (opt[0] == '+') + options |= option; + } + + UTI_IPHostToNetwork(&ip_addr, &msg->data.modify_select_opts.address); + msg->data.modify_select_opts.ref_id = htonl(ref_id); + msg->data.modify_select_opts.mask = htonl(mask); + msg->data.modify_select_opts.options = htonl(convert_addsrc_sel_options(options)); + + msg->command = htons(REQ_MODIFY_SELECTOPTS); + + return 1; +} + +/* ================================================== */ + static int process_cmd_waitsync(char *line) { @@ -3201,6 +3251,8 @@ process_line(char *line) } else if (!strcmp(command, "selectdata")) { do_normal_submit = 0; ret = process_cmd_selectdata(line); + } else if (!strcmp(command, "selectopts")) { + do_normal_submit = process_cmd_selectopts(&tx_message, line); } else if (!strcmp(command, "serverstats")) { do_normal_submit = 0; ret = process_cmd_serverstats(line); diff --git a/cmdmon.c b/cmdmon.c index d513cab..cdb1d86 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -144,6 +144,7 @@ static const char permissions[] = { PERMIT_AUTH, /* SELECT_DATA */ PERMIT_AUTH, /* RELOAD_SOURCES */ PERMIT_AUTH, /* DOFFSET2 */ + PERMIT_AUTH, /* MODIFY_SELECTOPTS */ }; /* ================================================== */ @@ -1370,6 +1371,24 @@ handle_select_data(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.select_data.lo_limit = UTI_FloatHostToNetwork(report.lo_limit); } +/* ================================================== */ + +static void +handle_modify_selectopts(CMD_Request *rx_message, CMD_Reply *tx_message) +{ + int mask, options; + uint32_t ref_id; + IPAddr ip_addr; + + UTI_IPNetworkToHost(&rx_message->data.modify_select_opts.address, &ip_addr); + ref_id = ntohl(rx_message->data.modify_select_opts.ref_id); + mask = ntohl(rx_message->data.modify_select_opts.mask); + options = convert_addsrc_select_options(ntohl(rx_message->data.modify_select_opts.options)); + + if (!SRC_ModifySelectOptions(&ip_addr, ref_id, options, mask)) + tx_message->status = htons(STT_NOSUCHSOURCE); +} + /* ================================================== */ /* Read a packet and process it */ @@ -1766,6 +1785,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything) handle_reload_sources(&rx_message, &tx_message); break; + case REQ_MODIFY_SELECTOPTS: + handle_modify_selectopts(&rx_message, &tx_message); + break; + default: DEBUG_LOG("Unhandled command %d", rx_command); tx_message.status = htons(STT_FAILED); diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc index 57300ee..ca261c7 100644 --- a/doc/chronyc.adoc +++ b/doc/chronyc.adoc @@ -522,6 +522,23 @@ This column displays the current leap status of the source. * _-_ indicates that a leap second will be deleted at the end of the month. * _?_ indicates the unknown status (i.e. no valid measurement was made). +[[selectopts]]*selectopts* _address|refid_ [_+|-option_]...:: +The *selectopts* command modifies the configured selection options 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. ++ +The selection options can be added with the *+* symbol or removed with the *-* +symbol. The *selectdata* command can be used to verify the configuration. The +modified options will be applied in the next source selection, e.g. when a new +measurement is made, or the *reselect* command is executed. ++ +An example of using this command is shown below. ++ +---- +selectopts 1.2.3.4 -noselect +prefer +selectopts GPS +trust +---- + [[reselect]]*reselect*:: To avoid excessive switching between sources, *chronyd* can stay synchronised to a source even when it is not currently the best one among the available diff --git a/pktlength.c b/pktlength.c index 642e477..263b16d 100644 --- a/pktlength.c +++ b/pktlength.c @@ -129,6 +129,7 @@ static const struct request_length request_lengths[] = { REQ_LENGTH_ENTRY(select_data, select_data), /* SELECT_DATA */ REQ_LENGTH_ENTRY(null, null), /* RELOAD_SOURCES */ REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET2 */ + REQ_LENGTH_ENTRY(modify_select_opts, null), /* MODIFY_SELECTOPTS */ }; static const uint16_t reply_lengths[] = { diff --git a/test/simulation/110-chronyc b/test/simulation/110-chronyc index b78f0d8..7ecfcb5 100755 --- a/test/simulation/110-chronyc +++ b/test/simulation/110-chronyc @@ -164,6 +164,9 @@ for chronyc_conf in \ "reselectdist 1e-3" \ "reset sources" \ "selectdata" \ + "selectopts 1.2.3.4 -noselect +trust +require +prefer" \ + "selectopts ID#0000000001 +prefer" \ + "selectopts PPS0 +prefer" \ "settime 16:30" \ "settime 16:30:05" \ "settime Nov 21, 2015 16:30:05" \ @@ -327,6 +330,8 @@ maxupdateskew 192.168.123.1 10.0 minpoll 192.168.123.1 3 minstratum 192.168.123.1 1 polltarget 192.168.123.1 10 +selectopts 192.168.123.1 +trust +prefer -require +selectdata delete 192.168.123.1" run_test || test_fail @@ -345,6 +350,10 @@ 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 \? 200 OK$" || test_fail chronyc_conf=" diff --git a/test/system/007-cmdmon b/test/system/007-cmdmon index 04d14c2..301d01c 100755 --- a/test/system/007-cmdmon +++ b/test/system/007-cmdmon @@ -42,6 +42,7 @@ for command in \ "reselect" \ "reselectdist 1e-3" \ "reset sources" \ + "selectopts $server -noselect +trust +prefer +require" \ "smoothtime reset" \ "smoothtime activate" \ ; do @@ -101,7 +102,7 @@ Total good RX : [0-9]+$" || test_fail run_chronyc "selectdata" || test_fail check_chronyc_output "^S Name/IP Address Auth COpts EOpts Last Score Interval Leap ======================================================================= -s 127\.0\.0\.1 N ----- ----- 0 1\.0 \+0ns \+0ns \?$" || test_fail +s 127\.0\.0\.1 N -PTR- -PTR- 0 1\.0 \+0ns \+0ns \?$" || test_fail run_chronyc "serverstats" || test_fail check_chronyc_output "^NTP packets received : [0-9]+