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>
21 #include "ctl_socket_client.h"
22 #include "ctl_functions.h"
24 int get_index_die(const char *ifname
, const char *doc
, int die
)
26 int r
= if_nametoindex(ifname
);
29 "Can't find index for %s %s. Not a valid interface.\n",
38 int get_index(const char *ifname
, const char *doc
)
40 return get_index_die(ifname
, doc
, 1);
43 #define BR_ID_FMT "%02x%02x.%02x%02x%02x%02x%02x%02x"
44 #define BR_ID_ARGS(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
46 #define BOOL_STR(x) ((x) ? "yes" : "no")
48 static int do_showbridge(const char *br_name
)
52 int br_index
= get_index_die(br_name
, "bridge", 0);
56 int r
= CTL_get_bridge_status(br_index
, &s
);
60 printf("%s\n", br_name
);
61 printf(" enabled\t\t%4s\n", BOOL_STR(s
.enabled
));
62 printf(" bridge id\t\t" BR_ID_FMT
"\n", BR_ID_ARGS(s
.bridge_id
));
63 printf(" designated root\t" BR_ID_FMT
"\n",
64 BR_ID_ARGS(s
.designated_root
));
65 //printf(" designated bridge\t\t", BR_ID_FMT "\n",
66 // BR_ID_ARGS(s.designated_bridge));
67 printf(" root port\t\t%4u", s
.root_port
);
68 printf("\t\t\tpath cost\t\t%4u\n", s
.root_path_cost
);
69 printf(" max age\t\t%4u", s
.max_age
);
70 printf("\t\t\tbridge max age\t\t%4u\n", s
.bridge_max_age
);
71 printf(" hello time\t\t%4u", s
.hello_time
);
72 printf("\t\t\tbridge hello time\t%4u\n", s
.bridge_hello_time
);
73 printf(" forward delay\t\t%4u", s
.forward_delay
);
74 printf("\t\t\tbridge forward delay\t%4u\n", s
.bridge_forward_delay
);
75 printf(" tx hold count\t\t%4u\n", s
.tx_hold_count
);
76 printf(" protocol version\t%4u\n", s
.protocol_version
);
77 printf(" time since topology change\t%4u\n",
78 s
.time_since_topology_change
);
79 printf(" toplogy change count\t\t%4u\n", s
.topology_change_count
);
80 printf(" topology change\t\t%4s\n", BOOL_STR(s
.topology_change
));
85 #define SYSFS_PATH_MAX 256
86 #define SYSFS_CLASS_NET "/sys/class/net"
88 static int isbridge(const struct dirent
*entry
)
90 char path
[SYSFS_PATH_MAX
];
93 snprintf(path
, SYSFS_PATH_MAX
, SYSFS_CLASS_NET
"/%s/bridge",
95 return stat(path
, &st
) == 0 && S_ISDIR(st
.st_mode
);
98 static int cmd_showbridge(int argc
, char *const *argv
)
102 struct dirent
**namelist
;
108 scandir(SYSFS_CLASS_NET
, &namelist
, isbridge
, alphasort
);
110 fprintf(stderr
, "Error getting list of all bridges\n");
115 for (i
= 0; i
< count
; i
++) {
120 name
= namelist
[i
]->d_name
;
122 int err
= do_showbridge(name
);
128 for (i
= 0; i
< count
; i
++)
137 #define STATE_STR(_state) \
140 char *_str = "unknown"; \
143 case STP_PORT_STATE_DISCARDING: _str = "discarding"; break; \
144 case STP_PORT_STATE_LEARNING: _str = "learning"; break; \
145 case STP_PORT_STATE_FORWARDING: _str = "forwarding"; break; \
150 #define SHORT_STATE_STR(_state) \
153 char *_str = "unkn"; \
156 case STP_PORT_STATE_DISCARDING: _str = "disc"; break; \
157 case STP_PORT_STATE_LEARNING: _str = "lear"; break; \
158 case STP_PORT_STATE_FORWARDING: _str = "forw"; break; \
163 #define ADMIN_P2P_STR(_state) \
166 char *_str = "unkn"; \
169 case STP_ADMIN_P2P_FORCE_FALSE: _str = "no"; break; \
170 case STP_ADMIN_P2P_FORCE_TRUE: _str = "yes"; break; \
171 case STP_ADMIN_P2P_AUTO: _str = "auto"; break; \
179 static int do_showport(int br_index
, const char *port_name
)
183 int port_index
= get_index_die(port_name
, "port", 0);
187 r
= CTL_get_port_status(br_index
, port_index
, &s
);
189 fprintf(stderr
, "Failed to get port state for port %d\n",
195 printf("%s (%u)\n", port_name
, (s
.id
& 0xfff));
196 printf(" enabled\t\t%4s\n", BOOL_STR(s
.enabled
));
197 printf(" port id\t\t%04x\t\t\tstate\t\t%15s\n",
198 s
.id
, STATE_STR(s
.state
));
199 printf(" path cost\t%12d\t\t\tadmin path cost\t%12d\n",
200 s
.path_cost
, s
.admin_path_cost
);
201 printf(" designated root\t" BR_ID_FMT
,
202 BR_ID_ARGS(s
.designated_root
));
203 printf("\tdesignated cost\t%12u\n", s
.designated_cost
);
204 printf(" designated bridge\t" BR_ID_FMT
,
205 BR_ID_ARGS(s
.designated_bridge
));
206 printf("\tdesignated port\t\t%04x\n", s
.designated_port
);
207 printf(" admin edge port\t%4s", BOOL_STR(s
.admin_edge_port
));
208 printf("\t\t\tauto edge port\t\t%4s\n",
209 BOOL_STR(s
.auto_edge_port
));
210 printf(" oper edge port\t\t%4s", BOOL_STR(s
.oper_edge_port
));
211 printf("\t\t\ttoplogy change ack\t%4s\n", BOOL_STR(s
.tc_ack
));
212 printf(" point to point\t\t%4s", BOOL_STR(s
.oper_p2p
));
213 printf("\t\t\tadmin point to point\t%4s\n",
214 ADMIN_P2P_STR(s
.admin_p2p
));
216 printf("%c%c %4s %04x %4s " BR_ID_FMT
" " BR_ID_FMT
" %04x\n",
217 (s
.oper_p2p
) ? ' ' : '*',
218 (s
.oper_edge_port
) ? 'E' : ' ',
221 s
.enabled
?SHORT_STATE_STR(s
.state
):"down",
222 BR_ID_ARGS(s
.designated_root
),
223 BR_ID_ARGS(s
.designated_bridge
),
229 static int not_dot_dotdot(const struct dirent
*entry
)
231 const char *n
= entry
->d_name
;
233 return !(n
[0] == '.' && (n
[1] == 0 || (n
[1] == '.' && n
[2] == 0)));
236 static int cmd_showport(int argc
, char *const *argv
)
240 int br_index
= get_index(argv
[1], "bridge");
243 struct dirent
**namelist
;
248 char buf
[SYSFS_PATH_MAX
];
249 snprintf(buf
, sizeof(buf
), SYSFS_CLASS_NET
"/%s/brif", argv
[1]);
250 count
= scandir(buf
, &namelist
, not_dot_dotdot
, alphasort
);
253 "Error getting list of all ports of bridge %s\n",
259 for (i
= 0; i
< count
; i
++) {
264 name
= namelist
[i
]->d_name
;
266 int err
= do_showport(br_index
, name
);
272 for (i
= 0; i
< count
; i
++)
280 static int cmd_showportdetail(int argc
, char *const *argv
)
283 return cmd_showport(argc
, argv
);
286 unsigned int getuint(const char *s
)
290 l
= strtoul(s
, &end
, 0);
291 if (*s
== 0 || *end
!= 0 || l
> INT_MAX
) {
292 fprintf(stderr
, "Invalid unsigned int arg %s\n", s
);
298 int getenum(const char *s
, const char *opt
[])
301 for (i
= 0; opt
[i
] != NULL
; i
++)
302 if (strcmp(s
, opt
[i
]) == 0)
305 fprintf(stderr
, "Invalid argument %s: expecting one of ", s
);
306 for (i
= 0; opt
[i
] != NULL
; i
++)
307 fprintf(stderr
, "%s%s", opt
[i
], (opt
[i
+ 1] ? ", " : "\n"));
312 int getyesno(const char *s
, const char *yes
, const char *no
)
314 /* Reverse yes and no so error message looks more normal */
315 const char *opt
[] = { yes
, no
, NULL
};
316 return 1 - getenum(s
, opt
);
319 #define set_bridge_cfg(field, value) \
321 STP_BridgeConfig c; \
322 memset(&c, 0, sizeof(c)); \
324 c.set_ ## field = 1; \
325 int r = CTL_set_bridge_config(br_index, &c); \
327 printf("Couldn't change bridge " #field "\n"); \
331 #define set_port_cfg(field, value) \
334 memset(&c, 0, sizeof(c)); \
336 c.set_ ## field = 1; \
337 int r = CTL_set_port_config(br_index, port_index, &c); \
339 printf("Couldn't change port " #field "\n"); \
345 static int cmd_setbridgeprio(int argc
, char *const *argv
)
348 int br_index
= get_index(argv
[1], "bridge");
349 return set_bridge_cfg(bridge_priority
, getuint(argv
[2]));
352 static int cmd_setbridgemaxage(int argc
, char *const *argv
)
355 int br_index
= get_index(argv
[1], "bridge");
356 return set_bridge_cfg(bridge_max_age
, getuint(argv
[2]));
359 static int cmd_setbridgehello(int argc
, char *const *argv
)
362 int br_index
= get_index(argv
[1], "bridge");
363 return set_bridge_cfg(bridge_hello_time
, getuint(argv
[2]));
366 static int cmd_setbridgefdelay(int argc
, char *const *argv
)
369 int br_index
= get_index(argv
[1], "bridge");
370 return set_bridge_cfg(bridge_forward_delay
, getuint(argv
[2]));
373 static int cmd_setbridgeforcevers(int argc
, char *const *argv
)
376 int br_index
= get_index(argv
[1], "bridge");
377 return set_bridge_cfg(bridge_protocol_version
,
378 2 * getyesno(argv
[2], "normal", "slow"));
381 static int cmd_setbridgetxholdcount(int argc
, char *const *argv
)
384 int br_index
= get_index(argv
[1], "bridge");
385 return set_bridge_cfg(bridge_tx_hold_count
, getuint(argv
[2]));
389 static int cmd_setportprio(int argc
, char *const *argv
)
392 int br_index
= get_index(argv
[1], "bridge");
393 int port_index
= get_index(argv
[2], "port");
394 return set_port_cfg(port_priority
, getuint(argv
[3]));
397 static int cmd_setportpathcost(int argc
, char *const *argv
)
400 int br_index
= get_index(argv
[1], "bridge");
401 int port_index
= get_index(argv
[2], "port");
402 return set_port_cfg(port_pathcost
, getuint(argv
[3]));
405 static int cmd_setportadminedge(int argc
, char *const *argv
)
408 int br_index
= get_index(argv
[1], "bridge");
409 int port_index
= get_index(argv
[2], "port");
410 return set_port_cfg(port_admin_edge
, getyesno(argv
[3], "yes", "no"));
413 static int cmd_setportautoedge(int argc
, char *const *argv
)
416 int br_index
= get_index(argv
[1], "bridge");
417 int port_index
= get_index(argv
[2], "port");
418 return set_port_cfg(port_auto_edge
, getyesno(argv
[3], "yes", "no"));
421 static int cmd_setportp2p(int argc
, char *const *argv
)
424 int br_index
= get_index(argv
[1], "bridge");
425 int port_index
= get_index(argv
[2], "port");
426 const char *opts
[] = { "no", "yes", "auto", NULL
};
427 int vals
[] = { STP_ADMIN_P2P_FORCE_FALSE
, STP_ADMIN_P2P_FORCE_TRUE
,
428 STP_ADMIN_P2P_AUTO
};
430 return set_port_cfg(port_admin_p2p
, vals
[getenum(argv
[3], opts
)]);
433 static int cmd_portmcheck(int argc
, char *const *argv
)
436 int br_index
= get_index(argv
[1], "bridge");
437 int port_index
= get_index(argv
[2], "port");
438 return CTL_port_mcheck(br_index
, port_index
);
441 static int cmd_debuglevel(int argc
, char *const *argv
)
443 return CTL_set_debug_level(getuint(argv
[1]));
450 int (*func
) (int argc
, char *const *argv
);
454 static const struct command commands
[] = {
455 {0, 32, "showbridge", cmd_showbridge
,
456 "[<bridge> ... ]\t\tshow bridge state"},
457 {1, 32, "showport", cmd_showport
,
458 "<bridge> [<port> ... ]\tshow port state"},
459 {1, 32, "showportdetail", cmd_showportdetail
,
460 "<bridge> [<port> ... ]\tshow port state (detail)"},
461 {2, 0, "setbridgeprio", cmd_setbridgeprio
,
462 "<bridge> <priority>\tset bridge priority (0-61440)"},
463 {2, 0, "sethello", cmd_setbridgehello
,
464 "<bridge> <hellotime>\tset bridge hello time (1-10)"},
465 {2, 0, "setmaxage", cmd_setbridgemaxage
,
466 "<bridge> <maxage>\tset bridge max age (6-40)"},
467 {2, 0, "setfdelay", cmd_setbridgefdelay
,
468 "<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
469 {2, 0, "setforcevers", cmd_setbridgeforcevers
,
470 "<bridge> {normal|slow}\tnormal RSTP or force to STP"},
471 {2, 0, "settxholdcount", cmd_setbridgetxholdcount
,
472 "<bridge> <tx_hold_count>\tset bridge transmit hold count (1-10)"},
473 {3, 0, "setportprio", cmd_setportprio
,
474 "<bridge> <port> <priority>\tset port priority (0-240)"},
475 {3, 0, "setportpathcost", cmd_setportpathcost
,
476 "<bridge> <port> <cost>\tset port path cost"},
477 {3, 0, "setportadminedge", cmd_setportadminedge
,
478 "<bridge> <port> {yes|no}\tconfigure if it is an admin edge port"},
479 {3, 0, "setportautoedge", cmd_setportautoedge
,
480 "<bridge> <port> {yes|no}\tconfigure if it is an auto edge port"},
481 {3, 0, "setportp2p", cmd_setportp2p
,
482 "<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
483 {2, 0, "portmcheck", cmd_portmcheck
,
484 "<bridge> <port>\ttry to get back from STP to RSTP mode"},
485 {1, 0, "debuglevel", cmd_debuglevel
, "<level>\t\tLevel of verbosity"},
488 const struct command
*command_lookup(const char *cmd
)
492 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
493 if (!strcmp(cmd
, commands
[i
].name
))
500 void command_helpall(void)
504 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
505 printf("\t%-10s\t%s\n", commands
[i
].name
, commands
[i
].help
);
511 printf("Usage: rstpctl [commands]\n");
512 printf("commands:\n");
516 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
517 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
519 int main(int argc
, char *const *argv
)
521 const struct command
*cmd
;
523 static const struct option options
[] = {
524 {.name
= "help",.val
= 'h'},
525 {.name
= "version",.val
= 'V'},
529 while ((f
= getopt_long(argc
, argv
, "Vh", options
, NULL
)) != EOF
)
535 printf("%s\n", PACKAGE_VERSION(VERSION
, BUILD
));
538 fprintf(stderr
, "Unknown option '%c'\n", f
);
545 if (ctl_client_init()) {
546 fprintf(stderr
, "can't setup control connection\n");
552 if ((cmd
= command_lookup(argv
[0])) == NULL
) {
553 fprintf(stderr
, "never heard of command [%s]\n", argv
[0]);
557 if (argc
< cmd
->nargs
+ 1 || argc
> cmd
->nargs
+ cmd
->optargs
+ 1) {
558 printf("Incorrect number of arguments for command\n");
559 printf("Usage: rstpctl %s %s\n", cmd
->name
, cmd
->help
);
563 return cmd
->func(argc
, argv
);