Commit b746e39ff3 for frr

commit b746e39ff3eabcfbe01850f17956b15ac6557722
Author: Sougata Barik <sougatab@nvidia.com>
Date:   Tue Aug 4 06:07:53 2026 +0530

    lib: LTTng trace for deferred link-local BFD session install

    Adds observability for the #5131052 fix path: _bfd_sess_valid() defers
    the install of a single-hop IPv6 link-local BFD session when its outgoing
    interface is not yet known. Each deferral is now visible on the
    frr_libfrr:bfd_sess_defer_linklocal_without_intf tracepoint, which tells
    us exactly which session and VRF is being held back and how often, before
    it later installs with a unique per-interface key.

    Files:
      lib/libfrr_trace.h       : new TRACEPOINT_EVENT for the defer event
                                 (fields: bsp_ptr, vrf_id, family, dst, src).
      lib/bfd.c                : #include "libfrr_trace.h" and the matching
                                 frrtrace() call inside _bfd_sess_valid().
      tools/frr_babeltrace.py  : parser for the new event.

    No functional change; the tracepoint degrades to (void)0 when HAVE_LTTNG
    is not compiled in.  Building the fix-path tracepoint requires the usual
    opt-in configure flag ('./configure --enable-lttng') documented in
    doc/developer/tracing.rst.  The stock upstream .deb build is not modified
    and remains LTTng-off.

    Ticket: #5131052
    Signed-off-by: Sougata Barik <sougatab@nvidia.com>

diff --git a/lib/bfd.c b/lib/bfd.c
index f67e69c7ad..d2e4b2f0de 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -20,6 +20,7 @@
 #include "lib/json.h"
 #include "bfd.h"
 #include "bfdd/bfd.h"
+#include "libfrr_trace.h"

 DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info");
 DEFINE_MTYPE_STATIC(LIB, BFD_SOURCE, "BFD source cache");
@@ -478,6 +479,10 @@ static bool _bfd_sess_valid(const struct bfd_session_params *bsp)
 	if (!bsp->args.mhop && bsp->args.family == AF_INET6 &&
 	    IN6_IS_ADDR_LINKLOCAL(&bsp->args.dst) &&
 	    bsp->args.ifnamelen == 0) {
+		frrtrace(5, frr_libfrr, bfd_sess_defer_linklocal_without_intf,
+			 (void *)bsp, (uint32_t)bsp->args.vrf_id,
+			 (uint8_t)bsp->args.family,
+			 &bsp->args.dst, &bsp->args.src);
 		if (bsglobal.debugging)
 			zlog_debug("%s: single-hop link-local session without interface; deferring install",
 				   __func__);
diff --git a/lib/libfrr_trace.h b/lib/libfrr_trace.h
index 62a4034aa5..ddad49cda6 100644
--- a/lib/libfrr_trace.h
+++ b/lib/libfrr_trace.h
@@ -28,6 +28,38 @@

 /* clang-format off */

+/*
+ * Fired by _bfd_sess_valid() (lib/bfd.c) when a single-hop IPv6 link-local
+ * BFD session is deferred because its outgoing interface is not yet known
+ * (the #5131052 fix). One event per deferral tells us exactly which session
+ * is being held back and how often, before it later installs with a unique
+ * per-interface key.
+ *
+ *   bsp_ptr : pointer of the struct bfd_session_params (per-session id)
+ *   vrf_id  : VRF id recorded on the session params
+ *   family  : AF_INET (2) or AF_INET6 (10); expected AF_INET6 for this event
+ *   dst/src : 16-byte in6_addr link-local pair (only first 4 bytes for AF_INET)
+ */
+TRACEPOINT_EVENT(
+	frr_libfrr,
+	bfd_sess_defer_linklocal_without_intf,
+	TP_ARGS(
+		void *, bsp,
+		uint32_t, vrf_id,
+		uint8_t, family,
+		const void *, dst,
+		const void *, src
+	),
+	TP_FIELDS(
+		ctf_integer_hex(intptr_t, bsp_ptr, (intptr_t)bsp)
+		ctf_integer(uint32_t, vrf_id, vrf_id)
+		ctf_integer(uint8_t, family, family)
+		ctf_array(uint8_t, dst, dst ? (const uint8_t *)dst : (const uint8_t[16]) {0}, 16)
+		ctf_array(uint8_t, src, src ? (const uint8_t *)src : (const uint8_t[16]) {0}, 16)
+	)
+)
+TRACEPOINT_LOGLEVEL(frr_libfrr, bfd_sess_defer_linklocal_without_intf, TRACE_INFO)
+
 TRACEPOINT_EVENT(
 	frr_libfrr,
 	hash_get,
diff --git a/tools/frr_babeltrace.py b/tools/frr_babeltrace.py
index 8f15032dff..29831b60b5 100755
--- a/tools/frr_babeltrace.py
+++ b/tools/frr_babeltrace.py
@@ -782,6 +782,19 @@ def parse_frr_bfd_stats_error(event):
     parse_event(event, field_parsers)


+def parse_frr_libfrr_bfd_sess_defer_linklocal_without_intf(event):
+    """Parse BFD client-lib single-hop link-local defer events (lib/bfd.c)."""
+    family = event.get("family", 0)
+    field_parsers = {
+        "family": lambda x: "IPv4" if x == socket.AF_INET
+                            else "IPv6" if x == socket.AF_INET6
+                            else f"AF_{x}",
+        "dst": lambda x: print_bfd_addr(x, family) if family else "N/A",
+        "src": lambda x: print_bfd_addr(x, family) if family else "N/A",
+    }
+    parse_event(event, field_parsers)
+
+
 ############################ BFD parsers - end #################################


@@ -2000,6 +2013,8 @@ def main():
         "frr_bfd:ptm_config_refcount_error": parse_frr_bfd_ptm_config_refcount_error,
         "frr_bfd:packet_send_error": parse_frr_bfd_packet_send_error,
         "frr_bfd:stats_error": parse_frr_bfd_stats_error,
+        "frr_libfrr:bfd_sess_defer_linklocal_without_intf":
+            parse_frr_libfrr_bfd_sess_defer_linklocal_without_intf,
     }

     # get the trace path from the first command line argument