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
31 print_bridge_id (UID_BRIDGE_ID_T
*bridge_id
, unsigned char cr
)
33 printf("%04lX-%02x%02x%02x%02x%02x%02x",
34 (unsigned long) bridge_id
->prio
,
35 (unsigned char) bridge_id
->addr
[0],
36 (unsigned char) bridge_id
->addr
[1],
37 (unsigned char) bridge_id
->addr
[2],
38 (unsigned char) bridge_id
->addr
[3],
39 (unsigned char) bridge_id
->addr
[4],
40 (unsigned char) bridge_id
->addr
[5]);
46 stp_state2str (RSTP_PORT_STATE stp_port_state
, int detail
)
49 switch (stp_port_state
) {
50 case UID_PORT_DISABLED
: return "Disabled";
51 case UID_PORT_DISCARDING
: return "Discarding";
52 case UID_PORT_LEARNING
: return "Learning";
53 case UID_PORT_FORWARDING
: return "Forwarding";
54 case UID_PORT_NON_STP
: return "NoStp";
55 default: return "Unknown";
59 switch (stp_port_state
) {
60 case UID_PORT_DISABLED
: return "Dis";
61 case UID_PORT_DISCARDING
: return "Blk";
62 case UID_PORT_LEARNING
: return "Lrn";
63 case UID_PORT_FORWARDING
: return "Fwd";
64 case UID_PORT_NON_STP
: return "Non";
65 default: return "Unk";
69 static void CLI_out_port_id (int port
, unsigned char cr
)
71 static char ifname
[IFNAMSIZ
];
72 if (if_indextoname(port
, ifname
))
75 printf ("Ifindex %02d", port
);
80 int get_index_die(const char *ifname
, const char *doc
, int die
)
82 int r
= if_nametoindex(ifname
);
84 fprintf(stderr
, "Can't find index for %s %s. Not a valid interface.\n",
93 int get_index(const char *ifname
, const char *doc
)
95 return get_index_die(ifname
, doc
, 1);
98 static int cmd_rstp(int argc
, char *const* argv
)
101 int br_index
= get_index(argv
[1], "bridge");
103 if (!strcmp(argv
[2], "on") || !strcmp(argv
[2], "yes")
104 || !strcmp(argv
[2], "1"))
106 else if (!strcmp(argv
[2], "off") || !strcmp(argv
[2], "no")
107 || !strcmp(argv
[2], "0"))
110 fprintf(stderr
, "expect on/off for argument\n");
113 r
= CTL_enable_bridge_rstp(br_index
, stp
);
115 fprintf(stderr
, "Failed to enable/disable RSTP: %s\n",
116 CTL_error_explanation(r
));
122 static int do_showbridge(const char *br_name
)
124 UID_STP_STATE_T uid_state
;
125 UID_STP_CFG_T uid_cfg
;
127 int br_index
= get_index_die(br_name
, "bridge", 0);
131 int r
= CTL_get_bridge_state(br_index
, &uid_cfg
, &uid_state
);
133 fprintf(stderr
, "Failed to get bridge state: %s\n",
134 CTL_error_explanation(r
));
139 printf("Interface: %-7s (tag:%d) State: ",
140 uid_state
.vlan_name
, (int) uid_state
.vlan_id
);
142 printf("Bridge: %-7s State:",
143 uid_state
.vlan_name
);
145 switch (uid_state
.stp_enabled
) {
146 case STP_ENABLED
: printf("enabled\n"); break;
147 case STP_DISABLED
: printf("disabled\n");break;
148 default: printf("unknown\n"); return 0;
151 printf("BridgeId: "); print_bridge_id (&uid_state
.bridge_id
, 0);
152 printf(" Bridge Proirity: %lu (0x%lX)\n",
153 (unsigned long) uid_state
.bridge_id
.prio
, (unsigned long) uid_state
.bridge_id
.prio
);
154 if (uid_cfg
.force_version
< 2)
155 printf("Force Version: stp\n");
157 printf("Designated Root: "); print_bridge_id (&uid_state
.designated_root
, 1);
158 if (uid_state
.root_port
) {
159 printf("Root Port: %04lx", (unsigned long) uid_state
.root_port
);
160 // CLI_out_port_id (uid_state.root_port & 0xfff, False);
161 // printf("not implemented"); // XXX
162 printf(", Root Cost: %-lu\n", (unsigned long) uid_state
.root_path_cost
);
164 printf("Root Port: none\n");
167 if (uid_state
.Topo_Change
)
168 printf ("Topology Change Count: %lu\n", uid_state
.Topo_Change_Count
);
170 printf ("Time Since Topology Change: %lu\n", uid_state
.timeSince_Topo_Change
);
172 printf ("Max Age: %2d Bridge Max Age: %-2d\n",
173 (int) uid_state
.max_age
, (int) uid_cfg
.max_age
);
174 printf ("Hello Time: %2d Bridge Hello Time: %-2d\n",
175 (int) uid_state
.hello_time
, (int) uid_cfg
.hello_time
);
176 printf ("Forward Delay: %2d Bridge Forward Delay: %-2d\n",
177 (int) uid_state
.forward_delay
, (int) uid_cfg
.forward_delay
);
178 printf ("Hold Time: %2d\n", (int) uid_cfg
.hold_time
);
183 #define SYSFS_PATH_MAX 256
184 #define SYSFS_CLASS_NET "/sys/class/net"
186 static int isbridge(const struct dirent
*entry
)
188 char path
[SYSFS_PATH_MAX
];
191 snprintf(path
, SYSFS_PATH_MAX
, SYSFS_CLASS_NET
"/%s/bridge",
193 return stat(path
, &st
) == 0 && S_ISDIR(st
.st_mode
);
196 static int cmd_showbridge(int argc
, char *const* argv
)
200 struct dirent
**namelist
;
206 count
= scandir(SYSFS_CLASS_NET
, &namelist
, isbridge
, alphasort
);
208 fprintf(stderr
, "Error getting list of all bridges\n");
213 for (i
= 0; i
< count
; i
++) {
218 name
= namelist
[i
]->d_name
;
220 int err
= do_showbridge(name
);
226 for (i
= 0; i
< count
; i
++)
236 static int do_showport(int br_index
, const char *port_name
,
237 UID_STP_STATE_T
*uid_state
)
239 UID_STP_PORT_STATE_T uid_port
;
240 UID_STP_PORT_CFG_T uid_cfg
;
242 int port_index
= get_index_die(port_name
, "port", 0);
246 memset (&uid_cfg
, 0, sizeof (UID_STP_PORT_CFG_T
));
247 r
= CTL_get_port_state(br_index
, port_index
, &uid_cfg
, &uid_port
);
249 fprintf(stderr
, "Failed to get port state for port %d: %s\n",
250 port_index
, CTL_error_explanation(r
));
255 printf("Stp Port "); CLI_out_port_id (port_index
, False
);
257 printf(": PortId: %04lx in vlan '%s' with tag %d:\n",
258 (unsigned long) uid_port
.port_id
, uid_state
->vlan_name
, (int) uid_state
->vlan_id
);
260 printf(": PortId: %04lx in Bridge '%s':\n",
261 (unsigned long) uid_port
.port_id
, uid_state
->vlan_name
);
263 printf ("Priority: %-d\n", (int) (uid_port
.port_id
>> 8));
264 printf ("State: %-16s", stp_state2str (uid_port
.state
, 1));
265 printf (" Uptime: %-9lu\n", uid_port
.uptime
);
266 printf ("PortPathCost: admin: ");
267 if (ADMIN_PORT_PATH_COST_AUTO
== uid_cfg
.admin_port_path_cost
)
268 printf ("%-9s", "Auto");
270 printf ("%-9lu", uid_cfg
.admin_port_path_cost
);
271 printf (" oper: %-9lu\n", uid_port
.oper_port_path_cost
);
273 printf ("Point2Point: admin: ");
274 switch (uid_cfg
.admin_point2point
) {
276 printf ("%-9s", "ForceYes");
278 case P2P_FORCE_FALSE
:
279 printf ("%-9s", "ForceNo");
282 printf ("%-9s", "Auto");
285 printf (" oper: %-9s\n", uid_port
.oper_point2point
? "Yes" : "No");
286 printf ("Edge: admin: %-9s oper: %-9s\n",
287 uid_cfg
.admin_edge
? "Y" : "N",
288 uid_port
.oper_edge
? "Y" : "N");
289 printf ("Partner: oper: %-9s\n",
290 uid_port
.oper_stp_neigb
? "Slow" : "Rapid");
292 if (' ' != uid_port
.role
) {
293 if ('-' != uid_port
.role
) {
294 printf("PathCost: %-lu\n", (unsigned long) (uid_port
.path_cost
));
295 printf("Designated Root: "); print_bridge_id (&uid_port
.designated_root
, 1);
296 printf("Designated Cost: %-ld\n", (unsigned long) uid_port
.designated_cost
);
297 printf("Designated Bridge: "); print_bridge_id (&uid_port
.designated_bridge
, 1);
298 printf("Designated Port: %-4lx\n\r", (unsigned long) uid_port
.designated_port
);
301 switch (uid_port
.role
) {
302 case 'A': printf("Alternate\n"); break;
303 case 'B': printf("Backup\n"); break;
304 case 'R': printf("Root\n"); break;
305 case 'D': printf("Designated\n"); break;
306 case '-': printf("NonStp\n"); break;
307 default: printf("Unknown(%c)\n", uid_port
.role
); break;
310 if ('R' == uid_port
.role
|| 'D' == uid_port
.role
) {
311 /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */
313 uid_port
.top_change_ack
? 'Y' : 'N');
314 printf("TcWhile: %3d\n", (int) uid_port
.tcWhile
);
318 if (UID_PORT_DISABLED
== uid_port
.state
|| '-' == uid_port
.role
) {
320 printf("helloWhen: %3d ", (int) uid_port
.helloWhen
);
321 printf("lnkWhile: %3d\n", (int) uid_port
.lnkWhile
);
322 printf("fdWhile: %3d\n", (int) uid_port
.fdWhile
);
324 } else if ('-' != uid_port
.role
) {
325 printf("fdWhile: %3d ", (int) uid_port
.fdWhile
);
326 printf("rcvdInfoWhile: %3d\n", (int) uid_port
.rcvdInfoWhile
);
327 printf("rbWhile: %3d ", (int) uid_port
.rbWhile
);
328 printf("rrWhile: %3d\n", (int) uid_port
.rrWhile
);
330 printf("mdelayWhile: %3d ", (int) uid_port
.mdelayWhile
);
331 printf("lnkWhile: %3d\n", (int) uid_port
.lnkWhile
);
332 printf("helloWhen: %3d ", (int) uid_port
.helloWhen
);
333 printf("txCount: %3d\n", (int) uid_port
.txCount
);
337 printf("RSTP BPDU rx: %lu\n", (unsigned long) uid_port
.rx_rstp_bpdu_cnt
);
338 printf("CONFIG BPDU rx: %lu\n", (unsigned long) uid_port
.rx_cfg_bpdu_cnt
);
339 printf("TCN BPDU rx: %lu\n", (unsigned long) uid_port
.rx_tcn_bpdu_cnt
);
342 (uid_port
.oper_point2point
) ? ' ' : '*',
343 (uid_port
.oper_edge
) ? 'E' : ' ',
344 (uid_port
.oper_stp_neigb
) ? 's' : ' ');
345 CLI_out_port_id (port_index
, False
);
346 printf(" %04lx %3s ", (unsigned long) uid_port
.port_id
,
347 stp_state2str (uid_port
.state
, 0));
349 print_bridge_id (&uid_port
.designated_root
, 0);
351 print_bridge_id (&uid_port
.designated_bridge
, 0);
352 printf(" %4lx %c", (unsigned long) uid_port
.designated_port
, uid_port
.role
);
358 static int not_dot_dotdot(const struct dirent
*entry
)
360 const char *n
= entry
->d_name
;
362 return !(n
[0] == '.' && (n
[1] == 0 || (n
[1] == '.' && n
[2] == 0)));
365 static int cmd_showport(int argc
, char *const* argv
)
367 UID_STP_STATE_T uid_state
;
368 UID_STP_CFG_T uid_br_cfg
;
371 int br_index
= get_index(argv
[1], "bridge");
373 r
= CTL_get_bridge_state(br_index
, &uid_br_cfg
, &uid_state
);
375 fprintf(stderr
, "Failed to get bridge state: %s\n",
376 CTL_error_explanation(r
));
381 struct dirent
**namelist
;
387 char buf
[SYSFS_PATH_MAX
];
388 snprintf(buf
, sizeof(buf
), SYSFS_CLASS_NET
"/%s/brif", argv
[1]);
389 count
= scandir(buf
, &namelist
, not_dot_dotdot
, alphasort
);
391 fprintf(stderr
, "Error getting list of all ports of bridge %s\n",
397 for (i
= 0; i
< count
; i
++) {
402 name
= namelist
[i
]->d_name
;
404 int err
= do_showport(br_index
, name
, &uid_state
);
410 for (i
= 0; i
< count
; i
++)
418 static int cmd_showportdetail(int argc
, char *const* argv
)
421 return cmd_showport(argc
, argv
);
424 unsigned int getuint(const char *s
)
428 l
= strtoul(s
, &end
, 0);
429 if (*s
== 0 || *end
!= 0 || l
> INT_MAX
) {
430 fprintf(stderr
, "Invalid unsigned int arg %s\n", s
);
436 int getenum(const char *s
, const char *opt
[])
439 for (i
= 0; opt
[i
] != NULL
; i
++)
440 if (strcmp(s
, opt
[i
]) == 0)
443 fprintf(stderr
, "Invalid argument %s: expecting one of ", s
);
444 for (i
= 0; opt
[i
] != NULL
; i
++)
445 fprintf(stderr
, "%s%s", opt
[i
], (opt
[i
+1]?", ":"\n"));
450 int getyesno(const char *s
, const char *yes
, const char *no
)
452 /* Reverse yes and no so error message looks more normal */
453 const char *opt
[] = { yes
, no
, NULL
};
454 return 1 - getenum(s
, opt
);
457 static int set_bridge_cfg_value (int br_index
, unsigned long value
,
458 unsigned long val_mask
)
460 UID_STP_CFG_T uid_cfg
;
464 uid_cfg
.field_mask
= val_mask
;
467 uid_cfg
.stp_enabled
= value
;
471 uid_cfg
.bridge_priority
= value
;
472 val_name
= "priority";
475 uid_cfg
.max_age
= value
;
476 val_name
= "max_age";
479 uid_cfg
.hello_time
= value
;
480 val_name
= "hello_time";
483 uid_cfg
.forward_delay
= value
;
484 val_name
= "forward_delay";
486 case BR_CFG_FORCE_VER
:
487 uid_cfg
.force_version
= value
;
488 val_name
= "force_version";
490 case BR_CFG_AGE_MODE
:
491 case BR_CFG_AGE_TIME
:
492 default: printf ("Invalid value mask 0X%lx\n", val_mask
); return -1;
496 rc
= CTL_set_bridge_config(br_index
, &uid_cfg
);
499 printf ("Can't change rstp bridge %s:%s\n", val_name
, STP_IN_get_error_explanation (rc
));
505 static int cmd_setbridgestate(int argc
, char *const* argv
)
508 int br_index
= get_index(argv
[1], "bridge");
509 return set_bridge_cfg_value(br_index
,
510 getyesno(argv
[2], "on", "off"),
514 static int cmd_setbridgeprio(int argc
, char *const* argv
)
517 int br_index
= get_index(argv
[1], "bridge");
518 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_PRIO
);
521 static int cmd_setbridgemaxage(int argc
, char *const* argv
)
524 int br_index
= get_index(argv
[1], "bridge");
525 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_AGE
);
528 static int cmd_setbridgehello(int argc
, char *const* argv
)
531 int br_index
= get_index(argv
[1], "bridge");
532 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_HELLO
);
535 static int cmd_setbridgefdelay(int argc
, char *const* argv
)
538 int br_index
= get_index(argv
[1], "bridge");
539 return set_bridge_cfg_value(br_index
, getuint(argv
[2]), BR_CFG_DELAY
);
542 static int cmd_setbridgeforcevers(int argc
, char *const* argv
)
545 int br_index
= get_index(argv
[1], "bridge");
546 return set_bridge_cfg_value(br_index
,
547 2 * getyesno(argv
[2], "normal", "slow"),
553 set_port_cfg_value (int br_index
, int port_index
,
555 unsigned long val_mask
)
557 UID_STP_PORT_CFG_T uid_cfg
;
561 BitmapClear(&uid_cfg
.port_bmp
);
562 uid_cfg
.field_mask
= val_mask
;
568 uid_cfg
.admin_port_path_cost
= value
;
569 val_name
= "path cost";
572 uid_cfg
.port_priority
= value
;
573 val_name
= "priority";
576 uid_cfg
.admin_point2point
= (ADMIN_P2P_T
) value
;
577 val_name
= "p2p flag";
580 uid_cfg
.admin_edge
= value
;
581 val_name
= "adminEdge";
584 uid_cfg
.admin_non_stp
= value
;
585 val_name
= "adminNonStp";
588 case PT_CFG_DBG_SKIP_TX
:
589 uid_cfg
.skip_tx
= value
;
590 val_name
= "skip tx";
592 case PT_CFG_DBG_SKIP_RX
:
593 uid_cfg
.skip_rx
= value
;
594 val_name
= "skip rx";
599 printf ("Invalid value mask 0X%lx\n", val_mask
);
603 rc
= CTL_set_port_config(br_index
, port_index
, &uid_cfg
);
606 printf ("can't change rstp port[s] %s: %s\n",
607 val_name
, STP_IN_get_error_explanation (rc
));
613 static int cmd_setportprio(int argc
, char *const* argv
)
616 int br_index
= get_index(argv
[1], "bridge");
617 int port_index
= get_index(argv
[2], "port");
618 return set_port_cfg_value(br_index
, port_index
,
619 getuint(argv
[3]), PT_CFG_PRIO
);
622 static int cmd_setportpathcost(int argc
, char *const* argv
)
625 int br_index
= get_index(argv
[1], "bridge");
626 int port_index
= get_index(argv
[2], "port");
627 return set_port_cfg_value(br_index
, port_index
,
628 getuint(argv
[3]), PT_CFG_COST
);
631 static int cmd_setportedge(int argc
, char *const* argv
)
634 int br_index
= get_index(argv
[1], "bridge");
635 int port_index
= get_index(argv
[2], "port");
636 return set_port_cfg_value(br_index
, port_index
,
637 getyesno(argv
[3], "yes", "no"), PT_CFG_EDGE
);
640 static int cmd_setportnonstp(int argc
, char *const* argv
)
643 int br_index
= get_index(argv
[1], "bridge");
644 int port_index
= get_index(argv
[2], "port");
645 return set_port_cfg_value(br_index
, port_index
,
646 getyesno(argv
[3], "yes", "no"), PT_CFG_NON_STP
);
649 static int cmd_setportp2p(int argc
, char *const* argv
)
652 int br_index
= get_index(argv
[1], "bridge");
653 int port_index
= get_index(argv
[2], "port");
654 const char *opts
[] = {"yes", "no", "auto", NULL
};
655 int vals
[] = { P2P_FORCE_TRUE
, P2P_FORCE_FALSE
, P2P_AUTO
};
657 return set_port_cfg_value(br_index
, port_index
,
658 vals
[getenum(argv
[3], opts
)], PT_CFG_P2P
);
661 static int cmd_portmcheck(int argc
, char *const* argv
)
664 int br_index
= get_index(argv
[1], "bridge");
665 int port_index
= get_index(argv
[2], "port");
666 return set_port_cfg_value(br_index
, port_index
, 0, PT_CFG_MCHECK
);
669 static int cmd_debuglevel(int argc
, char *const* argv
)
671 return CTL_set_debug_level(getuint(argv
[1]));
679 int (*func
)(int argc
, char *const* argv
);
683 static const struct command commands
[] = {
684 { 0, 32, "showbridge", cmd_showbridge
, "[<bridge> ... ]\t\tshow bridge state" },
685 { 1, 32, "showport", cmd_showport
, "<bridge> [<port> ... ]\tshow port state" },
686 { 1, 32, "showportdetail", cmd_showportdetail
, "<bridge> [<port> ... ]\tshow port state (detail)" },
687 { 2, 0, "rstp", cmd_rstp
, "<bridge> {on|off}\tenable/disable rstpd control" },
688 { 2, 0, "setbridgestate", cmd_setbridgestate
, "<bridge> {on|off}\tstart/stop rstp (when enabled)" },
689 { 2, 0, "setbridgeprio", cmd_setbridgeprio
, "<bridge> <priority>\tset bridge priority (0-61440)" },
690 { 2, 0, "sethello", cmd_setbridgehello
, "<bridge> <hellotime>\tset bridge hello time (1-10)" },
691 { 2, 0, "setmaxage", cmd_setbridgemaxage
, "<bridge> <maxage>\tset bridge max age (6-40)" },
692 { 2, 0, "setfdelay", cmd_setbridgefdelay
, "<bridge> <fwd_delay>\tset bridge forward delay (4-30)" },
693 { 2, 0, "setforcevers", cmd_setbridgeforcevers
, "<bridge> {normal|slow}\tnormal RSTP or force to STP" },
694 { 3, 0, "setportprio", cmd_setportprio
, "<bridge> <port> <priority>\tset port priority (0-240)" },
695 { 3, 0, "setportpathcost", cmd_setportpathcost
, "<bridge> <port> <cost>\tset port path cost" },
696 { 3, 0, "setportedge", cmd_setportedge
, "<bridge> <port> {yes|no}\tconfigure if it is an edge port" },
697 { 3, 0, "setportnonstp", cmd_setportnonstp
, "<bridge> <port> {yes|no}\tdisable STP for the port" },
698 { 3, 0, "setportp2p", cmd_setportp2p
, "<bridge> <port> {yes|no|auto}\tset whether p2p connection" },
699 { 2, 0, "portmcheck", cmd_portmcheck
, "<bridge> <port>\ttry to get back from STP to RSTP mode" },
700 { 1, 0, "debuglevel", cmd_debuglevel
, "<level>\t\tLevel of verbosity" },
703 const struct command
*command_lookup(const char *cmd
)
707 for (i
= 0; i
< sizeof(commands
)/sizeof(commands
[0]); i
++) {
708 if (!strcmp(cmd
, commands
[i
].name
))
715 void command_helpall(void)
719 for (i
= 0; i
< sizeof(commands
)/sizeof(commands
[0]); i
++) {
720 printf("\t%-10s\t%s\n", commands
[i
].name
, commands
[i
].help
);
726 printf("Usage: rstpctl [commands]\n");
727 printf("commands:\n");
731 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
732 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
734 int main(int argc
, char *const* argv
)
736 const struct command
*cmd
;
738 static const struct option options
[] = {
739 { .name
= "help", .val
= 'h' },
740 { .name
= "version", .val
= 'V' },
744 while ((f
= getopt_long(argc
, argv
, "Vh", options
, NULL
)) != EOF
)
750 printf("%s\n", PACKAGE_VERSION(VERSION
, BUILD
));
753 fprintf(stderr
, "Unknown option '%c'\n", f
);
760 if (ctl_client_init()) {
761 fprintf(stderr
, "can't setup control connection\n");
767 if ((cmd
= command_lookup(argv
[0])) == NULL
) {
768 fprintf(stderr
, "never heard of command [%s]\n", argv
[0]);
772 if (argc
< cmd
->nargs
+ 1 || argc
> cmd
->nargs
+ cmd
->optargs
+ 1) {
773 printf("Incorrect number of arguments for command\n");
774 printf("Usage: rstpctl %s %s\n", cmd
->name
, cmd
->help
);
778 return cmd
->func(argc
, argv
);