1 /*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
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: Srinivas Aji <Aji_Srinivas@emc.com>
23 ******************************************************************************/
25 #include "bridge_ctl.h"
26 #include "netif_utils.h"
32 #include <linux/if_bridge.h>
33 #include <arpa/inet.h>
34 #include <sys/types.h>
47 /*------------------------------------------------------------*/
57 struct ifdata
*bridge_next
;
58 struct ifdata
*port_list
;
61 struct stp_instance
*stp
;
62 UID_BRIDGE_ID_T bridge_id
;
64 UID_STP_MODE_T stp_enabled
;
75 struct ifdata
*master
;
76 struct ifdata
*port_next
;
81 int admin_port_path_cost
;
82 ADMIN_P2P_T admin_point2point
;
83 unsigned char admin_edge
;
84 unsigned char admin_non_stp
; /* 1- doesn't participate in STP, 1 - regular */
86 struct epoll_event_handler event
;
90 struct ifdata
*current_br
= NULL
;
92 void instance_begin(struct ifdata
*br
)
95 ERROR("BUG: Trying to set instance over existing instance.");
96 ERROR("%d", *(int *)0); /* ABORT */
99 STP_IN_instance_begin(br
->stp
);
102 void instance_end(void)
104 STP_IN_instance_end(current_br
->stp
);
108 struct ifdata
*find_port(int port_index
)
110 struct ifdata
*ifc
= current_br
->port_list
;
111 while (ifc
&& ifc
->port_index
!= port_index
)
112 ifc
= ifc
->port_next
;
116 /*************************************************************/
117 /* Bridge and port defaults */
119 UID_STP_CFG_T default_bridge_stp_cfg
= {
120 .field_mask
= BR_CFG_ALL
,
121 .bridge_priority
= DEF_BR_PRIO
,
122 .max_age
= DEF_BR_MAXAGE
,
123 .hello_time
= DEF_BR_HELLOT
,
124 .forward_delay
= DEF_BR_FWDELAY
,
125 .force_version
= DEF_FORCE_VERS
, /*NORMAL_RSTP */
128 void update_bridge_stp_config(struct ifdata
*br
, UID_STP_CFG_T
* cfg
)
130 if (cfg
->field_mask
& BR_CFG_PRIO
)
131 br
->bridge_priority
= cfg
->bridge_priority
;
132 if (cfg
->field_mask
& BR_CFG_AGE
)
133 br
->max_age
= cfg
->max_age
;
134 if (cfg
->field_mask
& BR_CFG_HELLO
)
135 br
->hello_time
= cfg
->hello_time
;
136 if (cfg
->field_mask
& BR_CFG_DELAY
)
137 br
->forward_delay
= cfg
->forward_delay
;
138 if (cfg
->field_mask
& BR_CFG_FORCE_VER
)
139 br
->force_version
= cfg
->force_version
;
142 UID_STP_PORT_CFG_T default_port_stp_cfg
= {
143 .field_mask
= PT_CFG_ALL
,
144 .port_priority
= DEF_PORT_PRIO
,
145 .admin_non_stp
= DEF_ADMIN_NON_STP
,
146 .admin_edge
= False
, // DEF_ADMIN_EDGE,
147 .admin_port_path_cost
= ADMIN_PORT_PATH_COST_AUTO
,
148 .admin_point2point
= DEF_P2P
,
151 void update_port_stp_config(struct ifdata
*ifc
, UID_STP_PORT_CFG_T
* cfg
)
153 if (cfg
->field_mask
& PT_CFG_PRIO
)
154 ifc
->port_priority
= cfg
->port_priority
;
155 if (cfg
->field_mask
& PT_CFG_NON_STP
)
156 ifc
->admin_non_stp
= cfg
->admin_non_stp
;
157 if (cfg
->field_mask
& PT_CFG_EDGE
)
158 ifc
->admin_edge
= cfg
->admin_edge
;
159 if (cfg
->field_mask
& PT_CFG_COST
)
160 ifc
->admin_port_path_cost
= cfg
->admin_port_path_cost
;
161 if (cfg
->field_mask
& PT_CFG_P2P
)
162 ifc
->admin_point2point
= cfg
->admin_point2point
;
165 /**************************************************************/
167 int add_port_stp(struct ifdata
*ifc
)
168 { /* Bridge is ifc->master */
169 TST((ifc
->port_index
= get_bridge_portno(ifc
->name
)) >= 0, -1);
171 /* Add port to STP */
172 instance_begin(ifc
->master
);
173 int r
= STP_IN_port_create(0, ifc
->port_index
);
174 if (r
== 0) { /* Update bridge ID */
175 UID_STP_STATE_T state
;
176 STP_IN_stpm_get_state(0, &state
);
177 ifc
->master
->bridge_id
= state
.bridge_id
;
180 if (r
/* check for failure */ ) {
181 ERROR("Couldn't add port for ifindex %d to STP", ifc
->if_index
);
187 void remove_port_stp(struct ifdata
*ifc
)
189 /* Remove port from STP */
190 instance_begin(ifc
->master
);
191 int r
= STP_IN_port_delete(0, ifc
->port_index
);
193 ifc
->port_index
= -1;
195 ERROR("removing port %s failed for bridge %s: %s",
196 ifc
->name
, ifc
->master
->name
,
197 STP_IN_get_error_explanation(r
));
201 int init_rstplib_instance(struct ifdata
*br
)
203 br
->stp
= STP_IN_instance_create();
204 if (br
->stp
== NULL
) {
205 ERROR("Couldn't create STP instance for bridge %s", br
->name
);
212 int r
= STP_IN_stpm_create(0, br
->name
, &ports
);
215 ERROR("stpm create failed for bridge %s: %s",
216 br
->name
, STP_IN_get_error_explanation(r
));
223 void clear_rstplib_instance(struct ifdata
*br
)
226 int r
= STP_IN_delete_all();
229 ERROR("stpm delete failed for bridge %s: %s",
230 br
->name
, STP_IN_get_error_explanation(r
));
233 STP_IN_instance_delete(br
->stp
);
237 int init_bridge_stp(struct ifdata
*br
)
240 ERROR("STP already started");
245 TST(init_rstplib_instance(br
) == 0, -1);
247 struct ifdata
*p
= br
->port_list
;
249 if (add_port_stp(p
) != 0)
254 struct ifdata
*q
= br
->port_list
;
259 /* Clear bridge STP state */
260 clear_rstplib_instance(br
);
267 void clear_bridge_stp(struct ifdata
*br
)
272 struct ifdata
*p
= br
->port_list
;
277 /* Clear bridge STP state */
278 clear_rstplib_instance(br
);
281 struct ifdata
*if_head
= NULL
;
282 struct ifdata
*br_head
= NULL
;
284 struct ifdata
*find_if(int if_index
)
286 struct ifdata
*p
= if_head
;
287 while (p
&& p
->if_index
!= if_index
)
292 #define ADD_TO_LIST(_list, _next, _ifc) \
294 (_ifc)->_next = (_list); \
298 #define REMOVE_FROM_LIST(_list, _next, _ifc, _error_fmt, _args...) \
300 struct ifdata **_prev = &(_list); \
301 while (*_prev && *_prev != (_ifc)) \
302 _prev = &(*_prev)->_next; \
303 if (*_prev != (_ifc)) \
304 ERROR(_error_fmt, ##_args); \
306 *_prev = (_ifc)->_next; \
309 /* Caller ensures that there isn't any ifdata with this index */
310 /* If br is NULL, new interface is a bridge, else it is a port of br */
311 struct ifdata
*create_if(int if_index
, struct ifdata
*br
)
314 TST((p
= malloc(sizeof(*p
))) != NULL
, NULL
);
316 memset(p
, 0, sizeof(*p
));
319 p
->if_index
= if_index
;
320 p
->is_bridge
= (br
== NULL
);
322 /* TODO: purge use of name, due to issue with renameing */
323 if_indextoname(if_index
, p
->name
);
326 INFO("Add bridge %s", p
->name
);
327 /* Init slave list */
334 update_bridge_stp_config(p
, &default_bridge_stp_cfg
);
335 ADD_TO_LIST(br_head
, bridge_next
, p
); /* Add to bridge list */
337 INFO("Add iface %s to bridge %s", p
->name
, br
->name
);
343 update_port_stp_config(p
, &default_port_stp_cfg
);
344 ADD_TO_LIST(br
->port_list
, port_next
, p
); /* Add to bridge port list */
351 /* Add to interface list */
352 ADD_TO_LIST(if_head
, next
, p
);
357 void delete_if(struct ifdata
*ifc
)
359 INFO("Delete iface %s", ifc
->name
);
360 if (ifc
->is_bridge
) { /* Bridge: */
362 clear_bridge_stp(ifc
);
364 while (ifc
->port_list
)
365 delete_if(ifc
->port_list
);
366 /* Remove from bridge list */
367 REMOVE_FROM_LIST(br_head
, bridge_next
, ifc
,
368 "Can't find interface ifindex %d bridge list",
371 if (ifc
->master
->stp_up
)
372 remove_port_stp(ifc
);
373 /* Remove from bridge port list */
374 REMOVE_FROM_LIST(ifc
->master
->port_list
, port_next
, ifc
,
375 "Can't find interface ifindex %d on br %d's port list",
376 ifc
->if_index
, ifc
->master
->if_index
);
379 /* Remove from bridge interface list */
380 REMOVE_FROM_LIST(if_head
, next
, ifc
,
381 "Can't find interface ifindex %d on iflist",
386 static int stp_enabled(struct ifdata
*br
)
388 char path
[40 + IFNAMSIZ
];
390 sprintf(path
, "/sys/class/net/%s/bridge/stp_state", br
->name
);
391 FILE *f
= fopen(path
, "r");
393 LOG("Open %s failed", path
);
397 ret
= fscanf(f
, "%d", &enabled
);
399 LOG("%s, stp_state parsing error", path
);
403 INFO("STP on %s state %d", br
->name
, enabled
);
405 return enabled
== 2; /* ie user mode STP */
408 static void set_br_up(struct ifdata
*br
, int up
)
410 int stp_up
= stp_enabled(br
);
411 INFO("%s was %s stp was %s", br
->name
,
413 br
->stp_up
? "up" : "down");
414 INFO("Set bridge %s %s stp %s" , br
->name
,
416 stp_up
? "up" : "down");
421 if (br
->stp_up
!= stp_up
) {
425 clear_bridge_stp(br
);
429 static void set_if_up(struct ifdata
*ifc
, int up
)
431 INFO("Port %s : %s", ifc
->name
, (up
? "up" : "down"));
434 int notify_flags
= 0;
435 const int NOTIFY_UP
= 1, NOTIFY_SPEED
= 2, NOTIFY_DUPLEX
= 4;
436 if (!up
) { /* Down */
439 notify_flags
|= NOTIFY_UP
;
442 int r
= ethtool_get_speed_duplex(ifc
->name
, &speed
, &duplex
);
443 if (r
< 0) { /* Didn't succeed */
448 duplex
= 0; /* Assume half duplex */
450 if (speed
!= ifc
->speed
) {
452 notify_flags
|= NOTIFY_SPEED
;
454 if (duplex
!= ifc
->duplex
) {
455 ifc
->duplex
= duplex
;
456 notify_flags
|= NOTIFY_DUPLEX
;
460 notify_flags
|= NOTIFY_UP
;
463 if (notify_flags
&& ifc
->master
->stp_up
) {
464 instance_begin(ifc
->master
);
466 if (notify_flags
& NOTIFY_SPEED
)
467 STP_IN_changed_port_speed(ifc
->port_index
, speed
);
468 if (notify_flags
& NOTIFY_DUPLEX
)
469 STP_IN_changed_port_duplex(ifc
->port_index
);
470 if (notify_flags
& NOTIFY_UP
)
471 STP_IN_enable_port(ifc
->port_index
, ifc
->up
);
477 /*------------------------------------------------------------*/
479 int bridge_notify(int br_index
, int if_index
, int newlink
,
482 struct ifdata
*br
= NULL
;
484 LOG("br_index %d, if_index %d, up %d running %d",
485 br_index
, if_index
, (flags
& IFF_UP
), flags
& IFF_RUNNING
);
488 br
= find_if(br_index
);
489 if (br
&& !br
->is_bridge
) {
491 ("Notification shows non bridge interface %d as bridge.",
496 br
= create_if(br_index
, NULL
);
498 ERROR("Couldn't create data for bridge interface %d",
502 /* Bridge must be up if we get such notifications */
507 struct ifdata
*ifc
= find_if(if_index
);
511 if (ifc
->is_bridge
) {
513 ("Notification shows bridge interface %d as slave of %d",
517 if (ifc
->master
!= br
) {
518 INFO("Device %d has come to bridge %d. "
519 "Missed notify for deletion from bridge %d",
520 if_index
, br_index
, ifc
->master
->if_index
);
526 ifc
= create_if(if_index
, br
);
529 ("Couldn't create data for interface %d (master %d)",
533 if (!newlink
&& !is_bridge_slave(br
->name
, ifc
->name
)) {
534 /* brctl delif generates a DELLINK, but so does ifconfig <slave> down.
535 So check and delete if it has been removed.
540 int up
= (flags
& (IFF_UP
|IFF_RUNNING
)) == (IFF_UP
|IFF_RUNNING
);
543 set_if_up(ifc
, up
); /* And speed and duplex */
544 } else { /* No br_index */
546 /* DELLINK not from bridge means interface unregistered. */
547 /* Cleanup removed bridge or removed bridge slave */
551 } else { /* This may be a new link */
553 char ifname
[IFNAMSIZ
];
554 if (if_indextoname(if_index
, ifname
)
555 && is_bridge(ifname
)) {
556 ifc
= create_if(if_index
, NULL
);
559 ("Couldn't create data for bridge interface %d",
565 if (ifc
&& !ifc
->is_bridge
&&
566 !is_bridge_slave(ifc
->master
->name
, ifc
->name
)) {
567 /* Interface might have left bridge and we might have missed deletion */
573 if (ifc
->is_bridge
) {
574 int up
= (flags
& IFF_UP
) != 0;
578 int up
= (flags
& (IFF_UP
|IFF_RUNNING
)) == (IFF_UP
|IFF_RUNNING
);
589 void bridge_bpdu_rcv(int if_index
, const unsigned char *data
, int len
)
591 struct ifdata
*ifc
= find_if(if_index
);
592 BPDU_T
*bpdu
= (BPDU_T
*) (data
+ sizeof(MAC_HEADER_T
));
594 LOG("ifindex %d, len %d", if_index
, len
);
595 if (!ifc
|| !ifc
->master
)
599 TST(ifc
->master
->stp_up
,);
600 TST(len
> sizeof(MAC_HEADER_T
) + sizeof(ETH_HEADER_T
) + sizeof(BPDU_HEADER_T
),);
602 /* Do some validation */
603 if (bpdu
->hdr
.protocol
[0] || bpdu
->hdr
.protocol
[1])
606 switch (bpdu
->hdr
.bpdu_type
) {
609 case BPDU_CONFIG_TYPE
:
611 /* 802.1w doesn't ask for this */
612 // TST(ntohs(*(uint16_t*)bpdu.body.message_age)
613 // < ntohs(*(uint16_t*)bpdu.body.max_age), );
614 TST(memcmp(bpdu
->body
.bridge_id
, &ifc
->master
->bridge_id
, 8) != 0
615 || (ntohs(*(uint16_t *) bpdu
->body
.port_id
) & 0xfff) !=
618 case BPDU_TOPO_CHANGE_TYPE
:
621 LOG("Receive unknown bpdu type %x", bpdu
->hdr
.bpdu_type
);
625 // dump_hex(data, len);
626 instance_begin(ifc
->master
);
627 int r
= STP_IN_rx_bpdu(0, ifc
->port_index
, bpdu
, len
);
629 ERROR("STP_IN_rx_bpdu on port %s returned %s", ifc
->name
,
630 STP_IN_get_error_explanation(r
));
634 void bridge_one_second(void)
638 for (br
= br_head
; br
; br
= br
->bridge_next
) {
646 /* To get information about port changes when bridge is down */
647 /* But won't work so well since we will not sense deletions */
648 static int count
= 0;
651 bridge_get_configuration();
655 /* Implementing STP_OUT functions */
657 int flush_port(char *sys_name
)
659 FILE *f
= fopen(sys_name
, "w");
660 TSTM(f
, -1, "Couldn't open flush file %s for write.", sys_name
);
661 int r
= fwrite("1", 1, 1, f
);
668 STP_OUT_flush_lt(IN
int port_index
, IN
int vlan_id
,
669 IN LT_FLASH_TYPE_T type
, IN
char *reason
)
671 LOG("port index %d, flash type %d, reason %s", port_index
, type
,
673 TST(vlan_id
== 0, 0);
676 if (port_index
== 0) { /* i.e. passed port_index was 0 */
677 sprintf(fname
, "/sys/class/net/%s/bridge/flush",
680 } else if (type
== LT_FLASH_ONLY_THE_PORT
) {
681 struct ifdata
*port
= find_port(port_index
);
682 TST(port
!= NULL
, 0);
683 sprintf(fname
, "/sys/class/net/%s/brif/%s/flush",
684 current_br
->name
, port
->name
);
686 } else if (type
== LT_FLASH_ALL_PORTS_EXCLUDE_THIS
) {
688 for (port
= current_br
->port_list
; port
; port
= port
->port_next
) {
689 if (port
->port_index
!= port_index
) {
691 "/sys/class/net/%s/brif/%s/flush",
692 current_br
->name
, port
->name
);
702 void /* for bridge id calculation */ STP_OUT_get_port_mac(IN
int port_index
,
706 LOG("port index %d", port_index
);
707 struct ifdata
*port
= find_port(port_index
);
709 get_hwaddr(port
->name
, mac
);
712 unsigned long STP_OUT_get_port_oper_speed(IN
unsigned int port_index
)
714 LOG("port index %d", port_index
);
715 struct ifdata
*port
= find_port(port_index
);
716 TST(port
!= NULL
, 0);
717 LOG("Speed: %d", port
->speed
);
721 int /* 1- Up, 0- Down */ STP_OUT_get_port_link_status(IN
int port_index
)
723 LOG("port index %d", port_index
);
724 struct ifdata
*port
= find_port(port_index
);
725 TST(port
!= NULL
, 0);
726 LOG("Link status: %d", port
->up
);
730 int /* 1- Full, 0- Half */ STP_OUT_get_duplex(IN
int port_index
)
732 LOG("port index %d", port_index
);
733 struct ifdata
*port
= find_port(port_index
);
734 TST(port
!= NULL
, 0);
735 LOG("Duplex: %d", port
->duplex
);
740 STP_OUT_set_port_state(IN
int port_index
, IN
int vlan_id
,
741 IN RSTP_PORT_STATE state
)
743 LOG("port index %d, state %d", port_index
, state
);
744 struct ifdata
*port
= find_port(port_index
);
745 TST(port
!= NULL
, 0);
746 TST(vlan_id
== 0, 0);
750 case UID_PORT_DISCARDING
:
751 br_state
= BR_STATE_BLOCKING
;
753 case UID_PORT_LEARNING
:
754 br_state
= BR_STATE_LEARNING
;
756 case UID_PORT_FORWARDING
:
757 br_state
= BR_STATE_FORWARDING
;
760 fprintf(stderr
, "set_port_state: Unexpected state %d\n", state
);
764 bridge_set_state(port
->if_index
, br_state
);
768 int STP_OUT_set_hardware_mode(int vlan_id
, UID_STP_MODE_T mode
)
770 LOG("vlan id %d, mode %d", vlan_id
, mode
);
775 STP_OUT_tx_bpdu(IN
int port_index
, IN
int vlan_id
,
776 IN
unsigned char *bpdu
, IN
size_t bpdu_len
)
778 LOG("port index %d, len %zd", port_index
, bpdu_len
);
779 struct ifdata
*port
= find_port(port_index
);
780 TST(port
!= NULL
, 0);
781 TST(vlan_id
== 0, 0);
783 packet_send(port
->if_index
, bpdu
,
784 bpdu_len
+ sizeof(MAC_HEADER_T
) + sizeof(ETH_HEADER_T
));
788 const char *STP_OUT_get_port_name(IN
int port_index
)
790 LOG("port index %d", port_index
);
791 struct ifdata
*port
= find_port(port_index
);
792 TST(port
!= NULL
, 0);
796 int STP_OUT_get_init_stpm_cfg(IN
int vlan_id
, INOUT UID_STP_CFG_T
* cfg
)
799 TST(vlan_id
== 0, 0);
801 cfg
->bridge_priority
= current_br
->bridge_priority
;
802 cfg
->max_age
= current_br
->max_age
;
803 cfg
->hello_time
= current_br
->hello_time
;
804 cfg
->forward_delay
= current_br
->forward_delay
;
805 cfg
->force_version
= current_br
->force_version
;
811 STP_OUT_get_init_port_cfg(IN
int vlan_id
,
812 IN
int port_index
, INOUT UID_STP_PORT_CFG_T
* cfg
)
814 LOG("port index %d", port_index
);
815 struct ifdata
*port
= find_port(port_index
);
816 TST(port
!= NULL
, 0);
817 TST(vlan_id
== 0, 0);
819 cfg
->port_priority
= port
->port_priority
;
820 cfg
->admin_non_stp
= port
->admin_non_stp
;
821 cfg
->admin_edge
= port
->admin_edge
;
822 cfg
->admin_port_path_cost
= port
->admin_port_path_cost
;
823 cfg
->admin_point2point
= port
->admin_point2point
;
828 extern void stp_trace(const char *fmt
, ...)
832 vDprintf(LOG_LEVEL_RSTPLIB
, fmt
, ap
);
836 /* Commands and status */
837 #include "ctl_functions.h"
839 #define CTL_CHECK_BRIDGE \
840 struct ifdata *br = find_if(br_index); \
841 if (br == NULL || !br->is_bridge) return Err_Interface_not_a_bridge; \
842 if (!br->do_stp) return Err_Bridge_RSTP_not_enabled; \
843 if (!br->stp_up) return Err_Bridge_is_down; \
846 #define CTL_CHECK_BRIDGE_PORT \
848 struct ifdata *port = find_if(port_index); \
849 if (port == NULL || port->is_bridge || port->master != br) \
850 return Err_Port_does_not_belong_to_bridge; \
853 int CTL_enable_bridge_rstp(int br_index
, int enable
)
855 INFO("bridge %d, enable %d", br_index
, enable
);
859 struct ifdata
*br
= find_if(br_index
);
861 char ifname
[IFNAMSIZ
];
862 if (if_indextoname(br_index
, ifname
) && is_bridge(ifname
))
863 br
= create_if(br_index
, NULL
);
865 if (br
== NULL
|| !br
->is_bridge
)
866 return Err_Interface_not_a_bridge
;
867 if (br
->do_stp
!= enable
) {
870 r
= enable
? init_bridge_stp(br
)
871 : (clear_bridge_stp(br
), 0);
876 int CTL_get_bridge_state(int br_index
,
877 UID_STP_CFG_T
* cfg
, UID_STP_STATE_T
* state
)
879 LOG("bridge %d", br_index
);
883 r
= STP_IN_stpm_get_state(0, state
);
885 ERROR("Error getting bridge state for %d: %s", br_index
,
886 STP_IN_get_error_explanation(r
));
890 r
= STP_IN_stpm_get_cfg(0, cfg
);
892 ERROR("Error getting bridge config for %d: %s", br_index
,
893 STP_IN_get_error_explanation(r
));
901 int CTL_set_bridge_config(int br_index
, UID_STP_CFG_T
* cfg
)
903 INFO("bridge %d, flags %#lx", br_index
, cfg
->field_mask
);
907 r
= STP_IN_stpm_set_cfg(0, NULL
, cfg
);
909 ERROR("Error setting bridge config for %d: %s", br_index
,
910 STP_IN_get_error_explanation(r
));
915 /* Change init config in ifdata so it will be applied if we
916 disable and enable rstp */
917 update_bridge_stp_config(br
, cfg
);
921 int CTL_get_port_state(int br_index
, int port_index
,
922 UID_STP_PORT_CFG_T
* cfg
, UID_STP_PORT_STATE_T
* state
)
924 LOG("bridge %d port %d", br_index
, port_index
);
925 CTL_CHECK_BRIDGE_PORT
;
928 state
->port_no
= port
->port_index
;
929 r
= STP_IN_port_get_state(0, state
);
931 ERROR("Error getting port state for port %d, bridge %d: %s",
932 port
->port_index
, br_index
,
933 STP_IN_get_error_explanation(r
));
937 r
= STP_IN_port_get_cfg(0, port
->port_index
, cfg
);
939 ERROR("Error getting port config for port %d, bridge %d: %s",
940 port
->port_index
, br_index
,
941 STP_IN_get_error_explanation(r
));
950 int CTL_set_port_config(int br_index
, int port_index
, UID_STP_PORT_CFG_T
* cfg
)
952 INFO("bridge %d, port %d, flags %#lx", br_index
, port_index
,
954 CTL_CHECK_BRIDGE_PORT
;
957 r
= STP_IN_set_port_cfg(0, port
->port_index
, cfg
);
959 ERROR("Error setting port config for port %d, bridge %d: %s",
960 port
->port_index
, br_index
,
961 STP_IN_get_error_explanation(r
));
966 /* Change init config in ifdata so it will be applied if we
967 disable and enable rstp */
968 update_port_stp_config(port
, cfg
);
972 int CTL_set_debug_level(int level
)
974 INFO("level %d", level
);
979 #undef CTL_CHECK_BRIDGE_PORT
980 #undef CTL_CHECK_BRIDGE