]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
b249c083 | 2 | * Memory and dynamic module VTY routine |
718e3744 | 3 | * |
b249c083 DL |
4 | * Copyright (C) 1998 Kunihiro Ishiguro |
5 | * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc. | |
718e3744 | 6 | * |
b249c083 DL |
7 | * This program 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 Free | |
9 | * Software Foundation; either version 2 of the License, or (at your option) | |
10 | * any later version. | |
718e3744 | 11 | * |
b249c083 DL |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 | * more details. | |
718e3744 | 16 | * |
896014f4 DL |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; see the file COPYING; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
718e3744 | 20 | */ |
21 | ||
22 | #include <zebra.h> | |
d09552d0 | 23 | /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */ |
24f5e2fc | 24 | #if (defined(GNU_LINUX) && defined(HAVE_MALLINFO)) |
41be32bf | 25 | #include <malloc.h> |
24f5e2fc | 26 | #endif /* HAVE_MALLINFO */ |
b249c083 DL |
27 | #include <dlfcn.h> |
28 | #include <link.h> | |
718e3744 | 29 | |
30 | #include "log.h" | |
31 | #include "memory.h" | |
b249c083 | 32 | #include "module.h" |
fc7948fa | 33 | #include "memory_vty.h" |
6b0655a2 | 34 | |
718e3744 | 35 | /* Looking up memory status from vty interface. */ |
36 | #include "vector.h" | |
37 | #include "vty.h" | |
38 | #include "command.h" | |
39 | ||
41be32bf PJ |
40 | #ifdef HAVE_MALLINFO |
41 | static int | |
42 | show_memory_mallinfo (struct vty *vty) | |
43 | { | |
44 | struct mallinfo minfo = mallinfo(); | |
45 | char buf[MTYPE_MEMSTR_LEN]; | |
46 | ||
5c7571d4 DL |
47 | vty_out (vty, "System allocator statistics:\n"); |
48 | vty_out (vty, " Total heap allocated: %s\n", | |
96ade3ed | 49 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.arena)); |
5c7571d4 | 50 | vty_out (vty, " Holding block headers: %s\n", |
96ade3ed | 51 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.hblkhd)); |
5c7571d4 | 52 | vty_out (vty, " Used small blocks: %s\n", |
96ade3ed | 53 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.usmblks)); |
5c7571d4 | 54 | vty_out (vty, " Used ordinary blocks: %s\n", |
96ade3ed | 55 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.uordblks)); |
5c7571d4 | 56 | vty_out (vty, " Free small blocks: %s\n", |
96ade3ed | 57 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fsmblks)); |
5c7571d4 | 58 | vty_out (vty, " Free ordinary blocks: %s\n", |
96ade3ed | 59 | mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fordblks)); |
5c7571d4 | 60 | vty_out (vty, " Ordinary blocks: %ld\n", |
96ade3ed | 61 | (unsigned long)minfo.ordblks); |
5c7571d4 | 62 | vty_out (vty, " Small blocks: %ld\n", |
96ade3ed | 63 | (unsigned long)minfo.smblks); |
5c7571d4 | 64 | vty_out (vty, " Holding blocks: %ld\n", |
96ade3ed | 65 | (unsigned long)minfo.hblks); |
5c7571d4 | 66 | vty_out (vty,"(see system documentation for 'mallinfo' for meaning)\n"); |
41be32bf PJ |
67 | return 1; |
68 | } | |
69 | #endif /* HAVE_MALLINFO */ | |
70 | ||
3b4cd783 DL |
71 | static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt) |
72 | { | |
73 | struct vty *vty = arg; | |
74 | if (!mt) | |
5c7571d4 | 75 | vty_out (vty, "--- qmem %s ---\n", mg->name); |
3b4cd783 | 76 | else { |
3694c43a DS |
77 | if (mt->n_alloc != 0) { |
78 | char size[32]; | |
79 | snprintf(size, sizeof(size), "%6zu", mt->size); | |
5c7571d4 | 80 | vty_out (vty, "%-30s: %10zu %s\n", |
3694c43a | 81 | mt->name, mt->n_alloc, |
96ade3ed | 82 | mt->size == 0 ? "" : mt->size == SIZE_VAR ? "(variably sized)" : size); |
3694c43a | 83 | } |
3b4cd783 DL |
84 | } |
85 | return 0; | |
86 | } | |
87 | ||
88 | ||
0d05fa51 DS |
89 | DEFUN (show_memory, |
90 | show_memory_cmd, | |
91 | "show memory", | |
718e3744 | 92 | "Show running system information\n" |
0d05fa51 | 93 | "Memory statistics\n") |
718e3744 | 94 | { |
41be32bf | 95 | #ifdef HAVE_MALLINFO |
7a13c923 | 96 | show_memory_mallinfo (vty); |
41be32bf | 97 | #endif /* HAVE_MALLINFO */ |
fc7948fa | 98 | |
3b4cd783 | 99 | qmem_walk(qmem_walker, vty); |
718e3744 | 100 | return CMD_SUCCESS; |
101 | } | |
102 | ||
b249c083 DL |
103 | DEFUN (show_modules, |
104 | show_modules_cmd, | |
105 | "show modules", | |
106 | "Show running system information\n" | |
107 | "Loaded modules\n") | |
108 | { | |
109 | struct frrmod_runtime *plug = frrmod_list; | |
110 | ||
5c7571d4 | 111 | vty_out (vty, "%-12s %-25s %s%s\n", |
2a8e27af | 112 | "Module Name", "Version", "Description", |
1318e7c8 | 113 | VTYNL); |
b249c083 DL |
114 | while (plug) |
115 | { | |
116 | const struct frrmod_info *i = plug->info; | |
117 | ||
5c7571d4 | 118 | vty_out (vty, "%-12s %-25s %s\n", i->name, i->version,i->description); |
b249c083 DL |
119 | if (plug->dl_handle) |
120 | { | |
121 | #ifdef HAVE_DLINFO_ORIGIN | |
122 | char origin[MAXPATHLEN] = ""; | |
123 | dlinfo (plug->dl_handle, RTLD_DI_ORIGIN, &origin); | |
124 | # ifdef HAVE_DLINFO_LINKMAP | |
125 | const char *name; | |
126 | struct link_map *lm = NULL; | |
127 | dlinfo (plug->dl_handle, RTLD_DI_LINKMAP, &lm); | |
128 | if (lm) | |
129 | { | |
130 | name = strrchr(lm->l_name, '/'); | |
131 | name = name ? name + 1 : lm->l_name; | |
5c7571d4 | 132 | vty_out (vty, "\tfrom: %s/%s\n", origin, name); |
b249c083 DL |
133 | } |
134 | # else | |
5c7571d4 | 135 | vty_out (vty, "\tfrom: %s \n", origin, plug->load_name); |
b249c083 DL |
136 | # endif |
137 | #else | |
5c7571d4 | 138 | vty_out (vty, "\tfrom: %s\n", plug->load_name); |
b249c083 DL |
139 | #endif |
140 | } | |
141 | plug = plug->next; | |
142 | } | |
143 | return CMD_SUCCESS; | |
144 | } | |
145 | ||
718e3744 | 146 | void |
f858e49b | 147 | memory_init (void) |
718e3744 | 148 | { |
149 | install_element (VIEW_NODE, &show_memory_cmd); | |
b249c083 | 150 | install_element (VIEW_NODE, &show_modules_cmd); |
718e3744 | 151 | } |
6b0655a2 | 152 | |
41be32bf PJ |
153 | /* Stats querying from users */ |
154 | /* Return a pointer to a human friendly string describing | |
155 | * the byte count passed in. E.g: | |
156 | * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc. | |
157 | * Up to 4 significant figures will be given. | |
158 | * The pointer returned may be NULL (indicating an error) | |
159 | * or point to the given buffer, or point to static storage. | |
160 | */ | |
161 | const char * | |
162 | mtype_memstr (char *buf, size_t len, unsigned long bytes) | |
163 | { | |
6896f650 DS |
164 | unsigned int m, k; |
165 | ||
41be32bf PJ |
166 | /* easy cases */ |
167 | if (!bytes) | |
168 | return "0 bytes"; | |
169 | if (bytes == 1) | |
170 | return "1 byte"; | |
6896f650 DS |
171 | |
172 | /* | |
173 | * When we pass the 2gb barrier mallinfo() can no longer report | |
174 | * correct data so it just does something odd... | |
175 | * Reporting like Terrabytes of data. Which makes users... | |
176 | * edgy.. yes edgy that's the term for it. | |
177 | * So let's just give up gracefully | |
178 | */ | |
179 | if (bytes > 0x7fffffff) | |
180 | return "> 2GB"; | |
181 | ||
41be32bf PJ |
182 | m = bytes >> 20; |
183 | k = bytes >> 10; | |
6896f650 DS |
184 | |
185 | if (m > 10) | |
41be32bf PJ |
186 | { |
187 | if (bytes & (1 << 19)) | |
188 | m++; | |
189 | snprintf (buf, len, "%d MiB", m); | |
190 | } | |
191 | else if (k > 10) | |
192 | { | |
193 | if (bytes & (1 << 9)) | |
194 | k++; | |
195 | snprintf (buf, len, "%d KiB", k); | |
196 | } | |
197 | else | |
198 | snprintf (buf, len, "%ld bytes", bytes); | |
199 | ||
200 | return buf; | |
201 | } |