blob: 802c07f29049361b7ccc4bd5c112046288acfd11 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * Memory management routine
3 * Copyright (C) 1998 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
Paul Jakma41be32b2006-03-30 13:53:59 +000024#include <malloc.h>
paul718e3742002-12-13 20:15:29 +000025
26#include "log.h"
27#include "memory.h"
28
ajsf858e492004-11-16 14:25:30 +000029static void alloc_inc (int);
30static void alloc_dec (int);
ajs7fa25ff2004-11-15 16:12:32 +000031static void log_memstats(int log_priority);
paul718e3742002-12-13 20:15:29 +000032
ajsf858e492004-11-16 14:25:30 +000033static struct message mstr [] =
paul718e3742002-12-13 20:15:29 +000034{
35 { MTYPE_THREAD, "thread" },
36 { MTYPE_THREAD_MASTER, "thread_master" },
37 { MTYPE_VECTOR, "vector" },
38 { MTYPE_VECTOR_INDEX, "vector_index" },
39 { MTYPE_IF, "interface" },
40 { 0, NULL },
41};
42
43/* Fatal memory allocation error occured. */
paul8cc41982005-05-06 21:25:49 +000044static void __attribute__ ((noreturn))
paul718e3742002-12-13 20:15:29 +000045zerror (const char *fname, int type, size_t size)
46{
ajs7fa25ff2004-11-15 16:12:32 +000047 zlog_err ("%s : can't allocate memory for `%s' size %d: %s\n",
ajs6099b3b2004-11-20 02:06:59 +000048 fname, lookup (mstr, type), (int) size, safe_strerror(errno));
ajs7fa25ff2004-11-15 16:12:32 +000049 log_memstats(LOG_WARNING);
ajs48d6c692004-11-26 20:52:59 +000050 /* N.B. It might be preferable to call zlog_backtrace_sigsafe here, since
ajs063ee522004-11-26 18:11:14 +000051 that function should definitely be safe in an OOM condition. But
ajs48d6c692004-11-26 20:52:59 +000052 unfortunately zlog_backtrace_sigsafe does not support syslog logging at
ajs063ee522004-11-26 18:11:14 +000053 this time... */
54 zlog_backtrace(LOG_WARNING);
ajs7fa25ff2004-11-15 16:12:32 +000055 abort();
paul718e3742002-12-13 20:15:29 +000056}
57
58/* Memory allocation. */
59void *
60zmalloc (int type, size_t size)
61{
62 void *memory;
63
64 memory = malloc (size);
65
66 if (memory == NULL)
67 zerror ("malloc", type, size);
68
69 alloc_inc (type);
70
71 return memory;
72}
73
74/* Memory allocation with num * size with cleared. */
75void *
76zcalloc (int type, size_t size)
77{
78 void *memory;
79
80 memory = calloc (1, size);
81
82 if (memory == NULL)
83 zerror ("calloc", type, size);
84
85 alloc_inc (type);
86
87 return memory;
88}
89
90/* Memory reallocation. */
91void *
92zrealloc (int type, void *ptr, size_t size)
93{
94 void *memory;
95
96 memory = realloc (ptr, size);
97 if (memory == NULL)
98 zerror ("realloc", type, size);
99 return memory;
100}
101
102/* Memory free. */
103void
104zfree (int type, void *ptr)
105{
106 alloc_dec (type);
107 free (ptr);
108}
109
110/* String duplication. */
111char *
hassob04c6992004-10-04 19:10:31 +0000112zstrdup (int type, const char *str)
paul718e3742002-12-13 20:15:29 +0000113{
114 void *dup;
115
116 dup = strdup (str);
117 if (dup == NULL)
118 zerror ("strdup", type, strlen (str));
119 alloc_inc (type);
120 return dup;
121}
122
123#ifdef MEMORY_LOG
ajsf858e492004-11-16 14:25:30 +0000124static struct
paul718e3742002-12-13 20:15:29 +0000125{
hassob04c6992004-10-04 19:10:31 +0000126 const char *name;
paul718e3742002-12-13 20:15:29 +0000127 unsigned long alloc;
128 unsigned long t_malloc;
129 unsigned long c_malloc;
130 unsigned long t_calloc;
131 unsigned long c_calloc;
132 unsigned long t_realloc;
133 unsigned long t_free;
134 unsigned long c_strdup;
135} mstat [MTYPE_MAX];
136
ajsf858e492004-11-16 14:25:30 +0000137static void
paul718e3742002-12-13 20:15:29 +0000138mtype_log (char *func, void *memory, const char *file, int line, int type)
139{
ajsb9e70282004-12-08 17:14:45 +0000140 zlog_debug ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
paul718e3742002-12-13 20:15:29 +0000141}
142
143void *
144mtype_zmalloc (const char *file, int line, int type, size_t size)
145{
146 void *memory;
147
148 mstat[type].c_malloc++;
149 mstat[type].t_malloc++;
150
151 memory = zmalloc (type, size);
152 mtype_log ("zmalloc", memory, file, line, type);
153
154 return memory;
155}
156
157void *
158mtype_zcalloc (const char *file, int line, int type, size_t size)
159{
160 void *memory;
161
162 mstat[type].c_calloc++;
163 mstat[type].t_calloc++;
164
165 memory = zcalloc (type, size);
166 mtype_log ("xcalloc", memory, file, line, type);
167
168 return memory;
169}
170
171void *
172mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
173{
174 void *memory;
175
176 /* Realloc need before allocated pointer. */
177 mstat[type].t_realloc++;
178
179 memory = zrealloc (type, ptr, size);
180
181 mtype_log ("xrealloc", memory, file, line, type);
182
183 return memory;
184}
185
186/* Important function. */
187void
188mtype_zfree (const char *file, int line, int type, void *ptr)
189{
190 mstat[type].t_free++;
191
192 mtype_log ("xfree", ptr, file, line, type);
193
194 zfree (type, ptr);
195}
196
197char *
hassob04c6992004-10-04 19:10:31 +0000198mtype_zstrdup (const char *file, int line, int type, const char *str)
paul718e3742002-12-13 20:15:29 +0000199{
200 char *memory;
201
202 mstat[type].c_strdup++;
203
204 memory = zstrdup (type, str);
205
206 mtype_log ("xstrdup", memory, file, line, type);
207
208 return memory;
209}
210#else
ajsf858e492004-11-16 14:25:30 +0000211static struct
paul718e3742002-12-13 20:15:29 +0000212{
213 char *name;
214 unsigned long alloc;
215} mstat [MTYPE_MAX];
216#endif /* MTPYE_LOG */
217
218/* Increment allocation counter. */
ajsf858e492004-11-16 14:25:30 +0000219static void
paul718e3742002-12-13 20:15:29 +0000220alloc_inc (int type)
221{
222 mstat[type].alloc++;
223}
224
225/* Decrement allocation counter. */
ajsf858e492004-11-16 14:25:30 +0000226static void
paul718e3742002-12-13 20:15:29 +0000227alloc_dec (int type)
228{
229 mstat[type].alloc--;
230}
231
232/* Looking up memory status from vty interface. */
233#include "vector.h"
234#include "vty.h"
235#include "command.h"
236
ajs7fa25ff2004-11-15 16:12:32 +0000237static void
238log_memstats(int pri)
239{
240 struct mlist *ml;
241
242 for (ml = mlists; ml->list; ml++)
243 {
244 struct memory_list *m;
245
246 zlog (NULL, pri, "Memory utilization in module %s:", ml->name);
247 for (m = ml->list; m->index >= 0; m++)
248 if (m->index && mstat[m->index].alloc)
paul2fd2fd52005-04-15 11:47:15 +0000249 zlog (NULL, pri, " %-30s: %10ld", m->format, mstat[m->index].alloc);
ajs7fa25ff2004-11-15 16:12:32 +0000250 }
251}
252
ajsf858e492004-11-16 14:25:30 +0000253static void
ajs24065a32005-10-20 22:28:14 +0000254show_separator(struct vty *vty)
255{
256 vty_out (vty, "-----------------------------\r\n");
257}
258
259static int
paul718e3742002-12-13 20:15:29 +0000260show_memory_vty (struct vty *vty, struct memory_list *list)
261{
262 struct memory_list *m;
ajs24065a32005-10-20 22:28:14 +0000263 int needsep = 0;
paul718e3742002-12-13 20:15:29 +0000264
265 for (m = list; m->index >= 0; m++)
266 if (m->index == 0)
ajs24065a32005-10-20 22:28:14 +0000267 {
268 if (needsep)
269 {
270 show_separator (vty);
271 needsep = 0;
272 }
273 }
274 else if (mstat[m->index].alloc)
275 {
276 vty_out (vty, "%-30s: %10ld\r\n", m->format, mstat[m->index].alloc);
277 needsep = 1;
278 }
279 return needsep;
paul718e3742002-12-13 20:15:29 +0000280}
281
Paul Jakma41be32b2006-03-30 13:53:59 +0000282#ifdef HAVE_MALLINFO
283static int
284show_memory_mallinfo (struct vty *vty)
285{
286 struct mallinfo minfo = mallinfo();
287 char buf[MTYPE_MEMSTR_LEN];
288
289 vty_out (vty, "System allocator statistics:%s", VTY_NEWLINE);
290 vty_out (vty, " Total heap allocated: %s%s",
291 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.arena),
292 VTY_NEWLINE);
293 vty_out (vty, " Holding block headers: %s%s",
294 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.hblkhd),
295 VTY_NEWLINE);
296 vty_out (vty, " Used small blocks: %s%s",
297 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.usmblks),
298 VTY_NEWLINE);
299 vty_out (vty, " Used ordinary blocks: %s%s",
300 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.uordblks),
301 VTY_NEWLINE);
302 vty_out (vty, " Free small blocks: %s%s",
303 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fsmblks),
304 VTY_NEWLINE);
305 vty_out (vty, " Free ordinary blocks: %s%s",
306 mtype_memstr (buf, MTYPE_MEMSTR_LEN, minfo.fordblks),
307 VTY_NEWLINE);
308 vty_out (vty, " Ordinary blocks: %ld%s",
309 (unsigned long)minfo.ordblks,
310 VTY_NEWLINE);
311 vty_out (vty, " Small blocks: %ld%s",
312 (unsigned long)minfo.smblks,
313 VTY_NEWLINE);
314 vty_out (vty, " Holding blocks: %ld%s",
315 (unsigned long)minfo.hblks,
316 VTY_NEWLINE);
317 vty_out (vty, "(see system documentation for 'mallinfo' for meaning)%s",
318 VTY_NEWLINE);
319 return 1;
320}
321#endif /* HAVE_MALLINFO */
322
paul718e3742002-12-13 20:15:29 +0000323DEFUN (show_memory_all,
324 show_memory_all_cmd,
325 "show memory all",
326 "Show running system information\n"
327 "Memory statistics\n"
328 "All memory statistics\n")
329{
ajs7fa25ff2004-11-15 16:12:32 +0000330 struct mlist *ml;
ajs24065a32005-10-20 22:28:14 +0000331 int needsep = 0;
Paul Jakma41be32b2006-03-30 13:53:59 +0000332
333#ifdef HAVE_MALLINFO
334 needsep = show_memory_mallinfo (vty);
335#endif /* HAVE_MALLINFO */
336
ajs7fa25ff2004-11-15 16:12:32 +0000337 for (ml = mlists; ml->list; ml++)
338 {
ajs24065a32005-10-20 22:28:14 +0000339 if (needsep)
340 show_separator (vty);
341 needsep = show_memory_vty (vty, ml->list);
ajs7fa25ff2004-11-15 16:12:32 +0000342 }
paul718e3742002-12-13 20:15:29 +0000343
344 return CMD_SUCCESS;
345}
346
347ALIAS (show_memory_all,
348 show_memory_cmd,
349 "show memory",
350 "Show running system information\n"
351 "Memory statistics\n")
352
353DEFUN (show_memory_lib,
354 show_memory_lib_cmd,
355 "show memory lib",
356 SHOW_STR
357 "Memory statistics\n"
358 "Library memory\n")
359{
360 show_memory_vty (vty, memory_list_lib);
361 return CMD_SUCCESS;
362}
363
paul2fd2fd52005-04-15 11:47:15 +0000364DEFUN (show_memory_zebra,
365 show_memory_zebra_cmd,
366 "show memory zebra",
367 SHOW_STR
368 "Memory statistics\n"
369 "Zebra memory\n")
370{
371 show_memory_vty (vty, memory_list_zebra);
372 return CMD_SUCCESS;
373}
374
paul718e3742002-12-13 20:15:29 +0000375DEFUN (show_memory_rip,
376 show_memory_rip_cmd,
377 "show memory rip",
378 SHOW_STR
379 "Memory statistics\n"
380 "RIP memory\n")
381{
382 show_memory_vty (vty, memory_list_rip);
383 return CMD_SUCCESS;
384}
385
hassoa94434b2003-05-25 17:10:12 +0000386DEFUN (show_memory_ripng,
387 show_memory_ripng_cmd,
388 "show memory ripng",
389 SHOW_STR
390 "Memory statistics\n"
391 "RIPng memory\n")
392{
393 show_memory_vty (vty, memory_list_ripng);
394 return CMD_SUCCESS;
395}
396
paul718e3742002-12-13 20:15:29 +0000397DEFUN (show_memory_bgp,
398 show_memory_bgp_cmd,
399 "show memory bgp",
400 SHOW_STR
401 "Memory statistics\n"
402 "BGP memory\n")
403{
404 show_memory_vty (vty, memory_list_bgp);
405 return CMD_SUCCESS;
406}
407
408DEFUN (show_memory_ospf,
409 show_memory_ospf_cmd,
410 "show memory ospf",
411 SHOW_STR
412 "Memory statistics\n"
413 "OSPF memory\n")
414{
415 show_memory_vty (vty, memory_list_ospf);
416 return CMD_SUCCESS;
417}
418
419DEFUN (show_memory_ospf6,
420 show_memory_ospf6_cmd,
421 "show memory ospf6",
422 SHOW_STR
423 "Memory statistics\n"
424 "OSPF6 memory\n")
425{
426 show_memory_vty (vty, memory_list_ospf6);
427 return CMD_SUCCESS;
428}
429
jardin9e867fe2003-12-23 08:56:18 +0000430DEFUN (show_memory_isis,
431 show_memory_isis_cmd,
432 "show memory isis",
433 SHOW_STR
434 "Memory statistics\n"
435 "ISIS memory\n")
436{
437 show_memory_vty (vty, memory_list_isis);
438 return CMD_SUCCESS;
439}
440
paul718e3742002-12-13 20:15:29 +0000441void
ajsf858e492004-11-16 14:25:30 +0000442memory_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 install_element (VIEW_NODE, &show_memory_cmd);
445 install_element (VIEW_NODE, &show_memory_all_cmd);
446 install_element (VIEW_NODE, &show_memory_lib_cmd);
447 install_element (VIEW_NODE, &show_memory_rip_cmd);
hassoa94434b2003-05-25 17:10:12 +0000448 install_element (VIEW_NODE, &show_memory_ripng_cmd);
paul718e3742002-12-13 20:15:29 +0000449 install_element (VIEW_NODE, &show_memory_bgp_cmd);
450 install_element (VIEW_NODE, &show_memory_ospf_cmd);
451 install_element (VIEW_NODE, &show_memory_ospf6_cmd);
jardin9e867fe2003-12-23 08:56:18 +0000452 install_element (VIEW_NODE, &show_memory_isis_cmd);
paul718e3742002-12-13 20:15:29 +0000453
454 install_element (ENABLE_NODE, &show_memory_cmd);
455 install_element (ENABLE_NODE, &show_memory_all_cmd);
456 install_element (ENABLE_NODE, &show_memory_lib_cmd);
paul2fd2fd52005-04-15 11:47:15 +0000457 install_element (ENABLE_NODE, &show_memory_zebra_cmd);
paul718e3742002-12-13 20:15:29 +0000458 install_element (ENABLE_NODE, &show_memory_rip_cmd);
hassoa94434b2003-05-25 17:10:12 +0000459 install_element (ENABLE_NODE, &show_memory_ripng_cmd);
paul718e3742002-12-13 20:15:29 +0000460 install_element (ENABLE_NODE, &show_memory_bgp_cmd);
461 install_element (ENABLE_NODE, &show_memory_ospf_cmd);
462 install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
jardin9e867fe2003-12-23 08:56:18 +0000463 install_element (ENABLE_NODE, &show_memory_isis_cmd);
paul718e3742002-12-13 20:15:29 +0000464}
Paul Jakma41be32b2006-03-30 13:53:59 +0000465
466/* Stats querying from users */
467/* Return a pointer to a human friendly string describing
468 * the byte count passed in. E.g:
469 * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
470 * Up to 4 significant figures will be given.
471 * The pointer returned may be NULL (indicating an error)
472 * or point to the given buffer, or point to static storage.
473 */
474const char *
475mtype_memstr (char *buf, size_t len, unsigned long bytes)
476{
477 unsigned int t, g, m, k;
478
479 /* easy cases */
480 if (!bytes)
481 return "0 bytes";
482 if (bytes == 1)
483 return "1 byte";
484
485 if (sizeof (unsigned long) >= 8)
486 /* Hacked to make it not warn on ILP32 machines
487 * Shift will always be 40 at runtime. See below too */
488 t = bytes >> (sizeof (unsigned long) >= 8 ? 40 : 0);
489 else
490 t = 0;
491 g = bytes >> 30;
492 m = bytes >> 20;
493 k = bytes >> 10;
494
495 if (t > 10)
496 {
497 /* The shift will always be 39 at runtime.
498 * Just hacked to make it not warn on 'smaller' machines.
499 * Static compiler analysis should mean no extra code
500 */
501 if (bytes & (1 << (sizeof (unsigned long) >= 8 ? 39 : 0)))
502 t++;
503 snprintf (buf, len, "%4d TiB", t);
504 }
505 else if (g > 10)
506 {
507 if (bytes & (1 << 29))
508 g++;
509 snprintf (buf, len, "%d GiB", g);
510 }
511 else if (m > 10)
512 {
513 if (bytes & (1 << 19))
514 m++;
515 snprintf (buf, len, "%d MiB", m);
516 }
517 else if (k > 10)
518 {
519 if (bytes & (1 << 9))
520 k++;
521 snprintf (buf, len, "%d KiB", k);
522 }
523 else
524 snprintf (buf, len, "%ld bytes", bytes);
525
526 return buf;
527}
528
529unsigned long
530mtype_stats_alloc (int type)
531{
532 return mstat[type].alloc;
533}