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"
23 int get_index_die(const char *ifname
, const char *doc
, int die
)
25 int r
= if_nametoindex(ifname
);
28 "Can't find index for %s %s. Not a valid interface.\n",
37 int get_index(const char *ifname
, const char *doc
)
39 return get_index_die(ifname
, doc
, 1);
42 #define BR_ID_FMT "%02x%02x.%02x%02x%02x%02x%02x%02x"
43 #define BR_ID_ARGS(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
45 #define BOOL_STR(x) ((x) ? "yes" : "no")
47 static int do_showbridge(const char *br_name
)
51 int br_index
= get_index_die(br_name
, "bridge", 0);
55 int r
= CTL_get_bridge_status(br_index
, &s
);
59 printf("%s\n", br_name
);
60 printf(" enabled\t\t%4s\n", BOOL_STR(s
.enabled
));
61 printf(" bridge id\t\t" BR_ID_FMT
"\n", BR_ID_ARGS(s
.bridge_id
));
62 printf(" designated root\t" BR_ID_FMT
"\n",
63 BR_ID_ARGS(s
.designated_root
));
64 //printf(" designated bridge\t\t", BR_ID_FMT "\n",
65 // BR_ID_ARGS(s.designated_bridge));
66 printf(" root port\t\t%4u", s
.root_port
);
67 printf("\t\t\tpath cost\t\t%4u\n", s
.root_path_cost
);
68 printf(" max age\t\t%4u", s
.max_age
);
69 printf("\t\t\tbridge max age\t\t%4u\n", s
.bridge_max_age
);
70 printf(" hello time\t\t%4u", s
.hello_time
);
71 printf("\t\t\tbridge hello time\t%4u\n", s
.bridge_hello_time
);
72 printf(" forward delay\t\t%4u", s
.forward_delay
);
73 printf("\t\t\tbridge forward delay\t%4u\n", s
.bridge_forward_delay
);
74 printf(" tx hold count\t\t%4u\n", s
.tx_hold_count
);
75 printf(" protocol version\t%4u\n", s
.protocol_version
);
76 printf(" time since topology change\t%4u\n",
77 s
.time_since_topology_change
);
78 printf(" toplogy change count\t\t%4u\n", s
.topology_change_count
);
79 printf(" topology change\t\t%4s\n", BOOL_STR(s
.topology_change
));
84 #define SYSFS_PATH_MAX 256
85 #define SYSFS_CLASS_NET "/sys/class/net"
87 static int isbridge(const struct dirent
*entry
)
89 char path
[SYSFS_PATH_MAX
];
92 snprintf(path
, SYSFS_PATH_MAX
, SYSFS_CLASS_NET
"/%s/bridge",
94 return stat(path
, &st
) == 0 && S_ISDIR(st
.st_mode
);
97 static int cmd_showbridge(int argc
, char *const *argv
)
101 struct dirent
**namelist
;
107 scandir(SYSFS_CLASS_NET
, &namelist
, isbridge
, alphasort
);
109 fprintf(stderr
, "Error getting list of all bridges\n");
114 for (i
= 0; i
< count
; i
++) {
119 name
= namelist
[i
]->d_name
;
121 int err
= do_showbridge(name
);
127 for (i
= 0; i
< count
; i
++)
136 #define STATE_STR(_state) \
139 char *_str = "unknown"; \
142 case STP_PORT_STATE_DISCARDING: _str = "discarding"; break; \
143 case STP_PORT_STATE_LEARNING: _str = "learning"; break; \
144 case STP_PORT_STATE_FORWARDING: _str = "forwarding"; break; \
149 #define SHORT_STATE_STR(_state) \
152 char *_str = "unkn"; \
155 case STP_PORT_STATE_DISCARDING: _str = "disc"; break; \
156 case STP_PORT_STATE_LEARNING: _str = "lear"; break; \
157 case STP_PORT_STATE_FORWARDING: _str = "forw"; break; \
162 #define ADMIN_P2P_STR(_state) \
165 char *_str = "unkn"; \
168 case STP_ADMIN_P2P_FORCE_FALSE: _str = "no"; break; \
169 case STP_ADMIN_P2P_FORCE_TRUE: _str = "yes"; break; \
170 case STP_ADMIN_P2P_AUTO: _str = "auto"; break; \
178 static int do_showport(int br_index
, const char *port_name
)
182 int port_index
= get_index_die(port_name
, "port", 0);
186 r
= CTL_get_port_status(br_index
, port_index
, &s
);
188 fprintf(stderr
, "Failed to get port state for port %d\n",
194 printf("%s (%u)\n", port_name
, (s
.id
& 0xfff));
195 printf(" enabled\t\t%4s\n", BOOL_STR(s
.enabled
));
196 printf(" port id\t\t%04x\t\t\tstate\t\t%15s\n",
197 s
.id
, STATE_STR(s
.state
));
198 printf(" path cost\t%12d\t\t\tadmin path cost\t%12d\n",
199 s
.path_cost
, s
.admin_path_cost
);
200 printf(" designated root\t" BR_ID_FMT
,
201 BR_ID_ARGS(s
.designated_root
));
202 printf("\tdesignated cost\t%12u\n", s
.designated_cost
);
203 printf(" designated bridge\t" BR_ID_FMT
,
204 BR_ID_ARGS(s
.designated_bridge
));
205 printf("\tdesignated port\t\t%04x\n", s
.designated_port
);
206 printf(" admin edge port\t%4s", BOOL_STR(s
.admin_edge_port
));
207 printf("\t\t\tauto edge port\t\t%4s\n",
208 BOOL_STR(s
.auto_edge_port
));
209 printf(" oper edge port\t\t%4s", BOOL_STR(s
.oper_edge_port
));
210 printf("\t\t\ttoplogy change ack\t%4s\n", BOOL_STR(s
.tc_ack
));
211 printf(" point to point\t\t%4s", BOOL_STR(s
.oper_p2p
));
212 printf("\t\t\tadmin point to point\t%4s\n",
213 ADMIN_P2P_STR(s
.admin_p2p
));
215 printf("%c%c %4s %04x %4s " BR_ID_FMT
" " BR_ID_FMT
" %04x\n",
216 (s
.oper_p2p
) ? ' ' : '*',
217 (s
.oper_edge_port
) ? 'E' : ' ',
220 s
.enabled
?SHORT_STATE_STR(s
.state
):"down",
221 BR_ID_ARGS(s
.designated_root
),
222 BR_ID_ARGS(s
.designated_bridge
),
228 static int not_dot_dotdot(const struct dirent
*entry
)
230 const char *n
= entry
->d_name
;
232 return !(n
[0] == '.' && (n
[1] == 0 || (n
[1] == '.' && n
[2] == 0)));
235 static int cmd_showport(int argc
, char *const *argv
)
239 int br_index
= get_index(argv
[1], "bridge");
242 struct dirent
**namelist
;
247 char buf
[SYSFS_PATH_MAX
];
248 snprintf(buf
, sizeof(buf
), SYSFS_CLASS_NET
"/%s/brif", argv
[1]);
249 count
= scandir(buf
, &namelist
, not_dot_dotdot
, alphasort
);
252 "Error getting list of all ports of bridge %s\n",
258 for (i
= 0; i
< count
; i
++) {
263 name
= namelist
[i
]->d_name
;
265 int err
= do_showport(br_index
, name
);
271 for (i
= 0; i
< count
; i
++)
279 static int cmd_showportdetail(int argc
, char *const *argv
)
282 return cmd_showport(argc
, argv
);
285 unsigned int getuint(const char *s
)
289 l
= strtoul(s
, &end
, 0);
290 if (*s
== 0 || *end
!= 0 || l
> INT_MAX
) {
291 fprintf(stderr
, "Invalid unsigned int arg %s\n", s
);
297 int getenum(const char *s
, const char *opt
[])
300 for (i
= 0; opt
[i
] != NULL
; i
++)
301 if (strcmp(s
, opt
[i
]) == 0)
304 fprintf(stderr
, "Invalid argument %s: expecting one of ", s
);
305 for (i
= 0; opt
[i
] != NULL
; i
++)
306 fprintf(stderr
, "%s%s", opt
[i
], (opt
[i
+ 1] ? ", " : "\n"));
311 int getyesno(const char *s
, const char *yes
, const char *no
)
313 /* Reverse yes and no so error message looks more normal */
314 const char *opt
[] = { yes
, no
, NULL
};
315 return 1 - getenum(s
, opt
);
318 #define set_bridge_cfg(field, value) \
320 STP_BridgeConfig c; \
321 memset(&c, 0, sizeof(c)); \
323 c.set_ ## field = 1; \
324 int r = CTL_set_bridge_config(br_index, &c); \
326 printf("Couldn't change bridge " #field "\n"); \
330 #define set_port_cfg(field, value) \
333 memset(&c, 0, sizeof(c)); \
335 c.set_ ## field = 1; \
336 int r = CTL_set_port_config(br_index, port_index, &c); \
338 printf("Couldn't change port " #field "\n"); \
344 static int cmd_setbridgeprio(int argc
, char *const *argv
)
347 int br_index
= get_index(argv
[1], "bridge");
348 return set_bridge_cfg(bridge_priority
, getuint(argv
[2]));
351 static int cmd_setbridgemaxage(int argc
, char *const *argv
)
354 int br_index
= get_index(argv
[1], "bridge");
355 return set_bridge_cfg(bridge_max_age
, getuint(argv
[2]));
358 static int cmd_setbridgehello(int argc
, char *const *argv
)
361 int br_index
= get_index(argv
[1], "bridge");
362 return set_bridge_cfg(bridge_hello_time
, getuint(argv
[2]));
365 static int cmd_setbridgefdelay(int argc
, char *const *argv
)
368 int br_index
= get_index(argv
[1], "bridge");
369 return set_bridge_cfg(bridge_forward_delay
, getuint(argv
[2]));
372 static int cmd_setbridgeforcevers(int argc
, char *const *argv
)
375 int br_index
= get_index(argv
[1], "bridge");
376 return set_bridge_cfg(bridge_protocol_version
,
377 2 * getyesno(argv
[2], "normal", "slow"));
380 static int cmd_setbridgetxholdcount(int argc
, char *const *argv
)
383 int br_index
= get_index(argv
[1], "bridge");
384 return set_bridge_cfg(bridge_tx_hold_count
, getuint(argv
[2]));
388 static int cmd_setportprio(int argc
, char *const *argv
)
391 int br_index
= get_index(argv
[1], "bridge");
392 int port_index
= get_index(argv
[2], "port");
393 return set_port_cfg(port_priority
, getuint(argv
[3]));
396 static int cmd_setportpathcost(int argc
, char *const *argv
)
399 int br_index
= get_index(argv
[1], "bridge");
400 int port_index
= get_index(argv
[2], "port");
401 return set_port_cfg(port_pathcost
, getuint(argv
[3]));
404 static int cmd_setportadminedge(int argc
, char *const *argv
)
407 int br_index
= get_index(argv
[1], "bridge");
408 int port_index
= get_index(argv
[2], "port");
409 return set_port_cfg(port_admin_edge
, getyesno(argv
[3], "yes", "no"));
412 static int cmd_setportautoedge(int argc
, char *const *argv
)
415 int br_index
= get_index(argv
[1], "bridge");
416 int port_index
= get_index(argv
[2], "port");
417 return set_port_cfg(port_auto_edge
, getyesno(argv
[3], "yes", "no"));
420 static int cmd_setportp2p(int argc
, char *const *argv
)
423 int br_index
= get_index(argv
[1], "bridge");
424 int port_index
= get_index(argv
[2], "port");
425 const char *opts
[] = { "no", "yes", "auto", NULL
};
426 int vals
[] = { STP_ADMIN_P2P_FORCE_FALSE
, STP_ADMIN_P2P_FORCE_TRUE
,
427 STP_ADMIN_P2P_AUTO
};
429 return set_port_cfg(port_admin_p2p
, vals
[getenum(argv
[3], opts
)]);
432 static int cmd_portmcheck(int argc
, char *const *argv
)
435 int br_index
= get_index(argv
[1], "bridge");
436 int port_index
= get_index(argv
[2], "port");
437 return CTL_port_mcheck(br_index
, port_index
);
440 static int cmd_debuglevel(int argc
, char *const *argv
)
442 return CTL_set_debug_level(getuint(argv
[1]));
449 int (*func
) (int argc
, char *const *argv
);
453 static const struct command commands
[] = {
454 {0, 32, "showbridge", cmd_showbridge
,
455 "[<bridge> ... ]\t\tshow bridge state"},
456 {1, 32, "showport", cmd_showport
,
457 "<bridge> [<port> ... ]\tshow port state"},
458 {1, 32, "showportdetail", cmd_showportdetail
,
459 "<bridge> [<port> ... ]\tshow port state (detail)"},
460 {2, 0, "setbridgeprio", cmd_setbridgeprio
,
461 "<bridge> <priority>\tset bridge priority (0-61440)"},
462 {2, 0, "sethello", cmd_setbridgehello
,
463 "<bridge> <hellotime>\tset bridge hello time (1-10)"},
464 {2, 0, "setmaxage", cmd_setbridgemaxage
,
465 "<bridge> <maxage>\tset bridge max age (6-40)"},
466 {2, 0, "setfdelay", cmd_setbridgefdelay
,
467 "<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
468 {2, 0, "setforcevers", cmd_setbridgeforcevers
,
469 "<bridge> {normal|slow}\tnormal RSTP or force to STP"},
470 {2, 0, "settxholdcount", cmd_setbridgetxholdcount
,
471 "<bridge> <tx_hold_count>\tset bridge transmit hold count (1-10)"},
472 {3, 0, "setportprio", cmd_setportprio
,
473 "<bridge> <port> <priority>\tset port priority (0-240)"},
474 {3, 0, "setportpathcost", cmd_setportpathcost
,
475 "<bridge> <port> <cost>\tset port path cost"},
476 {3, 0, "setportadminedge", cmd_setportadminedge
,
477 "<bridge> <port> {yes|no}\tconfigure if it is an admin edge port"},
478 {3, 0, "setportautoedge", cmd_setportautoedge
,
479 "<bridge> <port> {yes|no}\tconfigure if it is an auto edge port"},
480 {3, 0, "setportp2p", cmd_setportp2p
,
481 "<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
482 {2, 0, "portmcheck", cmd_portmcheck
,
483 "<bridge> <port>\ttry to get back from STP to RSTP mode"},
484 {1, 0, "debuglevel", cmd_debuglevel
, "<level>\t\tLevel of verbosity"},
487 const struct command
*command_lookup(const char *cmd
)
491 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
492 if (!strcmp(cmd
, commands
[i
].name
))
499 void command_helpall(void)
503 for (i
= 0; i
< sizeof(commands
) / sizeof(commands
[0]); i
++) {
504 printf("\t%-10s\t%s\n", commands
[i
].name
, commands
[i
].help
);
510 printf("Usage: rstpctl [commands]\n");
511 printf("commands:\n");
515 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
516 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
518 int main(int argc
, char *const *argv
)
520 const struct command
*cmd
;
522 static const struct option options
[] = {
523 {.name
= "help",.val
= 'h'},
524 {.name
= "version",.val
= 'V'},
528 while ((f
= getopt_long(argc
, argv
, "Vh", options
, NULL
)) != EOF
)
534 printf("%s\n", PACKAGE_VERSION(VERSION
, BUILD
));
537 fprintf(stderr
, "Unknown option '%c'\n", f
);
544 if (ctl_client_init()) {
545 fprintf(stderr
, "can't setup control connection\n");
551 if ((cmd
= command_lookup(argv
[0])) == NULL
) {
552 fprintf(stderr
, "never heard of command [%s]\n", argv
[0]);
556 if (argc
< cmd
->nargs
+ 1 || argc
> cmd
->nargs
+ cmd
->optargs
+ 1) {
557 printf("Incorrect number of arguments for command\n");
558 printf("Usage: rstpctl %s %s\n", cmd
->name
, cmd
->help
);
562 return cmd
->func(argc
, argv
);