Commit 024f6e4f37 for frr

commit 024f6e4f3784910aeb48a3876784869292cd176c
Author: Jafar Al-Gharaibeh <to.jafar@gmail.com>
Date:   Thu Oct 1 01:22:37 2026 -0500

    lib: allocate nb_node xpath to its exact length

    struct nb_node embedded a fixed char xpath[XPATH_MAXLEN] (1024 bytes),
    which made each northbound node 1232 bytes even though the longest data
    path in any FRR YANG module is 211 characters (average 50-120).

    Store the path as an allocated string instead. The field is only read
    after nb_node_new_cb() fills it in, so no other code changes are needed.
    Track the strings under a separate "Northbound Node XPath" mtype so
    `show memory` still accounts for them.

    Northbound memory (`show memory` on freshly started daemons):
    ```
        daemon     before    after     saved
        mgmtd       1374K     310K    1064K (77%)
        zebra       1057K     236K     821K (78%)
        staticd      139K      33K     106K (76%)
        ripd         441K      97K     344K (78%)
        ripngd       318K      70K     249K (78%)
        ospfd        306K      68K     239K (78%)
        ospf6d       311K      69K     242K (78%)
        isisd        764K     171K     593K (78%)
        fabricd      241K      52K     189K (78%)
        bgpd         412K      95K     317K (77%)
        pimd         470K     113K     357K (76%)
        pim6d        470K     113K     357K (76%)
        ldpd         139K      29K     110K (79%)
        nhrpd        156K      33K     123K (79%)
        eigrpd       360K      79K     280K (78%)
        babeld       156K      33K     123K (79%)
        sharpd       235K      51K     184K (78%)
        pbrd         156K      33K     123K (79%)
        bfdd         446K      99K     346K (78%)
        vrrpd        205K      44K     160K (78%)
        pathd        208K      45K     163K (78%)
        total       8365K    1875K    6490K (78%)
    ```
    Signed-off-by: Jafar Al-Gharaibeh <jafar@atcorp.com>

diff --git a/lib/northbound.c b/lib/northbound.c
index 3c6fb0b8b5..f8c7787152 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -22,6 +22,7 @@
 #include "frrstr.h"

 DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node");
+DEFINE_MTYPE_STATIC(LIB, NB_NODE_XPATH, "NB XPath");
 DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Config");
 DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Config Entry");
 DEFINE_MTYPE_STATIC(LIB, NB_TRANS, "NB transaction");
@@ -79,11 +80,12 @@ static int nb_node_new_cb(const struct lysc_node *snode, void *arg)
 	struct nb_node *nb_node;
 	struct lysc_node *sparent, *sparent_list;
 	struct frr_yang_module_info *module;
+	char xpath[XPATH_MAXLEN];

 	module = (struct frr_yang_module_info *)arg;
 	nb_node = XCALLOC(MTYPE_NB_NODE, sizeof(*nb_node));
-	yang_snode_get_path(snode, YANG_PATH_DATA, nb_node->xpath,
-			    sizeof(nb_node->xpath));
+	yang_snode_get_path(snode, YANG_PATH_DATA, xpath, sizeof(xpath));
+	nb_node->xpath = XSTRDUP(MTYPE_NB_NODE_XPATH, xpath);
 	nb_node->priority = NB_DFLT_PRIORITY;
 	sparent = yang_snode_real_parent(snode);
 	if (sparent)
@@ -163,6 +165,7 @@ static int nb_node_del_cb(const struct lysc_node *snode, void *arg)
 	nb_node = snode->priv;
 	if (nb_node) {
 		((struct lysc_node *)snode)->priv = NULL;
+		XFREE(MTYPE_NB_NODE_XPATH, nb_node->xpath);
 		XFREE(MTYPE_NB_NODE, nb_node);
 	}

diff --git a/lib/northbound.h b/lib/northbound.h
index 5229d2950c..c986d1dccd 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -664,8 +664,8 @@ struct nb_node {
 	/* Back pointer to the libyang schema node. */
 	const struct lysc_node *snode;

-	/* Data path of this YANG node. */
-	char xpath[XPATH_MAXLEN];
+	/* Data path of this YANG node (allocated to its exact length). */
+	char *xpath;

 	/* Priority - lower priorities are processed first. */
 	uint32_t priority;