]> git.ipfire.org Git - people/ms/rstp.git/blob - ctl_main.c
RSTP testing - PATCH: source MAC address of BPDU
[people/ms/rstp.git] / ctl_main.c
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>
19
20 #include "ctl_socket_client.h"
21 #include "ctl_functions.h"
22
23 #ifndef False
24 # define False 0
25 # define True 1
26 #endif
27
28 #define STP_IN_get_error_explanation CTL_error_explanation
29
30 static void print_bridge_id(UID_BRIDGE_ID_T * bridge_id, unsigned char cr)
31 {
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]);
40 if (cr)
41 printf("\n");
42 }
43
44 static char *stp_state2str(RSTP_PORT_STATE stp_port_state, int detail)
45 {
46 if (detail) {
47 switch (stp_port_state) {
48 case UID_PORT_DISABLED:
49 return "Disabled";
50 case UID_PORT_DISCARDING:
51 return "Discarding";
52 case UID_PORT_LEARNING:
53 return "Learning";
54 case UID_PORT_FORWARDING:
55 return "Forwarding";
56 case UID_PORT_NON_STP:
57 return "NoStp";
58 default:
59 return "Unknown";
60 }
61 }
62
63 switch (stp_port_state) {
64 case UID_PORT_DISABLED:
65 return "Dis";
66 case UID_PORT_DISCARDING:
67 return "Blk";
68 case UID_PORT_LEARNING:
69 return "Lrn";
70 case UID_PORT_FORWARDING:
71 return "Fwd";
72 case UID_PORT_NON_STP:
73 return "Non";
74 default:
75 return "Unk";
76 }
77 }
78
79 static void CLI_out_port_id(int port, unsigned char cr)
80 {
81 static char ifname[IFNAMSIZ];
82 if (if_indextoname(port, ifname))
83 printf("%s", ifname);
84 else
85 printf("Ifindex %02d", port);
86 if (cr)
87 printf("\n");
88 }
89
90 int get_index_die(const char *ifname, const char *doc, int die)
91 {
92 int r = if_nametoindex(ifname);
93 if (r == 0) {
94 fprintf(stderr,
95 "Can't find index for %s %s. Not a valid interface.\n",
96 doc, ifname);
97 if (die)
98 exit(1);
99 return -1;
100 }
101 return r;
102 }
103
104 int get_index(const char *ifname, const char *doc)
105 {
106 return get_index_die(ifname, doc, 1);
107 }
108
109 static int cmd_rstp(int argc, char *const *argv)
110 {
111 int stp, r;
112 int br_index = get_index(argv[1], "bridge");
113
114 if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
115 || !strcmp(argv[2], "1"))
116 stp = 1;
117 else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no")
118 || !strcmp(argv[2], "0"))
119 stp = 0;
120 else {
121 fprintf(stderr, "expect on/off for argument\n");
122 return 1;
123 }
124 r = CTL_enable_bridge_rstp(br_index, stp);
125 if (r) {
126 fprintf(stderr, "Failed to enable/disable RSTP: %s\n",
127 CTL_error_explanation(r));
128 return -1;
129 }
130 return 0;
131 }
132
133 static int do_showbridge(const char *br_name)
134 {
135 UID_STP_STATE_T uid_state;
136 UID_STP_CFG_T uid_cfg;
137
138 int br_index = get_index_die(br_name, "bridge", 0);
139 if (br_index < 0)
140 return -1;
141
142 int r = CTL_get_bridge_state(br_index, &uid_cfg, &uid_state);
143 if (r) {
144 fprintf(stderr, "Failed to get bridge state: %s\n",
145 CTL_error_explanation(r));
146 return -1;
147 }
148 #if 0
149 printf("Interface: %-7s (tag:%d) State: ",
150 uid_state.vlan_name, (int)uid_state.vlan_id);
151 #else
152 printf("Bridge: %-7s State:",
153 uid_state.vlan_name);
154 #endif
155 switch (uid_state.stp_enabled) {
156 case STP_ENABLED:
157 printf("enabled\n");
158 break;
159 case STP_DISABLED:
160 printf("disabled\n");
161 break;
162 default:
163 printf("unknown\n");
164 return 0;
165 }
166
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");
174
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);
184 } else {
185 printf("Root Port: none\n");
186 }
187
188 if (uid_state.Topo_Change)
189 printf("Topology Change Count: %lu\n",
190 uid_state.Topo_Change_Count);
191 else
192 printf("Time Since Topology Change: %lu\n",
193 uid_state.timeSince_Topo_Change);
194
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);
202
203 return 0;
204 }
205
206 #define SYSFS_PATH_MAX 256
207 #define SYSFS_CLASS_NET "/sys/class/net"
208
209 static int isbridge(const struct dirent *entry)
210 {
211 char path[SYSFS_PATH_MAX];
212 struct stat st;
213
214 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "/%s/bridge",
215 entry->d_name);
216 return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
217 }
218
219 static int cmd_showbridge(int argc, char *const *argv)
220 {
221 int i, count = 0;
222 int r = 0;
223 struct dirent **namelist;
224
225 if (argc > 1) {
226 count = argc - 1;
227 } else {
228 count =
229 scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
230 if (count < 0) {
231 fprintf(stderr, "Error getting list of all bridges\n");
232 return -1;
233 }
234 }
235
236 for (i = 0; i < count; i++) {
237 const char *name;
238 if (argc > 1)
239 name = argv[i + 1];
240 else
241 name = namelist[i]->d_name;
242
243 int err = do_showbridge(name);
244 if (err)
245 r = err;
246 }
247
248 if (argc <= 1) {
249 for (i = 0; i < count; i++)
250 free(namelist[i]);
251 free(namelist);
252 }
253
254 return r;
255 }
256
257 int detail = 0;
258
259 static int do_showport(int br_index, const char *port_name,
260 UID_STP_STATE_T * uid_state)
261 {
262 UID_STP_PORT_STATE_T uid_port;
263 UID_STP_PORT_CFG_T uid_cfg;
264 int r = 0;
265 int port_index = get_index_die(port_name, "port", 0);
266 if (port_index < 0)
267 return -1;
268
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);
271 if (r) {
272 fprintf(stderr, "Failed to get port state for port %d: %s\n",
273 port_index, CTL_error_explanation(r));
274 return -1;
275 }
276
277 if (detail) {
278 printf("Stp Port ");
279 CLI_out_port_id(port_index, False);
280 #if 0
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);
284 #else
285 printf(": PortId: %04lx in Bridge '%s':\n",
286 (unsigned long)uid_port.port_id, uid_state->vlan_name);
287 #endif
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");
296 else
297 printf("%-9lu", uid_cfg.admin_port_path_cost);
298 printf(" oper: %-9lu\n", uid_port.oper_port_path_cost);
299
300 printf("Point2Point: admin: ");
301 switch (uid_cfg.admin_point2point) {
302 case P2P_FORCE_TRUE:
303 printf("%-9s", "ForceYes");
304 break;
305 case P2P_FORCE_FALSE:
306 printf("%-9s", "ForceNo");
307 break;
308 case P2P_AUTO:
309 printf("%-9s", "Auto");
310 break;
311 }
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");
319
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);
332 }
333 printf("Role: ");
334 switch (uid_port.role) {
335 case 'A':
336 printf("Alternate\n");
337 break;
338 case 'B':
339 printf("Backup\n");
340 break;
341 case 'R':
342 printf("Root\n");
343 break;
344 case 'D':
345 printf("Designated\n");
346 break;
347 case '-':
348 printf("NonStp\n");
349 break;
350 default:
351 printf("Unknown(%c)\n", uid_port.role);
352 break;
353 }
354
355 if ('R' == uid_port.role || 'D' == uid_port.role) {
356 /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */
357 printf("TcAck: %c ",
358 uid_port.top_change_ack ? 'Y' : 'N');
359 printf("TcWhile: %3d\n",
360 (int)uid_port.tcWhile);
361 }
362 }
363
364 if (UID_PORT_DISABLED == uid_port.state || '-' == uid_port.role) {
365 #if 0
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);
370 #endif
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);
377 #if 0
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);
384 #endif
385 }
386
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);
393 } else {
394 printf("%c%c%c ",
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));
401 printf(" ");
402 print_bridge_id(&uid_port.designated_root, 0);
403 printf(" ");
404 print_bridge_id(&uid_port.designated_bridge, 0);
405 printf(" %4lx %c", (unsigned long)uid_port.designated_port,
406 uid_port.role);
407 printf("\n");
408 }
409 return 0;
410 }
411
412 static int not_dot_dotdot(const struct dirent *entry)
413 {
414 const char *n = entry->d_name;
415
416 return !(n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
417 }
418
419 static int cmd_showport(int argc, char *const *argv)
420 {
421 UID_STP_STATE_T uid_state;
422 UID_STP_CFG_T uid_br_cfg;
423 int r = 0;
424
425 int br_index = get_index(argv[1], "bridge");
426
427 r = CTL_get_bridge_state(br_index, &uid_br_cfg, &uid_state);
428 if (r) {
429 fprintf(stderr, "Failed to get bridge state: %s\n",
430 CTL_error_explanation(r));
431 return -1;
432 }
433
434 int i, count = 0;
435 struct dirent **namelist;
436
437 if (argc > 2) {
438 count = argc - 2;
439 } else {
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);
443 if (count < 0) {
444 fprintf(stderr,
445 "Error getting list of all ports of bridge %s\n",
446 argv[1]);
447 return -1;
448 }
449 }
450
451 for (i = 0; i < count; i++) {
452 const char *name;
453 if (argc > 2)
454 name = argv[i + 2];
455 else
456 name = namelist[i]->d_name;
457
458 int err = do_showport(br_index, name, &uid_state);
459 if (err)
460 r = err;
461 }
462
463 if (argc <= 2) {
464 for (i = 0; i < count; i++)
465 free(namelist[i]);
466 free(namelist);
467 }
468
469 return r;
470 }
471
472 static int cmd_showportdetail(int argc, char *const *argv)
473 {
474 detail = 1;
475 return cmd_showport(argc, argv);
476 }
477
478 unsigned int getuint(const char *s)
479 {
480 char *end;
481 long l;
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);
485 exit(1);
486 }
487 return l;
488 }
489
490 int getenum(const char *s, const char *opt[])
491 {
492 int i;
493 for (i = 0; opt[i] != NULL; i++)
494 if (strcmp(s, opt[i]) == 0)
495 return i;
496
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"));
500
501 exit(1);
502 }
503
504 int getyesno(const char *s, const char *yes, const char *no)
505 {
506 /* Reverse yes and no so error message looks more normal */
507 const char *opt[] = { yes, no, NULL };
508 return 1 - getenum(s, opt);
509 }
510
511 static int set_bridge_cfg_value(int br_index, unsigned long value,
512 unsigned long val_mask)
513 {
514 UID_STP_CFG_T uid_cfg;
515 char *val_name;
516 int rc;
517
518 uid_cfg.field_mask = val_mask;
519 switch (val_mask) {
520 case BR_CFG_STATE:
521 uid_cfg.stp_enabled = value;
522 val_name = "state";
523 break;
524 case BR_CFG_PRIO:
525 uid_cfg.bridge_priority = value;
526 val_name = "priority";
527 break;
528 case BR_CFG_AGE:
529 uid_cfg.max_age = value;
530 val_name = "max_age";
531 break;
532 case BR_CFG_HELLO:
533 uid_cfg.hello_time = value;
534 val_name = "hello_time";
535 break;
536 case BR_CFG_DELAY:
537 uid_cfg.forward_delay = value;
538 val_name = "forward_delay";
539 break;
540 case BR_CFG_FORCE_VER:
541 uid_cfg.force_version = value;
542 val_name = "force_version";
543 break;
544 case BR_CFG_AGE_MODE:
545 case BR_CFG_AGE_TIME:
546 default:
547 printf("Invalid value mask 0X%lx\n", val_mask);
548 return -1;
549 break;
550 }
551
552 rc = CTL_set_bridge_config(br_index, &uid_cfg);
553
554 if (0 != rc) {
555 printf("Can't change rstp bridge %s:%s\n", val_name,
556 STP_IN_get_error_explanation(rc));
557 return -1;
558 }
559 return 0;
560 }
561
562 static int cmd_setbridgestate(int argc, char *const *argv)
563 {
564
565 int br_index = get_index(argv[1], "bridge");
566 return set_bridge_cfg_value(br_index,
567 getyesno(argv[2], "on", "off"),
568 BR_CFG_STATE);
569 }
570
571 static int cmd_setbridgeprio(int argc, char *const *argv)
572 {
573
574 int br_index = get_index(argv[1], "bridge");
575 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_PRIO);
576 }
577
578 static int cmd_setbridgemaxage(int argc, char *const *argv)
579 {
580
581 int br_index = get_index(argv[1], "bridge");
582 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_AGE);
583 }
584
585 static int cmd_setbridgehello(int argc, char *const *argv)
586 {
587
588 int br_index = get_index(argv[1], "bridge");
589 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_HELLO);
590 }
591
592 static int cmd_setbridgefdelay(int argc, char *const *argv)
593 {
594
595 int br_index = get_index(argv[1], "bridge");
596 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_DELAY);
597 }
598
599 static int cmd_setbridgeforcevers(int argc, char *const *argv)
600 {
601
602 int br_index = get_index(argv[1], "bridge");
603 return set_bridge_cfg_value(br_index,
604 2 * getyesno(argv[2], "normal", "slow"),
605 BR_CFG_FORCE_VER);
606 }
607
608 static int
609 set_port_cfg_value(int br_index, int port_index,
610 unsigned long value, unsigned long val_mask)
611 {
612 UID_STP_PORT_CFG_T uid_cfg;
613 int rc;
614 char *val_name;
615
616 BitmapClear(&uid_cfg.port_bmp);
617 uid_cfg.field_mask = val_mask;
618 switch (val_mask) {
619 case PT_CFG_MCHECK:
620 val_name = "mcheck";
621 break;
622 case PT_CFG_COST:
623 uid_cfg.admin_port_path_cost = value;
624 val_name = "path cost";
625 break;
626 case PT_CFG_PRIO:
627 uid_cfg.port_priority = value;
628 val_name = "priority";
629 break;
630 case PT_CFG_P2P:
631 uid_cfg.admin_point2point = (ADMIN_P2P_T) value;
632 val_name = "p2p flag";
633 break;
634 case PT_CFG_EDGE:
635 uid_cfg.admin_edge = value;
636 val_name = "adminEdge";
637 break;
638 case PT_CFG_NON_STP:
639 uid_cfg.admin_non_stp = value;
640 val_name = "adminNonStp";
641 break;
642 #ifdef STP_DBG
643 case PT_CFG_DBG_SKIP_TX:
644 uid_cfg.skip_tx = value;
645 val_name = "skip tx";
646 break;
647 case PT_CFG_DBG_SKIP_RX:
648 uid_cfg.skip_rx = value;
649 val_name = "skip rx";
650 break;
651 #endif
652 case PT_CFG_STATE:
653 default:
654 printf("Invalid value mask 0X%lx\n", val_mask);
655 return -1;
656 }
657
658 rc = CTL_set_port_config(br_index, port_index, &uid_cfg);
659
660 if (0 != rc) {
661 printf("can't change rstp port[s] %s: %s\n",
662 val_name, STP_IN_get_error_explanation(rc));
663 return -1;
664 }
665 return 0;
666 }
667
668 static int cmd_setportprio(int argc, char *const *argv)
669 {
670
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);
675 }
676
677 static int cmd_setportpathcost(int argc, char *const *argv)
678 {
679
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);
684 }
685
686 static int cmd_setportedge(int argc, char *const *argv)
687 {
688
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);
693 }
694
695 static int cmd_setportnonstp(int argc, char *const *argv)
696 {
697
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"),
702 PT_CFG_NON_STP);
703 }
704
705 static int cmd_setportp2p(int argc, char *const *argv)
706 {
707
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 };
712
713 return set_port_cfg_value(br_index, port_index,
714 vals[getenum(argv[3], opts)], PT_CFG_P2P);
715 }
716
717 static int cmd_portmcheck(int argc, char *const *argv)
718 {
719
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);
723 }
724
725 static int cmd_debuglevel(int argc, char *const *argv)
726 {
727 return CTL_set_debug_level(getuint(argv[1]));
728 }
729
730 struct command {
731 int nargs;
732 int optargs;
733 const char *name;
734 int (*func) (int argc, char *const *argv);
735 const char *help;
736 };
737
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"},
772 };
773
774 const struct command *command_lookup(const char *cmd)
775 {
776 int i;
777
778 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
779 if (!strcmp(cmd, commands[i].name))
780 return &commands[i];
781 }
782
783 return NULL;
784 }
785
786 void command_helpall(void)
787 {
788 int i;
789
790 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
791 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
792 }
793 }
794
795 static void help()
796 {
797 printf("Usage: rstpctl [commands]\n");
798 printf("commands:\n");
799 command_helpall();
800 }
801
802 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
803 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
804
805 int main(int argc, char *const *argv)
806 {
807 const struct command *cmd;
808 int f;
809 static const struct option options[] = {
810 {.name = "help",.val = 'h'},
811 {.name = "version",.val = 'V'},
812 {0}
813 };
814
815 while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
816 switch (f) {
817 case 'h':
818 help();
819 return 0;
820 case 'V':
821 printf("%s\n", PACKAGE_VERSION(VERSION, BUILD));
822 return 0;
823 default:
824 fprintf(stderr, "Unknown option '%c'\n", f);
825 goto help;
826 }
827
828 if (argc == optind)
829 goto help;
830
831 if (ctl_client_init()) {
832 fprintf(stderr, "can't setup control connection\n");
833 return 1;
834 }
835
836 argc -= optind;
837 argv += optind;
838 if ((cmd = command_lookup(argv[0])) == NULL) {
839 fprintf(stderr, "never heard of command [%s]\n", argv[0]);
840 goto help;
841 }
842
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);
846 return 1;
847 }
848
849 return cmd->func(argc, argv);
850
851 help:
852 help();
853 return 1;
854 }