From 3ea412d77f41fb0e1c5aaa7edfcaad242e271475 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Wed, 21 Aug 2024 18:20:26 +0100 Subject: [PATCH 1/2] all: ensure pidfile is created if a reload causes child to start Signed-off-by: Quentin Armitage --- doc/man/man5/keepalived.conf.5.in | 9 +++- keepalived/check/check_api.c | 13 ++--- keepalived/check/check_bfd.c | 20 +++---- keepalived/check/check_daemon.c | 24 +++++++++ keepalived/check/check_dns.c | 32 +++++------ keepalived/check/check_file.c | 17 ++++-- keepalived/check/check_genhash.c | 6 +-- keepalived/check/check_http.c | 50 +++++++++--------- keepalived/check/check_misc.c | 39 +++++++------- keepalived/check/check_parser.c | 6 +++ keepalived/check/check_ping.c | 20 +++---- keepalived/check/check_smtp.c | 52 +++++++++--------- keepalived/check/check_ssl.c | 4 +- keepalived/check/check_tcp.c | 4 +- keepalived/check/check_udp.c | 29 +++++----- keepalived/check/ipwrapper.c | 88 +++++++++++++++++++++++++++---- keepalived/core/pidfile.c | 8 ++- keepalived/include/check_api.h | 36 +++++++++++-- keepalived/include/check_bfd.h | 2 +- keepalived/include/check_http.h | 2 +- keepalived/include/check_misc.h | 2 +- keepalived/include/check_ping.h | 2 +- keepalived/include/check_smtp.h | 3 +- keepalived/include/ipwrapper.h | 1 + lib/parser.c | 13 ++++- 25 files changed, 323 insertions(+), 159 deletions(-) diff --git a/doc/man/man5/keepalived.conf.5.in b/doc/man/man5/keepalived.conf.5.in index 62830a4848..dc9652a43c 100644 --- a/doc/man/man5/keepalived.conf.5.in +++ b/doc/man/man5/keepalived.conf.5.in @@ -1098,7 +1098,7 @@ sync group or real server monitors it. A value will be read as a number in text from the file. If the weight configured against the track_file is 0, a non-zero value in the file will be treated as a failure status, and a zero value will be treated as -an OK status, otherwise the value will be multiplied by the weight configured +an OK status, otherwise the value will be multiplied by the weight configured in the track_file statement. For VRRP instances, if the result is less than -253 anything monitoring the @@ -2334,6 +2334,11 @@ The syntax for virtual_server is : # Minimum total weight of all live servers in # the pool necessary to operate VS with no # quality regression. Defaults to 1. + # If a sorry server is configured and the quorum + # is not met, any remaining alive real servers will + # be taken down and the sorry server enabled. + # If there is no sorry server, the remaining alive + # real servers will not be modified. \fBquorum \fR # Tolerate this much weight units compared to the @@ -2984,7 +2989,7 @@ There can be multiple ~SEQ elements on a line, so for example: .SH List blocks .PP List blocks are similar to sequence blocks, except that the values to substitute into -the variable are listed in the ~LST specification. +the variable(s) are listed in the ~LST specification. A line starting \fB~LST(var, val1, val2, val3)\fR will cause the remainder of the line to be processed multiple times, with the variable \fB$var\fR set initially to diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c index 4eda626a21..054a523932 100644 --- a/keepalived/check/check_api.c +++ b/keepalived/check/check_api.c @@ -120,9 +120,10 @@ dump_connection_opts(FILE *fp, const void *data) /* Queue a checker into the real server's checkers_queue */ void -queue_checker(const checker_funcs_t *funcs +queue_checker(real_server_t *rs + , const checker_funcs_t *funcs , thread_func_t launch - , void *data + , checker_details_t checker_details , conn_opts_t *co , bool fd_required) { @@ -130,7 +131,7 @@ queue_checker(const checker_funcs_t *funcs /* Set default dst = RS, timeout = default */ if (co) { - co->dst = current_rs->addr; + co->dst = rs->addr; co->connection_to = UINT_MAX; } @@ -139,8 +140,8 @@ queue_checker(const checker_funcs_t *funcs checker->checker_funcs = funcs; checker->launch = launch; checker->vs = current_vs; - checker->rs = current_rs; - checker->data = data; + checker->rs = rs; + checker->check_type = checker_details; checker->co = co; checker->enabled = true; checker->alpha = -1; @@ -156,7 +157,7 @@ queue_checker(const checker_funcs_t *funcs if (fd_required) check_data->num_checker_fd_required++; - list_add_tail(&checker->rs_list, ¤t_rs->checkers_list); + list_add_tail(&checker->rs_list, &rs->checkers_list); current_checker = checker; } diff --git a/keepalived/check/check_bfd.c b/keepalived/check/check_bfd.c index 46a4beb410..b114e9d25d 100644 --- a/keepalived/check/check_bfd.c +++ b/keepalived/check/check_bfd.c @@ -54,7 +54,7 @@ static void bfd_check_thread(thread_ref_t); static void free_bfd_check(checker_t *checker) { - bfd_checker_t *bfd_checker = checker->data; + bfd_checker_t *bfd_checker = checker->check_type.bfd_check; FREE(bfd_checker); FREE(checker); @@ -63,7 +63,7 @@ free_bfd_check(checker_t *checker) static void dump_bfd_check(FILE *fp, const checker_t *checker) { - const bfd_checker_t *bfd_checker = checker->data; + const bfd_checker_t *bfd_checker = checker->check_type.bfd_check; conf_write(fp, " Keepalive method = BFD_CHECK"); conf_write(fp, " Name = %s", bfd_checker->bfd->bname); @@ -108,8 +108,8 @@ dump_bfds_rs_list(FILE *fp, const list_head_t *l) static bool compare_bfd_check(const checker_t *old_c, checker_t *new_c) { - const bfd_checker_t *old = old_c->data; - const bfd_checker_t *new = new_c->data; + const bfd_checker_t *old = old_c->check_type.bfd_check; + const bfd_checker_t *new = new_c->check_type.bfd_check; if (strcmp(old->bfd->bname, new->bfd->bname)) return false; @@ -135,13 +135,13 @@ static const checker_funcs_t bfd_checker_funcs = { CHECKER_BFD, free_bfd_check, static void bfd_check_handler(__attribute__((unused)) const vector_t *strvec) { - bfd_checker_t *new_bfd_checker; + checker_details_t checker_details; - PMALLOC(new_bfd_checker); - INIT_LIST_HEAD(&new_bfd_checker->e_list); + PMALLOC(checker_details.bfd_check); + INIT_LIST_HEAD(&checker_details.bfd_check->e_list); /* queue new checker */ - queue_checker(&bfd_checker_funcs, NULL, new_bfd_checker, NULL, false); + queue_checker(current_rs, &bfd_checker_funcs, NULL, checker_details, NULL, false); } static void @@ -153,7 +153,7 @@ bfd_name_handler(const vector_t *strvec) bool config_error = true; char *name; - bfdc = current_checker->data; + bfdc = current_checker->check_type.bfd_check; if (vector_size(strvec) >= 2) name = vector_slot(strvec, 1); @@ -224,7 +224,7 @@ bfd_end_handler(void) tracking_obj_t *top; cref_tracked_bfd_t *tbfd; - bfdc = current_checker->data; + bfdc = current_checker->check_type.bfd_check; if (!bfdc->bfd) { report_config_error(CONFIG_GENERAL_ERROR, "(%s) No name has been specified for BFD_CHECKER - skipping" diff --git a/keepalived/check/check_daemon.c b/keepalived/check/check_daemon.c index d98411e183..abf60c39e7 100644 --- a/keepalived/check/check_daemon.c +++ b/keepalived/check/check_daemon.c @@ -424,19 +424,40 @@ start_check(data_t *prev_global_data) /* Set up the track files */ add_rs_to_track_files(); init_track_files(&check_data->track_files); +dump_vs_rs_checker_state("after init_track_files"); /* Processing differential configuration parsing */ set_track_file_weights(); +dump_vs_rs_checker_state("after set_track_file_weights"); +//#define MOVE_CLEAR_DIFF_SVCS +#ifndef MOVE_CLEAR_DIFF_SVCS if (reload) + { clear_diff_services(); +dump_vs_rs_checker_state("after clear_diff_services"); + } +#endif set_track_file_checkers_down(); +dump_vs_rs_checker_state("after set_track_file_checkers_down"); set_effective_weights(); +dump_vs_rs_checker_state("after set_effective_weights"); if (reload) +{ check_new_rs_state(); +dump_vs_rs_checker_state("after check_new_rs_state"); +} +#ifdef MOVE_CLEAR_DIFF_SVCS + if (reload) + { + clear_diff_services(); +dump_vs_rs_checker_state("after clear_diff_services"); + } +#endif /* Initialize IPVS topology */ if (!init_services()) stop_check(KEEPALIVED_EXIT_FATAL); +dump_vs_rs_checker_state("after init_services"); #ifndef _ONE_PROCESS_DEBUG_ /* Notify parent config has been read if appropriate */ @@ -457,6 +478,7 @@ start_check(data_t *prev_global_data) /* Set the process cpu affinity if configured */ set_process_cpu_affinity(&global_data->checker_cpu_mask, "checker"); +dump_vs_rs_checker_state("end of start_check"); } void @@ -485,6 +507,7 @@ reload_check_thread(__attribute__((unused)) thread_ref_t thread) /* set the reloading flag */ SET_RELOAD; +dump_vs_rs_checker_state("Pre reload"); /* Terminate all script process */ script_killall(master, SIGTERM, false); @@ -760,6 +783,7 @@ start_check_child(void) separate_config_file(); /* Child process part, write pidfile */ +log_message(LOG_INFO, "pidfile fd %d, name %s", checkers_pidfile.fd, checkers_pidfile.path); if (!pidfile_write(&checkers_pidfile)) { log_message(LOG_INFO, "Healthcheck child process: cannot write pidfile"); exit(KEEPALIVED_EXIT_FATAL); diff --git a/keepalived/check/check_dns.c b/keepalived/check/check_dns.c index 56ab6ac10e..3d01be0440 100644 --- a/keepalived/check/check_dns.c +++ b/keepalived/check/check_dns.c @@ -179,7 +179,7 @@ dns_recv_thread(thread_ref_t thread) int flags, rcode; checker_t *checker = THREAD_ARG(thread); - dns_check_t *dns_check = CHECKER_ARG(checker); + dns_check_t *dns_check = checker->check_type.dns_check; if (thread->type == THREAD_READ_TIMEOUT) { dns_final(thread, true, "read timeout from socket"); @@ -257,7 +257,7 @@ dns_make_query(thread_ref_t thread) const char *s, *e; size_t n; checker_t *checker = THREAD_ARG(thread); - dns_check_t *dns_check = CHECKER_ARG(checker); + dns_check_t *dns_check = checker->check_type.dns_check; dns_header_t *header = PTR_CAST(dns_header_t, dns_check->sbuf); DNS_SET_RD(flags, 1); /* Recursion Desired */ @@ -296,7 +296,7 @@ static void dns_send(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - dns_check_t *dns_check = CHECKER_ARG(checker); + dns_check_t *dns_check = checker->check_type.dns_check; unsigned long timeout; ssize_t ret; @@ -430,18 +430,18 @@ dns_connect_thread(thread_ref_t thread) static void free_dns_check(checker_t *checker) { - dns_check_t *dns_check = checker->data; + dns_check_t *dns_check = checker->check_type.dns_check; FREE_CONST(dns_check->name); FREE(checker->co); - FREE(checker->data); + FREE(checker->check_type.dns_check); FREE(checker); } static void dump_dns_check(FILE *fp, const checker_t *checker) { - const dns_check_t *dns_check = checker->data; + const dns_check_t *dns_check = checker->check_type.dns_check; conf_write(fp, " Keepalive method = DNS_CHECK"); conf_write(fp, " Type = %s", dns_type_name(dns_check->type)); @@ -451,8 +451,8 @@ dump_dns_check(FILE *fp, const checker_t *checker) static bool compare_dns_check(const checker_t *old_c, checker_t *new_c) { - const dns_check_t *old = old_c->data; - const dns_check_t *new = new_c->data; + const dns_check_t *old = old_c->check_type.dns_check; + const dns_check_t *new = new_c->check_type.dns_check; if (!compare_conn_opts(old_c->co, new_c->co)) return false; @@ -469,12 +469,12 @@ static const checker_funcs_t dns_checker_funcs = { CHECKER_DNS, free_dns_check, static void dns_check_handler(__attribute__((unused)) const vector_t *strvec) { - dns_check_t *dns_check; + checker_details_t checker_details; - PMALLOC(dns_check); - dns_check->type = DNS_DEFAULT_TYPE; - queue_checker(&dns_checker_funcs, dns_connect_thread, - dns_check, CHECKER_NEW_CO(), true); + PMALLOC(checker_details.dns_check); + checker_details.dns_check->type = DNS_DEFAULT_TYPE; + queue_checker(current_rs, &dns_checker_funcs, dns_connect_thread, + checker_details, CHECKER_NEW_CO(), true); /* Set the non-standard retry time */ current_checker->default_retry = DNS_DEFAULT_RETRY; @@ -484,7 +484,7 @@ dns_check_handler(__attribute__((unused)) const vector_t *strvec) static void dns_type_handler(const vector_t *strvec) { - dns_check_t *dns_check = current_checker->data; + dns_check_t *dns_check = current_checker->check_type.dns_check; uint16_t dns_type; dns_type = dns_type_lookup(strvec_slot(strvec, 1)); @@ -498,7 +498,7 @@ dns_type_handler(const vector_t *strvec) static void dns_name_handler(const vector_t *strvec) { - dns_check_t *dns_check = current_checker->data; + dns_check_t *dns_check = current_checker->check_type.dns_check; const char *name; bool name_invalid = false; const char *p; @@ -532,7 +532,7 @@ dns_name_handler(const vector_t *strvec) static void dns_check_end(void) { - dns_check_t *dns_check = current_checker->data; + dns_check_t *dns_check = current_checker->check_type.dns_check; if (!check_conn_opts(current_checker->co)) { dequeue_new_checker(); diff --git a/keepalived/check/check_file.c b/keepalived/check/check_file.c index 1649658fc1..dd9bd4884e 100644 --- a/keepalived/check/check_file.c +++ b/keepalived/check/check_file.c @@ -3,7 +3,7 @@ * . It monitor & manipulate * a loadbalanced server pool using multi-layer checks. * - * Part: FILE CHECK. Monitor contents if a file + * Part: FILE CHECK. Monitor contents of a file * * Authors: Quentin Armitage, * @@ -46,7 +46,7 @@ free_file_check(checker_t *checker) static void dump_file_check(FILE *fp, const checker_t *checker) { - tracked_file_t *tfp = checker->data; + tracked_file_t *tfp = checker->check_type.file_check; conf_write(fp, " Keepalive method = FILE_CHECK"); conf_write(fp, " Tracked file = %s", tfp->fname); @@ -64,6 +64,14 @@ track_file_handler(const vector_t *strvec) return; } + if (current_tfile->file) { + report_config_error(CONFIG_GENERAL_ERROR, "%s track_file already specified as %s - ignoring %s", FMT_RS(current_rs, current_vs), current_tfile->file->fname, strvec_slot(strvec, 1)); + return; + } + + if (vector_size(strvec) > 2) + report_config_error(CONFIG_WARNING, "%s track_file %s has extra parameters - ignoring %s ...", FMT_RS(current_rs, current_vs), strvec_slot(strvec, 1), strvec_slot(strvec, 2)); + current_tfile->file = vsf; } @@ -106,6 +114,7 @@ track_file_weight_handler(const vector_t *strvec) current_tfile->weight = weight; current_tfile->weight_reverse = reverse; +log_message(LOG_INFO, "Set track_file weight %d", current_tfile->weight); } static void @@ -147,6 +156,7 @@ add_rs_to_track_files(void) { virtual_server_t *vs; real_server_t *rs; + checker_details_t checker_details; tracked_file_monitor_t *tfl; list_for_each_entry(vs, &check_data->vs, e_list) { @@ -154,7 +164,8 @@ add_rs_to_track_files(void) list_for_each_entry(tfl, &rs->track_files, e_list) { /* queue new checker - we don't have a compare function since we don't * update file checkers that way on a reload. */ - queue_checker(&file_checker_funcs, NULL, tfl->file, NULL, false); + checker_details.file_check = tfl->file; + queue_checker(rs, &file_checker_funcs, NULL, checker_details, NULL, false); current_checker->vs = vs; current_checker->rs = rs; diff --git a/keepalived/check/check_genhash.c b/keepalived/check/check_genhash.c index 25c81dae11..bc47876916 100644 --- a/keepalived/check/check_genhash.c +++ b/keepalived/check/check_genhash.c @@ -86,7 +86,7 @@ genhash_usage(const char *prog, bool am_genhash) static int check_genhash_parse_cmdline(int argc, char **argv, checker_t *checker) { - http_checker_t *http_get_check = checker->data; + http_checker_t *http_get_check = checker->check_type.http_check; conn_opts_t *co = checker->co; const char *start; char *endptr; @@ -131,7 +131,7 @@ check_genhash_parse_cmdline(int argc, char **argv, checker_t *checker) bad_option = true; break; case 'v': - ((http_checker_t *)checker->data)->genhash_flags |= GENHASH_VERBOSE; + ((http_checker_t *)checker->check_type.http_check)->genhash_flags |= GENHASH_VERBOSE; break; case 'S': http_get_check->proto = PROTO_SSL; @@ -290,7 +290,7 @@ check_genhash(bool am_genhash, int argc, char **argv) INIT_LIST_HEAD(&http_get_check->url); http_get_check->genhash_flags = GENHASH; http_get_check->proto = PROTO_HTTP; - checker->data = http_get_check; + checker->check_type.http_check = http_get_check; checker->enabled = true; /* Parse command line */ diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c index 9517a27e65..f5ab469baf 100644 --- a/keepalived/check/check_http.c +++ b/keepalived/check/check_http.c @@ -319,7 +319,7 @@ free_http_request(request_t *req) void free_http_check(checker_t *checker) { - http_checker_t *http_get_chk = checker->data; + http_checker_t *http_get_chk = checker->check_type.http_check; free_url_list(&http_get_chk->url); free_http_request(http_get_chk->req); @@ -332,7 +332,7 @@ free_http_check(checker_t *checker) static void dump_http_check(FILE *fp, const checker_t *checker) { - const http_checker_t *http_get_chk = checker->data; + const http_checker_t *http_get_chk = checker->check_type.http_check; conf_write(fp, " Keepalive method = %s_GET, http protocol %s", http_get_chk->proto == PROTO_HTTP ? "HTTP" : "SSL", @@ -381,8 +381,8 @@ url_list_size(const list_head_t *l) static bool __attribute__((pure)) compare_http_check(const checker_t *old_c, checker_t *new_c) { - const http_checker_t *old = old_c->data; - const http_checker_t *new = new_c->data; + const http_checker_t *old = old_c->check_type.http_check; + const http_checker_t *new = new_c->check_type.http_check; url_t *u1, *u2 = NULL; unsigned i; @@ -443,8 +443,8 @@ migrate_http_check(checker_t *new_c, const checker_t *old_c) if (new_c->is_up) return; - old_http_c = CHECKER_ARG(old_c); - new_http_c = CHECKER_ARG(new_c); + old_http_c = old_c->check_type.http_check; + new_http_c = new_c->check_type.http_check; /* For the real servers to be the same, the checkers must match, * which means that the urls match */ @@ -465,12 +465,12 @@ static const checker_funcs_t http_checker_funcs = { CHECKER_HTTP, free_http_chec static void http_get_handler(const vector_t *strvec) { - http_checker_t *http_get_chk; const char *str = strvec_slot(strvec, 0); + checker_details_t check_details; /* queue new checker */ - http_get_chk = alloc_http_get(str); - queue_checker(&http_checker_funcs, http_connect_thread, http_get_chk, CHECKER_NEW_CO(), true); + check_details.http_check = alloc_http_get(str); + queue_checker(current_rs, &http_checker_funcs, http_connect_thread, check_details, CHECKER_NEW_CO(), true); current_checker->default_delay_before_retry = 3 * TIMER_HZ; } @@ -492,7 +492,7 @@ http_get_retry_handler(const vector_t *strvec) static void virtualhost_handler(const vector_t *strvec) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; if (vector_size(strvec) < 2) { report_config_error(CONFIG_GENERAL_ERROR, "HTTP_GET virtualhost name missing"); @@ -505,7 +505,7 @@ virtualhost_handler(const vector_t *strvec) static void http_get_check_end(void) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; if (list_empty(&http_get_chk->url)) { report_config_error(CONFIG_GENERAL_ERROR, "HTTP/SSL_GET checker has no urls specified - ignoring"); @@ -635,7 +635,7 @@ url_tls_compliant_handler(const vector_t *strvec) static void http_protocol_handler(const vector_t *strvec) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; if (vector_size(strvec) < 2) { report_config_error(CONFIG_GENERAL_ERROR, "Missing http_protocol version"); @@ -837,7 +837,7 @@ prepare_regex(url_t *url) static void enable_sni_handler(const vector_t *strvec) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; int res = true; if (vector_size(strvec) >= 2) { @@ -854,7 +854,7 @@ enable_sni_handler(const vector_t *strvec) static void fast_recovery_handler(const vector_t *strvec) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; int res = true; if (vector_size(strvec) >= 2) { @@ -870,7 +870,7 @@ fast_recovery_handler(const vector_t *strvec) static void tls_compliant_handler(const vector_t *strvec) { - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; int res = true; if (vector_size(strvec) >= 2) { @@ -887,7 +887,7 @@ static void url_check(void) { unsigned i; - http_checker_t *http_get_chk = current_checker->data; + http_checker_t *http_get_chk = current_checker->check_type.http_check; if (!current_url->path) { @@ -1029,7 +1029,7 @@ static void epilog(thread_ref_t thread, register_checker_t method) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; unsigned long delay = 0; bool checker_was_up; @@ -1144,7 +1144,7 @@ timeout_epilog(thread_ref_t thread, const char *debug_msg) /* check if server is currently alive */ if (checker->is_up || !checker->has_run) { - if (((http_checker_t *)checker->data)->genhash_flags & GENHASH) { + if (((http_checker_t *)checker->check_type.http_check)->genhash_flags & GENHASH) { printf("%s\n", debug_msg); thread_add_terminate_event(thread->master); return; @@ -1350,7 +1350,7 @@ http_handle_response(thread_ref_t thread, unsigned char digest[MD5_DIGEST_LENGTH bool empty_buffer) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; url_t *url = fetch_next_url(http_get_check); const char *msg = "HTTP status code"; @@ -1469,7 +1469,7 @@ http_process_response(thread_ref_t thread, request_t *req, size_t r, url_t *url) { size_t old_req_len = req->len; checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; req->len += r; req->buffer[req->len] = '\0'; /* Terminate the received data since it is used as a string */ @@ -1524,7 +1524,7 @@ static void http_read_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; url_t *url = fetch_next_url(http_get_check); unsigned timeout = checker->co->connection_to; @@ -1592,7 +1592,7 @@ static void http_response_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; url_t *url = fetch_next_url(http_get_check); unsigned timeout = checker->co->connection_to; @@ -1634,7 +1634,7 @@ static void http_request(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; sockaddr_t *addr = &checker->co->dst; unsigned timeout = checker->co->connection_to; @@ -1709,7 +1709,7 @@ static void http_check_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; int ret = 1; int status; unsigned long timeout = 0; @@ -1794,7 +1794,7 @@ void http_connect_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; conn_opts_t *co = checker->co; url_t *fetched_url; enum connect_result status; diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c index f85ec6671a..98905057cd 100644 --- a/keepalived/check/check_misc.c +++ b/keepalived/check/check_misc.c @@ -55,7 +55,7 @@ static bool script_user_set; static void free_misc_check(checker_t *checker) { - misc_checker_t *misck_checker = checker->data; + misc_checker_t *misck_checker = checker->check_type.misc_check; notify_free_script(&misck_checker->script); FREE(misck_checker); @@ -65,7 +65,7 @@ free_misc_check(checker_t *checker) static void dump_misc_check(FILE *fp, const checker_t *checker) { - const misc_checker_t *misck_checker = checker->data; + const misc_checker_t *misck_checker = checker->check_type.misc_check; char time_str[26]; conf_write(fp, " Keepalive method = MISC_CHECK"); @@ -83,8 +83,8 @@ dump_misc_check(FILE *fp, const checker_t *checker) static bool compare_misc_check(const checker_t *old_c, checker_t *new_c) { - const misc_checker_t *old = old_c->data; - const misc_checker_t *new = new_c->data; + const misc_checker_t *old = old_c->check_type.misc_check; + const misc_checker_t *new = new_c->check_type.misc_check; if (new->dynamic != old->dynamic) return false; @@ -95,13 +95,13 @@ compare_misc_check(const checker_t *old_c, checker_t *new_c) static void migrate_misc_check(checker_t *new_c, const checker_t *old_c) { - const misc_checker_t *old = old_c->data; - misc_checker_t *new = new_c->data; + const misc_checker_t *old = old_c->check_type.misc_check; + misc_checker_t *new = new_c->check_type.misc_check; new->last_exit_code = old->last_exit_code; new->last_ran = old->last_ran; - if (!new->dynamic || old->last_exit_code == 1) + if (!new->dynamic || old->last_exit_code == 0 || old->last_exit_code == 1) return; new_c->cur_weight = new->last_exit_code - (new->last_exit_code ? 2 : 0) - new_c->rs->iweight; @@ -112,15 +112,16 @@ static const checker_funcs_t misc_checker_funcs = { CHECKER_MISC, free_misc_chec static void misc_check_handler(__attribute__((unused)) const vector_t *strvec) { - misc_checker_t *new_misck_checker; +// misc_checker_t *new_misck_checker; + checker_details_t checker_details; - PMALLOC(new_misck_checker); - new_misck_checker->state = SCRIPT_STATE_IDLE; + PMALLOC(checker_details.misc_check); + checker_details.misc_check->state = SCRIPT_STATE_IDLE; script_user_set = false; /* queue new checker */ - queue_checker(&misc_checker_funcs, misc_check_thread, new_misck_checker, NULL, false); + queue_checker(current_rs, &misc_checker_funcs, misc_check_thread, checker_details, NULL, false); /* Set non-standard default value */ current_checker->default_retry = 0; @@ -130,7 +131,7 @@ static void misc_path_handler(__attribute__((unused)) const vector_t *strvec) { const vector_t *strvec_qe; - misc_checker_t *new_misck_checker = current_checker->data; + misc_checker_t *new_misck_checker = current_checker->check_type.misc_check; /* We need to allow quoted and escaped strings for the script and parameters */ strvec_qe = alloc_strvec_quoted_escaped(NULL); @@ -144,7 +145,7 @@ static void misc_timeout_handler(const vector_t *strvec) { unsigned timeout; - misc_checker_t *new_misck_checker = current_checker->data; + misc_checker_t *new_misck_checker = current_checker->check_type.misc_check; if (!read_unsigned_strvec(strvec, 1, &timeout, 0, UINT_MAX / TIMER_HZ, true)) { report_config_error(CONFIG_GENERAL_ERROR, "Invalid misc_timeout value '%s'", strvec_slot(strvec, 1)); @@ -157,7 +158,7 @@ misc_timeout_handler(const vector_t *strvec) static void misc_dynamic_handler(__attribute__((unused)) const vector_t *strvec) { - misc_checker_t *new_misck_checker = current_checker->data; + misc_checker_t *new_misck_checker = current_checker->check_type.misc_check; new_misck_checker->dynamic = true; } @@ -165,7 +166,7 @@ misc_dynamic_handler(__attribute__((unused)) const vector_t *strvec) static void misc_user_handler(const vector_t *strvec) { - misc_checker_t *new_misck_checker = current_checker->data; + misc_checker_t *new_misck_checker = current_checker->check_type.misc_check; if (vector_size(strvec) < 2) { report_config_error(CONFIG_GENERAL_ERROR, "No user specified for misc checker script %s", cmd_str(&new_misck_checker->script)); @@ -183,7 +184,7 @@ misc_user_handler(const vector_t *strvec) static void misc_end_handler(void) { - misc_checker_t *new_misck_checker = current_checker->data; + misc_checker_t *new_misck_checker = current_checker->check_type.misc_check; if (!new_misck_checker->script.args) { report_config_error(CONFIG_GENERAL_ERROR, "No script path has been specified for MISC_CHECKER - skipping"); @@ -235,7 +236,7 @@ check_misc_script_security(magic_t magic) if (checker->launch != misc_check_thread) continue; - misc_script = CHECKER_ARG(checker); + misc_script = checker->check_type.misc_check; script_flags |= (flags = check_script_secure(&misc_script->script, magic)); @@ -270,7 +271,7 @@ misc_check_thread(thread_ref_t thread) misc_checker_t *misck_checker; int ret; - misck_checker = CHECKER_ARG(checker); + misck_checker = checker->check_type.misc_check; /* * Register a new checker thread & return @@ -311,7 +312,7 @@ misc_check_child_thread(thread_ref_t thread) bool message_only = false; checker = THREAD_ARG(thread); - misck_checker = CHECKER_ARG(checker); + misck_checker = checker->check_type.misc_check; if (thread->type == THREAD_CHILD_TIMEOUT) { pid = THREAD_CHILD_PID(thread); diff --git a/keepalived/check/check_parser.c b/keepalived/check/check_parser.c index 037d8f7b20..8c8991be0e 100644 --- a/keepalived/check/check_parser.c +++ b/keepalived/check/check_parser.c @@ -222,6 +222,12 @@ vs_end_handler(void) } } + if (current_vs->hysteresis >= current_vs->quorum) { + /* If hysteresis >= quorum, the vs would never lose its quorum */ + report_config_error(CONFIG_GENERAL_ERROR, "Virtual server %s hysteresis (%u) >= quorum (%u) - reducing hysteresis to %u", FMT_VS(current_vs), current_vs->quorum, current_vs->hysteresis, current_vs->quorum - 1); + current_vs->hysteresis = current_vs->quorum - 1; + } + list_add_tail(¤t_vs->e_list, &check_data->vs); } static void diff --git a/keepalived/check/check_ping.c b/keepalived/check/check_ping.c index f25a7f593e..654f114296 100644 --- a/keepalived/check/check_ping.c +++ b/keepalived/check/check_ping.c @@ -123,14 +123,14 @@ static void free_ping_check(checker_t *checker) { FREE(checker->co); - FREE_PTR(checker->data); + FREE_PTR(checker->check_type.ping_check); FREE(checker); } static void dump_ping_check(FILE *fp, const checker_t *checker) { - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; conf_write(fp, " Keepalive method = PING_CHECK"); conf_write(fp, " ICMP seq no = %u", ping_checker->seq_no); @@ -147,10 +147,12 @@ static const checker_funcs_t ping_checker_funcs = { CHECKER_PING, free_ping_chec static void ping_check_handler(__attribute__((unused)) const vector_t *strvec) { - ping_check_t *ping_check = sizeof(ping_check_t) ? MALLOC(sizeof (ping_check_t)) : NULL; + checker_details_t checker_details; + + checker_details.ping_check = sizeof(*checker_details.ping_check) ? MALLOC(sizeof (*checker_details.ping_check)) : NULL; /* queue new checker */ - queue_checker(&ping_checker_funcs, icmp_connect_thread, ping_check, CHECKER_NEW_CO(), true); + queue_checker(current_rs, &ping_checker_funcs, icmp_connect_thread, checker_details, CHECKER_NEW_CO(), true); if (!checked_ping_group_range) set_ping_group_range(true); @@ -181,7 +183,7 @@ install_ping_check_keyword(void) static enum connect_result ping_it(int fd, checker_t *checker, conn_opts_t* co) { - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; struct icmphdr *icmp_hdr; char send_buf[sizeof(*icmp_hdr) + ICMP_BUFSIZE] __attribute__((aligned(__alignof__(struct icmphdr)))); @@ -204,7 +206,7 @@ ping_it(int fd, checker_t *checker, conn_opts_t* co) static enum connect_result recv_it(int fd, checker_t *checker) { - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; ssize_t len; const struct icmphdr *icmp_hdr; char recv_buf[sizeof(*icmp_hdr) + ICMP_BUFSIZE] __attribute__((aligned(__alignof__(struct icmphdr)))); @@ -238,7 +240,7 @@ recv_it(int fd, checker_t *checker) static enum connect_result ping6_it(int fd, checker_t *checker, conn_opts_t* co) { - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; struct icmp6_hdr* icmp6_hdr; char send_buf[sizeof(*icmp6_hdr) + ICMP_BUFSIZE] __attribute__((aligned(__alignof__(struct icmp6_hdr)))); @@ -261,7 +263,7 @@ ping6_it(int fd, checker_t *checker, conn_opts_t* co) static enum connect_result recv6_it(int fd, checker_t *checker) { - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; ssize_t len; const struct icmp6_hdr* icmp6_hdr; char recv_buf[sizeof (*icmp6_hdr) + ICMP_BUFSIZE] __attribute__((aligned(__alignof__(struct icmp6_hdr)))); @@ -420,7 +422,7 @@ static void icmp_connect_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - ping_check_t *ping_checker = CHECKER_ARG(checker); + ping_check_t *ping_checker = checker->check_type.ping_check; conn_opts_t *co = checker->co; int fd; int size = SOCK_RECV_BUFF; diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c index 44ca4fb755..3a7bd180d2 100644 --- a/keepalived/check/check_smtp.c +++ b/keepalived/check/check_smtp.c @@ -67,7 +67,7 @@ static void smtp_engine_thread(thread_ref_t); static void free_smtp_check(checker_t *checker) { - smtp_checker_t *smtp_checker = checker->data; + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; FREE_PTR(checker->co); FREE_CONST(smtp_checker->helo_name); @@ -82,7 +82,7 @@ free_smtp_check(checker_t *checker) static void dump_smtp_check(FILE *fp, const checker_t *checker) { - const smtp_checker_t *smtp_checker = checker->data; + const smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conf_write(fp, " Keepalive method = SMTP_CHECK"); conf_write(fp, " helo = %s", smtp_checker->helo_name); @@ -91,8 +91,8 @@ dump_smtp_check(FILE *fp, const checker_t *checker) static bool compare_smtp_check(const checker_t *old_c, checker_t *new_c) { - const smtp_checker_t *old = old_c->data; - const smtp_checker_t *new = new_c->data; + const smtp_checker_t *old = old_c->check_type.smtp_check; + const smtp_checker_t *new = new_c->check_type.smtp_check; if (strcmp(old->helo_name, new->helo_name) != 0) return false; @@ -111,15 +111,15 @@ static const checker_funcs_t smtp_checker_funcs = { CHECKER_SMTP, free_smtp_chec static void smtp_check_handler(__attribute__((unused)) const vector_t *strvec) { - smtp_checker_t *smtp_checker; + checker_details_t checker_details; conn_opts_t *co; - PMALLOC(smtp_checker); + PMALLOC(checker_details.smtp_check); PMALLOC(co); co->connection_to = UINT_MAX; /* Have the checker queue code put our checker into the real server's checkers_queue list. */ - queue_checker(&smtp_checker_funcs, smtp_start_check_thread, smtp_checker, co, true); + queue_checker(current_rs, &smtp_checker_funcs, smtp_start_check_thread, checker_details, co, true); /* We need to be able to check if anything has been set */ co->dst.ss_family = AF_UNSPEC; @@ -129,10 +129,10 @@ smtp_check_handler(__attribute__((unused)) const vector_t *strvec) static void smtp_check_end_handler(void) { - smtp_checker_t *smtp_checker = current_checker->data; + smtp_checker_t *smtp_checker = current_checker->check_type.smtp_check; checker_t *checker = current_checker; #ifdef WITH_HOST_ENTRIES - smtp_checker_t *new_smtp_checker; + checker_details_t checker_details; conn_opts_t *co; ref_co_t *rco, *rco_tmp; list_head_t sav_rs_list; @@ -204,16 +204,16 @@ smtp_check_end_handler(void) /* Create a new checker for each host on the host list */ list_for_each_entry_safe(rco, rco_tmp, &host_list, e_list) { co = rco->co; - PMALLOC(new_smtp_checker); - *new_smtp_checker = *smtp_checker; + PMALLOC(checker_details.smtp_check); + *checker_details.smtp_check = *smtp_checker; if (co->connection_to == UINT_MAX) co->connection_to = conn_to; - new_smtp_checker->helo_name = STRDUP(smtp_checker->helo_name); + checker_details.smtp_check->helo_name = STRDUP(smtp_checker->helo_name); - queue_checker(&smtp_checker_funcs, smtp_start_check_thread, - new_smtp_checker, NULL, true); + queue_checker(current_rs, &smtp_checker_funcs, smtp_start_check_thread, + checker_details, NULL, true); /* Copy the checker info, but preserve the list_head entry, th * co pointer and the pointer to new_smtp_checker. */ @@ -221,7 +221,7 @@ smtp_check_end_handler(void) *current_checker = *checker; current_checker->rs_list = sav_rs_list; current_checker->co = co; - current_checker->data = new_smtp_checker; + current_checker->check_type.smtp_check = checker_details.smtp_check; /* queue the checker */ list_add_tail(¤t_checker->rs_list, &checker->rs->checkers_list); @@ -267,7 +267,7 @@ smtp_host_end_handler(void) static void smtp_helo_name_handler(const vector_t *strvec) { - smtp_checker_t *smtp_checker = current_checker->data; + smtp_checker_t *smtp_checker = current_checker->check_type.smtp_check; if (vector_size(strvec) < 2) { report_config_error(CONFIG_GENERAL_ERROR, "SMTP_CHECK helo name missing"); @@ -442,7 +442,7 @@ static void smtp_get_line_cb(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conn_opts_t *smtp_host = checker->co; ssize_t r; char *nl; @@ -521,7 +521,7 @@ static void smtp_get_line(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conn_opts_t *smtp_host = checker->co; /* clear the buffer */ @@ -543,7 +543,7 @@ static void smtp_put_line_cb(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conn_opts_t *smtp_host = checker->co; ssize_t w; @@ -590,7 +590,7 @@ static void smtp_put_line(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; smtp_checker->buff_ctr = strlen(smtp_checker->buff); @@ -631,7 +631,7 @@ static void smtp_engine_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conn_opts_t *smtp_host = checker->co; switch (smtp_checker->state) { @@ -710,7 +710,7 @@ static void smtp_check_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - smtp_checker_t *smtp_checker = CHECKER_ARG(checker); + smtp_checker_t *smtp_checker = checker->check_type.smtp_check; conn_opts_t *smtp_host = checker->co; int status; @@ -780,12 +780,12 @@ smtp_connect_thread(thread_ref_t thread) * defined in the keepalived.conf will more than likely have * a checker structure assigned to it. Each checker structure * has a data element that is meant to hold per checker - * configurations. So thread->arg(checker)->data points to - * a smtp_checker structure. In the smtp_checker structure - * we hold global configuration data for the smtp check. + * configurations. So thread->arg(checker)->check_type.smtp_check + * points to a smtp_checker structure. In the smtp_checker + * structure we hold global configuration data for the smtp check. * * So this whole thing looks like this: - * thread->arg(checker)->data(smtp_checker)->host(smtp_host) + * thread->arg(checker)->check_type.smtp_check->host(smtp_host) * * To make life simple, we'll break the structures out so * that "checker" always points to the current checker structure, diff --git a/keepalived/check/check_ssl.c b/keepalived/check/check_ssl.c index 0f7f944849..bf0baa099b 100644 --- a/keepalived/check/check_ssl.c +++ b/keepalived/check/check_ssl.c @@ -204,7 +204,7 @@ int ssl_connect(thread_ref_t thread, int new_req) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; #ifdef _HAVE_SSL_SET_TLSEXT_HOST_NAME_ url_t *url = http_get_check->url_it; @@ -300,7 +300,7 @@ void ssl_read_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - http_checker_t *http_get_check = CHECKER_ARG(checker); + http_checker_t *http_get_check = checker->check_type.http_check; request_t *req = http_get_check->req; url_t *url = http_get_check->url_it; unsigned long timeout; diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c index 00ccae324e..11b980d37e 100644 --- a/keepalived/check/check_tcp.c +++ b/keepalived/check/check_tcp.c @@ -68,7 +68,9 @@ static void tcp_check_handler(__attribute__((unused)) const vector_t *strvec) { /* queue new checker */ - queue_checker(&tcp_checker_funcs, tcp_connect_thread, NULL, CHECKER_NEW_CO(), true); + checker_details_t check_details = { .misc_check = NULL }; + + queue_checker(current_rs, &tcp_checker_funcs, tcp_connect_thread, check_details, CHECKER_NEW_CO(), true); } static void diff --git a/keepalived/check/check_udp.c b/keepalived/check/check_udp.c index 3f882f67eb..15bc278753 100644 --- a/keepalived/check/check_udp.c +++ b/keepalived/check/check_udp.c @@ -46,20 +46,20 @@ static void udp_connect_thread(thread_ref_t); static void free_udp_check(checker_t *checker) { - udp_check_t *udp_check = CHECKER_ARG(checker); + udp_check_t *udp_check = checker->check_type.udp_check; FREE_PTR(udp_check->payload); FREE_PTR(udp_check->reply_data); FREE_PTR(udp_check->reply_mask); FREE(checker->co); - FREE(checker->data); + FREE(checker->check_type.udp_check); FREE(checker); } static void dump_udp_check(FILE *fp, const checker_t *checker) { - udp_check_t *udp_check = CHECKER_ARG(checker); + udp_check_t *udp_check = checker->check_type.udp_check; conf_write(fp, " Keepalive method = UDP_CHECK"); @@ -89,19 +89,20 @@ static const checker_funcs_t udp_checker_funcs = { CHECKER_UDP, free_udp_check, static void udp_check_handler(__attribute__((unused)) const vector_t *strvec) { - udp_check_t *udp_check = MALLOC(sizeof (udp_check_t)); + checker_details_t checker_details; - udp_check->min_reply_len = 0; - udp_check->max_reply_len = UINT8_MAX; + PMALLOC(checker_details.udp_check); + checker_details.udp_check->min_reply_len = 0; + checker_details.udp_check->max_reply_len = UINT8_MAX; /* queue new checker */ - queue_checker(&udp_checker_funcs, udp_connect_thread, udp_check, CHECKER_NEW_CO(), true); + queue_checker(current_rs, &udp_checker_funcs, udp_connect_thread, checker_details, CHECKER_NEW_CO(), true); } static void payload_handler(const vector_t *strvec) { - udp_check_t *udp_check = current_checker->data; + udp_check_t *udp_check = current_checker->check_type.udp_check; char *hex_str; if (vector_size(strvec) == 1) { @@ -121,7 +122,7 @@ payload_handler(const vector_t *strvec) static void require_reply_handler(const vector_t *strvec) { - udp_check_t *udp_check = current_checker->data; + udp_check_t *udp_check = current_checker->check_type.udp_check; char *hex_str; udp_check->require_reply = true; @@ -141,7 +142,7 @@ require_reply_handler(const vector_t *strvec) static void min_length_handler(const vector_t *strvec) { - udp_check_t *udp_check = current_checker->data; + udp_check_t *udp_check = current_checker->check_type.udp_check; unsigned len; if (!read_unsigned_strvec(strvec, 1, &len, 0, UINT16_MAX, false)) { @@ -155,7 +156,7 @@ min_length_handler(const vector_t *strvec) static void max_length_handler(const vector_t *strvec) { - udp_check_t *udp_check = current_checker->data; + udp_check_t *udp_check = current_checker->check_type.udp_check; unsigned len; if (!read_unsigned_strvec(strvec, 1, &len, 0, UINT16_MAX, false)) { @@ -169,7 +170,7 @@ max_length_handler(const vector_t *strvec) static void udp_check_end_handler(void) { - udp_check_t *udp_check = current_checker->data; + udp_check_t *udp_check = current_checker->check_type.udp_check; if (!check_conn_opts(current_checker->co)) { dequeue_new_checker(); @@ -280,7 +281,7 @@ static void udp_check_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - udp_check_t *udp_check = CHECKER_ARG(checker); + udp_check_t *udp_check = checker->check_type.udp_check; int status; uint8_t *recv_buf; size_t len = udp_check->max_reply_len + 1; @@ -321,7 +322,7 @@ static void udp_connect_thread(thread_ref_t thread) { checker_t *checker = THREAD_ARG(thread); - udp_check_t *udp_check = CHECKER_ARG(checker); + udp_check_t *udp_check = checker->check_type.udp_check; conn_opts_t *co = checker->co; int fd; int status; diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c index 25ac13458e..d37e2d55d0 100644 --- a/keepalived/check/ipwrapper.c +++ b/keepalived/check/ipwrapper.c @@ -42,6 +42,32 @@ #include "check_data.h" #endif +void +dump_vs_rs_checker_state(const char *title) +{ + virtual_server_t *vs; + real_server_t *rs; + checker_t *checker; + + log_message(LOG_INFO, "vs rs dump: %s", title); + list_for_each_entry(vs, &check_data->vs, e_list) { + log_message(LOG_INFO, "%s", format_vs(vs)); + if (vs->s_svr) + log_message(LOG_INFO, "quorum %u quorum_up %d s_svr %s set = %d alive = %d", vs->quorum, vs->quorum_state_up, FMT_RS(vs->s_svr, vs), vs->s_svr->set, vs->s_svr->alive); + + list_for_each_entry(rs, &vs->rs, e_list) { + log_message(LOG_INFO, "\t%s, set = %d alive = %d, # failed checkers %u, wgt: eff %ld peff %ld i %d, reloaded %d", format_rs(rs, vs), rs->set, rs->alive, rs->num_failed_checkers, + rs->effective_weight, rs->peffective_weight, rs->iweight, rs->reloaded); + list_for_each_entry(checker, &rs->checkers_list, rs_list) { + log_message(LOG_INFO, "\t\t%s enabled %d is_up %d has_run %d cur_weight %d", + checker->checker_funcs->type == CHECKER_FILE ? "FILE" : + checker->checker_funcs->type == CHECKER_MISC ? "MISC" : "unknown", + checker->enabled, checker->is_up, checker->has_run, checker->cur_weight); + } + } + } +} + static bool __attribute((pure)) vs_iseq(const virtual_server_t *vs_a, const virtual_server_t *vs_b) { @@ -85,16 +111,24 @@ vsge_iseq(const virtual_server_group_entry_t *vsge_a, const virtual_server_group } /* Returns the sum of all alive RS weight in a virtual server. */ +// *** count is long, but returned as unsigned long !!!! static unsigned long __attribute__ ((pure)) weigh_live_realservers(virtual_server_t *vs) { real_server_t *rs; - long count = 0; + unsigned long count = 0; list_for_each_entry(rs, &vs->rs, e_list) { - if (ISALIVE(rs)) + if (ISALIVE(rs)) { count += real_weight(rs->effective_weight); + /* The maximum value returned by real_weight is IPVS_WEIGHT_MAX, + * which is INT32_MAX. This means that count cannot overflow + * so long as we never add more than IPVS_WEIGHT_MAX and IPVS_WEIGHT_MAX */ + if (count >= IPVS_WEIGHT_MAX) + return IPVS_WEIGHT_MAX; + } } + return count; } @@ -225,8 +259,8 @@ do_rs_notifies(virtual_server_t* vs, real_server_t* rs, bool stopping) static void update_vs_notifies(virtual_server_t *vs, bool stopping) { - long threshold = vs->quorum - vs->hysteresis; - long weight_sum; + unsigned threshold = vs->quorum - vs->hysteresis; + unsigned long weight_sum; /* Sooner or later VS will lose the quorum (if any). However, * we don't push in a sorry server then, hence the regression @@ -515,16 +549,17 @@ set_quorum_states(void) static void update_quorum_state(virtual_server_t * vs, bool init) { - long weight_sum = weigh_live_realservers(vs); - long threshold; + unsigned long weight_sum = weigh_live_realservers(vs); + unsigned threshold; threshold = vs->quorum + (vs->quorum_state_up ? -1 : 1) * vs->hysteresis; - +log_message(LOG_INFO, "update_quorum_state(init=%d) vs quorum %u state %d tot weight %lu threshold %u", init, vs->quorum, vs->quorum_state_up, weight_sum, threshold); +// THIS IS WHERE DONE WHEN 2 RSs. /* If we have just gained quorum, it's time to consider notify_up. */ if (!vs->quorum_state_up && weight_sum >= threshold) { vs->quorum_state_up = true; - log_message(LOG_INFO, "Gained quorum %u+%u=%ld <= %ld for VS %s" + log_message(LOG_INFO, "Gained quorum %u+%u=%u <= %lu for VS %s" , vs->quorum , vs->hysteresis , threshold @@ -558,7 +593,7 @@ update_quorum_state(virtual_server_t * vs, bool init) * We are starting up and need to add the sorry server */ vs->quorum_state_up = false; - log_message(LOG_INFO, "%s %u-%u=%ld > %ld for VS %s" + log_message(LOG_INFO, "%s %u-%u=%u > %lu for VS %s" , init ? "Starting with quorum down" : "Lost quorum" , vs->quorum , vs->hysteresis @@ -619,7 +654,10 @@ perform_svr_state(bool alive, checker_t *checker) /* We may have changed quorum state. If the quorum wasn't up * but is now up, this is where the rs is added. */ +dump_vs_rs_checker_state("Pre update_quorum_state 3"); +// When have two RSs when first RS processed and checker removed, we don't have quorum. When second RS processed, alive does not change. ******* update_quorum_state(vs, false); +dump_vs_rs_checker_state("Post update_quorum_state 3"); return true; } @@ -654,9 +692,13 @@ init_service_vs(virtual_server_t * vs) sync_service_vsg(vs); } +#if 1 +dump_vs_rs_checker_state("Pre update_quorum_state 1"); /* we may have got/lost quorum due to quorum setting changed */ /* also update, in case we need the sorry server in alpha mode */ update_quorum_state(vs, true); +dump_vs_rs_checker_state("Post update_quorum_state 1"); +#endif /* If we have a sorry server with inhibit, add it now */ if (vs->s_svr && vs->s_svr->inhibit && !vs->s_svr->set) { @@ -671,6 +713,7 @@ init_service_vs(virtual_server_t * vs) vs->s_svr->num_failed_checkers = 0; } } +dump_vs_rs_checker_state("After s_svr check"); return true; } @@ -719,7 +762,11 @@ update_svr_wgt(int64_t weight, virtual_server_t * vs, real_server_t * rs (vs->quorum_state_up || !vs->s_svr || !ISALIVE(vs->s_svr))) ipvs_cmd(LVS_CMD_EDIT_DEST, vs, rs); if (update_quorum) +{ +dump_vs_rs_checker_state("Pre update_quorum_state 2"); update_quorum_state(vs, false); +dump_vs_rs_checker_state("Post update_quorum_state 2"); +} } } @@ -947,6 +994,7 @@ migrate_checkers(virtual_server_t *vs, real_server_t *old_rs, real_server_t *new checker_t dummy_checker; bool a_checker_has_run = false; +dump_vs_rs_checker_state("At migrate_checkers entry"); if (!list_empty(&old_rs->checkers_list)) { list_for_each_entry(new_c, &new_rs->checkers_list, rs_list) { if (!new_c->checker_funcs->compare) @@ -1004,10 +1052,16 @@ migrate_checkers(virtual_server_t *vs, real_server_t *old_rs, real_server_t *new } } +return; +log_message(LOG_INFO, "About to update rs's num failed %u alive %d set %d inhibit %d for %s", new_rs->num_failed_checkers, new_rs->alive, new_rs->set, new_rs->inhibit, FMT_RS(new_rs, vs)); +dump_vs_rs_checker_state("Pre update rs's"); +// THIS IS WHERE DONE WHEN ONLY 1 RS. Why not when there are 2 RS's? /* If there are no failed checkers, the RS needs to be up */ if (!new_rs->num_failed_checkers && !new_rs->alive) { +// What about quorum? dummy_checker.vs = vs; dummy_checker.rs = new_rs; +log_message(LOG_INFO, "Calling perform_svr_state()"); perform_svr_state(true, &dummy_checker); } else if (new_rs->num_failed_checkers && new_rs->set != new_rs->inhibit) { /* ipvs_cmd() checks for alive rather than set */ @@ -1015,6 +1069,7 @@ migrate_checkers(virtual_server_t *vs, real_server_t *old_rs, real_server_t *new ipvs_cmd(new_rs->inhibit ? IP_VS_SO_SET_ADDDEST : IP_VS_SO_SET_DELDEST, vs, new_rs); new_rs->alive = false; } +dump_vs_rs_checker_state("Done update rs's"); } /* Clear the diff rs of the old vs */ @@ -1043,22 +1098,26 @@ clear_diff_rs(virtual_server_t *old_vs, virtual_server_t *new_vs) * flag value to not try to set * already set IPVS rule. */ +// Alive should be set based on state of checkers new_rs->alive = rs->alive; new_rs->set = rs->set; new_rs->effective_weight = rs->effective_weight; new_rs->peffective_weight = rs->effective_weight; new_rs->reloaded = true; +log_message(LOG_INFO, "%s: alive %d set %d eff %ld peff %ld", FMT_RS(new_rs, new_vs), new_rs->alive, new_rs->set, new_rs->effective_weight, new_rs->peffective_weight); /* * We must migrate the state of the old checkers. * If we do not, the new RS is in a state where it’s reported * as down with no check failed. As a result, the server will never - * be put back up when it’s alive again in check_tcp.c#83 because + * be put back up when it’s alive again in check_tcp.c#83 because, * of the check that put a rs up only if it was not previously up. * For alpha mode checkers, if it was up, we don't need another * success to say it is now up. */ +log_message(LOG_INFO, "About to migrate checkers %s", FMT_RS(new_rs, new_vs)); migrate_checkers(new_vs, rs, new_rs); +dump_vs_rs_checker_state("Done migrate checkers"); /* Do we need to update the RS configuration? */ if ((new_rs->alive && new_rs->effective_weight != rs->effective_weight) || @@ -1168,10 +1227,18 @@ clear_diff_services(void) ipvs_cmd(IP_VS_SO_SET_EDIT, new_vs, NULL); vs->omega = true; +log_message(LOG_INFO, "About to clear_diff_rs %s", FMT_VS(new_vs)); clear_diff_rs(vs, new_vs); +dump_vs_rs_checker_state("Done clear_diff_rs"); +log_message(LOG_INFO, "About to clear_diff_s_svr %s", FMT_VS(new_vs)); clear_diff_s_srv(vs, new_vs); +dump_vs_rs_checker_state("Done clear_diff_s_svr"); +log_message(LOG_INFO, "About to update_alive_counts %s", FMT_VS(new_vs)); update_alive_counts(vs, new_vs); +dump_vs_rs_checker_state("Done update_alive_couns"); +// if (vs->s_svr && vs->s_svr.is_alive == vs->quorum_up) { +// } } } @@ -1191,6 +1258,7 @@ check_new_rs_state(void) continue; if (!checker->alpha) continue; +// Check if weighted checker set_checker_state(checker, false); UNSET_ALIVE(checker->rs); } diff --git a/keepalived/core/pidfile.c b/keepalived/core/pidfile.c index 8e2214d86d..59d5029dcc 100644 --- a/keepalived/core/pidfile.c +++ b/keepalived/core/pidfile.c @@ -253,7 +253,7 @@ pidfile_write(pidfile_t *pidf) { int ret; - if (pidf->fd == -1) + if (!children_started && pidf->fd == -1) return false; if (children_started) { @@ -261,7 +261,11 @@ pidfile_write(pidfile_t *pidf) /* There could be more error handling, but that will just * complicate the code for minimal benefit. */ - if (stat(pidf->path, &statb)) { + if (pidf->fd == -1) { + /* This process wasn't originally started (due to no configuration) + * but configuration has been added */ + create_pidfile(pidf); + } else if (stat(pidf->path, &statb)) { /* pidfile no longer exists */ close(pidf->fd); create_pidfile(pidf); diff --git a/keepalived/include/check_api.h b/keepalived/include/check_api.h index f13be751f8..441d7e41fb 100644 --- a/keepalived/include/check_api.h +++ b/keepalived/include/check_api.h @@ -37,6 +37,15 @@ #include "layer4.h" #include "sockaddr.h" +//#include "check_dns.h" +//#include "check_http.h" +//#include "check_misc.h" +//#include "check_ping.h" +//#include "check_smtp.h" +//#include "check_udp.h" +//#include "track_file.h" +//#include "check_bfd.h" + typedef enum _checker_type { CHECKER_MISC, CHECKER_TCP, @@ -62,13 +71,33 @@ typedef struct _checker_funcs { void (*migrate) (struct _checker *, const struct _checker *); } checker_funcs_t; +struct _dns_check; +struct _http_check; +struct _misc_check; +struct _ping_check; +struct _smtp_check; +struct _udp_check; +struct _tracked_file_monitor; +struct _bfd_check; +typedef union { + struct _dns_check *dns_check; + struct _http_check *http_check; + struct _misc_check *misc_check; + struct _ping_check *ping_check; + struct _smtp_check *smtp_check; + struct _udp_check *udp_check; + struct _tracked_file *file_check; + struct _bfd_check *bfd_check; + void *any; +} checker_details_t; + /* Checkers structure definition */ typedef struct _checker { const checker_funcs_t *checker_funcs; thread_func_t launch; virtual_server_t *vs; /* pointer to the checker thread virtualserver */ real_server_t *rs; /* pointer to the checker thread realserver */ - void *data; /* Details for the specific checker type */ + checker_details_t check_type; /* Details for the specific checker type */ bool enabled; /* Activation flag */ bool is_up; /* Set if checker is up */ bool has_run; /* Set if the checker has completed at least once */ @@ -115,9 +144,10 @@ extern void free_checker(checker_t *); extern void free_checker_list(list_head_t *); extern void free_rs_checkers(const real_server_t *); extern void dump_connection_opts(FILE *, const void *); -extern void queue_checker(const checker_funcs_t * +extern void queue_checker(real_server_t * + ,const checker_funcs_t * , thread_func_t - , void * + , checker_details_t , conn_opts_t * , bool); extern void dequeue_new_checker(void); diff --git a/keepalived/include/check_bfd.h b/keepalived/include/check_bfd.h index fda39140c1..b56f0d0f8b 100644 --- a/keepalived/include/check_bfd.h +++ b/keepalived/include/check_bfd.h @@ -48,7 +48,7 @@ typedef struct _cref_tracked_bfd { } cref_tracked_bfd_t; /* bfd_checker structure */ -typedef struct _bfd_checker { +typedef struct _bfd_check { checker_tracked_bfd_t *bfd; /* track bfd pointer, cannot be NULL */ // int weight; // Set in bfd_weight_handler diff --git a/keepalived/include/check_http.h b/keepalived/include/check_http.h index 382e59584d..6cc42384a0 100644 --- a/keepalived/include/check_http.h +++ b/keepalived/include/check_http.h @@ -115,7 +115,7 @@ typedef struct _url { list_head_t e_list; } url_t; -typedef struct _http_checker { +typedef struct _http_check { unsigned proto; url_t *url_it; /* current url checked list entry */ url_t *failed_url; /* the url that is currently failing, if any */ diff --git a/keepalived/include/check_misc.h b/keepalived/include/check_misc.h index e243fa4571..efab135d4f 100644 --- a/keepalived/include/check_misc.h +++ b/keepalived/include/check_misc.h @@ -33,7 +33,7 @@ #include "keepalived_magic.h" /* Checker argument structure */ -typedef struct _misc_checker { +typedef struct _misc_check { notify_script_t script; /* The script details */ unsigned long timeout; bool dynamic; /* false: old-style, true: exit code from checker affects weight */ diff --git a/keepalived/include/check_ping.h b/keepalived/include/check_ping.h index cecf040532..1e3a60c7e5 100644 --- a/keepalived/include/check_ping.h +++ b/keepalived/include/check_ping.h @@ -23,7 +23,7 @@ #ifndef _CHECK_PING_H #define _CHECK_PING_H -#include "check_api.h" +#include typedef struct _ping_check { uint16_t seq_no; diff --git a/keepalived/include/check_smtp.h b/keepalived/include/check_smtp.h index 9c924cf438..dd9cf50548 100644 --- a/keepalived/include/check_smtp.h +++ b/keepalived/include/check_smtp.h @@ -29,7 +29,6 @@ /* local includes */ #include "scheduler.h" -#include "check_api.h" #define SMTP_BUFF_MAX 512U @@ -45,7 +44,7 @@ typedef enum { #define SMTP_DEFAULT_HELO "smtpchecker.keepalived.org" /* Checker argument structure */ -typedef struct _smtp_checker { +typedef struct _smtp_check { /* non per host config data goes here */ const char *helo_name; diff --git a/keepalived/include/ipwrapper.h b/keepalived/include/ipwrapper.h index fcc32f5a58..724ccdc671 100644 --- a/keepalived/include/ipwrapper.h +++ b/keepalived/include/ipwrapper.h @@ -60,4 +60,5 @@ extern void clear_diff_services(void); extern void check_new_rs_state(void); extern void link_vsg_to_vs(void); +extern void dump_vs_rs_checker_state(const char *); #endif diff --git a/lib/parser.c b/lib/parser.c index f34059fd83..bd4d77fbdd 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -1512,6 +1512,12 @@ add_lst(char *buf) p += strspn(p + 1, " \t") + 1; num_vars++; } + + if (end_char == '}' && *p != '}') { + free_seq_lst(seq_ent); + return false; + } + if (*p == '}') p += strspn(p + 1, " \t") + 1; if (*p++ != ',') { @@ -1537,15 +1543,18 @@ add_lst(char *buf) /* Read one set of values */ num_values = 0; while (true) { +// Need to allow escapes and quotes to have starting/trailing spaces var = p; - var_end = p += strcspn(p, " \t,})"); + var_end = p += strcspn(p, ",})"); + while (var_end > var && (var_end[-1] == ' ' || var_end[-1] == '\t')) + var_end--; PMALLOC(value); INIT_LIST_HEAD(&value->e_list); value->val = STRNDUP(var, var_end - var); list_add_tail(&value->e_list, &value_set->values); - p += strspn(p, " \t"); +// p += strspn(p, " \t"); if (*p == end_char || (*p == ')' && end_char == ',')) break; if (*p != ',') { From b93596f2806d538a7b2adb5de2101a5e1ec88209 Mon Sep 17 00:00:00 2001 From: Quentin Armitage Date: Wed, 21 Aug 2024 18:47:14 +0100 Subject: [PATCH 2/2] all: update how pidfile handled after reload with new configuration Signed-off-by: Quentin Armitage --- keepalived/core/pidfile.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/keepalived/core/pidfile.c b/keepalived/core/pidfile.c index 59d5029dcc..7696e8912a 100644 --- a/keepalived/core/pidfile.c +++ b/keepalived/core/pidfile.c @@ -253,6 +253,10 @@ pidfile_write(pidfile_t *pidf) { int ret; + /* If keepalived originally started with no configuration for this process, + * the process won't have originally been started, and the parent process + * will not have created and opened a pid file. This means that pidf->fd + * could be -1 after a reload. */ if (!children_started && pidf->fd == -1) return false; @@ -261,34 +265,32 @@ pidfile_write(pidfile_t *pidf) /* There could be more error handling, but that will just * complicate the code for minimal benefit. */ - if (pidf->fd == -1) { - /* This process wasn't originally started (due to no configuration) - * but configuration has been added */ - create_pidfile(pidf); - } else if (stat(pidf->path, &statb)) { + if (stat(pidf->path, &statb)) { /* pidfile no longer exists */ - close(pidf->fd); + if (pidf->fd != -1) + close(pidf->fd); create_pidfile(pidf); } else { - if (fstat(pidf->fd, &fstatb) || + if (pidf->fd == -1 || + fstat(pidf->fd, &fstatb) || statb.st_dev != fstatb.st_dev || statb.st_ino != fstatb.st_ino) { - /* The pidfile has been deleted and recreated. Open the new one. */ - close(pidf->fd); + if (pidf->fd != -1) { + /* The pidfile has been deleted and recreated. Open the new one. */ + close(pidf->fd); + } + while ((pidf->fd = open(pidf->path, O_NOFOLLOW | O_WRONLY | O_NONBLOCK)) == -1 && errno == EINTR); if (pidf->fd == -1) return false; } - /* Since we have already written to the pid file, + /* Since we may have already written to the pid file, * we need to reset the file offset and truncate the file. */ - off_t offs = lseek(pidf->fd, 0, SEEK_CUR); - if (offs) { - lseek(pidf->fd, 0, SEEK_SET); - if (ftruncate(pidf->fd, 0)) - log_message(LOG_INFO, "ftruncate error %d - %m", errno); - } + lseek(pidf->fd, 0, SEEK_SET); + if (ftruncate(pidf->fd, 0)) + log_message(LOG_INFO, "ftruncate error %d - %m", errno); } }