2 * mstp.c State machines from IEEE 802.1Q-2005
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Vitalii Demianets <vitas@nppfactor.kiev.ua>
12 /* NOTE: The standard messes up Hello_Time timer management.
13 * The portTimes and msgTimes structures have it, while
14 * designatedTimes, rootTimes and BridgeTimes do not!
15 * And there are places, where standard says:
16 * "portTimes = designatedTimes" (13.32)
17 * "rootTimes = portTimes" (13.26.23)
19 * For now I decide: All structures will hold Hello_Time,
20 * because in 802.1D they do.
21 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
24 /* 802.1Q-2005 does not define but widely use variable name newInfoXst.
25 * From the 802.1s I can guess that it means:
26 * - "newInfo" when tree is CIST;
27 * - "newInfoMsti" when tree is not CIST (is MSTI).
28 * But that is only a guess and I could be wrong here ;)
32 #include <linux/if_bridge.h>
33 #include <asm/byteorder.h>
38 static void PTSM_tick(port_t
*prt
);
39 static void TCSM_run(per_tree_port_t
*ptp
);
40 static void BDSM_begin(port_t
*prt
);
41 static void br_state_machines_begin(bridge_t
*br
);
42 static void prt_state_machines_begin(port_t
*prt
);
43 static void tree_state_machines_begin(tree_t
*tree
);
44 static void br_state_machines_run(bridge_t
*br
);
46 #define FOREACH_PORT_IN_BRIDGE(port, bridge) \
47 list_for_each_entry((port), &(bridge)->ports, br_list)
48 #define FOREACH_TREE_IN_BRIDGE(tree, bridge) \
49 list_for_each_entry((tree), &(bridge)->trees, bridge_list)
50 #define FOREACH_PTP_IN_TREE(ptp, tree) \
51 list_for_each_entry((ptp), &(tree)->ports, tree_list)
52 #define FOREACH_PTP_IN_PORT(ptp, port) \
53 list_for_each_entry((ptp), &(port)->trees, port_list)
55 /* 17.20.11 of 802.1D */
56 #define rstpVersion(br) ((br)->ForceProtocolVersion >= protoRSTP)
59 * Recalculate configuration digest. (13.7)
61 static void RecalcConfigDigest(bridge_t
*br
)
63 __be16 vid2mstid
[MAX_VID
+ 2];
64 unsigned char mstp_key
[] = HMAC_KEY
;
67 vid2mstid
[0] = vid2mstid
[MAX_VID
+ 1] = 0;
68 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
69 vid2mstid
[vid
] = br
->fid2mstid
[br
->vid2fid
[vid
]];
71 hmac_md5((void *)vid2mstid
, sizeof(vid2mstid
), mstp_key
, sizeof(mstp_key
),
72 br
->MstConfigId
.s
.configuration_digest
);
76 * 13.37.1 - Table 13-3
78 static __u32
compute_pcost(int speed
)
82 return (speed
< 20000000) ? 20000000 / speed
: 1;
87 static tree_t
* create_tree(bridge_t
*br
, __u8
*macaddr
, __be16 MSTID
)
89 /* Initialize all fields except anchor */
90 tree_t
*tree
= calloc(1, sizeof(*tree
));
93 ERROR_BRNAME(br
, "Out of memory");
98 INIT_LIST_HEAD(&tree
->ports
);
100 memcpy(tree
->BridgeIdentifier
.s
.mac_address
, macaddr
, ETH_ALEN
);
101 /* 0x8000 = default bridge priority (17.14 of 802.1D) */
102 tree
->BridgeIdentifier
.s
.priority
= __constant_cpu_to_be16(0x8000) | MSTID
;
103 assign(tree
->BridgePriority
.RootID
, tree
->BridgeIdentifier
);
104 assign(tree
->BridgePriority
.RRootID
, tree
->BridgeIdentifier
);
105 assign(tree
->BridgePriority
.DesignatedBridgeID
, tree
->BridgeIdentifier
);
107 assign(tree
->BridgeTimes
.remainingHops
, br
->MaxHops
);
108 assign(tree
->BridgeTimes
.Forward_Delay
, br
->Forward_Delay
);
109 assign(tree
->BridgeTimes
.Max_Age
, br
->Max_Age
);
110 assign(tree
->BridgeTimes
.Message_Age
, (__u8
)0);
111 /* 17.14 of 802.1D */
112 assign(tree
->BridgeTimes
.Hello_Time
, (__u8
)2);
114 /* 12.8.1.1.3.(b,c,d) */
115 tree
->time_since_topology_change
= 0;
116 tree
->topology_change_count
= 0;
117 tree
->topology_change
= false; /* since all tcWhile are initialized to 0 */
119 /* The following are initialized in BEGIN state:
120 * - rootPortId, rootPriority, rootTimes: in Port Role Selection SM
125 static per_tree_port_t
* create_ptp(tree_t
*tree
, port_t
*prt
)
127 /* Initialize all fields except anchors */
128 per_tree_port_t
*ptp
= calloc(1, sizeof(*ptp
));
131 ERROR_PRTNAME(prt
->bridge
, prt
, "Out of memory");
136 ptp
->MSTID
= tree
->MSTID
;
138 ptp
->state
= BR_STATE_DISABLED
;
141 ptp
->updtInfo
= false;
142 /* 0x80 = default port priority (17.14 of 802.1D) */
143 ptp
->portId
= __constant_cpu_to_be16(0x8000) | prt
->port_number
;
144 ptp
->master
= false; /* 13.24.5 */
145 assign(ptp
->AdminInternalPortPathCost
, 0u);
146 assign(ptp
->InternalPortPathCost
, compute_pcost(GET_PORT_SPEED(prt
)));
147 /* 802.1Q leaves portPriority and portTimes uninitialized */
148 assign(ptp
->portPriority
, tree
->BridgePriority
);
149 assign(ptp
->portTimes
, tree
->BridgeTimes
);
151 ptp
->calledFromFlushRoutine
= false;
153 /* The following are initialized in BEGIN state:
154 * - rcvdMsg: in Port Receive SM
155 * - fdWhile, rrWhile, rbWhile, role, learn, forward,
156 * sync, synced, reRoot: in Port Role Transitions SM
157 * - tcWhile, fdbFlush: Topology Change SM
158 * - rcvdInfoWhile, proposed, proposing, agree, agreed,
159 * infoIs, reselect, selected: Port Information SM
160 * - forwarding, learning: Port State Transition SM
161 * - selectedRole, designatedPriority, designatedTimes: Port Role Selection SM
164 /* The following are not initialized (set to zero thanks to calloc):
174 /* External events */
176 bool MSTP_IN_bridge_create(bridge_t
*br
, __u8
*macaddr
)
180 /* Initialize all fields except sysdeps and anchor */
181 INIT_LIST_HEAD(&br
->ports
);
182 INIT_LIST_HEAD(&br
->trees
);
183 br
->bridgeEnabled
= false;
184 memset(br
->vid2fid
, 0, sizeof(br
->vid2fid
));
185 memset(br
->fid2mstid
, 0, sizeof(br
->fid2mstid
));
186 assign(br
->MstConfigId
.s
.selector
, (__u8
)0);
187 sprintf(br
->MstConfigId
.s
.configuration_name
,
188 "%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
189 macaddr
[0], macaddr
[1], macaddr
[2],
190 macaddr
[3], macaddr
[4], macaddr
[5]);
191 assign(br
->MstConfigId
.s
.revision_level
, __constant_cpu_to_be16(0));
192 RecalcConfigDigest(br
); /* set br->MstConfigId.s.configuration_digest */
193 br
->ForceProtocolVersion
= protoMSTP
;
194 assign(br
->MaxHops
, (__u8
)20); /* 13.37.3 */
195 assign(br
->Forward_Delay
, (__u8
)15); /* 17.14 of 802.1D */
196 assign(br
->Max_Age
, (__u8
)20); /* 17.14 of 802.1D */
197 assign(br
->Transmit_Hold_Count
, 6u); /* 17.14 of 802.1D */
198 assign(br
->Migrate_Time
, 3u); /* 17.14 of 802.1D */
199 assign(br
->rapidAgeingWhile
, 0u);
204 if(!(cist
= create_tree(br
, macaddr
, 0)))
206 list_add_tail(&cist
->bridge_list
, &br
->trees
);
208 br_state_machines_begin(br
);
212 bool MSTP_IN_port_create_and_add_tail(port_t
*prt
, __u16 portno
)
215 per_tree_port_t
*ptp
, *nxt
;
216 bridge_t
*br
= prt
->bridge
;
218 /* Initialize all fields except sysdeps and bridge */
219 INIT_LIST_HEAD(&prt
->trees
);
220 prt
->port_number
= __cpu_to_be16(portno
);
222 assign(prt
->AdminExternalPortPathCost
, 0u);
223 /* Default for operP2P is false because by default AdminP2P
224 * says to auto-detect p2p state, and it is derived from duplex
225 * and initially port is in down state and in this down state
226 * duplex is set to false (half) */
227 prt
->AdminP2P
= p2pAuto
;
228 prt
->operPointToPointMAC
= false;
229 prt
->portEnabled
= false;
230 prt
->infoInternal
= false;
231 prt
->rcvdInternal
= false;
232 prt
->rcvdTcAck
= false;
233 prt
->rcvdTcn
= false;
234 prt
->restrictedRole
= false; /* 13.25.14 */
235 prt
->restrictedTcn
= false; /* 13.25.15 */
236 assign(prt
->ExternalPortPathCost
, MAX_PATH_COST
); /* 13.37.1 */
237 prt
->AdminEdgePort
= false; /* 13.25 */
238 prt
->AutoEdge
= true; /* 13.25 */
240 /* The following are initialized in BEGIN state:
241 * - mdelayWhile. mcheck, sendRSTP: in Port Protocol Migration SM
242 * - helloWhen, newInfo, newInfoMsti, txCount: in Port Transmit SM
243 * - edgeDelayWhile, rcvdBpdu, rcvdRSTP, rcvdSTP : in Port Receive SM
244 * - operEdge: in Bridge Detection SM
245 * - tcAck: in Topology Change SM
248 /* Create PerTreePort structures for all existing trees */
249 FOREACH_TREE_IN_BRIDGE(tree
, br
)
251 if(!(ptp
= create_ptp(tree
, prt
)))
253 /* Remove and free all previously created entries in port's list */
254 list_for_each_entry_safe(ptp
, nxt
, &prt
->trees
, port_list
)
256 list_del(&ptp
->port_list
);
257 list_del(&ptp
->tree_list
);
262 list_add_tail(&ptp
->port_list
, &prt
->trees
);
263 list_add_tail(&ptp
->tree_list
, &tree
->ports
);
266 /* Add new port to the tail of the list in the bridge */
267 /* NOTE: if one wants add port NOT to the tail of the list of ports,
268 * one should revise above loop (FOREACH_TREE_IN_BRIDGE)
269 * because it heavily depends on the fact that port is added to the tail.
271 list_add_tail(&prt
->br_list
, &br
->ports
);
273 prt_state_machines_begin(prt
);
277 void MSTP_IN_delete_port(port_t
*prt
)
279 per_tree_port_t
*ptp
, *nxt
;
280 bridge_t
*br
= prt
->bridge
;
284 prt
->portEnabled
= false;
285 br_state_machines_run(br
);
288 list_for_each_entry_safe(ptp
, nxt
, &prt
->trees
, port_list
)
290 list_del(&ptp
->port_list
);
291 list_del(&ptp
->tree_list
);
295 br_state_machines_run(br
);
298 void MSTP_IN_delete_bridge(bridge_t
*br
)
300 tree_t
*tree
, *nxt_tree
;
301 port_t
*prt
, *nxt_prt
;
303 br
->bridgeEnabled
= false;
305 /* We SHOULD first delete all ports and only THEN delete all tree_t
306 * structures as the tree_t structure contains the head for the per-port
307 * list of tree data (tree_t.ports).
308 * If this list_head will be deleted before all the per_tree_ports
309 * bad things will happen ;)
312 list_for_each_entry_safe(prt
, nxt_prt
, &br
->ports
, br_list
)
314 list_del(&prt
->br_list
);
315 MSTP_IN_delete_port(prt
);
319 list_for_each_entry_safe(tree
, nxt_tree
, &br
->trees
, bridge_list
)
321 list_del(&tree
->bridge_list
);
326 void MSTP_IN_set_bridge_address(bridge_t
*br
, __u8
*macaddr
)
329 bool changed
= false;
331 FOREACH_TREE_IN_BRIDGE(tree
, br
)
333 if(0 == memcmp(tree
->BridgeIdentifier
.s
.mac_address
, macaddr
, ETH_ALEN
))
336 memcpy(tree
->BridgeIdentifier
.s
.mac_address
, macaddr
, ETH_ALEN
);
337 tree
->BridgePriority
.RootID
= tree
->BridgePriority
.RRootID
=
338 tree
->BridgePriority
.DesignatedBridgeID
= tree
->BridgeIdentifier
;
342 br_state_machines_begin(br
);
345 void MSTP_IN_set_bridge_enable(bridge_t
*br
, bool up
)
347 if(br
->bridgeEnabled
== up
)
349 br
->bridgeEnabled
= up
;
350 br_state_machines_begin(br
);
353 void MSTP_IN_set_port_enable(port_t
*prt
, bool up
, int speed
, int duplex
)
355 __u32 computed_pcost
, new_ExternalPathCost
, new_InternalPathCost
;
356 per_tree_port_t
*ptp
;
358 bool changed
= false;
362 computed_pcost
= compute_pcost(speed
);
363 new_ExternalPathCost
= (0 == prt
->AdminExternalPortPathCost
) ?
365 : prt
->AdminExternalPortPathCost
;
366 if(prt
->ExternalPortPathCost
!= new_ExternalPathCost
)
368 assign(prt
->ExternalPortPathCost
, new_ExternalPathCost
);
371 FOREACH_PTP_IN_PORT(ptp
, prt
)
373 new_InternalPathCost
= (0 == ptp
->AdminInternalPortPathCost
) ?
375 : ptp
->AdminInternalPortPathCost
;
376 if(ptp
->InternalPortPathCost
!= new_InternalPathCost
)
378 assign(ptp
->InternalPortPathCost
, new_InternalPathCost
);
383 switch(prt
->AdminP2P
)
396 if(prt
->operPointToPointMAC
!= new_p2p
)
398 prt
->operPointToPointMAC
= new_p2p
;
402 if(!prt
->portEnabled
)
404 prt
->portEnabled
= true;
412 prt
->portEnabled
= false;
418 br_state_machines_run(prt
->bridge
);
421 void MSTP_IN_one_second(bridge_t
*br
)
428 if(!br
->bridgeEnabled
)
431 FOREACH_TREE_IN_BRIDGE(tree
, br
)
432 if(!(tree
->topology_change
))
433 ++(tree
->time_since_topology_change
);
435 FOREACH_PORT_IN_BRIDGE(prt
, br
)
437 /* support for rapid ageing */
438 if(br
->rapidAgeingWhile
)
440 if((--(br
->rapidAgeingWhile
)) == 0)
441 MSTP_OUT_set_ageing_time(br
, -1);
444 br_state_machines_run(br
);
447 void MSTP_IN_all_fids_flushed(per_tree_port_t
*ptp
)
449 bridge_t
*br
= ptp
->port
->bridge
;
450 ptp
->fdbFlush
= false;
451 if(!br
->bridgeEnabled
)
453 if(!ptp
->calledFromFlushRoutine
)
456 br_state_machines_run(br
);
460 /* NOTE: bpdu pointer is unaligned, but it works because
461 * bpdu_t is packed. Don't try to cast bpdu to non-packed type ;)
463 void MSTP_IN_rx_bpdu(port_t
*prt
, bpdu_t
*bpdu
, int size
)
466 bridge_t
*br
= prt
->bridge
;
468 if(!br
->bridgeEnabled
)
470 INFO_PRTNAME(br
, prt
, "Received BPDU while bridge is disabled");
476 ERROR_PRTNAME(br
, prt
, "Port hasn't processed previous BPDU");
480 /* 14.4 Validation */
481 if((TCN_BPDU_SIZE
> size
) || (0 != bpdu
->protocolIdentifier
))
483 bpdu_validation_failed
:
484 INFO_PRTNAME(br
, prt
, "BPDU validation failed");
487 switch(bpdu
->bpduType
)
492 bpdu
->protocolVersion
= protoSTP
;
493 LOG_PRTNAME(br
, prt
, "received TCN BPDU");
497 if(CONFIG_BPDU_SIZE
> size
)
498 goto bpdu_validation_failed
;
499 /* Valid Config BPDU */
500 bpdu
->protocolVersion
= protoSTP
;
501 LOG_PRTNAME(br
, prt
, "received Config BPDU");
504 if(protoRSTP
== bpdu
->protocolVersion
)
506 if(RST_BPDU_SIZE
> size
)
507 goto bpdu_validation_failed
;
509 /* bpdu->protocolVersion = protoRSTP; */
510 LOG_PRTNAME(br
, prt
, "received RST BPDU");
513 if(protoMSTP
> bpdu
->protocolVersion
)
514 goto bpdu_validation_failed
;
515 /* Yes, 802.1Q-2005 says here to check if it contains
516 * "35 or more octets", not 36! (see 14.4.d).1) )
517 * That's why I check size against CONFIG_BPDU_SIZE
518 * and not RST_BPDU_SIZE.
520 if(CONFIG_BPDU_SIZE
> size
)
521 goto bpdu_validation_failed
;
522 mstis_size
= __be16_to_cpu(bpdu
->version3_len
)
523 - MST_BPDU_VER3LEN_WO_MSTI_MSGS
;
524 if((MST_BPDU_SIZE_WO_MSTI_MSGS
> size
) || (0 != bpdu
->version1_len
)
526 || ((MAX_STANDARD_MSTIS
* sizeof(msti_configuration_message_t
))
528 || (0 != (mstis_size
% sizeof(msti_configuration_message_t
)))
532 bpdu
->protocolVersion
= protoRSTP
;
533 LOG_PRTNAME(br
, prt
, "received RST BPDU");
538 bpdu
->protocolVersion
= protoMSTP
;
539 prt
->rcvdBpduNumOfMstis
= mstis_size
540 / sizeof(msti_configuration_message_t
);
541 LOG_PRTNAME(br
, prt
, "received MST BPDU with %d MSTIs",
542 prt
->rcvdBpduNumOfMstis
);
545 goto bpdu_validation_failed
;
548 assign(prt
->rcvdBpduData
, *bpdu
);
549 prt
->rcvdBpdu
= true;
551 br_state_machines_run(br
);
554 /* 12.8.1.1 Read CIST Bridge Protocol Parameters */
555 void MSTP_IN_get_cist_bridge_status(bridge_t
*br
, CIST_BridgeStatus
*status
)
557 tree_t
*cist
= GET_CIST_TREE(br
);
558 assign(status
->bridge_id
, cist
->BridgeIdentifier
);
559 assign(status
->time_since_topology_change
,
560 cist
->time_since_topology_change
);
561 assign(status
->topology_change_count
, cist
->topology_change_count
);
562 status
->topology_change
= cist
->topology_change
;
563 assign(status
->designated_root
, cist
->rootPriority
.RootID
);
564 assign(status
->root_path_cost
,
565 __be32_to_cpu(cist
->rootPriority
.ExtRootPathCost
));
566 assign(status
->regional_root
, cist
->rootPriority
.RRootID
);
567 assign(status
->internal_path_cost
,
568 __be32_to_cpu(cist
->rootPriority
.IntRootPathCost
));
569 assign(status
->root_port_id
, cist
->rootPortId
);
570 assign(status
->root_max_age
, cist
->rootTimes
.Max_Age
);
571 assign(status
->root_forward_delay
, cist
->rootTimes
.Forward_Delay
);
572 assign(status
->bridge_max_age
, br
->Max_Age
);
573 assign(status
->bridge_forward_delay
, br
->Forward_Delay
);
574 assign(status
->max_hops
, br
->MaxHops
);
575 assign(status
->tx_hold_count
, br
->Transmit_Hold_Count
);
576 status
->protocol_version
= br
->ForceProtocolVersion
;
577 status
->enabled
= br
->bridgeEnabled
;
580 /* 12.8.1.2 Read MSTI Bridge Protocol Parameters */
581 void MSTP_IN_get_msti_bridge_status(tree_t
*tree
, MSTI_BridgeStatus
*status
)
583 assign(status
->bridge_id
, tree
->BridgeIdentifier
);
584 assign(status
->time_since_topology_change
,
585 tree
->time_since_topology_change
);
586 assign(status
->topology_change_count
, tree
->topology_change_count
);
587 status
->topology_change
= tree
->topology_change
;
588 assign(status
->regional_root
, tree
->rootPriority
.RRootID
);
589 assign(status
->internal_path_cost
,
590 __be32_to_cpu(tree
->rootPriority
.IntRootPathCost
));
591 assign(status
->root_port_id
, tree
->rootPortId
);
594 /* 12.8.1.3 Set CIST Bridge Protocol Parameters */
595 int MSTP_IN_set_cist_bridge_config(bridge_t
*br
, CIST_BridgeConfig
*cfg
)
597 bool changed
, changedBridgeTimes
, init
;
599 __u8 new_forward_delay
, new_max_age
;
602 per_tree_port_t
*ptp
;
604 /* Firstly, validation */
605 if(cfg
->set_bridge_max_age
)
607 new_max_age
= cfg
->bridge_max_age
;
608 if((6 > new_max_age
) || (40 < new_max_age
))
611 "Bridge Max Age must be between 6 and 40 seconds");
616 new_max_age
= br
->Max_Age
;
618 if(cfg
->set_bridge_forward_delay
)
620 new_forward_delay
= cfg
->bridge_forward_delay
;
621 if((4 > new_forward_delay
) || (30 < new_forward_delay
))
624 "Bridge Forward Delay must be between 4 and 30 seconds");
629 new_forward_delay
= br
->Forward_Delay
;
631 if(cfg
->set_bridge_max_age
|| cfg
->set_bridge_forward_delay
)
633 if((2 * (new_forward_delay
- 1)) < new_max_age
)
635 ERROR_BRNAME(br
, "Configured Bridge Times don't meet "
636 "2 * (Bridge Foward Delay - 1 second) >= Bridge Max Age");
641 if(cfg
->set_protocol_version
)
643 switch(cfg
->protocol_version
)
650 ERROR_BRNAME(br
, "Bad protocol version (%d)",
651 cfg
->protocol_version
);
656 if(cfg
->set_tx_hold_count
)
658 if((1 > cfg
->tx_hold_count
) || (10 < cfg
->tx_hold_count
))
661 "Transmit Hold Count must be between 1 and 10 seconds");
666 if(cfg
->set_max_hops
)
668 if((6 > cfg
->max_hops
) || (40 < cfg
->max_hops
))
670 ERROR_BRNAME(br
, "Bridge Max Hops must be between 6 and 40");
678 /* Secondly, do set */
679 changed
= changedBridgeTimes
= init
= false;
681 if(cfg
->set_bridge_max_age
|| cfg
->set_bridge_forward_delay
)
683 if(cmp(new_max_age
, !=, br
->Max_Age
)
684 || cmp(new_forward_delay
, !=, br
->Forward_Delay
)
687 assign(br
->Max_Age
, new_max_age
);
688 assign(br
->Forward_Delay
, new_forward_delay
);
689 changed
= changedBridgeTimes
= true;
693 if((cfg
->set_protocol_version
)
694 && (cfg
->protocol_version
!= br
->ForceProtocolVersion
)
697 br
->ForceProtocolVersion
= cfg
->protocol_version
;
698 changed
= init
= true;
701 if(cfg
->set_tx_hold_count
)
703 if(cfg
->tx_hold_count
!= br
->Transmit_Hold_Count
)
705 assign(br
->Transmit_Hold_Count
, cfg
->tx_hold_count
);
706 FOREACH_PORT_IN_BRIDGE(prt
, br
)
707 assign(prt
->txCount
, 0u);
712 if(cfg
->set_max_hops
)
714 if(cfg
->max_hops
!= br
->MaxHops
)
716 assign(br
->MaxHops
, cfg
->max_hops
);
717 changed
= changedBridgeTimes
= true;
721 /* Thirdly, finalize changes */
722 if(changedBridgeTimes
)
724 FOREACH_TREE_IN_BRIDGE(tree
, br
)
726 assign(tree
->BridgeTimes
.remainingHops
, br
->MaxHops
);
727 assign(tree
->BridgeTimes
.Forward_Delay
, br
->Forward_Delay
);
728 assign(tree
->BridgeTimes
.Max_Age
, br
->Max_Age
);
729 /* Comment found in rstpd by Srinivas Aji:
730 * Do this for any change in BridgeTimes.
731 * Otherwise we fail UNH rstp.op_D test 3.2 since when administratively
732 * setting BridgeForwardDelay, etc, the values don't propagate from
733 * rootTimes to designatedTimes immediately without this change.
735 FOREACH_PTP_IN_TREE(ptp
, tree
)
737 ptp
->selected
= false;
738 ptp
->reselect
= true;
743 if(changed
&& br
->bridgeEnabled
)
746 br_state_machines_begin(br
);
748 br_state_machines_run(br
);
754 /* 12.8.1.4 Set MSTI Bridge Protocol Parameters */
755 int MSTP_IN_set_msti_bridge_config(tree_t
*tree
, __u8 bridge_priority
)
757 per_tree_port_t
*ptp
;
760 if(15 < bridge_priority
)
762 ERROR_BRNAME(tree
->bridge
,
763 "MSTI %hu: Bridge Priority must be between 0 and 15",
764 __be16_to_cpu(tree
->MSTID
));
768 valuePri
= bridge_priority
<< 4;
769 if(GET_PRIORITY_FROM_IDENTIFIER(tree
->BridgeIdentifier
) == valuePri
)
771 SET_PRIORITY_IN_IDENTIFIER(valuePri
, tree
->BridgeIdentifier
);
772 tree
->BridgePriority
.RootID
= tree
->BridgePriority
.RRootID
=
773 tree
->BridgePriority
.DesignatedBridgeID
= tree
->BridgeIdentifier
;
774 /* 12.8.1.4.4 do not require reselect, but I think it is needed,
775 * because 12.8.1.3.4.c) requires it */
776 FOREACH_PTP_IN_TREE(ptp
, tree
)
778 ptp
->selected
= false;
779 ptp
->reselect
= true;
784 /* 12.8.2.1 Read CIST Port Parameters */
785 void MSTP_IN_get_cist_port_status(port_t
*prt
, CIST_PortStatus
*status
)
787 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
789 status
->uptime
= (signed int)((prt
->bridge
)->uptime
)
790 - (signed int)(cist
->start_time
);
791 status
->state
= cist
->state
;
792 assign(status
->port_id
, cist
->portId
);
793 assign(status
->admin_external_port_path_cost
,
794 prt
->AdminExternalPortPathCost
);
795 assign(status
->external_port_path_cost
, prt
->ExternalPortPathCost
);
796 assign(status
->designated_root
, cist
->portPriority
.RootID
);
797 assign(status
->designated_external_cost
,
798 __be32_to_cpu(cist
->portPriority
.ExtRootPathCost
));
799 assign(status
->designated_bridge
, cist
->portPriority
.DesignatedBridgeID
);
800 assign(status
->designated_port
, cist
->portPriority
.DesignatedPortID
);
801 assign(status
->designated_regional_root
, cist
->portPriority
.RRootID
);
802 assign(status
->designated_internal_cost
,
803 __be32_to_cpu(cist
->portPriority
.IntRootPathCost
));
804 status
->tc_ack
= prt
->tcAck
;
805 assign(status
->port_hello_time
, cist
->portTimes
.Hello_Time
);
806 status
->admin_edge_port
= prt
->AdminEdgePort
;
807 status
->auto_edge_port
= prt
->AutoEdge
;
808 status
->oper_edge_port
= prt
->operEdge
;
809 status
->enabled
= prt
->portEnabled
;
810 status
->admin_p2p
= prt
->AdminP2P
;
811 status
->oper_p2p
= prt
->operPointToPointMAC
;
812 status
->restricted_role
= prt
->restrictedRole
;
813 status
->restricted_tcn
= prt
->restrictedTcn
;
814 status
->role
= cist
->role
;
815 status
->disputed
= cist
->disputed
;
816 assign(status
->admin_internal_port_path_cost
,
817 cist
->AdminInternalPortPathCost
);
818 assign(status
->internal_port_path_cost
, cist
->InternalPortPathCost
);
821 /* 12.8.2.2 Read MSTI Port Parameters */
822 void MSTP_IN_get_msti_port_status(per_tree_port_t
*ptp
,
823 MSTI_PortStatus
*status
)
825 status
->uptime
= (signed int)((ptp
->port
->bridge
)->uptime
)
826 - (signed int)(ptp
->start_time
);
827 status
->state
= ptp
->state
;
828 assign(status
->port_id
, ptp
->portId
);
829 assign(status
->admin_internal_port_path_cost
,
830 ptp
->AdminInternalPortPathCost
);
831 assign(status
->internal_port_path_cost
, ptp
->InternalPortPathCost
);
832 assign(status
->designated_regional_root
, ptp
->portPriority
.RRootID
);
833 assign(status
->designated_internal_cost
,
834 __be32_to_cpu(ptp
->portPriority
.IntRootPathCost
));
835 assign(status
->designated_bridge
, ptp
->portPriority
.DesignatedBridgeID
);
836 assign(status
->designated_port
, ptp
->portPriority
.DesignatedPortID
);
837 status
->role
= ptp
->role
;
838 status
->disputed
= ptp
->disputed
;
841 /* 12.8.2.3 Set CIST port parameters */
842 int MSTP_IN_set_cist_port_config(port_t
*prt
, CIST_PortConfig
*cfg
)
845 __u32 new_ExternalPathCost
;
847 per_tree_port_t
*cist
;
849 /* Firstly, validation */
850 if(cfg
->set_admin_p2p
)
852 switch(cfg
->admin_p2p
)
859 cfg
->admin_p2p
= p2pAuto
;
863 /* Secondly, do set */
866 if(cfg
->set_admin_external_port_path_cost
)
868 prt
->AdminExternalPortPathCost
= cfg
->admin_external_port_path_cost
;
869 new_ExternalPathCost
= (0 == prt
->AdminExternalPortPathCost
) ?
870 compute_pcost(GET_PORT_SPEED(prt
))
871 : prt
->AdminExternalPortPathCost
;
872 if(prt
->ExternalPortPathCost
!= new_ExternalPathCost
)
874 assign(prt
->ExternalPortPathCost
, new_ExternalPathCost
);
877 cist
= GET_CIST_PTP_FROM_PORT(prt
);
878 cist
->selected
= false;
879 cist
->reselect
= true;
883 if(cfg
->set_admin_p2p
)
885 prt
->AdminP2P
= cfg
->admin_p2p
;
886 switch(prt
->AdminP2P
)
896 new_p2p
= !!GET_PORT_DUPLEX(prt
);
899 if(prt
->operPointToPointMAC
!= new_p2p
)
901 prt
->operPointToPointMAC
= new_p2p
;
906 if(cfg
->set_admin_edge_port
)
908 if(prt
->AdminEdgePort
!= cfg
->admin_edge_port
)
910 prt
->AdminEdgePort
= cfg
->admin_edge_port
;
916 if(cfg
->set_auto_edge_port
)
918 if(prt
->AutoEdge
!= cfg
->auto_edge_port
)
920 prt
->AutoEdge
= cfg
->auto_edge_port
;
925 if(cfg
->set_restricted_role
)
927 if(prt
->restrictedRole
!= cfg
->restricted_role
)
929 prt
->restrictedRole
= cfg
->restricted_role
;
934 if(cfg
->set_restricted_tcn
)
936 if(prt
->restrictedTcn
!= cfg
->restricted_tcn
)
938 prt
->restrictedTcn
= cfg
->restricted_tcn
;
943 if(changed
&& prt
->portEnabled
)
944 br_state_machines_run(prt
->bridge
);
949 /* 12.8.2.4 Set MSTI port parameters */
950 int MSTP_IN_set_msti_port_config(per_tree_port_t
*ptp
, MSTI_PortConfig
*cfg
)
953 __u32 new_InternalPathCost
;
954 bool changed
= false;
955 port_t
*prt
= ptp
->port
;
956 bridge_t
*br
= prt
->bridge
;
958 if(cfg
->set_port_priority
)
960 if(15 < cfg
->port_priority
)
962 ERROR_MSTINAME(br
, prt
, ptp
,
963 "Port Priority must be between 0 and 15");
966 valuePri
= cfg
->port_priority
<< 4;
967 if(GET_PRIORITY_FROM_IDENTIFIER(ptp
->portId
) != valuePri
)
969 SET_PRIORITY_IN_IDENTIFIER(valuePri
, ptp
->portId
);
974 if(cfg
->set_admin_internal_port_path_cost
)
976 ptp
->AdminInternalPortPathCost
= cfg
->admin_internal_port_path_cost
;
977 new_InternalPathCost
= (0 == ptp
->AdminInternalPortPathCost
) ?
978 compute_pcost(GET_PORT_SPEED(prt
))
979 : ptp
->AdminInternalPortPathCost
;
980 if(ptp
->InternalPortPathCost
!= new_InternalPathCost
)
982 assign(ptp
->InternalPortPathCost
, new_InternalPathCost
);
987 if(changed
&& prt
->portEnabled
)
990 ptp
->selected
= false;
991 ptp
->reselect
= true;
993 br_state_machines_run(br
);
999 /* 12.8.2.5 Force BPDU Migration Check */
1000 int MSTP_IN_port_mcheck(port_t
*prt
)
1002 bridge_t
*br
= prt
->bridge
;
1004 if(rstpVersion(br
) && prt
->portEnabled
&& br
->bridgeEnabled
)
1007 br_state_machines_run(br
);
1013 /* 12.10.3.8 Set VID to FID allocation */
1014 bool MSTP_IN_set_vid2fid(bridge_t
*br
, __u16 vid
, __u16 fid
)
1016 bool vid2mstid_changed
;
1018 if((vid
< 1) || (vid
> MAX_VID
) || (fid
> MAX_FID
))
1020 ERROR_BRNAME(br
, "Error allocating VID(%hu) to FID(%hu)", vid
, fid
);
1025 (br
->fid2mstid
[fid
] != br
->fid2mstid
[br
->vid2fid
[vid
]]);
1026 br
->vid2fid
[vid
] = fid
;
1027 if(vid2mstid_changed
)
1029 RecalcConfigDigest(br
);
1030 br_state_machines_begin(br
);
1036 /* Set all VID-to-FID mappings at once */
1037 bool MSTP_IN_set_all_vids2fids(bridge_t
*br
, __u16
*vids2fids
)
1039 bool vid2mstid_changed
;
1042 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1043 if(vids2fids
[vid
] > MAX_FID
)
1045 ERROR_BRNAME(br
, "Error allocating VID(%hu) to FID(%hu)",
1046 vid
, vids2fids
[vid
]);
1050 vid2mstid_changed
= false;
1051 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1053 if(br
->fid2mstid
[vids2fids
[vid
]] != br
->fid2mstid
[br
->vid2fid
[vid
]])
1055 vid2mstid_changed
= true;
1059 memcpy(br
->vid2fid
, vids2fids
, sizeof(br
->vid2fid
));
1060 if(vid2mstid_changed
)
1062 RecalcConfigDigest(br
);
1063 br_state_machines_begin(br
);
1069 /* 12.12.2.2 Set FID to MSTID allocation */
1070 bool MSTP_IN_set_fid2mstid(bridge_t
*br
, __u16 fid
, __u16 mstid
)
1079 ERROR_BRNAME(br
, "Bad FID(%hu)", fid
);
1083 MSTID
= __cpu_to_be16(mstid
);
1085 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1087 if(tree
->MSTID
== MSTID
)
1095 ERROR_BRNAME(br
, "MSTID(%hu) not found", mstid
);
1099 if(br
->fid2mstid
[fid
] != MSTID
)
1101 br
->fid2mstid
[fid
] = MSTID
;
1102 /* check if there are VLANs using this FID */
1103 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1105 if(br
->vid2fid
[vid
] == fid
)
1107 RecalcConfigDigest(br
);
1108 br_state_machines_begin(br
);
1117 /* Set all FID-to-MSTID mappings at once */
1118 bool MSTP_IN_set_all_fids2mstids(bridge_t
*br
, __u16
*fids2mstids
)
1121 __be16 MSTID
[MAX_FID
+ 1];
1122 bool found
, vid2mstid_changed
;
1124 __be16 prev_vid2mstid
[MAX_VID
+ 2];
1126 for(fid
= 0; fid
<= MAX_FID
; ++fid
)
1128 MSTID
[fid
] = __cpu_to_be16(fids2mstids
[fid
]);
1130 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1132 if(tree
->MSTID
== MSTID
[fid
])
1141 "Error allocating FID(%hu) to MSTID(%hu): MSTID not found",
1142 fid
, fids2mstids
[fid
]);
1147 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1148 prev_vid2mstid
[vid
] = br
->fid2mstid
[br
->vid2fid
[vid
]];
1149 memcpy(br
->fid2mstid
, MSTID
, sizeof(br
->fid2mstid
));
1150 vid2mstid_changed
= false;
1151 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1153 if(prev_vid2mstid
[vid
] != br
->fid2mstid
[br
->vid2fid
[vid
]])
1155 vid2mstid_changed
= true;
1159 if(vid2mstid_changed
)
1161 RecalcConfigDigest(br
);
1162 br_state_machines_begin(br
);
1168 /* 12.12.1.1 Read MSTI List */
1169 bool MSTP_IN_get_mstilist(bridge_t
*br
, int *num_mstis
, __u16
*mstids
)
1174 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1176 mstids
[*num_mstis
] = __be16_to_cpu(tree
->MSTID
);
1177 /* Check for "<", not for "<=", as num_mstis include CIST */
1178 if(MAX_IMPLEMENTATION_MSTIS
< ++(*num_mstis
))
1185 /* 12.12.1.2 Create MSTI */
1186 bool MSTP_IN_create_msti(bridge_t
*br
, __u16 mstid
)
1188 tree_t
*tree
, *tree_after
, *new_tree
;
1189 per_tree_port_t
*ptp
, *nxt
, *ptp_after
, *new_ptp
;
1193 if((mstid
< 1) || (mstid
> MAX_MSTID
))
1195 ERROR_BRNAME(br
, "Bad MSTID(%hu)", mstid
);
1199 MSTID
= __cpu_to_be16(mstid
);
1200 /* Find place where to insert new MSTID.
1201 * Also check if such MSTID is already in the list.
1202 * Also count existing mstis.
1206 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1208 if(tree
->MSTID
== MSTID
)
1210 INFO_BRNAME(br
, "MSTID(%hu) is already in the list", mstid
);
1211 return true; /* yes, it is success */
1213 if(cmp(tree
->MSTID
, <, MSTID
))
1218 if(NULL
== tree_after
)
1220 ERROR_BRNAME(br
, "Can't add MSTID(%hu): no CIST in the list", mstid
);
1223 /* End of Sanity check */
1225 /* Check for "<", not for "<=", as num_of_mstis include CIST */
1226 if(MAX_IMPLEMENTATION_MSTIS
< num_of_mstis
)
1228 ERROR_BRNAME(br
, "Can't add MSTID(%hu): maximum count(%u) reached",
1229 mstid
, MAX_IMPLEMENTATION_MSTIS
);
1233 /* Create new tree and its list of PerTreePort structures */
1234 tree
= GET_CIST_TREE(br
);
1235 if(!(new_tree
=create_tree(br
,tree
->BridgeIdentifier
.s
.mac_address
,MSTID
)))
1238 FOREACH_PTP_IN_TREE(ptp_after
, tree_after
)
1240 if(!(new_ptp
= create_ptp(new_tree
, ptp_after
->port
)))
1242 /* Remove and free all previously created entries in tree's list */
1243 list_for_each_entry_safe(ptp
, nxt
, &new_tree
->ports
, tree_list
)
1245 list_del(&ptp
->port_list
);
1246 list_del(&ptp
->tree_list
);
1251 list_add(&new_ptp
->port_list
, &ptp_after
->port_list
);
1252 list_add_tail(&new_ptp
->tree_list
, &new_tree
->ports
);
1255 list_add(&new_tree
->bridge_list
, &tree_after
->bridge_list
);
1256 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping
1257 * did not change. So, no need in RecalcConfigDigest.
1258 * Just initialize state machines for this tree.
1260 tree_state_machines_begin(new_tree
);
1264 /* 12.12.1.3 Delete MSTI */
1265 bool MSTP_IN_delete_msti(bridge_t
*br
, __u16 mstid
)
1268 per_tree_port_t
*ptp
, *nxt
;
1271 __be16 MSTID
= __cpu_to_be16(mstid
);
1273 if((mstid
< 1) || (mstid
> MAX_MSTID
))
1275 ERROR_BRNAME(br
, "Bad MSTID(%hu)", mstid
);
1279 /* Check if there are FIDs associated with this MSTID */
1280 for(fid
= 0; fid
<= MAX_FID
; ++fid
)
1282 if(br
->fid2mstid
[fid
] == MSTID
)
1285 "Can't delete MSTID(%hu): there are FIDs allocated to it",
1292 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1294 if(tree
->MSTID
== MSTID
)
1302 INFO_BRNAME(br
, "MSTID(%hu) is not in the list", mstid
);
1303 return true; /* yes, it is success */
1306 list_del(&tree
->bridge_list
);
1307 list_for_each_entry_safe(ptp
, nxt
, &tree
->ports
, tree_list
)
1309 list_del(&ptp
->port_list
);
1310 list_del(&ptp
->tree_list
);
1315 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping
1316 * did not change. So, no need in RecalcConfigDigest.
1317 * Give state machine a spare run, just for the case...
1319 br_state_machines_run(br
);
1323 /* 12.12.3.4 Set MST Configuration Identifier Elements */
1324 void MSTP_IN_set_mst_config_id(bridge_t
*br
, __u16 revision
, __u8
*name
)
1326 __be16 valueRevision
= __cpu_to_be16(revision
);
1327 bool changed
= (0 != strncmp(name
, br
->MstConfigId
.s
.configuration_name
,
1328 sizeof(br
->MstConfigId
.s
.configuration_name
))
1330 || (valueRevision
!= br
->MstConfigId
.s
.revision_level
);
1334 assign(br
->MstConfigId
.s
.revision_level
, valueRevision
);
1335 memset(br
->MstConfigId
.s
.configuration_name
, 0,
1336 sizeof(br
->MstConfigId
.s
.configuration_name
));
1337 strncpy(br
->MstConfigId
.s
.configuration_name
, name
,
1338 sizeof(br
->MstConfigId
.s
.configuration_name
));
1339 br_state_machines_begin(br
);
1344 * If hint_SetToYes == true, some tcWhile in this tree has non-zero value.
1345 * If hint_SetToYes == false, some tcWhile in this tree has just became zero,
1346 * so we should check all other tcWhile's in this tree.
1348 static void set_TopologyChange(tree_t
*tree
, bool hint_SetToYes
)
1350 per_tree_port_t
*ptp
;
1351 bool prev_tc_not_set
= !tree
->topology_change
;
1355 tree
->topology_change
= true;
1356 tree
->time_since_topology_change
= 0;
1358 ++(tree
->topology_change_count
);
1362 /* Some tcWhile has just became zero. Check if we need reset
1363 * topology_change flag */
1367 tree
->topology_change
= false;
1368 FOREACH_PTP_IN_TREE(ptp
, tree
)
1370 if(0 != ptp
->tcWhile
)
1372 tree
->topology_change
= true;
1373 tree
->time_since_topology_change
= 0;
1379 /* Helper functions, compare two priority vectors */
1380 static bool samePriorityAndTimers(port_priority_vector_t
*vec1
,
1381 port_priority_vector_t
*vec2
,
1388 if(cmp(time1
->Forward_Delay
, !=, time2
->Forward_Delay
))
1390 if(cmp(time1
->Max_Age
, !=, time2
->Max_Age
))
1392 if(cmp(time1
->Message_Age
, !=, time2
->Message_Age
))
1394 if(cmp(time1
->Hello_Time
, !=, time2
->Hello_Time
))
1397 if(cmp(vec1
->RootID
, !=, vec2
->RootID
))
1399 if(cmp(vec1
->ExtRootPathCost
, !=, vec2
->ExtRootPathCost
))
1403 if(cmp(time1
->remainingHops
, !=, time2
->remainingHops
))
1406 if(cmp(vec1
->RRootID
, !=, vec2
->RRootID
))
1408 if(cmp(vec1
->IntRootPathCost
, !=, vec2
->IntRootPathCost
))
1410 if(cmp(vec1
->DesignatedBridgeID
, !=, vec2
->DesignatedBridgeID
))
1412 if(cmp(vec1
->DesignatedPortID
, !=, vec2
->DesignatedPortID
))
1418 static bool betterorsamePriority(port_priority_vector_t
*vec1
,
1419 port_priority_vector_t
*vec2
,
1420 port_identifier_t pId1
,
1421 port_identifier_t pId2
,
1428 if(0 < (result
= _ncmp(vec1
->RootID
, vec2
->RootID
)))
1429 return false; /* worse */
1431 return true; /* better */
1432 /* The same. Check further. */
1433 if(0 < (result
= _ncmp(vec1
->ExtRootPathCost
, vec2
->ExtRootPathCost
)))
1434 return false; /* worse */
1436 return true; /* better */
1437 /* The same. Check further. */
1440 if(0 < (result
= _ncmp(vec1
->RRootID
, vec2
->RRootID
)))
1441 return false; /* worse */
1443 return true; /* better */
1444 /* The same. Check further. */
1446 if(0 < (result
= _ncmp(vec1
->IntRootPathCost
, vec2
->IntRootPathCost
)))
1447 return false; /* worse */
1449 return true; /* better */
1450 /* The same. Check further. */
1452 if(0 < (result
= _ncmp(vec1
->DesignatedBridgeID
, vec2
->DesignatedBridgeID
)))
1453 return false; /* worse */
1455 return true; /* better */
1456 /* The same. Check further. */
1458 if(0 < (result
= _ncmp(vec1
->DesignatedPortID
, vec2
->DesignatedPortID
)))
1459 return false; /* worse */
1461 return true; /* better */
1462 /* The same. Check further. */
1464 /* Port ID is a tie-breaker */
1465 return cmp(pId1
, <=, pId2
);
1468 /* 13.26.1 betterorsameInfo */
1469 static bool betterorsameInfo(per_tree_port_t
*ptp
, port_info_origin_t newInfoIs
)
1471 if((ioReceived
== newInfoIs
) && (ioReceived
== ptp
->infoIs
))
1472 return betterorsamePriority(&ptp
->msgPriority
,
1474 0, 0, (0 == ptp
->MSTID
));
1475 else if((ioMine
== newInfoIs
) && (ioMine
== ptp
->infoIs
))
1476 return betterorsamePriority(&ptp
->designatedPriority
,
1478 0, 0, (0 == ptp
->MSTID
));
1482 /* 13.26.2 clearAllRcvdMsgs */
1483 static void clearAllRcvdMsgs(port_t
*prt
)
1485 per_tree_port_t
*ptp
;
1487 FOREACH_PTP_IN_PORT(ptp
, prt
)
1488 ptp
->rcvdMsg
= false;
1491 /* 13.26.3 clearReselectTree */
1492 static void clearReselectTree(tree_t
*tree
)
1494 per_tree_port_t
*ptp
;
1496 FOREACH_PTP_IN_TREE(ptp
, tree
)
1497 ptp
->reselect
= false;
1500 /* 13.26.4 fromSameRegion */
1501 static bool fromSameRegion(port_t
*prt
)
1503 /* Check for rcvdRSTP is superfluous here */
1504 if((protoMSTP
> prt
->rcvdBpduData
.protocolVersion
)/* || (!prt->rcvdRSTP)*/)
1506 return cmp(prt
->bridge
->MstConfigId
,
1507 ==, prt
->rcvdBpduData
.mstConfigurationIdentifier
);
1510 /* 13.26.5 newTcWhile */
1511 static void newTcWhile(per_tree_port_t
*ptp
)
1513 if(0 != ptp
->tcWhile
)
1516 tree_t
*tree
= ptp
->tree
;
1517 port_t
*prt
= ptp
->port
;
1521 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
1523 ptp
->tcWhile
= cist
->portTimes
.Hello_Time
+ 1;
1524 set_TopologyChange(tree
, true);
1527 prt
->newInfo
= true;
1529 prt
->newInfoMsti
= true;
1533 times_t
*times
= &tree
->rootTimes
;
1535 ptp
->tcWhile
= times
->Max_Age
+ times
->Forward_Delay
;
1536 set_TopologyChange(tree
, true);
1539 /* 13.26.6 rcvInfo */
1540 static port_info_t
rcvInfo(per_tree_port_t
*ptp
)
1542 msti_configuration_message_t
*msti_msg
;
1543 per_tree_port_t
*ptp_1
;
1544 bool roleIsDesignated
, cist
;
1545 bool msg_Better_port
, msg_SamePriorityAndTimers_port
;
1546 port_priority_vector_t
*mPri
= &(ptp
->msgPriority
);
1547 times_t
*mTimes
= &(ptp
->msgTimes
);
1548 port_t
*prt
= ptp
->port
;
1549 bpdu_t
*b
= &(prt
->rcvdBpduData
);
1551 if(bpduTypeTCN
== b
->bpduType
)
1553 prt
->rcvdTcn
= true;
1554 FOREACH_PTP_IN_PORT(ptp_1
, prt
)
1555 ptp_1
->rcvdTc
= true;
1563 assign(mPri
->RRootID
, b
->cistRRootID
);
1564 assign(mPri
->DesignatedPortID
, b
->cistPortID
);
1565 assign(mPri
->RootID
, b
->cistRootID
);
1566 assign(mPri
->ExtRootPathCost
, b
->cistExtRootPathCost
);
1568 #define NEAREST_WHOLE_SECOND(msgTime) \
1569 ((128 > msgTime[1]) ? msgTime[0] : msgTime[0] + 1)
1570 mTimes
->Forward_Delay
= NEAREST_WHOLE_SECOND(b
->ForwardDelay
);
1571 mTimes
->Max_Age
= NEAREST_WHOLE_SECOND(b
->MaxAge
);
1572 mTimes
->Message_Age
= NEAREST_WHOLE_SECOND(b
->MessageAge
);
1573 mTimes
->Hello_Time
= NEAREST_WHOLE_SECOND(b
->HelloTime
);
1574 if(protoMSTP
> b
->protocolVersion
)
1575 { /* STP or RSTP Configuration BPDU */
1576 /* 13.26.6.NOTE: A Configuration BPDU implicitly conveys a
1577 * Designated Port Role */
1578 roleIsDesignated
= true;
1579 assign(mPri
->IntRootPathCost
, __constant_cpu_to_be32(0));
1580 assign(mPri
->DesignatedBridgeID
, b
->cistRRootID
);
1581 /* messageTimes.remainingHops */
1582 assign(mTimes
->remainingHops
, prt
->bridge
->MaxHops
);
1586 switch(BPDU_FLAGS_ROLE_GET(b
->flags
))
1588 case encodedRoleAlternateBackup
:
1589 case encodedRoleRoot
:
1590 roleIsDesignated
= false;
1592 case encodedRoleDesignated
:
1593 roleIsDesignated
= true;
1598 assign(mPri
->IntRootPathCost
, b
->cistIntRootPathCost
);
1599 assign(mPri
->DesignatedBridgeID
, b
->cistBridgeID
);
1600 /* messageTimes.remainingHops */
1601 assign(mTimes
->remainingHops
, b
->cistRemainingHops
);
1606 if(protoMSTP
> b
->protocolVersion
)
1608 msti_msg
= ptp
->rcvdMstiConfig
;
1609 switch(BPDU_FLAGS_ROLE_GET(msti_msg
->flags
))
1611 case encodedRoleAlternateBackup
:
1612 case encodedRoleRoot
:
1613 roleIsDesignated
= false;
1615 case encodedRoleDesignated
:
1616 roleIsDesignated
= true;
1623 assign(mPri
->RRootID
, msti_msg
->mstiRRootID
);
1624 assign(mPri
->IntRootPathCost
, msti_msg
->mstiIntRootPathCost
);
1625 /* Build MSTI DesignatedBridgeID */
1626 assign(mPri
->DesignatedBridgeID
, b
->cistBridgeID
);
1627 assign(mPri
->DesignatedBridgeID
.s
.priority
, ptp
->MSTID
);
1628 SET_PRIORITY_IN_IDENTIFIER(msti_msg
->bridgeIdentifierPriority
,
1629 mPri
->DesignatedBridgeID
);
1630 /* Build MSTI DesignatedPortID */
1631 assign(mPri
->DesignatedPortID
, b
->cistPortID
);
1632 SET_PRIORITY_IN_IDENTIFIER(msti_msg
->portIdentifierPriority
,
1633 mPri
->DesignatedPortID
);
1635 assign(mTimes
->remainingHops
, msti_msg
->remainingHops
);
1638 msg_Better_port
= !betterorsamePriority(&(ptp
->portPriority
), mPri
,
1640 if(roleIsDesignated
)
1644 || ((0 == memcmp(mPri
->DesignatedBridgeID
.s
.mac_address
,
1645 ptp
->portPriority
.DesignatedBridgeID
.s
.mac_address
,
1648 && (0 == ((mPri
->DesignatedPortID
1649 ^ ptp
->portPriority
.DesignatedPortID
1650 ) & __constant_cpu_to_be16(0x0FFF)
1655 return SuperiorDesignatedInfo
;
1658 /* We already know that msgPriority _IS_NOT_BETTER_than portPriority.
1659 * So, if msgPriority _IS_SAME_OR_BETTER_than portPriority then
1660 * msgPriority _IS_SAME_as portPriority.
1662 msg_SamePriorityAndTimers_port
=
1663 samePriorityAndTimers(mPri
, &(ptp
->portPriority
),
1664 mTimes
, &(ptp
->portTimes
),
1666 if((!msg_SamePriorityAndTimers_port
)
1667 && betterorsamePriority(mPri
, &(ptp
->portPriority
), 0, 0, cist
)
1669 return SuperiorDesignatedInfo
;
1672 if(msg_SamePriorityAndTimers_port
&& (ioReceived
== ptp
->infoIs
))
1673 return RepeatedDesignatedInfo
;
1676 return InferiorDesignatedInfo
;
1680 if(!msg_Better_port
)
1681 return InferiorRootAlternateInfo
;
1686 /* 13.26.7 recordAgreement */
1687 static void recordAgreement(per_tree_port_t
*ptp
)
1689 bool cist_agreed
, cist_proposing
;
1690 per_tree_port_t
*cist
;
1691 port_t
*prt
= ptp
->port
;
1692 bpdu_t
*b
= &(prt
->rcvdBpduData
);
1696 if(rstpVersion(prt
->bridge
) && prt
->operPointToPointMAC
1697 && (b
->flags
& (1 << offsetAgreement
))
1701 ptp
->proposing
= false;
1704 ptp
->agreed
= false;
1705 cist_agreed
= ptp
->agreed
;
1706 cist_proposing
= ptp
->proposing
;
1707 if(!prt
->rcvdInternal
)
1708 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1710 ptp
->agreed
= cist_agreed
;
1711 ptp
->proposing
= cist_proposing
;
1716 cist
= GET_CIST_PTP_FROM_PORT(prt
);
1717 if(prt
->operPointToPointMAC
1718 && cmp(b
->cistRootID
, ==, cist
->portPriority
.RootID
)
1719 && cmp(b
->cistExtRootPathCost
, ==, cist
->portPriority
.ExtRootPathCost
)
1720 && cmp(b
->cistRRootID
, ==, cist
->portPriority
.RRootID
)
1721 && (ptp
->rcvdMstiConfig
->flags
& (1 << offsetAgreement
))
1725 ptp
->proposing
= false;
1728 ptp
->agreed
= false;
1731 /* 13.26.8 recordDispute */
1732 static void recordDispute(per_tree_port_t
*ptp
)
1739 /* 802.1Q-2005 is somewhat unclear for the case (!prt->rcvdInternal):
1740 * if we should record dispute for all MSTIs unconditionally
1741 * or only when CIST Learning flag is set in BPDU.
1742 * I guess that in this case MSTIs should be in sync with CIST
1743 * so record dispute for the MSTIs only when the same is done for CIST.
1744 * Additional supporting argument to this guess is that in
1745 * setTcFlags() we do the same.
1746 * But that is only a guess and I could be wrong here ;)
1747 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
1749 if(prt
->rcvdBpduData
.flags
& (1 << offsetLearnig
))
1751 ptp
->disputed
= true;
1752 ptp
->agreed
= false;
1753 if(!prt
->rcvdInternal
)
1754 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1756 ptp
->disputed
= true;
1757 ptp
->agreed
= false;
1763 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetLearnig
))
1765 ptp
->disputed
= true;
1766 ptp
->agreed
= false;
1770 /* 13.26.9 recordMastered */
1771 static void recordMastered(per_tree_port_t
*ptp
)
1773 port_t
*prt
= ptp
->port
;
1777 if(!prt
->rcvdInternal
)
1778 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1779 ptp
->mastered
= false;
1783 ptp
->mastered
= prt
->operPointToPointMAC
1784 && (ptp
->rcvdMstiConfig
->flags
& (1 << offsetMaster
));
1787 /* 13.26.f) recordPriority */
1788 static void recordPriority(per_tree_port_t
*ptp
)
1790 assign(ptp
->portPriority
, ptp
->msgPriority
);
1793 /* 13.26.10 recordProposal */
1794 static void recordProposal(per_tree_port_t
*ptp
)
1799 /* 802.1Q-2005 says to check if received message conveys
1800 * a Designated Port Role. But there is no need in this check,
1801 * as it is always true. This function is called only in two states:
1802 * PISM_SUPERIOR_DESIGNATED and PISM_REPEATED_DESIGNATED, which
1803 * can be entered only if rcvInfo returns
1804 * SuperiorDesignatedInfo or RepeatedDesignatedInfo.
1805 * Which in turn can only happen if message conveys designated role
1811 if(prt
->rcvdBpduData
.flags
& (1 << offsetProposal
))
1812 ptp
->proposed
= true;
1813 cist_proposed
= ptp
->proposed
;
1814 if(!prt
->rcvdInternal
)
1815 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1816 ptp
->proposed
= cist_proposed
;
1820 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetProposal
))
1821 ptp
->proposed
= true;
1824 /* 13.26.11 recordTimes */
1825 static void recordTimes(per_tree_port_t
*ptp
)
1827 assign(ptp
->portTimes
, ptp
->msgTimes
);
1829 if(MIN_COMPAT_HELLO_TIME
> ptp
->portTimes
.Hello_Time
)
1830 ptp
->portTimes
.Hello_Time
= MIN_COMPAT_HELLO_TIME
;
1833 /* 13.24.s) + 17.19.7 of 802.1D : fdbFlush */
1834 static void set_fdbFlush(per_tree_port_t
*ptp
)
1836 port_t
*prt
= ptp
->port
;
1840 ptp
->fdbFlush
= false;
1844 bridge_t
*br
= prt
->bridge
;
1848 ptp
->fdbFlush
= true;
1849 ptp
->calledFromFlushRoutine
= true;
1850 MSTP_OUT_flush_all_fids(ptp
);
1851 ptp
->calledFromFlushRoutine
= false;
1855 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
1856 unsigned int FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
1857 /* Initiate rapid ageing */
1858 MSTP_OUT_set_ageing_time(br
, FwdDelay
);
1859 assign(br
->rapidAgeingWhile
, FwdDelay
);
1860 ptp
->fdbFlush
= false;
1864 /* 13.26.12 setRcvdMsgs */
1865 static void setRcvdMsgs(port_t
*prt
)
1867 msti_configuration_message_t
*msti_msg
;
1871 per_tree_port_t
*ptp
= GET_CIST_PTP_FROM_PORT(prt
);
1872 ptp
->rcvdMsg
= true;
1874 /* 802.1Q-2005 says:
1875 * "Make the received CST or CIST message available to the CIST Port
1876 * Information state machines"
1877 * No need to do something special here, we already have rcvdBpduData.
1880 if(prt
->rcvdInternal
)
1882 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1885 /* Find if message for this MSTI is conveyed in the BPDU */
1886 for(i
= 0, msti_msg
= prt
->rcvdBpduData
.mstConfiguration
;
1887 i
< prt
->rcvdBpduNumOfMstis
;
1890 msg_MSTID
= msti_msg
->mstiRRootID
.s
.priority
1891 & __constant_cpu_to_be16(0x0FFF);
1892 if(msg_MSTID
== ptp
->MSTID
)
1900 ptp
->rcvdMsg
= true;
1901 /* 802.1Q-2005 says:
1902 * "Make available each MSTI message and the common parts of
1903 * the CIST message priority (the CIST Root Identifier,
1904 * External Root Path Cost and Regional Root Identifier)
1905 * to the Port Information state machine for that MSTI"
1906 * We set pointer to the MSTI configuration message for
1907 * fast access, while do not anything special for common
1908 * parts of the message, as the whole message is available
1911 ptp
->rcvdMstiConfig
= msti_msg
;
1917 /* 13.26.13 setReRootTree */
1918 static void setReRootTree(tree_t
*tree
)
1920 per_tree_port_t
*ptp
;
1922 FOREACH_PTP_IN_TREE(ptp
, tree
)
1926 /* 13.26.14 setSelectedTree */
1927 static void setSelectedTree(tree_t
*tree
)
1929 per_tree_port_t
*ptp
;
1932 * 802.1Q-2005 says that I should check "reselect" var
1933 * and take no action if it is "true" for any of the ports.
1934 * But there is no need in this check as setSelectedTree is called
1935 * only from PRSSM_to_ROLE_SELECTION, which is atomic, and it is called
1936 * in this sequence (13.33):
1937 * clearReselectTree(tree);
1938 * updtRolesTree(tree);
1939 * setSelectedTree(tree);
1940 * And we know that clearReselectTree resets "reselect" for all ports
1941 * and updtRolesTree() does not change value of "reselect".
1943 FOREACH_PTP_IN_TREE(ptp
, tree
)
1944 ptp
->selected
= true;
1947 /* 13.26.15 setSyncTree */
1948 static void setSyncTree(tree_t
*tree
)
1950 per_tree_port_t
*ptp
;
1952 FOREACH_PTP_IN_TREE(ptp
, tree
)
1956 /* 13.26.16 setTcFlags */
1957 static void setTcFlags(per_tree_port_t
*ptp
)
1965 cistFlags
= prt
->rcvdBpduData
.flags
;
1966 if(cistFlags
& (1 << offsetTcAck
))
1967 prt
->rcvdTcAck
= true;
1968 if(cistFlags
& (1 << offsetTc
))
1971 if(!prt
->rcvdInternal
)
1972 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1973 ptp
->proposed
= true;
1978 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetTc
))
1982 /* 13.26.17 setTcPropTree */
1983 static void setTcPropTree(per_tree_port_t
*ptp
)
1985 per_tree_port_t
*ptp_1
;
1987 if(ptp
->port
->restrictedTcn
)
1990 FOREACH_PTP_IN_TREE(ptp_1
, ptp
->tree
)
1993 ptp_1
->tcProp
= true;
1997 /* 13.26.18 syncMaster */
1998 static void syncMaster(bridge_t
*br
)
2000 per_tree_port_t
*ptp
;
2001 tree_t
*tree
= GET_CIST_TREE(br
);
2004 list_for_each_entry_continue(tree
, &br
->trees
, bridge_list
)
2006 FOREACH_PTP_IN_TREE(ptp
, tree
)
2008 /* for each Port that has infoInternal set */
2009 if(ptp
->port
->infoInternal
)
2012 ptp
->agreed
= false;
2013 ptp
->synced
= false;
2020 /* 13.26.19 txConfig */
2021 static void txConfig(port_t
*prt
)
2024 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2026 b
.protocolIdentifier
= 0;
2027 b
.protocolVersion
= protoSTP
;
2028 b
.bpduType
= bpduTypeConfig
;
2029 /* Standard says "tcWhile ... for the Port". Which one tcWhile?
2030 * I guess that this means tcWhile for the CIST.
2031 * But that is only a guess and I could be wrong here ;)
2032 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
2034 b
.flags
= (0 != cist
->tcWhile
) ? (1 << offsetTc
) : 0;
2036 b
.flags
|= (1 << offsetTcAck
);
2037 assign(b
.cistRootID
, cist
->designatedPriority
.RootID
);
2038 assign(b
.cistExtRootPathCost
, cist
->designatedPriority
.ExtRootPathCost
);
2039 assign(b
.cistRRootID
, cist
->designatedPriority
.DesignatedBridgeID
);
2040 assign(b
.cistPortID
, cist
->designatedPriority
.DesignatedPortID
);
2041 b
.MessageAge
[0] = cist
->designatedTimes
.Message_Age
;
2042 b
.MessageAge
[1] = 0;
2043 b
.MaxAge
[0] = cist
->designatedTimes
.Max_Age
;
2045 b
.HelloTime
[0] = cist
->portTimes
.Hello_Time
; /* ! use portTimes ! */
2047 b
.ForwardDelay
[0] = cist
->designatedTimes
.Forward_Delay
;
2048 b
.ForwardDelay
[1] = 0;
2050 MSTP_OUT_tx_bpdu(prt
, &b
, CONFIG_BPDU_SIZE
);
2053 static inline __u8
message_role_from_port_role(per_tree_port_t
*ptp
)
2058 return encodedRoleRoot
;
2059 case roleDesignated
:
2060 return encodedRoleDesignated
;
2063 return encodedRoleAlternateBackup
;
2065 return encodedRoleMaster
;
2067 ERROR_PRTNAME(ptp
->port
->bridge
, ptp
->port
,
2068 "Attempt to send from port with Disabled role");
2069 return encodedRoleAlternateBackup
;
2073 /* 13.26.20 txMstp */
2074 static void txMstp(port_t
*prt
)
2077 bridge_t
*br
= prt
->bridge
;
2078 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2079 int msti_msgs_total_size
;
2080 per_tree_port_t
*ptp
;
2081 msti_configuration_message_t
*msti_msg
;
2083 b
.protocolIdentifier
= 0;
2084 b
.bpduType
= bpduTypeRST
;
2085 /* Standard says "{tcWhile, agree, proposing, role} ... for the Port".
2086 * Which one {tcWhile, agree, proposing, role}?
2087 * I guess that this means {tcWhile, agree, proposing, role} for the CIST.
2088 * But that is only a guess and I could be wrong here ;)
2089 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
2091 b
.flags
= BPDU_FLAGS_ROLE_SET(message_role_from_port_role(cist
));
2092 if(0 != cist
->tcWhile
)
2093 b
.flags
|= (1 << offsetTc
);
2095 b
.flags
|= (1 << offsetProposal
);
2097 b
.flags
|= (1 << offsetLearnig
);
2098 if(cist
->forwarding
)
2099 b
.flags
|= (1 << offsetForwarding
);
2101 b
.flags
|= (1 << offsetAgreement
);
2102 assign(b
.cistRootID
, cist
->designatedPriority
.RootID
);
2103 assign(b
.cistExtRootPathCost
, cist
->designatedPriority
.ExtRootPathCost
);
2104 assign(b
.cistRRootID
, cist
->designatedPriority
.RRootID
);
2105 assign(b
.cistPortID
, cist
->designatedPriority
.DesignatedPortID
);
2106 b
.MessageAge
[0] = cist
->designatedTimes
.Message_Age
;
2107 b
.MessageAge
[1] = 0;
2108 b
.MaxAge
[0] = cist
->designatedTimes
.Max_Age
;
2110 b
.HelloTime
[0] = cist
->portTimes
.Hello_Time
; /* ! use portTimes ! */
2112 b
.ForwardDelay
[0] = cist
->designatedTimes
.Forward_Delay
;
2113 b
.ForwardDelay
[1] = 0;
2117 if(br
->ForceProtocolVersion
< protoMSTP
)
2119 b
.protocolVersion
= protoRSTP
;
2120 MSTP_OUT_tx_bpdu(prt
, &b
, RST_BPDU_SIZE
);
2124 b
.protocolVersion
= protoMSTP
;
2126 /* MST specific fields */
2127 assign(b
.mstConfigurationIdentifier
, br
->MstConfigId
);
2128 assign(b
.cistIntRootPathCost
, cist
->designatedPriority
.IntRootPathCost
);
2129 assign(b
.cistBridgeID
, cist
->designatedPriority
.DesignatedBridgeID
);
2130 assign(b
.cistRemainingHops
, cist
->designatedTimes
.remainingHops
);
2132 msti_msgs_total_size
= 0;
2134 msti_msg
= b
.mstConfiguration
;
2135 /* 13.26.20.f) requires that msti configs should be inserted in
2136 * MSTID order. This is met by inserting trees in port's list of trees
2137 * in sorted (by MSTID) order (see MSTP_IN_create_msti) */
2138 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2141 BPDU_FLAGS_ROLE_SET(message_role_from_port_role(ptp
));
2142 if(0 != ptp
->tcWhile
)
2143 msti_msg
->flags
|= (1 << offsetTc
);
2145 msti_msg
->flags
|= (1 << offsetProposal
);
2147 msti_msg
->flags
|= (1 << offsetLearnig
);
2149 msti_msg
->flags
|= (1 << offsetForwarding
);
2151 msti_msg
->flags
|= (1 << offsetAgreement
);
2153 msti_msg
->flags
|= (1 << offsetMaster
);
2154 assign(msti_msg
->mstiRRootID
, ptp
->designatedPriority
.RRootID
);
2155 assign(msti_msg
->mstiIntRootPathCost
,
2156 ptp
->designatedPriority
.IntRootPathCost
);
2157 msti_msg
->bridgeIdentifierPriority
=
2158 GET_PRIORITY_FROM_IDENTIFIER(ptp
->designatedPriority
.DesignatedBridgeID
);
2159 msti_msg
->portIdentifierPriority
=
2160 GET_PRIORITY_FROM_IDENTIFIER(ptp
->designatedPriority
.DesignatedPortID
);
2161 assign(msti_msg
->remainingHops
, ptp
->designatedTimes
.remainingHops
);
2163 msti_msgs_total_size
+= sizeof(msti_configuration_message_t
);
2167 assign(b
.version3_len
, __cpu_to_be16(MST_BPDU_VER3LEN_WO_MSTI_MSGS
2168 + msti_msgs_total_size
));
2169 MSTP_OUT_tx_bpdu(prt
, &b
, MST_BPDU_SIZE_WO_MSTI_MSGS
2170 + msti_msgs_total_size
);
2173 /* 13.26.a) txTcn */
2174 static void txTcn(port_t
*prt
)
2178 b
.protocolIdentifier
= 0;
2179 b
.protocolVersion
= protoSTP
;
2180 b
.bpduType
= bpduTypeTCN
;
2182 MSTP_OUT_tx_bpdu(prt
, &b
, TCN_BPDU_SIZE
);
2185 /* 13.26.21 updtBPDUVersion */
2186 static void updtBPDUVersion(port_t
*prt
)
2188 if(protoRSTP
<= prt
->rcvdBpduData
.protocolVersion
)
2189 prt
->rcvdRSTP
= true;
2191 prt
->rcvdSTP
= true;
2194 /* 13.26.22 updtRcvdInfoWhile */
2195 static void updtRcvdInfoWhile(per_tree_port_t
*ptp
)
2197 port_t
*prt
= ptp
->port
;
2198 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2199 unsigned int Message_Age
= cist
->portTimes
.Message_Age
;
2200 unsigned int Max_Age
= cist
->portTimes
.Max_Age
;
2201 unsigned int Hello_Time
= cist
->portTimes
.Hello_Time
;
2203 if((!prt
->rcvdInternal
&& ((Message_Age
+ 1) <= Max_Age
))
2204 || (prt
->rcvdInternal
&& (cist
->portTimes
.remainingHops
> 1))
2206 ptp
->rcvdInfoWhile
= 3 * Hello_Time
;
2208 ptp
->rcvdInfoWhile
= 0;
2211 /* 13.26.24 updtRolesDisabledTree */
2212 static void updtRolesDisabledTree(tree_t
*tree
)
2214 per_tree_port_t
*ptp
;
2216 FOREACH_PTP_IN_TREE(ptp
, tree
)
2217 ptp
->selectedRole
= roleDisabled
;
2220 /* 13.26.23 updtRolesTree */
2221 static void updtRolesTree(tree_t
*tree
)
2223 per_tree_port_t
*ptp
, *root_ptp
= NULL
;
2224 port_priority_vector_t root_path_priority
;
2225 bridge_identifier_t prevRRootID
= tree
->rootPriority
.RRootID
;
2226 __be32 prevExtRootPathCost
= tree
->rootPriority
.ExtRootPathCost
;
2227 bool cist
= (0 == tree
->MSTID
);
2228 times_t
*timesOfRootPort
;
2230 /* a), b) Select new root priority vector = {rootPriority, rootPortId} */
2231 /* Initial value = bridge priority vector = {BridgePriority, 0} */
2232 assign(tree
->rootPriority
, tree
->BridgePriority
);
2233 assign(tree
->rootPortId
, __constant_cpu_to_be16(0));
2234 /* Now check root path priority vectors of all ports in tree and see if
2235 * there is a better vector */
2236 FOREACH_PTP_IN_TREE(ptp
, tree
)
2238 port_t
*prt
= ptp
->port
;
2239 /* 802.1Q says to calculate root priority vector only if port
2240 * is not Disabled, but check (infoIs == ioReceived) covers
2241 * the case (infoIs != ioDisabled).
2243 if((ioReceived
== ptp
->infoIs
) && !prt
->restrictedRole
2244 && cmp(ptp
->portPriority
.DesignatedBridgeID
, !=,
2245 tree
->BridgeIdentifier
)
2248 root_path_priority
= ptp
->portPriority
;
2249 if(prt
->rcvdInternal
)
2251 assign(root_path_priority
.IntRootPathCost
,
2252 __cpu_to_be32(__be32_to_cpu(root_path_priority
.IntRootPathCost
)
2253 + ptp
->InternalPortPathCost
)
2258 assign(root_path_priority
.ExtRootPathCost
,
2259 __cpu_to_be32(__be32_to_cpu(root_path_priority
.ExtRootPathCost
)
2260 + prt
->ExternalPortPathCost
)
2262 assign(root_path_priority
.IntRootPathCost
,
2263 __constant_cpu_to_be32(0));
2265 if(betterorsamePriority(&root_path_priority
, &tree
->rootPriority
,
2266 ptp
->portId
, tree
->rootPortId
, cist
))
2268 assign(tree
->rootPriority
, root_path_priority
);
2269 assign(tree
->rootPortId
, ptp
->portId
);
2275 /* 802.1q-2005 says, that at some point we need compare portTimes with
2276 * "... one for the Root Port ...". Bad IEEE! Why not mention explicit
2277 * var names??? (see 13.26.23.g) for instance)
2278 * So, now I should guess what will work for the timesOfRootPort.
2279 * Below is the result of my guess. I could be wrong, of course:
2280 * timesOfRootPort = root_ptp ? &root_ptp->portTimes
2281 * : &tree->BridgeTimes;
2282 * NOTE: Both Alex Rozin (author of rstplib) and Srinivas Aji (author
2283 * of rstpd) compare portTimes with designatedTimes instead of
2284 * timesOfRootPort. This differs from my interpretation of the standard
2285 * because designatedTimes have incremented Message_Age (or decremented
2286 * remainingHops if rcvdInternal).
2289 /* c) Set new rootTimes */
2292 assign(tree
->rootTimes
, root_ptp
->portTimes
);
2293 port_t
*prt
= root_ptp
->port
;
2294 if(prt
->rcvdInternal
)
2296 if(tree
->rootTimes
.remainingHops
)
2297 --(tree
->rootTimes
.remainingHops
);
2300 ++(tree
->rootTimes
.Message_Age
);
2301 timesOfRootPort
= &root_ptp
->portTimes
;
2305 assign(tree
->rootTimes
, tree
->BridgeTimes
);
2306 timesOfRootPort
= &tree
->BridgeTimes
;
2309 FOREACH_PTP_IN_TREE(ptp
, tree
)
2311 port_t
*prt
= ptp
->port
;
2313 /* d) Set new designatedPriority */
2314 assign(ptp
->designatedPriority
, tree
->rootPriority
);
2315 assign(ptp
->designatedPriority
.DesignatedBridgeID
,
2316 tree
->BridgeIdentifier
);
2317 assign(ptp
->designatedPriority
.DesignatedPortID
, ptp
->portId
);
2318 /* I am not sure which condition to check here, as 802.1Q-2005 says:
2319 * "... If {Port} is attached to a LAN that has one or more STP Bridges
2320 * attached (as determined by the Port Protocol Migration state
2321 * machine) ..." -- why not to mention explicit var name? Bad IEEE.
2322 * But I guess that sendSTP (i.e. !sendRSTP) var will do ;)
2324 if(cist
&& !prt
->sendRSTP
)
2325 assign(ptp
->designatedPriority
.RRootID
, tree
->BridgeIdentifier
);
2327 /* e) Set new designatedTimes */
2328 assign(ptp
->designatedTimes
, tree
->rootTimes
);
2332 if(cist
&& cmp(tree
->rootPriority
.RRootID
, !=, prevRRootID
)
2333 && ((0 != tree
->rootPriority
.ExtRootPathCost
)
2334 || (0 != prevExtRootPathCost
)
2337 syncMaster(tree
->bridge
);
2339 FOREACH_PTP_IN_TREE(ptp
, tree
)
2341 port_t
*prt
= ptp
->port
;
2343 /* f) Set Disabled role */
2344 if(ioDisabled
== ptp
->infoIs
)
2346 ptp
->selectedRole
= roleDisabled
;
2350 if(!cist
&& (ioReceived
== ptp
->infoIs
)
2351 && !prt
->infoInternal
)
2353 /* g) Set role for the boundary port in MSTI */
2354 per_tree_port_t
*cist_tree
= GET_CIST_PTP_FROM_PORT(prt
);
2355 if(roleRoot
== cist_tree
->selectedRole
)
2357 ptp
->selectedRole
= roleMaster
;
2358 if(!samePriorityAndTimers(&ptp
->portPriority
,
2359 &ptp
->designatedPriority
,
2363 ptp
->updtInfo
= true;
2366 if(roleAlternate
== cist_tree
->selectedRole
)
2368 ptp
->selectedRole
= roleAlternate
;
2369 if(!samePriorityAndTimers(&ptp
->portPriority
,
2370 &ptp
->designatedPriority
,
2374 ptp
->updtInfo
= true;
2378 else /* if(cist || (ioReceived != ptp->infoIs) || prt->infoInternal) */
2380 /* h) Set role for the aged info */
2381 if(ioAged
== ptp
->infoIs
)
2383 ptp
->selectedRole
= roleDesignated
;
2384 ptp
->updtInfo
= true;
2387 /* i) Set role for the mine info */
2388 if(ioMine
== ptp
->infoIs
)
2390 ptp
->selectedRole
= roleDesignated
;
2391 if(!samePriorityAndTimers(&ptp
->portPriority
,
2392 &ptp
->designatedPriority
,
2396 ptp
->updtInfo
= true;
2399 if(ioReceived
== ptp
->infoIs
)
2401 /* j) Set Root role */
2404 ptp
->selectedRole
= roleRoot
;
2405 ptp
->updtInfo
= false;
2408 if(betterorsamePriority(&ptp
->portPriority
,
2409 &ptp
->designatedPriority
,
2412 if(cmp(ptp
->portPriority
.DesignatedBridgeID
, !=,
2413 tree
->BridgeIdentifier
))
2415 /* k) Set Alternate role */
2416 ptp
->selectedRole
= roleAlternate
;
2420 /* l) Set Backup role */
2421 ptp
->selectedRole
= roleBackup
;
2423 /* reset updtInfo for both k) and l) */
2424 ptp
->updtInfo
= false;
2427 else /* designatedPriority is better than portPriority */
2429 /* m) Set Designated role */
2430 ptp
->selectedRole
= roleDesignated
;
2431 ptp
->updtInfo
= true;
2439 /* 13.27 The Port Timers state machine */
2441 static void PTSM_tick(port_t
*prt
)
2443 per_tree_port_t
*ptp
;
2447 if(prt
->mdelayWhile
)
2448 --(prt
->mdelayWhile
);
2449 if(prt
->edgeDelayWhile
)
2450 --(prt
->edgeDelayWhile
);
2454 FOREACH_PTP_IN_PORT(ptp
, prt
)
2464 if(0 == --(ptp
->tcWhile
))
2465 set_TopologyChange(ptp
->tree
, false);
2467 if(ptp
->rcvdInfoWhile
)
2468 --(ptp
->rcvdInfoWhile
);
2472 /* 13.28 Port Receive state machine */
2473 #define PRSM_begin(prt) PRSM_to_DISCARD(prt)
2474 static void PRSM_to_DISCARD(port_t
*prt
/*, bool begin*/)
2476 prt
->PRSM_state
= PRSM_DISCARD
;
2478 prt
->rcvdBpdu
= false;
2479 prt
->rcvdRSTP
= false;
2480 prt
->rcvdSTP
= false;
2481 clearAllRcvdMsgs(prt
);
2482 assign(prt
->edgeDelayWhile
, prt
->bridge
->Migrate_Time
);
2484 /* No need to run, no one condition will be met
2489 static void PRSM_to_RECEIVE(port_t
*prt
)
2491 prt
->PRSM_state
= PRSM_RECEIVE
;
2493 updtBPDUVersion(prt
);
2494 prt
->rcvdInternal
= fromSameRegion(prt
);
2496 prt
->operEdge
= false;
2497 prt
->rcvdBpdu
= false;
2498 assign(prt
->edgeDelayWhile
, prt
->bridge
->Migrate_Time
);
2500 /* No need to run, no one condition will be met
2504 static void PRSM_run(port_t
*prt
)
2506 per_tree_port_t
*ptp
;
2509 if((prt
->rcvdBpdu
|| (prt
->edgeDelayWhile
!= prt
->bridge
->Migrate_Time
))
2510 && !prt
->portEnabled
)
2512 PRSM_to_DISCARD(prt
);
2516 switch(prt
->PRSM_state
)
2519 if(prt
->rcvdBpdu
&& prt
->portEnabled
)
2520 PRSM_to_RECEIVE(prt
);
2524 FOREACH_PTP_IN_PORT(ptp
, prt
)
2532 if(prt
->rcvdBpdu
&& prt
->portEnabled
&& !rcvdAnyMsg
)
2533 PRSM_to_RECEIVE(prt
);
2538 /* 13.29 Port Protocol Migration state machine */
2540 static void PPMSM_run(port_t
*prt
);
2541 #define PPMSM_begin(prt) PPMSM_to_CHECKING_RSTP(prt)
2543 static void PPMSM_to_CHECKING_RSTP(port_t
*prt
/*, bool begin*/)
2545 prt
->PPMSM_state
= PPMSM_CHECKING_RSTP
;
2547 bridge_t
*br
= prt
->bridge
;
2548 prt
->mcheck
= false;
2549 prt
->sendRSTP
= rstpVersion(br
);
2550 assign(prt
->mdelayWhile
, br
->Migrate_Time
);
2552 /* No need to run, no one condition will be met
2554 * PPMSM_run(prt); */
2557 static void PPMSM_to_SELECTING_STP(port_t
*prt
)
2559 prt
->PPMSM_state
= PPMSM_SELECTING_STP
;
2561 prt
->sendRSTP
= false;
2562 assign(prt
->mdelayWhile
, prt
->bridge
->Migrate_Time
);
2567 static void PPMSM_to_SENSING(port_t
*prt
)
2569 prt
->PPMSM_state
= PPMSM_SENSING
;
2571 prt
->rcvdRSTP
= false;
2572 prt
->rcvdSTP
= false;
2577 static void PPMSM_run(port_t
*prt
)
2579 bridge_t
*br
= prt
->bridge
;
2581 switch(prt
->PPMSM_state
)
2583 case PPMSM_CHECKING_RSTP
:
2584 if((prt
->mdelayWhile
!= br
->Migrate_Time
)
2585 && !prt
->portEnabled
)
2587 PPMSM_to_CHECKING_RSTP(prt
);
2590 if(0 == prt
->mdelayWhile
)
2591 PPMSM_to_SENSING(prt
);
2593 case PPMSM_SELECTING_STP
:
2594 if(0 == prt
->mdelayWhile
|| !prt
->portEnabled
|| prt
->mcheck
)
2595 PPMSM_to_SENSING(prt
);
2598 if(!prt
->portEnabled
|| prt
->mcheck
2599 || (rstpVersion(br
) && !prt
->sendRSTP
&& prt
->rcvdRSTP
))
2601 PPMSM_to_CHECKING_RSTP(prt
);
2604 if(prt
->sendRSTP
&& prt
->rcvdSTP
)
2605 PPMSM_to_SELECTING_STP(prt
);
2610 /* 13.30 Bridge Detection state machine */
2611 static void BDSM_to_EDGE(port_t
*prt
/*, bool begin*/)
2613 prt
->BDSM_state
= BDSM_EDGE
;
2615 prt
->operEdge
= true;
2617 /* No need to run, no one condition will be met
2622 static void BDSM_to_NOT_EDGE(port_t
*prt
/*, bool begin*/)
2624 prt
->BDSM_state
= BDSM_NOT_EDGE
;
2626 prt
->operEdge
= false;
2628 /* No need to run, no one condition will be met
2633 static void BDSM_begin(port_t
*prt
/*, bool begin*/)
2635 if(prt
->AdminEdgePort
)
2636 BDSM_to_EDGE(prt
/*, begin*/);
2638 BDSM_to_NOT_EDGE(prt
/*, begin*/);
2641 static void BDSM_run(port_t
*prt
)
2643 per_tree_port_t
*cist
;
2645 switch(prt
->BDSM_state
)
2648 if((!prt
->portEnabled
&& !prt
->AdminEdgePort
) || !prt
->operEdge
)
2649 BDSM_to_NOT_EDGE(prt
);
2652 cist
= GET_CIST_PTP_FROM_PORT(prt
);
2653 /* NOTE: 802.1Q-2005 is not clear, which of the per-tree
2654 * "proposing" flags to use here, or one should combine
2655 * them all for all trees? Maybe 802.1Q-2011 clarifies
2656 * this, but I don't have the text.
2657 * So, I decide that it will be the "proposing" flag
2658 * from CIST tree - it seems like a good bet.
2660 if((!prt
->portEnabled
&& prt
->AdminEdgePort
)
2661 || ((0 == prt
->edgeDelayWhile
) && prt
->AutoEdge
&& prt
->sendRSTP
2669 /* 13.31 Port Transmit state machine */
2671 static void PTSM_run(port_t
*prt
);
2672 #define PTSM_begin(prt) PTSM_to_TRANSMIT_INIT((prt), true)
2674 static void PTSM_to_TRANSMIT_INIT(port_t
*prt
, bool begin
)
2676 prt
->PTSM_state
= PTSM_TRANSMIT_INIT
;
2678 prt
->newInfo
= true;
2679 prt
->newInfoMsti
= true;
2680 assign(prt
->txCount
, 0u);
2682 if(!begin
&& prt
->portEnabled
) /* prevent infinite loop */
2686 static void PTSM_to_TRANSMIT_CONFIG(port_t
*prt
)
2688 prt
->PTSM_state
= PTSM_TRANSMIT_CONFIG
;
2690 prt
->newInfo
= false;
2698 static void PTSM_to_TRANSMIT_TCN(port_t
*prt
)
2700 prt
->PTSM_state
= PTSM_TRANSMIT_TCN
;
2702 prt
->newInfo
= false;
2709 static void PTSM_to_TRANSMIT_RSTP(port_t
*prt
)
2711 prt
->PTSM_state
= PTSM_TRANSMIT_RSTP
;
2713 prt
->newInfo
= false;
2714 prt
->newInfoMsti
= false;
2722 static void PTSM_to_TRANSMIT_PERIODIC(port_t
*prt
)
2724 prt
->PTSM_state
= PTSM_TRANSMIT_PERIODIC
;
2726 per_tree_port_t
*ptp
= GET_CIST_PTP_FROM_PORT(prt
);
2727 bool cistDesignatedOrTCpropagatingRootPort
=
2728 (roleDesignated
== ptp
->role
)
2729 || ((roleRoot
== ptp
->role
) && (0 != ptp
->tcWhile
));
2730 bool mstiDesignatedOrTCpropagatingRootPort
;
2732 mstiDesignatedOrTCpropagatingRootPort
= false;
2733 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2735 if((roleDesignated
== ptp
->role
)
2736 || ((roleRoot
== ptp
->role
) && (0 != ptp
->tcWhile
))
2739 mstiDesignatedOrTCpropagatingRootPort
= true;
2744 prt
->newInfo
= prt
->newInfo
|| cistDesignatedOrTCpropagatingRootPort
;
2745 prt
->newInfoMsti
= prt
->newInfoMsti
2746 || mstiDesignatedOrTCpropagatingRootPort
;
2751 static void PTSM_to_IDLE(port_t
*prt
)
2753 prt
->PTSM_state
= PTSM_IDLE
;
2755 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2756 prt
->helloWhen
= cist
->portTimes
.Hello_Time
;
2761 static void PTSM_run(port_t
*prt
)
2763 /* bool allTransmitReady; */
2764 per_tree_port_t
*ptp
;
2765 port_role_t cistRole
;
2766 bool mstiMasterPort
;
2768 if(!prt
->portEnabled
)
2770 PTSM_to_TRANSMIT_INIT(prt
, false);
2774 switch(prt
->PTSM_state
)
2776 case PTSM_TRANSMIT_INIT
:
2778 case PTSM_TRANSMIT_CONFIG
:
2780 case PTSM_TRANSMIT_TCN
:
2782 case PTSM_TRANSMIT_RSTP
:
2784 case PTSM_TRANSMIT_PERIODIC
:
2785 PTSM_to_IDLE(prt
); /* UnConditional Transition */
2788 /* allTransmitReady = true; */
2789 ptp
= GET_CIST_PTP_FROM_PORT(prt
);
2790 if(!ptp
->selected
|| ptp
->updtInfo
)
2792 /* allTransmitReady = false; */
2795 cistRole
= ptp
->role
;
2796 mstiMasterPort
= false;
2797 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2799 if(!ptp
->selected
|| ptp
->updtInfo
)
2801 /* allTransmitReady = false; */
2804 if(roleMaster
== ptp
->role
)
2805 mstiMasterPort
= true;
2807 if(0 == prt
->helloWhen
)
2809 PTSM_to_TRANSMIT_PERIODIC(prt
);
2812 if(!(prt
->txCount
< prt
->bridge
->Transmit_Hold_Count
))
2815 { /* implement MSTP */
2816 if(prt
->newInfo
|| (prt
->newInfoMsti
&& !mstiMasterPort
))
2818 PTSM_to_TRANSMIT_RSTP(prt
);
2823 { /* fallback to STP */
2824 if(prt
->newInfo
&& (roleDesignated
== cistRole
))
2826 PTSM_to_TRANSMIT_CONFIG(prt
);
2829 if(prt
->newInfo
&& (roleRoot
== cistRole
))
2831 PTSM_to_TRANSMIT_TCN(prt
);
2839 /* 13.32 Port Information state machine */
2841 #ifdef PISM_ENABLE_LOG
2842 #define PISM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args)
2844 #define PISM_LOG(_fmt, _args...) {}
2845 #endif /* PISM_ENABLE_LOG */
2847 static void PISM_run(per_tree_port_t
*ptp
);
2848 #define PISM_begin(ptp) PISM_to_DISABLED((ptp), true)
2850 static void PISM_to_DISABLED(per_tree_port_t
*ptp
, bool begin
)
2853 ptp
->PISM_state
= PISM_DISABLED
;
2855 ptp
->rcvdMsg
= false;
2856 ptp
->proposing
= false;
2857 ptp
->proposed
= false;
2859 ptp
->agreed
= false;
2860 assign(ptp
->rcvdInfoWhile
, 0u);
2861 ptp
->infoIs
= ioDisabled
;
2862 ptp
->reselect
= true;
2863 ptp
->selected
= false;
2869 static void PISM_to_AGED(per_tree_port_t
*ptp
)
2872 ptp
->PISM_state
= PISM_AGED
;
2874 ptp
->infoIs
= ioAged
;
2875 ptp
->reselect
= true;
2876 ptp
->selected
= false;
2881 static void PISM_to_UPDATE(per_tree_port_t
*ptp
)
2884 ptp
->PISM_state
= PISM_UPDATE
;
2886 ptp
->proposing
= false;
2887 ptp
->proposed
= false;
2888 ptp
->agreed
= ptp
->agreed
&& betterorsameInfo(ptp
, ioMine
);
2889 ptp
->synced
= ptp
->synced
&& ptp
->agreed
;
2890 assign(ptp
->portPriority
, ptp
->designatedPriority
);
2891 assign(ptp
->portTimes
, ptp
->designatedTimes
);
2892 ptp
->updtInfo
= false;
2893 ptp
->infoIs
= ioMine
;
2894 /* newInfoXst = TRUE; */
2895 port_t
*prt
= ptp
->port
;
2897 prt
->newInfo
= true;
2899 prt
->newInfoMsti
= true;
2904 static void PISM_to_SUPERIOR_DESIGNATED(per_tree_port_t
*ptp
)
2907 ptp
->PISM_state
= PISM_SUPERIOR_DESIGNATED
;
2909 port_t
*prt
= ptp
->port
;
2911 prt
->infoInternal
= prt
->rcvdInternal
;
2912 ptp
->agreed
= false;
2913 ptp
->proposing
= false;
2914 recordProposal(ptp
);
2916 ptp
->agree
= ptp
->agree
&& betterorsameInfo(ptp
, ioReceived
);
2917 recordAgreement(ptp
);
2918 ptp
->synced
= ptp
->synced
&& ptp
->agreed
;
2919 recordPriority(ptp
);
2921 updtRcvdInfoWhile(ptp
);
2922 ptp
->infoIs
= ioReceived
;
2923 ptp
->reselect
= true;
2924 ptp
->selected
= false;
2925 ptp
->rcvdMsg
= false;
2930 static void PISM_to_REPEATED_DESIGNATED(per_tree_port_t
*ptp
)
2933 ptp
->PISM_state
= PISM_REPEATED_DESIGNATED
;
2935 port_t
*prt
= ptp
->port
;
2937 prt
->infoInternal
= prt
->rcvdInternal
;
2938 recordProposal(ptp
);
2940 recordAgreement(ptp
);
2941 updtRcvdInfoWhile(ptp
);
2942 ptp
->rcvdMsg
= false;
2947 static void PISM_to_INFERIOR_DESIGNATED(per_tree_port_t
*ptp
)
2950 ptp
->PISM_state
= PISM_INFERIOR_DESIGNATED
;
2953 ptp
->rcvdMsg
= false;
2958 static void PISM_to_NOT_DESIGNATED(per_tree_port_t
*ptp
)
2961 ptp
->PISM_state
= PISM_NOT_DESIGNATED
;
2963 recordAgreement(ptp
);
2965 ptp
->rcvdMsg
= false;
2970 static void PISM_to_OTHER(per_tree_port_t
*ptp
)
2973 ptp
->PISM_state
= PISM_OTHER
;
2975 ptp
->rcvdMsg
= false;
2980 static void PISM_to_CURRENT(per_tree_port_t
*ptp
)
2983 ptp
->PISM_state
= PISM_CURRENT
;
2988 static void PISM_to_RECEIVE(per_tree_port_t
*ptp
)
2991 ptp
->PISM_state
= PISM_RECEIVE
;
2993 ptp
->rcvdInfo
= rcvInfo(ptp
);
2994 recordMastered(ptp
);
2999 static void PISM_run(per_tree_port_t
*ptp
)
3001 bool rcvdXstMsg
, updtXstInfo
;
3002 port_t
*prt
= ptp
->port
;
3004 if((!prt
->portEnabled
) && (ioDisabled
!= ptp
->infoIs
))
3006 PISM_to_DISABLED(ptp
, false);
3010 switch(ptp
->PISM_state
)
3013 if(prt
->portEnabled
)
3019 PISM_to_DISABLED(ptp
, false);
3022 if(ptp
->selected
&& ptp
->updtInfo
)
3023 PISM_to_UPDATE(ptp
);
3027 case PISM_SUPERIOR_DESIGNATED
:
3029 case PISM_REPEATED_DESIGNATED
:
3031 case PISM_INFERIOR_DESIGNATED
:
3033 case PISM_NOT_DESIGNATED
:
3036 PISM_to_CURRENT(ptp
);
3040 * Although 802.1Q-2005 does not define rcvdXstMsg and updtXstInfo
3041 * from 802.1s we can conclude that they are:
3042 * - rcvdXstMsg = rcvdCistMsg, if tree is CIST
3043 * rcvdMstiMsg, if tree is MSTI.
3044 * - updtXstInfo = updtCistInfo, if tree is CIST
3045 * updtMstiInfo, if tree is MSTI.
3049 rcvdXstMsg
= ptp
->rcvdMsg
; /* 13.25.12 */
3050 updtXstInfo
= ptp
->updtInfo
; /* 13.25.16 */
3054 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
3055 rcvdXstMsg
= !cist
->rcvdMsg
&& ptp
->rcvdMsg
; /* 13.25.13 */
3056 updtXstInfo
= ptp
->updtInfo
|| cist
->updtInfo
; /* 13.25.17 */
3058 if(rcvdXstMsg
&& !updtXstInfo
)
3060 PISM_to_RECEIVE(ptp
);
3063 if((ioReceived
== ptp
->infoIs
) && (0 == ptp
->rcvdInfoWhile
)
3064 && !ptp
->updtInfo
&& !rcvdXstMsg
)
3069 if(ptp
->selected
&& ptp
->updtInfo
)
3070 PISM_to_UPDATE(ptp
);
3073 switch(ptp
->rcvdInfo
)
3075 case SuperiorDesignatedInfo
:
3076 PISM_to_SUPERIOR_DESIGNATED(ptp
);
3078 case RepeatedDesignatedInfo
:
3079 PISM_to_REPEATED_DESIGNATED(ptp
);
3081 case InferiorDesignatedInfo
:
3082 PISM_to_INFERIOR_DESIGNATED(ptp
);
3084 case InferiorRootAlternateInfo
:
3085 PISM_to_NOT_DESIGNATED(ptp
);
3095 /* 13.33 Port Role Selection state machine */
3097 static void PRSSM_run(tree_t
*tree
);
3098 #define PRSSM_begin(tree) PRSSM_to_INIT_TREE(tree)
3100 static void PRSSM_to_INIT_TREE(tree_t
*tree
/*, bool begin*/)
3102 tree
->PRSSM_state
= PRSSM_INIT_TREE
;
3104 updtRolesDisabledTree(tree
);
3106 /* No need to check, as we assume begin = true here
3107 * because transition to this state can be initiated only by BEGIN var.
3108 * In other words, this function is called via xxx_begin macro only.
3110 * PRSSM_run(prt); */
3113 static void PRSSM_to_ROLE_SELECTION(tree_t
*tree
)
3115 tree
->PRSSM_state
= PRSSM_ROLE_SELECTION
;
3117 clearReselectTree(tree
);
3118 updtRolesTree(tree
);
3119 setSelectedTree(tree
);
3121 /* No need to run, no one condition will be met
3125 static void PRSSM_run(tree_t
*tree
)
3127 per_tree_port_t
*ptp
;
3129 switch(tree
->PRSSM_state
)
3131 case PRSSM_INIT_TREE
:
3132 PRSSM_to_ROLE_SELECTION(tree
);
3134 case PRSSM_ROLE_SELECTION
:
3135 FOREACH_PTP_IN_TREE(ptp
, tree
)
3138 PRSSM_to_ROLE_SELECTION(tree
);
3145 /* 13.34 Port Role Transitions state machine */
3147 #ifdef PRTSM_ENABLE_LOG
3148 #define PRTSM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args)
3150 #define PRTSM_LOG(_fmt, _args...) {}
3151 #endif /* PRTSM_ENABLE_LOG */
3153 static void PRTSM_runr(per_tree_port_t
*ptp
, bool recursive_call
);
3154 #define PRTSM_run(ptp) PRTSM_runr((ptp), false)
3155 #define PRTSM_begin(ptp) PRTSM_to_INIT_PORT(ptp)
3157 /* Disabled Port role transitions */
3159 static void PRTSM_to_INIT_PORT(per_tree_port_t
*ptp
/*, bool begin*/)
3162 ptp
->PRTSM_state
= PRTSM_INIT_PORT
;
3164 unsigned int MaxAge
, FwdDelay
;
3165 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(ptp
->port
);
3167 ptp
->role
= roleDisabled
;
3169 ptp
->forward
= false;
3170 ptp
->synced
= false;
3174 FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
3175 assign(ptp
->rrWhile
, FwdDelay
);
3177 MaxAge
= cist
->designatedTimes
.Max_Age
;
3178 assign(ptp
->fdWhile
, MaxAge
);
3179 assign(ptp
->rbWhile
, 0u);
3181 /* No need to check, as we assume begin = true here
3182 * because transition to this state can be initiated only by BEGIN var.
3183 * In other words, this function is called via xxx_begin macro only.
3185 * PRTSM_runr(ptp, false); */
3188 static void PRTSM_to_DISABLE_PORT(per_tree_port_t
*ptp
)
3191 ptp
->PRTSM_state
= PRTSM_DISABLE_PORT
;
3193 /* Although 802.1Q-2005 says here to do role = selectedRole
3194 * I have difficulties with it in the next scenario:
3195 * 1) port was designated (role == selectedRole == roleDesignated)
3196 * 2) some config event occurs, e.g. MAC address changes and
3197 * br_state_machines_begin is called
3198 * 3) role == selectedRole == roleDisabled, PRTSM_state = PRTSM_INIT_PORT
3199 * Because port was not actually down, on the next run
3200 * Port Role Selection state machine sets selectedRole = roleDesignated
3201 * and updtInfo = true:
3202 * 4) we have unconditional transition to DISABLE_PORT, and because
3203 * updtInfo = true we can not follow transition to DESIGNATED_PORT
3204 * 5) if we follow standard, role = selectedRole = roleDesignated and
3205 * on the next run we have transition to the DISABLED_PORT
3206 * And there we stuck. role == selectedRole, so we can not transit to
3207 * DESIGNATED_PORT (it requires role != selectedRole ).
3209 * Solution: do not follow the standard, and do role = roleDisabled
3210 * instead of role = selectedRole.
3212 ptp
->role
= roleDisabled
;
3214 ptp
->forward
= false;
3216 PRTSM_runr(ptp
, true);
3219 static void PRTSM_to_DISABLED_PORT(per_tree_port_t
*ptp
, unsigned int MaxAge
)
3222 ptp
->PRTSM_state
= PRTSM_DISABLED_PORT
;
3224 assign(ptp
->fdWhile
, MaxAge
);
3226 assign(ptp
->rrWhile
, 0u);
3228 ptp
->reRoot
= false;
3230 PRTSM_runr(ptp
, true);
3233 /* MasterPort role transitions */
3235 static void PRTSM_to_MASTER_PROPOSED(per_tree_port_t
*ptp
)
3238 ptp
->PRTSM_state
= PRTSM_MASTER_PROPOSED
;
3240 setSyncTree(ptp
->tree
);
3241 ptp
->proposed
= false;
3243 PRTSM_runr(ptp
, true);
3246 static void PRTSM_to_MASTER_AGREED(per_tree_port_t
*ptp
)
3249 ptp
->PRTSM_state
= PRTSM_MASTER_AGREED
;
3251 ptp
->proposed
= false;
3255 PRTSM_runr(ptp
, true);
3258 static void PRTSM_to_MASTER_SYNCED(per_tree_port_t
*ptp
)
3261 ptp
->PRTSM_state
= PRTSM_MASTER_SYNCED
;
3263 assign(ptp
->rrWhile
, 0u);
3267 PRTSM_runr(ptp
, true);
3270 static void PRTSM_to_MASTER_RETIRED(per_tree_port_t
*ptp
)
3273 ptp
->PRTSM_state
= PRTSM_MASTER_RETIRED
;
3275 ptp
->reRoot
= false;
3277 PRTSM_runr(ptp
, true);
3280 static void PRTSM_to_MASTER_FORWARD(per_tree_port_t
*ptp
)
3283 ptp
->PRTSM_state
= PRTSM_MASTER_FORWARD
;
3285 ptp
->forward
= true;
3286 assign(ptp
->fdWhile
, 0u);
3287 ptp
->agreed
= ptp
->port
->sendRSTP
;
3289 PRTSM_runr(ptp
, true);
3292 static void PRTSM_to_MASTER_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3295 ptp
->PRTSM_state
= PRTSM_MASTER_LEARN
;
3298 assign(ptp
->fdWhile
, forwardDelay
);
3300 PRTSM_runr(ptp
, true);
3303 static void PRTSM_to_MASTER_DISCARD(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3306 ptp
->PRTSM_state
= PRTSM_MASTER_DISCARD
;
3309 ptp
->forward
= false;
3310 ptp
->disputed
= false;
3311 assign(ptp
->fdWhile
, forwardDelay
);
3313 PRTSM_runr(ptp
, true);
3316 static void PRTSM_to_MASTER_PORT(per_tree_port_t
*ptp
)
3319 ptp
->PRTSM_state
= PRTSM_MASTER_PORT
;
3321 ptp
->role
= roleMaster
;
3323 PRTSM_runr(ptp
, true);
3326 /* RootPort role transitions */
3328 static void PRTSM_to_ROOT_PROPOSED(per_tree_port_t
*ptp
)
3331 ptp
->PRTSM_state
= PRTSM_ROOT_PROPOSED
;
3333 setSyncTree(ptp
->tree
);
3334 ptp
->proposed
= false;
3336 PRTSM_runr(ptp
, true);
3339 static void PRTSM_to_ROOT_AGREED(per_tree_port_t
*ptp
)
3342 ptp
->PRTSM_state
= PRTSM_ROOT_AGREED
;
3344 ptp
->proposed
= false;
3347 /* newInfoXst = TRUE; */
3348 port_t
*prt
= ptp
->port
;
3350 prt
->newInfo
= true;
3352 prt
->newInfoMsti
= true;
3354 PRTSM_runr(ptp
, true);
3357 static void PRTSM_to_ROOT_SYNCED(per_tree_port_t
*ptp
)
3360 ptp
->PRTSM_state
= PRTSM_ROOT_SYNCED
;
3365 PRTSM_runr(ptp
, true);
3368 static void PRTSM_to_REROOT(per_tree_port_t
*ptp
)
3371 ptp
->PRTSM_state
= PRTSM_REROOT
;
3373 setReRootTree(ptp
->tree
);
3375 PRTSM_runr(ptp
, true);
3378 static void PRTSM_to_ROOT_FORWARD(per_tree_port_t
*ptp
)
3381 ptp
->PRTSM_state
= PRTSM_ROOT_FORWARD
;
3383 assign(ptp
->fdWhile
, 0u);
3384 ptp
->forward
= true;
3386 PRTSM_runr(ptp
, true);
3389 static void PRTSM_to_ROOT_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3392 ptp
->PRTSM_state
= PRTSM_ROOT_LEARN
;
3394 assign(ptp
->fdWhile
, forwardDelay
);
3397 PRTSM_runr(ptp
, true);
3400 static void PRTSM_to_REROOTED(per_tree_port_t
*ptp
)
3403 ptp
->PRTSM_state
= PRTSM_REROOTED
;
3405 ptp
->reRoot
= false;
3407 PRTSM_runr(ptp
, true);
3410 static void PRTSM_to_ROOT_PORT(per_tree_port_t
*ptp
, unsigned int FwdDelay
)
3413 ptp
->PRTSM_state
= PRTSM_ROOT_PORT
;
3415 ptp
->role
= roleRoot
;
3416 assign(ptp
->rrWhile
, FwdDelay
);
3418 PRTSM_runr(ptp
, true);
3421 /* DesignatedPort role transitions */
3423 static void PRTSM_to_DESIGNATED_PROPOSE(per_tree_port_t
*ptp
)
3426 ptp
->PRTSM_state
= PRTSM_DESIGNATED_PROPOSE
;
3428 port_t
*prt
= ptp
->port
;
3430 ptp
->proposing
= true;
3431 /* newInfoXst = TRUE; */
3434 /* 13.25.8. This tree is CIST. */
3435 unsigned int MaxAge
= ptp
->designatedTimes
.Max_Age
;
3436 /* 13.25.c) -> 17.20.4 of 802.1D : EdgeDelay */
3437 unsigned int EdgeDelay
= prt
->operPointToPointMAC
?
3438 prt
->bridge
->Migrate_Time
3440 assign(prt
->edgeDelayWhile
, EdgeDelay
);
3441 prt
->newInfo
= true;
3444 prt
->newInfoMsti
= true;
3446 PRTSM_runr(ptp
, true);
3449 static void PRTSM_to_DESIGNATED_AGREED(per_tree_port_t
*ptp
)
3452 ptp
->PRTSM_state
= PRTSM_DESIGNATED_AGREED
;
3454 ptp
->proposed
= false;
3457 /* newInfoXst = TRUE; */
3458 port_t
*prt
= ptp
->port
;
3460 prt
->newInfo
= true;
3462 prt
->newInfoMsti
= true;
3464 PRTSM_runr(ptp
, true);
3467 static void PRTSM_to_DESIGNATED_SYNCED(per_tree_port_t
*ptp
)
3470 ptp
->PRTSM_state
= PRTSM_DESIGNATED_SYNCED
;
3472 assign(ptp
->rrWhile
, 0u);
3476 PRTSM_runr(ptp
, true);
3479 static void PRTSM_to_DESIGNATED_RETIRED(per_tree_port_t
*ptp
)
3482 ptp
->PRTSM_state
= PRTSM_DESIGNATED_RETIRED
;
3484 ptp
->reRoot
= false;
3486 PRTSM_runr(ptp
, true);
3489 static void PRTSM_to_DESIGNATED_FORWARD(per_tree_port_t
*ptp
)
3492 ptp
->PRTSM_state
= PRTSM_DESIGNATED_FORWARD
;
3494 ptp
->forward
= true;
3495 assign(ptp
->fdWhile
, 0u);
3496 ptp
->agreed
= ptp
->port
->sendRSTP
;
3498 PRTSM_runr(ptp
, true);
3501 static void PRTSM_to_DESIGNATED_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3504 ptp
->PRTSM_state
= PRTSM_DESIGNATED_LEARN
;
3507 assign(ptp
->fdWhile
, forwardDelay
);
3509 PRTSM_runr(ptp
, true);
3512 static void PRTSM_to_DESIGNATED_DISCARD(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3515 ptp
->PRTSM_state
= PRTSM_DESIGNATED_DISCARD
;
3518 ptp
->forward
= false;
3519 ptp
->disputed
= false;
3520 assign(ptp
->fdWhile
, forwardDelay
);
3522 PRTSM_runr(ptp
, true);
3525 static void PRTSM_to_DESIGNATED_PORT(per_tree_port_t
*ptp
)
3528 ptp
->PRTSM_state
= PRTSM_DESIGNATED_PORT
;
3530 ptp
->role
= roleDesignated
;
3532 PRTSM_runr(ptp
, true);
3535 /* AlternatePort and BackupPort role transitions */
3537 static void PRTSM_to_BLOCK_PORT(per_tree_port_t
*ptp
)
3540 ptp
->PRTSM_state
= PRTSM_BLOCK_PORT
;
3542 ptp
->role
= ptp
->selectedRole
;
3544 ptp
->forward
= false;
3546 PRTSM_runr(ptp
, true);
3549 static void PRTSM_to_BACKUP_PORT(per_tree_port_t
*ptp
, unsigned int HelloTime
)
3552 ptp
->PRTSM_state
= PRTSM_BACKUP_PORT
;
3554 assign(ptp
->rbWhile
, 2 * HelloTime
);
3556 PRTSM_runr(ptp
, true);
3559 static void PRTSM_to_ALTERNATE_PROPOSED(per_tree_port_t
*ptp
)
3562 ptp
->PRTSM_state
= PRTSM_ALTERNATE_PROPOSED
;
3564 setSyncTree(ptp
->tree
);
3565 ptp
->proposed
= false;
3567 PRTSM_runr(ptp
, true);
3570 static void PRTSM_to_ALTERNATE_AGREED(per_tree_port_t
*ptp
)
3573 ptp
->PRTSM_state
= PRTSM_ALTERNATE_AGREED
;
3575 ptp
->proposed
= false;
3577 /* newInfoXst = TRUE; */
3578 port_t
*prt
= ptp
->port
;
3580 prt
->newInfo
= true;
3582 prt
->newInfoMsti
= true;
3584 PRTSM_runr(ptp
, true);
3587 static void PRTSM_to_ALTERNATE_PORT(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3590 ptp
->PRTSM_state
= PRTSM_ALTERNATE_PORT
;
3592 assign(ptp
->fdWhile
, forwardDelay
);
3594 assign(ptp
->rrWhile
, 0u);
3596 ptp
->reRoot
= false;
3598 PRTSM_runr(ptp
, true);
3601 static void PRTSM_runr(per_tree_port_t
*ptp
, bool recursive_call
)
3603 /* Following vars do not need recalculating on recursive calls */
3604 static unsigned int MaxAge
, FwdDelay
, forwardDelay
, HelloTime
;
3606 static tree_t
*tree
;
3607 static per_tree_port_t
*cist
;
3608 /* Following vars are recalculated on each state transition */
3609 bool allSynced
, reRooted
;
3610 /* Following vars are auxiliary and don't depend on recursive_call */
3611 per_tree_port_t
*ptp_1
;
3614 { /* calculate these intermediate vars only first time in chain of
3615 * recursive calls */
3619 cist
= GET_CIST_PTP_FROM_PORT(prt
);
3622 FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
3625 HelloTime
= cist
->portTimes
.Hello_Time
;
3627 /* 13.25.d) -> 17.20.5 of 802.1D */
3628 forwardDelay
= prt
->sendRSTP
? HelloTime
: FwdDelay
;
3631 MaxAge
= cist
->designatedTimes
.Max_Age
;
3634 PRTSM_LOG("role = %d, selectedRole = %d, selected = %d, updtInfo = %d",
3635 ptp
->role
, ptp
->selectedRole
, ptp
->selected
, ptp
->updtInfo
);
3636 if((ptp
->role
!= ptp
->selectedRole
) && ptp
->selected
&& !ptp
->updtInfo
)
3638 switch(ptp
->selectedRole
)
3641 PRTSM_to_DISABLE_PORT(ptp
);
3644 PRTSM_to_MASTER_PORT(ptp
);
3647 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3649 case roleDesignated
:
3650 PRTSM_to_DESIGNATED_PORT(ptp
);
3654 PRTSM_to_BLOCK_PORT(ptp
);
3661 FOREACH_PTP_IN_TREE(ptp_1
, tree
)
3665 || (ptp_1
->role
!= ptp_1
->selectedRole
)
3678 if((roleRoot
!= ptp_1
->role
) && !ptp_1
->synced
)
3681 case roleDesignated
:
3683 if((ptp
!= ptp_1
) && !ptp_1
->synced
)
3693 switch(ptp
->PRTSM_state
)
3695 /* Disabled Port role transitions */
3696 case PRTSM_INIT_PORT
:
3697 PRTSM_to_DISABLE_PORT(ptp
);
3699 case PRTSM_DISABLE_PORT
:
3700 if(ptp
->selected
&& !ptp
->updtInfo
3701 && !ptp
->learning
&& !ptp
->forwarding
3703 PRTSM_to_DISABLED_PORT(ptp
, MaxAge
);
3705 case PRTSM_DISABLED_PORT
:
3706 if(ptp
->selected
&& !ptp
->updtInfo
3707 && (ptp
->sync
|| ptp
->reRoot
|| !ptp
->synced
3708 || (ptp
->fdWhile
!= MaxAge
))
3710 PRTSM_to_DISABLED_PORT(ptp
, MaxAge
);
3712 /* MasterPort role transitions */
3713 case PRTSM_MASTER_PROPOSED
:
3715 case PRTSM_MASTER_AGREED
:
3717 case PRTSM_MASTER_SYNCED
:
3719 case PRTSM_MASTER_RETIRED
:
3721 case PRTSM_MASTER_FORWARD
:
3723 case PRTSM_MASTER_LEARN
:
3725 case PRTSM_MASTER_DISCARD
:
3726 PRTSM_to_MASTER_PORT(ptp
);
3728 case PRTSM_MASTER_PORT
:
3729 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3731 if(ptp
->reRoot
&& (0 == ptp
->rrWhile
))
3733 PRTSM_to_MASTER_RETIRED(ptp
);
3736 if((!ptp
->learning
&& !ptp
->forwarding
&& !ptp
->synced
)
3737 || (ptp
->agreed
&& !ptp
->synced
)
3738 || (prt
->operEdge
&& !ptp
->synced
)
3739 || (ptp
->sync
&& ptp
->synced
)
3742 PRTSM_to_MASTER_SYNCED(ptp
);
3745 if((allSynced
&& !ptp
->agree
)
3746 || (ptp
->proposed
&& ptp
->agree
)
3749 PRTSM_to_MASTER_AGREED(ptp
);
3752 if(ptp
->proposed
&& !ptp
->agree
)
3754 PRTSM_to_MASTER_PROPOSED(ptp
);
3757 if(((0 == ptp
->fdWhile
) || allSynced
)
3758 && ptp
->learn
&& !ptp
->forward
3761 PRTSM_to_MASTER_FORWARD(ptp
);
3764 if(((0 == ptp
->fdWhile
) || allSynced
)
3768 PRTSM_to_MASTER_LEARN(ptp
, forwardDelay
);
3771 if(((ptp
->sync
&& !ptp
->synced
)
3772 || (ptp
->reRoot
&& (0 != ptp
->rrWhile
))
3775 && !prt
->operEdge
&& (ptp
->learn
|| ptp
->forward
)
3778 PRTSM_to_MASTER_DISCARD(ptp
, forwardDelay
);
3782 /* RootPort role transitions */
3783 case PRTSM_ROOT_PROPOSED
:
3785 case PRTSM_ROOT_AGREED
:
3787 case PRTSM_ROOT_SYNCED
:
3791 case PRTSM_ROOT_FORWARD
:
3793 case PRTSM_ROOT_LEARN
:
3795 case PRTSM_REROOTED
:
3796 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3798 case PRTSM_ROOT_PORT
:
3799 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3801 if(!ptp
->forward
&& !ptp
->reRoot
)
3803 PRTSM_to_REROOT(ptp
);
3806 if((ptp
->agreed
&& !ptp
->synced
) || (ptp
->sync
&& ptp
->synced
))
3808 PRTSM_to_ROOT_SYNCED(ptp
);
3811 if((allSynced
&& !ptp
->agree
) || (ptp
->proposed
&& ptp
->agree
))
3813 PRTSM_to_ROOT_AGREED(ptp
);
3816 if(ptp
->proposed
&& !ptp
->agree
)
3818 PRTSM_to_ROOT_PROPOSED(ptp
);
3821 /* 17.20.10 of 802.1D : reRooted */
3823 FOREACH_PTP_IN_TREE(ptp_1
, tree
)
3825 if((ptp
!= ptp_1
) && (0 != ptp_1
->rrWhile
))
3831 if((0 == ptp
->fdWhile
)
3832 || (reRooted
&& (0 == ptp
->rbWhile
) && rstpVersion(prt
->bridge
))
3837 PRTSM_to_ROOT_LEARN(ptp
, forwardDelay
);
3840 else if(!ptp
->forward
)
3842 PRTSM_to_ROOT_FORWARD(ptp
);
3846 if(ptp
->reRoot
&& ptp
->forward
)
3848 PRTSM_to_REROOTED(ptp
);
3851 if(ptp
->rrWhile
!= FwdDelay
)
3853 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3857 /* DesignatedPort role transitions */
3858 case PRTSM_DESIGNATED_PROPOSE
:
3860 case PRTSM_DESIGNATED_AGREED
:
3862 case PRTSM_DESIGNATED_SYNCED
:
3864 case PRTSM_DESIGNATED_RETIRED
:
3866 case PRTSM_DESIGNATED_FORWARD
:
3868 case PRTSM_DESIGNATED_LEARN
:
3870 case PRTSM_DESIGNATED_DISCARD
:
3871 PRTSM_to_DESIGNATED_PORT(ptp
);
3873 case PRTSM_DESIGNATED_PORT
:
3874 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3876 if(ptp
->reRoot
&& (0 == ptp
->rrWhile
))
3878 PRTSM_to_DESIGNATED_RETIRED(ptp
);
3881 if((!ptp
->learning
&& !ptp
->forwarding
&& !ptp
->synced
)
3882 || (ptp
->agreed
&& !ptp
->synced
)
3883 || (prt
->operEdge
&& !ptp
->synced
)
3884 || (ptp
->sync
&& ptp
->synced
)
3887 PRTSM_to_DESIGNATED_SYNCED(ptp
);
3890 if(allSynced
&& (ptp
->proposed
|| !ptp
->agree
))
3892 PRTSM_to_DESIGNATED_AGREED(ptp
);
3895 if(!ptp
->forward
&& !ptp
->agreed
&& !ptp
->proposing
3898 PRTSM_to_DESIGNATED_PROPOSE(ptp
);
3901 if(((0 == ptp
->fdWhile
) || ptp
->agreed
|| prt
->operEdge
)
3902 && ((0 == ptp
->rrWhile
) || !ptp
->reRoot
) && !ptp
->sync
3907 PRTSM_to_DESIGNATED_LEARN(ptp
, forwardDelay
);
3910 else if(!ptp
->forward
)
3912 PRTSM_to_DESIGNATED_FORWARD(ptp
);
3916 if(((ptp
->sync
&& !ptp
->synced
)
3917 || (ptp
->reRoot
&& (0 != ptp
->rrWhile
))
3920 && !prt
->operEdge
&& (ptp
->learn
|| ptp
->forward
)
3923 PRTSM_to_DESIGNATED_DISCARD(ptp
, forwardDelay
);
3927 /* AlternatePort and BackupPort role transitions */
3928 case PRTSM_BLOCK_PORT
:
3929 if(ptp
->selected
&& !ptp
->updtInfo
3930 && !ptp
->learning
&& !ptp
->forwarding
3932 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3934 case PRTSM_BACKUP_PORT
:
3936 case PRTSM_ALTERNATE_PROPOSED
:
3938 case PRTSM_ALTERNATE_AGREED
:
3939 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3941 case PRTSM_ALTERNATE_PORT
:
3942 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3944 if((allSynced
&& !ptp
->agree
) || (ptp
->proposed
&& ptp
->agree
))
3946 PRTSM_to_ALTERNATE_AGREED(ptp
);
3949 if(ptp
->proposed
&& !ptp
->agree
)
3951 PRTSM_to_ALTERNATE_PROPOSED(ptp
);
3954 if((ptp
->rbWhile
!= 2 * HelloTime
) && (roleBackup
== ptp
->role
))
3956 PRTSM_to_BACKUP_PORT(ptp
, HelloTime
);
3959 if((ptp
->fdWhile
!= forwardDelay
) || ptp
->sync
|| ptp
->reRoot
3962 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3969 /* 13.35 Port State Transition state machine */
3971 static void PSTSM_run(per_tree_port_t
*ptp
);
3972 #define PSTSM_begin(ptp) PSTSM_to_DISCARDING((ptp), true)
3974 static void PSTSM_to_DISCARDING(per_tree_port_t
*ptp
, bool begin
)
3976 ptp
->PSTSM_state
= PSTSM_DISCARDING
;
3978 /* This effectively sets BLOCKING state:
3980 disableForwarding();
3982 if(BR_STATE_BLOCKING
!= ptp
->state
)
3983 MSTP_OUT_set_state(ptp
, BR_STATE_BLOCKING
);
3984 ptp
->learning
= false;
3985 ptp
->forwarding
= false;
3991 static void PSTSM_to_LEARNING(per_tree_port_t
*ptp
)
3993 ptp
->PSTSM_state
= PSTSM_LEARNING
;
3995 /* enableLearning(); */
3996 if(BR_STATE_LEARNING
!= ptp
->state
)
3997 MSTP_OUT_set_state(ptp
, BR_STATE_LEARNING
);
3998 ptp
->learning
= true;
4003 static void PSTSM_to_FORWARDING(per_tree_port_t
*ptp
)
4005 ptp
->PSTSM_state
= PSTSM_FORWARDING
;
4007 /* enableForwarding(); */
4008 if(BR_STATE_FORWARDING
!= ptp
->state
)
4009 MSTP_OUT_set_state(ptp
, BR_STATE_FORWARDING
);
4010 ptp
->forwarding
= true;
4012 /* No need to run, no one condition will be met
4016 static void PSTSM_run(per_tree_port_t
*ptp
)
4018 switch(ptp
->PSTSM_state
)
4020 case PSTSM_DISCARDING
:
4022 PSTSM_to_LEARNING(ptp
);
4024 case PSTSM_LEARNING
:
4026 PSTSM_to_DISCARDING(ptp
, false);
4027 else if(ptp
->forward
)
4028 PSTSM_to_FORWARDING(ptp
);
4030 case PSTSM_FORWARDING
:
4032 PSTSM_to_DISCARDING(ptp
, false);
4037 /* 13.36 Topology Change state machine */
4039 #define TCSM_begin(ptp) TCSM_to_INACTIVE((ptp), true)
4041 static void TCSM_to_INACTIVE(per_tree_port_t
*ptp
, bool begin
)
4043 ptp
->TCSM_state
= TCSM_INACTIVE
;
4046 assign(ptp
->tcWhile
, 0u);
4047 set_TopologyChange(ptp
->tree
, false);
4048 if(0 == ptp
->MSTID
) /* CIST */
4049 ptp
->port
->tcAck
= false;
4055 static void TCSM_to_LEARNING(per_tree_port_t
*ptp
)
4057 ptp
->TCSM_state
= TCSM_LEARNING
;
4059 if(0 == ptp
->MSTID
) /* CIST */
4061 port_t
*prt
= ptp
->port
;
4062 prt
->rcvdTcn
= false;
4063 prt
->rcvdTcAck
= false;
4065 ptp
->rcvdTc
= false;
4066 ptp
->tcProp
= false;
4071 static void TCSM_to_DETECTED(per_tree_port_t
*ptp
)
4073 ptp
->TCSM_state
= TCSM_DETECTED
;
4077 /* newInfoXst = TRUE; */
4078 port_t
*prt
= ptp
->port
;
4080 prt
->newInfo
= true;
4082 prt
->newInfoMsti
= true;
4087 static void TCSM_to_NOTIFIED_TCN(per_tree_port_t
*ptp
)
4089 ptp
->TCSM_state
= TCSM_NOTIFIED_TCN
;
4096 static void TCSM_to_NOTIFIED_TC(per_tree_port_t
*ptp
)
4098 ptp
->TCSM_state
= TCSM_NOTIFIED_TC
;
4100 ptp
->rcvdTc
= false;
4101 if(0 == ptp
->MSTID
) /* CIST */
4103 port_t
*prt
= ptp
->port
;
4104 prt
->rcvdTcn
= false;
4105 if(roleDesignated
== ptp
->role
)
4113 static void TCSM_to_PROPAGATING(per_tree_port_t
*ptp
)
4115 ptp
->TCSM_state
= TCSM_PROPAGATING
;
4119 ptp
->tcProp
= false;
4124 static void TCSM_to_ACKNOWLEDGED(per_tree_port_t
*ptp
)
4126 ptp
->TCSM_state
= TCSM_ACKNOWLEDGED
;
4128 assign(ptp
->tcWhile
, 0u);
4129 set_TopologyChange(ptp
->tree
, false);
4130 ptp
->port
->rcvdTcAck
= false;
4135 static void TCSM_to_ACTIVE(per_tree_port_t
*ptp
)
4137 ptp
->TCSM_state
= TCSM_ACTIVE
;
4142 static void TCSM_run(per_tree_port_t
*ptp
)
4145 port_t
*prt
= ptp
->port
;
4147 switch(ptp
->TCSM_state
)
4150 if(ptp
->learn
&& !ptp
->fdbFlush
)
4151 TCSM_to_LEARNING(ptp
);
4154 active_port
= (roleRoot
== ptp
->role
)
4155 || (roleDesignated
== ptp
->role
)
4156 || (roleMaster
== ptp
->role
);
4157 if(active_port
&& ptp
->forward
&& !prt
->operEdge
)
4159 TCSM_to_DETECTED(ptp
);
4162 if(ptp
->rcvdTc
|| prt
->rcvdTcn
|| prt
->rcvdTcAck
|| ptp
->tcProp
)
4164 TCSM_to_LEARNING(ptp
);
4167 else if(!active_port
&& !(ptp
->learn
|| ptp
->learning
))
4168 TCSM_to_INACTIVE(ptp
, false);
4170 case TCSM_NOTIFIED_TCN
:
4171 TCSM_to_NOTIFIED_TC(ptp
);
4175 case TCSM_NOTIFIED_TC
:
4177 case TCSM_PROPAGATING
:
4179 case TCSM_ACKNOWLEDGED
:
4180 TCSM_to_ACTIVE(ptp
);
4183 active_port
= (roleRoot
== ptp
->role
)
4184 || (roleDesignated
== ptp
->role
)
4185 || (roleMaster
== ptp
->role
);
4186 if(!active_port
|| prt
->operEdge
)
4188 TCSM_to_LEARNING(ptp
);
4193 TCSM_to_NOTIFIED_TCN(ptp
);
4198 TCSM_to_NOTIFIED_TC(ptp
);
4201 if(ptp
->tcProp
/* && !prt->operEdge */)
4203 TCSM_to_PROPAGATING(ptp
);
4208 TCSM_to_ACKNOWLEDGED(ptp
);
4215 /* Execute BEGIN state. We do not define BEGIN variable
4216 * but instead xxx_state_machines_begin execute begin state
4217 * abd do one step out of it
4220 static void tree_state_machines_begin(tree_t
*tree
)
4222 bridge_t
*br
= tree
->bridge
;
4223 per_tree_port_t
*ptp
;
4225 if(!br
->bridgeEnabled
)
4228 /* 13.32 Port Information state machine */
4229 FOREACH_PTP_IN_TREE(ptp
, tree
)
4231 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4235 /* 13.33 Port Role Selection state machine */
4238 /* 13.34 Port Role Transitions state machine */
4239 FOREACH_PTP_IN_TREE(ptp
, tree
)
4241 /* 13.35 Port State Transition state machine */
4242 FOREACH_PTP_IN_TREE(ptp
, tree
)
4244 /* 13.36 Topology Change state machine */
4245 FOREACH_PTP_IN_TREE(ptp
, tree
)
4248 br_state_machines_run(br
);
4251 static void prt_state_machines_begin(port_t
*prt
)
4253 bridge_t
*br
= prt
->bridge
;
4255 per_tree_port_t
*ptp
;
4257 if(!br
->bridgeEnabled
)
4260 /* 13.28 Port Receive state machine */
4262 /* 13.29 Port Protocol Migration state machine */
4264 /* 13.30 Bridge Detection state machine */
4266 /* 13.31 Port Transmit state machine */
4269 /* 13.32 Port Information state machine */
4270 FOREACH_PTP_IN_PORT(ptp
, prt
)
4272 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4276 /* 13.33 Port Role Selection state machine */
4277 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4280 /* 13.34 Port Role Transitions state machine */
4281 FOREACH_PTP_IN_PORT(ptp
, prt
)
4283 /* 13.35 Port State Transition state machine */
4284 FOREACH_PTP_IN_PORT(ptp
, prt
)
4286 /* 13.36 Topology Change state machine */
4287 FOREACH_PTP_IN_PORT(ptp
, prt
)
4290 br_state_machines_run(br
);
4293 static void br_state_machines_begin(bridge_t
*br
)
4296 per_tree_port_t
*ptp
;
4299 if(!br
->bridgeEnabled
)
4302 /* 13.28 Port Receive state machine */
4303 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4305 /* 13.29 Port Protocol Migration state machine */
4306 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4308 /* 13.30 Bridge Detection state machine */
4309 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4311 /* 13.31 Port Transmit state machine */
4312 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4315 /* 13.32 Port Information state machine */
4316 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4318 FOREACH_PTP_IN_PORT(ptp
, prt
)
4320 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4325 /* 13.33 Port Role Selection state machine */
4326 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4329 /* 13.34 Port Role Transitions state machine */
4330 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4332 FOREACH_PTP_IN_PORT(ptp
, prt
)
4335 /* 13.35 Port State Transition state machine */
4336 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4338 FOREACH_PTP_IN_PORT(ptp
, prt
)
4341 /* 13.36 Topology Change state machine */
4342 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4344 FOREACH_PTP_IN_PORT(ptp
, prt
)
4348 br_state_machines_run(br
);
4351 /* Run each state machine */
4352 static void br_state_machines_run(bridge_t
*br
)
4355 per_tree_port_t
*ptp
;
4358 if(!br
->bridgeEnabled
)
4361 /* 13.28 Port Receive state machine */
4362 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4364 /* 13.29 Port Protocol Migration state machine */
4365 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4367 /* 13.30 Bridge Detection state machine */
4368 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4370 /* 13.31 Port Transmit state machine */
4371 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4374 /* 13.32 Port Information state machine */
4375 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4377 FOREACH_PTP_IN_PORT(ptp
, prt
)
4381 /* 13.33 Port Role Selection state machine */
4382 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4385 /* 13.34 Port Role Transitions state machine */
4386 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4388 FOREACH_PTP_IN_PORT(ptp
, prt
)
4391 /* 13.35 Port State Transition state machine */
4392 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4394 FOREACH_PTP_IN_PORT(ptp
, prt
)
4397 /* 13.36 Topology Change state machine */
4398 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4400 FOREACH_PTP_IN_PORT(ptp
, prt
)