Line data Source code
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 : #include "northbound_cli.h"
41 :
42 : /* Looking up memory status from vty interface. */
43 : #include "vector.h"
44 : #include "vty.h"
45 : #include "command.h"
46 :
47 : #if defined(HAVE_MALLINFO2) || defined(HAVE_MALLINFO)
48 0 : static int show_memory_mallinfo(struct vty *vty)
49 : {
50 : #if defined(HAVE_MALLINFO2)
51 0 : struct mallinfo2 minfo = mallinfo2();
52 : #elif defined(HAVE_MALLINFO)
53 : struct mallinfo minfo = mallinfo();
54 : #endif
55 0 : char buf[MTYPE_MEMSTR_LEN];
56 :
57 0 : vty_out(vty, "System allocator statistics:\n");
58 0 : vty_out(vty, " Total heap allocated: %s\n",
59 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.arena));
60 0 : vty_out(vty, " Holding block headers: %s\n",
61 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.hblkhd));
62 0 : vty_out(vty, " Used small blocks: %s\n",
63 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.usmblks));
64 0 : vty_out(vty, " Used ordinary blocks: %s\n",
65 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.uordblks));
66 0 : vty_out(vty, " Free small blocks: %s\n",
67 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fsmblks));
68 0 : vty_out(vty, " Free ordinary blocks: %s\n",
69 : mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fordblks));
70 0 : vty_out(vty, " Ordinary blocks: %ld\n",
71 0 : (unsigned long)minfo.ordblks);
72 0 : vty_out(vty, " Small blocks: %ld\n",
73 0 : (unsigned long)minfo.smblks);
74 0 : vty_out(vty, " Holding blocks: %ld\n",
75 0 : (unsigned long)minfo.hblks);
76 0 : vty_out(vty, "(see system documentation for 'mallinfo' for meaning)\n");
77 0 : return 1;
78 : }
79 : #endif /* HAVE_MALLINFO */
80 :
81 0 : static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
82 : {
83 0 : struct vty *vty = arg;
84 0 : if (!mt) {
85 0 : vty_out(vty, "--- qmem %s ---\n", mg->name);
86 0 : vty_out(vty, "%-30s: %8s %-8s%s %8s %9s\n",
87 : "Type", "Current#", " Size",
88 : #ifdef HAVE_MALLOC_USABLE_SIZE
89 : " Total",
90 : #else
91 : "",
92 : #endif
93 : "Max#",
94 : #ifdef HAVE_MALLOC_USABLE_SIZE
95 : "MaxBytes"
96 : #else
97 : ""
98 : #endif
99 : );
100 : } else {
101 0 : if (mt->n_max != 0) {
102 0 : char size[32];
103 0 : snprintf(size, sizeof(size), "%6zu", mt->size);
104 : #ifdef HAVE_MALLOC_USABLE_SIZE
105 : #define TSTR " %9zu"
106 : #define TARG , mt->total
107 : #define TARG2 , mt->max_size
108 : #else
109 : #define TSTR ""
110 : #define TARG
111 : #define TARG2
112 : #endif
113 0 : vty_out(vty, "%-30s: %8zu %-8s"TSTR" %8zu"TSTR"\n",
114 : mt->name,
115 0 : mt->n_alloc,
116 0 : mt->size == 0 ? ""
117 0 : : mt->size == SIZE_VAR
118 : ? "variable"
119 0 : : size
120 0 : TARG,
121 0 : mt->n_max
122 0 : TARG2);
123 : }
124 : }
125 0 : return 0;
126 : }
127 :
128 :
129 0 : DEFUN_NOSH (show_memory,
130 : show_memory_cmd,
131 : "show memory",
132 : "Show running system information\n"
133 : "Memory statistics\n")
134 : {
135 : #ifdef HAVE_MALLINFO
136 0 : show_memory_mallinfo(vty);
137 : #endif /* HAVE_MALLINFO */
138 :
139 0 : qmem_walk(qmem_walker, vty);
140 0 : return CMD_SUCCESS;
141 : }
142 :
143 0 : DEFUN_NOSH (show_modules,
144 : show_modules_cmd,
145 : "show modules",
146 : "Show running system information\n"
147 : "Loaded modules\n")
148 : {
149 0 : struct frrmod_runtime *plug = frrmod_list;
150 :
151 0 : vty_out(vty, "%-12s %-25s %s\n\n", "Module Name", "Version",
152 : "Description");
153 0 : while (plug) {
154 0 : const struct frrmod_info *i = plug->info;
155 :
156 0 : vty_out(vty, "%-12s %-25s %s\n", i->name, i->version,
157 0 : i->description);
158 0 : if (plug->dl_handle) {
159 : #ifdef HAVE_DLINFO_ORIGIN
160 0 : char origin[MAXPATHLEN] = "";
161 0 : dlinfo(plug->dl_handle, RTLD_DI_ORIGIN, &origin);
162 : #ifdef HAVE_DLINFO_LINKMAP
163 0 : const char *name;
164 0 : struct link_map *lm = NULL;
165 0 : dlinfo(plug->dl_handle, RTLD_DI_LINKMAP, &lm);
166 0 : if (lm) {
167 0 : name = strrchr(lm->l_name, '/');
168 0 : name = name ? name + 1 : lm->l_name;
169 0 : vty_out(vty, "\tfrom: %s/%s\n", origin, name);
170 : }
171 : #else
172 : vty_out(vty, "\tfrom: %s \n", origin, plug->load_name);
173 : #endif
174 : #else
175 : vty_out(vty, "\tfrom: %s\n", plug->load_name);
176 : #endif
177 : }
178 0 : plug = plug->next;
179 : }
180 :
181 0 : vty_out(vty, "pid: %u\n", (uint32_t)(getpid()));
182 :
183 0 : return CMD_SUCCESS;
184 : }
185 :
186 0 : DEFUN (frr_defaults,
187 : frr_defaults_cmd,
188 : "frr defaults PROFILE...",
189 : "FRRouting global parameters\n"
190 : "set of configuration defaults used\n"
191 : "profile string\n")
192 : {
193 0 : char *profile = argv_concat(argv, argc, 2);
194 0 : int rv = CMD_SUCCESS;
195 :
196 0 : if (!frr_defaults_profile_valid(profile)) {
197 0 : vty_out(vty, "%% WARNING: profile %s is not known in this version\n",
198 : profile);
199 0 : rv = CMD_WARNING;
200 : }
201 0 : frr_defaults_profile_set(profile);
202 0 : XFREE(MTYPE_TMP, profile);
203 0 : return rv;
204 : }
205 :
206 0 : DEFUN (frr_version,
207 : frr_version_cmd,
208 : "frr version VERSION...",
209 : "FRRouting global parameters\n"
210 : "version configuration was written by\n"
211 : "version string\n")
212 : {
213 0 : char *version = argv_concat(argv, argc, 2);
214 :
215 0 : frr_defaults_version_set(version);
216 0 : XFREE(MTYPE_TMP, version);
217 0 : return CMD_SUCCESS;
218 : }
219 :
220 : static struct call_back {
221 : time_t readin_time;
222 :
223 : void (*start_config)(void);
224 : void (*end_config)(void);
225 : } callback;
226 :
227 :
228 0 : DEFUN_NOSH(start_config, start_config_cmd, "XFRR_start_configuration",
229 : "The Beginning of Configuration\n")
230 : {
231 0 : callback.readin_time = monotime(NULL);
232 :
233 0 : vty->pending_allowed = 1;
234 :
235 0 : if (callback.start_config)
236 0 : (*callback.start_config)();
237 :
238 0 : return CMD_SUCCESS;
239 : }
240 :
241 0 : DEFUN_NOSH(end_config, end_config_cmd, "XFRR_end_configuration",
242 : "The End of Configuration\n")
243 : {
244 0 : time_t readin_time;
245 0 : char readin_time_str[MONOTIME_STRLEN];
246 0 : int ret;
247 :
248 0 : readin_time = monotime(NULL);
249 0 : readin_time -= callback.readin_time;
250 :
251 0 : frrtime_to_interval(readin_time, readin_time_str,
252 : sizeof(readin_time_str));
253 :
254 0 : vty->pending_allowed = 0;
255 0 : ret = nb_cli_pending_commit_check(vty);
256 :
257 0 : zlog_info("Configuration Read in Took: %s", readin_time_str);
258 :
259 0 : if (callback.end_config)
260 0 : (*callback.end_config)();
261 :
262 0 : return ret;
263 : }
264 :
265 4 : void cmd_init_config_callbacks(void (*start_config_cb)(void),
266 : void (*end_config_cb)(void))
267 : {
268 4 : callback.start_config = start_config_cb;
269 4 : callback.end_config = end_config_cb;
270 4 : }
271 :
272 :
273 0 : static void defaults_autocomplete(vector comps, struct cmd_token *token)
274 : {
275 0 : const char **p;
276 :
277 0 : for (p = frr_defaults_profiles; *p; p++)
278 0 : vector_set(comps, XSTRDUP(MTYPE_COMPLETION, *p));
279 0 : }
280 :
281 : static const struct cmd_variable_handler default_var_handlers[] = {
282 : {.tokenname = "PROFILE", .completions = defaults_autocomplete},
283 : {.completions = NULL},
284 : };
285 :
286 8 : void lib_cmd_init(void)
287 : {
288 8 : cmd_variable_handler_register(default_var_handlers);
289 :
290 8 : install_element(CONFIG_NODE, &frr_defaults_cmd);
291 8 : install_element(CONFIG_NODE, &frr_version_cmd);
292 :
293 8 : install_element(VIEW_NODE, &show_memory_cmd);
294 8 : install_element(VIEW_NODE, &show_modules_cmd);
295 :
296 8 : install_element(CONFIG_NODE, &start_config_cmd);
297 8 : install_element(CONFIG_NODE, &end_config_cmd);
298 8 : }
299 :
300 : /* Stats querying from users */
301 : /* Return a pointer to a human friendly string describing
302 : * the byte count passed in. E.g:
303 : * "0 bytes", "2048 bytes", "110kB", "500MiB", "11GiB", etc.
304 : * Up to 4 significant figures will be given.
305 : * The pointer returned may be NULL (indicating an error)
306 : * or point to the given buffer, or point to static storage.
307 : */
308 0 : const char *mtype_memstr(char *buf, size_t len, unsigned long bytes)
309 : {
310 0 : unsigned int m, k;
311 :
312 : /* easy cases */
313 0 : if (!bytes)
314 : return "0 bytes";
315 0 : if (bytes == 1)
316 : return "1 byte";
317 :
318 : /*
319 : * When we pass the 2gb barrier mallinfo() can no longer report
320 : * correct data so it just does something odd...
321 : * Reporting like Terrabytes of data. Which makes users...
322 : * edgy.. yes edgy that's the term for it.
323 : * So let's just give up gracefully
324 : */
325 0 : if (bytes > 0x7fffffff)
326 : return "> 2GB";
327 :
328 0 : m = bytes >> 20;
329 0 : k = bytes >> 10;
330 :
331 0 : if (m > 10) {
332 0 : if (bytes & (1 << 19))
333 0 : m++;
334 0 : snprintf(buf, len, "%d MiB", m);
335 0 : } else if (k > 10) {
336 0 : if (bytes & (1 << 9))
337 0 : k++;
338 0 : snprintf(buf, len, "%d KiB", k);
339 : } else
340 0 : snprintf(buf, len, "%ld bytes", bytes);
341 :
342 : return buf;
343 : }
|