diff options
-rw-r--r-- | networking/brctl.c | 218 |
1 files changed, 215 insertions, 3 deletions
diff --git a/networking/brctl.c b/networking/brctl.c index ba5b6226f..e15710b5e 100644 --- a/networking/brctl.c +++ b/networking/brctl.c | |||
@@ -54,6 +54,7 @@ | |||
54 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" | 54 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" |
55 | //usage: IF_FEATURE_BRCTL_FANCY( | 55 | //usage: IF_FEATURE_BRCTL_FANCY( |
56 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" | 56 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off STP on/off" |
57 | //usage: "\n showstp BRIDGE Show stp info" | ||
57 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" | 58 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" |
58 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" | 59 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" |
59 | //usage: "\n sethello BRIDGE SECONDS Set hello time" | 60 | //usage: "\n sethello BRIDGE SECONDS Set hello time" |
@@ -65,7 +66,7 @@ | |||
65 | //usage: ) | 66 | //usage: ) |
66 | // Not yet implemented: | 67 | // Not yet implemented: |
67 | // hairpin BRIDGE IFACE on|off Hairpin on/off | 68 | // hairpin BRIDGE IFACE on|off Hairpin on/off |
68 | // showstp BRIDGE Show stp info | 69 | |
69 | 70 | ||
70 | #include "libbb.h" | 71 | #include "libbb.h" |
71 | #include "common_bufsiz.h" | 72 | #include "common_bufsiz.h" |
@@ -146,8 +147,7 @@ static int show_bridge(const char *name, int need_hdr) | |||
146 | 147 | ||
147 | if (need_hdr) | 148 | if (need_hdr) |
148 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); | 149 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); |
149 | printf("%s\t\t", name); | 150 | printf("%s\t\t%s\t", name, filedata); |
150 | printf("%s\t", filedata); | ||
151 | 151 | ||
152 | strcpy(sfx, "stp_state"); | 152 | strcpy(sfx, "stp_state"); |
153 | read_file(pathbuf); | 153 | read_file(pathbuf); |
@@ -279,6 +279,212 @@ static void show_bridge_macs(const char *name) | |||
279 | 279 | ||
280 | free(fdb); | 280 | free(fdb); |
281 | } | 281 | } |
282 | |||
283 | static void show_bridge_timer(const char *msg) | ||
284 | { | ||
285 | unsigned long long tvmsec = 10 * xstrtoull(filedata, 0); | ||
286 | unsigned tv_sec = tvmsec / 1000; | ||
287 | unsigned tv_msec = tvmsec % 1000; | ||
288 | printf("%s%4u.%.2u", msg, tv_sec, tv_msec / 10); | ||
289 | } | ||
290 | |||
291 | static const char *show_bridge_state(unsigned state) | ||
292 | { | ||
293 | /* See linux/if_bridge.h, BR_STATE_ constants */ | ||
294 | static const char state_names[] = | ||
295 | "disabled\0" //BR_STATE_DISABLED 0 | ||
296 | "listening\0" //BR_STATE_LISTENING 1 | ||
297 | "learning\0" //BR_STATE_LEARNING 2 | ||
298 | "forwarding\0" //BR_STATE_FORWARDING 3 | ||
299 | "blocking" //BR_STATE_BLOCKING 4 | ||
300 | ; | ||
301 | if (state < 5) | ||
302 | return nth_string(state_names, state); | ||
303 | return utoa(state); | ||
304 | } | ||
305 | |||
306 | static void printf_xstrtou(const char *fmt) | ||
307 | { | ||
308 | printf(fmt, xstrtou(filedata, 0)); | ||
309 | } | ||
310 | |||
311 | static void show_bridge_port(const char *name) | ||
312 | { | ||
313 | char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 32]; | ||
314 | char *sfx; | ||
315 | |||
316 | #if IFNAMSIZ == 16 | ||
317 | sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name); | ||
318 | #else | ||
319 | sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name); | ||
320 | #endif | ||
321 | |||
322 | strcpy(sfx, "port_no"); | ||
323 | read_file(pathbuf); | ||
324 | printf("%s (%u)\n", name, xstrtou(filedata, 0)); | ||
325 | |||
326 | strcpy(sfx + 5, "id"); // "port_id" | ||
327 | read_file(pathbuf); | ||
328 | printf_xstrtou(" port id\t\t%.4x"); | ||
329 | |||
330 | strcpy(sfx, "state"); | ||
331 | read_file(pathbuf); | ||
332 | printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0))); | ||
333 | |||
334 | strcpy(sfx, "designated_root"); | ||
335 | read_file(pathbuf); | ||
336 | printf(" designated root\t%s", filedata); | ||
337 | |||
338 | strcpy(sfx, "path_cost"); | ||
339 | read_file(pathbuf); | ||
340 | printf_xstrtou("\tpath cost\t\t%4u\n"); | ||
341 | |||
342 | strcpy(sfx, "designated_bridge"); | ||
343 | read_file(pathbuf); | ||
344 | printf(" designated bridge\t%s", filedata); | ||
345 | |||
346 | strcpy(sfx, "message_age_timer"); | ||
347 | read_file(pathbuf); | ||
348 | show_bridge_timer("\tmessage age timer\t"); | ||
349 | |||
350 | strcpy(sfx, "designated_port"); | ||
351 | read_file(pathbuf); | ||
352 | printf_xstrtou("\n designated port\t%.4x"); | ||
353 | |||
354 | strcpy(sfx, "forward_delay_timer"); | ||
355 | read_file(pathbuf); | ||
356 | show_bridge_timer("\t\t\tforward delay timer\t"); | ||
357 | |||
358 | strcpy(sfx, "designated_cost"); | ||
359 | read_file(pathbuf); | ||
360 | printf_xstrtou("\n designated cost\t%4u"); | ||
361 | |||
362 | strcpy(sfx, "hold_timer"); | ||
363 | read_file(pathbuf); | ||
364 | show_bridge_timer("\t\t\thold timer\t\t"); | ||
365 | |||
366 | printf("\n flags\t\t\t"); | ||
367 | |||
368 | strcpy(sfx, "config_pending"); | ||
369 | read_file(pathbuf); | ||
370 | if (!LONE_CHAR(filedata, '0')) | ||
371 | printf("CONFIG_PENDING "); | ||
372 | |||
373 | strcpy(sfx, "change_ack"); | ||
374 | read_file(pathbuf); | ||
375 | if (!LONE_CHAR(filedata, '0')) | ||
376 | printf("TOPOLOGY_CHANGE_ACK "); | ||
377 | |||
378 | strcpy(sfx, "hairpin_mode"); | ||
379 | read_file(pathbuf); | ||
380 | if (!LONE_CHAR(filedata, '0')) | ||
381 | printf_xstrtou("\n hairpin mode\t\t%4u"); | ||
382 | |||
383 | printf("\n\n"); | ||
384 | } | ||
385 | |||
386 | static void show_bridge_ports(const char *name) | ||
387 | { | ||
388 | DIR *ifaces; | ||
389 | struct dirent *ent; | ||
390 | char pathbuf[IFNAMSIZ + sizeof("/brif") + 8]; | ||
391 | |||
392 | #if IFNAMSIZ == 16 | ||
393 | sprintf(pathbuf, "%.16s/brif", name); | ||
394 | #else | ||
395 | sprintf(pathbuf, "%.*s/brif", (int)IFNAMSIZ, name); | ||
396 | #endif | ||
397 | ifaces = opendir(pathbuf); | ||
398 | if (ifaces) { | ||
399 | while ((ent = readdir(ifaces)) != NULL) { | ||
400 | if (DOT_OR_DOTDOT(ent->d_name)) | ||
401 | continue; /* . or .. */ | ||
402 | show_bridge_port(ent->d_name); | ||
403 | } | ||
404 | closedir(ifaces); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | static void show_bridge_stp(const char *name) | ||
409 | { | ||
410 | char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 32]; | ||
411 | char *sfx; | ||
412 | |||
413 | #if IFNAMSIZ == 16 | ||
414 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); | ||
415 | #else | ||
416 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); | ||
417 | #endif | ||
418 | |||
419 | strcpy(sfx, "bridge_id"); | ||
420 | if (read_file(pathbuf) < 0) | ||
421 | bb_error_msg_and_die("bridge %s does not exist", name); | ||
422 | |||
423 | printf("%s\n" | ||
424 | " bridge id\t\t%s", name, filedata); | ||
425 | |||
426 | strcpy(sfx, "root_id"); | ||
427 | read_file(pathbuf); | ||
428 | printf("\n designated root\t%s", filedata); | ||
429 | |||
430 | strcpy(sfx + 5, "port"); // "root_port" | ||
431 | read_file(pathbuf); | ||
432 | printf_xstrtou("\n root port\t\t%4u\t\t\t"); | ||
433 | |||
434 | strcpy(sfx + 6, "ath_cost"); // "root_path_cost" | ||
435 | read_file(pathbuf); | ||
436 | printf_xstrtou("path cost\t\t%4u\n"); | ||
437 | |||
438 | strcpy(sfx, "max_age"); | ||
439 | read_file(pathbuf); | ||
440 | show_bridge_timer(" max age\t\t"); | ||
441 | show_bridge_timer("\t\t\tbridge max age\t\t"); | ||
442 | |||
443 | strcpy(sfx, "hello_time"); | ||
444 | read_file(pathbuf); | ||
445 | show_bridge_timer("\n hello time\t\t"); | ||
446 | show_bridge_timer("\t\t\tbridge hello time\t"); | ||
447 | |||
448 | strcpy(sfx, "forward_delay"); | ||
449 | read_file(pathbuf); | ||
450 | show_bridge_timer("\n forward delay\t\t"); | ||
451 | show_bridge_timer("\t\t\tbridge forward delay\t"); | ||
452 | |||
453 | strcpy(sfx, "ageing_time"); | ||
454 | read_file(pathbuf); | ||
455 | show_bridge_timer("\n ageing time\t\t"); | ||
456 | |||
457 | strcpy(sfx, "hello_timer"); | ||
458 | read_file(pathbuf); | ||
459 | show_bridge_timer("\n hello timer\t\t"); | ||
460 | |||
461 | strcpy(sfx, "tcn_timer"); | ||
462 | read_file(pathbuf); | ||
463 | show_bridge_timer("\t\t\ttcn timer\t\t"); | ||
464 | |||
465 | strcpy(sfx, "topology_change_timer"); | ||
466 | read_file(pathbuf); | ||
467 | show_bridge_timer("\n topology change timer\t"); | ||
468 | |||
469 | strcpy(sfx, "gc_timer"); | ||
470 | read_file(pathbuf); | ||
471 | show_bridge_timer("\t\t\tgc timer\t\t"); | ||
472 | |||
473 | printf("\n flags\t\t\t"); | ||
474 | |||
475 | strcpy(sfx, "topology_change"); | ||
476 | read_file(pathbuf); | ||
477 | if (!LONE_CHAR(filedata, '0')) | ||
478 | printf("TOPOLOGY_CHANGE "); | ||
479 | |||
480 | strcpy(sfx, "topology_change_detected"); | ||
481 | read_file(pathbuf); | ||
482 | if (!LONE_CHAR(filedata, '0')) | ||
483 | printf("TOPOLOGY_CHANGE_DETECTED "); | ||
484 | printf("\n\n\n"); | ||
485 | |||
486 | show_bridge_ports(name); | ||
487 | } | ||
282 | #endif | 488 | #endif |
283 | 489 | ||
284 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 490 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -288,6 +494,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
288 | "addbr\0" "delbr\0" "addif\0" "delif\0" | 494 | "addbr\0" "delbr\0" "addif\0" "delif\0" |
289 | IF_FEATURE_BRCTL_FANCY( | 495 | IF_FEATURE_BRCTL_FANCY( |
290 | "stp\0" | 496 | "stp\0" |
497 | "showstp\0" | ||
291 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" | 498 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" |
292 | "setpathcost\0" "setportprio\0" | 499 | "setpathcost\0" "setportprio\0" |
293 | "setbridgeprio\0" | 500 | "setbridgeprio\0" |
@@ -297,6 +504,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
297 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif | 504 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif |
298 | IF_FEATURE_BRCTL_FANCY(, | 505 | IF_FEATURE_BRCTL_FANCY(, |
299 | ARG_stp, | 506 | ARG_stp, |
507 | ARG_showstp, | ||
300 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, | 508 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, |
301 | ARG_setpathcost, ARG_setportprio, | 509 | ARG_setpathcost, ARG_setportprio, |
302 | ARG_setbridgeprio, | 510 | ARG_setbridgeprio, |
@@ -388,6 +596,10 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) | |||
388 | show_bridge_macs(br); | 596 | show_bridge_macs(br); |
389 | return EXIT_SUCCESS; | 597 | return EXIT_SUCCESS; |
390 | } | 598 | } |
599 | if (key == ARG_showstp) { | ||
600 | show_bridge_stp(br); | ||
601 | return EXIT_SUCCESS; | ||
602 | } | ||
391 | 603 | ||
392 | if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ | 604 | if (!*argv) /* all but 'addbr/delbr' need at least two arguments */ |
393 | bb_show_usage(); | 605 | bb_show_usage(); |