]> git.ipfire.org Git - people/ms/mstpd.git/blame - ctl_main.c
Initial import
[people/ms/mstpd.git] / ctl_main.c
CommitLineData
1e6d2d09
VD
1/*****************************************************************************
2 Copyright (c) 2011 Factor-SPE
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 59
16 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 The full GNU General Public License is included in this distribution in the
19 file called LICENSE.
20
21 Authors: Vitalii Demianets <vitas@nppfactor.kiev.ua>
22
23******************************************************************************/
24
25#include <string.h>
26#include <getopt.h>
27#include <dirent.h>
28#include <errno.h>
29#include <limits.h>
30#include <sys/stat.h>
31
32#include "ctl_socket_client.h"
33#include "log.h"
34
35static int get_index_die(const char *ifname, const char *doc, bool die)
36{
37 int r = if_nametoindex(ifname);
38 if(0 == r)
39 {
40 fprintf(stderr,
41 "Can't find index for %s %s. Not a valid interface.\n",
42 doc, ifname);
43 if(die)
44 exit(1);
45 return -1;
46 }
47 return r;
48}
49
50static inline int get_index(const char *ifname, const char *doc)
51{
52 return get_index_die(ifname, doc, true);
53}
54
55static inline int get_id(const char *str, const char *doc, unsigned int max_id)
56{
57 int id = strtol(str, NULL, 10);
58 if((0 > id) || (max_id < id)
59 || ((0 == id) && ('0' != str[0]))
60 )
61 {
62 fprintf(stderr, "Bad %s %s\n", doc, str);
63 return -1;
64 }
65 return id;
66}
67
68#define GET_NUM_FROM_PRIO(p) (__be16_to_cpu(p) & 0x0FFF)
69
70#define BR_ID_FMT "%01hhX.%03hX.%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX"
71#define BR_ID_ARGS(x) ((GET_PRIORITY_FROM_IDENTIFIER(x) >> 4) & 0x0F), \
72 GET_NUM_FROM_PRIO((x).s.priority), \
73 x.s.mac_address[0], x.s.mac_address[1], x.s.mac_address[2], \
74 x.s.mac_address[3], x.s.mac_address[4], x.s.mac_address[5]
75
76#define PRT_ID_FMT "%01hhX.%03hX"
77#define PRT_ID_ARGS(x) ((GET_PRIORITY_FROM_IDENTIFIER(x) >> 4) & 0x0F), \
78 GET_NUM_FROM_PRIO(x)
79
80#define BOOL_STR(x) ((x) ? "yes" : "no")
81
82static int do_showbridge(const char *br_name)
83{
84 CIST_BridgeStatus s;
85 char root_port_name[IFNAMSIZ];
86 unsigned int root_portno;
87 int br_index = get_index_die(br_name, "bridge", false);
88 if(0 > br_index)
89 return br_index;
90
91 if(CTL_get_cist_bridge_status(br_index, &s, root_port_name))
92 return -1;
93 printf("%s CIST info\n", br_name);
94 printf(" enabled %s\n", BOOL_STR(s.enabled));
95 printf(" bridge id "BR_ID_FMT"\n", BR_ID_ARGS(s.bridge_id));
96 printf(" designated root "BR_ID_FMT"\n", BR_ID_ARGS(s.designated_root));
97 printf(" regional root "BR_ID_FMT"\n", BR_ID_ARGS(s.regional_root));
98 printf(" root port ");
99 if(0 != (root_portno = GET_NUM_FROM_PRIO(s.root_port_id)))
100 printf("%s (#%u)\n", root_port_name, root_portno);
101 else
102 printf("none\n");
103 printf(" path cost %-10u ", s.root_path_cost);
104 printf("internal path cost %u\n", s.internal_path_cost);
105 printf(" max age %-10u ", s.root_max_age);
106 printf("bridge max age %u\n", s.bridge_max_age);
107 printf(" forward delay %-10u ", s.root_forward_delay);
108 printf("bridge forward delay %u\n", s.bridge_forward_delay);
109 printf(" tx hold count %-10u ", s.tx_hold_count);
110 printf("max hops %hhu\n", s.max_hops);
111 printf(" force protocol version %u\n", s.protocol_version);
112 printf(" time since topology change %u\n", s.time_since_topology_change);
113 printf(" toplogy change count %u\n", s.topology_change_count);
114 printf(" topology change %s\n", BOOL_STR(s.topology_change));
115
116 return 0;
117}
118
119#define SYSFS_PATH_MAX 256
120#define SYSFS_CLASS_NET "/sys/class/net"
121
122static int isbridge(const struct dirent *entry)
123{
124 char path[SYSFS_PATH_MAX];
125 int save_errno;
126 bool result;
127 struct stat st;
128
129 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "/%s/bridge",
130 entry->d_name);
131 save_errno = errno;
132 result = (0 == stat(path, &st)) && S_ISDIR(st.st_mode);
133 errno = save_errno;
134 return result;
135}
136
137static int cmd_showbridge(int argc, char *const *argv)
138{
139 int i, count = 0;
140 int r = 0;
141 struct dirent **namelist;
142
143 if(1 < argc)
144 {
145 count = argc - 1;
146 }
147 else
148 {
149 /* TODO: use versionsort, if available */
150 count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
151 if(0 > count)
152 {
153 fprintf(stderr, "Error getting list of all bridges\n");
154 return -1;
155 }
156 }
157
158 for(i = 0; i < count; ++i)
159 {
160 const char *name;
161 if(1 < argc)
162 name = argv[i + 1];
163 else
164 name = namelist[i]->d_name;
165
166 int err = do_showbridge(name);
167 if(err)
168 r = err;
169 }
170
171 if(1 >= argc)
172 {
173 for(i = 0; i < count; ++i)
174 free(namelist[i]);
175 free(namelist);
176 }
177
178 return r;
179}
180
181static int cmd_showtree(int argc, char *const *argv)
182{
183 MSTI_BridgeStatus s;
184 char root_port_name[IFNAMSIZ];
185 unsigned int root_portno;
186 int br_index = get_index(argv[1], "bridge");
187 if(0 > br_index)
188 return br_index;
189 int mstid = get_id(argv[2], "mstid", MAX_MSTID);
190 if(0 > mstid)
191 return mstid;
192
193 if(CTL_get_msti_bridge_status(br_index, mstid, &s, root_port_name))
194 return -1;
195
196 printf("%s MSTI %hu info\n", argv[1], mstid);
197 printf(" bridge id "BR_ID_FMT"\n", BR_ID_ARGS(s.bridge_id));
198 printf(" regional root "BR_ID_FMT"\n", BR_ID_ARGS(s.regional_root));
199 printf(" root port ");
200 if(0 != (root_portno = GET_NUM_FROM_PRIO(s.root_port_id)))
201 printf("%s (#%u)\n", root_port_name, root_portno);
202 else
203 printf("none\n");
204 printf(" internal path cost %u\n", s.internal_path_cost);
205 printf(" time since topology change %u\n", s.time_since_topology_change);
206 printf(" toplogy change count %u\n", s.topology_change_count);
207 printf(" topology change %s\n", BOOL_STR(s.topology_change));
208
209 return 0;
210}
211
212#define STATE_STR(_state) \
213 ({ \
214 int _s = _state; \
215 char *_str = "unknown"; \
216 switch(_s) \
217 { \
218 case BR_STATE_DISABLED: \
219 case BR_STATE_BLOCKING: \
220 case BR_STATE_LISTENING: _str = "discarding"; break; \
221 case BR_STATE_LEARNING: _str = "learning"; break; \
222 case BR_STATE_FORWARDING:_str = "forwarding"; break; \
223 } \
224 _str; \
225 })
226
227#define SHORT_STATE_STR(_state) \
228 ({ \
229 int _s = _state; \
230 char *_str = "unkn"; \
231 switch(_s) \
232 { \
233 case BR_STATE_DISABLED: \
234 case BR_STATE_BLOCKING: \
235 case BR_STATE_LISTENING: _str = "disc"; break; \
236 case BR_STATE_LEARNING: _str = "lear"; break; \
237 case BR_STATE_FORWARDING:_str = "forw"; break; \
238 } \
239 _str; \
240 })
241
242#define ADMIN_P2P_STR(_state) \
243 ({ \
244 admin_p2p_t _s = _state; \
245 char *_str = "unkn"; \
246 switch(_s) \
247 { \
248 case p2pForceFalse:_str = "no"; break; \
249 case p2pForceTrue: _str = "yes"; break; \
250 case p2pAuto: _str = "auto"; break; \
251 } \
252 _str; \
253 })
254
255#define ROLE_STR(_role) \
256 ({ \
257 port_role_t _r = _role; \
258 char *_str = "Unknown"; \
259 switch(_r) \
260 { \
261 case roleRoot: _str = "Root"; break; \
262 case roleDesignated:_str = "Designated"; break; \
263 case roleAlternate: _str = "Alternate"; break; \
264 case roleBackup: _str = "Backup"; break; \
265 case roleMaster: _str = "Master"; break; \
266 case roleDisabled: _str = "Disabled"; break; \
267 } \
268 _str; \
269 })
270
271#define SHORT_ROLE_STR(_role) \
272 ({ \
273 port_role_t _r = _role; \
274 char *_str = "Unkn"; \
275 switch(_r) \
276 { \
277 case roleRoot: _str = "Root"; break; \
278 case roleDesignated:_str = "Desg"; break; \
279 case roleAlternate: _str = "Altn"; break; \
280 case roleBackup: _str = "Back"; break; \
281 case roleMaster: _str = "Mstr"; break; \
282 case roleDisabled: _str = "Disa"; break; \
283 } \
284 _str; \
285 })
286
287
288static int detail = 0;
289
290static int do_showport(int br_index, const char *bridge_name,
291 const char *port_name)
292{
293 CIST_PortStatus s;
294 int r = 0;
295 int port_index = get_index_die(port_name, "port", false);
296 if(0 > port_index)
297 return port_index;
298
299 if((r = CTL_get_cist_port_status(br_index, port_index, &s)))
300 {
301 fprintf(stderr, "%s:%s Failed to get port state\n",
302 bridge_name, port_name);
303 return -1;
304 }
305
306 if(detail)
307 {
308 printf("%s:%s CIST info\n", bridge_name, port_name);
309 printf(" enabled %-23s ", BOOL_STR(s.enabled));
310 printf("role %s\n", ROLE_STR(s.role));
311 printf(" port id "PRT_ID_FMT" ",
312 PRT_ID_ARGS(s.port_id));
313 printf("state %s\n", STATE_STR(s.state));
314 printf(" external port cost %-23u ", s.external_port_path_cost);
315 printf("admin external cost %u\n", s.admin_external_port_path_cost);
316 printf(" internal port cost %-23u ", s.internal_port_path_cost);
317 printf("admin internal cost %u\n", s.admin_internal_port_path_cost);
318 printf(" designated root "BR_ID_FMT" ",
319 BR_ID_ARGS(s.designated_root));
320 printf("dsgn external cost %u\n", s.designated_external_cost);
321 printf(" dsgn regional root "BR_ID_FMT" ",
322 BR_ID_ARGS(s.designated_regional_root));
323 printf("dsgn internal cost %u\n", s.designated_internal_cost);
324 printf(" designated bridge "BR_ID_FMT" ",
325 BR_ID_ARGS(s.designated_bridge));
326 printf("designated port "PRT_ID_FMT"\n",
327 PRT_ID_ARGS(s.designated_port));
328 printf(" admin edge port %-23s ", BOOL_STR(s.admin_edge_port));
329 printf("auto edge port %s\n", BOOL_STR(s.auto_edge_port));
330 printf(" oper edge port %-23s ", BOOL_STR(s.oper_edge_port));
331 printf("toplogy change ack %s\n", BOOL_STR(s.tc_ack));
332 printf(" point-to-point %-23s ", BOOL_STR(s.oper_p2p));
333 printf("admin point-to-point %s\n", ADMIN_P2P_STR(s.admin_p2p));
334 printf(" restricted role %-23s ", BOOL_STR(s.restricted_role));
335 printf("restricted TCN %s\n", BOOL_STR(s.restricted_tcn));
336 printf(" port hello time %-23u ", s.port_hello_time);
337 printf("disputed %s\n", BOOL_STR(s.disputed));
338 }
339 else
340 {
341 printf("%c%c %-5s "PRT_ID_FMT" %4s "BR_ID_FMT" "BR_ID_FMT" "PRT_ID_FMT" %s\n",
342 (s.oper_p2p) ? ' ' : '*',
343 (s.oper_edge_port) ? 'E' : ' ',
344 port_name,
345 PRT_ID_ARGS(s.port_id),
346 s.enabled ? SHORT_STATE_STR(s.state) : "down",
347 BR_ID_ARGS(s.designated_root),
348 BR_ID_ARGS(s.designated_bridge),
349 PRT_ID_ARGS(s.designated_port),
350 SHORT_ROLE_STR(s.role));
351 }
352 return 0;
353}
354
355static int not_dot_dotdot(const struct dirent *entry)
356{
357 const char *n = entry->d_name;
358
359 return !('.' == n[0] && (0 == n[1] || ('.' == n[1] && 0 == n[2])));
360}
361
362static int cmd_showport(int argc, char *const *argv)
363{
364 int r = 0;
365
366 int br_index = get_index(argv[1], "bridge");
367 if(0 > br_index)
368 return br_index;
369
370 int i, count = 0;
371 struct dirent **namelist;
372
373 if(2 < argc)
374 {
375 count = argc - 2;
376 }
377 else
378 {
379 char buf[SYSFS_PATH_MAX];
380 snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
381 /* TODO: use versionsort, if available */
382 count = scandir(buf, &namelist, not_dot_dotdot, alphasort);
383 if(0 > count)
384 {
385 fprintf(stderr, "Error getting list of all ports of bridge %s\n",
386 argv[1]);
387 return -1;
388 }
389 }
390
391 for(i = 0; i < count; ++i)
392 {
393 const char *name;
394 if(2 < argc)
395 name = argv[i + 2];
396 else
397 name = namelist[i]->d_name;
398
399 int err = do_showport(br_index, argv[1], name);
400 if(err)
401 r = err;
402 }
403
404 if(2 >= argc)
405 {
406 for(i = 0; i < count; ++i)
407 free(namelist[i]);
408 free(namelist);
409 }
410
411 return r;
412}
413
414static int cmd_showportdetail(int argc, char *const *argv)
415{
416 detail = 1;
417 return cmd_showport(argc, argv);
418}
419
420static int cmd_showtreeport(int argc, char *const *argv)
421{
422 MSTI_PortStatus s;
423 int br_index = get_index(argv[1], "bridge");
424 if(0 > br_index)
425 return br_index;
426 int port_index = get_index(argv[2], "port");
427 if(0 > port_index)
428 return port_index;
429 int mstid = get_id(argv[3], "mstid", MAX_MSTID);
430 if(0 > mstid)
431 return mstid;
432
433 if(CTL_get_msti_port_status(br_index, port_index, mstid, &s))
434 return -1;
435
436 printf("%s:%s MSTI %hu info\n", argv[1], argv[2], mstid);
437 printf(" role %-23s ", ROLE_STR(s.role));
438 printf("port id "PRT_ID_FMT"\n", PRT_ID_ARGS(s.port_id));
439 printf(" state %-23s ", STATE_STR(s.state));
440 printf("disputed %s\n", BOOL_STR(s.disputed));
441 printf(" internal port cost %-23u ", s.internal_port_path_cost);
442 printf("admin internal cost %u\n", s.admin_internal_port_path_cost);
443 printf(" dsgn regional root "BR_ID_FMT" ",
444 BR_ID_ARGS(s.designated_regional_root));
445 printf("dsgn internal cost %u\n", s.designated_internal_cost);
446 printf(" designated bridge "BR_ID_FMT" ",
447 BR_ID_ARGS(s.designated_bridge));
448 printf("designated port "PRT_ID_FMT"\n",
449 PRT_ID_ARGS(s.designated_port));
450
451 return 0;
452}
453
454static unsigned int getuint(const char *s)
455{
456 char *end;
457 long l;
458 l = strtoul(s, &end, 0);
459 if(0 == *s || 0 != *end || INT_MAX < l)
460 {
461 fprintf(stderr, "Invalid unsigned int arg %s\n", s);
462 exit(1);
463 }
464 return l;
465}
466
467static int getenum(const char *s, const char *opt[])
468{
469 int i;
470 for(i = 0; opt[i] != NULL; ++i)
471 if(0 == strcmp(s, opt[i]))
472 return i;
473
474 fprintf(stderr, "Invalid argument %s: expecting one of ", s);
475 for(i = 0; opt[i] != NULL; ++i)
476 fprintf(stderr, "%s%s", opt[i], (opt[i + 1] ? ", " : "\n"));
477
478 exit(1);
479}
480
481static int getyesno(const char *s, const char *yes, const char *no)
482{
483 /* Reverse yes and no so error message looks more normal */
484 const char *opt[] = { yes, no, NULL };
485 return 1 - getenum(s, opt);
486}
487
488static int cmd_setmstconfid(int argc, char *const *argv)
489{
490 int br_index = get_index(argv[1], "bridge");
491 if(0 > br_index)
492 return br_index;
493 unsigned int revision = getuint(argv[2]);
494 if(revision > 0xFFFF)
495 {
496 fprintf(stderr, "Bad revision %s\n", argv[2]);
497 return -1;
498 }
499 return CTL_set_mstconfid(br_index, revision, argv[3]);
500}
501
502#define set_bridge_cfg(field, value) \
503 ({ \
504 CIST_BridgeConfig c; \
505 memset(&c, 0, sizeof(c)); \
506 c.field = value; \
507 c.set_ ## field = true; \
508 int r = CTL_set_cist_bridge_config(br_index, &c); \
509 if(r) \
510 printf("Couldn't change bridge " #field "\n"); \
511 r; \
512 })
513
514#define set_port_cfg(field, value) \
515 ({ \
516 CIST_PortConfig c; \
517 memset(&c, 0, sizeof(c)); \
518 c.field = value; \
519 c.set_ ## field = true; \
520 int r = CTL_set_cist_port_config(br_index, port_index, &c); \
521 if(r) \
522 printf("Couldn't change port " #field "\n"); \
523 r; \
524 })
525
526#define set_tree_port_cfg(field, value) \
527 ({ \
528 MSTI_PortConfig c; \
529 memset(&c, 0, sizeof(c)); \
530 c.field = value; \
531 c.set_ ## field = true; \
532 int r = CTL_set_msti_port_config(br_index, port_index, mstid, &c); \
533 if(r) \
534 printf("Couldn't change per-tree port " #field "\n"); \
535 r; \
536 })
537
538static int cmd_setbridgemaxage(int argc, char *const *argv)
539{
540 int br_index = get_index(argv[1], "bridge");
541 if(0 > br_index)
542 return br_index;
543 return set_bridge_cfg(bridge_max_age, getuint(argv[2]));
544}
545
546static int cmd_setbridgefdelay(int argc, char *const *argv)
547{
548 int br_index = get_index(argv[1], "bridge");
549 if(0 > br_index)
550 return br_index;
551 return set_bridge_cfg(bridge_forward_delay, getuint(argv[2]));
552}
553
554static int cmd_setbridgemaxhops(int argc, char *const *argv)
555{
556 int br_index = get_index(argv[1], "bridge");
557 if(0 > br_index)
558 return br_index;
559 unsigned int max_hops = getuint(argv[2]);
560 if(max_hops > 255)
561 max_hops = 255;
562 return set_bridge_cfg(max_hops, max_hops);
563}
564
565static int cmd_setbridgeforcevers(int argc, char *const *argv)
566{
567 int br_index = get_index(argv[1], "bridge");
568 if(0 > br_index)
569 return br_index;
570 const char *opts[] = { "stp", "rstp", "mstp", NULL };
571 int vals[] = { protoSTP, protoRSTP, protoMSTP };
572 return set_bridge_cfg(protocol_version, vals[getenum(argv[2], opts)]);
573}
574
575static int cmd_setbridgetxholdcount(int argc, char *const *argv)
576{
577 int br_index = get_index(argv[1], "bridge");
578 if(0 > br_index)
579 return br_index;
580 return set_bridge_cfg(tx_hold_count, getuint(argv[2]));
581}
582
583static int cmd_settreeprio(int argc, char *const *argv)
584{
585 int br_index = get_index(argv[1], "bridge");
586 if(0 > br_index)
587 return br_index;
588 int mstid = get_id(argv[2], "mstid", MAX_MSTID);
589 if(0 > mstid)
590 return mstid;
591 unsigned int prio = getuint(argv[3]);
592 if(prio > 255)
593 prio = 255;
594 return CTL_set_msti_bridge_config(br_index, mstid, prio);
595}
596
597static int cmd_setportpathcost(int argc, char *const *argv)
598{
599 int br_index = get_index(argv[1], "bridge");
600 if(0 > br_index)
601 return br_index;
602 int port_index = get_index(argv[2], "port");
603 if(0 > port_index)
604 return port_index;
605 return set_port_cfg(admin_external_port_path_cost, getuint(argv[3]));
606}
607
608static int cmd_setportadminedge(int argc, char *const *argv)
609{
610 int br_index = get_index(argv[1], "bridge");
611 if(0 > br_index)
612 return br_index;
613 int port_index = get_index(argv[2], "port");
614 if(0 > port_index)
615 return port_index;
616 return set_port_cfg(admin_edge_port, getyesno(argv[3], "yes", "no"));
617}
618
619static int cmd_setportautoedge(int argc, char *const *argv)
620{
621 int br_index = get_index(argv[1], "bridge");
622 if(0 > br_index)
623 return br_index;
624 int port_index = get_index(argv[2], "port");
625 if(0 > port_index)
626 return port_index;
627 return set_port_cfg(auto_edge_port, getyesno(argv[3], "yes", "no"));
628}
629
630static int cmd_setportp2p(int argc, char *const *argv)
631{
632 int br_index = get_index(argv[1], "bridge");
633 if(0 > br_index)
634 return br_index;
635 int port_index = get_index(argv[2], "port");
636 if(0 > port_index)
637 return port_index;
638 const char *opts[] = { "no", "yes", "auto", NULL };
639 int vals[] = { p2pForceFalse, p2pForceTrue, p2pAuto };
640 return set_port_cfg(admin_p2p, vals[getenum(argv[3], opts)]);
641}
642
643static int cmd_setportrestrrole(int argc, char *const *argv)
644{
645 int br_index = get_index(argv[1], "bridge");
646 if(0 > br_index)
647 return br_index;
648 int port_index = get_index(argv[2], "port");
649 if(0 > port_index)
650 return port_index;
651 return set_port_cfg(restricted_role, getyesno(argv[3], "yes", "no"));
652}
653
654static int cmd_setportrestrtcn(int argc, char *const *argv)
655{
656 int br_index = get_index(argv[1], "bridge");
657 if(0 > br_index)
658 return br_index;
659 int port_index = get_index(argv[2], "port");
660 if(0 > port_index)
661 return port_index;
662 return set_port_cfg(restricted_tcn, getyesno(argv[3], "yes", "no"));
663}
664
665static int cmd_settreeportprio(int argc, char *const *argv)
666{
667 int br_index = get_index(argv[1], "bridge");
668 if(0 > br_index)
669 return br_index;
670 int port_index = get_index(argv[2], "port");
671 if(0 > port_index)
672 return port_index;
673 int mstid = get_id(argv[3], "mstid", MAX_MSTID);
674 if(0 > mstid)
675 return mstid;
676 unsigned int prio = getuint(argv[4]);
677 if(prio > 255)
678 prio = 255;
679 return set_tree_port_cfg(port_priority, prio);
680}
681
682static int cmd_settreeportcost(int argc, char *const *argv)
683{
684 int br_index = get_index(argv[1], "bridge");
685 if(0 > br_index)
686 return br_index;
687 int port_index = get_index(argv[2], "port");
688 if(0 > port_index)
689 return port_index;
690 int mstid = get_id(argv[3], "mstid", MAX_MSTID);
691 if(0 > mstid)
692 return mstid;
693 return set_tree_port_cfg(admin_internal_port_path_cost, getuint(argv[4]));
694}
695
696static int cmd_portmcheck(int argc, char *const *argv)
697{
698 int br_index = get_index(argv[1], "bridge");
699 if(0 > br_index)
700 return br_index;
701 int port_index = get_index(argv[2], "port");
702 if(0 > port_index)
703 return port_index;
704 return CTL_port_mcheck(br_index, port_index);
705}
706
707static int cmd_debuglevel(int argc, char *const *argv)
708{
709 return CTL_set_debug_level(getuint(argv[1]));
710}
711
712static int cmd_showmstilist(int argc, char *const *argv)
713{
714 int br_index = get_index(argv[1], "bridge");
715 if(0 > br_index)
716 return br_index;
717 int num_mstis = 0, i;
718 __u16 mstids[MAX_IMPLEMENTATION_MSTIS + 1]; /* +1 - for the CIST */
719
720 if(CTL_get_mstilist(br_index, &num_mstis, mstids))
721 return -1;
722
723 printf("%s list of known MSTIs:\n", argv[1]);
724 for(i = 0; i < num_mstis; ++i)
725 printf(" %hu", mstids[i]);
726 printf("\n");
727
728 return 0;
729}
730
731static int cmd_showmstconfid(int argc, char *const *argv)
732{
733 mst_configuration_identifier_t cfgid;
734 int br_index = get_index(argv[1], "bridge");
735 if(0 > br_index)
736 return br_index;
737 int i;
738
739 if(CTL_get_mstconfid(br_index, &cfgid))
740 return -1;
741
742 printf("%s MST Configuration Identifier:\n", argv[1]);
743 printf(" Format Selector: %hhu\n", cfgid.s.selector);
744 printf(" Configuration Name: %.*s\n", CONFIGURATION_NAME_LEN,
745 cfgid.s.configuration_name);
746 printf(" Revision Level: %hu\n",
747 __be16_to_cpu(cfgid.s.revision_level));
748 printf(" Configuration Digest: ");
749 for(i = 0; i < CONFIGURATION_DIGEST_LEN; ++i)
750 printf("%02hhX", cfgid.s.configuration_digest[i]);
751 printf("\n");
752
753 return 0;
754}
755
756static int cmd_createtree(int argc, char *const *argv)
757{
758 int br_index = get_index(argv[1], "bridge");
759 if(0 > br_index)
760 return br_index;
761 int mstid = get_id(argv[2], "mstid", MAX_MSTID);
762 if(0 > mstid)
763 return mstid;
764 return CTL_create_msti(br_index, mstid);
765}
766
767static int cmd_deletetree(int argc, char *const *argv)
768{
769 int br_index = get_index(argv[1], "bridge");
770 if(0 > br_index)
771 return br_index;
772 int mstid = get_id(argv[2], "mstid", MAX_MSTID);
773 if(0 > mstid)
774 return mstid;
775 return CTL_delete_msti(br_index, mstid);
776}
777
778static int cmd_showvid2fid(int argc, char *const *argv)
779{
780 __u16 vid2fid[MAX_VID + 2];
781 int br_index = get_index(argv[1], "bridge");
782 if(0 > br_index)
783 return br_index;
784
785 if(CTL_get_vids2fids(br_index, vid2fid))
786 return -1;
787
788 printf("%s VID-to-FID allocation table:\n", argv[1]);
789 int i, cur_fid;
790 int interval_count;
791 vid2fid[MAX_VID + 1] = 0xFFFF; /* helps to finalize last interval */
792 do{
793 cur_fid = vid2fid[0];
794 for(i = 1; i <= MAX_VID; ++i)
795 if(cur_fid > vid2fid[i])
796 cur_fid = vid2fid[i];
797 if(cur_fid > MAX_FID)
798 break;
799 printf(" FID %u:", cur_fid);
800 for(i = 0, interval_count = 0; i <= (MAX_VID + 1); ++i)
801 {
802 if(cur_fid != vid2fid[i])
803 {
804 if(interval_count)
805 {
806 printf(" %u", i - interval_count);
807 if(1 < interval_count)
808 printf("-%u", i - 1);
809 interval_count = 0;
810 }
811 continue;
812 }
813 vid2fid[i] = 0xFFFF;
814 ++interval_count;
815 }
816 printf("\n");
817 }while(true);
818
819 return 0;
820}
821
822static int cmd_showfid2mstid(int argc, char *const *argv)
823{
824 __u16 fid2mstid[MAX_FID + 2];
825 int br_index = get_index(argv[1], "bridge");
826 if(0 > br_index)
827 return br_index;
828
829 if(CTL_get_fids2mstids(br_index, fid2mstid))
830 return -1;
831
832 printf("%s FID-to-MSTID allocation table:\n", argv[1]);
833 int i, cur_mstid;
834 int interval_count;
835 fid2mstid[MAX_FID + 1] = 0xFFFF; /* helps to finalize last interval */
836 do{
837 cur_mstid = fid2mstid[0];
838 for(i = 1; i <= MAX_FID; ++i)
839 if(cur_mstid > fid2mstid[i])
840 cur_mstid = fid2mstid[i];
841 if(cur_mstid > MAX_MSTID)
842 break;
843 printf(" MSTID %u:", cur_mstid);
844 for(i = 0, interval_count = 0; i <= (MAX_FID + 1); ++i)
845 {
846 if(cur_mstid != fid2mstid[i])
847 {
848 if(interval_count)
849 {
850 printf(" %u", i - interval_count);
851 if(1 < interval_count)
852 printf("-%u", i - 1);
853 interval_count = 0;
854 }
855 continue;
856 }
857 fid2mstid[i] = 0xFFFF;
858 ++interval_count;
859 }
860 printf("\n");
861 }while(true);
862
863 return 0;
864}
865
866static int cmd_setvid2fid(int argc, char *const *argv)
867{
868 int br_index = get_index(argv[1], "bridge");
869 if(0 > br_index)
870 return br_index;
871 int vid = get_id(argv[2], "VID", MAX_VID);
872 if(0 > vid)
873 return vid;
874 if(0 == vid)
875 {
876 fprintf(stderr, "Bad VID %s\n", argv[2]);
877 return -1;
878 }
879 int fid = get_id(argv[3], "FID", MAX_FID);
880 if(0 > fid)
881 return fid;
882 return CTL_set_vid2fid(br_index, vid, fid);
883}
884
885static int cmd_setfid2mstid(int argc, char *const *argv)
886{
887 int br_index = get_index(argv[1], "bridge");
888 if(0 > br_index)
889 return br_index;
890 int fid = get_id(argv[2], "FID", MAX_FID);
891 if(0 > fid)
892 return fid;
893 int mstid = get_id(argv[3], "mstid", MAX_MSTID);
894 if(0 > mstid)
895 return mstid;
896 return CTL_set_fid2mstid(br_index, fid, mstid);
897}
898
899struct command
900{
901 int nargs;
902 int optargs;
903 const char *name;
904 int (*func) (int argc, char *const *argv);
905 const char *format;
906 const char *help;
907};
908
909static const struct command commands[] =
910{
911 /* Show global bridge */
912 {0, 32, "showbridge", cmd_showbridge,
913 "[<bridge> ... ]", "Show bridge state for the CIST"},
914 {1, 0, "showmstilist", cmd_showmstilist,
915 "<bridge>", "Show list of registered MSTIs"},
916 {1, 0, "showmstconfid", cmd_showmstconfid,
917 "<bridge>", "Show MST ConfigId"},
918 {1, 0, "showvid2fid", cmd_showvid2fid,
919 "<bridge>", "Show VID-to-FID allocation table"},
920 {1, 0, "showfid2mstid", cmd_showfid2mstid,
921 "<bridge>", "Show FID-to-MSTID allocation table"},
922 /* Show global port */
923 {1, 32, "showport", cmd_showport,
924 "<bridge> [<port> ... ]", "Show port state for the CIST"},
925 {1, 32, "showportdetail", cmd_showportdetail,
926 "<bridge> [<port> ... ]", "Show port detailed state for the CIST"},
927 /* Show tree bridge */
928 {2, 0, "showtree", cmd_showtree,
929 "<bridge> <mstid>", "Show bridge state for the given MSTI"},
930 /* Show tree port */
931 {3, 0, "showtreeport", cmd_showtreeport,
932 "<bridge> <port> <mstid>", "Show port detailed state for the given MSTI"},
933
934 /* Set global bridge */
935 {3, 0, "setmstconfid", cmd_setmstconfid,
936 "<bridge> <revision> <name>",
937 "Set MST ConfigId elements: Revision Level (0-65535) and Name"},
938 {3, 0, "setvid2fid", cmd_setvid2fid,
939 "<bridge> <VID> <FID>", "Set VID-to-FID allocation"},
940 {3, 0, "setfid2mstid", cmd_setfid2mstid,
941 "<bridge> <FID> <mstid>", "Set FID-to-MSTID allocation"},
942 {2, 0, "setmaxage", cmd_setbridgemaxage,
943 "<bridge> <max_age>", "Set bridge max age (6-40)"},
944 {2, 0, "setfdelay", cmd_setbridgefdelay,
945 "<bridge> <fwd_delay>", "Set bridge forward delay (4-30)"},
946 {2, 0, "setmaxhops", cmd_setbridgemaxhops,
947 "<bridge> <max_hops>", "Set bridge max hops (6-40)"},
948 {2, 0, "setforcevers", cmd_setbridgeforcevers,
949 "<bridge> {mstp|rstp|stp}", "Force Spanning Tree protocol version"},
950 {2, 0, "settxholdcount", cmd_setbridgetxholdcount,
951 "<bridge> <tx_hold_count>", "Set bridge transmit hold count (1-10)"},
952 /* Set tree bridge */
953 {2, 0, "createtree", cmd_createtree,
954 "<bridge> <mstid>", "Create new MSTI"},
955 {2, 0, "deletetree", cmd_deletetree,
956 "<bridge> <mstid>", "Delete existing MSTI"},
957 {3, 0, "settreeprio", cmd_settreeprio,
958 "<bridge> <mstid> <priority>",
959 "Set bridge priority (0-15) for the given MSTI"},
960 /* Set global port */
961 {3, 0, "setportpathcost", cmd_setportpathcost,
962 "<bridge> <port> <cost>",
963 "Set port external path cost for the CIST (0 = auto)"},
964 {3, 0, "setportadminedge", cmd_setportadminedge,
965 "<bridge> <port> {yes|no}", "Set initial edge state"},
966 {3, 0, "setportautoedge", cmd_setportautoedge,
967 "<bridge> <port> {yes|no}", "Enable auto transition to/from edge state"},
968 {3, 0, "setportp2p", cmd_setportp2p,
969 "<bridge> <port> {yes|no|auto}", "Set p2p detection mode"},
970 {3, 0, "setportrestrrole", cmd_setportrestrrole,
971 "<bridge> <port> {yes|no}", "Restrict port ability to take Root role"},
972 {3, 0, "setportrestrtcn", cmd_setportrestrtcn,
973 "<bridge> <port> {yes|no}",
974 "Restrict port ability to propagate received TCNs"},
975 {2, 0, "portmcheck", cmd_portmcheck,
976 "<bridge> <port>", "Try to get back from STP to rapid (RSTP/MSTP) mode"},
977 /* Set tree port */
978 {4, 0, "settreeportprio", cmd_settreeportprio,
979 "<bridge> <port> <mstid> <priority>",
980 "Set port priority (0-15) for the given MSTI"},
981 {4, 0, "settreeportcost", cmd_settreeportcost,
982 "<bridge> <port> <mstid> <cost>",
983 "Set port internal path cost for the given MSTI (0 = auto)"},
984
985 /* Other */
986 {1, 0, "debuglevel", cmd_debuglevel, "<level>", "Level of verbosity"},
987};
988
989static const struct command *command_lookup(const char *cmd)
990{
991 int i;
992
993 for(i = 0; i < COUNT_OF(commands); ++i)
994 {
995 if(!strcmp(cmd, commands[i].name))
996 return &commands[i];
997 }
998
999 return NULL;
1000}
1001
1002static void command_helpall(void)
1003{
1004 int i;
1005
1006 for(i = 0; i < COUNT_OF(commands); ++i)
1007 {
1008 printf("-%s:\n %-16s %s\n", commands[i].help, commands[i].name,
1009 commands[i].format);
1010 }
1011}
1012
1013static void help()
1014{
1015 printf("Usage: mstpctl [commands]\n");
1016 printf("commands:\n");
1017 command_helpall();
1018}
1019
1020#define PACKAGE_VERSION2(v, b) "mstp, " #v "-" #b
1021#define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
1022
1023int main(int argc, char *const *argv)
1024{
1025 const struct command *cmd;
1026 int f;
1027 static const struct option options[] =
1028 {
1029 {.name = "help", .val = 'h'},
1030 {.name = "version", .val = 'V'},
1031 {0}
1032 };
1033
1034 while(EOF != (f = getopt_long(argc, argv, "Vh", options, NULL)))
1035 switch(f)
1036 {
1037 case 'h':
1038 help();
1039 return 0;
1040 case 'V':
1041 printf("%s\n", PACKAGE_VERSION(VERSION, BUILD));
1042 return 0;
1043 default:
1044 fprintf(stderr, "Unknown option '%c'\n", f);
1045 goto help;
1046 }
1047
1048 if(argc == optind)
1049 goto help;
1050
1051 if(ctl_client_init())
1052 {
1053 fprintf(stderr, "can't setup control connection\n");
1054 return 1;
1055 }
1056
1057 argc -= optind;
1058 argv += optind;
1059 if(NULL == (cmd = command_lookup(argv[0])))
1060 {
1061 fprintf(stderr, "never heard of command [%s]\n", argv[0]);
1062 goto help;
1063 }
1064
1065 if(argc < cmd->nargs + 1 || argc > cmd->nargs + cmd->optargs + 1)
1066 {
1067 printf("Incorrect number of arguments for command\n");
1068 printf("Usage: mstpctl %s %s\n %s\n",
1069 cmd->name, cmd->format, cmd->help);
1070 return 1;
1071 }
1072
1073 return cmd->func(argc, argv);
1074
1075help:
1076 help();
1077 return 1;
1078}
1079
1080/* Implementation of client-side functions */
1081CLIENT_SIDE_FUNCTION(get_cist_bridge_status)
1082CLIENT_SIDE_FUNCTION(get_msti_bridge_status)
1083CLIENT_SIDE_FUNCTION(set_cist_bridge_config)
1084CLIENT_SIDE_FUNCTION(set_msti_bridge_config)
1085CLIENT_SIDE_FUNCTION(get_cist_port_status)
1086CLIENT_SIDE_FUNCTION(get_msti_port_status)
1087CLIENT_SIDE_FUNCTION(set_cist_port_config)
1088CLIENT_SIDE_FUNCTION(set_msti_port_config)
1089CLIENT_SIDE_FUNCTION(port_mcheck)
1090CLIENT_SIDE_FUNCTION(set_debug_level)
1091CLIENT_SIDE_FUNCTION(get_mstilist)
1092CLIENT_SIDE_FUNCTION(create_msti)
1093CLIENT_SIDE_FUNCTION(delete_msti)
1094CLIENT_SIDE_FUNCTION(get_mstconfid)
1095CLIENT_SIDE_FUNCTION(set_mstconfid)
1096CLIENT_SIDE_FUNCTION(get_vids2fids)
1097CLIENT_SIDE_FUNCTION(get_fids2mstids)
1098CLIENT_SIDE_FUNCTION(set_vid2fid)
1099CLIENT_SIDE_FUNCTION(set_fid2mstid)
1100CLIENT_SIDE_FUNCTION(set_vids2fids)
1101CLIENT_SIDE_FUNCTION(set_fids2mstids)
1102
1103/*********************** Logging *********************/
1104
1105void Dprintf(int level, const char *fmt, ...)
1106{
1107 char logbuf[LOG_STRING_LEN];
1108 logbuf[sizeof(logbuf) - 1] = 0;
1109 va_list ap;
1110 va_start(ap, fmt);
1111 vsnprintf(logbuf, sizeof(logbuf) - 1, fmt, ap);
1112 va_end(ap);
1113 printf("%s\n", logbuf);
1114}