Blob Blame History Raw
From fce93460597d27a86798c57ec410f63e4bd33be9 Mon Sep 17 00:00:00 2001
From: YAMAMOTO Masaya <pandax381@gmail.com>
Date: Fri, 7 Jul 2017 19:27:16 +0900
Subject: [PATCH 3/8] Implement comparison of checkers

---
 keepalived/check/check_api.c    | 29 ++++++++++++++++++++++++-
 keepalived/check/check_daemon.c |  7 +++++-
 keepalived/check/check_dns.c    | 24 +++++++++++++++++++--
 keepalived/check/check_http.c   | 35 +++++++++++++++++++++++++++++-
 keepalived/check/check_misc.c   | 22 ++++++++++++++++++-
 keepalived/check/check_smtp.c   | 33 +++++++++++++++++++++++++++-
 keepalived/check/check_tcp.c    | 22 +++++++++++++++++--
 keepalived/check/ipwrapper.c    | 38 +++++++++++++++++++++++++--------
 keepalived/include/check_api.h  |  5 +++++
 9 files changed, 197 insertions(+), 18 deletions(-)

diff --git a/keepalived/check/check_api.c b/keepalived/check/check_api.c
index b7081fd0..a722fc84 100644
--- a/keepalived/check/check_api.c
+++ b/keepalived/check/check_api.c
@@ -42,8 +42,9 @@
 #include "check_dns.h"
 
 /* Global vars */
-static checker_id_t ncheckers = 0;
+checker_id_t ncheckers = 0;
 list checkers_queue;
+list old_checkers_queue;
 
 /* free checker data */
 static void
@@ -80,6 +81,7 @@ dump_conn_opts(void *data)
 void
 queue_checker(void (*free_func) (void *), void (*dump_func) (void *)
 	      , int (*launch) (thread_t *)
+	      , int (*compare) (void *, void *)
 	      , void *data
 	      , conn_opts_t *co)
 {
@@ -96,6 +98,7 @@ queue_checker(void (*free_func) (void *), void (*dump_func) (void *)
 	checker->free_func = free_func;
 	checker->dump_func = dump_func;
 	checker->launch = launch;
+	checker->compare = compare;
 	checker->vs = vs;
 	checker->rs = rs;
 	checker->data = data;
@@ -117,6 +120,30 @@ queue_checker(void (*free_func) (void *), void (*dump_func) (void *)
 	}
 }
 
+int
+compare_conn_opts(conn_opts_t *a, conn_opts_t *b)
+{
+	if (a == b)
+		return 0;
+
+	if (!a || !b)
+		goto err;
+	if (!sockstorage_equal(&a->dst, &b->dst))
+		goto err;
+	if (!sockstorage_equal(&a->bindto, &b->bindto))
+		goto err;
+	//if (a->connection_to != b->connection_to)
+	//	goto err;
+#ifdef _WITH_SO_MARK_
+	if (a->fwmark != b->fwmark)
+		goto err;
+#endif
+
+	return  0;
+err:
+	return -1;
+}
+
 static void
 checker_set_dst_port(struct sockaddr_storage *dst, uint16_t port)
 {
diff --git a/keepalived/check/check_daemon.c b/keepalived/check/check_daemon.c
index a3ff8cab..462360e6 100644
--- a/keepalived/check/check_daemon.c
+++ b/keepalived/check/check_daemon.c
@@ -233,7 +233,11 @@ reload_check_thread(__attribute__((unused)) thread_t * thread)
 	thread_cleanup_master(master);
 	free_global_data(global_data);
 
-	free_checkers_queue();
+	/* Save previous checker data */
+	old_checkers_queue = checkers_queue;
+	checkers_queue = NULL;
+	ncheckers = 0;
+
 	free_ssl();
 	ipvs_stop();
 
@@ -246,6 +250,7 @@ reload_check_thread(__attribute__((unused)) thread_t * thread)
 
 	/* free backup data */
 	free_check_data(old_check_data);
+	free_list(&old_checkers_queue);
 	UNSET_RELOAD;
 
 	return 0;
diff --git a/keepalived/check/check_dns.c b/keepalived/check/check_dns.c
index 96328027..84a5f56d 100644
--- a/keepalived/check/check_dns.c
+++ b/keepalived/check/check_dns.c
@@ -388,6 +388,26 @@ dns_dump(void *data)
 	log_message(LOG_INFO, "   Name = %s", dns_check->name);
 }
 
+static int
+dns_compare(void *a, void *b)
+{
+	dns_check_t *old = CHECKER_DATA(a);
+	dns_check_t *new = CHECKER_DATA(b);
+
+	if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0)
+		goto err;
+	if (old->retry != new->retry)
+		goto err;
+	if (strcmp(old->type, new->type) != 0)
+		goto err;
+	if (strcmp(old->name, new->name) != 0)
+		goto err;
+
+	return  0;
+err:
+	return -1;
+}
+
 static void
 dns_check_handler(__attribute__((unused)) vector_t * strvec)
 {
@@ -396,8 +416,8 @@ dns_check_handler(__attribute__((unused)) vector_t * strvec)
 	dns_check->attempts = 0;
 	dns_check->type = DNS_DEFAULT_TYPE;
 	dns_check->name = DNS_DEFAULT_NAME;
-	queue_checker(dns_free, dns_dump, dns_connect_thread, dns_check,
-		      CHECKER_NEW_CO());
+	queue_checker(dns_free, dns_dump, dns_connect_thread,
+		      dns_compare, dns_check, CHECKER_NEW_CO());
 }
 
 static void
diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c
index 05e29b23..c2089a3b 100644
--- a/keepalived/check/check_http.c
+++ b/keepalived/check/check_http.c
@@ -123,6 +123,38 @@ alloc_http_get(char *proto)
 	return http_get_chk;
 }
 
+static int
+compare_http_get_check(void *a, void *b)
+{
+	http_checker_t *old = CHECKER_DATA(a);
+	http_checker_t *new = CHECKER_DATA(b);
+	size_t n;
+	url_t *u1, *u2;
+
+	if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0)
+		goto err;
+	if (old->nb_get_retry != new->nb_get_retry)
+		goto err;
+	if (old->delay_before_retry != new->delay_before_retry)
+		goto err;
+	if (LIST_SIZE(old->url) != LIST_SIZE(new->url))
+		goto err;
+	for (n = 0; n < LIST_SIZE(new->url); n++) {
+		u1 = (url_t *)list_element(old->url, n);
+		u2 = (url_t *)list_element(new->url, n);
+		if (strcmp(u1->path, u2->path) != 0)
+			goto err;
+		if (strcmp(u1->digest, u2->digest) != 0)
+			goto err;
+		if (u1->status_code != u2->status_code)
+			goto err;
+	}
+
+	return  0;
+err:
+	return -1;
+}
+
 static void
 http_get_handler(vector_t *strvec)
 {
@@ -132,7 +164,8 @@ http_get_handler(vector_t *strvec)
 	/* queue new checker */
 	http_get_chk = alloc_http_get(str);
 	queue_checker(free_http_get_check, dump_http_get_check,
-		      http_connect_thread, http_get_chk, CHECKER_NEW_CO());
+		      http_connect_thread, compare_http_get_check,
+		      http_get_chk, CHECKER_NEW_CO());
 }
 
 static void
diff --git a/keepalived/check/check_misc.c b/keepalived/check/check_misc.c
index 10ac1e23..311a1127 100644
--- a/keepalived/check/check_misc.c
+++ b/keepalived/check/check_misc.c
@@ -72,6 +72,26 @@ dump_misc_check(void *data)
 	log_message(LOG_INFO, "   insecure = %s", misck_checker->insecure ? "Yes" : "No");
 }
 
