From 24f8a1e1220e5f1fa762e60669ef1215cc15d138 Mon Sep 17 00:00:00 2001
From: Quentin Armitage <quentin@armitage.org.uk>
Date: Sun, 17 Apr 2022 14:52:44 +0100
Subject: [PATCH] vrrp: Resolve segfault when enable_snmp_vrrp is added at a
 reload

Signed-off-by: Quentin Armitage <quentin@armitage.org.uk>
Conflict: NA
Reference: https://github.com/acassen/keepalived/commit/24f8a1e1220e5f1fa762e60669ef1215cc15d138
---
 keepalived/core/snmp.c         |  1 +
 keepalived/include/vrrp_snmp.h |  3 ++-
 keepalived/vrrp/vrrp_daemon.c  | 10 ++++++++--
 keepalived/vrrp/vrrp_snmp.c    | 18 +++++++++---------
 4 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/keepalived/core/snmp.c b/keepalived/core/snmp.c
index 421484e..2aae126 100644
--- a/keepalived/core/snmp.c
+++ b/keepalived/core/snmp.c
@@ -496,6 +496,7 @@ snmp_agent_close(bool base_mib)
 	if (base_mib)
 		snmp_unregister_mib(global_oid, OID_LENGTH(global_oid));
 	snmp_shutdown(global_name);
+	shutdown_agent();
 
 	snmp_running = false;
 }
diff --git a/keepalived/include/vrrp_snmp.h b/keepalived/include/vrrp_snmp.h
index f75d32f..028356a 100644
--- a/keepalived/include/vrrp_snmp.h
+++ b/keepalived/include/vrrp_snmp.h
@@ -26,6 +26,7 @@
 
 #include "config.h"
 
+#include "global_data.h"
 #ifdef _WITH_SNMP_RFC_
 #include "timer.h"
 #endif
@@ -74,7 +75,7 @@ extern timeval_t snmp_vrrp_start_time;
 
 /* Prototypes */
 extern void vrrp_snmp_agent_init(const char *);
-extern void vrrp_snmp_agent_close(void);
+extern void vrrp_snmp_agent_close(const data_t *);
 
 #ifdef _WITH_SNMP_VRRP_
 extern void vrrp_snmp_instance_trap(vrrp_t *);
diff --git a/keepalived/vrrp/vrrp_daemon.c b/keepalived/vrrp/vrrp_daemon.c
index 036f9f2..5568a52 100644
--- a/keepalived/vrrp/vrrp_daemon.c
+++ b/keepalived/vrrp/vrrp_daemon.c
@@ -286,7 +286,7 @@ vrrp_terminate_phase2(int exit_status)
 	    global_data->enable_snmp_rfcv3 ||
 #endif
 	    snmp_option)
-		vrrp_snmp_agent_close();
+		vrrp_snmp_agent_close(global_data);
 #endif
 
 #ifdef _WITH_LVS_
@@ -554,13 +554,19 @@ start_vrrp(data_t *prev_global_data)
 		     global_data->enable_snmp_rfcv3 ||
 #endif
 		     snmp_option)) {
-			if (reload)
+			if (snmp_running)
 				snmp_epoll_info(master);
 			else
 				vrrp_snmp_agent_init(global_data->snmp_socket);
 #ifdef _WITH_SNMP_RFC_
 			snmp_vrrp_start_time = time_now;
 #endif
+		} else {
+// We have a problem at reload if VRRP had SNMP and checker didn't, but now checker does.
+// Also race condition if changing so checker does and we dont, from other way round.
+// SOLUTION: Stop snmp before reload and start afterwards. ? A race anyway
+			if (snmp_running)
+				vrrp_snmp_agent_close(old_global_data);
 		}
 #endif
 
diff --git a/keepalived/vrrp/vrrp_snmp.c b/keepalived/vrrp/vrrp_snmp.c
index fc7749b..aa4c426 100644
--- a/keepalived/vrrp/vrrp_snmp.c
+++ b/keepalived/vrrp/vrrp_snmp.c
@@ -4471,15 +4471,15 @@ vrrp_rfcv3_snmp_proto_err_notify(vrrp_t *vrrp)
 #endif
 
 static bool
-vrrp_handles_global_oid(void)
+vrrp_handles_global_oid(const data_t *global_data_in_use)
 {
 #ifdef _WITH_SNMP_VRRP_
-	if (global_data->enable_snmp_vrrp) {
+	if (global_data_in_use->enable_snmp_vrrp) {
 #ifdef _WITH_LVS_
 		if (!running_checker())
 			return true;
 #ifdef _WITH_SNMP_CHECKER_
-		if (!global_data->enable_snmp_checker)
+		if (!global_data_in_use->enable_snmp_checker)
 			return true;
 #endif
 #else
@@ -4498,7 +4498,7 @@ vrrp_snmp_agent_init(const char *snmp_socket_name)
 		return;
 
 	/* We let the check process handle the global OID if it is running and with snmp */
-	snmp_agent_init(snmp_socket_name, vrrp_handles_global_oid());
+	snmp_agent_init(snmp_socket_name, vrrp_handles_global_oid(global_data));
 
 #ifdef _WITH_SNMP_VRRP_
 	if (global_data->enable_snmp_vrrp)
@@ -4524,22 +4524,22 @@ vrrp_snmp_agent_init(const char *snmp_socket_name)
 }
 
 void
-vrrp_snmp_agent_close(void)
+vrrp_snmp_agent_close(const data_t *global_data_in_use)
 {
 	if (!snmp_running)
 		return;
 
 #ifdef _WITH_SNMP_VRRP_
-	if (global_data->enable_snmp_vrrp)
+	if (global_data_in_use->enable_snmp_vrrp)
 		snmp_unregister_mib(vrrp_oid, OID_LENGTH(vrrp_oid));
 #endif
 #ifdef _WITH_SNMP_RFCV2_
-	if (global_data->enable_snmp_rfcv2)
+	if (global_data_in_use->enable_snmp_rfcv2)
 		snmp_unregister_mib(vrrp_rfcv2_oid, OID_LENGTH(vrrp_rfcv2_oid));
 #endif
 #ifdef _WITH_SNMP_RFCV3_
-	if (global_data->enable_snmp_rfcv3)
+	if (global_data_in_use->enable_snmp_rfcv3)
 		snmp_unregister_mib(vrrp_rfcv3_oid, OID_LENGTH(vrrp_rfcv3_oid));
 #endif
-	snmp_agent_close(vrrp_handles_global_oid());
+	snmp_agent_close(vrrp_handles_global_oid(global_data_in_use));
 }
-- 
2.23.0

