]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
718e3744 | 2 | /* |
1c0d8808 | 3 | * Assorted library VTY commands |
718e3744 | 4 | * |
b249c083 DL |
5 | * Copyright (C) 1998 Kunihiro Ishiguro |
6 | * Copyright (C) 2016-2017 David Lamparter for NetDEF, Inc. | |
718e3744 | 7 | */ |
8 | ||
9 | #include <zebra.h> | |
d09552d0 | 10 | /* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */ |
fa896a1d | 11 | #ifdef HAVE_MALLOC_H |
41be32bf | 12 | #include <malloc.h> |
fa896a1d DL |
13 | #endif |
14 | #ifdef HAVE_MALLOC_MALLOC_H | |
15 | #include <malloc/malloc.h> | |
16 | #endif | |
b249c083 | 17 | #include <dlfcn.h> |
7b90f00c | 18 | #ifdef HAVE_LINK_H |
b249c083 | 19 | #include <link.h> |
7b90f00c | 20 | #endif |
718e3744 | 21 | |
22 | #include "log.h" | |
23 | #include "memory.h" | |
b249c083 | 24 | #include "module.h" |
ac4adef4 | 25 | #include "defaults.h" |
1c0d8808 | 26 | #include "lib_vty.h" |
fd396924 | 27 | #include "northbound_cli.h" |
6b0655a2 | 28 | |
718e3744 | 29 | /* Looking up memory status from vty interface. */ |
30 | #include "vector.h" | |
31 | #include "vty.h" | |
32 | #include "command.h" | |
33 | ||
51ab4dba | 34 | #if defined(HAVE_MALLINFO2) || defined(HAVE_MALLINFO) |
d62a17ae | 35 | static int show_memory_mallinfo(struct vty *vty) |
41be32bf | 36 | { |
51ab4dba QY |
37 | #if defined(HAVE_MALLINFO2) |
38 | struct mallinfo2 minfo = mallinfo2(); | |
39 | #elif defined(HAVE_MALLINFO) | |
d62a17ae | 40 | struct mallinfo minfo = mallinfo(); |
51ab4dba | 41 | #endif |
d62a17ae | 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; | |
41be32bf PJ |
65 | } |
66 | #endif /* HAVE_MALLINFO */ | |
67 | ||
3b4cd783 DL |
68 | static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt) |
69 | { | |
70 | struct vty *vty = arg; | |
13f1ba41 | 71 | if (!mt) { |
d62a17ae | 72 | vty_out(vty, "--- qmem %s ---\n", mg->name); |
13f1ba41 LB |
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 { | |
a0c5e446 | 88 | if (mt->n_max != 0) { |
3694c43a DS |
89 | char size[32]; |
90 | snprintf(size, sizeof(size), "%6zu", mt->size); | |
602a6584 DL |
91 | #ifdef HAVE_MALLOC_USABLE_SIZE |
92 | #define TSTR " %9zu" | |
93 | #define TARG , mt->total | |
13f1ba41 | 94 | #define TARG2 , mt->max_size |
602a6584 DL |
95 | #else |
96 | #define TSTR "" | |
97 | #define TARG | |
13f1ba41 | 98 | #define TARG2 |
602a6584 | 99 | #endif |
13f1ba41 LB |
100 | vty_out(vty, "%-30s: %8zu %-8s"TSTR" %8zu"TSTR"\n", |
101 | mt->name, | |
d62a17ae | 102 | mt->n_alloc, |
103 | mt->size == 0 ? "" | |
104 | : mt->size == SIZE_VAR | |
13f1ba41 | 105 | ? "variable" |
602a6584 | 106 | : size |
13f1ba41 LB |
107 | TARG, |
108 | mt->n_max | |
109 | TARG2); | |
3694c43a | 110 | } |
3b4cd783 DL |
111 | } |
112 | return 0; | |
113 | } | |
114 | ||
115 | ||
1c0d8808 DL |
116 | DEFUN_NOSH (show_memory, |
117 | show_memory_cmd, | |
118 | "show memory", | |
119 | "Show running system information\n" | |
120 | "Memory statistics\n") | |
718e3744 | 121 | { |
41be32bf | 122 | #ifdef HAVE_MALLINFO |
d62a17ae | 123 | show_memory_mallinfo(vty); |
41be32bf | 124 | #endif /* HAVE_MALLINFO */ |
fc7948fa | 125 | |
d62a17ae | 126 | qmem_walk(qmem_walker, vty); |
127 | return CMD_SUCCESS; | |
718e3744 | 128 | } |
129 | ||
1c0d8808 DL |
130 | DEFUN_NOSH (show_modules, |
131 | show_modules_cmd, | |
132 | "show modules", | |
133 | "Show running system information\n" | |
134 | "Loaded modules\n") | |
b249c083 | 135 | { |
d62a17ae | 136 | struct frrmod_runtime *plug = frrmod_list; |
b249c083 | 137 | |
d62a17ae | 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; | |
b249c083 | 142 | |
d62a17ae | 143 | vty_out(vty, "%-12s %-25s %s\n", i->name, i->version, |
144 | i->description); | |
145 | if (plug->dl_handle) { | |
b249c083 | 146 | #ifdef HAVE_DLINFO_ORIGIN |
d62a17ae | 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 | } | |
b249c083 | 158 | #else |
d62a17ae | 159 | vty_out(vty, "\tfrom: %s \n", origin, plug->load_name); |
b249c083 | 160 | #endif |
d62a17ae | 161 | #else |
162 | vty_out(vty, "\tfrom: %s\n", plug->load_name); | |
163 | #endif | |
164 | } | |
165 | plug = plug->next; | |
166 | } | |
bfae97a6 MS |
167 | |
168 | vty_out(vty, "pid: %u\n", (uint32_t)(getpid())); | |
169 | ||
d62a17ae | 170 | return CMD_SUCCESS; |
b249c083 DL |
171 | } |
172 | ||
ac4adef4 DL |
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 | ||
f8e6ada8 | 207 | static struct call_back { |
16ae941f DS |
208 | time_t readin_time; |
209 | ||
f8e6ada8 DS |
210 | void (*start_config)(void); |
211 | void (*end_config)(void); | |
212 | } callback; | |
213 | ||
16ae941f | 214 | |
e6648f01 DS |
215 | DEFUN_NOSH(start_config, start_config_cmd, "XFRR_start_configuration", |
216 | "The Beginning of Configuration\n") | |
f8e6ada8 | 217 | { |
16ae941f DS |
218 | callback.readin_time = monotime(NULL); |
219 | ||
fd396924 CH |
220 | vty->pending_allowed = 1; |
221 | ||
f8e6ada8 DS |
222 | if (callback.start_config) |
223 | (*callback.start_config)(); | |
224 | ||
225 | return CMD_SUCCESS; | |
226 | } | |
227 | ||
e6648f01 DS |
228 | DEFUN_NOSH(end_config, end_config_cmd, "XFRR_end_configuration", |
229 | "The End of Configuration\n") | |
f8e6ada8 | 230 | { |
16ae941f DS |
231 | time_t readin_time; |
232 | char readin_time_str[MONOTIME_STRLEN]; | |
fd396924 | 233 | int ret; |
16ae941f DS |
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 | ||
fd396924 CH |
241 | vty->pending_allowed = 0; |
242 | ret = nb_cli_pending_commit_check(vty); | |
243 | ||
16ae941f | 244 | zlog_info("Configuration Read in Took: %s", readin_time_str); |
1401ee8b PS |
245 | zlog_debug("%s: VTY:%p, pending SET-CFG: %u", |
246 | __func__, vty, (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()) | |
ef43a632 CH |
255 | vty_mgmt_send_commit_config(vty, false, false); |
256 | ||
f8e6ada8 DS |
257 | if (callback.end_config) |
258 | (*callback.end_config)(); | |
259 | ||
fd396924 | 260 | return ret; |
f8e6ada8 DS |
261 | } |
262 | ||
62b43962 IR |
263 | void cmd_init_config_callbacks(void (*start_config_cb)(void), |
264 | void (*end_config_cb)(void)) | |
f8e6ada8 | 265 | { |
62b43962 IR |
266 | callback.start_config = start_config_cb; |
267 | callback.end_config = end_config_cb; | |
f8e6ada8 DS |
268 | } |
269 | ||
270 | ||
ac4adef4 DL |
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 | ||
1c0d8808 | 284 | void lib_cmd_init(void) |
718e3744 | 285 | { |
ac4adef4 DL |
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 | ||
d62a17ae | 291 | install_element(VIEW_NODE, &show_memory_cmd); |
292 | install_element(VIEW_NODE, &show_modules_cmd); | |
f8e6ada8 DS |
293 | |
294 | install_element(CONFIG_NODE, &start_config_cmd); | |
295 | install_element(CONFIG_NODE, &end_config_cmd); | |
718e3744 | 296 | } |
6b0655a2 | 297 | |
41be32bf PJ |
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 | */ | |
d62a17ae | 306 | const char *mtype_memstr(char *buf, size_t len, unsigned long bytes) |
41be32bf | 307 | { |
d62a17ae | 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; | |
41be32bf | 341 | } |