]> git.proxmox.com Git - mirror_frr.git/blob - lib/lib_vty.c
Merge pull request #5590 from qlyoung/fix-nhrp-underflow
[mirror_frr.git] / lib / lib_vty.c
1 /*
2 * Assorted library VTY commands
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
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
20 */
21
22 #include <zebra.h>
23 /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */
24 #ifdef HAVE_MALLOC_H
25 #include <malloc.h>
26 #endif
27 #ifdef HAVE_MALLOC_MALLOC_H
28 #include <malloc/malloc.h>
29 #endif
30 #include <dlfcn.h>
31 #ifdef HAVE_LINK_H
32 #include <link.h>
33 #endif
34
35 #include "log.h"
36 #include "memory.h"
37 #include "module.h"
38 #include "defaults.h"
39 #include "lib_vty.h"
40
41 /* Looking up memory status from vty interface. */
42 #include "vector.h"
43 #include "vty.h"
44 #include "command.h"
45
46 #ifdef HAVE_MALLINFO
47 static int show_memory_mallinfo(struct vty *vty)
48 {
49 struct mallinfo minfo = mallinfo();
50 char buf[MTYPE_MEMSTR_LEN];
51
52 vty_out(vty, "System allocator statistics:\n");
53 vty_out(vty, " Total heap allocated: %s\n",
54 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.arena));
55 vty_out(vty, " Holding block headers: %s\n",
56 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.hblkhd));
57 vty_out(vty, " Used small blocks: %s\n",
58 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.usmblks));
59 vty_out(vty, " Used ordinary blocks: %s\n",
60 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.uordblks));
61 vty_out(vty, " Free small blocks: %s\n",
62 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fsmblks));
63 vty_out(vty, " Free ordinary blocks: %s\n",
64 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fordblks));
65 vty_out(vty, " Ordinary blocks: %ld\n",
66 (unsigned long)minfo.ordblks);
67 vty_out(vty, " Small blocks: %ld\n",
68 (unsigned long)minfo.smblks);
69 vty_out(vty, " Holding blocks: %ld\n",
70 (unsigned long)minfo.hblks);
71 vty_out(vty, "(see system documentation for 'mallinfo' for meaning)\n");
72 return 1;
73 }
74 #endif /* HAVE_MALLINFO */
75
76 static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
77 {
78 struct vty *vty = arg;
79 if (!mt) {
80 vty_out(vty, "--- qmem %s ---\n", mg->name);
81 vty_out(vty, "%-30s: %8s %-8s%s %8s %9s\n",
82 "Type", "Current#", " Size",
83 #ifdef HAVE_MALLOC_USABLE_SIZE
84 " Total",
85 #else
86 "",
87 #endif
88 "Max#",
89 #ifdef HAVE_MALLOC_USABLE_SIZE
90 "MaxBytes"
91 #else
92 ""
93 #endif
94 );
95 } else {
96 if (mt->n_alloc != 0) {
97 char size[32];
98 snprintf(size, sizeof(size), "%6zu", mt->size);
99 #ifdef HAVE_MALLOC_USABLE_SIZE
100 #define TSTR " %9zu"
101 #define TARG , mt->total
102 #define TARG2 , mt->max_size
103 #else
104 #define TSTR ""
105 #define TARG
106 #define TARG2
107 #endif
108 vty_out(vty, "%-30s: %8zu %-8s"TSTR" %8zu"TSTR"\n",
109 mt->name,
110 mt->n_alloc,
111 mt->size == 0 ? ""
112 : mt->size == SIZE_VAR
113 ? "variable"
114 : size
115 TARG,
116 mt->n_max
117 TARG2);
118 }
119 }
120 return 0;
121 }
122
123
124 DEFUN_NOSH (show_memory,
125 show_memory_cmd,
126 "show memory",
127 "Show running system information\n"
128 "Memory statistics\n")
129 {
130 #ifdef HAVE_MALLINFO
131 show_memory_mallinfo(vty);
132 #endif /* HAVE_MALLINFO */
133
134 qmem_walk(qmem_walker, vty);
135 return CMD_SUCCESS;
136 }
137
138 DEFUN_NOSH (show_modules,
139 show_modules_cmd,
140 "show modules",
141 "Show running system information\n"
142 "Loaded modules\n")
143 {
144 struct frrmod_runtime *plug = frrmod_list;
145
146 vty_out(vty, "%-12s %-25s %s\n\n", "Module Name", "Version",
147 "Description");
148 while (plug) {
149 const struct frrmod_info *i = plug->info;
150
151 vty_out(vty, "%-12s %-25s %s\n", i->name, i->version,
152 i->description);
153 if (plug->dl_handle) {
154 #ifdef HAVE_DLINFO_ORIGIN
155 char origin[MAXPATHLEN] = "";
156 dlinfo(plug->dl_handle, RTLD_DI_ORIGIN, &origin);
157 #ifdef HAVE_DLINFO_LINKMAP
158 const char *name;
159 struct link_map *lm = NULL;
160 dlinfo(plug->dl_handle, RTLD_DI_LINKMAP, &lm);
161 if (lm) {
162 name = strrchr(lm->l_name, '/');
163 name = name ? name + 1 : lm->l_name;
164 vty_out(vty, "\tfrom: %s/%s\n", origin, name);
165 }
166 #else
167 vty_out(vty, "\tfrom: %s \n", origin, plug->load_name);
168 #endif
169 #else
170 vty_out(vty, "\tfrom: %s\n", plug->load_name);
171 #endif
172 }
173 plug = plug->next;
174 }
175
176 vty_out(vty, "pid: %u\n", (uint32_t)(getpid()));
177
178 return CMD_SUCCESS;
179 }
180
181 DEFUN (frr_defaults,
182 frr_defaults_cmd,
183 "frr defaults PROFILE...",
184 "FRRouting global parameters\n"
185 "set of configuration defaults used\n"
186 "profile string\n")
187 {
188 char *profile = argv_concat(argv, argc, 2);
189 int rv = CMD_SUCCESS;
190
191 if (!frr_defaults_profile_valid(profile)) {
192 vty_out(vty, "%% WARNING: profile %s is not known in this version\n",
193 profile);
194 rv = CMD_WARNING;
195 }
196 frr_defaults_profile_set(profile);
197 XFREE(MTYPE_TMP, profile);
198 return rv;
199 }
200
201 DEFUN (frr_version,
202 frr_version_cmd,
203 "frr version VERSION...",
204 "FRRouting global parameters\n"
205 "version configuration was written by\n"
206 "version string\n")
207 {
208 char *version = argv_concat(argv, argc, 2);
209
210 frr_defaults_version_set(version);
211 XFREE(MTYPE_TMP, version);
212 return CMD_SUCCESS;
213 }
214
215 static void defaults_autocomplete(vector comps, struct cmd_token *token)
216 {
217 const char **p;
218
219 for (p = frr_defaults_profiles; *p; p++)
220 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, *p));
221 }
222
223 static const struct cmd_variable_handler default_var_handlers[] = {
224 {.tokenname = "PROFILE", .completions = defaults_autocomplete},
225 {.completions = NULL},
226 };
227
228 void lib_cmd_init(void)
229 {
230 cmd_variable_handler_register(default_var_handlers);
231
232 install_element(CONFIG_NODE, &frr_defaults_cmd);
233 install_element(CONFIG_NODE, &frr_version_cmd);
234
235 install_element(VIEW_NODE, &show_memory_cmd);
236 install_element(VIEW_NODE, &show_modules_cmd);
237 }
238
239 /* Stats querying from users */
240 /* Return a pointer to a human friendly string describing
241 * the byte count passed in. E.g:
242 * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
243 * Up to 4 significant figures will be given.
244 * The pointer returned may be NULL (indicating an error)
245 * or point to the given buffer, or point to static storage.
246 */
247 const char *mtype_memstr(char *buf, size_t len, unsigned long bytes)
248 {
249 unsigned int m, k;
250
251 /* easy cases */
252 if (!bytes)
253 return "0 bytes";
254 if (bytes == 1)
255 return "1 byte";
256
257 /*
258 * When we pass the 2gb barrier mallinfo() can no longer report
259 * correct data so it just does something odd...
260 * Reporting like Terrabytes of data. Which makes users...
261 * edgy.. yes edgy that's the term for it.
262 * So let's just give up gracefully
263 */
264 if (bytes > 0x7fffffff)
265 return "> 2GB";
266
267 m = bytes >> 20;
268 k = bytes >> 10;
269
270 if (m > 10) {
271 if (bytes & (1 << 19))
272 m++;
273 snprintf(buf, len, "%d MiB", m);
274 } else if (k > 10) {
275 if (bytes & (1 << 9))
276 k++;
277 snprintf(buf, len, "%d KiB", k);
278 } else
279 snprintf(buf, len, "%ld bytes", bytes);
280
281 return buf;
282 }