]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/client/show.c
lldpcli: fix watch return code
[thirdparty/lldpd.git] / src / client / show.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "client.h"
19 #include <string.h>
20 #include <limits.h>
21
22 /**
23 * Show neighbors.
24 *
25 * The environment will contain the following keys:
26 * - C{ports} list of ports we want to restrict showing.
27 * - C{hidden} if we should show hidden ports.
28 * - C{summary} if we want to show only a summary
29 * - C{detailed} for a detailed overview
30 */
31 static int
32 cmd_show_neighbors(struct lldpctl_conn_t *conn, struct writer *w,
33 struct cmd_env *env, void *arg)
34 {
35 log_debug("lldpctl", "show neighbors data (%s) %s hidden neighbors",
36 cmdenv_get(env, "summary")?"summary":
37 cmdenv_get(env, "detailed")?"detailed":
38 "normal", cmdenv_get(env, "hidden")?"with":"without");
39 if (cmdenv_get(env, "ports"))
40 log_debug("lldpctl", "restrict to the following ports: %s",
41 cmdenv_get(env, "ports"));
42
43 display_interfaces(conn, w, env, !!cmdenv_get(env, "hidden"),
44 cmdenv_get(env, "summary")?DISPLAY_BRIEF:
45 cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
46 DISPLAY_NORMAL);
47
48 return 1;
49 }
50
51 /**
52 * Show chassis.
53 *
54 * The environment will contain the following keys:
55 * - C{summary} if we want to show only a summary
56 * - C{detailed} for a detailed overview
57 */
58 static int
59 cmd_show_chassis(struct lldpctl_conn_t *conn, struct writer *w,
60 struct cmd_env *env, void *arg)
61 {
62 log_debug("lldpctl", "show chassis data (%s)",
63 cmdenv_get(env, "summary")?"summary":
64 cmdenv_get(env, "detailed")?"detailed":
65 "normal");
66
67 display_local_chassis(conn, w, env,
68 cmdenv_get(env, "summary")?DISPLAY_BRIEF:
69 cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
70 DISPLAY_NORMAL);
71
72 return 1;
73 }
74
75 /**
76 * Show stats.
77 *
78 * The environment will contain the following keys:
79 * - C{ports} list of ports we want to restrict showing.
80 * - C{summary} summary of stats
81 */
82 static int
83 cmd_show_interface_stats(struct lldpctl_conn_t *conn, struct writer *w,
84 struct cmd_env *env, void *arg)
85 {
86 log_debug("lldpctl", "show stats data");
87 if (cmdenv_get(env, "ports"))
88 log_debug("lldpctl", "restrict to the following ports: %s",
89 cmdenv_get(env, "ports"));
90 if (cmdenv_get(env, "summary"))
91 log_debug("lldpctl", "show summary of stats across ports");
92
93 display_interfaces_stats(conn, w, env);
94
95 return 1;
96 }
97
98 static int
99 cmd_check_no_detailed_nor_summary(struct cmd_env *env, void *arg)
100 {
101 if (cmdenv_get(env, "detailed")) return 0;
102 if (cmdenv_get(env, "summary")) return 0;
103 return 1;
104 }
105
106 /**
107 * Show running configuration.
108 */
109 static int
110 cmd_show_configuration(struct lldpctl_conn_t *conn, struct writer *w,
111 struct cmd_env *env, void *arg)
112 {
113 log_debug("lldpctl", "show running configuration");
114 display_configuration(conn, w);
115 return 1;
116 }
117
118 struct watcharg {
119 struct cmd_env *env;
120 struct writer *w;
121 size_t nb;
122 };
123
124 /**
125 * Callback for the next function to display a new neighbor.
126 */
127 static void
128 watchcb(lldpctl_conn_t *conn,
129 lldpctl_change_t type,
130 lldpctl_atom_t *interface,
131 lldpctl_atom_t *neighbor,
132 void *data)
133 {
134 struct watcharg *wa = data;
135 struct cmd_env *env = wa->env;
136 struct writer *w = wa->w;
137 const char *interfaces = cmdenv_get(env, "ports");
138 const char *proto_str;
139 int protocol = LLDPD_MODE_MAX;
140
141 if (interfaces && !contains(interfaces, lldpctl_atom_get_str(interface,
142 lldpctl_k_interface_name)))
143 return;
144
145 /* user might have specified protocol to filter display results */
146 proto_str = cmdenv_get(env, "protocol");
147
148 if (proto_str) {
149 log_debug("display", "filter protocol: %s ", proto_str);
150
151 protocol = 0; /* unsupported */
152 for (lldpctl_map_t *protocol_map =
153 lldpctl_key_get_map(lldpctl_k_port_protocol);
154 protocol_map->string;
155 protocol_map++) {
156 if (!strcasecmp(proto_str, protocol_map->string)) {
157 protocol = protocol_map->value;
158 break;
159 }
160 }
161 }
162
163 switch (type) {
164 case lldpctl_c_deleted:
165 tag_start(w, "lldp-deleted", "LLDP neighbor deleted");
166 break;
167 case lldpctl_c_updated:
168 tag_start(w, "lldp-updated", "LLDP neighbor updated");
169 break;
170 case lldpctl_c_added:
171 tag_start(w, "lldp-added", "LLDP neighbor added");
172 break;
173 default: return;
174 }
175 display_interface(conn, w, 1, interface, neighbor,
176 cmdenv_get(env, "summary")?DISPLAY_BRIEF:
177 cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
178 DISPLAY_NORMAL, protocol);
179 tag_end(w);
180 wa->nb++;
181 }
182
183 /**
184 * Watch for neighbor changes.
185 */
186 static int
187 cmd_watch_neighbors(struct lldpctl_conn_t *conn, struct writer *w,
188 struct cmd_env *env, void *arg)
189 {
190 struct watcharg wa = {
191 .env = env,
192 .w = w,
193 .nb = 0
194 };
195 const char *limit_str = cmdenv_get(env, "limit");
196 size_t limit = 0;
197
198 if (limit_str) {
199 const char *errstr;
200 limit = strtonum(limit_str, 1, LLONG_MAX, &errstr);
201 if (errstr != NULL) {
202 log_warnx("lldpctl", "specified limit (%s) is %s and ignored",
203 limit_str, errstr);
204 }
205 }
206
207 log_debug("lldpctl", "watch for neighbor changes");
208 if (lldpctl_watch_callback(conn, watchcb, &wa) < 0) {
209 log_warnx("lldpctl", "unable to watch for neighbors. %s",
210 lldpctl_last_strerror(conn));
211 return 0;
212 }
213 while (1) {
214 if (lldpctl_watch(conn) < 0) {
215 log_warnx("lldpctl", "unable to watch for neighbors. %s",
216 lldpctl_last_strerror(conn));
217 return 0;
218 }
219 if (limit > 0 && wa.nb >= limit)
220 return 1;
221 }
222 return 0;
223 }
224
225 /**
226 * Register common subcommands for `watch` and `show neighbors` and `show chassis'
227 */
228 void
229 register_common_commands(struct cmd_node *root, int neighbor)
230 {
231 /* With more details */
232 commands_new(root,
233 "details",
234 "With more details",
235 cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "detailed");
236
237 /* With less details */
238 commands_new(root,
239 "summary",
240 "With less details",
241 cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary");
242
243 if (!neighbor) return;
244
245 /* With hidden neighbors */
246 commands_new(root,
247 "hidden",
248 "Include hidden neighbors",
249 cmd_check_no_env, cmd_store_env_and_pop, "hidden");
250
251 /* Some specific port */
252 cmd_restrict_ports(root);
253
254 /* Specific protocol */
255 cmd_restrict_protocol(root);
256 }
257
258 /**
259 * Register sub command summary
260 */
261 void
262 register_summary_command(struct cmd_node *root)
263 {
264 commands_new(root,
265 "summary",
266 "With less details",
267 cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary");
268 }
269
270 /**
271 * Register subcommands to `show`
272 *
273 * @param root Root node
274 */
275 void
276 register_commands_show(struct cmd_node *root)
277 {
278 struct cmd_node *show = commands_new(
279 root,
280 "show",
281 "Show running system information",
282 NULL, NULL, NULL);
283 struct cmd_node *neighbors = commands_new(
284 show,
285 "neighbors",
286 "Show neighbors data",
287 NULL, NULL, NULL);
288
289 struct cmd_node *chassis = commands_new(
290 show,
291 "chassis",
292 "Show local chassis data",
293 NULL, NULL, NULL);
294
295 struct cmd_node *stats = commands_new(
296 show,
297 "statistics",
298 "Show statistics",
299 NULL, NULL, NULL);
300
301 /* Neighbors data */
302 commands_new(neighbors,
303 NEWLINE,
304 "Show neighbors data",
305 NULL, cmd_show_neighbors, NULL);
306
307 register_common_commands(neighbors, 1);
308
309 /* Chassis data */
310 commands_new(chassis,
311 NEWLINE,
312 "Show local chassis data",
313 NULL, cmd_show_chassis, NULL);
314
315 register_common_commands(chassis, 0);
316
317 /* Stats data */
318 commands_new(stats,
319 NEWLINE,
320 "Show stats data",
321 NULL, cmd_show_interface_stats, NULL);
322
323 cmd_restrict_ports(stats);
324 register_summary_command(stats);
325
326 /* Register "show configuration" and "show running-configuration" */
327 commands_new(
328 commands_new(show,
329 "configuration",
330 "Show running configuration",
331 NULL, NULL, NULL),
332 NEWLINE,
333 "Show running configuration",
334 NULL, cmd_show_configuration, NULL);
335 commands_new(
336 commands_new(show,
337 "running-configuration",
338 "Show running configuration",
339 NULL, NULL, NULL),
340 NEWLINE,
341 "Show running configuration",
342 NULL, cmd_show_configuration, NULL);
343 }
344
345 /**
346 * Register subcommands to `watch`
347 *
348 * @param root Root node
349 */
350 void
351 register_commands_watch(struct cmd_node *root)
352 {
353 struct cmd_node *watch = commands_new(
354 root,
355 "watch",
356 "Monitor neighbor changes",
357 NULL, NULL, NULL);
358
359 commands_new(watch,
360 NEWLINE,
361 "Monitor neighbors change",
362 NULL, cmd_watch_neighbors, NULL);
363
364 commands_new(
365 commands_new(watch,
366 "limit",
367 "Don't show more than X events",
368 cmd_check_no_env, NULL, "limit"),
369 NULL,
370 "Stop after getting X events",
371 NULL, cmd_store_env_value_and_pop2, "limit");
372
373 register_common_commands(watch, 1);
374 }