+static int
+compare_misc_check(void *a, void *b)
+{
+	misc_checker_t *old = CHECKER_DATA(a);
+	misc_checker_t *new = CHECKER_DATA(b);
+
+	if (strcmp(old->path, new->path) != 0)
+		goto err;
+	if (old->timeout != new->timeout)
+		goto err;
+	if (old->dynamic != new->dynamic)
+		goto err;
+	if (old->uid != new->uid || new->gid != new->gid)
+		goto err;
+
+	return  0;
+err:
+	return -1;
+}
+
 static void
 misc_check_handler(__attribute__((unused)) vector_t *strvec)
 {
@@ -149,7 +169,7 @@ log_message(LOG_INFO, "Setting uid.gid");
 	}
 
 	/* queue new checker */
-	queue_checker(free_misc_check, dump_misc_check, misc_check_thread, misck_checker, NULL);
+	queue_checker(free_misc_check, dump_misc_check, misc_check_thread, compare_misc_check, misck_checker, NULL);
 	misck_checker = NULL;
 log_message(LOG_INFO, "Leaving misc_end_handler");
 }
diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c
index 901b77f5..e19511cc 100644
--- a/keepalived/check/check_smtp.c
+++ b/keepalived/check/check_smtp.c
@@ -82,6 +82,37 @@ dump_smtp_check(void *data)
 	dump_list(smtp_checker->host);
 }
 
+static int
+compare_smtp_check(void *a, void *b)
+{
+	smtp_checker_t *old = CHECKER_DATA(a);
+	smtp_checker_t *new = CHECKER_DATA(b);
+	size_t n;
+	smtp_host_t *h1, *h2;
+
+	if (strcmp(old->helo_name, new->helo_name) != 0)
+		goto err;
+	if (old->retry != new->retry)
+		goto err;
+	if (old->db_retry != new->db_retry)
+		goto err;
+	if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0)
+		goto err;
+	if (LIST_SIZE(old->host) != LIST_SIZE(new->host))
+		goto err;
+	for (n = 0; n < LIST_SIZE(new->host); n++) {
+		h1 = (smtp_host_t *)list_element(old->host, n);
+		h2 = (smtp_host_t *)list_element(new->host, n);
+		if (compare_conn_opts(h1, h2) != 0) {
+			goto err;
+		}
+	}
+
+	return  0;
+err:
+	return -1;
+}
+
 /* Allocates a default host structure */
 static smtp_host_t *
 smtp_alloc_host(void)
@@ -136,7 +167,7 @@ smtp_check_handler(__attribute__((unused)) vector_t *strvec)
 	 *               void *data, conn_opts_t *)
 	 */
 	queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread,
-		      smtp_checker, smtp_checker->default_co);
+		      compare_smtp_check, smtp_checker, smtp_checker->default_co);
 
 	/*
 	 * Last, allocate the list that will hold all the per host
diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c
index 078ba705..026a0e3c 100644
--- a/keepalived/check/check_tcp.c
+++ b/keepalived/check/check_tcp.c
@@ -62,6 +62,24 @@ dump_tcp_check(void *data)
 	}
 }
 
+static int
+compare_tcp_check(void *a, void *b)
+{
+	tcp_check_t *old = CHECKER_DATA(a);
+	tcp_check_t *new = CHECKER_DATA(b);
+
+	if (compare_conn_opts(CHECKER_CO(a), CHECKER_CO(b)) != 0)
+		goto err;
+	if (old->n_retry != new->n_retry)
+		goto err;
+	if (old->delay_before_retry != new->delay_before_retry)
+		goto err;
+
+	return  0;
+err:
+	return -1;
+}
+
 static void
 tcp_check_handler(__attribute__((unused)) vector_t *strvec)
 {
@@ -72,8 +90,8 @@ tcp_check_handler(__attribute__((unused)) vector_t *strvec)
 	tcp_check->delay_before_retry = 1 * TIMER_HZ;
 
 	/* queue new checker */
