diff options
| -rw-r--r-- | bgpd/bgp_main.c | 3 | ||||
| -rw-r--r-- | lib/command.c | 17 | ||||
| -rw-r--r-- | lib/libfrr.c | 30 | ||||
| -rw-r--r-- | lib/libfrr.h | 2 | ||||
| -rw-r--r-- | lib/log.c | 2 | ||||
| -rw-r--r-- | lib/memory.c | 10 | ||||
| -rw-r--r-- | lib/memory.h | 4 | ||||
| -rw-r--r-- | lib/sigevent.c | 2 | ||||
| -rw-r--r-- | tests/isisd/test_fuzz_isis_tlv.c | 2 | ||||
| -rw-r--r-- | tests/lib/cli/common_cli.c | 2 | 
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 */ @@ -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);  }  | 
