]> git.ipfire.org Git - people/ms/rstp.git/blame - ctl_main.c
Fix rstpctl usage
[people/ms/rstp.git] / ctl_main.c
CommitLineData
ad02a0eb
SH
1/*
2 Command parsing taken from brctl utility.
3 Display code from stp_cli.c in rstplib.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/errno.h>
10#include <getopt.h>
11
12#include <net/if.h>
13
14/* For scanning through sysfs directories */
15#include <dirent.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <unistd.h>
76eb7423 19#include <limits.h>
ad02a0eb
SH
20
21#include "ctl_socket_client.h"
22#include "ctl_functions.h"
23
24#ifndef False
25# define False 0
26# define True 1
27#endif
28
29#define STP_IN_get_error_explanation CTL_error_explanation
30
11904a35
SH
31static void print_bridge_id(UID_BRIDGE_ID_T * bridge_id, unsigned char cr)
32{
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]);
41 if (cr)
42 printf("\n");
43}
44
45static char *stp_state2str(RSTP_PORT_STATE stp_port_state, int detail)
46{
47 if (detail) {
48 switch (stp_port_state) {
49 case UID_PORT_DISABLED:
50 return "Disabled";
51 case UID_PORT_DISCARDING:
52 return "Discarding";
53 case UID_PORT_LEARNING:
54 return "Learning";
55 case UID_PORT_FORWARDING:
56 return "Forwarding";
57 case UID_PORT_NON_STP:
58 return "NoStp";
59 default:
60 return "Unknown";
61 }
62 }
63
64 switch (stp_port_state) {
65 case UID_PORT_DISABLED:
66 return "Dis";
67 case UID_PORT_DISCARDING:
68 return "Blk";
69 case UID_PORT_LEARNING:
70 return "Lrn";
71 case UID_PORT_FORWARDING:
72 return "Fwd";
73 case UID_PORT_NON_STP:
74 return "Non";
75 default:
76 return "Unk";
77 }
78}
79
80static void CLI_out_port_id(int port, unsigned char cr)
81{
82 static char ifname[IFNAMSIZ];
83 if (if_indextoname(port, ifname))
84 printf("%s", ifname);
85 else
86 printf("Ifindex %02d", port);
87 if (cr)
88 printf("\n");
ad02a0eb
SH
89}
90
91int get_index_die(const char *ifname, const char *doc, int die)
92{
11904a35
SH
93 int r = if_nametoindex(ifname);
94 if (r == 0) {
95 fprintf(stderr,
96 "Can't find index for %s %s. Not a valid interface.\n",
97 doc, ifname);
98 if (die)
99 exit(1);
100 return -1;
101 }
102 return r;
ad02a0eb
SH
103}
104
105int get_index(const char *ifname, const char *doc)
106{
11904a35 107 return get_index_die(ifname, doc, 1);
ad02a0eb
SH
108}
109
11904a35 110static int cmd_rstp(int argc, char *const *argv)
ad02a0eb 111{
11904a35
SH
112 int stp, r;
113 int br_index = get_index(argv[1], "bridge");
ad02a0eb 114
11904a35
SH
115 if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
116 || !strcmp(argv[2], "1"))
117 stp = 1;
118 else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no")
119 || !strcmp(argv[2], "0"))
120 stp = 0;
121 else {
122 fprintf(stderr, "expect on/off for argument\n");
123 return 1;
124 }
125 r = CTL_enable_bridge_rstp(br_index, stp);
126 if (r) {
127 fprintf(stderr, "Failed to enable/disable RSTP: %s\n",
128 CTL_error_explanation(r));
129 return -1;
130 }
131 return 0;
ad02a0eb
SH
132}
133
134static int do_showbridge(const char *br_name)
135{
11904a35
SH
136 UID_STP_STATE_T uid_state;
137 UID_STP_CFG_T uid_cfg;
138
139 int br_index = get_index_die(br_name, "bridge", 0);
140 if (br_index < 0)
141 return -1;
142
143 int r = CTL_get_bridge_state(br_index, &uid_cfg, &uid_state);
144 if (r) {
145 fprintf(stderr, "Failed to get bridge state: %s\n",
146 CTL_error_explanation(r));
147 return -1;
148 }
ad02a0eb 149#if 0
11904a35
SH
150 printf("Interface: %-7s (tag:%d) State: ",
151 uid_state.vlan_name, (int)uid_state.vlan_id);
ad02a0eb 152#else
11904a35
SH
153 printf("Bridge: %-7s State:",
154 uid_state.vlan_name);
ad02a0eb 155#endif
11904a35
SH
156 switch (uid_state.stp_enabled) {
157 case STP_ENABLED:
158 printf("enabled\n");
159 break;
160 case STP_DISABLED:
161 printf("disabled\n");
162 break;
163 default:
164 printf("unknown\n");
165 return 0;
166 }
167
168 printf("BridgeId: ");
169 print_bridge_id(&uid_state.bridge_id, 0);
170 printf(" Bridge Proirity: %lu (0x%lX)\n",
171 (unsigned long)uid_state.bridge_id.prio,
172 (unsigned long)uid_state.bridge_id.prio);
173 if (uid_cfg.force_version < 2)
174 printf("Force Version: stp\n");
175
176 printf("Designated Root: ");
177 print_bridge_id(&uid_state.designated_root, 1);
178 if (uid_state.root_port) {
179 printf("Root Port: %04lx",
180 (unsigned long)uid_state.root_port);
181 // CLI_out_port_id (uid_state.root_port & 0xfff, False);
182 // printf("not implemented"); // XXX
183 printf(", Root Cost: %-lu\n",
184 (unsigned long)uid_state.root_path_cost);
185 } else {
186 printf("Root Port: none\n");
187 }
188
189 if (uid_state.Topo_Change)
190 printf("Topology Change Count: %lu\n",
191 uid_state.Topo_Change_Count);
192 else
193 printf("Time Since Topology Change: %lu\n",
194 uid_state.timeSince_Topo_Change);
195
196 printf("Max Age: %2d Bridge Max Age: %-2d\n",
197 (int)uid_state.max_age, (int)uid_cfg.max_age);
198 printf("Hello Time: %2d Bridge Hello Time: %-2d\n",
199 (int)uid_state.hello_time, (int)uid_cfg.hello_time);
200 printf("Forward Delay: %2d Bridge Forward Delay: %-2d\n",
201 (int)uid_state.forward_delay, (int)uid_cfg.forward_delay);
202 printf("Hold Time: %2d\n", (int)uid_cfg.hold_time);
203
204 return 0;
ad02a0eb
SH
205}
206
207#define SYSFS_PATH_MAX 256
208#define SYSFS_CLASS_NET "/sys/class/net"
209
210static int isbridge(const struct dirent *entry)
211{
11904a35
SH
212 char path[SYSFS_PATH_MAX];
213 struct stat st;
214
215 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "/%s/bridge",
216 entry->d_name);
217 return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
218}
219
220static int cmd_showbridge(int argc, char *const *argv)
221{
222 int i, count = 0;
223 int r = 0;
224 struct dirent **namelist;
225
226 if (argc > 1) {
227 count = argc - 1;
228 } else {
229 count =
230 scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
231 if (count < 0) {
232 fprintf(stderr, "Error getting list of all bridges\n");
233 return -1;
234 }
235 }
236
237 for (i = 0; i < count; i++) {
238 const char *name;
239 if (argc > 1)
240 name = argv[i + 1];
241 else
242 name = namelist[i]->d_name;
243
244 int err = do_showbridge(name);
245 if (err)
246 r = err;
247 }
248
249 if (argc <= 1) {
250 for (i = 0; i < count; i++)
251 free(namelist[i]);
252 free(namelist);
253 }
254
255 return r;
ad02a0eb
SH
256}
257
258int detail = 0;
259
260static int do_showport(int br_index, const char *port_name,
11904a35
SH
261 UID_STP_STATE_T * uid_state)
262{
263 UID_STP_PORT_STATE_T uid_port;
264 UID_STP_PORT_CFG_T uid_cfg;
265 int r = 0;
266 int port_index = get_index_die(port_name, "port", 0);
267 if (port_index < 0)
268 return -1;
269
270 memset(&uid_cfg, 0, sizeof(UID_STP_PORT_CFG_T));
271 r = CTL_get_port_state(br_index, port_index, &uid_cfg, &uid_port);
272 if (r) {
273 fprintf(stderr, "Failed to get port state for port %d: %s\n",
274 port_index, CTL_error_explanation(r));
275 return -1;
276 }
277
278 if (detail) {
279 printf("Stp Port ");
280 CLI_out_port_id(port_index, False);
ad02a0eb 281#if 0
11904a35
SH
282 printf(": PortId: %04lx in vlan '%s' with tag %d:\n",
283 (unsigned long)uid_port.port_id, uid_state->vlan_name,
284 (int)uid_state->vlan_id);
ad02a0eb 285#else
11904a35
SH
286 printf(": PortId: %04lx in Bridge '%s':\n",
287 (unsigned long)uid_port.port_id, uid_state->vlan_name);
ad02a0eb 288#endif
11904a35
SH
289 printf("Priority: %-d\n",
290 (int)(uid_port.port_id >> 8));
291 printf("State: %-16s",
292 stp_state2str(uid_port.state, 1));
293 printf(" Uptime: %-9lu\n", uid_port.uptime);
294 printf("PortPathCost: admin: ");
295 if (ADMIN_PORT_PATH_COST_AUTO == uid_cfg.admin_port_path_cost)
296 printf("%-9s", "Auto");
297 else
298 printf("%-9lu", uid_cfg.admin_port_path_cost);
299 printf(" oper: %-9lu\n", uid_port.oper_port_path_cost);
300
301 printf("Point2Point: admin: ");
302 switch (uid_cfg.admin_point2point) {
303 case P2P_FORCE_TRUE:
304 printf("%-9s", "ForceYes");
305 break;
306 case P2P_FORCE_FALSE:
307 printf("%-9s", "ForceNo");
308 break;
309 case P2P_AUTO:
310 printf("%-9s", "Auto");
311 break;
312 }
313 printf(" oper: %-9s\n",
314 uid_port.oper_point2point ? "Yes" : "No");
315 printf("Edge: admin: %-9s oper: %-9s\n",
316 uid_cfg.admin_edge ? "Y" : "N",
317 uid_port.oper_edge ? "Y" : "N");
318 printf("Partner: oper: %-9s\n",
319 uid_port.oper_stp_neigb ? "Slow" : "Rapid");
320
321 if (' ' != uid_port.role) {
322 if ('-' != uid_port.role) {
323 printf("PathCost: %-lu\n",
324 (unsigned long)(uid_port.path_cost));
325 printf("Designated Root: ");
326 print_bridge_id(&uid_port.designated_root, 1);
327 printf("Designated Cost: %-ld\n",
328 (unsigned long)uid_port.designated_cost);
329 printf("Designated Bridge: ");
330 print_bridge_id(&uid_port.designated_bridge, 1);
331 printf("Designated Port: %-4lx\n\r",
332 (unsigned long)uid_port.designated_port);
333 }
334 printf("Role: ");
335 switch (uid_port.role) {
336 case 'A':
337 printf("Alternate\n");
338 break;
339 case 'B':
340 printf("Backup\n");
341 break;
342 case 'R':
343 printf("Root\n");
344 break;
345 case 'D':
346 printf("Designated\n");
347 break;
348 case '-':
349 printf("NonStp\n");
350 break;
351 default:
352 printf("Unknown(%c)\n", uid_port.role);
353 break;
354 }
355
356 if ('R' == uid_port.role || 'D' == uid_port.role) {
357 /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */
358 printf("TcAck: %c ",
359 uid_port.top_change_ack ? 'Y' : 'N');
360 printf("TcWhile: %3d\n",
361 (int)uid_port.tcWhile);
362 }
363 }
364
365 if (UID_PORT_DISABLED == uid_port.state || '-' == uid_port.role) {
ad02a0eb 366#if 0
11904a35
SH
367 printf("helloWhen: %3d ",
368 (int)uid_port.helloWhen);
369 printf("lnkWhile: %3d\n", (int)uid_port.lnkWhile);
370 printf("fdWhile: %3d\n", (int)uid_port.fdWhile);
ad02a0eb 371#endif
11904a35
SH
372 } else if ('-' != uid_port.role) {
373 printf("fdWhile: %3d ", (int)uid_port.fdWhile);
374 printf("rcvdInfoWhile: %3d\n",
375 (int)uid_port.rcvdInfoWhile);
376 printf("rbWhile: %3d ", (int)uid_port.rbWhile);
377 printf("rrWhile: %3d\n", (int)uid_port.rrWhile);
ad02a0eb 378#if 0
11904a35
SH
379 printf("mdelayWhile: %3d ",
380 (int)uid_port.mdelayWhile);
381 printf("lnkWhile: %3d\n", (int)uid_port.lnkWhile);
382 printf("helloWhen: %3d ",
383 (int)uid_port.helloWhen);
384 printf("txCount: %3d\n", (int)uid_port.txCount);
ad02a0eb 385#endif
11904a35
SH
386 }
387
388 printf("RSTP BPDU rx: %lu\n",
389 (unsigned long)uid_port.rx_rstp_bpdu_cnt);
390 printf("CONFIG BPDU rx: %lu\n",
391 (unsigned long)uid_port.rx_cfg_bpdu_cnt);
392 printf("TCN BPDU rx: %lu\n",
393 (unsigned long)uid_port.rx_tcn_bpdu_cnt);
394 } else {
395 printf("%c%c%c ",
396 (uid_port.oper_point2point) ? ' ' : '*',
397 (uid_port.oper_edge) ? 'E' : ' ',
398 (uid_port.oper_stp_neigb) ? 's' : ' ');
399 CLI_out_port_id(port_index, False);
400 printf(" %04lx %3s ", (unsigned long)uid_port.port_id,
401 stp_state2str(uid_port.state, 0));
402 printf(" ");
403 print_bridge_id(&uid_port.designated_root, 0);
404 printf(" ");
405 print_bridge_id(&uid_port.designated_bridge, 0);
406 printf(" %4lx %c", (unsigned long)uid_port.designated_port,
407 uid_port.role);
408 printf("\n");
409 }
410 return 0;
ad02a0eb
SH
411}
412
413static int not_dot_dotdot(const struct dirent *entry)
414{
11904a35
SH
415 const char *n = entry->d_name;
416
417 return !(n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
ad02a0eb
SH
418}
419
11904a35 420static int cmd_showport(int argc, char *const *argv)
ad02a0eb 421{
11904a35
SH
422 UID_STP_STATE_T uid_state;
423 UID_STP_CFG_T uid_br_cfg;
424 int r = 0;
425
426 int br_index = get_index(argv[1], "bridge");
427
428 r = CTL_get_bridge_state(br_index, &uid_br_cfg, &uid_state);
429 if (r) {
430 fprintf(stderr, "Failed to get bridge state: %s\n",
431 CTL_error_explanation(r));
432 return -1;
433 }
434
435 int i, count = 0;
436 struct dirent **namelist;
437
438 if (argc > 2) {
439 count = argc - 2;
440 } else {
441 char buf[SYSFS_PATH_MAX];
442 snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
443 count = scandir(buf, &namelist, not_dot_dotdot, alphasort);
444 if (count < 0) {
445 fprintf(stderr,
446 "Error getting list of all ports of bridge %s\n",
447 argv[1]);
448 return -1;
449 }
450 }
451
452 for (i = 0; i < count; i++) {
453 const char *name;
454 if (argc > 2)
455 name = argv[i + 2];
456 else
457 name = namelist[i]->d_name;
458
459 int err = do_showport(br_index, name, &uid_state);
460 if (err)
461 r = err;
462 }
463
464 if (argc <= 2) {
465 for (i = 0; i < count; i++)
466 free(namelist[i]);
467 free(namelist);
468 }
469
470 return r;
ad02a0eb
SH
471}
472
11904a35 473static int cmd_showportdetail(int argc, char *const *argv)
ad02a0eb 474{
11904a35
SH
475 detail = 1;
476 return cmd_showport(argc, argv);
ad02a0eb
SH
477}
478
11904a35 479unsigned int getuint(const char *s)
ad02a0eb 480{
11904a35
SH
481 char *end;
482 long l;
483 l = strtoul(s, &end, 0);
484 if (*s == 0 || *end != 0 || l > INT_MAX) {
485 fprintf(stderr, "Invalid unsigned int arg %s\n", s);
486 exit(1);
487 }
488 return l;
ad02a0eb
SH
489}
490
11904a35 491int getenum(const char *s, const char *opt[])
ad02a0eb 492{
11904a35
SH
493 int i;
494 for (i = 0; opt[i] != NULL; i++)
495 if (strcmp(s, opt[i]) == 0)
496 return i;
497
498 fprintf(stderr, "Invalid argument %s: expecting one of ", s);
499 for (i = 0; opt[i] != NULL; i++)
500 fprintf(stderr, "%s%s", opt[i], (opt[i + 1] ? ", " : "\n"));
501
502 exit(1);
503}
504
505int getyesno(const char *s, const char *yes, const char *no)
506{
507 /* Reverse yes and no so error message looks more normal */
508 const char *opt[] = { yes, no, NULL };
509 return 1 - getenum(s, opt);
510}
511
512static int set_bridge_cfg_value(int br_index, unsigned long value,
513 unsigned long val_mask)
514{
515 UID_STP_CFG_T uid_cfg;
516 char *val_name;
517 int rc;
518
519 uid_cfg.field_mask = val_mask;
520 switch (val_mask) {
521 case BR_CFG_STATE:
522 uid_cfg.stp_enabled = value;
523 val_name = "state";
524 break;
525 case BR_CFG_PRIO:
526 uid_cfg.bridge_priority = value;
527 val_name = "priority";
528 break;
529 case BR_CFG_AGE:
530 uid_cfg.max_age = value;
531 val_name = "max_age";
532 break;
533 case BR_CFG_HELLO:
534 uid_cfg.hello_time = value;
535 val_name = "hello_time";
536 break;
537 case BR_CFG_DELAY:
538 uid_cfg.forward_delay = value;
539 val_name = "forward_delay";
540 break;
541 case BR_CFG_FORCE_VER:
542 uid_cfg.force_version = value;
543 val_name = "force_version";
544 break;
545 case BR_CFG_AGE_MODE:
546 case BR_CFG_AGE_TIME:
547 default:
548 printf("Invalid value mask 0X%lx\n", val_mask);
549 return -1;
550 break;
551 }
ad02a0eb 552
11904a35 553 rc = CTL_set_bridge_config(br_index, &uid_cfg);
ad02a0eb 554
11904a35
SH
555 if (0 != rc) {
556 printf("Can't change rstp bridge %s:%s\n", val_name,
557 STP_IN_get_error_explanation(rc));
558 return -1;
559 }
560 return 0;
ad02a0eb
SH
561}
562
11904a35 563static int cmd_setbridgestate(int argc, char *const *argv)
ad02a0eb
SH
564{
565
11904a35
SH
566 int br_index = get_index(argv[1], "bridge");
567 return set_bridge_cfg_value(br_index,
568 getyesno(argv[2], "on", "off"),
569 BR_CFG_STATE);
ad02a0eb
SH
570}
571
11904a35 572static int cmd_setbridgeprio(int argc, char *const *argv)
ad02a0eb
SH
573{
574
11904a35
SH
575 int br_index = get_index(argv[1], "bridge");
576 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_PRIO);
ad02a0eb
SH
577}
578
11904a35 579static int cmd_setbridgemaxage(int argc, char *const *argv)
ad02a0eb
SH
580{
581
11904a35
SH
582 int br_index = get_index(argv[1], "bridge");
583 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_AGE);
ad02a0eb
SH
584}
585
11904a35 586static int cmd_setbridgehello(int argc, char *const *argv)
ad02a0eb
SH
587{
588
11904a35
SH
589 int br_index = get_index(argv[1], "bridge");
590 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_HELLO);
ad02a0eb
SH
591}
592
11904a35 593static int cmd_setbridgefdelay(int argc, char *const *argv)
ad02a0eb
SH
594{
595
11904a35
SH
596 int br_index = get_index(argv[1], "bridge");
597 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_DELAY);
ad02a0eb
SH
598}
599
11904a35 600static int cmd_setbridgeforcevers(int argc, char *const *argv)
ad02a0eb
SH
601{
602
11904a35
SH
603 int br_index = get_index(argv[1], "bridge");
604 return set_bridge_cfg_value(br_index,
605 2 * getyesno(argv[2], "normal", "slow"),
606 BR_CFG_FORCE_VER);
ad02a0eb
SH
607}
608
ad02a0eb 609static int
11904a35
SH
610set_port_cfg_value(int br_index, int port_index,
611 unsigned long value, unsigned long val_mask)
612{
613 UID_STP_PORT_CFG_T uid_cfg;
614 int rc;
615 char *val_name;
616
617 BitmapClear(&uid_cfg.port_bmp);
618 uid_cfg.field_mask = val_mask;
619 switch (val_mask) {
620 case PT_CFG_MCHECK:
621 val_name = "mcheck";
622 break;
623 case PT_CFG_COST:
624 uid_cfg.admin_port_path_cost = value;
625 val_name = "path cost";
626 break;
627 case PT_CFG_PRIO:
628 uid_cfg.port_priority = value;
629 val_name = "priority";
630 break;
631 case PT_CFG_P2P:
632 uid_cfg.admin_point2point = (ADMIN_P2P_T) value;
633 val_name = "p2p flag";
634 break;
635 case PT_CFG_EDGE:
636 uid_cfg.admin_edge = value;
637 val_name = "adminEdge";
638 break;
639 case PT_CFG_NON_STP:
640 uid_cfg.admin_non_stp = value;
641 val_name = "adminNonStp";
642 break;
ad02a0eb 643#ifdef STP_DBG
11904a35
SH
644 case PT_CFG_DBG_SKIP_TX:
645 uid_cfg.skip_tx = value;
646 val_name = "skip tx";
647 break;
648 case PT_CFG_DBG_SKIP_RX:
649 uid_cfg.skip_rx = value;
650 val_name = "skip rx";
651 break;
ad02a0eb 652#endif
11904a35
SH
653 case PT_CFG_STATE:
654 default:
655 printf("Invalid value mask 0X%lx\n", val_mask);
656 return -1;
657 }
ad02a0eb 658
11904a35 659 rc = CTL_set_port_config(br_index, port_index, &uid_cfg);
ad02a0eb 660
11904a35
SH
661 if (0 != rc) {
662 printf("can't change rstp port[s] %s: %s\n",
663 val_name, STP_IN_get_error_explanation(rc));
664 return -1;
665 }
666 return 0;
ad02a0eb
SH
667}
668
11904a35 669static int cmd_setportprio(int argc, char *const *argv)
ad02a0eb
SH
670{
671
11904a35
SH
672 int br_index = get_index(argv[1], "bridge");
673 int port_index = get_index(argv[2], "port");
674 return set_port_cfg_value(br_index, port_index,
675 getuint(argv[3]), PT_CFG_PRIO);
ad02a0eb
SH
676}
677
11904a35 678static int cmd_setportpathcost(int argc, char *const *argv)
ad02a0eb
SH
679{
680
11904a35
SH
681 int br_index = get_index(argv[1], "bridge");
682 int port_index = get_index(argv[2], "port");
683 return set_port_cfg_value(br_index, port_index,
684 getuint(argv[3]), PT_CFG_COST);
ad02a0eb
SH
685}
686
11904a35 687static int cmd_setportedge(int argc, char *const *argv)
ad02a0eb
SH
688{
689
11904a35
SH
690 int br_index = get_index(argv[1], "bridge");
691 int port_index = get_index(argv[2], "port");
692 return set_port_cfg_value(br_index, port_index,
693 getyesno(argv[3], "yes", "no"), PT_CFG_EDGE);
ad02a0eb
SH
694}
695
11904a35 696static int cmd_setportnonstp(int argc, char *const *argv)
ad02a0eb
SH
697{
698
11904a35
SH
699 int br_index = get_index(argv[1], "bridge");
700 int port_index = get_index(argv[2], "port");
701 return set_port_cfg_value(br_index, port_index,
702 getyesno(argv[3], "yes", "no"),
703 PT_CFG_NON_STP);
ad02a0eb
SH
704}
705
11904a35 706static int cmd_setportp2p(int argc, char *const *argv)
ad02a0eb
SH
707{
708
11904a35
SH
709 int br_index = get_index(argv[1], "bridge");
710 int port_index = get_index(argv[2], "port");
711 const char *opts[] = { "yes", "no", "auto", NULL };
712 int vals[] = { P2P_FORCE_TRUE, P2P_FORCE_FALSE, P2P_AUTO };
ad02a0eb 713
11904a35
SH
714 return set_port_cfg_value(br_index, port_index,
715 vals[getenum(argv[3], opts)], PT_CFG_P2P);
ad02a0eb
SH
716}
717
11904a35 718static int cmd_portmcheck(int argc, char *const *argv)
ad02a0eb
SH
719{
720
11904a35
SH
721 int br_index = get_index(argv[1], "bridge");
722 int port_index = get_index(argv[2], "port");
723 return set_port_cfg_value(br_index, port_index, 0, PT_CFG_MCHECK);
ad02a0eb
SH
724}
725
11904a35 726static int cmd_debuglevel(int argc, char *const *argv)
ad02a0eb 727{
11904a35 728 return CTL_set_debug_level(getuint(argv[1]));
ad02a0eb
SH
729}
730
11904a35
SH
731struct command {
732 int nargs;
733 int optargs;
734 const char *name;
735 int (*func) (int argc, char *const *argv);
736 const char *help;
ad02a0eb
SH
737};
738
739static const struct command commands[] = {
11904a35
SH
740 {0, 32, "showbridge", cmd_showbridge,
741 "[<bridge> ... ]\t\tshow bridge state"},
742 {1, 32, "showport", cmd_showport,
743 "<bridge> [<port> ... ]\tshow port state"},
744 {1, 32, "showportdetail", cmd_showportdetail,
745 "<bridge> [<port> ... ]\tshow port state (detail)"},
746 {2, 0, "rstp", cmd_rstp,
747 "<bridge> {on|off}\tenable/disable rstpd control"},
748 {2, 0, "setbridgestate", cmd_setbridgestate,
749 "<bridge> {on|off}\tstart/stop rstp (when enabled)"},
750 {2, 0, "setbridgeprio", cmd_setbridgeprio,
751 "<bridge> <priority>\tset bridge priority (0-61440)"},
752 {2, 0, "sethello", cmd_setbridgehello,
753 "<bridge> <hellotime>\tset bridge hello time (1-10)"},
754 {2, 0, "setmaxage", cmd_setbridgemaxage,
755 "<bridge> <maxage>\tset bridge max age (6-40)"},
756 {2, 0, "setfdelay", cmd_setbridgefdelay,
757 "<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
758 {2, 0, "setforcevers", cmd_setbridgeforcevers,
759 "<bridge> {normal|slow}\tnormal RSTP or force to STP"},
760 {3, 0, "setportprio", cmd_setportprio,
761 "<bridge> <port> <priority>\tset port priority (0-240)"},
762 {3, 0, "setportpathcost", cmd_setportpathcost,
763 "<bridge> <port> <cost>\tset port path cost"},
764 {3, 0, "setportedge", cmd_setportedge,
765 "<bridge> <port> {yes|no}\tconfigure if it is an edge port"},
766 {3, 0, "setportnonstp", cmd_setportnonstp,
767 "<bridge> <port> {yes|no}\tdisable STP for the port"},
768 {3, 0, "setportp2p", cmd_setportp2p,
769 "<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
770 {2, 0, "portmcheck", cmd_portmcheck,
771 "<bridge> <port>\ttry to get back from STP to RSTP mode"},
772 {1, 0, "debuglevel", cmd_debuglevel, "<level>\t\tLevel of verbosity"},
ad02a0eb
SH
773};
774
775const struct command *command_lookup(const char *cmd)
776{
777 int i;
778
11904a35 779 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ad02a0eb
SH
780 if (!strcmp(cmd, commands[i].name))
781 return &commands[i];
782 }
783
784 return NULL;
785}
786
787void command_helpall(void)
788{
789 int i;
790
11904a35 791 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ad02a0eb
SH
792 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
793 }
794}
795
796static void help()
797{
798 printf("Usage: rstpctl [commands]\n");
799 printf("commands:\n");
800 command_helpall();
801}
802
803#define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
804#define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
805
11904a35 806int main(int argc, char *const *argv)
ad02a0eb
SH
807{
808 const struct command *cmd;
809 int f;
810 static const struct option options[] = {
11904a35
SH
811 {.name = "help",.val = 'h'},
812 {.name = "version",.val = 'V'},
813 {0}
ad02a0eb
SH
814 };
815
11904a35
SH
816 while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
817 switch (f) {
ad02a0eb
SH
818 case 'h':
819 help();
820 return 0;
821 case 'V':
822 printf("%s\n", PACKAGE_VERSION(VERSION, BUILD));
823 return 0;
824 default:
825 fprintf(stderr, "Unknown option '%c'\n", f);
826 goto help;
827 }
11904a35 828
ad02a0eb
SH
829 if (argc == optind)
830 goto help;
11904a35 831
ad02a0eb
SH
832 if (ctl_client_init()) {
833 fprintf(stderr, "can't setup control connection\n");
834 return 1;
835 }
836
837 argc -= optind;
838 argv += optind;
839 if ((cmd = command_lookup(argv[0])) == NULL) {
840 fprintf(stderr, "never heard of command [%s]\n", argv[0]);
841 goto help;
842 }
11904a35 843
ad02a0eb
SH
844 if (argc < cmd->nargs + 1 || argc > cmd->nargs + cmd->optargs + 1) {
845 printf("Incorrect number of arguments for command\n");
846 printf("Usage: rstpctl %s %s\n", cmd->name, cmd->help);
847 return 1;
848 }
849
850 return cmd->func(argc, argv);
851
11904a35 852 help:
ad02a0eb
SH
853 help();
854 return 1;
855}