summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_main.c3
-rw-r--r--lib/command.c17
-rw-r--r--lib/libfrr.c30
-rw-r--r--lib/libfrr.h2
-rw-r--r--lib/log.c2
-rw-r--r--lib/memory.c10
-rw-r--r--lib/memory.h4
-rw-r--r--lib/sigevent.c2
-rw-r--r--tests/isisd/test_fuzz_isis_tlv.c2
-rw-r--r--tests/lib/cli/common_cli.c2
10 files changed, 62 insertions, 12 deletions
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 3bf9ea02d5..fa8c45b004 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -219,9 +219,6 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
memset(bm, 0, sizeof(*bm));
frr_fini();
-
- if (bgp_debug_count())
- log_memstats_stderr("bgpd");
exit(status);
}
diff --git a/lib/command.c b/lib/command.c
index 45b5593a3e..f47bf81452 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -42,6 +42,7 @@
#include "command_graph.h"
#include "qobj.h"
#include "defaults.h"
+#include "libfrr.h"
DEFINE_MTYPE(LIB, HOST, "Host config")
DEFINE_MTYPE(LIB, STRVEC, "String vector")
@@ -555,6 +556,9 @@ static int config_write_host(struct vty *vty)
else if (!host.motd)
vty_out(vty, "no banner motd\n");
+ if (debug_memstats_at_exit)
+ vty_out(vty, "!\ndebug memstats-at-exit\n");
+
return 1;
}
@@ -2366,6 +2370,17 @@ DEFUN (no_config_log_timestamp_precision,
return CMD_SUCCESS;
}
+DEFUN (debug_memstats,
+ debug_memstats_cmd,
+ "[no] debug memstats-at-exit",
+ NO_STR
+ DEBUG_STR
+ "Print memory type statistics at exit\n")
+{
+ debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
+ return CMD_SUCCESS;
+}
+
int cmd_banner_motd_file(const char *file)
{
int success = CMD_SUCCESS;
@@ -2527,6 +2542,7 @@ void cmd_init(int terminal)
/* Each node's basic commands. */
install_element(VIEW_NODE, &show_version_cmd);
install_element(ENABLE_NODE, &show_startup_config_cmd);
+ install_element(ENABLE_NODE, &debug_memstats_cmd);
if (terminal) {
install_element(VIEW_NODE, &config_list_cmd);
@@ -2560,6 +2576,7 @@ void cmd_init(int terminal)
install_element(CONFIG_NODE, &hostname_cmd);
install_element(CONFIG_NODE, &no_hostname_cmd);
install_element(CONFIG_NODE, &frr_version_defaults_cmd);
+ install_element(CONFIG_NODE, &debug_memstats_cmd);
if (terminal > 0) {
install_element(CONFIG_NODE, &password_cmd);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 255f91ec71..c3ef04c673 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -52,6 +52,8 @@ char frr_zclientpath[256];
static char pidfile_default[256];
static char vtypath_default[256];
+bool debug_memstats_at_exit = 0;
+
static char comb_optstr[256];
static struct option comb_lo[64];
static struct option *comb_next_lo = &comb_lo[0];
@@ -841,6 +843,10 @@ void frr_early_fini(void)
void frr_fini(void)
{
+ FILE *fp;
+ char filename[128];
+ int have_leftovers;
+
hook_call(frr_fini);
/* memory_init -> nothing needed */
@@ -851,4 +857,28 @@ void frr_fini(void)
thread_master_free(master);
closezlog();
/* frrmod_init -> nothing needed / hooks */
+
+ if (!debug_memstats_at_exit)
+ return;
+
+ have_leftovers = log_memstats(stderr, di->name);
+
+ /* in case we decide at runtime that we want exit-memstats for
+ * a daemon, but it has no stderr because it's daemonized
+ * (only do this if we actually have something to print though)
+ */
+ if (!have_leftovers)
+ return;
+
+ snprintf(filename, sizeof(filename),
+ "/tmp/frr-memstats-%s-%llu-%llu",
+ di->name,
+ (unsigned long long)getpid(),
+ (unsigned long long)time(NULL));
+
+ fp = fopen(filename, "w");
+ if (fp) {
+ log_memstats(fp, di->name);
+ fclose(fp);
+ }
}
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 8a15d168a1..f7d69eecb3 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -121,4 +121,6 @@ extern const char frr_moduledir[];
extern char frr_protoname[];
extern char frr_protonameinst[];
+extern bool debug_memstats_at_exit;
+
#endif /* _ZEBRA_FRR_H */
diff --git a/lib/log.c b/lib/log.c
index 5c89e7080e..5b2429b31a 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -701,7 +701,7 @@ void _zlog_assert_failed(const char *assertion, const char *file,
assertion, file, line, (function ? function : "?"));
zlog_backtrace(LOG_CRIT);
zlog_thread_info(LOG_CRIT);
- log_memstats_stderr("log");
+ log_memstats(stderr, "log");
abort();
}
diff --git a/lib/memory.c b/lib/memory.c
index 0ccc204002..c684c7605c 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -104,6 +104,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg)
}
struct exit_dump_args {
+ FILE *fp;
const char *prefix;
int error;
};
@@ -113,7 +114,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
struct exit_dump_args *eda = arg;
if (!mt) {
- fprintf(stderr,
+ fprintf(eda->fp,
"%s: showing active allocations in "
"memory group %s\n",
eda->prefix, mg->name);
@@ -122,15 +123,16 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
char size[32];
eda->error++;
snprintf(size, sizeof(size), "%10zu", mt->size);
- fprintf(stderr, "%s: memstats: %-30s: %6zu * %s\n",
+ fprintf(eda->fp, "%s: memstats: %-30s: %6zu * %s\n",
eda->prefix, mt->name, mt->n_alloc,
mt->size == SIZE_VAR ? "(variably sized)" : size);
}
return 0;
}
-void log_memstats_stderr(const char *prefix)
+int log_memstats(FILE *fp, const char *prefix)
{
- struct exit_dump_args eda = {.prefix = prefix, .error = 0};
+ struct exit_dump_args eda = { .fp = fp, .prefix = prefix, .error = 0 };
qmem_walk(qmem_exit_walker, &eda);
+ return eda.error;
}
diff --git a/lib/memory.h b/lib/memory.h
index d5facad583..132d4abd30 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -18,6 +18,7 @@
#define _QUAGGA_MEMORY_H
#include <stdlib.h>
+#include <stdio.h>
#include <frratomic.h>
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
@@ -194,7 +195,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
* last value from qmem_walk_fn. */
typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
extern int qmem_walk(qmem_walk_fn *func, void *arg);
-extern void log_memstats_stderr(const char *);
+extern int log_memstats(FILE *fp, const char *);
+#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
extern void memory_oom(size_t size, const char *name);
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 2a04fa23cb..d55f368dfb 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -245,7 +245,7 @@ core_handler(int signo
#endif
);
/* dump memory stats on core */
- log_memstats_stderr("core_handler");
+ log_memstats(stderr, "core_handler");
abort();
}
diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c
index 6727e663f5..e61e9639ee 100644
--- a/tests/isisd/test_fuzz_isis_tlv.c
+++ b/tests/isisd/test_fuzz_isis_tlv.c
@@ -23,7 +23,7 @@ static bool atexit_registered;
static void show_meminfo_at_exit(void)
{
- log_memstats_stderr("isis fuzztest");
+ log_memstats(stderr, "isis fuzztest");
}
static int comp_line(const void *p1, const void *p2)
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index 77f1610fe2..0fd2f80a39 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -53,7 +53,7 @@ static void vty_do_exit(int isexit)
thread_master_free(master);
closezlog();
- log_memstats_stderr("testcli");
+ log_memstats(stderr, "testcli");
if (!isexit)
exit(0);
}