]> git.ipfire.org Git - people/ms/rstp.git/blame - ctl_main.c
reindent source
[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>
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
11904a35
SH
30static 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
44static 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
79static 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");
ad02a0eb
SH
88}
89
90int get_index_die(const char *ifname, const char *doc, int die)
91{
11904a35
SH
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;
ad02a0eb
SH
102}
103
104int get_index(const char *ifname, const char *doc)
105{
11904a35 106 return get_index_die(ifname, doc, 1);
ad02a0eb
SH
107}
108
11904a35 109static int cmd_rstp(int argc, char *const *argv)
ad02a0eb 110{
11904a35
SH
111 int stp, r;
112 int br_index = get_index(argv[1], "bridge");
ad02a0eb 113
11904a35
SH
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;
ad02a0eb
SH
131}
132
133static int do_showbridge(const char *br_name)
134{
11904a35
SH
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 }
ad02a0eb 148#if 0
11904a35
SH
149 printf("Interface: %-7s (tag:%d) State: ",
150 uid_state.vlan_name, (int)uid_state.vlan_id);
ad02a0eb 151#else
11904a35
SH
152 printf("Bridge: %-7s State:",
153 uid_state.vlan_name);
ad02a0eb 154#endif
11904a35
SH
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;
ad02a0eb
SH
204}
205
206#define SYSFS_PATH_MAX 256
207#define SYSFS_CLASS_NET "/sys/class/net"
208
209static int isbridge(const struct dirent *entry)
210{
11904a35
SH
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
219static 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;
ad02a0eb
SH
255}
256
257int detail = 0;
258
259static int do_showport(int br_index, const char *port_name,
11904a35
SH
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);
ad02a0eb 280#if 0
11904a35
SH
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);
ad02a0eb 284#else
11904a35
SH
285 printf(": PortId: %04lx in Bridge '%s':\n",
286 (unsigned long)uid_port.port_id, uid_state->vlan_name);
ad02a0eb 287#endif
11904a35
SH
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) {
ad02a0eb 365#if 0
11904a35
SH
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);
ad02a0eb 370#endif
11904a35
SH
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);
ad02a0eb 377#if 0
11904a35
SH
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);
ad02a0eb 384#endif
11904a35
SH
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;
ad02a0eb
SH
410}
411
412static int not_dot_dotdot(const struct dirent *entry)
413{
11904a35
SH
414 const char *n = entry->d_name;
415
416 return !(n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
ad02a0eb
SH
417}
418
11904a35 419static int cmd_showport(int argc, char *const *argv)
ad02a0eb 420{
11904a35
SH
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;
ad02a0eb
SH
470}
471
11904a35 472static int cmd_showportdetail(int argc, char *const *argv)
ad02a0eb 473{
11904a35
SH
474 detail = 1;
475 return cmd_showport(argc, argv);
ad02a0eb
SH
476}
477
11904a35 478unsigned int getuint(const char *s)
ad02a0eb 479{
11904a35
SH
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;
ad02a0eb
SH
488}
489
11904a35 490int getenum(const char *s, const char *opt[])
ad02a0eb 491{
11904a35
SH
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
504int 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
511static 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 }
ad02a0eb 551
11904a35 552 rc = CTL_set_bridge_config(br_index, &uid_cfg);
ad02a0eb 553
11904a35
SH
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;
ad02a0eb
SH
560}
561
11904a35 562static int cmd_setbridgestate(int argc, char *const *argv)
ad02a0eb
SH
563{
564
11904a35
SH
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);
ad02a0eb
SH
569}
570
11904a35 571static int cmd_setbridgeprio(int argc, char *const *argv)
ad02a0eb
SH
572{
573
11904a35
SH
574 int br_index = get_index(argv[1], "bridge");
575 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_PRIO);
ad02a0eb
SH
576}
577
11904a35 578static int cmd_setbridgemaxage(int argc, char *const *argv)
ad02a0eb
SH
579{
580
11904a35
SH
581 int br_index = get_index(argv[1], "bridge");
582 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_AGE);
ad02a0eb
SH
583}
584
11904a35 585static int cmd_setbridgehello(int argc, char *const *argv)
ad02a0eb
SH
586{
587
11904a35
SH
588 int br_index = get_index(argv[1], "bridge");
589 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_HELLO);
ad02a0eb
SH
590}
591
11904a35 592static int cmd_setbridgefdelay(int argc, char *const *argv)
ad02a0eb
SH
593{
594
11904a35
SH
595 int br_index = get_index(argv[1], "bridge");
596 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_DELAY);
ad02a0eb
SH
597}
598
11904a35 599static int cmd_setbridgeforcevers(int argc, char *const *argv)
ad02a0eb
SH
600{
601
11904a35
SH
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);
ad02a0eb
SH
606}
607
ad02a0eb 608static int
11904a35
SH
609set_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;
ad02a0eb 642#ifdef STP_DBG
11904a35
SH
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;
ad02a0eb 651#endif
11904a35
SH
652 case PT_CFG_STATE:
653 default:
654 printf("Invalid value mask 0X%lx\n", val_mask);
655 return -1;
656 }
ad02a0eb 657
11904a35 658 rc = CTL_set_port_config(br_index, port_index, &uid_cfg);
ad02a0eb 659
11904a35
SH
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;
ad02a0eb
SH
666}
667
11904a35 668static int cmd_setportprio(int argc, char *const *argv)
ad02a0eb
SH
669{
670
11904a35
SH
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);
ad02a0eb
SH
675}
676
11904a35 677static int cmd_setportpathcost(int argc, char *const *argv)
ad02a0eb
SH
678{
679
11904a35
SH
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);
ad02a0eb
SH
684}
685
11904a35 686static int cmd_setportedge(int argc, char *const *argv)
ad02a0eb
SH
687{
688
11904a35
SH
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);
ad02a0eb
SH
693}
694
11904a35 695static int cmd_setportnonstp(int argc, char *const *argv)
ad02a0eb
SH
696{
697
11904a35
SH
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);
ad02a0eb
SH
703}
704
11904a35 705static int cmd_setportp2p(int argc, char *const *argv)
ad02a0eb
SH
706{
707
11904a35
SH
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 };
ad02a0eb 712
11904a35
SH
713 return set_port_cfg_value(br_index, port_index,
714 vals[getenum(argv[3], opts)], PT_CFG_P2P);
ad02a0eb
SH
715}
716
11904a35 717static int cmd_portmcheck(int argc, char *const *argv)
ad02a0eb
SH
718{
719
11904a35
SH
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);
ad02a0eb
SH
723}
724
11904a35 725static int cmd_debuglevel(int argc, char *const *argv)
ad02a0eb 726{
11904a35 727 return CTL_set_debug_level(getuint(argv[1]));
ad02a0eb
SH
728}
729
11904a35
SH
730struct command {
731 int nargs;
732 int optargs;
733 const char *name;
734 int (*func) (int argc, char *const *argv);
735 const char *help;
ad02a0eb
SH
736};
737
738static const struct command commands[] = {
11904a35
SH
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"},
ad02a0eb
SH
772};
773
774const struct command *command_lookup(const char *cmd)
775{
776 int i;
777
11904a35 778 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ad02a0eb
SH
779 if (!strcmp(cmd, commands[i].name))
780 return &commands[i];
781 }
782
783 return NULL;
784}
785
786void command_helpall(void)
787{
788 int i;
789
11904a35 790 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
ad02a0eb
SH
791 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
792 }
793}
794
795static 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
11904a35 805int main(int argc, char *const *argv)
ad02a0eb
SH
806{
807 const struct command *cmd;
808 int f;
809 static const struct option options[] = {
11904a35
SH
810 {.name = "help",.val = 'h'},
811 {.name = "version",.val = 'V'},
812 {0}
ad02a0eb
SH
813 };
814
11904a35
SH
815 while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
816 switch (f) {
ad02a0eb
SH
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 }
11904a35 827
ad02a0eb
SH
828 if (argc == optind)
829 goto help;
11904a35 830
ad02a0eb
SH
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 }
11904a35 842
ad02a0eb
SH
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
11904a35 851 help:
ad02a0eb
SH
852 help();
853 return 1;
854}