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