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
->Ageing_Time
, 300u);/* 8.8.3 Table 8-3 */
200 assign(br
->rapidAgeingWhile
, 0u);
205 if(!(cist
= create_tree(br
, macaddr
, 0)))
207 list_add_tail(&cist
->bridge_list
, &br
->trees
);
209 br_state_machines_begin(br
);
213 bool MSTP_IN_port_create_and_add_tail(port_t
*prt
, __u16 portno
)
216 per_tree_port_t
*ptp
, *nxt
;
217 bridge_t
*br
= prt
->bridge
;
219 /* Initialize all fields except sysdeps and bridge */
220 INIT_LIST_HEAD(&prt
->trees
);
221 prt
->port_number
= __cpu_to_be16(portno
);
223 assign(prt
->AdminExternalPortPathCost
, 0u);
224 /* Default for operP2P is false because by default AdminP2P
225 * says to auto-detect p2p state, and it is derived from duplex
226 * and initially port is in down state and in this down state
227 * duplex is set to false (half) */
228 prt
->AdminP2P
= p2pAuto
;
229 prt
->operPointToPointMAC
= false;
230 prt
->portEnabled
= false;
231 prt
->infoInternal
= false;
232 prt
->rcvdInternal
= false;
233 prt
->rcvdTcAck
= false;
234 prt
->rcvdTcn
= false;
235 prt
->restrictedRole
= false; /* 13.25.14 */
236 prt
->restrictedTcn
= false; /* 13.25.15 */
237 assign(prt
->ExternalPortPathCost
, MAX_PATH_COST
); /* 13.37.1 */
238 prt
->AdminEdgePort
= false; /* 13.25 */
239 prt
->AutoEdge
= true; /* 13.25 */
241 /* The following are initialized in BEGIN state:
242 * - mdelayWhile. mcheck, sendRSTP: in Port Protocol Migration SM
243 * - helloWhen, newInfo, newInfoMsti, txCount: in Port Transmit SM
244 * - edgeDelayWhile, rcvdBpdu, rcvdRSTP, rcvdSTP : in Port Receive SM
245 * - operEdge: in Bridge Detection SM
246 * - tcAck: in Topology Change SM
249 /* Create PerTreePort structures for all existing trees */
250 FOREACH_TREE_IN_BRIDGE(tree
, br
)
252 if(!(ptp
= create_ptp(tree
, prt
)))
254 /* Remove and free all previously created entries in port's list */
255 list_for_each_entry_safe(ptp
, nxt
, &prt
->trees
, port_list
)
257 list_del(&ptp
->port_list
);
258 list_del(&ptp
->tree_list
);
263 list_add_tail(&ptp
->port_list
, &prt
->trees
);
264 list_add_tail(&ptp
->tree_list
, &tree
->ports
);
267 /* Add new port to the tail of the list in the bridge */
268 /* NOTE: if one wants add port NOT to the tail of the list of ports,
269 * one should revise above loop (FOREACH_TREE_IN_BRIDGE)
270 * because it heavily depends on the fact that port is added to the tail.
272 list_add_tail(&prt
->br_list
, &br
->ports
);
274 prt_state_machines_begin(prt
);
278 void MSTP_IN_delete_port(port_t
*prt
)
280 per_tree_port_t
*ptp
, *nxt
;
281 bridge_t
*br
= prt
->bridge
;
285 prt
->portEnabled
= false;
286 br_state_machines_run(br
);
289 list_for_each_entry_safe(ptp
, nxt
, &prt
->trees
, port_list
)
291 list_del(&ptp
->port_list
);
292 list_del(&ptp
->tree_list
);
296 br_state_machines_run(br
);
299 void MSTP_IN_delete_bridge(bridge_t
*br
)
301 tree_t
*tree
, *nxt_tree
;
302 port_t
*prt
, *nxt_prt
;
304 br
->bridgeEnabled
= false;
306 /* We SHOULD first delete all ports and only THEN delete all tree_t
307 * structures as the tree_t structure contains the head for the per-port
308 * list of tree data (tree_t.ports).
309 * If this list_head will be deleted before all the per_tree_ports
310 * bad things will happen ;)
313 list_for_each_entry_safe(prt
, nxt_prt
, &br
->ports
, br_list
)
315 list_del(&prt
->br_list
);
316 MSTP_IN_delete_port(prt
);
320 list_for_each_entry_safe(tree
, nxt_tree
, &br
->trees
, bridge_list
)
322 list_del(&tree
->bridge_list
);
327 void MSTP_IN_set_bridge_address(bridge_t
*br
, __u8
*macaddr
)
330 bool changed
= false;
332 FOREACH_TREE_IN_BRIDGE(tree
, br
)
334 if(0 == memcmp(tree
->BridgeIdentifier
.s
.mac_address
, macaddr
, ETH_ALEN
))
337 memcpy(tree
->BridgeIdentifier
.s
.mac_address
, macaddr
, ETH_ALEN
);
338 tree
->BridgePriority
.RootID
= tree
->BridgePriority
.RRootID
=
339 tree
->BridgePriority
.DesignatedBridgeID
= tree
->BridgeIdentifier
;
343 br_state_machines_begin(br
);
346 void MSTP_IN_set_bridge_enable(bridge_t
*br
, bool up
)
348 if(br
->bridgeEnabled
== up
)
350 br
->bridgeEnabled
= up
;
351 br_state_machines_begin(br
);
354 void MSTP_IN_set_port_enable(port_t
*prt
, bool up
, int speed
, int duplex
)
356 __u32 computed_pcost
, new_ExternalPathCost
, new_InternalPathCost
;
357 per_tree_port_t
*ptp
;
359 bool changed
= false;
363 computed_pcost
= compute_pcost(speed
);
364 new_ExternalPathCost
= (0 == prt
->AdminExternalPortPathCost
) ?
366 : prt
->AdminExternalPortPathCost
;
367 if(prt
->ExternalPortPathCost
!= new_ExternalPathCost
)
369 assign(prt
->ExternalPortPathCost
, new_ExternalPathCost
);
372 FOREACH_PTP_IN_PORT(ptp
, prt
)
374 new_InternalPathCost
= (0 == ptp
->AdminInternalPortPathCost
) ?
376 : ptp
->AdminInternalPortPathCost
;
377 if(ptp
->InternalPortPathCost
!= new_InternalPathCost
)
379 assign(ptp
->InternalPortPathCost
, new_InternalPathCost
);
384 switch(prt
->AdminP2P
)
397 if(prt
->operPointToPointMAC
!= new_p2p
)
399 prt
->operPointToPointMAC
= new_p2p
;
403 if(!prt
->portEnabled
)
405 prt
->portEnabled
= true;
413 prt
->portEnabled
= false;
419 br_state_machines_run(prt
->bridge
);
422 void MSTP_IN_one_second(bridge_t
*br
)
429 if(!br
->bridgeEnabled
)
432 FOREACH_TREE_IN_BRIDGE(tree
, br
)
433 if(!(tree
->topology_change
))
434 ++(tree
->time_since_topology_change
);
436 FOREACH_PORT_IN_BRIDGE(prt
, br
)
438 /* support for rapid ageing */
439 if(br
->rapidAgeingWhile
)
441 if((--(br
->rapidAgeingWhile
)) == 0)
442 MSTP_OUT_set_ageing_time(br
, br
->Ageing_Time
);
445 br_state_machines_run(br
);
448 void MSTP_IN_all_fids_flushed(per_tree_port_t
*ptp
)
450 bridge_t
*br
= ptp
->port
->bridge
;
451 ptp
->fdbFlush
= false;
452 if(!br
->bridgeEnabled
)
454 if(!ptp
->calledFromFlushRoutine
)
457 br_state_machines_run(br
);
461 /* NOTE: bpdu pointer is unaligned, but it works because
462 * bpdu_t is packed. Don't try to cast bpdu to non-packed type ;)
464 void MSTP_IN_rx_bpdu(port_t
*prt
, bpdu_t
*bpdu
, int size
)
467 bridge_t
*br
= prt
->bridge
;
469 if(!br
->bridgeEnabled
)
471 INFO_PRTNAME(br
, prt
, "Received BPDU while bridge is disabled");
477 ERROR_PRTNAME(br
, prt
, "Port hasn't processed previous BPDU");
481 /* 14.4 Validation */
482 if((TCN_BPDU_SIZE
> size
) || (0 != bpdu
->protocolIdentifier
))
484 bpdu_validation_failed
:
485 INFO_PRTNAME(br
, prt
, "BPDU validation failed");
488 switch(bpdu
->bpduType
)
493 bpdu
->protocolVersion
= protoSTP
;
494 LOG_PRTNAME(br
, prt
, "received TCN BPDU");
498 if(CONFIG_BPDU_SIZE
> size
)
499 goto bpdu_validation_failed
;
500 /* Valid Config BPDU */
501 bpdu
->protocolVersion
= protoSTP
;
502 LOG_PRTNAME(br
, prt
, "received Config BPDU");
505 if(protoRSTP
== bpdu
->protocolVersion
)
507 if(RST_BPDU_SIZE
> size
)
508 goto bpdu_validation_failed
;
510 /* bpdu->protocolVersion = protoRSTP; */
511 LOG_PRTNAME(br
, prt
, "received RST BPDU");
514 if(protoMSTP
> bpdu
->protocolVersion
)
515 goto bpdu_validation_failed
;
516 /* Yes, 802.1Q-2005 says here to check if it contains
517 * "35 or more octets", not 36! (see 14.4.d).1) )
518 * That's why I check size against CONFIG_BPDU_SIZE
519 * and not RST_BPDU_SIZE.
521 if(CONFIG_BPDU_SIZE
> size
)
522 goto bpdu_validation_failed
;
523 mstis_size
= __be16_to_cpu(bpdu
->version3_len
)
524 - MST_BPDU_VER3LEN_WO_MSTI_MSGS
;
525 if((MST_BPDU_SIZE_WO_MSTI_MSGS
> size
) || (0 != bpdu
->version1_len
)
527 || ((MAX_STANDARD_MSTIS
* sizeof(msti_configuration_message_t
))
529 || (0 != (mstis_size
% sizeof(msti_configuration_message_t
)))
533 bpdu
->protocolVersion
= protoRSTP
;
534 LOG_PRTNAME(br
, prt
, "received RST BPDU");
539 bpdu
->protocolVersion
= protoMSTP
;
540 prt
->rcvdBpduNumOfMstis
= mstis_size
541 / sizeof(msti_configuration_message_t
);
542 LOG_PRTNAME(br
, prt
, "received MST BPDU with %d MSTIs",
543 prt
->rcvdBpduNumOfMstis
);
546 goto bpdu_validation_failed
;
549 assign(prt
->rcvdBpduData
, *bpdu
);
550 prt
->rcvdBpdu
= true;
552 br_state_machines_run(br
);
555 /* 12.8.1.1 Read CIST Bridge Protocol Parameters */
556 void MSTP_IN_get_cist_bridge_status(bridge_t
*br
, CIST_BridgeStatus
*status
)
558 tree_t
*cist
= GET_CIST_TREE(br
);
559 assign(status
->bridge_id
, cist
->BridgeIdentifier
);
560 assign(status
->time_since_topology_change
,
561 cist
->time_since_topology_change
);
562 assign(status
->topology_change_count
, cist
->topology_change_count
);
563 status
->topology_change
= cist
->topology_change
;
564 assign(status
->designated_root
, cist
->rootPriority
.RootID
);
565 assign(status
->root_path_cost
,
566 __be32_to_cpu(cist
->rootPriority
.ExtRootPathCost
));
567 assign(status
->regional_root
, cist
->rootPriority
.RRootID
);
568 assign(status
->internal_path_cost
,
569 __be32_to_cpu(cist
->rootPriority
.IntRootPathCost
));
570 assign(status
->root_port_id
, cist
->rootPortId
);
571 assign(status
->root_max_age
, cist
->rootTimes
.Max_Age
);
572 assign(status
->root_forward_delay
, cist
->rootTimes
.Forward_Delay
);
573 assign(status
->bridge_max_age
, br
->Max_Age
);
574 assign(status
->bridge_forward_delay
, br
->Forward_Delay
);
575 assign(status
->max_hops
, br
->MaxHops
);
576 assign(status
->tx_hold_count
, br
->Transmit_Hold_Count
);
577 status
->protocol_version
= br
->ForceProtocolVersion
;
578 status
->enabled
= br
->bridgeEnabled
;
581 /* 12.8.1.2 Read MSTI Bridge Protocol Parameters */
582 void MSTP_IN_get_msti_bridge_status(tree_t
*tree
, MSTI_BridgeStatus
*status
)
584 assign(status
->bridge_id
, tree
->BridgeIdentifier
);
585 assign(status
->time_since_topology_change
,
586 tree
->time_since_topology_change
);
587 assign(status
->topology_change_count
, tree
->topology_change_count
);
588 status
->topology_change
= tree
->topology_change
;
589 assign(status
->regional_root
, tree
->rootPriority
.RRootID
);
590 assign(status
->internal_path_cost
,
591 __be32_to_cpu(tree
->rootPriority
.IntRootPathCost
));
592 assign(status
->root_port_id
, tree
->rootPortId
);
595 /* 12.8.1.3 Set CIST Bridge Protocol Parameters */
596 int MSTP_IN_set_cist_bridge_config(bridge_t
*br
, CIST_BridgeConfig
*cfg
)
598 bool changed
, changedBridgeTimes
, init
;
600 __u8 new_forward_delay
, new_max_age
;
603 per_tree_port_t
*ptp
;
605 /* Firstly, validation */
606 if(cfg
->set_bridge_max_age
)
608 new_max_age
= cfg
->bridge_max_age
;
609 if((6 > new_max_age
) || (40 < new_max_age
))
612 "Bridge Max Age must be between 6 and 40 seconds");
617 new_max_age
= br
->Max_Age
;
619 if(cfg
->set_bridge_forward_delay
)
621 new_forward_delay
= cfg
->bridge_forward_delay
;
622 if((4 > new_forward_delay
) || (30 < new_forward_delay
))
625 "Bridge Forward Delay must be between 4 and 30 seconds");
630 new_forward_delay
= br
->Forward_Delay
;
632 if(cfg
->set_bridge_max_age
|| cfg
->set_bridge_forward_delay
)
634 if((2 * (new_forward_delay
- 1)) < new_max_age
)
636 ERROR_BRNAME(br
, "Configured Bridge Times don't meet "
637 "2 * (Bridge Foward Delay - 1 second) >= Bridge Max Age");
642 if(cfg
->set_protocol_version
)
644 switch(cfg
->protocol_version
)
651 ERROR_BRNAME(br
, "Bad protocol version (%d)",
652 cfg
->protocol_version
);
657 if(cfg
->set_tx_hold_count
)
659 if((1 > cfg
->tx_hold_count
) || (10 < cfg
->tx_hold_count
))
662 "Transmit Hold Count must be between 1 and 10 seconds");
667 if(cfg
->set_max_hops
)
669 if((6 > cfg
->max_hops
) || (40 < cfg
->max_hops
))
671 ERROR_BRNAME(br
, "Bridge Max Hops must be between 6 and 40");
679 /* Secondly, do set */
680 changed
= changedBridgeTimes
= init
= false;
682 if(cfg
->set_bridge_max_age
|| cfg
->set_bridge_forward_delay
)
684 if(cmp(new_max_age
, !=, br
->Max_Age
)
685 || cmp(new_forward_delay
, !=, br
->Forward_Delay
)
688 assign(br
->Max_Age
, new_max_age
);
689 assign(br
->Forward_Delay
, new_forward_delay
);
690 changed
= changedBridgeTimes
= true;
694 if((cfg
->set_protocol_version
)
695 && (cfg
->protocol_version
!= br
->ForceProtocolVersion
)
698 br
->ForceProtocolVersion
= cfg
->protocol_version
;
699 changed
= init
= true;
702 if(cfg
->set_tx_hold_count
)
704 if(cfg
->tx_hold_count
!= br
->Transmit_Hold_Count
)
706 assign(br
->Transmit_Hold_Count
, cfg
->tx_hold_count
);
707 FOREACH_PORT_IN_BRIDGE(prt
, br
)
708 assign(prt
->txCount
, 0u);
713 if(cfg
->set_max_hops
)
715 if(cfg
->max_hops
!= br
->MaxHops
)
717 assign(br
->MaxHops
, cfg
->max_hops
);
718 changed
= changedBridgeTimes
= true;
722 /* Thirdly, finalize changes */
723 if(changedBridgeTimes
)
725 FOREACH_TREE_IN_BRIDGE(tree
, br
)
727 assign(tree
->BridgeTimes
.remainingHops
, br
->MaxHops
);
728 assign(tree
->BridgeTimes
.Forward_Delay
, br
->Forward_Delay
);
729 assign(tree
->BridgeTimes
.Max_Age
, br
->Max_Age
);
730 /* Comment found in rstpd by Srinivas Aji:
731 * Do this for any change in BridgeTimes.
732 * Otherwise we fail UNH rstp.op_D test 3.2 since when administratively
733 * setting BridgeForwardDelay, etc, the values don't propagate from
734 * rootTimes to designatedTimes immediately without this change.
736 FOREACH_PTP_IN_TREE(ptp
, tree
)
738 ptp
->selected
= false;
739 ptp
->reselect
= true;
744 if(changed
&& br
->bridgeEnabled
)
747 br_state_machines_begin(br
);
749 br_state_machines_run(br
);
755 /* 12.8.1.4 Set MSTI Bridge Protocol Parameters */
756 int MSTP_IN_set_msti_bridge_config(tree_t
*tree
, __u8 bridge_priority
)
758 per_tree_port_t
*ptp
;
761 if(15 < bridge_priority
)
763 ERROR_BRNAME(tree
->bridge
,
764 "MSTI %hu: Bridge Priority must be between 0 and 15",
765 __be16_to_cpu(tree
->MSTID
));
769 valuePri
= bridge_priority
<< 4;
770 if(GET_PRIORITY_FROM_IDENTIFIER(tree
->BridgeIdentifier
) == valuePri
)
772 SET_PRIORITY_IN_IDENTIFIER(valuePri
, tree
->BridgeIdentifier
);
773 tree
->BridgePriority
.RootID
= tree
->BridgePriority
.RRootID
=
774 tree
->BridgePriority
.DesignatedBridgeID
= tree
->BridgeIdentifier
;
775 /* 12.8.1.4.4 do not require reselect, but I think it is needed,
776 * because 12.8.1.3.4.c) requires it */
777 FOREACH_PTP_IN_TREE(ptp
, tree
)
779 ptp
->selected
= false;
780 ptp
->reselect
= true;
785 /* 12.8.2.1 Read CIST Port Parameters */
786 void MSTP_IN_get_cist_port_status(port_t
*prt
, CIST_PortStatus
*status
)
788 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
790 status
->uptime
= (signed int)((prt
->bridge
)->uptime
)
791 - (signed int)(cist
->start_time
);
792 status
->state
= cist
->state
;
793 assign(status
->port_id
, cist
->portId
);
794 assign(status
->admin_external_port_path_cost
,
795 prt
->AdminExternalPortPathCost
);
796 assign(status
->external_port_path_cost
, prt
->ExternalPortPathCost
);
797 assign(status
->designated_root
, cist
->portPriority
.RootID
);
798 assign(status
->designated_external_cost
,
799 __be32_to_cpu(cist
->portPriority
.ExtRootPathCost
));
800 assign(status
->designated_bridge
, cist
->portPriority
.DesignatedBridgeID
);
801 assign(status
->designated_port
, cist
->portPriority
.DesignatedPortID
);
802 assign(status
->designated_regional_root
, cist
->portPriority
.RRootID
);
803 assign(status
->designated_internal_cost
,
804 __be32_to_cpu(cist
->portPriority
.IntRootPathCost
));
805 status
->tc_ack
= prt
->tcAck
;
806 assign(status
->port_hello_time
, cist
->portTimes
.Hello_Time
);
807 status
->admin_edge_port
= prt
->AdminEdgePort
;
808 status
->auto_edge_port
= prt
->AutoEdge
;
809 status
->oper_edge_port
= prt
->operEdge
;
810 status
->enabled
= prt
->portEnabled
;
811 status
->admin_p2p
= prt
->AdminP2P
;
812 status
->oper_p2p
= prt
->operPointToPointMAC
;
813 status
->restricted_role
= prt
->restrictedRole
;
814 status
->restricted_tcn
= prt
->restrictedTcn
;
815 status
->role
= cist
->role
;
816 status
->disputed
= cist
->disputed
;
817 assign(status
->admin_internal_port_path_cost
,
818 cist
->AdminInternalPortPathCost
);
819 assign(status
->internal_port_path_cost
, cist
->InternalPortPathCost
);
822 /* 12.8.2.2 Read MSTI Port Parameters */
823 void MSTP_IN_get_msti_port_status(per_tree_port_t
*ptp
,
824 MSTI_PortStatus
*status
)
826 status
->uptime
= (signed int)((ptp
->port
->bridge
)->uptime
)
827 - (signed int)(ptp
->start_time
);
828 status
->state
= ptp
->state
;
829 assign(status
->port_id
, ptp
->portId
);
830 assign(status
->admin_internal_port_path_cost
,
831 ptp
->AdminInternalPortPathCost
);
832 assign(status
->internal_port_path_cost
, ptp
->InternalPortPathCost
);
833 assign(status
->designated_regional_root
, ptp
->portPriority
.RRootID
);
834 assign(status
->designated_internal_cost
,
835 __be32_to_cpu(ptp
->portPriority
.IntRootPathCost
));
836 assign(status
->designated_bridge
, ptp
->portPriority
.DesignatedBridgeID
);
837 assign(status
->designated_port
, ptp
->portPriority
.DesignatedPortID
);
838 status
->role
= ptp
->role
;
839 status
->disputed
= ptp
->disputed
;
842 /* 12.8.2.3 Set CIST port parameters */
843 int MSTP_IN_set_cist_port_config(port_t
*prt
, CIST_PortConfig
*cfg
)
846 __u32 new_ExternalPathCost
;
848 per_tree_port_t
*cist
;
850 /* Firstly, validation */
851 if(cfg
->set_admin_p2p
)
853 switch(cfg
->admin_p2p
)
860 cfg
->admin_p2p
= p2pAuto
;
864 /* Secondly, do set */
867 if(cfg
->set_admin_external_port_path_cost
)
869 prt
->AdminExternalPortPathCost
= cfg
->admin_external_port_path_cost
;
870 new_ExternalPathCost
= (0 == prt
->AdminExternalPortPathCost
) ?
871 compute_pcost(GET_PORT_SPEED(prt
))
872 : prt
->AdminExternalPortPathCost
;
873 if(prt
->ExternalPortPathCost
!= new_ExternalPathCost
)
875 assign(prt
->ExternalPortPathCost
, new_ExternalPathCost
);
878 cist
= GET_CIST_PTP_FROM_PORT(prt
);
879 cist
->selected
= false;
880 cist
->reselect
= true;
884 if(cfg
->set_admin_p2p
)
886 prt
->AdminP2P
= cfg
->admin_p2p
;
887 switch(prt
->AdminP2P
)
897 new_p2p
= !!GET_PORT_DUPLEX(prt
);
900 if(prt
->operPointToPointMAC
!= new_p2p
)
902 prt
->operPointToPointMAC
= new_p2p
;
907 if(cfg
->set_admin_edge_port
)
909 if(prt
->AdminEdgePort
!= cfg
->admin_edge_port
)
911 prt
->AdminEdgePort
= cfg
->admin_edge_port
;
917 if(cfg
->set_auto_edge_port
)
919 if(prt
->AutoEdge
!= cfg
->auto_edge_port
)
921 prt
->AutoEdge
= cfg
->auto_edge_port
;
926 if(cfg
->set_restricted_role
)
928 if(prt
->restrictedRole
!= cfg
->restricted_role
)
930 prt
->restrictedRole
= cfg
->restricted_role
;
935 if(cfg
->set_restricted_tcn
)
937 if(prt
->restrictedTcn
!= cfg
->restricted_tcn
)
939 prt
->restrictedTcn
= cfg
->restricted_tcn
;
944 if(changed
&& prt
->portEnabled
)
945 br_state_machines_run(prt
->bridge
);
950 /* 12.8.2.4 Set MSTI port parameters */
951 int MSTP_IN_set_msti_port_config(per_tree_port_t
*ptp
, MSTI_PortConfig
*cfg
)
954 __u32 new_InternalPathCost
;
955 bool changed
= false;
956 port_t
*prt
= ptp
->port
;
957 bridge_t
*br
= prt
->bridge
;
959 if(cfg
->set_port_priority
)
961 if(15 < cfg
->port_priority
)
963 ERROR_MSTINAME(br
, prt
, ptp
,
964 "Port Priority must be between 0 and 15");
967 valuePri
= cfg
->port_priority
<< 4;
968 if(GET_PRIORITY_FROM_IDENTIFIER(ptp
->portId
) != valuePri
)
970 SET_PRIORITY_IN_IDENTIFIER(valuePri
, ptp
->portId
);
975 if(cfg
->set_admin_internal_port_path_cost
)
977 ptp
->AdminInternalPortPathCost
= cfg
->admin_internal_port_path_cost
;
978 new_InternalPathCost
= (0 == ptp
->AdminInternalPortPathCost
) ?
979 compute_pcost(GET_PORT_SPEED(prt
))
980 : ptp
->AdminInternalPortPathCost
;
981 if(ptp
->InternalPortPathCost
!= new_InternalPathCost
)
983 assign(ptp
->InternalPortPathCost
, new_InternalPathCost
);
988 if(changed
&& prt
->portEnabled
)
991 ptp
->selected
= false;
992 ptp
->reselect
= true;
994 br_state_machines_run(br
);
1000 /* 12.8.2.5 Force BPDU Migration Check */
1001 int MSTP_IN_port_mcheck(port_t
*prt
)
1003 bridge_t
*br
= prt
->bridge
;
1005 if(rstpVersion(br
) && prt
->portEnabled
&& br
->bridgeEnabled
)
1008 br_state_machines_run(br
);
1014 /* 12.10.3.8 Set VID to FID allocation */
1015 bool MSTP_IN_set_vid2fid(bridge_t
*br
, __u16 vid
, __u16 fid
)
1017 bool vid2mstid_changed
;
1019 if((vid
< 1) || (vid
> MAX_VID
) || (fid
> MAX_FID
))
1021 ERROR_BRNAME(br
, "Error allocating VID(%hu) to FID(%hu)", vid
, fid
);
1026 (br
->fid2mstid
[fid
] != br
->fid2mstid
[br
->vid2fid
[vid
]]);
1027 br
->vid2fid
[vid
] = fid
;
1028 if(vid2mstid_changed
)
1030 RecalcConfigDigest(br
);
1031 br_state_machines_begin(br
);
1037 /* Set all VID-to-FID mappings at once */
1038 bool MSTP_IN_set_all_vids2fids(bridge_t
*br
, __u16
*vids2fids
)
1040 bool vid2mstid_changed
;
1043 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1044 if(vids2fids
[vid
] > MAX_FID
)
1046 ERROR_BRNAME(br
, "Error allocating VID(%hu) to FID(%hu)",
1047 vid
, vids2fids
[vid
]);
1051 vid2mstid_changed
= false;
1052 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1054 if(br
->fid2mstid
[vids2fids
[vid
]] != br
->fid2mstid
[br
->vid2fid
[vid
]])
1056 vid2mstid_changed
= true;
1060 memcpy(br
->vid2fid
, vids2fids
, sizeof(br
->vid2fid
));
1061 if(vid2mstid_changed
)
1063 RecalcConfigDigest(br
);
1064 br_state_machines_begin(br
);
1070 /* 12.12.2.2 Set FID to MSTID allocation */
1071 bool MSTP_IN_set_fid2mstid(bridge_t
*br
, __u16 fid
, __u16 mstid
)
1080 ERROR_BRNAME(br
, "Bad FID(%hu)", fid
);
1084 MSTID
= __cpu_to_be16(mstid
);
1086 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1088 if(tree
->MSTID
== MSTID
)
1096 ERROR_BRNAME(br
, "MSTID(%hu) not found", mstid
);
1100 if(br
->fid2mstid
[fid
] != MSTID
)
1102 br
->fid2mstid
[fid
] = MSTID
;
1103 /* check if there are VLANs using this FID */
1104 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1106 if(br
->vid2fid
[vid
] == fid
)
1108 RecalcConfigDigest(br
);
1109 br_state_machines_begin(br
);
1118 /* Set all FID-to-MSTID mappings at once */
1119 bool MSTP_IN_set_all_fids2mstids(bridge_t
*br
, __u16
*fids2mstids
)
1122 __be16 MSTID
[MAX_FID
+ 1];
1123 bool found
, vid2mstid_changed
;
1125 __be16 prev_vid2mstid
[MAX_VID
+ 2];
1127 for(fid
= 0; fid
<= MAX_FID
; ++fid
)
1129 MSTID
[fid
] = __cpu_to_be16(fids2mstids
[fid
]);
1131 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1133 if(tree
->MSTID
== MSTID
[fid
])
1142 "Error allocating FID(%hu) to MSTID(%hu): MSTID not found",
1143 fid
, fids2mstids
[fid
]);
1148 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1149 prev_vid2mstid
[vid
] = br
->fid2mstid
[br
->vid2fid
[vid
]];
1150 memcpy(br
->fid2mstid
, MSTID
, sizeof(br
->fid2mstid
));
1151 vid2mstid_changed
= false;
1152 for(vid
= 1; vid
<= MAX_VID
; ++vid
)
1154 if(prev_vid2mstid
[vid
] != br
->fid2mstid
[br
->vid2fid
[vid
]])
1156 vid2mstid_changed
= true;
1160 if(vid2mstid_changed
)
1162 RecalcConfigDigest(br
);
1163 br_state_machines_begin(br
);
1169 /* 12.12.1.1 Read MSTI List */
1170 bool MSTP_IN_get_mstilist(bridge_t
*br
, int *num_mstis
, __u16
*mstids
)
1175 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1177 mstids
[*num_mstis
] = __be16_to_cpu(tree
->MSTID
);
1178 /* Check for "<", not for "<=", as num_mstis include CIST */
1179 if(MAX_IMPLEMENTATION_MSTIS
< ++(*num_mstis
))
1186 /* 12.12.1.2 Create MSTI */
1187 bool MSTP_IN_create_msti(bridge_t
*br
, __u16 mstid
)
1189 tree_t
*tree
, *tree_after
, *new_tree
;
1190 per_tree_port_t
*ptp
, *nxt
, *ptp_after
, *new_ptp
;
1194 if((mstid
< 1) || (mstid
> MAX_MSTID
))
1196 ERROR_BRNAME(br
, "Bad MSTID(%hu)", mstid
);
1200 MSTID
= __cpu_to_be16(mstid
);
1201 /* Find place where to insert new MSTID.
1202 * Also check if such MSTID is already in the list.
1203 * Also count existing mstis.
1207 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1209 if(tree
->MSTID
== MSTID
)
1211 INFO_BRNAME(br
, "MSTID(%hu) is already in the list", mstid
);
1212 return true; /* yes, it is success */
1214 if(cmp(tree
->MSTID
, <, MSTID
))
1219 if(NULL
== tree_after
)
1221 ERROR_BRNAME(br
, "Can't add MSTID(%hu): no CIST in the list", mstid
);
1224 /* End of Sanity check */
1226 /* Check for "<", not for "<=", as num_of_mstis include CIST */
1227 if(MAX_IMPLEMENTATION_MSTIS
< num_of_mstis
)
1229 ERROR_BRNAME(br
, "Can't add MSTID(%hu): maximum count(%u) reached",
1230 mstid
, MAX_IMPLEMENTATION_MSTIS
);
1234 /* Create new tree and its list of PerTreePort structures */
1235 tree
= GET_CIST_TREE(br
);
1236 if(!(new_tree
=create_tree(br
,tree
->BridgeIdentifier
.s
.mac_address
,MSTID
)))
1239 FOREACH_PTP_IN_TREE(ptp_after
, tree_after
)
1241 if(!(new_ptp
= create_ptp(new_tree
, ptp_after
->port
)))
1243 /* Remove and free all previously created entries in tree's list */
1244 list_for_each_entry_safe(ptp
, nxt
, &new_tree
->ports
, tree_list
)
1246 list_del(&ptp
->port_list
);
1247 list_del(&ptp
->tree_list
);
1252 list_add(&new_ptp
->port_list
, &ptp_after
->port_list
);
1253 list_add_tail(&new_ptp
->tree_list
, &new_tree
->ports
);
1256 list_add(&new_tree
->bridge_list
, &tree_after
->bridge_list
);
1257 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping
1258 * did not change. So, no need in RecalcConfigDigest.
1259 * Just initialize state machines for this tree.
1261 tree_state_machines_begin(new_tree
);
1265 /* 12.12.1.3 Delete MSTI */
1266 bool MSTP_IN_delete_msti(bridge_t
*br
, __u16 mstid
)
1269 per_tree_port_t
*ptp
, *nxt
;
1272 __be16 MSTID
= __cpu_to_be16(mstid
);
1274 if((mstid
< 1) || (mstid
> MAX_MSTID
))
1276 ERROR_BRNAME(br
, "Bad MSTID(%hu)", mstid
);
1280 /* Check if there are FIDs associated with this MSTID */
1281 for(fid
= 0; fid
<= MAX_FID
; ++fid
)
1283 if(br
->fid2mstid
[fid
] == MSTID
)
1286 "Can't delete MSTID(%hu): there are FIDs allocated to it",
1293 FOREACH_TREE_IN_BRIDGE(tree
, br
)
1295 if(tree
->MSTID
== MSTID
)
1303 INFO_BRNAME(br
, "MSTID(%hu) is not in the list", mstid
);
1304 return true; /* yes, it is success */
1307 list_del(&tree
->bridge_list
);
1308 list_for_each_entry_safe(ptp
, nxt
, &tree
->ports
, tree_list
)
1310 list_del(&ptp
->port_list
);
1311 list_del(&ptp
->tree_list
);
1316 /* There are no FIDs allocated to this MSTID, so VID-to-MSTID mapping
1317 * did not change. So, no need in RecalcConfigDigest.
1318 * Give state machine a spare run, just for the case...
1320 br_state_machines_run(br
);
1324 /* 12.12.3.4 Set MST Configuration Identifier Elements */
1325 void MSTP_IN_set_mst_config_id(bridge_t
*br
, __u16 revision
, __u8
*name
)
1327 __be16 valueRevision
= __cpu_to_be16(revision
);
1328 bool changed
= (0 != strncmp(name
, br
->MstConfigId
.s
.configuration_name
,
1329 sizeof(br
->MstConfigId
.s
.configuration_name
))
1331 || (valueRevision
!= br
->MstConfigId
.s
.revision_level
);
1335 assign(br
->MstConfigId
.s
.revision_level
, valueRevision
);
1336 memset(br
->MstConfigId
.s
.configuration_name
, 0,
1337 sizeof(br
->MstConfigId
.s
.configuration_name
));
1338 strncpy(br
->MstConfigId
.s
.configuration_name
, name
,
1339 sizeof(br
->MstConfigId
.s
.configuration_name
));
1340 br_state_machines_begin(br
);
1345 * If hint_SetToYes == true, some tcWhile in this tree has non-zero value.
1346 * If hint_SetToYes == false, some tcWhile in this tree has just became zero,
1347 * so we should check all other tcWhile's in this tree.
1349 static void set_TopologyChange(tree_t
*tree
, bool hint_SetToYes
)
1351 per_tree_port_t
*ptp
;
1352 bool prev_tc_not_set
= !tree
->topology_change
;
1356 tree
->topology_change
= true;
1357 tree
->time_since_topology_change
= 0;
1359 ++(tree
->topology_change_count
);
1363 /* Some tcWhile has just became zero. Check if we need reset
1364 * topology_change flag */
1368 tree
->topology_change
= false;
1369 FOREACH_PTP_IN_TREE(ptp
, tree
)
1371 if(0 != ptp
->tcWhile
)
1373 tree
->topology_change
= true;
1374 tree
->time_since_topology_change
= 0;
1380 /* Helper functions, compare two priority vectors */
1381 static bool samePriorityAndTimers(port_priority_vector_t
*vec1
,
1382 port_priority_vector_t
*vec2
,
1389 if(cmp(time1
->Forward_Delay
, !=, time2
->Forward_Delay
))
1391 if(cmp(time1
->Max_Age
, !=, time2
->Max_Age
))
1393 if(cmp(time1
->Message_Age
, !=, time2
->Message_Age
))
1395 if(cmp(time1
->Hello_Time
, !=, time2
->Hello_Time
))
1398 if(cmp(vec1
->RootID
, !=, vec2
->RootID
))
1400 if(cmp(vec1
->ExtRootPathCost
, !=, vec2
->ExtRootPathCost
))
1404 if(cmp(time1
->remainingHops
, !=, time2
->remainingHops
))
1407 if(cmp(vec1
->RRootID
, !=, vec2
->RRootID
))
1409 if(cmp(vec1
->IntRootPathCost
, !=, vec2
->IntRootPathCost
))
1411 if(cmp(vec1
->DesignatedBridgeID
, !=, vec2
->DesignatedBridgeID
))
1413 if(cmp(vec1
->DesignatedPortID
, !=, vec2
->DesignatedPortID
))
1419 static bool betterorsamePriority(port_priority_vector_t
*vec1
,
1420 port_priority_vector_t
*vec2
,
1421 port_identifier_t pId1
,
1422 port_identifier_t pId2
,
1429 if(0 < (result
= _ncmp(vec1
->RootID
, vec2
->RootID
)))
1430 return false; /* worse */
1432 return true; /* better */
1433 /* The same. Check further. */
1434 if(0 < (result
= _ncmp(vec1
->ExtRootPathCost
, vec2
->ExtRootPathCost
)))
1435 return false; /* worse */
1437 return true; /* better */
1438 /* The same. Check further. */
1441 if(0 < (result
= _ncmp(vec1
->RRootID
, vec2
->RRootID
)))
1442 return false; /* worse */
1444 return true; /* better */
1445 /* The same. Check further. */
1447 if(0 < (result
= _ncmp(vec1
->IntRootPathCost
, vec2
->IntRootPathCost
)))
1448 return false; /* worse */
1450 return true; /* better */
1451 /* The same. Check further. */
1453 if(0 < (result
= _ncmp(vec1
->DesignatedBridgeID
, vec2
->DesignatedBridgeID
)))
1454 return false; /* worse */
1456 return true; /* better */
1457 /* The same. Check further. */
1459 if(0 < (result
= _ncmp(vec1
->DesignatedPortID
, vec2
->DesignatedPortID
)))
1460 return false; /* worse */
1462 return true; /* better */
1463 /* The same. Check further. */
1465 /* Port ID is a tie-breaker */
1466 return cmp(pId1
, <=, pId2
);
1469 /* 13.26.1 betterorsameInfo */
1470 static bool betterorsameInfo(per_tree_port_t
*ptp
, port_info_origin_t newInfoIs
)
1472 if((ioReceived
== newInfoIs
) && (ioReceived
== ptp
->infoIs
))
1473 return betterorsamePriority(&ptp
->msgPriority
,
1475 0, 0, (0 == ptp
->MSTID
));
1476 else if((ioMine
== newInfoIs
) && (ioMine
== ptp
->infoIs
))
1477 return betterorsamePriority(&ptp
->designatedPriority
,
1479 0, 0, (0 == ptp
->MSTID
));
1483 /* 13.26.2 clearAllRcvdMsgs */
1484 static void clearAllRcvdMsgs(port_t
*prt
)
1486 per_tree_port_t
*ptp
;
1488 FOREACH_PTP_IN_PORT(ptp
, prt
)
1489 ptp
->rcvdMsg
= false;
1492 /* 13.26.3 clearReselectTree */
1493 static void clearReselectTree(tree_t
*tree
)
1495 per_tree_port_t
*ptp
;
1497 FOREACH_PTP_IN_TREE(ptp
, tree
)
1498 ptp
->reselect
= false;
1501 /* 13.26.4 fromSameRegion */
1502 static bool fromSameRegion(port_t
*prt
)
1504 /* Check for rcvdRSTP is superfluous here */
1505 if((protoMSTP
> prt
->rcvdBpduData
.protocolVersion
)/* || (!prt->rcvdRSTP)*/)
1507 return cmp(prt
->bridge
->MstConfigId
,
1508 ==, prt
->rcvdBpduData
.mstConfigurationIdentifier
);
1511 /* 13.26.5 newTcWhile */
1512 static void newTcWhile(per_tree_port_t
*ptp
)
1514 if(0 != ptp
->tcWhile
)
1517 tree_t
*tree
= ptp
->tree
;
1518 port_t
*prt
= ptp
->port
;
1522 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
1524 ptp
->tcWhile
= cist
->portTimes
.Hello_Time
+ 1;
1525 set_TopologyChange(tree
, true);
1528 prt
->newInfo
= true;
1530 prt
->newInfoMsti
= true;
1534 times_t
*times
= &tree
->rootTimes
;
1536 ptp
->tcWhile
= times
->Max_Age
+ times
->Forward_Delay
;
1537 set_TopologyChange(tree
, true);
1540 /* 13.26.6 rcvInfo */
1541 static port_info_t
rcvInfo(per_tree_port_t
*ptp
)
1543 msti_configuration_message_t
*msti_msg
;
1544 per_tree_port_t
*ptp_1
;
1545 bool roleIsDesignated
, cist
;
1546 bool msg_Better_port
, msg_SamePriorityAndTimers_port
;
1547 port_priority_vector_t
*mPri
= &(ptp
->msgPriority
);
1548 times_t
*mTimes
= &(ptp
->msgTimes
);
1549 port_t
*prt
= ptp
->port
;
1550 bpdu_t
*b
= &(prt
->rcvdBpduData
);
1552 if(bpduTypeTCN
== b
->bpduType
)
1554 prt
->rcvdTcn
= true;
1555 FOREACH_PTP_IN_PORT(ptp_1
, prt
)
1556 ptp_1
->rcvdTc
= true;
1562 if(protoSTP
!= b
->protocolVersion
)
1564 switch(BPDU_FLAGS_ROLE_GET(b
->flags
))
1566 case encodedRoleAlternateBackup
:
1567 case encodedRoleRoot
:
1568 roleIsDesignated
= false;
1570 case encodedRoleDesignated
:
1571 roleIsDesignated
= true;
1578 { /* 13.26.6.NOTE: A Configuration BPDU implicitly conveys a
1579 * Designated Port Role */
1580 roleIsDesignated
= true;
1584 assign(mPri
->RRootID
, b
->cistRRootID
);
1585 assign(mPri
->DesignatedPortID
, b
->cistPortID
);
1586 assign(mPri
->RootID
, b
->cistRootID
);
1587 assign(mPri
->ExtRootPathCost
, b
->cistExtRootPathCost
);
1589 #define NEAREST_WHOLE_SECOND(msgTime) \
1590 ((128 > msgTime[1]) ? msgTime[0] : msgTime[0] + 1)
1591 mTimes
->Forward_Delay
= NEAREST_WHOLE_SECOND(b
->ForwardDelay
);
1592 mTimes
->Max_Age
= NEAREST_WHOLE_SECOND(b
->MaxAge
);
1593 mTimes
->Message_Age
= NEAREST_WHOLE_SECOND(b
->MessageAge
);
1594 mTimes
->Hello_Time
= NEAREST_WHOLE_SECOND(b
->HelloTime
);
1595 if(protoMSTP
> b
->protocolVersion
)
1596 { /* STP Configuration BPDU or RST BPDU */
1597 assign(mPri
->IntRootPathCost
, __constant_cpu_to_be32(0));
1598 assign(mPri
->DesignatedBridgeID
, b
->cistRRootID
);
1599 /* messageTimes.remainingHops */
1600 assign(mTimes
->remainingHops
, prt
->bridge
->MaxHops
);
1604 assign(mPri
->IntRootPathCost
, b
->cistIntRootPathCost
);
1605 assign(mPri
->DesignatedBridgeID
, b
->cistBridgeID
);
1606 /* messageTimes.remainingHops */
1607 assign(mTimes
->remainingHops
, b
->cistRemainingHops
);
1612 if(protoMSTP
> b
->protocolVersion
)
1614 msti_msg
= ptp
->rcvdMstiConfig
;
1615 switch(BPDU_FLAGS_ROLE_GET(msti_msg
->flags
))
1617 case encodedRoleAlternateBackup
:
1618 case encodedRoleRoot
:
1619 roleIsDesignated
= false;
1621 case encodedRoleDesignated
:
1622 roleIsDesignated
= true;
1629 assign(mPri
->RRootID
, msti_msg
->mstiRRootID
);
1630 assign(mPri
->IntRootPathCost
, msti_msg
->mstiIntRootPathCost
);
1631 /* Build MSTI DesignatedBridgeID */
1632 assign(mPri
->DesignatedBridgeID
, b
->cistBridgeID
);
1633 assign(mPri
->DesignatedBridgeID
.s
.priority
, ptp
->MSTID
);
1634 SET_PRIORITY_IN_IDENTIFIER(msti_msg
->bridgeIdentifierPriority
,
1635 mPri
->DesignatedBridgeID
);
1636 /* Build MSTI DesignatedPortID */
1637 assign(mPri
->DesignatedPortID
, b
->cistPortID
);
1638 SET_PRIORITY_IN_IDENTIFIER(msti_msg
->portIdentifierPriority
,
1639 mPri
->DesignatedPortID
);
1641 assign(mTimes
->remainingHops
, msti_msg
->remainingHops
);
1644 msg_Better_port
= !betterorsamePriority(&(ptp
->portPriority
), mPri
,
1646 if(roleIsDesignated
)
1650 || ((0 == memcmp(mPri
->DesignatedBridgeID
.s
.mac_address
,
1651 ptp
->portPriority
.DesignatedBridgeID
.s
.mac_address
,
1654 && (0 == ((mPri
->DesignatedPortID
1655 ^ ptp
->portPriority
.DesignatedPortID
1656 ) & __constant_cpu_to_be16(0x0FFF)
1661 return SuperiorDesignatedInfo
;
1664 /* We already know that msgPriority _IS_NOT_BETTER_than portPriority.
1665 * So, if msgPriority _IS_SAME_OR_BETTER_than portPriority then
1666 * msgPriority _IS_SAME_as portPriority.
1668 msg_SamePriorityAndTimers_port
=
1669 samePriorityAndTimers(mPri
, &(ptp
->portPriority
),
1670 mTimes
, &(ptp
->portTimes
),
1672 if((!msg_SamePriorityAndTimers_port
)
1673 && betterorsamePriority(mPri
, &(ptp
->portPriority
), 0, 0, cist
)
1675 return SuperiorDesignatedInfo
;
1678 if(msg_SamePriorityAndTimers_port
&& (ioReceived
== ptp
->infoIs
))
1679 return RepeatedDesignatedInfo
;
1682 return InferiorDesignatedInfo
;
1686 if(!msg_Better_port
)
1687 return InferiorRootAlternateInfo
;
1692 /* 13.26.7 recordAgreement */
1693 static void recordAgreement(per_tree_port_t
*ptp
)
1695 bool cist_agreed
, cist_proposing
;
1696 per_tree_port_t
*cist
;
1697 port_t
*prt
= ptp
->port
;
1698 bpdu_t
*b
= &(prt
->rcvdBpduData
);
1702 if(rstpVersion(prt
->bridge
) && prt
->operPointToPointMAC
1703 && (b
->flags
& (1 << offsetAgreement
))
1707 ptp
->proposing
= false;
1710 ptp
->agreed
= false;
1711 cist_agreed
= ptp
->agreed
;
1712 cist_proposing
= ptp
->proposing
;
1713 if(!prt
->rcvdInternal
)
1714 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1716 ptp
->agreed
= cist_agreed
;
1717 ptp
->proposing
= cist_proposing
;
1722 cist
= GET_CIST_PTP_FROM_PORT(prt
);
1723 if(prt
->operPointToPointMAC
1724 && cmp(b
->cistRootID
, ==, cist
->portPriority
.RootID
)
1725 && cmp(b
->cistExtRootPathCost
, ==, cist
->portPriority
.ExtRootPathCost
)
1726 && cmp(b
->cistRRootID
, ==, cist
->portPriority
.RRootID
)
1727 && (ptp
->rcvdMstiConfig
->flags
& (1 << offsetAgreement
))
1731 ptp
->proposing
= false;
1734 ptp
->agreed
= false;
1737 /* 13.26.8 recordDispute */
1738 static void recordDispute(per_tree_port_t
*ptp
)
1745 /* 802.1Q-2005 is somewhat unclear for the case (!prt->rcvdInternal):
1746 * if we should record dispute for all MSTIs unconditionally
1747 * or only when CIST Learning flag is set in BPDU.
1748 * I guess that in this case MSTIs should be in sync with CIST
1749 * so record dispute for the MSTIs only when the same is done for CIST.
1750 * Additional supporting argument to this guess is that in
1751 * setTcFlags() we do the same.
1752 * But that is only a guess and I could be wrong here ;)
1753 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
1755 if(prt
->rcvdBpduData
.flags
& (1 << offsetLearnig
))
1757 ptp
->disputed
= true;
1758 ptp
->agreed
= false;
1759 if(!prt
->rcvdInternal
)
1760 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1762 ptp
->disputed
= true;
1763 ptp
->agreed
= false;
1769 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetLearnig
))
1771 ptp
->disputed
= true;
1772 ptp
->agreed
= false;
1776 /* 13.26.9 recordMastered */
1777 static void recordMastered(per_tree_port_t
*ptp
)
1779 port_t
*prt
= ptp
->port
;
1783 if(!prt
->rcvdInternal
)
1784 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1785 ptp
->mastered
= false;
1789 ptp
->mastered
= prt
->operPointToPointMAC
1790 && (ptp
->rcvdMstiConfig
->flags
& (1 << offsetMaster
));
1793 /* 13.26.f) recordPriority */
1794 static void recordPriority(per_tree_port_t
*ptp
)
1796 assign(ptp
->portPriority
, ptp
->msgPriority
);
1799 /* 13.26.10 recordProposal */
1800 static void recordProposal(per_tree_port_t
*ptp
)
1805 /* 802.1Q-2005 says to check if received message conveys
1806 * a Designated Port Role. But there is no need in this check,
1807 * as it is always true. This function is called only in two states:
1808 * PISM_SUPERIOR_DESIGNATED and PISM_REPEATED_DESIGNATED, which
1809 * can be entered only if rcvInfo returns
1810 * SuperiorDesignatedInfo or RepeatedDesignatedInfo.
1811 * Which in turn can only happen if message conveys designated role
1817 if(prt
->rcvdBpduData
.flags
& (1 << offsetProposal
))
1818 ptp
->proposed
= true;
1819 cist_proposed
= ptp
->proposed
;
1820 if(!prt
->rcvdInternal
)
1821 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1822 ptp
->proposed
= cist_proposed
;
1826 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetProposal
))
1827 ptp
->proposed
= true;
1830 /* 13.26.11 recordTimes */
1831 static void recordTimes(per_tree_port_t
*ptp
)
1833 assign(ptp
->portTimes
, ptp
->msgTimes
);
1835 if(MIN_COMPAT_HELLO_TIME
> ptp
->portTimes
.Hello_Time
)
1836 ptp
->portTimes
.Hello_Time
= MIN_COMPAT_HELLO_TIME
;
1839 /* 13.24.s) + 17.19.7 of 802.1D : fdbFlush */
1840 static void set_fdbFlush(per_tree_port_t
*ptp
)
1842 port_t
*prt
= ptp
->port
;
1846 ptp
->fdbFlush
= false;
1850 bridge_t
*br
= prt
->bridge
;
1854 ptp
->fdbFlush
= true;
1855 ptp
->calledFromFlushRoutine
= true;
1856 MSTP_OUT_flush_all_fids(ptp
);
1857 ptp
->calledFromFlushRoutine
= false;
1861 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
1862 unsigned int FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
1863 /* Initiate rapid ageing */
1864 MSTP_OUT_set_ageing_time(br
, FwdDelay
);
1865 assign(br
->rapidAgeingWhile
, FwdDelay
);
1866 ptp
->fdbFlush
= false;
1870 /* 13.26.12 setRcvdMsgs */
1871 static void setRcvdMsgs(port_t
*prt
)
1873 msti_configuration_message_t
*msti_msg
;
1877 per_tree_port_t
*ptp
= GET_CIST_PTP_FROM_PORT(prt
);
1878 ptp
->rcvdMsg
= true;
1880 /* 802.1Q-2005 says:
1881 * "Make the received CST or CIST message available to the CIST Port
1882 * Information state machines"
1883 * No need to do something special here, we already have rcvdBpduData.
1886 if(prt
->rcvdInternal
)
1888 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1891 /* Find if message for this MSTI is conveyed in the BPDU */
1892 for(i
= 0, msti_msg
= prt
->rcvdBpduData
.mstConfiguration
;
1893 i
< prt
->rcvdBpduNumOfMstis
;
1896 msg_MSTID
= msti_msg
->mstiRRootID
.s
.priority
1897 & __constant_cpu_to_be16(0x0FFF);
1898 if(msg_MSTID
== ptp
->MSTID
)
1906 ptp
->rcvdMsg
= true;
1907 /* 802.1Q-2005 says:
1908 * "Make available each MSTI message and the common parts of
1909 * the CIST message priority (the CIST Root Identifier,
1910 * External Root Path Cost and Regional Root Identifier)
1911 * to the Port Information state machine for that MSTI"
1912 * We set pointer to the MSTI configuration message for
1913 * fast access, while do not anything special for common
1914 * parts of the message, as the whole message is available
1917 ptp
->rcvdMstiConfig
= msti_msg
;
1923 /* 13.26.13 setReRootTree */
1924 static void setReRootTree(tree_t
*tree
)
1926 per_tree_port_t
*ptp
;
1928 FOREACH_PTP_IN_TREE(ptp
, tree
)
1932 /* 13.26.14 setSelectedTree */
1933 static void setSelectedTree(tree_t
*tree
)
1935 per_tree_port_t
*ptp
;
1938 * 802.1Q-2005 says that I should check "reselect" var
1939 * and take no action if it is "true" for any of the ports.
1940 * But there is no need in this check as setSelectedTree is called
1941 * only from PRSSM_to_ROLE_SELECTION, which is atomic, and it is called
1942 * in this sequence (13.33):
1943 * clearReselectTree(tree);
1944 * updtRolesTree(tree);
1945 * setSelectedTree(tree);
1946 * And we know that clearReselectTree resets "reselect" for all ports
1947 * and updtRolesTree() does not change value of "reselect".
1949 FOREACH_PTP_IN_TREE(ptp
, tree
)
1950 ptp
->selected
= true;
1953 /* 13.26.15 setSyncTree */
1954 static void setSyncTree(tree_t
*tree
)
1956 per_tree_port_t
*ptp
;
1958 FOREACH_PTP_IN_TREE(ptp
, tree
)
1962 /* 13.26.16 setTcFlags */
1963 static void setTcFlags(per_tree_port_t
*ptp
)
1971 cistFlags
= prt
->rcvdBpduData
.flags
;
1972 if(cistFlags
& (1 << offsetTcAck
))
1973 prt
->rcvdTcAck
= true;
1974 if(cistFlags
& (1 << offsetTc
))
1977 if(!prt
->rcvdInternal
)
1978 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
1979 ptp
->proposed
= true;
1984 if(ptp
->rcvdMstiConfig
->flags
& (1 << offsetTc
))
1988 /* 13.26.17 setTcPropTree */
1989 static void setTcPropTree(per_tree_port_t
*ptp
)
1991 per_tree_port_t
*ptp_1
;
1993 if(ptp
->port
->restrictedTcn
)
1996 FOREACH_PTP_IN_TREE(ptp_1
, ptp
->tree
)
1999 ptp_1
->tcProp
= true;
2003 /* 13.26.18 syncMaster */
2004 static void syncMaster(bridge_t
*br
)
2006 per_tree_port_t
*ptp
;
2007 tree_t
*tree
= GET_CIST_TREE(br
);
2010 list_for_each_entry_continue(tree
, &br
->trees
, bridge_list
)
2012 FOREACH_PTP_IN_TREE(ptp
, tree
)
2014 /* for each Port that has infoInternal set */
2015 if(ptp
->port
->infoInternal
)
2018 ptp
->agreed
= false;
2019 ptp
->synced
= false;
2026 /* 13.26.19 txConfig */
2027 static void txConfig(port_t
*prt
)
2030 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2032 b
.protocolIdentifier
= 0;
2033 b
.protocolVersion
= protoSTP
;
2034 b
.bpduType
= bpduTypeConfig
;
2035 /* Standard says "tcWhile ... for the Port". Which one tcWhile?
2036 * I guess that this means tcWhile for the CIST.
2037 * But that is only a guess and I could be wrong here ;)
2038 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
2040 b
.flags
= (0 != cist
->tcWhile
) ? (1 << offsetTc
) : 0;
2042 b
.flags
|= (1 << offsetTcAck
);
2043 assign(b
.cistRootID
, cist
->designatedPriority
.RootID
);
2044 assign(b
.cistExtRootPathCost
, cist
->designatedPriority
.ExtRootPathCost
);
2045 assign(b
.cistRRootID
, cist
->designatedPriority
.DesignatedBridgeID
);
2046 assign(b
.cistPortID
, cist
->designatedPriority
.DesignatedPortID
);
2047 b
.MessageAge
[0] = cist
->designatedTimes
.Message_Age
;
2048 b
.MessageAge
[1] = 0;
2049 b
.MaxAge
[0] = cist
->designatedTimes
.Max_Age
;
2051 b
.HelloTime
[0] = cist
->portTimes
.Hello_Time
; /* ! use portTimes ! */
2053 b
.ForwardDelay
[0] = cist
->designatedTimes
.Forward_Delay
;
2054 b
.ForwardDelay
[1] = 0;
2056 MSTP_OUT_tx_bpdu(prt
, &b
, CONFIG_BPDU_SIZE
);
2059 static inline __u8
message_role_from_port_role(per_tree_port_t
*ptp
)
2064 return encodedRoleRoot
;
2065 case roleDesignated
:
2066 return encodedRoleDesignated
;
2069 return encodedRoleAlternateBackup
;
2071 return encodedRoleMaster
;
2073 ERROR_PRTNAME(ptp
->port
->bridge
, ptp
->port
,
2074 "Attempt to send from port with Disabled role");
2075 return encodedRoleAlternateBackup
;
2079 /* 13.26.20 txMstp */
2080 static void txMstp(port_t
*prt
)
2083 bridge_t
*br
= prt
->bridge
;
2084 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2085 int msti_msgs_total_size
;
2086 per_tree_port_t
*ptp
;
2087 msti_configuration_message_t
*msti_msg
;
2089 b
.protocolIdentifier
= 0;
2090 b
.bpduType
= bpduTypeRST
;
2091 /* Standard says "{tcWhile, agree, proposing, role} ... for the Port".
2092 * Which one {tcWhile, agree, proposing, role}?
2093 * I guess that this means {tcWhile, agree, proposing, role} for the CIST.
2094 * But that is only a guess and I could be wrong here ;)
2095 * Maybe 802.1Q-2011 clarifies this, but I don't have the text.
2097 b
.flags
= BPDU_FLAGS_ROLE_SET(message_role_from_port_role(cist
));
2098 if(0 != cist
->tcWhile
)
2099 b
.flags
|= (1 << offsetTc
);
2101 b
.flags
|= (1 << offsetProposal
);
2103 b
.flags
|= (1 << offsetLearnig
);
2104 if(cist
->forwarding
)
2105 b
.flags
|= (1 << offsetForwarding
);
2107 b
.flags
|= (1 << offsetAgreement
);
2108 assign(b
.cistRootID
, cist
->designatedPriority
.RootID
);
2109 assign(b
.cistExtRootPathCost
, cist
->designatedPriority
.ExtRootPathCost
);
2110 assign(b
.cistRRootID
, cist
->designatedPriority
.RRootID
);
2111 assign(b
.cistPortID
, cist
->designatedPriority
.DesignatedPortID
);
2112 b
.MessageAge
[0] = cist
->designatedTimes
.Message_Age
;
2113 b
.MessageAge
[1] = 0;
2114 b
.MaxAge
[0] = cist
->designatedTimes
.Max_Age
;
2116 b
.HelloTime
[0] = cist
->portTimes
.Hello_Time
; /* ! use portTimes ! */
2118 b
.ForwardDelay
[0] = cist
->designatedTimes
.Forward_Delay
;
2119 b
.ForwardDelay
[1] = 0;
2123 if(br
->ForceProtocolVersion
< protoMSTP
)
2125 b
.protocolVersion
= protoRSTP
;
2126 MSTP_OUT_tx_bpdu(prt
, &b
, RST_BPDU_SIZE
);
2130 b
.protocolVersion
= protoMSTP
;
2132 /* MST specific fields */
2133 assign(b
.mstConfigurationIdentifier
, br
->MstConfigId
);
2134 assign(b
.cistIntRootPathCost
, cist
->designatedPriority
.IntRootPathCost
);
2135 assign(b
.cistBridgeID
, cist
->designatedPriority
.DesignatedBridgeID
);
2136 assign(b
.cistRemainingHops
, cist
->designatedTimes
.remainingHops
);
2138 msti_msgs_total_size
= 0;
2140 msti_msg
= b
.mstConfiguration
;
2141 /* 13.26.20.f) requires that msti configs should be inserted in
2142 * MSTID order. This is met by inserting trees in port's list of trees
2143 * in sorted (by MSTID) order (see MSTP_IN_create_msti) */
2144 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2147 BPDU_FLAGS_ROLE_SET(message_role_from_port_role(ptp
));
2148 if(0 != ptp
->tcWhile
)
2149 msti_msg
->flags
|= (1 << offsetTc
);
2151 msti_msg
->flags
|= (1 << offsetProposal
);
2153 msti_msg
->flags
|= (1 << offsetLearnig
);
2155 msti_msg
->flags
|= (1 << offsetForwarding
);
2157 msti_msg
->flags
|= (1 << offsetAgreement
);
2159 msti_msg
->flags
|= (1 << offsetMaster
);
2160 assign(msti_msg
->mstiRRootID
, ptp
->designatedPriority
.RRootID
);
2161 assign(msti_msg
->mstiIntRootPathCost
,
2162 ptp
->designatedPriority
.IntRootPathCost
);
2163 msti_msg
->bridgeIdentifierPriority
=
2164 GET_PRIORITY_FROM_IDENTIFIER(ptp
->designatedPriority
.DesignatedBridgeID
);
2165 msti_msg
->portIdentifierPriority
=
2166 GET_PRIORITY_FROM_IDENTIFIER(ptp
->designatedPriority
.DesignatedPortID
);
2167 assign(msti_msg
->remainingHops
, ptp
->designatedTimes
.remainingHops
);
2169 msti_msgs_total_size
+= sizeof(msti_configuration_message_t
);
2173 assign(b
.version3_len
, __cpu_to_be16(MST_BPDU_VER3LEN_WO_MSTI_MSGS
2174 + msti_msgs_total_size
));
2175 MSTP_OUT_tx_bpdu(prt
, &b
, MST_BPDU_SIZE_WO_MSTI_MSGS
2176 + msti_msgs_total_size
);
2179 /* 13.26.a) txTcn */
2180 static void txTcn(port_t
*prt
)
2184 b
.protocolIdentifier
= 0;
2185 b
.protocolVersion
= protoSTP
;
2186 b
.bpduType
= bpduTypeTCN
;
2188 MSTP_OUT_tx_bpdu(prt
, &b
, TCN_BPDU_SIZE
);
2191 /* 13.26.21 updtBPDUVersion */
2192 static void updtBPDUVersion(port_t
*prt
)
2194 if(protoRSTP
<= prt
->rcvdBpduData
.protocolVersion
)
2195 prt
->rcvdRSTP
= true;
2197 prt
->rcvdSTP
= true;
2200 /* 13.26.22 updtRcvdInfoWhile */
2201 static void updtRcvdInfoWhile(per_tree_port_t
*ptp
)
2203 port_t
*prt
= ptp
->port
;
2204 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2205 unsigned int Message_Age
= cist
->portTimes
.Message_Age
;
2206 unsigned int Max_Age
= cist
->portTimes
.Max_Age
;
2207 unsigned int Hello_Time
= cist
->portTimes
.Hello_Time
;
2209 if((!prt
->rcvdInternal
&& ((Message_Age
+ 1) <= Max_Age
))
2210 || (prt
->rcvdInternal
&& (cist
->portTimes
.remainingHops
> 1))
2212 ptp
->rcvdInfoWhile
= 3 * Hello_Time
;
2214 ptp
->rcvdInfoWhile
= 0;
2217 /* 13.26.24 updtRolesDisabledTree */
2218 static void updtRolesDisabledTree(tree_t
*tree
)
2220 per_tree_port_t
*ptp
;
2222 FOREACH_PTP_IN_TREE(ptp
, tree
)
2223 ptp
->selectedRole
= roleDisabled
;
2226 /* 13.26.23 updtRolesTree */
2227 static void updtRolesTree(tree_t
*tree
)
2229 per_tree_port_t
*ptp
, *root_ptp
= NULL
;
2230 port_priority_vector_t root_path_priority
;
2231 bridge_identifier_t prevRRootID
= tree
->rootPriority
.RRootID
;
2232 __be32 prevExtRootPathCost
= tree
->rootPriority
.ExtRootPathCost
;
2233 bool cist
= (0 == tree
->MSTID
);
2234 times_t
*timesOfRootPort
;
2236 /* a), b) Select new root priority vector = {rootPriority, rootPortId} */
2237 /* Initial value = bridge priority vector = {BridgePriority, 0} */
2238 assign(tree
->rootPriority
, tree
->BridgePriority
);
2239 assign(tree
->rootPortId
, __constant_cpu_to_be16(0));
2240 /* Now check root path priority vectors of all ports in tree and see if
2241 * there is a better vector */
2242 FOREACH_PTP_IN_TREE(ptp
, tree
)
2244 port_t
*prt
= ptp
->port
;
2245 /* 802.1Q says to calculate root priority vector only if port
2246 * is not Disabled, but check (infoIs == ioReceived) covers
2247 * the case (infoIs != ioDisabled).
2249 if((ioReceived
== ptp
->infoIs
) && !prt
->restrictedRole
2250 && cmp(ptp
->portPriority
.DesignatedBridgeID
, !=,
2251 tree
->BridgeIdentifier
)
2254 root_path_priority
= ptp
->portPriority
;
2255 if(prt
->rcvdInternal
)
2257 assign(root_path_priority
.IntRootPathCost
,
2258 __cpu_to_be32(__be32_to_cpu(root_path_priority
.IntRootPathCost
)
2259 + ptp
->InternalPortPathCost
)
2264 assign(root_path_priority
.ExtRootPathCost
,
2265 __cpu_to_be32(__be32_to_cpu(root_path_priority
.ExtRootPathCost
)
2266 + prt
->ExternalPortPathCost
)
2268 assign(root_path_priority
.IntRootPathCost
,
2269 __constant_cpu_to_be32(0));
2271 if(betterorsamePriority(&root_path_priority
, &tree
->rootPriority
,
2272 ptp
->portId
, tree
->rootPortId
, cist
))
2274 assign(tree
->rootPriority
, root_path_priority
);
2275 assign(tree
->rootPortId
, ptp
->portId
);
2281 /* 802.1q-2005 says, that at some point we need compare portTimes with
2282 * "... one for the Root Port ...". Bad IEEE! Why not mention explicit
2283 * var names??? (see 13.26.23.g) for instance)
2284 * So, now I should guess what will work for the timesOfRootPort.
2285 * Below is the result of my guess. I could be wrong, of course:
2286 * timesOfRootPort = root_ptp ? &root_ptp->portTimes
2287 * : &tree->BridgeTimes;
2288 * NOTE: Both Alex Rozin (author of rstplib) and Srinivas Aji (author
2289 * of rstpd) compare portTimes with designatedTimes instead of
2290 * timesOfRootPort. This differs from my interpretation of the standard
2291 * because designatedTimes have incremented Message_Age (or decremented
2292 * remainingHops if rcvdInternal).
2295 /* c) Set new rootTimes */
2298 assign(tree
->rootTimes
, root_ptp
->portTimes
);
2299 port_t
*prt
= root_ptp
->port
;
2300 if(prt
->rcvdInternal
)
2302 if(tree
->rootTimes
.remainingHops
)
2303 --(tree
->rootTimes
.remainingHops
);
2306 ++(tree
->rootTimes
.Message_Age
);
2307 timesOfRootPort
= &root_ptp
->portTimes
;
2311 assign(tree
->rootTimes
, tree
->BridgeTimes
);
2312 timesOfRootPort
= &tree
->BridgeTimes
;
2315 FOREACH_PTP_IN_TREE(ptp
, tree
)
2317 port_t
*prt
= ptp
->port
;
2319 /* d) Set new designatedPriority */
2320 assign(ptp
->designatedPriority
, tree
->rootPriority
);
2321 assign(ptp
->designatedPriority
.DesignatedBridgeID
,
2322 tree
->BridgeIdentifier
);
2323 assign(ptp
->designatedPriority
.DesignatedPortID
, ptp
->portId
);
2324 /* I am not sure which condition to check here, as 802.1Q-2005 says:
2325 * "... If {Port} is attached to a LAN that has one or more STP Bridges
2326 * attached (as determined by the Port Protocol Migration state
2327 * machine) ..." -- why not to mention explicit var name? Bad IEEE.
2328 * But I guess that sendSTP (i.e. !sendRSTP) var will do ;)
2330 if(cist
&& !prt
->sendRSTP
)
2331 assign(ptp
->designatedPriority
.RRootID
, tree
->BridgeIdentifier
);
2333 /* e) Set new designatedTimes */
2334 assign(ptp
->designatedTimes
, tree
->rootTimes
);
2338 if(cist
&& cmp(tree
->rootPriority
.RRootID
, !=, prevRRootID
)
2339 && ((0 != tree
->rootPriority
.ExtRootPathCost
)
2340 || (0 != prevExtRootPathCost
)
2343 syncMaster(tree
->bridge
);
2345 FOREACH_PTP_IN_TREE(ptp
, tree
)
2347 port_t
*prt
= ptp
->port
;
2349 /* f) Set Disabled role */
2350 if(ioDisabled
== ptp
->infoIs
)
2352 ptp
->selectedRole
= roleDisabled
;
2356 if(!cist
&& (ioReceived
== ptp
->infoIs
)
2357 && !prt
->infoInternal
)
2359 /* g) Set role for the boundary port in MSTI */
2360 per_tree_port_t
*cist_tree
= GET_CIST_PTP_FROM_PORT(prt
);
2361 if(roleRoot
== cist_tree
->selectedRole
)
2363 ptp
->selectedRole
= roleMaster
;
2364 if(!samePriorityAndTimers(&ptp
->portPriority
,
2365 &ptp
->designatedPriority
,
2369 ptp
->updtInfo
= true;
2372 if(roleAlternate
== cist_tree
->selectedRole
)
2374 ptp
->selectedRole
= roleAlternate
;
2375 if(!samePriorityAndTimers(&ptp
->portPriority
,
2376 &ptp
->designatedPriority
,
2380 ptp
->updtInfo
= true;
2384 else /* if(cist || (ioReceived != ptp->infoIs) || prt->infoInternal) */
2386 /* h) Set role for the aged info */
2387 if(ioAged
== ptp
->infoIs
)
2389 ptp
->selectedRole
= roleDesignated
;
2390 ptp
->updtInfo
= true;
2393 /* i) Set role for the mine info */
2394 if(ioMine
== ptp
->infoIs
)
2396 ptp
->selectedRole
= roleDesignated
;
2397 if(!samePriorityAndTimers(&ptp
->portPriority
,
2398 &ptp
->designatedPriority
,
2402 ptp
->updtInfo
= true;
2405 if(ioReceived
== ptp
->infoIs
)
2407 /* j) Set Root role */
2410 ptp
->selectedRole
= roleRoot
;
2411 ptp
->updtInfo
= false;
2414 if(betterorsamePriority(&ptp
->portPriority
,
2415 &ptp
->designatedPriority
,
2418 if(cmp(ptp
->portPriority
.DesignatedBridgeID
, !=,
2419 tree
->BridgeIdentifier
))
2421 /* k) Set Alternate role */
2422 ptp
->selectedRole
= roleAlternate
;
2426 /* l) Set Backup role */
2427 ptp
->selectedRole
= roleBackup
;
2429 /* reset updtInfo for both k) and l) */
2430 ptp
->updtInfo
= false;
2433 else /* designatedPriority is better than portPriority */
2435 /* m) Set Designated role */
2436 ptp
->selectedRole
= roleDesignated
;
2437 ptp
->updtInfo
= true;
2445 /* 13.27 The Port Timers state machine */
2447 static void PTSM_tick(port_t
*prt
)
2449 per_tree_port_t
*ptp
;
2453 if(prt
->mdelayWhile
)
2454 --(prt
->mdelayWhile
);
2455 if(prt
->edgeDelayWhile
)
2456 --(prt
->edgeDelayWhile
);
2460 FOREACH_PTP_IN_PORT(ptp
, prt
)
2470 if(0 == --(ptp
->tcWhile
))
2471 set_TopologyChange(ptp
->tree
, false);
2473 if(ptp
->rcvdInfoWhile
)
2474 --(ptp
->rcvdInfoWhile
);
2478 /* 13.28 Port Receive state machine */
2479 #define PRSM_begin(prt) PRSM_to_DISCARD(prt)
2480 static void PRSM_to_DISCARD(port_t
*prt
/*, bool begin*/)
2482 prt
->PRSM_state
= PRSM_DISCARD
;
2484 prt
->rcvdBpdu
= false;
2485 prt
->rcvdRSTP
= false;
2486 prt
->rcvdSTP
= false;
2487 clearAllRcvdMsgs(prt
);
2488 assign(prt
->edgeDelayWhile
, prt
->bridge
->Migrate_Time
);
2490 /* No need to run, no one condition will be met
2495 static void PRSM_to_RECEIVE(port_t
*prt
)
2497 prt
->PRSM_state
= PRSM_RECEIVE
;
2499 updtBPDUVersion(prt
);
2500 prt
->rcvdInternal
= fromSameRegion(prt
);
2502 prt
->operEdge
= false;
2503 prt
->rcvdBpdu
= false;
2504 assign(prt
->edgeDelayWhile
, prt
->bridge
->Migrate_Time
);
2506 /* No need to run, no one condition will be met
2510 static void PRSM_run(port_t
*prt
)
2512 per_tree_port_t
*ptp
;
2515 if((prt
->rcvdBpdu
|| (prt
->edgeDelayWhile
!= prt
->bridge
->Migrate_Time
))
2516 && !prt
->portEnabled
)
2518 PRSM_to_DISCARD(prt
);
2522 switch(prt
->PRSM_state
)
2525 if(prt
->rcvdBpdu
&& prt
->portEnabled
)
2526 PRSM_to_RECEIVE(prt
);
2530 FOREACH_PTP_IN_PORT(ptp
, prt
)
2538 if(prt
->rcvdBpdu
&& prt
->portEnabled
&& !rcvdAnyMsg
)
2539 PRSM_to_RECEIVE(prt
);
2544 /* 13.29 Port Protocol Migration state machine */
2546 static void PPMSM_run(port_t
*prt
);
2547 #define PPMSM_begin(prt) PPMSM_to_CHECKING_RSTP(prt)
2549 static void PPMSM_to_CHECKING_RSTP(port_t
*prt
/*, bool begin*/)
2551 prt
->PPMSM_state
= PPMSM_CHECKING_RSTP
;
2553 bridge_t
*br
= prt
->bridge
;
2554 prt
->mcheck
= false;
2555 prt
->sendRSTP
= rstpVersion(br
);
2556 assign(prt
->mdelayWhile
, br
->Migrate_Time
);
2558 /* No need to run, no one condition will be met
2560 * PPMSM_run(prt); */
2563 static void PPMSM_to_SELECTING_STP(port_t
*prt
)
2565 prt
->PPMSM_state
= PPMSM_SELECTING_STP
;
2567 prt
->sendRSTP
= false;
2568 assign(prt
->mdelayWhile
, prt
->bridge
->Migrate_Time
);
2573 static void PPMSM_to_SENSING(port_t
*prt
)
2575 prt
->PPMSM_state
= PPMSM_SENSING
;
2577 prt
->rcvdRSTP
= false;
2578 prt
->rcvdSTP
= false;
2583 static void PPMSM_run(port_t
*prt
)
2585 bridge_t
*br
= prt
->bridge
;
2587 switch(prt
->PPMSM_state
)
2589 case PPMSM_CHECKING_RSTP
:
2590 if((prt
->mdelayWhile
!= br
->Migrate_Time
)
2591 && !prt
->portEnabled
)
2593 PPMSM_to_CHECKING_RSTP(prt
);
2596 if(0 == prt
->mdelayWhile
)
2597 PPMSM_to_SENSING(prt
);
2599 case PPMSM_SELECTING_STP
:
2600 if(0 == prt
->mdelayWhile
|| !prt
->portEnabled
|| prt
->mcheck
)
2601 PPMSM_to_SENSING(prt
);
2604 if(!prt
->portEnabled
|| prt
->mcheck
2605 || (rstpVersion(br
) && !prt
->sendRSTP
&& prt
->rcvdRSTP
))
2607 PPMSM_to_CHECKING_RSTP(prt
);
2610 if(prt
->sendRSTP
&& prt
->rcvdSTP
)
2611 PPMSM_to_SELECTING_STP(prt
);
2616 /* 13.30 Bridge Detection state machine */
2617 static void BDSM_to_EDGE(port_t
*prt
/*, bool begin*/)
2619 prt
->BDSM_state
= BDSM_EDGE
;
2621 prt
->operEdge
= true;
2623 /* No need to run, no one condition will be met
2628 static void BDSM_to_NOT_EDGE(port_t
*prt
/*, bool begin*/)
2630 prt
->BDSM_state
= BDSM_NOT_EDGE
;
2632 prt
->operEdge
= false;
2634 /* No need to run, no one condition will be met
2639 static void BDSM_begin(port_t
*prt
/*, bool begin*/)
2641 if(prt
->AdminEdgePort
)
2642 BDSM_to_EDGE(prt
/*, begin*/);
2644 BDSM_to_NOT_EDGE(prt
/*, begin*/);
2647 static void BDSM_run(port_t
*prt
)
2649 per_tree_port_t
*cist
;
2651 switch(prt
->BDSM_state
)
2654 if((!prt
->portEnabled
&& !prt
->AdminEdgePort
) || !prt
->operEdge
)
2655 BDSM_to_NOT_EDGE(prt
);
2658 cist
= GET_CIST_PTP_FROM_PORT(prt
);
2659 /* NOTE: 802.1Q-2005 is not clear, which of the per-tree
2660 * "proposing" flags to use here, or one should combine
2661 * them all for all trees? Maybe 802.1Q-2011 clarifies
2662 * this, but I don't have the text.
2663 * So, I decide that it will be the "proposing" flag
2664 * from CIST tree - it seems like a good bet.
2666 if((!prt
->portEnabled
&& prt
->AdminEdgePort
)
2667 || ((0 == prt
->edgeDelayWhile
) && prt
->AutoEdge
&& prt
->sendRSTP
2675 /* 13.31 Port Transmit state machine */
2677 static void PTSM_run(port_t
*prt
);
2678 #define PTSM_begin(prt) PTSM_to_TRANSMIT_INIT((prt), true)
2680 static void PTSM_to_TRANSMIT_INIT(port_t
*prt
, bool begin
)
2682 prt
->PTSM_state
= PTSM_TRANSMIT_INIT
;
2684 prt
->newInfo
= true;
2685 prt
->newInfoMsti
= true;
2686 assign(prt
->txCount
, 0u);
2688 if(!begin
&& prt
->portEnabled
) /* prevent infinite loop */
2692 static void PTSM_to_TRANSMIT_CONFIG(port_t
*prt
)
2694 prt
->PTSM_state
= PTSM_TRANSMIT_CONFIG
;
2696 prt
->newInfo
= false;
2704 static void PTSM_to_TRANSMIT_TCN(port_t
*prt
)
2706 prt
->PTSM_state
= PTSM_TRANSMIT_TCN
;
2708 prt
->newInfo
= false;
2715 static void PTSM_to_TRANSMIT_RSTP(port_t
*prt
)
2717 prt
->PTSM_state
= PTSM_TRANSMIT_RSTP
;
2719 prt
->newInfo
= false;
2720 prt
->newInfoMsti
= false;
2728 static void PTSM_to_TRANSMIT_PERIODIC(port_t
*prt
)
2730 prt
->PTSM_state
= PTSM_TRANSMIT_PERIODIC
;
2732 per_tree_port_t
*ptp
= GET_CIST_PTP_FROM_PORT(prt
);
2733 bool cistDesignatedOrTCpropagatingRootPort
=
2734 (roleDesignated
== ptp
->role
)
2735 || ((roleRoot
== ptp
->role
) && (0 != ptp
->tcWhile
));
2736 bool mstiDesignatedOrTCpropagatingRootPort
;
2738 mstiDesignatedOrTCpropagatingRootPort
= false;
2739 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2741 if((roleDesignated
== ptp
->role
)
2742 || ((roleRoot
== ptp
->role
) && (0 != ptp
->tcWhile
))
2745 mstiDesignatedOrTCpropagatingRootPort
= true;
2750 prt
->newInfo
= prt
->newInfo
|| cistDesignatedOrTCpropagatingRootPort
;
2751 prt
->newInfoMsti
= prt
->newInfoMsti
2752 || mstiDesignatedOrTCpropagatingRootPort
;
2757 static void PTSM_to_IDLE(port_t
*prt
)
2759 prt
->PTSM_state
= PTSM_IDLE
;
2761 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
2762 prt
->helloWhen
= cist
->portTimes
.Hello_Time
;
2767 static void PTSM_run(port_t
*prt
)
2769 /* bool allTransmitReady; */
2770 per_tree_port_t
*ptp
;
2771 port_role_t cistRole
;
2772 bool mstiMasterPort
;
2774 if(!prt
->portEnabled
)
2776 PTSM_to_TRANSMIT_INIT(prt
, false);
2780 switch(prt
->PTSM_state
)
2782 case PTSM_TRANSMIT_INIT
:
2784 case PTSM_TRANSMIT_CONFIG
:
2786 case PTSM_TRANSMIT_TCN
:
2788 case PTSM_TRANSMIT_RSTP
:
2790 case PTSM_TRANSMIT_PERIODIC
:
2791 PTSM_to_IDLE(prt
); /* UnConditional Transition */
2794 /* allTransmitReady = true; */
2795 ptp
= GET_CIST_PTP_FROM_PORT(prt
);
2796 if(!ptp
->selected
|| ptp
->updtInfo
)
2798 /* allTransmitReady = false; */
2801 cistRole
= ptp
->role
;
2802 mstiMasterPort
= false;
2803 list_for_each_entry_continue(ptp
, &prt
->trees
, port_list
)
2805 if(!ptp
->selected
|| ptp
->updtInfo
)
2807 /* allTransmitReady = false; */
2810 if(roleMaster
== ptp
->role
)
2811 mstiMasterPort
= true;
2813 if(0 == prt
->helloWhen
)
2815 PTSM_to_TRANSMIT_PERIODIC(prt
);
2818 if(!(prt
->txCount
< prt
->bridge
->Transmit_Hold_Count
))
2821 { /* implement MSTP */
2822 if(prt
->newInfo
|| (prt
->newInfoMsti
&& !mstiMasterPort
))
2824 PTSM_to_TRANSMIT_RSTP(prt
);
2829 { /* fallback to STP */
2830 if(prt
->newInfo
&& (roleDesignated
== cistRole
))
2832 PTSM_to_TRANSMIT_CONFIG(prt
);
2835 if(prt
->newInfo
&& (roleRoot
== cistRole
))
2837 PTSM_to_TRANSMIT_TCN(prt
);
2845 /* 13.32 Port Information state machine */
2847 #ifdef PISM_ENABLE_LOG
2848 #define PISM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args)
2850 #define PISM_LOG(_fmt, _args...) {}
2851 #endif /* PISM_ENABLE_LOG */
2853 static void PISM_run(per_tree_port_t
*ptp
);
2854 #define PISM_begin(ptp) PISM_to_DISABLED((ptp), true)
2856 static void PISM_to_DISABLED(per_tree_port_t
*ptp
, bool begin
)
2859 ptp
->PISM_state
= PISM_DISABLED
;
2861 ptp
->rcvdMsg
= false;
2862 ptp
->proposing
= false;
2863 ptp
->proposed
= false;
2865 ptp
->agreed
= false;
2866 assign(ptp
->rcvdInfoWhile
, 0u);
2867 ptp
->infoIs
= ioDisabled
;
2868 ptp
->reselect
= true;
2869 ptp
->selected
= false;
2875 static void PISM_to_AGED(per_tree_port_t
*ptp
)
2878 ptp
->PISM_state
= PISM_AGED
;
2880 ptp
->infoIs
= ioAged
;
2881 ptp
->reselect
= true;
2882 ptp
->selected
= false;
2887 static void PISM_to_UPDATE(per_tree_port_t
*ptp
)
2890 ptp
->PISM_state
= PISM_UPDATE
;
2892 ptp
->proposing
= false;
2893 ptp
->proposed
= false;
2894 ptp
->agreed
= ptp
->agreed
&& betterorsameInfo(ptp
, ioMine
);
2895 ptp
->synced
= ptp
->synced
&& ptp
->agreed
;
2896 assign(ptp
->portPriority
, ptp
->designatedPriority
);
2897 assign(ptp
->portTimes
, ptp
->designatedTimes
);
2898 ptp
->updtInfo
= false;
2899 ptp
->infoIs
= ioMine
;
2900 /* newInfoXst = TRUE; */
2901 port_t
*prt
= ptp
->port
;
2903 prt
->newInfo
= true;
2905 prt
->newInfoMsti
= true;
2910 static void PISM_to_SUPERIOR_DESIGNATED(per_tree_port_t
*ptp
)
2913 ptp
->PISM_state
= PISM_SUPERIOR_DESIGNATED
;
2915 port_t
*prt
= ptp
->port
;
2917 prt
->infoInternal
= prt
->rcvdInternal
;
2918 ptp
->agreed
= false;
2919 ptp
->proposing
= false;
2920 recordProposal(ptp
);
2922 ptp
->agree
= ptp
->agree
&& betterorsameInfo(ptp
, ioReceived
);
2923 recordAgreement(ptp
);
2924 ptp
->synced
= ptp
->synced
&& ptp
->agreed
;
2925 recordPriority(ptp
);
2927 updtRcvdInfoWhile(ptp
);
2928 ptp
->infoIs
= ioReceived
;
2929 ptp
->reselect
= true;
2930 ptp
->selected
= false;
2931 ptp
->rcvdMsg
= false;
2936 static void PISM_to_REPEATED_DESIGNATED(per_tree_port_t
*ptp
)
2939 ptp
->PISM_state
= PISM_REPEATED_DESIGNATED
;
2941 port_t
*prt
= ptp
->port
;
2943 prt
->infoInternal
= prt
->rcvdInternal
;
2944 recordProposal(ptp
);
2946 recordAgreement(ptp
);
2947 updtRcvdInfoWhile(ptp
);
2948 ptp
->rcvdMsg
= false;
2953 static void PISM_to_INFERIOR_DESIGNATED(per_tree_port_t
*ptp
)
2956 ptp
->PISM_state
= PISM_INFERIOR_DESIGNATED
;
2959 ptp
->rcvdMsg
= false;
2964 static void PISM_to_NOT_DESIGNATED(per_tree_port_t
*ptp
)
2967 ptp
->PISM_state
= PISM_NOT_DESIGNATED
;
2969 recordAgreement(ptp
);
2971 ptp
->rcvdMsg
= false;
2976 static void PISM_to_OTHER(per_tree_port_t
*ptp
)
2979 ptp
->PISM_state
= PISM_OTHER
;
2981 ptp
->rcvdMsg
= false;
2986 static void PISM_to_CURRENT(per_tree_port_t
*ptp
)
2989 ptp
->PISM_state
= PISM_CURRENT
;
2994 static void PISM_to_RECEIVE(per_tree_port_t
*ptp
)
2997 ptp
->PISM_state
= PISM_RECEIVE
;
2999 ptp
->rcvdInfo
= rcvInfo(ptp
);
3000 recordMastered(ptp
);
3005 static void PISM_run(per_tree_port_t
*ptp
)
3007 bool rcvdXstMsg
, updtXstInfo
;
3008 port_t
*prt
= ptp
->port
;
3010 if((!prt
->portEnabled
) && (ioDisabled
!= ptp
->infoIs
))
3012 PISM_to_DISABLED(ptp
, false);
3016 switch(ptp
->PISM_state
)
3019 if(prt
->portEnabled
)
3025 PISM_to_DISABLED(ptp
, false);
3028 if(ptp
->selected
&& ptp
->updtInfo
)
3029 PISM_to_UPDATE(ptp
);
3033 case PISM_SUPERIOR_DESIGNATED
:
3035 case PISM_REPEATED_DESIGNATED
:
3037 case PISM_INFERIOR_DESIGNATED
:
3039 case PISM_NOT_DESIGNATED
:
3042 PISM_to_CURRENT(ptp
);
3046 * Although 802.1Q-2005 does not define rcvdXstMsg and updtXstInfo
3047 * from 802.1s we can conclude that they are:
3048 * - rcvdXstMsg = rcvdCistMsg, if tree is CIST
3049 * rcvdMstiMsg, if tree is MSTI.
3050 * - updtXstInfo = updtCistInfo, if tree is CIST
3051 * updtMstiInfo, if tree is MSTI.
3055 rcvdXstMsg
= ptp
->rcvdMsg
; /* 13.25.12 */
3056 updtXstInfo
= ptp
->updtInfo
; /* 13.25.16 */
3060 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(prt
);
3061 rcvdXstMsg
= !cist
->rcvdMsg
&& ptp
->rcvdMsg
; /* 13.25.13 */
3062 updtXstInfo
= ptp
->updtInfo
|| cist
->updtInfo
; /* 13.25.17 */
3064 if(rcvdXstMsg
&& !updtXstInfo
)
3066 PISM_to_RECEIVE(ptp
);
3069 if((ioReceived
== ptp
->infoIs
) && (0 == ptp
->rcvdInfoWhile
)
3070 && !ptp
->updtInfo
&& !rcvdXstMsg
)
3075 if(ptp
->selected
&& ptp
->updtInfo
)
3076 PISM_to_UPDATE(ptp
);
3079 switch(ptp
->rcvdInfo
)
3081 case SuperiorDesignatedInfo
:
3082 PISM_to_SUPERIOR_DESIGNATED(ptp
);
3084 case RepeatedDesignatedInfo
:
3085 PISM_to_REPEATED_DESIGNATED(ptp
);
3087 case InferiorDesignatedInfo
:
3088 PISM_to_INFERIOR_DESIGNATED(ptp
);
3090 case InferiorRootAlternateInfo
:
3091 PISM_to_NOT_DESIGNATED(ptp
);
3101 /* 13.33 Port Role Selection state machine */
3103 static void PRSSM_run(tree_t
*tree
);
3104 #define PRSSM_begin(tree) PRSSM_to_INIT_TREE(tree)
3106 static void PRSSM_to_INIT_TREE(tree_t
*tree
/*, bool begin*/)
3108 tree
->PRSSM_state
= PRSSM_INIT_TREE
;
3110 updtRolesDisabledTree(tree
);
3112 /* No need to check, as we assume begin = true here
3113 * because transition to this state can be initiated only by BEGIN var.
3114 * In other words, this function is called via xxx_begin macro only.
3116 * PRSSM_run(prt); */
3119 static void PRSSM_to_ROLE_SELECTION(tree_t
*tree
)
3121 tree
->PRSSM_state
= PRSSM_ROLE_SELECTION
;
3123 clearReselectTree(tree
);
3124 updtRolesTree(tree
);
3125 setSelectedTree(tree
);
3127 /* No need to run, no one condition will be met
3131 static void PRSSM_run(tree_t
*tree
)
3133 per_tree_port_t
*ptp
;
3135 switch(tree
->PRSSM_state
)
3137 case PRSSM_INIT_TREE
:
3138 PRSSM_to_ROLE_SELECTION(tree
);
3140 case PRSSM_ROLE_SELECTION
:
3141 FOREACH_PTP_IN_TREE(ptp
, tree
)
3144 PRSSM_to_ROLE_SELECTION(tree
);
3151 /* 13.34 Port Role Transitions state machine */
3153 #ifdef PRTSM_ENABLE_LOG
3154 #define PRTSM_LOG(_fmt, _args...) SMLOG_MSTINAME(ptp, _fmt, ##_args)
3156 #define PRTSM_LOG(_fmt, _args...) {}
3157 #endif /* PRTSM_ENABLE_LOG */
3159 static void PRTSM_runr(per_tree_port_t
*ptp
, bool recursive_call
);
3160 #define PRTSM_run(ptp) PRTSM_runr((ptp), false)
3161 #define PRTSM_begin(ptp) PRTSM_to_INIT_PORT(ptp)
3163 /* Disabled Port role transitions */
3165 static void PRTSM_to_INIT_PORT(per_tree_port_t
*ptp
/*, bool begin*/)
3168 ptp
->PRTSM_state
= PRTSM_INIT_PORT
;
3170 unsigned int MaxAge
, FwdDelay
;
3171 per_tree_port_t
*cist
= GET_CIST_PTP_FROM_PORT(ptp
->port
);
3173 ptp
->role
= roleDisabled
;
3175 ptp
->forward
= false;
3176 ptp
->synced
= false;
3180 FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
3181 assign(ptp
->rrWhile
, FwdDelay
);
3183 MaxAge
= cist
->designatedTimes
.Max_Age
;
3184 assign(ptp
->fdWhile
, MaxAge
);
3185 assign(ptp
->rbWhile
, 0u);
3187 /* No need to check, as we assume begin = true here
3188 * because transition to this state can be initiated only by BEGIN var.
3189 * In other words, this function is called via xxx_begin macro only.
3191 * PRTSM_runr(ptp, false); */
3194 static void PRTSM_to_DISABLE_PORT(per_tree_port_t
*ptp
)
3197 ptp
->PRTSM_state
= PRTSM_DISABLE_PORT
;
3199 /* Although 802.1Q-2005 says here to do role = selectedRole
3200 * I have difficulties with it in the next scenario:
3201 * 1) port was designated (role == selectedRole == roleDesignated)
3202 * 2) some config event occurs, e.g. MAC address changes and
3203 * br_state_machines_begin is called
3204 * 3) role == selectedRole == roleDisabled, PRTSM_state = PRTSM_INIT_PORT
3205 * Because port was not actually down, on the next run
3206 * Port Role Selection state machine sets selectedRole = roleDesignated
3207 * and updtInfo = true:
3208 * 4) we have unconditional transition to DISABLE_PORT, and because
3209 * updtInfo = true we can not follow transition to DESIGNATED_PORT
3210 * 5) if we follow standard, role = selectedRole = roleDesignated and
3211 * on the next run we have transition to the DISABLED_PORT
3212 * And there we stuck. role == selectedRole, so we can not transit to
3213 * DESIGNATED_PORT (it requires role != selectedRole ).
3215 * Solution: do not follow the standard, and do role = roleDisabled
3216 * instead of role = selectedRole.
3218 ptp
->role
= roleDisabled
;
3220 ptp
->forward
= false;
3222 PRTSM_runr(ptp
, true);
3225 static void PRTSM_to_DISABLED_PORT(per_tree_port_t
*ptp
, unsigned int MaxAge
)
3228 ptp
->PRTSM_state
= PRTSM_DISABLED_PORT
;
3230 assign(ptp
->fdWhile
, MaxAge
);
3232 assign(ptp
->rrWhile
, 0u);
3234 ptp
->reRoot
= false;
3236 PRTSM_runr(ptp
, true);
3239 /* MasterPort role transitions */
3241 static void PRTSM_to_MASTER_PROPOSED(per_tree_port_t
*ptp
)
3244 ptp
->PRTSM_state
= PRTSM_MASTER_PROPOSED
;
3246 setSyncTree(ptp
->tree
);
3247 ptp
->proposed
= false;
3249 PRTSM_runr(ptp
, true);
3252 static void PRTSM_to_MASTER_AGREED(per_tree_port_t
*ptp
)
3255 ptp
->PRTSM_state
= PRTSM_MASTER_AGREED
;
3257 ptp
->proposed
= false;
3261 PRTSM_runr(ptp
, true);
3264 static void PRTSM_to_MASTER_SYNCED(per_tree_port_t
*ptp
)
3267 ptp
->PRTSM_state
= PRTSM_MASTER_SYNCED
;
3269 assign(ptp
->rrWhile
, 0u);
3273 PRTSM_runr(ptp
, true);
3276 static void PRTSM_to_MASTER_RETIRED(per_tree_port_t
*ptp
)
3279 ptp
->PRTSM_state
= PRTSM_MASTER_RETIRED
;
3281 ptp
->reRoot
= false;
3283 PRTSM_runr(ptp
, true);
3286 static void PRTSM_to_MASTER_FORWARD(per_tree_port_t
*ptp
)
3289 ptp
->PRTSM_state
= PRTSM_MASTER_FORWARD
;
3291 ptp
->forward
= true;
3292 assign(ptp
->fdWhile
, 0u);
3293 ptp
->agreed
= ptp
->port
->sendRSTP
;
3295 PRTSM_runr(ptp
, true);
3298 static void PRTSM_to_MASTER_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3301 ptp
->PRTSM_state
= PRTSM_MASTER_LEARN
;
3304 assign(ptp
->fdWhile
, forwardDelay
);
3306 PRTSM_runr(ptp
, true);
3309 static void PRTSM_to_MASTER_DISCARD(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3312 ptp
->PRTSM_state
= PRTSM_MASTER_DISCARD
;
3315 ptp
->forward
= false;
3316 ptp
->disputed
= false;
3317 assign(ptp
->fdWhile
, forwardDelay
);
3319 PRTSM_runr(ptp
, true);
3322 static void PRTSM_to_MASTER_PORT(per_tree_port_t
*ptp
)
3325 ptp
->PRTSM_state
= PRTSM_MASTER_PORT
;
3327 ptp
->role
= roleMaster
;
3329 PRTSM_runr(ptp
, true);
3332 /* RootPort role transitions */
3334 static void PRTSM_to_ROOT_PROPOSED(per_tree_port_t
*ptp
)
3337 ptp
->PRTSM_state
= PRTSM_ROOT_PROPOSED
;
3339 setSyncTree(ptp
->tree
);
3340 ptp
->proposed
= false;
3342 PRTSM_runr(ptp
, true);
3345 static void PRTSM_to_ROOT_AGREED(per_tree_port_t
*ptp
)
3348 ptp
->PRTSM_state
= PRTSM_ROOT_AGREED
;
3350 ptp
->proposed
= false;
3353 /* newInfoXst = TRUE; */
3354 port_t
*prt
= ptp
->port
;
3356 prt
->newInfo
= true;
3358 prt
->newInfoMsti
= true;
3360 PRTSM_runr(ptp
, true);
3363 static void PRTSM_to_ROOT_SYNCED(per_tree_port_t
*ptp
)
3366 ptp
->PRTSM_state
= PRTSM_ROOT_SYNCED
;
3371 PRTSM_runr(ptp
, true);
3374 static void PRTSM_to_REROOT(per_tree_port_t
*ptp
)
3377 ptp
->PRTSM_state
= PRTSM_REROOT
;
3379 setReRootTree(ptp
->tree
);
3381 PRTSM_runr(ptp
, true);
3384 static void PRTSM_to_ROOT_FORWARD(per_tree_port_t
*ptp
)
3387 ptp
->PRTSM_state
= PRTSM_ROOT_FORWARD
;
3389 assign(ptp
->fdWhile
, 0u);
3390 ptp
->forward
= true;
3392 PRTSM_runr(ptp
, true);
3395 static void PRTSM_to_ROOT_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3398 ptp
->PRTSM_state
= PRTSM_ROOT_LEARN
;
3400 assign(ptp
->fdWhile
, forwardDelay
);
3403 PRTSM_runr(ptp
, true);
3406 static void PRTSM_to_REROOTED(per_tree_port_t
*ptp
)
3409 ptp
->PRTSM_state
= PRTSM_REROOTED
;
3411 ptp
->reRoot
= false;
3413 PRTSM_runr(ptp
, true);
3416 static void PRTSM_to_ROOT_PORT(per_tree_port_t
*ptp
, unsigned int FwdDelay
)
3419 ptp
->PRTSM_state
= PRTSM_ROOT_PORT
;
3421 ptp
->role
= roleRoot
;
3422 assign(ptp
->rrWhile
, FwdDelay
);
3424 PRTSM_runr(ptp
, true);
3427 /* DesignatedPort role transitions */
3429 static void PRTSM_to_DESIGNATED_PROPOSE(per_tree_port_t
*ptp
)
3432 ptp
->PRTSM_state
= PRTSM_DESIGNATED_PROPOSE
;
3434 port_t
*prt
= ptp
->port
;
3436 ptp
->proposing
= true;
3437 /* newInfoXst = TRUE; */
3440 /* 13.25.8. This tree is CIST. */
3441 unsigned int MaxAge
= ptp
->designatedTimes
.Max_Age
;
3442 /* 13.25.c) -> 17.20.4 of 802.1D : EdgeDelay */
3443 unsigned int EdgeDelay
= prt
->operPointToPointMAC
?
3444 prt
->bridge
->Migrate_Time
3446 assign(prt
->edgeDelayWhile
, EdgeDelay
);
3447 prt
->newInfo
= true;
3450 prt
->newInfoMsti
= true;
3452 PRTSM_runr(ptp
, true);
3455 static void PRTSM_to_DESIGNATED_AGREED(per_tree_port_t
*ptp
)
3458 ptp
->PRTSM_state
= PRTSM_DESIGNATED_AGREED
;
3460 ptp
->proposed
= false;
3463 /* newInfoXst = TRUE; */
3464 port_t
*prt
= ptp
->port
;
3466 prt
->newInfo
= true;
3468 prt
->newInfoMsti
= true;
3470 PRTSM_runr(ptp
, true);
3473 static void PRTSM_to_DESIGNATED_SYNCED(per_tree_port_t
*ptp
)
3476 ptp
->PRTSM_state
= PRTSM_DESIGNATED_SYNCED
;
3478 assign(ptp
->rrWhile
, 0u);
3482 PRTSM_runr(ptp
, true);
3485 static void PRTSM_to_DESIGNATED_RETIRED(per_tree_port_t
*ptp
)
3488 ptp
->PRTSM_state
= PRTSM_DESIGNATED_RETIRED
;
3490 ptp
->reRoot
= false;
3492 PRTSM_runr(ptp
, true);
3495 static void PRTSM_to_DESIGNATED_FORWARD(per_tree_port_t
*ptp
)
3498 ptp
->PRTSM_state
= PRTSM_DESIGNATED_FORWARD
;
3500 ptp
->forward
= true;
3501 assign(ptp
->fdWhile
, 0u);
3502 ptp
->agreed
= ptp
->port
->sendRSTP
;
3504 PRTSM_runr(ptp
, true);
3507 static void PRTSM_to_DESIGNATED_LEARN(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3510 ptp
->PRTSM_state
= PRTSM_DESIGNATED_LEARN
;
3513 assign(ptp
->fdWhile
, forwardDelay
);
3515 PRTSM_runr(ptp
, true);
3518 static void PRTSM_to_DESIGNATED_DISCARD(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3521 ptp
->PRTSM_state
= PRTSM_DESIGNATED_DISCARD
;
3524 ptp
->forward
= false;
3525 ptp
->disputed
= false;
3526 assign(ptp
->fdWhile
, forwardDelay
);
3528 PRTSM_runr(ptp
, true);
3531 static void PRTSM_to_DESIGNATED_PORT(per_tree_port_t
*ptp
)
3534 ptp
->PRTSM_state
= PRTSM_DESIGNATED_PORT
;
3536 ptp
->role
= roleDesignated
;
3538 PRTSM_runr(ptp
, true);
3541 /* AlternatePort and BackupPort role transitions */
3543 static void PRTSM_to_BLOCK_PORT(per_tree_port_t
*ptp
)
3546 ptp
->PRTSM_state
= PRTSM_BLOCK_PORT
;
3548 ptp
->role
= ptp
->selectedRole
;
3550 ptp
->forward
= false;
3552 PRTSM_runr(ptp
, true);
3555 static void PRTSM_to_BACKUP_PORT(per_tree_port_t
*ptp
, unsigned int HelloTime
)
3558 ptp
->PRTSM_state
= PRTSM_BACKUP_PORT
;
3560 assign(ptp
->rbWhile
, 2 * HelloTime
);
3562 PRTSM_runr(ptp
, true);
3565 static void PRTSM_to_ALTERNATE_PROPOSED(per_tree_port_t
*ptp
)
3568 ptp
->PRTSM_state
= PRTSM_ALTERNATE_PROPOSED
;
3570 setSyncTree(ptp
->tree
);
3571 ptp
->proposed
= false;
3573 PRTSM_runr(ptp
, true);
3576 static void PRTSM_to_ALTERNATE_AGREED(per_tree_port_t
*ptp
)
3579 ptp
->PRTSM_state
= PRTSM_ALTERNATE_AGREED
;
3581 ptp
->proposed
= false;
3583 /* newInfoXst = TRUE; */
3584 port_t
*prt
= ptp
->port
;
3586 prt
->newInfo
= true;
3588 prt
->newInfoMsti
= true;
3590 PRTSM_runr(ptp
, true);
3593 static void PRTSM_to_ALTERNATE_PORT(per_tree_port_t
*ptp
, unsigned int forwardDelay
)
3596 ptp
->PRTSM_state
= PRTSM_ALTERNATE_PORT
;
3598 assign(ptp
->fdWhile
, forwardDelay
);
3600 assign(ptp
->rrWhile
, 0u);
3602 ptp
->reRoot
= false;
3604 PRTSM_runr(ptp
, true);
3607 static void PRTSM_runr(per_tree_port_t
*ptp
, bool recursive_call
)
3609 /* Following vars do not need recalculating on recursive calls */
3610 static unsigned int MaxAge
, FwdDelay
, forwardDelay
, HelloTime
;
3612 static tree_t
*tree
;
3613 static per_tree_port_t
*cist
;
3614 /* Following vars are recalculated on each state transition */
3615 bool allSynced
, reRooted
;
3616 /* Following vars are auxiliary and don't depend on recursive_call */
3617 per_tree_port_t
*ptp_1
;
3620 { /* calculate these intermediate vars only first time in chain of
3621 * recursive calls */
3625 cist
= GET_CIST_PTP_FROM_PORT(prt
);
3628 FwdDelay
= cist
->designatedTimes
.Forward_Delay
;
3631 HelloTime
= cist
->portTimes
.Hello_Time
;
3633 /* 13.25.d) -> 17.20.5 of 802.1D */
3634 forwardDelay
= prt
->sendRSTP
? HelloTime
: FwdDelay
;
3637 MaxAge
= cist
->designatedTimes
.Max_Age
;
3640 PRTSM_LOG("role = %d, selectedRole = %d, selected = %d, updtInfo = %d",
3641 ptp
->role
, ptp
->selectedRole
, ptp
->selected
, ptp
->updtInfo
);
3642 if((ptp
->role
!= ptp
->selectedRole
) && ptp
->selected
&& !ptp
->updtInfo
)
3644 switch(ptp
->selectedRole
)
3647 PRTSM_to_DISABLE_PORT(ptp
);
3650 PRTSM_to_MASTER_PORT(ptp
);
3653 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3655 case roleDesignated
:
3656 PRTSM_to_DESIGNATED_PORT(ptp
);
3660 PRTSM_to_BLOCK_PORT(ptp
);
3667 FOREACH_PTP_IN_TREE(ptp_1
, tree
)
3671 || (ptp_1
->role
!= ptp_1
->selectedRole
)
3684 if((roleRoot
!= ptp_1
->role
) && !ptp_1
->synced
)
3687 case roleDesignated
:
3689 if((ptp
!= ptp_1
) && !ptp_1
->synced
)
3699 switch(ptp
->PRTSM_state
)
3701 /* Disabled Port role transitions */
3702 case PRTSM_INIT_PORT
:
3703 PRTSM_to_DISABLE_PORT(ptp
);
3705 case PRTSM_DISABLE_PORT
:
3706 if(ptp
->selected
&& !ptp
->updtInfo
3707 && !ptp
->learning
&& !ptp
->forwarding
3709 PRTSM_to_DISABLED_PORT(ptp
, MaxAge
);
3711 case PRTSM_DISABLED_PORT
:
3712 if(ptp
->selected
&& !ptp
->updtInfo
3713 && (ptp
->sync
|| ptp
->reRoot
|| !ptp
->synced
3714 || (ptp
->fdWhile
!= MaxAge
))
3716 PRTSM_to_DISABLED_PORT(ptp
, MaxAge
);
3718 /* MasterPort role transitions */
3719 case PRTSM_MASTER_PROPOSED
:
3721 case PRTSM_MASTER_AGREED
:
3723 case PRTSM_MASTER_SYNCED
:
3725 case PRTSM_MASTER_RETIRED
:
3727 case PRTSM_MASTER_FORWARD
:
3729 case PRTSM_MASTER_LEARN
:
3731 case PRTSM_MASTER_DISCARD
:
3732 PRTSM_to_MASTER_PORT(ptp
);
3734 case PRTSM_MASTER_PORT
:
3735 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3737 if(ptp
->reRoot
&& (0 == ptp
->rrWhile
))
3739 PRTSM_to_MASTER_RETIRED(ptp
);
3742 if((!ptp
->learning
&& !ptp
->forwarding
&& !ptp
->synced
)
3743 || (ptp
->agreed
&& !ptp
->synced
)
3744 || (prt
->operEdge
&& !ptp
->synced
)
3745 || (ptp
->sync
&& ptp
->synced
)
3748 PRTSM_to_MASTER_SYNCED(ptp
);
3751 if((allSynced
&& !ptp
->agree
)
3752 || (ptp
->proposed
&& ptp
->agree
)
3755 PRTSM_to_MASTER_AGREED(ptp
);
3758 if(ptp
->proposed
&& !ptp
->agree
)
3760 PRTSM_to_MASTER_PROPOSED(ptp
);
3763 if(((0 == ptp
->fdWhile
) || allSynced
)
3764 && ptp
->learn
&& !ptp
->forward
3767 PRTSM_to_MASTER_FORWARD(ptp
);
3770 if(((0 == ptp
->fdWhile
) || allSynced
)
3774 PRTSM_to_MASTER_LEARN(ptp
, forwardDelay
);
3777 if(((ptp
->sync
&& !ptp
->synced
)
3778 || (ptp
->reRoot
&& (0 != ptp
->rrWhile
))
3781 && !prt
->operEdge
&& (ptp
->learn
|| ptp
->forward
)
3784 PRTSM_to_MASTER_DISCARD(ptp
, forwardDelay
);
3788 /* RootPort role transitions */
3789 case PRTSM_ROOT_PROPOSED
:
3791 case PRTSM_ROOT_AGREED
:
3793 case PRTSM_ROOT_SYNCED
:
3797 case PRTSM_ROOT_FORWARD
:
3799 case PRTSM_ROOT_LEARN
:
3801 case PRTSM_REROOTED
:
3802 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3804 case PRTSM_ROOT_PORT
:
3805 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3807 if(!ptp
->forward
&& !ptp
->reRoot
)
3809 PRTSM_to_REROOT(ptp
);
3812 if((ptp
->agreed
&& !ptp
->synced
) || (ptp
->sync
&& ptp
->synced
))
3814 PRTSM_to_ROOT_SYNCED(ptp
);
3817 if((allSynced
&& !ptp
->agree
) || (ptp
->proposed
&& ptp
->agree
))
3819 PRTSM_to_ROOT_AGREED(ptp
);
3822 if(ptp
->proposed
&& !ptp
->agree
)
3824 PRTSM_to_ROOT_PROPOSED(ptp
);
3827 /* 17.20.10 of 802.1D : reRooted */
3829 FOREACH_PTP_IN_TREE(ptp_1
, tree
)
3831 if((ptp
!= ptp_1
) && (0 != ptp_1
->rrWhile
))
3837 if((0 == ptp
->fdWhile
)
3838 || (reRooted
&& (0 == ptp
->rbWhile
) && rstpVersion(prt
->bridge
))
3843 PRTSM_to_ROOT_LEARN(ptp
, forwardDelay
);
3846 else if(!ptp
->forward
)
3848 PRTSM_to_ROOT_FORWARD(ptp
);
3852 if(ptp
->reRoot
&& ptp
->forward
)
3854 PRTSM_to_REROOTED(ptp
);
3857 if(ptp
->rrWhile
!= FwdDelay
)
3859 PRTSM_to_ROOT_PORT(ptp
, FwdDelay
);
3863 /* DesignatedPort role transitions */
3864 case PRTSM_DESIGNATED_PROPOSE
:
3866 case PRTSM_DESIGNATED_AGREED
:
3868 case PRTSM_DESIGNATED_SYNCED
:
3870 case PRTSM_DESIGNATED_RETIRED
:
3872 case PRTSM_DESIGNATED_FORWARD
:
3874 case PRTSM_DESIGNATED_LEARN
:
3876 case PRTSM_DESIGNATED_DISCARD
:
3877 PRTSM_to_DESIGNATED_PORT(ptp
);
3879 case PRTSM_DESIGNATED_PORT
:
3880 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3882 if(ptp
->reRoot
&& (0 == ptp
->rrWhile
))
3884 PRTSM_to_DESIGNATED_RETIRED(ptp
);
3887 if((!ptp
->learning
&& !ptp
->forwarding
&& !ptp
->synced
)
3888 || (ptp
->agreed
&& !ptp
->synced
)
3889 || (prt
->operEdge
&& !ptp
->synced
)
3890 || (ptp
->sync
&& ptp
->synced
)
3893 PRTSM_to_DESIGNATED_SYNCED(ptp
);
3896 if(allSynced
&& (ptp
->proposed
|| !ptp
->agree
))
3898 PRTSM_to_DESIGNATED_AGREED(ptp
);
3901 if(!ptp
->forward
&& !ptp
->agreed
&& !ptp
->proposing
3904 PRTSM_to_DESIGNATED_PROPOSE(ptp
);
3907 if(((0 == ptp
->fdWhile
) || ptp
->agreed
|| prt
->operEdge
)
3908 && ((0 == ptp
->rrWhile
) || !ptp
->reRoot
) && !ptp
->sync
3913 PRTSM_to_DESIGNATED_LEARN(ptp
, forwardDelay
);
3916 else if(!ptp
->forward
)
3918 PRTSM_to_DESIGNATED_FORWARD(ptp
);
3922 if(((ptp
->sync
&& !ptp
->synced
)
3923 || (ptp
->reRoot
&& (0 != ptp
->rrWhile
))
3926 && !prt
->operEdge
&& (ptp
->learn
|| ptp
->forward
)
3929 PRTSM_to_DESIGNATED_DISCARD(ptp
, forwardDelay
);
3933 /* AlternatePort and BackupPort role transitions */
3934 case PRTSM_BLOCK_PORT
:
3935 if(ptp
->selected
&& !ptp
->updtInfo
3936 && !ptp
->learning
&& !ptp
->forwarding
3938 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3940 case PRTSM_BACKUP_PORT
:
3942 case PRTSM_ALTERNATE_PROPOSED
:
3944 case PRTSM_ALTERNATE_AGREED
:
3945 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3947 case PRTSM_ALTERNATE_PORT
:
3948 if(!(ptp
->selected
&& !ptp
->updtInfo
))
3950 if((allSynced
&& !ptp
->agree
) || (ptp
->proposed
&& ptp
->agree
))
3952 PRTSM_to_ALTERNATE_AGREED(ptp
);
3955 if(ptp
->proposed
&& !ptp
->agree
)
3957 PRTSM_to_ALTERNATE_PROPOSED(ptp
);
3960 if((ptp
->rbWhile
!= 2 * HelloTime
) && (roleBackup
== ptp
->role
))
3962 PRTSM_to_BACKUP_PORT(ptp
, HelloTime
);
3965 if((ptp
->fdWhile
!= forwardDelay
) || ptp
->sync
|| ptp
->reRoot
3968 PRTSM_to_ALTERNATE_PORT(ptp
, forwardDelay
);
3975 /* 13.35 Port State Transition state machine */
3977 static void PSTSM_run(per_tree_port_t
*ptp
);
3978 #define PSTSM_begin(ptp) PSTSM_to_DISCARDING((ptp), true)
3980 static void PSTSM_to_DISCARDING(per_tree_port_t
*ptp
, bool begin
)
3982 ptp
->PSTSM_state
= PSTSM_DISCARDING
;
3984 /* This effectively sets BLOCKING state:
3986 disableForwarding();
3988 if(BR_STATE_BLOCKING
!= ptp
->state
)
3989 MSTP_OUT_set_state(ptp
, BR_STATE_BLOCKING
);
3990 ptp
->learning
= false;
3991 ptp
->forwarding
= false;
3997 static void PSTSM_to_LEARNING(per_tree_port_t
*ptp
)
3999 ptp
->PSTSM_state
= PSTSM_LEARNING
;
4001 /* enableLearning(); */
4002 if(BR_STATE_LEARNING
!= ptp
->state
)
4003 MSTP_OUT_set_state(ptp
, BR_STATE_LEARNING
);
4004 ptp
->learning
= true;
4009 static void PSTSM_to_FORWARDING(per_tree_port_t
*ptp
)
4011 ptp
->PSTSM_state
= PSTSM_FORWARDING
;
4013 /* enableForwarding(); */
4014 if(BR_STATE_FORWARDING
!= ptp
->state
)
4015 MSTP_OUT_set_state(ptp
, BR_STATE_FORWARDING
);
4016 ptp
->forwarding
= true;
4018 /* No need to run, no one condition will be met
4022 static void PSTSM_run(per_tree_port_t
*ptp
)
4024 switch(ptp
->PSTSM_state
)
4026 case PSTSM_DISCARDING
:
4028 PSTSM_to_LEARNING(ptp
);
4030 case PSTSM_LEARNING
:
4032 PSTSM_to_DISCARDING(ptp
, false);
4033 else if(ptp
->forward
)
4034 PSTSM_to_FORWARDING(ptp
);
4036 case PSTSM_FORWARDING
:
4038 PSTSM_to_DISCARDING(ptp
, false);
4043 /* 13.36 Topology Change state machine */
4045 #define TCSM_begin(ptp) TCSM_to_INACTIVE((ptp), true)
4047 static void TCSM_to_INACTIVE(per_tree_port_t
*ptp
, bool begin
)
4049 ptp
->TCSM_state
= TCSM_INACTIVE
;
4052 assign(ptp
->tcWhile
, 0u);
4053 set_TopologyChange(ptp
->tree
, false);
4054 if(0 == ptp
->MSTID
) /* CIST */
4055 ptp
->port
->tcAck
= false;
4061 static void TCSM_to_LEARNING(per_tree_port_t
*ptp
)
4063 ptp
->TCSM_state
= TCSM_LEARNING
;
4065 if(0 == ptp
->MSTID
) /* CIST */
4067 port_t
*prt
= ptp
->port
;
4068 prt
->rcvdTcn
= false;
4069 prt
->rcvdTcAck
= false;
4071 ptp
->rcvdTc
= false;
4072 ptp
->tcProp
= false;
4077 static void TCSM_to_DETECTED(per_tree_port_t
*ptp
)
4079 ptp
->TCSM_state
= TCSM_DETECTED
;
4083 /* newInfoXst = TRUE; */
4084 port_t
*prt
= ptp
->port
;
4086 prt
->newInfo
= true;
4088 prt
->newInfoMsti
= true;
4093 static void TCSM_to_NOTIFIED_TCN(per_tree_port_t
*ptp
)
4095 ptp
->TCSM_state
= TCSM_NOTIFIED_TCN
;
4102 static void TCSM_to_NOTIFIED_TC(per_tree_port_t
*ptp
)
4104 ptp
->TCSM_state
= TCSM_NOTIFIED_TC
;
4106 ptp
->rcvdTc
= false;
4107 if(0 == ptp
->MSTID
) /* CIST */
4109 port_t
*prt
= ptp
->port
;
4110 prt
->rcvdTcn
= false;
4111 if(roleDesignated
== ptp
->role
)
4119 static void TCSM_to_PROPAGATING(per_tree_port_t
*ptp
)
4121 ptp
->TCSM_state
= TCSM_PROPAGATING
;
4125 ptp
->tcProp
= false;
4130 static void TCSM_to_ACKNOWLEDGED(per_tree_port_t
*ptp
)
4132 ptp
->TCSM_state
= TCSM_ACKNOWLEDGED
;
4134 assign(ptp
->tcWhile
, 0u);
4135 set_TopologyChange(ptp
->tree
, false);
4136 ptp
->port
->rcvdTcAck
= false;
4141 static void TCSM_to_ACTIVE(per_tree_port_t
*ptp
)
4143 ptp
->TCSM_state
= TCSM_ACTIVE
;
4148 static void TCSM_run(per_tree_port_t
*ptp
)
4151 port_t
*prt
= ptp
->port
;
4153 switch(ptp
->TCSM_state
)
4156 if(ptp
->learn
&& !ptp
->fdbFlush
)
4157 TCSM_to_LEARNING(ptp
);
4160 active_port
= (roleRoot
== ptp
->role
)
4161 || (roleDesignated
== ptp
->role
)
4162 || (roleMaster
== ptp
->role
);
4163 if(active_port
&& ptp
->forward
&& !prt
->operEdge
)
4165 TCSM_to_DETECTED(ptp
);
4168 if(ptp
->rcvdTc
|| prt
->rcvdTcn
|| prt
->rcvdTcAck
|| ptp
->tcProp
)
4170 TCSM_to_LEARNING(ptp
);
4173 else if(!active_port
&& !(ptp
->learn
|| ptp
->learning
))
4174 TCSM_to_INACTIVE(ptp
, false);
4176 case TCSM_NOTIFIED_TCN
:
4177 TCSM_to_NOTIFIED_TC(ptp
);
4181 case TCSM_NOTIFIED_TC
:
4183 case TCSM_PROPAGATING
:
4185 case TCSM_ACKNOWLEDGED
:
4186 TCSM_to_ACTIVE(ptp
);
4189 active_port
= (roleRoot
== ptp
->role
)
4190 || (roleDesignated
== ptp
->role
)
4191 || (roleMaster
== ptp
->role
);
4192 if(!active_port
|| prt
->operEdge
)
4194 TCSM_to_LEARNING(ptp
);
4199 TCSM_to_NOTIFIED_TCN(ptp
);
4204 TCSM_to_NOTIFIED_TC(ptp
);
4207 if(ptp
->tcProp
/* && !prt->operEdge */)
4209 TCSM_to_PROPAGATING(ptp
);
4214 TCSM_to_ACKNOWLEDGED(ptp
);
4221 /* Execute BEGIN state. We do not define BEGIN variable
4222 * but instead xxx_state_machines_begin execute begin state
4223 * abd do one step out of it
4226 static void tree_state_machines_begin(tree_t
*tree
)
4228 bridge_t
*br
= tree
->bridge
;
4229 per_tree_port_t
*ptp
;
4231 if(!br
->bridgeEnabled
)
4234 /* 13.32 Port Information state machine */
4235 FOREACH_PTP_IN_TREE(ptp
, tree
)
4237 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4241 /* 13.33 Port Role Selection state machine */
4244 /* 13.34 Port Role Transitions state machine */
4245 FOREACH_PTP_IN_TREE(ptp
, tree
)
4247 /* 13.35 Port State Transition state machine */
4248 FOREACH_PTP_IN_TREE(ptp
, tree
)
4250 /* 13.36 Topology Change state machine */
4251 FOREACH_PTP_IN_TREE(ptp
, tree
)
4254 br_state_machines_run(br
);
4257 static void prt_state_machines_begin(port_t
*prt
)
4259 bridge_t
*br
= prt
->bridge
;
4261 per_tree_port_t
*ptp
;
4263 if(!br
->bridgeEnabled
)
4266 /* 13.28 Port Receive state machine */
4268 /* 13.29 Port Protocol Migration state machine */
4270 /* 13.30 Bridge Detection state machine */
4272 /* 13.31 Port Transmit state machine */
4275 /* 13.32 Port Information state machine */
4276 FOREACH_PTP_IN_PORT(ptp
, prt
)
4278 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4282 /* 13.33 Port Role Selection state machine */
4283 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4286 /* 13.34 Port Role Transitions state machine */
4287 FOREACH_PTP_IN_PORT(ptp
, prt
)
4289 /* 13.35 Port State Transition state machine */
4290 FOREACH_PTP_IN_PORT(ptp
, prt
)
4292 /* 13.36 Topology Change state machine */
4293 FOREACH_PTP_IN_PORT(ptp
, prt
)
4296 br_state_machines_run(br
);
4299 static void br_state_machines_begin(bridge_t
*br
)
4302 per_tree_port_t
*ptp
;
4305 if(!br
->bridgeEnabled
)
4308 /* 13.28 Port Receive state machine */
4309 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4311 /* 13.29 Port Protocol Migration state machine */
4312 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4314 /* 13.30 Bridge Detection state machine */
4315 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4317 /* 13.31 Port Transmit state machine */
4318 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4321 /* 13.32 Port Information state machine */
4322 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4324 FOREACH_PTP_IN_PORT(ptp
, prt
)
4326 ptp
->start_time
= br
->uptime
; /* 12.8.2.2.3 b) */
4331 /* 13.33 Port Role Selection state machine */
4332 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4335 /* 13.34 Port Role Transitions state machine */
4336 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4338 FOREACH_PTP_IN_PORT(ptp
, prt
)
4341 /* 13.35 Port State Transition state machine */
4342 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4344 FOREACH_PTP_IN_PORT(ptp
, prt
)
4347 /* 13.36 Topology Change state machine */
4348 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4350 FOREACH_PTP_IN_PORT(ptp
, prt
)
4354 br_state_machines_run(br
);
4357 /* Run each state machine */
4358 static void br_state_machines_run(bridge_t
*br
)
4361 per_tree_port_t
*ptp
;
4364 if(!br
->bridgeEnabled
)
4367 /* 13.28 Port Receive state machine */
4368 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4370 /* 13.29 Port Protocol Migration state machine */
4371 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4373 /* 13.30 Bridge Detection state machine */
4374 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4376 /* 13.31 Port Transmit state machine */
4377 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4380 /* 13.32 Port Information state machine */
4381 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4383 FOREACH_PTP_IN_PORT(ptp
, prt
)
4387 /* 13.33 Port Role Selection state machine */
4388 FOREACH_TREE_IN_BRIDGE(tree
, br
)
4391 /* 13.34 Port Role Transitions state machine */
4392 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4394 FOREACH_PTP_IN_PORT(ptp
, prt
)
4397 /* 13.35 Port State Transition state machine */
4398 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4400 FOREACH_PTP_IN_PORT(ptp
, prt
)
4403 /* 13.36 Topology Change state machine */
4404 FOREACH_PORT_IN_BRIDGE(prt
, br
)
4406 FOREACH_PTP_IN_PORT(ptp
, prt
)