-	queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread
-		      ,tcp_check, CHECKER_NEW_CO());
+	queue_checker(free_tcp_check, dump_tcp_check, tcp_connect_thread,
+		      compare_tcp_check, tcp_check, CHECKER_NEW_CO());
 }
 
 static void
diff --git a/keepalived/check/ipwrapper.c b/keepalived/check/ipwrapper.c
index 6acf18ba..49262e25 100644
--- a/keepalived/check/ipwrapper.c
+++ b/keepalived/check/ipwrapper.c
@@ -626,20 +626,40 @@ rs_exist(real_server_t * old_rs, list l)
 static void
 migrate_failed_checkers(real_server_t *old_rs, real_server_t *new_rs)
 {
-	element e;
-	checker_t *checker;
+	list l;
+	element e, e1;
+	checker_t *old_c, *new_c;
 	checker_id_t *id;
 
-	/* Notes: It's a provisional implementation */
-	(void)old_rs;
+	l = alloc_list(NULL, NULL);
+	for (e = LIST_HEAD(old_checkers_queue); e; ELEMENT_NEXT(e)) {
+		old_c = ELEMENT_DATA(e);
+		if (old_c->rs == old_rs) {
+			list_add(l, old_c);
+		}
+	}
+
+	if (LIST_ISEMPTY(l))
+		goto end;
+
 	for (e = LIST_HEAD(checkers_queue); e; ELEMENT_NEXT(e)) {
-		checker = ELEMENT_DATA(e);
-		if (checker->rs == new_rs) {
-			id = (checker_id_t *) MALLOC(sizeof(checker_id_t));
-			*id = checker->id;
-			list_add(new_rs->failed_checkers, id);
+		new_c = ELEMENT_DATA(e);
+		if (new_c->rs != new_rs || !new_c->compare)
+			continue;
+		for (e1 = LIST_HEAD(l); e1; ELEMENT_NEXT(e1)) {
+			old_c = ELEMENT_DATA(e1);
+			if (old_c->compare == new_c->compare && new_c->compare(old_c, new_c) == 0) {
+				if (svr_checker_up(old_c->id, old_rs) == 0) {
+					id = (checker_id_t *) MALLOC(sizeof(checker_id_t));
+					*id = old_c->id;
+					list_add(new_rs->failed_checkers, id);
+				}
+				break;
+			}
 		}
 	}
+end:
+	free_list(&l);
 }
 
 /* Clear the diff rs of the old vs */
diff --git a/keepalived/include/check_api.h b/keepalived/include/check_api.h
index 359c794a..4a10a36b 100644
--- a/keepalived/include/check_api.h
+++ b/keepalived/include/check_api.h
@@ -36,6 +36,7 @@ typedef struct _checker {
 	void				(*free_func) (void *);
 	void				(*dump_func) (void *);
 	int				(*launch) (struct _thread *);
+	int				(*compare) (void *, void *);
 	virtual_server_t		*vs;	/* pointer to the checker thread virtualserver */
 	real_server_t			*rs;	/* pointer to the checker thread realserver */
 	void				*data;
@@ -46,7 +47,9 @@ typedef struct _checker {
 } checker_t;
 
 /* Checkers queue */
+extern checker_id_t ncheckers;
 extern list checkers_queue;
+extern list old_checkers_queue;
 
 /* utility macro */
 #define CHECKER_ARG(X) ((X)->data)
@@ -68,8 +71,10 @@ extern void init_checkers_queue(void);
 extern void dump_conn_opts(void *);
 extern void queue_checker(void (*free_func) (void *), void (*dump_func) (void *)
 			  , int (*launch) (thread_t *)
+			  , int (*compare) (void *, void *)
 			  , void *
 			  , conn_opts_t *);
+extern int  compare_conn_opts(conn_opts_t *, conn_opts_t *);
 extern void dump_checkers_queue(void);
 extern void free_checkers_queue(void);
 extern void register_checkers_thread(void);
-- 
2.20.1