Merge pull request #2170 from RincewindsHat/modern_output/check_ntp_peer

Modern output/check ntp peer
This commit is contained in:
Lorenz Kästle 2025-11-05 12:14:00 +01:00 committed by GitHub
commit 8062f83675
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 256 additions and 177 deletions

View file

@ -35,11 +35,14 @@
*
*****************************************************************************/
#include "thresholds.h"
const char *progname = "check_ntp_peer";
const char *copyright = "2006-2024";
const char *email = "devel@monitoring-plugins.org";
#include "output.h"
#include "perfdata.h"
#include <openssl/x509.h>
#include "thresholds.h"
#include "common.h"
#include "netutils.h"
#include "utils.h"
@ -47,8 +50,6 @@ const char *email = "devel@monitoring-plugins.org";
#include "check_ntp_peer.d/config.h"
static int verbose = 0;
static bool syncsource_found = false;
static bool li_alarm = false;
typedef struct {
int errorcode;
@ -198,9 +199,7 @@ void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_
* positive value means a success retrieving the value.
* - status is set to WARNING if there's no sync.peer (otherwise OK) and is
* the return value of the function.
* status is pretty much useless as syncsource_found is a global variable
* used later in main to check is the server was synchronized. It works
* so I left it alone */
*/
typedef struct {
mp_state_enum state;
mp_state_enum offset_result;
@ -208,6 +207,8 @@ typedef struct {
double jitter;
long stratum;
int num_truechimers;
bool syncsource_found;
bool li_alarm;
} ntp_request_result;
ntp_request_result ntp_request(const check_ntp_peer_config config) {
@ -217,6 +218,8 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
.jitter = -1,
.stratum = -1,
.num_truechimers = 0,
.syncsource_found = false,
.li_alarm = false,
};
/* Long-winded explanation:
@ -235,19 +238,16 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
* 4) Extract the offset, jitter and stratum value from the data[]
* (it's ASCII)
*/
int min_peer_sel = PEER_INCLUDED;
int num_candidates = 0;
void *tmp;
ntp_assoc_status_pair *peers = NULL;
int peer_offset = 0;
size_t peers_size = 0;
size_t npeers = 0;
int conn = -1;
my_udp_connect(config.server_address, config.port, &conn);
/* keep sending requests until the server stops setting the
* REM_MORE bit, though usually this is only 1 packet. */
ntp_control_message req;
ntp_assoc_status_pair *peers = NULL;
int peer_offset = 0;
size_t peers_size = 0;
size_t npeers = 0;
do {
setup_control_request(&req, OP_READSTAT, 1);
DBG(printf("sending READSTAT request"));
@ -269,12 +269,13 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
} while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
if (LI(req.flags) == LI_ALARM) {
li_alarm = true;
result.li_alarm = true;
}
/* Each peer identifier is 4 bytes in the data section, which
* we represent as a ntp_assoc_status_pair datatype.
*/
peers_size += ntohs(req.count);
void *tmp;
if ((tmp = realloc(peers, peers_size)) == NULL) {
free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
}
@ -287,13 +288,15 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
/* first, let's find out if we have a sync source, or if there are
* at least some candidates. In the latter case we'll issue
* a warning but go ahead with the check on them. */
int min_peer_sel = PEER_INCLUDED;
int num_candidates = 0;
for (size_t i = 0; i < npeers; i++) {
if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
result.num_truechimers++;
if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
num_candidates++;
if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
syncsource_found = true;
result.syncsource_found = true;
min_peer_sel = PEER_SYNCSOURCE;
}
}
@ -302,18 +305,18 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
if (verbose) {
printf("%d candidate peers available\n", num_candidates);
}
if (verbose && syncsource_found) {
printf("synchronization source found\n");
if (result.syncsource_found) {
printf("synchronization source found\n");
}
}
if (!syncsource_found) {
if (!result.syncsource_found) {
result.state = STATE_WARNING;
if (verbose) {
printf("warning: no synchronization source found\n");
}
}
if (li_alarm) {
if (result.li_alarm) {
result.state = STATE_WARNING;
if (verbose) {
printf("warning: LI_ALARM bit is set\n");
@ -329,7 +332,7 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
if (verbose) {
printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
}
xasprintf(&data, "");
data = strdup("");
do {
setup_control_request(&req, OP_READVAR, 2);
req.assoc = peers[i].assoc;
@ -475,16 +478,30 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
}
check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'},
{"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
{"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'},
{"swarn", required_argument, 0, 'W'}, {"scrit", required_argument, 0, 'C'},
{"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'},
{"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'},
{"timeout", required_argument, 0, 't'}, {"hostname", required_argument, 0, 'H'},
{"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
enum {
output_format_index = CHAR_MAX + 1,
};
static struct option longopts[] = {{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'},
{"use-ipv4", no_argument, 0, '4'},
{"use-ipv6", no_argument, 0, '6'},
{"quiet", no_argument, 0, 'q'},
{"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'},
{"swarn", required_argument, 0, 'W'},
{"scrit", required_argument, 0, 'C'},
{"jwarn", required_argument, 0, 'j'},
{"jcrit", required_argument, 0, 'k'},
{"twarn", required_argument, 0, 'm'},
{"tcrit", required_argument, 0, 'n'},
{"timeout", required_argument, 0, 't'},
{"hostname", required_argument, 0, 'H'},
{"port", required_argument, 0, 'p'},
{"output-format", required_argument, 0, output_format_index},
{0, 0, 0, 0}};
if (argc < 2) {
usage("\n");
@ -504,6 +521,17 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
}
switch (option_char) {
case output_format_index: {
parsed_output_format parser = mp_parse_output_format(optarg);
if (!parser.parsing_success) {
printf("Invalid output format: %s\n", optarg);
exit(STATE_UNKNOWN);
}
result.config.output_format_is_set = true;
result.config.output_format = parser.output_format;
break;
}
case 'h':
print_help();
exit(STATE_UNKNOWN);
@ -518,36 +546,84 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
case 'q':
result.config.quiet = true;
break;
case 'w':
result.config.owarn = optarg;
break;
case 'c':
result.config.ocrit = optarg;
break;
case 'W':
case 'w': {
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse warning offset threshold");
}
result.config.offset_thresholds =
mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
} break;
case 'c': {
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse critical offset threshold");
}
result.config.offset_thresholds =
mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
} break;
case 'W': {
result.config.do_stratum = true;
result.config.swarn = optarg;
break;
case 'C':
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse warning stratum threshold");
}
result.config.stratum_thresholds =
mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range);
} break;
case 'C': {
result.config.do_stratum = true;
result.config.scrit = optarg;
break;
case 'j':
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse critical stratum threshold");
}
result.config.stratum_thresholds =
mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range);
} break;
case 'j': {
result.config.do_jitter = true;
result.config.jwarn = optarg;
break;
case 'k':
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse warning jitter threshold");
}
result.config.jitter_thresholds =
mp_thresholds_set_warn(result.config.jitter_thresholds, tmp.range);
} break;
case 'k': {
result.config.do_jitter = true;
result.config.jcrit = optarg;
break;
case 'm':
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse critical jitter threshold");
}
result.config.jitter_thresholds =
mp_thresholds_set_crit(result.config.jitter_thresholds, tmp.range);
} break;
case 'm': {
result.config.do_truechimers = true;
result.config.twarn = optarg;
break;
case 'n':
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse warning truechimer threshold");
}
result.config.truechimer_thresholds =
mp_thresholds_set_warn(result.config.truechimer_thresholds, tmp.range);
} break;
case 'n': {
result.config.do_truechimers = true;
result.config.tcrit = optarg;
break;
mp_range_parsed tmp = mp_parse_range_string(optarg);
if (tmp.error != MP_PARSING_SUCCES) {
die(STATE_UNKNOWN, "failed to parse critical truechimer threshold");
}
result.config.truechimer_thresholds =
mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range);
} break;
case 'H':
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
@ -581,11 +657,6 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
usage4(_("Hostname was not supplied"));
}
set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
return result;
}
@ -627,6 +698,10 @@ int main(int argc, char *argv[]) {
const check_ntp_peer_config config = tmp_config.config;
if (config.output_format_is_set) {
mp_set_format(config.output_format);
}
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -634,125 +709,113 @@ int main(int argc, char *argv[]) {
alarm(socket_timeout);
/* This returns either OK or WARNING (See comment preceding ntp_request) */
ntp_request_result ntp_res = ntp_request(config);
mp_state_enum result = STATE_UNKNOWN;
const ntp_request_result ntp_res = ntp_request(config);
mp_check overall = mp_check_init();
mp_subcheck sc_offset = mp_subcheck_init();
xasprintf(&sc_offset.output, "offset");
if (ntp_res.offset_result == STATE_UNKNOWN) {
/* if there's no sync peer (this overrides ntp_request output): */
result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
sc_offset =
mp_set_subcheck_state(sc_offset, (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL));
xasprintf(&sc_offset.output, "%s unknown", sc_offset.output);
} else {
/* Be quiet if there's no candidates either */
if (config.quiet && result == STATE_WARNING) {
result = STATE_UNKNOWN;
mp_state_enum tmp = STATE_OK;
if (config.quiet && ntp_res.state == STATE_WARNING) {
tmp = STATE_UNKNOWN;
}
result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
xasprintf(&sc_offset.output, "%s: %.6fs", sc_offset.output, ntp_res.offset);
mp_perfdata pd_offset = perfdata_init();
pd_offset.value = mp_create_pd_value(fabs(ntp_res.offset));
pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
pd_offset.label = "offset";
pd_offset.uom = "s";
mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
tmp = max_state_alt(tmp, mp_get_pd_status(pd_offset));
sc_offset = mp_set_subcheck_state(sc_offset, tmp);
}
mp_state_enum oresult = result;
mp_state_enum tresult = STATE_UNKNOWN;
mp_add_subcheck_to_check(&overall, sc_offset);
// truechimers
if (config.do_truechimers) {
tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
result = max_state_alt(result, tresult);
}
mp_subcheck sc_truechimers = mp_subcheck_init();
xasprintf(&sc_truechimers.output, "truechimers: %i", ntp_res.num_truechimers);
mp_state_enum sresult = STATE_UNKNOWN;
mp_perfdata pd_truechimers = perfdata_init();
pd_truechimers.value = mp_create_pd_value(ntp_res.num_truechimers);
pd_truechimers.label = "truechimers";
pd_truechimers = mp_pd_set_thresholds(pd_truechimers, config.truechimer_thresholds);
if (config.do_stratum) {
sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
result = max_state_alt(result, sresult);
}
mp_add_perfdata_to_subcheck(&sc_truechimers, pd_truechimers);
mp_state_enum jresult = STATE_UNKNOWN;
sc_truechimers = mp_set_subcheck_state(sc_truechimers, mp_get_pd_status(pd_truechimers));
if (config.do_jitter) {
jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
result = max_state_alt(result, jresult);
}
char *result_line;
switch (result) {
case STATE_CRITICAL:
xasprintf(&result_line, _("NTP CRITICAL:"));
break;
case STATE_WARNING:
xasprintf(&result_line, _("NTP WARNING:"));
break;
case STATE_OK:
xasprintf(&result_line, _("NTP OK:"));
break;
default:
xasprintf(&result_line, _("NTP UNKNOWN:"));
break;
}
if (!syncsource_found) {
xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
} else if (li_alarm) {
xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
}
char *perfdata_line;
if (ntp_res.offset_result == STATE_UNKNOWN) {
xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
xasprintf(&perfdata_line, "");
} else if (oresult == STATE_WARNING) {
xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"),
ntp_res.offset);
} else if (oresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"),
ntp_res.offset);
} else {
xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
}
xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
if (config.do_jitter) {
if (jresult == STATE_WARNING) {
xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
} else if (jresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
} else {
xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line,
perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
mp_add_subcheck_to_check(&overall, sc_truechimers);
}
if (config.do_stratum) {
if (sresult == STATE_WARNING) {
xasprintf(&result_line, "%s, stratum=%li (WARNING)", result_line, ntp_res.stratum);
} else if (sresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, stratum=%li (CRITICAL)", result_line, ntp_res.stratum);
} else {
xasprintf(&result_line, "%s, stratum=%li", result_line, ntp_res.stratum);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line,
perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
mp_subcheck sc_stratum = mp_subcheck_init();
xasprintf(&sc_stratum.output, "stratum: %li", ntp_res.stratum);
mp_perfdata pd_stratum = perfdata_init();
pd_stratum.value = mp_create_pd_value(ntp_res.stratum);
pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds);
pd_stratum.label = "stratum";
mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum);
sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum));
mp_add_subcheck_to_check(&overall, sc_stratum);
}
if (config.do_truechimers) {
if (tresult == STATE_WARNING) {
xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line,
ntp_res.num_truechimers);
} else if (tresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line,
ntp_res.num_truechimers);
} else {
xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line,
perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers,
config.truechimer_thresholds));
if (config.do_jitter) {
mp_subcheck sc_jitter = mp_subcheck_init();
xasprintf(&sc_jitter.output, "jitter: %f", ntp_res.jitter);
mp_perfdata pd_jitter = perfdata_init();
pd_jitter.value = mp_create_pd_value(ntp_res.jitter);
pd_jitter = mp_pd_set_thresholds(pd_jitter, config.jitter_thresholds);
pd_jitter.label = "jitter";
mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
sc_jitter = mp_set_subcheck_state(sc_jitter, mp_get_pd_status(pd_jitter));
mp_add_subcheck_to_check(&overall, sc_jitter);
}
printf("%s|%s\n", result_line, perfdata_line);
mp_subcheck sc_other_info = mp_subcheck_init();
sc_other_info = mp_set_subcheck_default_state(sc_other_info, STATE_OK);
if (!ntp_res.syncsource_found) {
xasprintf(&sc_other_info.output, "%s", _("Server not synchronized"));
mp_add_subcheck_to_check(&overall, sc_other_info);
} else if (ntp_res.li_alarm) {
xasprintf(&sc_other_info.output, "%s", _("Server has the LI_ALARM bit set"));
mp_add_subcheck_to_check(&overall, sc_other_info);
}
{
mp_subcheck sc_offset = mp_subcheck_init();
sc_offset = mp_set_subcheck_default_state(sc_offset, STATE_OK);
xasprintf(&sc_offset.output, "offset: %.10gs", ntp_res.offset);
mp_perfdata pd_offset = perfdata_init();
pd_offset.value = mp_create_pd_value(ntp_res.offset);
pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
sc_offset = mp_set_subcheck_state(sc_offset, ntp_res.offset_result);
}
if (config.server_address != NULL) {
free(config.server_address);
}
exit(result);
mp_exit(overall);
}
void print_help(void) {
@ -791,6 +854,7 @@ void print_help(void) {
printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf(UT_VERBOSE);
printf(UT_OUTPUT_FORMAT);
printf("\n");
printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));

