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