]> git.proxmox.com Git - mirror_frr.git/blob - lib/lib_vty.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[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 #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 static int show_memory_mallinfo(struct vty *vty)
49 {
50 #if defined(HAVE_MALLINFO2)
51 struct mallinfo2 minfo = mallinfo2();
52 #elif defined(HAVE_MALLINFO)
53 struct mallinfo minfo = mallinfo();
54 #endif
55 char buf[MTYPE_MEMSTR_LEN];
56
57 vty_out(vty, "System allocator statistics:\n");
58 vty_out(vty, " Total heap allocated: %s\n",
59 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.arena));
60 vty_out(vty, " Holding block headers: %s\n",
61 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.hblkhd));
62 vty_out(vty, " Used small blocks: %s\n",
63 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.usmblks));
64 vty_out(vty, " Used ordinary blocks: %s\n",
65 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.uordblks));
66 vty_out(vty, " Free small blocks: %s\n",
67 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fsmblks));
68 vty_out(vty, " Free ordinary blocks: %s\n",
69 mtype_memstr(buf, MTYPE_MEMSTR_LEN, minfo.fordblks));
70 vty_out(vty, " Ordinary blocks: %ld\n",
71 (unsigned long)minfo.ordblks);
72 vty_out(vty, " Small blocks: %ld\n",
73 (unsigned long)minfo.smblks);
74 vty_out(vty, " Holding blocks: %ld\n",
75 (unsigned long)minfo.hblks);
76 vty_out(vty, "(see system documentation for 'mallinfo' for meaning)\n");
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 ---\n", mg->name);
86 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 if (mt->n_max != 0) {
102 char size[32];
103 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 vty_out(vty, "%-30s: %8zu %-8s"TSTR" %8zu"TSTR"\n",
114 mt->name,
115 mt->n_alloc,
116 mt->size == 0 ? ""
117 : mt->size == SIZE_VAR
118 ? "variable"
119 : size
120 TARG,
121 mt->n_max
122 TARG2);
123 }
124 }
125 return 0;
126 }
127
128
129 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 show_memory_mallinfo(vty);
137 #endif /* HAVE_MALLINFO */
138
139 qmem_walk(qmem_walker, vty);
140 return CMD_SUCCESS;
141 }
142
143 DEFUN_NOSH (show_modules,
144 show_modules_cmd,
145 "show modules",
146 "Show running system information\n"
147 "Loaded modules\n")
148 {
149 struct frrmod_runtime *plug = frrmod_list;
150
151 vty_out(vty, "%-12s %-25s %s\n\n", "Module Name", "Version",
152 "Description");
153 while (plug) {
154 const struct frrmod_info *i = plug->info;
155
156 vty_out(vty, "%-12s %-25s %s\n", i->name, i->version,
157 i->description);
158 if (plug->dl_handle) {
159 #ifdef HAVE_DLINFO_ORIGIN
160 char origin[MAXPATHLEN] = "";
161 dlinfo(plug->dl_handle, RTLD_DI_ORIGIN, &origin);
162 #ifdef HAVE_DLINFO_LINKMAP
163 const char *name;
164 struct link_map *lm = NULL;
165 dlinfo(plug->dl_handle, RTLD_DI_LINKMAP, &lm);
166 if (lm) {
167 name = strrchr(lm->l_name, '/');
168 name = name ? name + 1 : lm->l_name;
169 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 plug = plug->next;
179 }
180
181 vty_out(vty, "pid: %u\n", (uint32_t)(getpid()));
182
183 return CMD_SUCCESS;
184 }
185
186 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 char *profile = argv_concat(argv, argc, 2);
194 int rv = CMD_SUCCESS;
195
196 if (!frr_defaults_profile_valid(profile)) {
197 vty_out(vty, "%% WARNING: profile %s is not known in this version\n",
198 profile);
199 rv = CMD_WARNING;
200 }
201 frr_defaults_profile_set(profile);
202 XFREE(MTYPE_TMP, profile);
203 return rv;
204 }
205
206 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 char *version = argv_concat(argv, argc, 2);
214
215 frr_defaults_version_set(version);
216 XFREE(MTYPE_TMP, version);
217 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 DEFUN_NOSH(start_config, start_config_cmd, "XFRR_start_configuration",
229 "The Beginning of Configuration\n")
230 {
231 callback.readin_time = monotime(NULL);
232
233 vty->pending_allowed = 1;
234
235 if (callback.start_config)
236 (*callback.start_config)();
237
238 return CMD_SUCCESS;
239 }
240
241 DEFUN_NOSH(end_config, end_config_cmd, "XFRR_end_configuration",
242 "The End of Configuration\n")
243 {
244 time_t readin_time;
245 char readin_time_str[MONOTIME_STRLEN];
246 int ret;
247
248 readin_time = monotime(NULL);
249 readin_time -= callback.readin_time;
250
251 frrtime_to_interval(readin_time, readin_time_str,
252 sizeof(readin_time_str));
253
254 vty->pending_allowed = 0;
255 ret = nb_cli_pending_commit_check(vty);
256
257 zlog_info("Configuration Read in Took: %s", readin_time_str);
258
259 if (callback.end_config)
260 (*callback.end_config)();
261
262 return ret;
263 }
264
265 void cmd_init_config_callbacks(void (*start_config_cb)(void),
266 void (*end_config_cb)(void))
267 {
268 callback.start_config = start_config_cb;
269 callback.end_config = end_config_cb;
270 }
271
272
273 static void defaults_autocomplete(vector comps, struct cmd_token *token)
274 {
275 const char **p;
276
277 for (p = frr_defaults_profiles; *p; p++)
278 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, *p));
279 }
280
281 static const struct cmd_variable_handler default_var_handlers[] = {
282 {.tokenname = "PROFILE", .completions = defaults_autocomplete},
283 {.completions = NULL},
284 };
285
286 void lib_cmd_init(void)
287 {
288 cmd_variable_handler_register(default_var_handlers);
289
290 install_element(CONFIG_NODE, &frr_defaults_cmd);
291 install_element(CONFIG_NODE, &frr_version_cmd);
292
293 install_element(VIEW_NODE, &show_memory_cmd);
294 install_element(VIEW_NODE, &show_modules_cmd);
295
296 install_element(CONFIG_NODE, &start_config_cmd);
297 install_element(CONFIG_NODE, &end_config_cmd);
298 }
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 const char *mtype_memstr(char *buf, size_t len, unsigned long bytes)
309 {
310 unsigned int m, k;
311
312 /* easy cases */
313 if (!bytes)
314 return "0 bytes";
315 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 if (bytes > 0x7fffffff)
326 return "> 2GB";
327
328 m = bytes >> 20;
329 k = bytes >> 10;
330
331 if (m > 10) {
332 if (bytes & (1 << 19))
333 m++;
334 snprintf(buf, len, "%d MiB", m);
335 } else if (k > 10) {
336 if (bytes & (1 << 9))
337 k++;
338 snprintf(buf, len, "%d KiB", k);
339 } else
340 snprintf(buf, len, "%ld bytes", bytes);
341
342 return buf;
343 }