1 /*****************************************************************************
2 Copyright (c) 2011 Factor-SPE
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)
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
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.
18 The full GNU General Public License is included in this distribution in the
21 Authors: Vitalii Demianets <vitas@nppfactor.kiev.ua>
23 ******************************************************************************/
32 #include "ctl_socket_client.h"
35 #ifdef __LIBC_HAS_VERSIONSORT__
36 #define sorting_func versionsort
38 #define sorting_func alphasort
41 static int get_index_die(const char *ifname
, const char *doc
, bool die
)
43 int r
= if_nametoindex(ifname
);
47 "Can't find index for %s %s. Not a valid interface.\n",
56 static inline int get_index(const char *ifname
, const char *doc
)
58 return get_index_die(ifname
, doc
, true);
61 static inline int get_id(const char *str
, const char *doc
, unsigned int max_id
)
63 int id
= strtol(str
, NULL
, 10);
64 if((0 > id
) || (max_id
< id
)
65 || ((0 == id
) && ('0' != str
[0]))
68 fprintf(stderr
, "Bad %s %s\n", doc
, str
);
74 #define GET_NUM_FROM_PRIO(p) (__be16_to_cpu(p) & 0x0FFF)
76 #define BR_ID_FMT "%01hhX.%03hX.%02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX"
77 #define BR_ID_ARGS(x) ((GET_PRIORITY_FROM_IDENTIFIER(x) >> 4) & 0x0F), \
78 GET_NUM_FROM_PRIO((x).s.priority), \
79 x.s.mac_address[0], x.s.mac_address[1], x.s.mac_address[2], \
80 x.s.mac_address[3], x.s.mac_address[4], x.s.mac_address[5]
82 #define PRT_ID_FMT "%01hhX.%03hX"
83 #define PRT_ID_ARGS(x) ((GET_PRIORITY_FROM_IDENTIFIER(x) >> 4) & 0x0F), \
86 #define BOOL_STR(x) ((x) ? "yes" : "no")
88 static int do_showbridge(const char *br_name
)
91 char root_port_name
[IFNAMSIZ
];
92 unsigned int root_portno
;
93 int br_index
= get_index_die(br_name
, "bridge", false);
97 if(CTL_get_cist_bridge_status(br_index
, &s
, root_port_name
))
99 printf("%s CIST info\n", br_name
);
100 printf(" enabled %s\n", BOOL_STR(s
.enabled
));
101 printf(" bridge id "BR_ID_FMT
"\n", BR_ID_ARGS(s
.bridge_id
));
102 printf(" designated root "BR_ID_FMT
"\n", BR_ID_ARGS(s
.designated_root
));
103 printf(" regional root "BR_ID_FMT
"\n", BR_ID_ARGS(s
.regional_root
));
104 printf(" root port ");
105 if(0 != (root_portno
= GET_NUM_FROM_PRIO(s
.root_port_id
)))
106 printf("%s (#%u)\n", root_port_name
, root_portno
);
109 printf(" path cost %-10u ", s
.root_path_cost
);
110 printf("internal path cost %u\n", s
.internal_path_cost
);
111 printf(" max age %-10hhu ", s
.root_max_age
);
112 printf("bridge max age %hhu\n", s
.bridge_max_age
);
113 printf(" forward delay %-10hhu ", s
.root_forward_delay
);
114 printf("bridge forward delay %hhu\n", s
.bridge_forward_delay
);
115 printf(" tx hold count %-10u ", s
.tx_hold_count
);
116 printf("max hops %hhu\n", s
.max_hops
);
117 printf(" force protocol version %u\n", s
.protocol_version
);
118 printf(" time since topology change %u\n", s
.time_since_topology_change
);
119 printf(" toplogy change count %u\n", s
.topology_change_count
);
120 printf(" topology change %s\n", BOOL_STR(s
.topology_change
));
125 #define SYSFS_PATH_MAX 256
126 #define SYSFS_CLASS_NET "/sys/class/net"
128 static int isbridge(const struct dirent
*entry
)
130 char path
[SYSFS_PATH_MAX
];
135 snprintf(path
, SYSFS_PATH_MAX
, SYSFS_CLASS_NET
"/%s/bridge",
138 result
= (0 == stat(path
, &st
)) && S_ISDIR(st
.st_mode
);
143 static int cmd_showbridge(int argc
, char *const *argv
)
147 struct dirent
**namelist
;
155 /* TODO: use versionsort, if available */
156 count
= scandir(SYSFS_CLASS_NET
, &namelist
, isbridge
, sorting_func
);
159 fprintf(stderr
, "Error getting list of all bridges\n");
164 for(i
= 0; i
< count
; ++i
)
170 name
= namelist
[i
]->d_name
;
172 int err
= do_showbridge(name
);
179 for(i
= 0; i
< count
; ++i
)
187 static int cmd_showtree(int argc
, char *const *argv
)
190 char root_port_name
[IFNAMSIZ
];
191 unsigned int root_portno
;
192 int br_index
= get_index(argv
[1], "bridge");
195 int mstid
= get_id(argv
[2], "mstid", MAX_MSTID
);
199 if(CTL_get_msti_bridge_status(br_index
, mstid
, &s
, root_port_name
))
202 printf("%s MSTI %hu info\n", argv
[1], mstid
);
203 printf(" bridge id "BR_ID_FMT
"\n", BR_ID_ARGS(s
.bridge_id
));
204 printf(" regional root "BR_ID_FMT
"\n", BR_ID_ARGS(s
.regional_root
));
205 printf(" root port ");
206 if(0 != (root_portno
= GET_NUM_FROM_PRIO(s
.root_port_id
)))
207 printf("%s (#%u)\n", root_port_name
, root_portno
);
210 printf(" internal path cost %u\n", s
.internal_path_cost
);
211 printf(" time since topology change %u\n", s
.time_since_topology_change
);
212 printf(" toplogy change count %u\n", s
.topology_change_count
);
213 printf(" topology change %s\n", BOOL_STR(s
.topology_change
));
218 #define STATE_STR(_state) \
221 char *_str = "unknown"; \
224 case BR_STATE_DISABLED: \
225 case BR_STATE_BLOCKING: \
226 case BR_STATE_LISTENING: _str = "discarding"; break; \
227 case BR_STATE_LEARNING: _str = "learning"; break; \
228 case BR_STATE_FORWARDING:_str = "forwarding"; break; \
233 #define SHORT_STATE_STR(_state) \
236 char *_str = "unkn"; \
239 case BR_STATE_DISABLED: \
240 case BR_STATE_BLOCKING: \
241 case BR_STATE_LISTENING: _str = "disc"; break; \
242 case BR_STATE_LEARNING: _str = "lear"; break; \
243 case BR_STATE_FORWARDING:_str = "forw"; break; \
248 #define ADMIN_P2P_STR(_state) \
250 admin_p2p_t _s = _state; \
251 char *_str = "unkn"; \
254 case p2pForceFalse:_str = "no"; break; \
255 case p2pForceTrue: _str = "yes"; break; \
256 case p2pAuto: _str = "auto"; break; \
261 #define ROLE_STR(_role) \
263 port_role_t _r = _role; \
264 char *_str = "Unknown"; \
267 case roleRoot: _str = "Root"; break; \
268 case roleDesignated:_str = "Designated"; break; \
269 case roleAlternate: _str = "Alternate"; break; \
270 case roleBackup: _str = "Backup"; break; \
271 case roleMaster: _str = "Master"; break; \
272 case roleDisabled: _str = "Disabled"; break; \
277 #define SHORT_ROLE_STR(_role) \
279 port_role_t _r = _role; \
280 char *_str = "Unkn"; \
283 case roleRoot: _str = "Root"; break; \
284 case roleDesignated:_str = "Desg"; break; \
285 case roleAlternate: _str = "Altn"; break; \
286 case roleBackup: _str = "Back"; break; \
287 case roleMaster: _str = "Mstr"; break; \
288 case roleDisabled: _str = "Disa"; break; \
294 static int detail
= 0;
296 static int do_showport(int br_index
, const char *bridge_name
,
297 const char *port_name
)
301 int port_index
= get_index_die(port_name
, "port", false);
305 if((r
= CTL_get_cist_port_status(br_index
, port_index
, &s
)))
307 fprintf(stderr
, "%s:%s Failed to get port state\n",
308 bridge_name
, port_name
);
314 printf("%s:%s CIST info\n", bridge_name
, port_name
);
315 printf(" enabled %-23s ", BOOL_STR(s
.enabled
));
316 printf("role %s\n", ROLE_STR(s
.role
));
317 printf(" port id "PRT_ID_FMT
" ",
318 PRT_ID_ARGS(s
.port_id
));
319 printf("state %s\n", STATE_STR(s
.state
));
320 printf(" external port cost %-23u ", s
.external_port_path_cost
);
321 printf("admin external cost %u\n", s
.admin_external_port_path_cost
);
322 printf(" internal port cost %-23u ", s
.internal_port_path_cost
);
323 printf("admin internal cost %u\n", s
.admin_internal_port_path_cost
);
324 printf(" designated root "BR_ID_FMT
" ",
325 BR_ID_ARGS(s
.designated_root
));
326 printf("dsgn external cost %u\n", s
.designated_external_cost
);
327 printf(" dsgn regional root "BR_ID_FMT
" ",
328 BR_ID_ARGS(s
.designated_regional_root
));
329 printf("dsgn internal cost %u\n", s
.designated_internal_cost
);
330 printf(" designated bridge "BR_ID_FMT
" ",
331 BR_ID_ARGS(s
.designated_bridge
));
332 printf("designated port "PRT_ID_FMT
"\n",
333 PRT_ID_ARGS(s
.designated_port
));
334 printf(" admin edge port %-23s ", BOOL_STR(s
.admin_edge_port
));
335 printf("auto edge port %s\n", BOOL_STR(s
.auto_edge_port
));
336 printf(" oper edge port %-23s ", BOOL_STR(s
.oper_edge_port
));
337 printf("toplogy change ack %s\n", BOOL_STR(s
.tc_ack
));
338 printf(" point-to-point %-23s ", BOOL_STR(s
.oper_p2p
));
339 printf("admin point-to-point %s\n", ADMIN_P2P_STR(s
.admin_p2p
));
340 printf(" restricted role %-23s ", BOOL_STR(s
.restricted_role
));
341 printf("restricted TCN %s\n", BOOL_STR(s
.restricted_tcn
));
342 printf(" port hello time %-23hhu ", s
.port_hello_time
);
343 printf("disputed %s\n", BOOL_STR(s
.disputed
));
347 printf("%c%c %-5s "PRT_ID_FMT
" %4s "BR_ID_FMT
" "BR_ID_FMT
" "PRT_ID_FMT
" %s\n",
348 (s
.oper_p2p
) ? ' ' : '*',
349 (s
.oper_edge_port
) ? 'E' : ' ',
351 PRT_ID_ARGS(s
.port_id
),
352 s
.enabled
? SHORT_STATE_STR(s
.state
) : "down",
353 BR_ID_ARGS(s
.designated_root
),
354 BR_ID_ARGS(s
.designated_bridge
),
355 PRT_ID_ARGS(s
.designated_port
),
356 SHORT_ROLE_STR(s
.role
));
361 static int not_dot_dotdot(const struct dirent
*entry
)
363 const char *n
= entry
->d_name
;
365 return !('.' == n
[0] && (0 == n
[1] || ('.' == n
[1] && 0 == n
[2])));
368 static int cmd_showport(int argc
, char *const *argv
)
372 int br_index
= get_index(argv
[1], "bridge");
377 struct dirent
**namelist
;
385 char buf
[SYSFS_PATH_MAX
];
386 snprintf(buf
, sizeof(buf
), SYSFS_CLASS_NET
"/%s/brif", argv
[1]);
387 /* TODO: use versionsort, if available */
388 count
= scandir(buf
, &namelist
, not_dot_dotdot
, sorting_func
);
391 fprintf(stderr
, "Error getting list of all ports of bridge %s\n",
397 for(i
= 0; i
< count
; ++i
)
403 name
= namelist
[i
]->d_name
;
405 int err
= do_showport(br_index
, argv
[1], name
);
412 for(i
= 0; i
< count
; ++i
)
420 static int cmd_showportdetail(int argc
, char *const *argv
)
423 return cmd_showport(argc
, argv
);
426 static int cmd_showtreeport(int argc
, char *const *argv
)
429 int br_index
= get_index(argv
[1], "bridge");
432 int port_index
= get_index(argv
[2], "port");
435 int mstid
= get_id(argv
[3], "mstid", MAX_MSTID
);
439 if(CTL_get_msti_port_status(br_index
, port_index
, mstid
, &s
))
442 printf("%s:%s MSTI %hu info\n", argv
[1], argv
[2], mstid
);
443 printf(" role %-23s ", ROLE_STR(s
.role
));
444 printf("port id "PRT_ID_FMT
"\n", PRT_ID_ARGS(s
.port_id
));
445 printf(" state %-23s ", STATE_STR(s
.state
));
446 printf("disputed %s\n", BOOL_STR(s
.disputed
));
447 printf(" internal port cost %-23u ", s
.internal_port_path_cost
);
448 printf("admin internal cost %u\n", s
.admin_internal_port_path_cost
);
449 printf(" dsgn regional root "BR_ID_FMT
" ",
450 BR_ID_ARGS(s
.designated_regional_root
));
451 printf("dsgn internal cost %u\n", s
.designated_internal_cost
);
452 printf(" designated bridge "BR_ID_FMT
" ",
453 BR_ID_ARGS(s
.designated_bridge
));
454 printf("designated port "PRT_ID_FMT
"\n",
455 PRT_ID_ARGS(s
.designated_port
));
460 static unsigned int getuint(const char *s
)
464 l
= strtoul(s
, &end
, 0);
465 if(0 == *s
|| 0 != *end
|| INT_MAX
< l
)
467 fprintf(stderr
, "Invalid unsigned int arg %s\n", s
);
473 static int getenum(const char *s
, const char *opt
[])
476 for(i
= 0; opt
[i
] != NULL
; ++i
)
477 if(0 == strcmp(s
, opt
[i
]))
480 fprintf(stderr
, "Invalid argument %s: expecting one of ", s
);
481 for(i
= 0; opt
[i
] != NULL
; ++i
)
482 fprintf(stderr
, "%s%s", opt
[i
], (opt
[i
+ 1] ? ", " : "\n"));
487 static int getyesno(const char *s
, const char *yes
, const char *no
)
489 /* Reverse yes and no so error message looks more normal */
490 const char *opt
[] = { yes
, no
, NULL
};
491 return 1 - getenum(s
, opt
);
494 static int cmd_setmstconfid(int argc
, char *const *argv
)
496 int br_index
= get_index(argv
[1], "bridge");
499 unsigned int revision
= getuint(argv
[2]);
500 if(revision
> 0xFFFF)
502 fprintf(stderr
, "Bad revision %s\n", argv
[2]);
505 return CTL_set_mstconfid(br_index
, revision
, argv
[3]);
508 #define set_bridge_cfg(field, value) \
510 CIST_BridgeConfig c; \
511 memset(&c, 0, sizeof(c)); \
513 c.set_ ## field = true; \
514 int r = CTL_set_cist_bridge_config(br_index, &c); \
516 printf("Couldn't change bridge " #field "\n"); \
520 #define set_port_cfg(field, value) \
523 memset(&c, 0, sizeof(c)); \
525 c.set_ ## field = true; \
526 int r = CTL_set_cist_port_config(br_index, port_index, &c); \
528 printf("Couldn't change port " #field "\n"); \
532 #define set_tree_port_cfg(field, value) \
535 memset(&c, 0, sizeof(c)); \
537 c.set_ ## field = true; \
538 int r = CTL_set_msti_port_config(br_index, port_index, mstid, &c); \
540 printf("Couldn't change per-tree port " #field "\n"); \
544 static int cmd_setbridgemaxage(int argc
, char *const *argv
)
546 int br_index
= get_index(argv
[1], "bridge");
549 unsigned int max_age
= getuint(argv
[2]);
552 return set_bridge_cfg(bridge_max_age
, max_age
);
555 static int cmd_setbridgefdelay(int argc
, char *const *argv
)
557 int br_index
= get_index(argv
[1], "bridge");
560 unsigned int forward_delay
= getuint(argv
[2]);
561 if(forward_delay
> 255)
563 return set_bridge_cfg(bridge_forward_delay
, forward_delay
);
566 static int cmd_setbridgemaxhops(int argc
, char *const *argv
)
568 int br_index
= get_index(argv
[1], "bridge");
571 unsigned int max_hops
= getuint(argv
[2]);
574 return set_bridge_cfg(max_hops
, max_hops
);
577 static int cmd_setbridgeforcevers(int argc
, char *const *argv
)
579 int br_index
= get_index(argv
[1], "bridge");
582 const char *opts
[] = { "stp", "rstp", "mstp", NULL
};
583 int vals
[] = { protoSTP
, protoRSTP
, protoMSTP
};
584 return set_bridge_cfg(protocol_version
, vals
[getenum(argv
[2], opts
)]);
587 static int cmd_setbridgetxholdcount(int argc
, char *const *argv
)
589 int br_index
= get_index(argv
[1], "bridge");
592 return set_bridge_cfg(tx_hold_count
, getuint(argv
[2]));
595 static int cmd_settreeprio(int argc
, char *const *argv
)
597 int br_index
= get_index(argv
[1], "bridge");
600 int mstid
= get_id(argv
[2], "mstid", MAX_MSTID
);
603 unsigned int prio
= getuint(argv
[3]);
606 return CTL_set_msti_bridge_config(br_index
, mstid
, prio
);
609 static int cmd_setportpathcost(int argc
, char *const *argv
)
611 int br_index
= get_index(argv
[1], "bridge");
614 int port_index
= get_index(argv
[2], "port");
617 return set_port_cfg(admin_external_port_path_cost
, getuint(argv
[3]));
620 static int cmd_setportadminedge(int argc
, char *const *argv
)
622 int br_index
= get_index(argv
[1], "bridge");
625 int port_index
= get_index(argv
[2], "port");
628 return set_port_cfg(admin_edge_port
, getyesno(argv
[3], "yes", "no"));
631 static int cmd_setportautoedge(int argc
, char *const *argv
)
633 int br_index
= get_index(argv
[1], "bridge");
636 int port_index
= get_index(argv
[2], "port");
639 return set_port_cfg(auto_edge_port
, getyesno(argv
[3], "yes", "no"));
642 static int cmd_setportp2p(int argc
, char *const *argv
)
644 int br_index
= get_index(argv
[1], "bridge");
647 int port_index
= get_index(argv
[2], "port");
650 const char *opts
[] = { "no", "yes", "auto", NULL
};
651 int vals
[] = { p2pForceFalse
, p2pForceTrue
, p2pAuto
};
652 return set_port_cfg(admin_p2p
, vals
[getenum(argv
[3], opts
)]);
655 static int cmd_setportrestrrole(int argc
, char *const *argv
)
657 int br_index
= get_index(argv
[1], "bridge");
660 int port_index
= get_index(argv
[2], "port");
663 return set_port_cfg(restricted_role
, getyesno(argv
[3], "yes", "no"));
666 static int cmd_setportrestrtcn(int argc
, char *const *argv
)
668 int br_index
= get_index(argv
[1], "bridge");
671 int port_index
= get_index(argv
[2], "port");
674 return set_port_cfg(restricted_tcn
, getyesno(argv
[3], "yes", "no"));
677 static int cmd_settreeportprio(int argc
, char *const *argv
)
679 int br_index
= get_index(argv
[1], "bridge");
682 int port_index
= get_index(argv
[2], "port");
685 int mstid
= get_id(argv
[3], "mstid", MAX_MSTID
);
688 unsigned int prio
= getuint(argv
[4]);
691 return set_tree_port_cfg(port_priority
, prio
);
694 static int cmd_settreeportcost(int argc
, char *const *argv
)
696 int br_index
= get_index(argv
[1], "bridge");
699 int port_index
= get_index(argv
[2], "port");
702 int mstid
= get_id(argv
[3], "mstid", MAX_MSTID
);
705 return set_tree_port_cfg(admin_internal_port_path_cost
, getuint(argv
[4]));
708 static int cmd_portmcheck(int argc
, char *const *argv
)
710 int br_index
= get_index(argv
[1], "bridge");
713 int port_index
= get_index(argv
[2], "port");
716 return CTL_port_mcheck(br_index
, port_index
);
719 static int cmd_debuglevel(int argc
, char *const *argv
)
721 return CTL_set_debug_level(getuint(argv
[1]));
724 static int cmd_showmstilist(int argc
, char *const *argv
)
726 int br_index
= get_index(argv
[1], "bridge");
729 int num_mstis
= 0, i
;
730 __u16 mstids
[MAX_IMPLEMENTATION_MSTIS
+ 1]; /* +1 - for the CIST */
732 if(CTL_get_mstilist(br_index
, &num_mstis
, mstids
))
735 printf("%s list of known MSTIs:\n", argv
[1]);
736 for(i
= 0; i
< num_mstis
; ++i
)
737 printf(" %hu", mstids
[i
]);
743 static int cmd_showmstconfid(int argc
, char *const *argv
)
745 mst_configuration_identifier_t cfgid
;
746 int br_index
= get_index(argv
[1], "bridge");
751 if(CTL_get_mstconfid(br_index
, &cfgid
))
754 printf("%s MST Configuration Identifier:\n", argv
[1]);
755 printf(" Format Selector: %hhu\n", cfgid
.s
.selector
);
756 printf(" Configuration Name: %.*s\n", CONFIGURATION_NAME_LEN
,
757 cfgid
.s
.configuration_name
);
758 printf(" Revision Level: %hu\n",
759 __be16_to_cpu(cfgid
.s
.revision_level
));
760 printf(" Configuration Digest: ");
761 for(i
= 0; i
< CONFIGURATION_DIGEST_LEN
; ++i
)
762 printf("%02hhX", cfgid
.s
.configuration_digest
[i
]);
768 static int cmd_createtree(int argc
, char *const *argv
)
770 int br_index
= get_index(argv
[1], "bridge");
773 int mstid
= get_id(argv
[2], "mstid", MAX_MSTID
);
776 return CTL_create_msti(br_index
, mstid
);
779 static int cmd_deletetree(int argc
, char *const *argv
)
781 int br_index
= get_index(argv
[1], "bridge");
784 int mstid
= get_id(argv
[2], "mstid", MAX_MSTID
);
787 return CTL_delete_msti(br_index
, mstid
);
790 static int cmd_showvid2fid(int argc
, char *const *argv
)
792 __u16 vid2fid
[MAX_VID
+ 2];
793 int br_index
= get_index(argv
[1], "bridge");
797 if(CTL_get_vids2fids(br_index
, vid2fid
))
800 printf("%s VID-to-FID allocation table:\n", argv
[1]);
803 vid2fid
[MAX_VID
+ 1] = 0xFFFF; /* helps to finalize last interval */
805 cur_fid
= vid2fid
[0];
806 for(i
= 1; i
<= MAX_VID
; ++i
)
807 if(cur_fid
> vid2fid
[i
])
808 cur_fid
= vid2fid
[i
];
809 if(cur_fid
> MAX_FID
)
811 printf(" FID %u:", cur_fid
);
812 for(i
= 0, interval_count
= 0; i
<= (MAX_VID
+ 1); ++i
)
814 if(cur_fid
!= vid2fid
[i
])
818 printf(" %u", i
- interval_count
);
819 if(1 < interval_count
)
820 printf("-%u", i
- 1);
834 static int cmd_showfid2mstid(int argc
, char *const *argv
)
836 __u16 fid2mstid
[MAX_FID
+ 2];
837 int br_index
= get_index(argv
[1], "bridge");
841 if(CTL_get_fids2mstids(br_index
, fid2mstid
))
844 printf("%s FID-to-MSTID allocation table:\n", argv
[1]);
847 fid2mstid
[MAX_FID
+ 1] = 0xFFFF; /* helps to finalize last interval */
849 cur_mstid
= fid2mstid
[0];
850 for(i
= 1; i
<= MAX_FID
; ++i
)
851 if(cur_mstid
> fid2mstid
[i
])
852 cur_mstid
= fid2mstid
[i
];
853 if(cur_mstid
> MAX_MSTID
)
855 printf(" MSTID %u:", cur_mstid
);
856 for(i
= 0, interval_count
= 0; i
<= (MAX_FID
+ 1); ++i
)
858 if(cur_mstid
!= fid2mstid
[i
])
862 printf(" %u", i
- interval_count
);
863 if(1 < interval_count
)
864 printf("-%u", i
- 1);
869 fid2mstid
[i
] = 0xFFFF;
878 static int cmd_setvid2fid(int argc
, char *const *argv
)
880 int br_index
= get_index(argv
[1], "bridge");
883 int vid
= get_id(argv
[2], "VID", MAX_VID
);
888 fprintf(stderr
, "Bad VID %s\n", argv
[2]);
891 int fid
= get_id(argv
[3], "FID", MAX_FID
);
894 return CTL_set_vid2fid(br_index
, vid
, fid
);
897 static int cmd_setfid2mstid(int argc
, char *const *argv
)
899 int br_index
= get_index(argv
[1], "bridge");
902 int fid
= get_id(argv
[2], "FID", MAX_FID
);
905 int mstid
= get_id(argv
[3], "mstid", MAX_MSTID
);
908 return CTL_set_fid2mstid(br_index
, fid
, mstid
);
916 int (*func
) (int argc
, char *const *argv
);
921 static const struct command commands
[] =
923 /* Show global bridge */
924 {0, 32, "showbridge", cmd_showbridge
,
925 "[<bridge> ... ]", "Show bridge state for the CIST"},
926 {1, 0, "showmstilist", cmd_showmstilist
,
927 "<bridge>", "Show list of registered MSTIs"},
928 {1, 0, "showmstconfid", cmd_showmstconfid
,
929 "<bridge>", "Show MST ConfigId"},
930 {1, 0, "showvid2fid", cmd_showvid2fid
,
931 "<bridge>", "Show VID-to-FID allocation table"},
932 {1, 0, "showfid2mstid", cmd_showfid2mstid
,
933 "<bridge>", "Show FID-to-MSTID allocation table"},
934 /* Show global port */
935 {1, 32, "showport", cmd_showport
,
936 "<bridge> [<port> ... ]", "Show port state for the CIST"},
937 {1, 32, "showportdetail", cmd_showportdetail
,
938 "<bridge> [<port> ... ]", "Show port detailed state for the CIST"},
939 /* Show tree bridge */
940 {2, 0, "showtree", cmd_showtree
,
941 "<bridge> <mstid>", "Show bridge state for the given MSTI"},
943 {3, 0, "showtreeport", cmd_showtreeport
,
944 "<bridge> <port> <mstid>", "Show port detailed state for the given MSTI"},
946 /* Set global bridge */
947 {3, 0, "setmstconfid", cmd_setmstconfid
,
948 "<bridge> <revision> <name>",
949 "Set MST ConfigId elements: Revision Level (0-65535) and Name"},
950 {3, 0, "setvid2fid", cmd_setvid2fid
,
951 "<bridge> <VID> <FID>", "Set VID-to-FID allocation"},
952 {3, 0, "setfid2mstid", cmd_setfid2mstid
,
953 "<bridge> <FID> <mstid>", "Set FID-to-MSTID allocation"},
954 {2, 0, "setmaxage", cmd_setbridgemaxage
,
955 "<bridge> <max_age>", "Set bridge max age (6-40)"},
956 {2, 0, "setfdelay", cmd_setbridgefdelay
,
957 "<bridge> <fwd_delay>", "Set bridge forward delay (4-30)"},
958 {2, 0, "setmaxhops", cmd_setbridgemaxhops
,
959 "<bridge> <max_hops>", "Set bridge max hops (6-40)"},
960 {2, 0, "setforcevers", cmd_setbridgeforcevers
,
961 "<bridge> {mstp|rstp|stp}", "Force Spanning Tree protocol version"},
962 {2, 0, "settxholdcount", cmd_setbridgetxholdcount
,
963 "<bridge> <tx_hold_count>", "Set bridge transmit hold count (1-10)"},
964 /* Set tree bridge */
965 {2, 0, "createtree", cmd_createtree
,
966 "<bridge> <mstid>", "Create new MSTI"},
967 {2, 0, "deletetree", cmd_deletetree
,
968 "<bridge> <mstid>", "Delete existing MSTI"},
969 {3, 0, "settreeprio", cmd_settreeprio
,
970 "<bridge> <mstid> <priority>",
971 "Set bridge priority (0-15) for the given MSTI"},
972 /* Set global port */
973 {3, 0, "setportpathcost", cmd_setportpathcost
,
974 "<bridge> <port> <cost>",
975 "Set port external path cost for the CIST (0 = auto)"},
976 {3, 0, "setportadminedge", cmd_setportadminedge
,
977 "<bridge> <port> {yes|no}", "Set initial edge state"},
978 {3, 0, "setportautoedge", cmd_setportautoedge
,
979 "<bridge> <port> {yes|no}", "Enable auto transition to/from edge state"},
980 {3, 0, "setportp2p", cmd_setportp2p
,
981 "<bridge> <port> {yes|no|auto}", "Set p2p detection mode"},
982 {3, 0, "setportrestrrole", cmd_setportrestrrole
,
983 "<bridge> <port> {yes|no}", "Restrict port ability to take Root role"},
984 {3, 0, "setportrestrtcn", cmd_setportrestrtcn
,
985 "<bridge> <port> {yes|no}",
986 "Restrict port ability to propagate received TCNs"},
987 {2, 0, "portmcheck", cmd_portmcheck
,
988 "<bridge> <port>", "Try to get back from STP to rapid (RSTP/MSTP) mode"},
990 {4, 0, "settreeportprio", cmd_settreeportprio
,
991 "<bridge> <port> <mstid> <priority>",
992 "Set port priority (0-15) for the given MSTI"},
993 {4, 0, "settreeportcost", cmd_settreeportcost
,
994 "<bridge> <port> <mstid> <cost>",
995 "Set port internal path cost for the given MSTI (0 = auto)"},
998 {1, 0, "debuglevel", cmd_debuglevel
, "<level>", "Level of verbosity"},
1001 static const struct command
*command_lookup(const char *cmd
)
1005 for(i
= 0; i
< COUNT_OF(commands
); ++i
)
1007 if(!strcmp(cmd
, commands
[i
].name
))
1008 return &commands
[i
];
1014 static void command_helpall(void)
1018 for(i
= 0; i
< COUNT_OF(commands
); ++i
)
1020 printf("-%s:\n %-16s %s\n", commands
[i
].help
, commands
[i
].name
,
1021 commands
[i
].format
);
1025 static void help(void)
1027 printf("Usage: mstpctl [commands]\n");
1028 printf("commands:\n");
1032 #define PACKAGE_VERSION2(v, b) "mstp, " #v "-" #b
1033 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
1035 int main(int argc
, char *const *argv
)
1037 const struct command
*cmd
;
1039 static const struct option options
[] =
1041 {.name
= "help", .val
= 'h'},
1042 {.name
= "version", .val
= 'V'},
1046 while(EOF
!= (f
= getopt_long(argc
, argv
, "Vh", options
, NULL
)))
1053 printf("%s\n", PACKAGE_VERSION(VERSION
, BUILD
));
1056 fprintf(stderr
, "Unknown option '%c'\n", f
);
1063 if(ctl_client_init())
1065 fprintf(stderr
, "can't setup control connection\n");
1071 if(NULL
== (cmd
= command_lookup(argv
[0])))
1073 fprintf(stderr
, "never heard of command [%s]\n", argv
[0]);
1077 if(argc
< cmd
->nargs
+ 1 || argc
> cmd
->nargs
+ cmd
->optargs
+ 1)
1079 printf("Incorrect number of arguments for command\n");
1080 printf("Usage: mstpctl %s %s\n %s\n",
1081 cmd
->name
, cmd
->format
, cmd
->help
);
1085 return cmd
->func(argc
, argv
);
1092 /* Implementation of client-side functions */
1093 CLIENT_SIDE_FUNCTION(get_cist_bridge_status
)
1094 CLIENT_SIDE_FUNCTION(get_msti_bridge_status
)
1095 CLIENT_SIDE_FUNCTION(set_cist_bridge_config
)
1096 CLIENT_SIDE_FUNCTION(set_msti_bridge_config
)
1097 CLIENT_SIDE_FUNCTION(get_cist_port_status
)
1098 CLIENT_SIDE_FUNCTION(get_msti_port_status
)
1099 CLIENT_SIDE_FUNCTION(set_cist_port_config
)
1100 CLIENT_SIDE_FUNCTION(set_msti_port_config
)
1101 CLIENT_SIDE_FUNCTION(port_mcheck
)
1102 CLIENT_SIDE_FUNCTION(set_debug_level
)
1103 CLIENT_SIDE_FUNCTION(get_mstilist
)
1104 CLIENT_SIDE_FUNCTION(create_msti
)
1105 CLIENT_SIDE_FUNCTION(delete_msti
)
1106 CLIENT_SIDE_FUNCTION(get_mstconfid
)
1107 CLIENT_SIDE_FUNCTION(set_mstconfid
)
1108 CLIENT_SIDE_FUNCTION(get_vids2fids
)
1109 CLIENT_SIDE_FUNCTION(get_fids2mstids
)
1110 CLIENT_SIDE_FUNCTION(set_vid2fid
)
1111 CLIENT_SIDE_FUNCTION(set_fid2mstid
)
1112 CLIENT_SIDE_FUNCTION(set_vids2fids
)
1113 CLIENT_SIDE_FUNCTION(set_fids2mstids
)
1115 /*********************** Logging *********************/
1117 void Dprintf(int level
, const char *fmt
, ...)
1119 char logbuf
[LOG_STRING_LEN
];
1120 logbuf
[sizeof(logbuf
) - 1] = 0;
1123 vsnprintf(logbuf
, sizeof(logbuf
) - 1, fmt
, ap
);
1125 printf("%s\n", logbuf
);