Commit 0a52901965 for frr

commit 0a52901965da7599c7d2ebb9b6baee66d72eed95
Author: Philippe Guibert <philippe.guibert@6wind.com>
Date:   Thu Oct 22 15:46:23 2026 +0200

    lib: add a zebra disconnected callback to zclient

    A daemon is notified when its connection to zebra is established, with
    the zebra_connected callback, but not when the connection is lost. When
    zebra exits, the daemon keeps the state it got from zebra, for instance
    the SRv6 locators and SIDs of bgp, and keeps advertising it, although
    the exited zebra has lost it.

    When reading from or writing to zebra fails, zclient_failed() closes
    the socket and schedules a new connection, without notifying the
    daemon.

    Fix this by adding a zebra_disconnected callback to zclient, called by
    zclient_failed() once the socket is closed. The callback is called from
    an event, because zclient_failed() may be called while the daemon is
    sending a message to zebra, for instance in the middle of a walk of its
    tables. The event is cancelled when the zclient is stopped.

    Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>

diff --git a/lib/zclient.c b/lib/zclient.c
index e411937997..cd4482256e 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -262,6 +262,7 @@ void zclient_stop(struct zclient *zclient)
 	event_cancel(&zclient->t_read);
 	event_cancel(&zclient->t_connect);
 	event_cancel(&zclient->t_write);
+	event_cancel(&zclient->t_disconnected);

 	/* Reset streams. */
 	stream_reset(zclient->ibuf);
@@ -340,10 +341,24 @@ int zclient_socket_connect(struct zclient *zclient)
 	return sock;
 }

+static void zclient_disconnected(struct event *event)
+{
+	struct zclient *zclient = EVENT_ARG(event);
+
+	(*zclient->zebra_disconnected)(zclient);
+}
+
 static enum zclient_send_status zclient_failed(struct zclient *zclient)
 {
 	zclient->fail++;
 	zclient_stop(zclient);
+	/*
+	 * Notify the daemon from an event: zclient_failed() may be called while
+	 * the daemon is sending a message to zebra.
+	 */
+	if (zclient->zebra_disconnected)
+		event_add_event(zclient->master, zclient_disconnected, zclient, 0,
+				&zclient->t_disconnected);
 	zclient_event(ZCLIENT_CONNECT, zclient);
 	return ZCLIENT_SEND_FAILURE;
 }
diff --git a/lib/zclient.h b/lib/zclient.h
index f2b57be864..02e8b067af 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -353,6 +353,9 @@ struct zclient {
 	/* Thread to write buffered data to zebra. */
 	struct event *t_write;

+	/* Thread to notify the daemon that the connection to zebra is lost. */
+	struct event *t_disconnected;
+
 	/* Redistribute information. */
 	uint8_t redist_default; /* clients protocol */
 	unsigned short instance;
@@ -364,6 +367,7 @@ struct zclient {

 	/* Pointer to the callback functions. */
 	void (*zebra_connected)(struct zclient *);
+	void (*zebra_disconnected)(struct zclient *client);
 	void (*zebra_capabilities)(struct zclient_capabilities *cap);

 	/*