]>
Commit | Line | Data |
---|---|---|
9a775667 VB |
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" | |
7efa65c1 | 19 | #include <string.h> |
a7c54949 | 20 | #include <limits.h> |
9a775667 VB |
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 | ||
a54f6012 SW |
51 | /** |
52 | * Show interfaces. | |
53 | * | |
54 | * The environment will contain the following keys: | |
55 | * - C{ports} list of ports we want to restrict showing. | |
56 | * - C{hidden} if we should show hidden ports. | |
57 | * - C{summary} if we want to show only a summary | |
58 | * - C{detailed} for a detailed overview | |
59 | */ | |
60 | static int | |
61 | cmd_show_interfaces(struct lldpctl_conn_t *conn, struct writer *w, | |
62 | struct cmd_env *env, void *arg) | |
63 | { | |
64 | log_debug("lldpctl", "show interfaces data (%s) %s hidden interfaces", | |
65 | cmdenv_get(env, "summary")?"summary": | |
66 | cmdenv_get(env, "detailed")?"detailed": | |
67 | "normal", cmdenv_get(env, "hidden")?"with":"without"); | |
68 | if (cmdenv_get(env, "ports")) | |
69 | log_debug("lldpctl", "restrict to the following ports: %s", | |
70 | cmdenv_get(env, "ports")); | |
71 | ||
72 | display_local_interfaces(conn, w, env, !!cmdenv_get(env, "hidden"), | |
73 | cmdenv_get(env, "summary")?DISPLAY_BRIEF: | |
74 | cmdenv_get(env, "detailed")?DISPLAY_DETAILS: | |
75 | DISPLAY_NORMAL); | |
76 | ||
77 | return 1; | |
78 | } | |
79 | ||
3407e638 VB |
80 | /** |
81 | * Show chassis. | |
82 | * | |
83 | * The environment will contain the following keys: | |
84 | * - C{summary} if we want to show only a summary | |
85 | * - C{detailed} for a detailed overview | |
86 | */ | |
87 | static int | |
88 | cmd_show_chassis(struct lldpctl_conn_t *conn, struct writer *w, | |
89 | struct cmd_env *env, void *arg) | |
90 | { | |
91 | log_debug("lldpctl", "show chassis data (%s)", | |
92 | cmdenv_get(env, "summary")?"summary": | |
93 | cmdenv_get(env, "detailed")?"detailed": | |
94 | "normal"); | |
95 | ||
96 | display_local_chassis(conn, w, env, | |
97 | cmdenv_get(env, "summary")?DISPLAY_BRIEF: | |
98 | cmdenv_get(env, "detailed")?DISPLAY_DETAILS: | |
99 | DISPLAY_NORMAL); | |
100 | ||
101 | return 1; | |
102 | } | |
103 | ||
78356144 | 104 | /** |
105 | * Show stats. | |
106 | * | |
107 | * The environment will contain the following keys: | |
108 | * - C{ports} list of ports we want to restrict showing. | |
5331eb2d | 109 | * - C{summary} summary of stats |
78356144 | 110 | */ |
111 | static int | |
112 | cmd_show_interface_stats(struct lldpctl_conn_t *conn, struct writer *w, | |
113 | struct cmd_env *env, void *arg) | |
114 | { | |
115 | log_debug("lldpctl", "show stats data"); | |
116 | if (cmdenv_get(env, "ports")) | |
adcb76f8 | 117 | log_debug("lldpctl", "restrict to the following ports: %s", |
78356144 | 118 | cmdenv_get(env, "ports")); |
5331eb2d | 119 | if (cmdenv_get(env, "summary")) |
44fb3587 | 120 | log_debug("lldpctl", "show summary of stats across ports"); |
78356144 | 121 | |
122 | display_interfaces_stats(conn, w, env); | |
123 | ||
124 | return 1; | |
125 | } | |
126 | ||
9a775667 VB |
127 | static int |
128 | cmd_check_no_detailed_nor_summary(struct cmd_env *env, void *arg) | |
129 | { | |
130 | if (cmdenv_get(env, "detailed")) return 0; | |
131 | if (cmdenv_get(env, "summary")) return 0; | |
132 | return 1; | |
133 | } | |
134 | ||
135 | /** | |
136 | * Show running configuration. | |
137 | */ | |
138 | static int | |
139 | cmd_show_configuration(struct lldpctl_conn_t *conn, struct writer *w, | |
140 | struct cmd_env *env, void *arg) | |
141 | { | |
142 | log_debug("lldpctl", "show running configuration"); | |
143 | display_configuration(conn, w); | |
144 | return 1; | |
145 | } | |
146 | ||
bd8a8861 VB |
147 | struct watcharg { |
148 | struct cmd_env *env; | |
149 | struct writer *w; | |
a7c54949 | 150 | size_t nb; |
bd8a8861 VB |
151 | }; |
152 | ||
9a775667 VB |
153 | /** |
154 | * Callback for the next function to display a new neighbor. | |
155 | */ | |
156 | static void | |
157 | watchcb(lldpctl_conn_t *conn, | |
158 | lldpctl_change_t type, | |
159 | lldpctl_atom_t *interface, | |
160 | lldpctl_atom_t *neighbor, | |
161 | void *data) | |
162 | { | |
bd8a8861 VB |
163 | struct watcharg *wa = data; |
164 | struct cmd_env *env = wa->env; | |
165 | struct writer *w = wa->w; | |
9a775667 | 166 | const char *interfaces = cmdenv_get(env, "ports"); |
7efa65c1 | 167 | const char *proto_str; |
494264f0 ST |
168 | int protocol = LLDPD_MODE_MAX; |
169 | ||
9a775667 VB |
170 | if (interfaces && !contains(interfaces, lldpctl_atom_get_str(interface, |
171 | lldpctl_k_interface_name))) | |
172 | return; | |
173 | ||
494264f0 ST |
174 | /* user might have specified protocol to filter display results */ |
175 | proto_str = cmdenv_get(env, "protocol"); | |
176 | ||
177 | if (proto_str) { | |
178 | log_debug("display", "filter protocol: %s ", proto_str); | |
179 | ||
7efa65c1 VB |
180 | protocol = 0; /* unsupported */ |
181 | for (lldpctl_map_t *protocol_map = | |
182 | lldpctl_key_get_map(lldpctl_k_port_protocol); | |
183 | protocol_map->string; | |
184 | protocol_map++) { | |
185 | if (!strcasecmp(proto_str, protocol_map->string)) { | |
186 | protocol = protocol_map->value; | |
187 | break; | |
188 | } | |
189 | } | |
494264f0 ST |
190 | } |
191 | ||
9a775667 VB |
192 | switch (type) { |
193 | case lldpctl_c_deleted: | |
194 | tag_start(w, "lldp-deleted", "LLDP neighbor deleted"); | |
195 | break; | |
196 | case lldpctl_c_updated: | |
197 | tag_start(w, "lldp-updated", "LLDP neighbor updated"); | |
198 | break; | |
199 | case lldpctl_c_added: | |
200 | tag_start(w, "lldp-added", "LLDP neighbor added"); | |
201 | break; | |
202 | default: return; | |
203 | } | |
204 | display_interface(conn, w, 1, interface, neighbor, | |
205 | cmdenv_get(env, "summary")?DISPLAY_BRIEF: | |
206 | cmdenv_get(env, "detailed")?DISPLAY_DETAILS: | |
494264f0 | 207 | DISPLAY_NORMAL, protocol); |
9a775667 | 208 | tag_end(w); |
a7c54949 | 209 | wa->nb++; |
9a775667 VB |
210 | } |
211 | ||
212 | /** | |
213 | * Watch for neighbor changes. | |
214 | */ | |
215 | static int | |
216 | cmd_watch_neighbors(struct lldpctl_conn_t *conn, struct writer *w, | |
217 | struct cmd_env *env, void *arg) | |
218 | { | |
bd8a8861 VB |
219 | struct watcharg wa = { |
220 | .env = env, | |
a7c54949 VB |
221 | .w = w, |
222 | .nb = 0 | |
bd8a8861 | 223 | }; |
a7c54949 VB |
224 | const char *limit_str = cmdenv_get(env, "limit"); |
225 | size_t limit = 0; | |
226 | ||
227 | if (limit_str) { | |
228 | const char *errstr; | |
229 | limit = strtonum(limit_str, 1, LLONG_MAX, &errstr); | |
230 | if (errstr != NULL) { | |
231 | log_warnx("lldpctl", "specified limit (%s) is %s and ignored", | |
232 | limit_str, errstr); | |
233 | } | |
234 | } | |
235 | ||
9a775667 | 236 | log_debug("lldpctl", "watch for neighbor changes"); |
bd8a8861 | 237 | if (lldpctl_watch_callback(conn, watchcb, &wa) < 0) { |
9a775667 VB |
238 | log_warnx("lldpctl", "unable to watch for neighbors. %s", |
239 | lldpctl_last_strerror(conn)); | |
240 | return 0; | |
241 | } | |
9122b2c9 | 242 | while (1) { |
9a775667 VB |
243 | if (lldpctl_watch(conn) < 0) { |
244 | log_warnx("lldpctl", "unable to watch for neighbors. %s", | |
245 | lldpctl_last_strerror(conn)); | |
9122b2c9 | 246 | return 0; |
9a775667 | 247 | } |
a7c54949 | 248 | if (limit > 0 && wa.nb >= limit) |
9122b2c9 | 249 | return 1; |
9a775667 VB |
250 | } |
251 | return 0; | |
252 | } | |
253 | ||
254 | /** | |
3407e638 | 255 | * Register common subcommands for `watch` and `show neighbors` and `show chassis' |
9a775667 VB |
256 | */ |
257 | void | |
3407e638 | 258 | register_common_commands(struct cmd_node *root, int neighbor) |
9a775667 | 259 | { |
9a775667 VB |
260 | /* With more details */ |
261 | commands_new(root, | |
262 | "details", | |
263 | "With more details", | |
264 | cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "detailed"); | |
265 | ||
266 | /* With less details */ | |
267 | commands_new(root, | |
268 | "summary", | |
269 | "With less details", | |
270 | cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary"); | |
271 | ||
3407e638 VB |
272 | if (!neighbor) return; |
273 | ||
274 | /* With hidden neighbors */ | |
275 | commands_new(root, | |
276 | "hidden", | |
277 | "Include hidden neighbors", | |
278 | cmd_check_no_env, cmd_store_env_and_pop, "hidden"); | |
279 | ||
9a775667 | 280 | /* Some specific port */ |
e688f90f | 281 | cmd_restrict_ports(root); |
494264f0 ST |
282 | |
283 | /* Specific protocol */ | |
284 | cmd_restrict_protocol(root); | |
9a775667 VB |
285 | } |
286 | ||
5331eb2d | 287 | /** |
288 | * Register sub command summary | |
289 | */ | |
290 | void | |
291 | register_summary_command(struct cmd_node *root) | |
292 | { | |
293 | commands_new(root, | |
294 | "summary", | |
295 | "With less details", | |
296 | cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary"); | |
297 | } | |
298 | ||
9a775667 VB |
299 | /** |
300 | * Register subcommands to `show` | |
301 | * | |
302 | * @param root Root node | |
303 | */ | |
304 | void | |
305 | register_commands_show(struct cmd_node *root) | |
306 | { | |
307 | struct cmd_node *show = commands_new( | |
308 | root, | |
309 | "show", | |
310 | "Show running system information", | |
311 | NULL, NULL, NULL); | |
312 | struct cmd_node *neighbors = commands_new( | |
313 | show, | |
314 | "neighbors", | |
315 | "Show neighbors data", | |
316 | NULL, NULL, NULL); | |
317 | ||
a54f6012 SW |
318 | struct cmd_node *interfaces = commands_new( |
319 | show, | |
320 | "interfaces", | |
321 | "Show interfaces data", | |
322 | NULL, NULL, NULL); | |
323 | ||
3407e638 VB |
324 | struct cmd_node *chassis = commands_new( |
325 | show, | |
326 | "chassis", | |
327 | "Show local chassis data", | |
328 | NULL, NULL, NULL); | |
329 | ||
78356144 | 330 | struct cmd_node *stats = commands_new( |
331 | show, | |
332 | "statistics", | |
333 | "Show statistics", | |
334 | NULL, NULL, NULL); | |
335 | ||
9a775667 VB |
336 | /* Neighbors data */ |
337 | commands_new(neighbors, | |
338 | NEWLINE, | |
339 | "Show neighbors data", | |
340 | NULL, cmd_show_neighbors, NULL); | |
341 | ||
3407e638 VB |
342 | register_common_commands(neighbors, 1); |
343 | ||
a54f6012 SW |
344 | /* Interfaces data */ |
345 | commands_new(interfaces, | |
346 | NEWLINE, | |
347 | "Show interfaces data", | |
348 | NULL, cmd_show_interfaces, NULL); | |
349 | ||
350 | cmd_restrict_ports(interfaces); | |
351 | register_common_commands(interfaces, 0); | |
352 | ||
3407e638 VB |
353 | /* Chassis data */ |
354 | commands_new(chassis, | |
355 | NEWLINE, | |
356 | "Show local chassis data", | |
357 | NULL, cmd_show_chassis, NULL); | |
358 | ||
359 | register_common_commands(chassis, 0); | |
9a775667 | 360 | |
78356144 | 361 | /* Stats data */ |
362 | commands_new(stats, | |
363 | NEWLINE, | |
364 | "Show stats data", | |
365 | NULL, cmd_show_interface_stats, NULL); | |
366 | ||
ddfbab08 | 367 | cmd_restrict_ports(stats); |
5331eb2d | 368 | register_summary_command(stats); |
78356144 | 369 | |
9a775667 VB |
370 | /* Register "show configuration" and "show running-configuration" */ |
371 | commands_new( | |
372 | commands_new(show, | |
373 | "configuration", | |
374 | "Show running configuration", | |
375 | NULL, NULL, NULL), | |
376 | NEWLINE, | |
377 | "Show running configuration", | |
378 | NULL, cmd_show_configuration, NULL); | |
379 | commands_new( | |
380 | commands_new(show, | |
381 | "running-configuration", | |
382 | "Show running configuration", | |
383 | NULL, NULL, NULL), | |
384 | NEWLINE, | |
385 | "Show running configuration", | |
386 | NULL, cmd_show_configuration, NULL); | |
387 | } | |
388 | ||
389 | /** | |
390 | * Register subcommands to `watch` | |
391 | * | |
392 | * @param root Root node | |
393 | */ | |
394 | void | |
395 | register_commands_watch(struct cmd_node *root) | |
396 | { | |
397 | struct cmd_node *watch = commands_new( | |
398 | root, | |
399 | "watch", | |
400 | "Monitor neighbor changes", | |
401 | NULL, NULL, NULL); | |
402 | ||
9a775667 VB |
403 | commands_new(watch, |
404 | NEWLINE, | |
405 | "Monitor neighbors change", | |
406 | NULL, cmd_watch_neighbors, NULL); | |
407 | ||
a7c54949 VB |
408 | commands_new( |
409 | commands_new(watch, | |
410 | "limit", | |
411 | "Don't show more than X events", | |
412 | cmd_check_no_env, NULL, "limit"), | |
413 | NULL, | |
414 | "Stop after getting X events", | |
415 | NULL, cmd_store_env_value_and_pop2, "limit"); | |
416 | ||
3407e638 | 417 | register_common_commands(watch, 1); |
9a775667 | 418 | } |