View file

@ -1,6 +1,8 @@
#pragma once
#include "../../config.h"
#include "output.h"
#include "perfdata.h"
#include "thresholds.h"
#include <stddef.h>
@ -16,26 +18,21 @@ typedef struct {
// truechimer stuff
bool do_truechimers;
char *twarn;
char *tcrit;
thresholds *truechimer_thresholds;
mp_thresholds truechimer_thresholds;
char *owarn;
char *ocrit;
thresholds *offset_thresholds;
// offset thresholds
mp_thresholds offset_thresholds;
// stratum stuff
bool do_stratum;
char *swarn;
char *scrit;
thresholds *stratum_thresholds;
mp_thresholds stratum_thresholds;
// jitter stuff
bool do_jitter;
char *jwarn;
char *jcrit;
thresholds *jitter_thresholds;
mp_thresholds jitter_thresholds;
bool output_format_is_set;
mp_output_format output_format;
} check_ntp_peer_config;
check_ntp_peer_config check_ntp_peer_config_init() {
@ -45,23 +42,41 @@ check_ntp_peer_config check_ntp_peer_config_init() {
.quiet = false,
.do_truechimers = false,
.twarn = "0:",
.tcrit = "0:",
.truechimer_thresholds = NULL,
.truechimer_thresholds = mp_thresholds_init(),
.owarn = "60",
.ocrit = "120",
.offset_thresholds = NULL,
.offset_thresholds = mp_thresholds_init(),
.do_stratum = false,
.swarn = "-1:16",
.scrit = "-1:16",
.stratum_thresholds = NULL,
.stratum_thresholds = mp_thresholds_init(),
.do_jitter = false,
.jwarn = "-1:5000",
.jcrit = "-1:10000",
.jitter_thresholds = NULL,
.jitter_thresholds = mp_thresholds_init(),
.output_format_is_set = false,
};
mp_range stratum_default = mp_range_init();
stratum_default = mp_range_set_start(stratum_default, mp_create_pd_value(-1));
stratum_default = mp_range_set_end(stratum_default, mp_create_pd_value(16));
tmp.stratum_thresholds = mp_thresholds_set_warn(tmp.stratum_thresholds, stratum_default);
tmp.stratum_thresholds = mp_thresholds_set_crit(tmp.stratum_thresholds, stratum_default);
mp_range jitter_w_default = mp_range_init();
jitter_w_default = mp_range_set_start(jitter_w_default, mp_create_pd_value(-1));
jitter_w_default = mp_range_set_end(jitter_w_default, mp_create_pd_value(5000));
tmp.jitter_thresholds = mp_thresholds_set_warn(tmp.jitter_thresholds, jitter_w_default);
mp_range jitter_c_default = mp_range_init();
jitter_c_default = mp_range_set_start(jitter_c_default, mp_create_pd_value(-1));
jitter_c_default = mp_range_set_end(jitter_c_default, mp_create_pd_value(10000));
tmp.jitter_thresholds = mp_thresholds_set_crit(tmp.jitter_thresholds, jitter_c_default);
mp_range offset_w_default = mp_range_init();
offset_w_default = mp_range_set_end(offset_w_default, mp_create_pd_value(60));
tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, offset_w_default);
mp_range offset_c_default = mp_range_init();
offset_c_default = mp_range_set_end(offset_c_default, mp_create_pd_value(120));
tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, offset_c_default);
return tmp;
}