2 Command parsing taken from brctl utility.
3 Display code from stp_cli.c in rstplib.
14 /* For scanning through sysfs directories */
16 #include <sys/types.h>
20 #include "ctl_socket_client.h"
21 #include "ctl_functions.h"
28 #define STP_IN_get_error_explanation CTL_error_explanation
30 static void print_bridge_id(UID_BRIDGE_ID_T
* bridge_id
, unsigned char cr
)
32 printf("%04lX-%02x%02x%02x%02x%02x%02x",
33 (unsigned long)bridge_id
->prio
,
34 (unsigned char)bridge_id
->addr
[0],
35 (unsigned char)bridge_id
->addr
[1],
36 (unsigned char)bridge_id
->addr
[2],
37 (unsigned char)bridge_id
->addr
[3],
38 (unsigned char)bridge_id
->addr
[4],
39 (unsigned char)bridge_id
->addr
[5]);
44 static char *stp_state2str(RSTP_PORT_STATE stp_port_state
, int detail
)
47 switch (stp_port_state
) {
48 case UID_PORT_DISABLED
:
50 case UID_PORT_DISCARDING
:
52 case UID_PORT_LEARNING
:
54 case UID_PORT_FORWARDING
:
56 case UID_PORT_NON_STP
:
63 switch (stp_port_state
) {
64 case UID_PORT_DISABLED
:
66 case UID_PORT_DISCARDING
:
68 case UID_PORT_LEARNING
:
70 case UID_PORT_FORWARDING
:
72 case UID_PORT_NON_STP
:
79 static void CLI_out_port_id(int port
, unsigned char cr
)
81 static char ifname
[IFNAMSIZ
];
82 if (if_indextoname(port
, ifname
))
85 printf("Ifindex %02d", port
);
90 int get_index_die(const char *ifname
, const char *doc
, int die
)
92 int r
= if_nametoindex(ifname
);
95 "Can't find index for %s %s. Not a valid interface.\n",
104 int get_index(const char *ifname
, const char *doc
)
106 return get_index_die(ifname
, doc
, 1);
109 static int cmd_rstp(int argc
, char *const *argv
)
112 int br_index
= get_index(argv
[1], "bridge");
114 if (!strcmp(argv
[2], "on") || !strcmp(argv
[2], "yes")
115 || !strcmp(argv
[2], "1"))
117 else if (!strcmp(argv
[2], "off") || !strcmp(argv
[2], "no")
118 || !strcmp(argv
[2], "0"))
121 fprintf(stderr
, "expect on/off for argument\n");
124 r
= CTL_enable_bridge_rstp(br_index
, stp
);
126 fprintf(stderr
, "Failed to enable/disable RSTP: %s\n",
127 CTL_error_explanation(r
));
133 static int do_showbridge(const char *br_name
)
135 UID_STP_STATE_T uid_state
;
136 UID_STP_CFG_T uid_cfg
;
138 int br_index
= get_index_die(br_name
, "bridge", 0);
142 int r
= CTL_get_bridge_state(br_index
, &uid_cfg
, &uid_state
);
144 fprintf(stderr
, "Failed to get bridge state: %s\n",
145 CTL_error_explanation(r
));
149 printf("Interface: %-7s (tag:%d) State: ",
150 uid_state
.vlan_name
, (int)uid_state
.vlan_id
);
152 printf("Bridge: %-7s State:",
153 uid_state
.vlan_name
);
155 switch (uid_state
.stp_enabled
) {
160 printf("disabled\n");
167 printf("BridgeId: ");
168 print_bridge_id(&uid_state
.bridge_id
, 0);
169 printf(" Bridge Proirity: %lu (0x%lX)\n",
170 (unsigned long)uid_state
.bridge_id
.prio
,
171 (unsigned long)uid_state
.bridge_id
.prio
);
172 if (uid_cfg
.force_version
< 2)
173 printf("Force Version: stp\n");
175 printf("Designated Root: ");
176 print_bridge_id(&uid_state
.designated_root
, 1);
177 if (uid_state
.root_port
) {
178 printf("Root Port: %04lx",
179 (unsigned long)uid_state
.root_port
);
180 // CLI_out_port_id (uid_state.root_port & 0xfff, False);
181 // printf("not implemented"); // XXX
182 printf(", Root Cost: %-lu\n",
183 (unsigned long)uid_state
.root_path_cost
);
185 printf("Root Port: none\n");
188 if (uid_state
.Topo_Change
)
189 printf("Topology Change Count: %lu\n",
190 uid_state
.Topo_Change_Count
);
192 printf("Time Since Topology Change: %lu\n",
193 uid_state
.timeSince_Topo_Change
);
195 printf("Max Age: %2d Bridge Max Age: %-2d\n",
196 (int)uid_state
.max_age
, (int)uid_cfg
.max_age
);
197 printf("Hello Time: %2d Bridge Hello Time: %-2d\n",
198 (int)uid_state
.hello_time
, (int)uid_cfg
.hello_time
);
199 printf("Forward Delay: %2d Bridge Forward Delay: %-2d\n",
200 (int)uid_state
.forward_delay
, (int)uid_cfg
.forward_delay
);
201 printf("Hold Time: %2d\n", (int)uid_cfg
.hold_time
);
206 #define SYSFS_PATH_MAX 256
207 #define SYSFS_CLASS_NET "/sys/class/net"
209 static int isbridge(const struct dirent
*entry
)
211 char path
[SYSFS_PATH_MAX
];
214 snprintf(path
, SYSFS_PATH_MAX
, SYSFS_CLASS_NET
"/%s/bridge",
216 return stat(path
, &st
) == 0 && S_ISDIR(st
.st_mode
);
219 static int cmd_showbridge(int argc
, char *const *argv
)
223 struct dirent
**namelist
;
229 scandir(SYSFS_CLASS_NET
, &namelist
, isbridge
, alphasort
);
231 fprintf(stderr
, "Error getting list of all bridges\n");
236 for (i
= 0; i
< count
; i
++) {
241 name
= namelist
[i
]->d_name
;
243 int err
= do_showbridge(name
);
249 for (i
= 0; i
< count
; i
++)
259 static int do_showport(int br_index
, const char *port_name
,
260 UID_STP_STATE_T
* uid_state
)
262 UID_STP_PORT_STATE_T uid_port
;
263 UID_STP_PORT_CFG_T uid_cfg
;
265 int port_index
= get_index_die(port_name
, "port", 0);
269 memset(&uid_cfg
, 0, sizeof(UID_STP_PORT_CFG_T
));
270 r
= CTL_get_port_state(br_index
, port_index
, &uid_cfg
, &uid_port
);
272 fprintf(stderr
, "Failed to get port state for port %d: %s\n",
273 port_index
, CTL_error_explanation(r
));
279 CLI_out_port_id(port_index
, False
);
281 printf(": PortId: %04lx in vlan '%s' with tag %d:\n",
282 (unsigned long)uid_port
.port_id
, uid_state
->vlan_name
,
283 (int)uid_state
->vlan_id
);
285 printf(": PortId: %04lx in Bridge '%s':\n",
286 (unsigned long)uid_port
.port_id
, uid_state
->vlan_name
);
288 printf("Priority: %-d\n",
289 (int)(uid_port
.port_id
>> 8));
290 printf("State: %-16s",
291 stp_state2str(uid_port
.state
, 1));
292 printf(" Uptime: %-9lu\n", uid_port
.uptime
);
293 printf("PortPathCost: admin: ");
294 if (ADMIN_PORT_PATH_COST_AUTO
== uid_cfg
.admin_port_path_cost
)
295 printf("%-9s", "Auto");
297 printf("%-9lu", uid_cfg
.admin_port_path_cost
);
298 printf(" oper: %-9lu\n", uid_port
.oper_port_path_cost
);
300 printf("Point2Point: admin: ");
301 switch (uid_cfg
.admin_point2point
) {
303 printf("%-9s", "ForceYes");
305 case P2P_FORCE_FALSE
:
306 printf("%-9s", "ForceNo");
309 printf("%-9s", "Auto");
312 printf(" oper: %-9s\n",
313 uid_port
.oper_point2point
? "Yes" : "No");
314 printf("Edge: admin: %-9s oper: %-9s\n",
315 uid_cfg
.admin_edge
? "Y" : "N",
316 uid_port
.oper_edge
? "Y" : "N");
317 printf("Partner: oper: %-9s\n",
318 uid_port
.oper_stp_neigb
? "Slow" : "Rapid");
320 if (' ' != uid_port
.role
) {
321 if ('-' != uid_port
.role
) {
322 printf("PathCost: %-lu\n",
323 (unsigned long)(uid_port
.path_cost
));
324 printf("Designated Root: ");
325 print_bridge_id(&uid_port
.designated_root
, 1);
326 printf("Designated Cost: %-ld\n",
327 (unsigned long)uid_port
.designated_cost
);
328 printf("Designated Bridge: ");
329 print_bridge_id(&uid_port
.designated_bridge
, 1);
330 printf("Designated Port: %-4lx\n\r",
331 (unsigned long)uid_port
.designated_port
);
334 switch (uid_port
.role
) {
336 printf("Alternate\n");
345 printf("Designated\n");
351 printf("Unknown(%c)\n", uid_port
.role
);
355 if ('R' == uid_port
.role
|| 'D' == uid_port
.role
) {
356 /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */
358 uid_port
.top_change_ack
? 'Y' : 'N');
359 printf("TcWhile: %3d\n",
360 (int)uid_port
.tcWhile
);
364 if (UID_PORT_DISABLED
== uid_port
.state
|| '-' == uid_port
.role
) {
366 printf("helloWhen: %3d ",
367 (int)uid_port
.helloWhen
);
368 printf("lnkWhile: %3d\n", (int)uid_port
.lnkWhile
);
369 printf("fdWhile: %3d\n", (int)uid_port
.fdWhile
);
371 } else if ('-' != uid_port
.role
) {
372 printf("fdWhile: %3d ", (int)uid_port
.fdWhile
);
373 printf("rcvdInfoWhile: %3d\n",
374 (int)uid_port
.rcvdInfoWhile
);
375 printf("rbWhile: %3d ", (int)uid_port
.rbWhile
);
376 printf("rrWhile: %3d\n", (int)uid_port
.rrWhile
);
378 printf("mdelayWhile: %3d ",
379 (int)uid_port
.mdelayWhile
);
380 printf("lnkWhile: %3d\n", (int)uid_port
.lnkWhile
);
381 printf("helloWhen: %3d ",
382 (int)uid_port
.helloWhen
);
383 printf("txCount: %3d\n", (int)uid_port
.txCount
);
387 printf("RSTP BPDU rx: %lu\n",
388 (unsigned long)uid_port
.rx_rstp_bpdu_cnt
);
389 printf("CONFIG BPDU rx: %lu\n",
390 (unsigned long)uid_port
.rx_cfg_bpdu_cnt
);
391 printf("TCN BPDU rx: %lu\n",
392 (unsigned long)uid_port
.rx_tcn_bpdu_cnt
);
395 (uid_port
.oper_point2point
) ? ' ' : '*',
396 (uid_port
.oper_edge
) ? 'E' : ' ',
397 (uid_port
.oper_stp_neigb
) ? 's' : ' ');
398 CLI_out_port_id(port_index
, False
);
399 printf(" %04lx %3s ", (unsigned long)uid_port
.port_id
,
400 stp_state2str(uid_port
.state
, 0));
402 print_bridge_id(&uid_port
.designated_root
, 0);
404 print_bridge_id(&uid_port
.designated_bridge
, 0);
405 printf(" %4lx %c", (unsigned long)uid_port
.designated_port
,
412 static int not_dot_dotdot(const struct dirent
*entry
)
414 const char *n
= entry
->d_name
;
416 return !(n
[0] == '.' && (n
[1] == 0 || (n
[1] == '.' && n
[2] == 0)));
419 static int cmd_showport(int argc
, char *const *argv
)
421 UID_STP_STATE_T uid_state
;
422 UID_STP_CFG_T uid_br_cfg
;
425 int br_index
= get_index(argv
[1], "bridge");
427 r
= CTL_get_bridge_state(br_index
, &uid_br_cfg
, &uid_state
);
429 fprintf(stderr
, "Failed to get bridge state: %s\n",
430 CTL_error_explanation(r
));
435 struct dirent
**namelist
;
440 char buf
[SYSFS_PATH_MAX
];
441 snprintf(buf
, sizeof(buf
), SYSFS_CLASS_NET
"/%s/brif", argv
[1]);
442 count
= scandir(buf
, &namelist
, not_dot_dotdot
, alphasort
);
445 "Error getting list of all ports of bridge %s\n",
451 for (i
= 0; i
< count
; i
++) {
456 name
= namelist
[i
]->d_name
;
458 int err
= do_showport(br_index
, name
, &uid_state
);
464 for (i
= 0; i
< count
; i
++)
472 static int cmd_showportdetail(int argc
, char *const *argv
)
475 return cmd_showport(argc
, argv
);
478 unsigned int getuint(const char *s
)
482 l
= strtoul(s
, &end
, 0);
483 if (*s
== 0 || *end
!= 0 || l
> INT_MAX
) {
484 fprintf(stderr
, "Invalid unsigned int arg %s\n", s
);
490 int getenum(const char *s
, const char *opt
[])
493 for (i
= 0; opt
[i
] != NULL
; i
++)
494 if (strcmp(s
, opt
[i
]) == 0)
497 fprintf(stderr
, "Invalid argument %s: expecting one of ", s
);
498 for (i
= 0; opt
[i
] != NULL
; i
++)
499 fprintf(stderr
, "%s%s", opt
[i
], (opt
[i
+ 1] ? ", " : "\n"));
504 int getyesno(const char *s
, const char *yes
, const char *no
)
506 /* Reverse yes and no so error message looks more normal */
507 const char *opt
[] = { yes
, no
, NULL
};
508 return 1 - getenum(s
, opt
);
511 static int set_bridge_cfg_value(int br_index
, unsigned long value
,
512 unsigned long val_mask
)
514 UID_STP_CFG_T uid_cfg
;
518 uid_cfg
.field_mask
= val_mask
;
521 uid_cfg
.stp_enabled
= value
;
525 uid_cfg
.bridge_priority
= value
;
526 val_name
= "priority";
529 uid_cfg
.max_age
= value
;
530 val_name
= "max_age";
533 uid_cfg
.hello_time
= value
;
534 val_name
= "hello_time";
537 uid_cfg
.forward_delay
= value
;
538 val_name
= "forward_delay";
540 case BR_CFG_FORCE_VER
:
541 uid_cfg
.force_version
= value
;
542 val_name
= "force_version";
544 case BR_CFG_AGE_MODE
:
545 case BR_CFG_AGE_TIME
:
547 printf("Invalid value mask 0X%lx\n", val_mask
);
552 rc
= CTL_set_bridge_config(br_index
, &uid_cfg
);
555 printf("Can't change rstp bridge %s:%s\n", val_name
,
556 STP_IN_get_error_explanation(rc
));
562 static int cmd_setbridgestate(int argc
, char *const *argv
)
565 int br_index
= get_index(argv
[1], "bridge");
566 return set_bridge_cfg_value(br_index
,
567 getyesno(argv
[2], "on", "off"),
571 static int cmd_setbridgeprio(int argc
, char *const *argv
)
574 int br_index
= get_index(argv
[1], "bridge");
575 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_PRIO
);
578 static int cmd_setbridgemaxage(int argc
, char *const *argv
)
581 int br_index
= get_index(argv
[1], "bridge");
582 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_AGE
);
585 static int cmd_setbridgehello(int argc
, char *const *argv
)
588 int br_index
= get_index(argv
[1], "bridge");
589 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_HELLO
);
592 static int cmd_setbridgefdelay(int argc
, char *const *argv
)
595 int br_index
= get_index(argv
[1], "bridge");
596 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_DELAY
);
599 static int cmd_setbridgeforcevers(int argc
, char *const *argv
)
602 int br_index
= get_index(argv
[1], "bridge");
603 return set_bridge_cfg_value(br_index
,
604 2 * getyesno(argv
[2], "normal", "slow"),
609 set_port_cfg_value(int br_index
, int port_index
,
610 unsigned long value
, unsigned long val_mask
)
612 UID_STP_PORT_CFG_T uid_cfg
;
616 BitmapClear(&uid_cfg
.port_bmp
);
617 uid_cfg
.field_mask
= val_mask
;
623 uid_cfg
.admin_port_path_cost
= value
;
624 val_name
= "path cost";
627 uid_cfg
.port_priority
= value
;
628 val_name
= "priority";
631 uid_cfg
.admin_point2point
= (ADMIN_P2P_T
) value
;
632 val_name
= "p2p flag";
635 uid_cfg
.admin_edge
= value
;
636 val_name
= "adminEdge";
639 uid_cfg
.admin_non_stp
= value
;
640 val_name
= "adminNonStp";
643 case PT_CFG_DBG_SKIP_TX
:
644 uid_cfg
.skip_tx
= value
;
645 val_name
= "skip tx";
647 case PT_CFG_DBG_SKIP_RX
:
648 uid_cfg
.skip_rx
= value
;
649 val_name
= "skip rx";
654 printf("Invalid value mask 0X%lx\n", val_mask
);
658 rc
= CTL_set_port_config(br_index
, port_index
, &uid_cfg
);
661 printf("can't change rstp port[s] %s: %s\n",
662 val_name
, STP_IN_get_error_explanation(rc
));
668 static int cmd_setportprio(int argc
, char *const *argv
)
671 int br_index
= get_index(argv
[1], "bridge");
672 int port_index
= get_index(argv
[2], "port");
673 return set_port_cfg_value(br_index
, port_index
,
674 getuint(argv
[3]), PT_CFG_PRIO
);
677 static int cmd_setportpathcost(int argc
, char *const *argv
)
680 int br_index
= get_index(argv
[1], "bridge");
681 int port_index
= get_index(argv
[2], "port");
682 return set_port_cfg_value(br_index
, port_index
,
683 getuint(argv
[3]), PT_CFG_COST
);
686 static int cmd_setportedge(int argc
, char *const *argv
)
689 int br_index
= get_index(argv
[1], "bridge");
690 int port_index
= get_index(argv
[2], "port");
691 return set_port_cfg_value(br_index
, port_index
,
692 getyesno(argv
[3], "yes", "no"), PT_CFG_EDGE
);
695 static int cmd_setportnonstp(int argc
, char *const *argv
)
698 int br_index
= get_index(argv
[1], "bridge");
699 int port_index
= get_index(argv
[2], "port");
700 return set_port_cfg_value(br_index
, port_index
,
701 getyesno(argv
[3], "yes", "no"),
705 static int cmd_setportp2p(int argc
, char *const *argv
)
708 int br_index
= get_index(argv
[1], "bridge");
709 int port_index
= get_index(argv
[2], "port");
710 const char *opts
[] = { "yes", "no", "auto", NULL
};
711 int vals
[] = { P2P_FORCE_TRUE
, P2P_FORCE_FALSE
, P2P_AUTO
};
713 return set_port_cfg_value(br_index
, port_index
,
714 vals
[getenum(argv
[3], opts
)], PT_CFG_P2P
);
717 static int cmd_portmcheck(int argc
, char *const *argv
)
720 int br_index
= get_index(argv
[1], "bridge");
721 int port_index
= get_index(argv
[2], "port");
722 return set_port_cfg_value(br_index
, port_index
, 0, PT_CFG_MCHECK
);
725 static int cmd_debuglevel(int argc
, char *const *argv
)
727 return CTL_set_debug_level(getuint(argv
[1]));
734 int (*func
) (int argc
, char *const *argv
);
738 static const struct command commands
[] = {
739 {0, 32, "showbridge", cmd_showbridge
,
740 "[<bridge> ... ]\t\tshow bridge state"},
741 {1, 32, "showport", cmd_showport
,
742 "<bridge> [<port> ... ]\tshow port state"},
743 {1, 32, "showportdetail", cmd_showportdetail
,
744 "<bridge> [<port> ... ]\tshow port state (detail)"},
745 {2, 0, "rstp", cmd_rstp
,
746 "<bridge> {on|off}\tenable/disable rstpd control"},
747 {2, 0, "setbridgestate", cmd_setbridgestate
,
748 "<bridge> {on|off}\tstart/stop rstp (when enabled)"},
749 {2, 0, "setbridgeprio", cmd_setbridgeprio
,
750 "<bridge> <priority>\tset bridge priority (0-61440)"},
751 {2, 0, "sethello", cmd_setbridgehello
,
752 "<bridge> <hellotime>\tset bridge hello time (1-10)"},
753 {2, 0, "setmaxage", cmd_setbridgemaxage
,
754 "<bridge> <maxage>\tset bridge max age (6-40)"},
755 {2, 0, "setfdelay", cmd_setbridgefdelay
,
756 "<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
757 {2, 0, "setforcevers", cmd_setbridgeforcevers
,
758 "<bridge> {normal|slow}\tnormal RSTP or force to STP"},
759 {3, 0, "setportprio", cmd_setportprio
,
760 "<bridge> <port> <priority>\tset port priority (0-240)"},
761 {3, 0, "setportpathcost", cmd_setportpathcost
,
762 "<bridge> <port> <cost>\tset port path cost"},
763 {3, 0, "setportedge", cmd_setportedge
,
764 "<bridge> <port> {yes|no}\tconfigure if it is an edge port"},
765 {3, 0, "setportnonstp", cmd_setportnonstp
,
766 "<bridge> <port> {yes|no}\tdisable STP for the port"},
767 {3, 0, "setportp2p", cmd_setportp2p
,
768 "<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
769 {2, 0, "portmcheck", cmd_portmcheck
,
770 "<bridge> <port>\ttry to get back from STP to RSTP mode"},
771 {1, 0, "debuglevel", cmd_debuglevel
, "<level>\t\tLevel of verbosity"},
774 const struct command
*command_lookup(const char *cmd
)
778 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
779 if (!strcmp(cmd
, commands
[i
].name
))
786 void command_helpall(void)
790 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
791 printf("\t%-10s\t%s\n", commands
[i
].name
, commands
[i
].help
);
797 printf("Usage: rstpctl [commands]\n");
798 printf("commands:\n");
802 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
803 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
805 int main(int argc
, char *const *argv
)
807 const struct command
*cmd
;
809 static const struct option options
[] = {
810 {.name
= "help",.val
= 'h'},
811 {.name
= "version",.val
= 'V'},
815 while ((f
= getopt_long(argc
, argv
, "Vh", options
, NULL
)) != EOF
)
821 printf("%s\n", PACKAGE_VERSION(VERSION
, BUILD
));
824 fprintf(stderr
, "Unknown option '%c'\n", f
);
831 if (ctl_client_init()) {
832 fprintf(stderr
, "can't setup control connection\n");
838 if ((cmd
= command_lookup(argv
[0])) == NULL
) {
839 fprintf(stderr
, "never heard of command [%s]\n", argv
[0]);
843 if (argc
< cmd
->nargs
+ 1 || argc
> cmd
->nargs
+ cmd
->optargs
+ 1) {
844 printf("Incorrect number of arguments for command\n");
845 printf("Usage: rstpctl %s %s\n", cmd
->name
, cmd
->help
);
849 return cmd
->func(argc
, argv
);