* But that is only a guess and I could be wrong here ;)
*/
+/* Important coding convention:
+ * All functions that have dry_run argument must follow the
+ * return value convention:
+ * They should return true if state change detected during dry run.
+ * Otherwise (!dry_run || !state_change) they return false.
+ */
+
#include <string.h>
+#include <sys/time.h>
#include <linux/if_bridge.h>
#include <asm/byteorder.h>
#include "log.h"
static void PTSM_tick(port_t *prt);
-static void TCSM_run(per_tree_port_t *ptp);
+static bool TCSM_run(per_tree_port_t *ptp, bool dry_run);
static void BDSM_begin(port_t *prt);
static void br_state_machines_begin(bridge_t *br);
static void prt_state_machines_begin(port_t *prt);
return;
if(!ptp->calledFromFlushRoutine)
{
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
br_state_machines_run(br);
}
}
}
/* 13.26.2 clearAllRcvdMsgs */
-static void clearAllRcvdMsgs(port_t *prt)
+static bool clearAllRcvdMsgs(port_t *prt, bool dry_run)
{
per_tree_port_t *ptp;
+ if(dry_run)
+ {
+ FOREACH_PTP_IN_PORT(ptp, prt)
+ if(ptp->rcvdMsg)
+ return true;
+ return false;
+ }
+
FOREACH_PTP_IN_PORT(ptp, prt)
ptp->rcvdMsg = false;
+
+ return false;
}
/* 13.26.3 clearReselectTree */
}
/* 13.28 Port Receive state machine */
-#define PRSM_begin(prt) PRSM_to_DISCARD(prt)
-static void PRSM_to_DISCARD(port_t *prt/*, bool begin*/)
+#define PRSM_begin(prt) PRSM_to_DISCARD((prt), false)
+static bool PRSM_to_DISCARD(port_t *prt, bool dry_run)
{
+ if(dry_run)
+ {
+ return (prt->PRSM_state != PRSM_DISCARD)
+ || prt->rcvdBpdu || prt->rcvdRSTP || prt->rcvdSTP
+ || (prt->edgeDelayWhile != prt->bridge->Migrate_Time)
+ || clearAllRcvdMsgs(prt, dry_run);
+ }
+
prt->PRSM_state = PRSM_DISCARD;
prt->rcvdBpdu = false;
prt->rcvdRSTP = false;
prt->rcvdSTP = false;
- clearAllRcvdMsgs(prt);
+ clearAllRcvdMsgs(prt, false /* actual run */);
assign(prt->edgeDelayWhile, prt->bridge->Migrate_Time);
/* No need to run, no one condition will be met
* if(!begin)
- * PRSM_run(prt); */
+ * PRSM_run(prt, false); */
+ return false;
}
static void PRSM_to_RECEIVE(port_t *prt)
assign(prt->edgeDelayWhile, prt->bridge->Migrate_Time);
/* No need to run, no one condition will be met
- PRSM_run(prt); */
+ PRSM_run(prt, false); */
}
-static void PRSM_run(port_t *prt)
+static bool PRSM_run(port_t *prt, bool dry_run)
{
per_tree_port_t *ptp;
bool rcvdAnyMsg;
if((prt->rcvdBpdu || (prt->edgeDelayWhile != prt->bridge->Migrate_Time))
&& !prt->portEnabled)
{
- PRSM_to_DISCARD(prt);
- return;
+ return PRSM_to_DISCARD(prt, dry_run);
}
switch(prt->PRSM_state)
{
case PRSM_DISCARD:
if(prt->rcvdBpdu && prt->portEnabled)
+ {
+ if(dry_run) /* state change */
+ return true;
PRSM_to_RECEIVE(prt);
- return;
+ }
+ return false;
case PRSM_RECEIVE:
rcvdAnyMsg = false;
FOREACH_PTP_IN_PORT(ptp, prt)
}
}
if(prt->rcvdBpdu && prt->portEnabled && !rcvdAnyMsg)
+ {
+ if(dry_run) /* at least rcvdBpdu will change */
+ return true;
PRSM_to_RECEIVE(prt);
- return;
+ }
+ return false;
}
}
/* 13.29 Port Protocol Migration state machine */
-static void PPMSM_run(port_t *prt);
+static bool PPMSM_run(port_t *prt, bool dry_run);
#define PPMSM_begin(prt) PPMSM_to_CHECKING_RSTP(prt)
static void PPMSM_to_CHECKING_RSTP(port_t *prt/*, bool begin*/)
/* No need to run, no one condition will be met
* if(!begin)
- * PPMSM_run(prt); */
+ * PPMSM_run(prt, false); */
}
static void PPMSM_to_SELECTING_STP(port_t *prt)
prt->sendRSTP = false;
assign(prt->mdelayWhile, prt->bridge->Migrate_Time);
- PPMSM_run(prt);
+ PPMSM_run(prt, false /* actual run */);
}
static void PPMSM_to_SENSING(port_t *prt)
prt->rcvdRSTP = false;
prt->rcvdSTP = false;
- PPMSM_run(prt);
+ PPMSM_run(prt, false /* actual run */);
}
-static void PPMSM_run(port_t *prt)
+static bool PPMSM_run(port_t *prt, bool dry_run)
{
bridge_t *br = prt->bridge;
if((prt->mdelayWhile != br->Migrate_Time)
&& !prt->portEnabled)
{
+ if(dry_run) /* at least mdelayWhile will change */
+ return true;
PPMSM_to_CHECKING_RSTP(prt);
- return;
+ return false;
}
if(0 == prt->mdelayWhile)
+ {
+ if(dry_run) /* state change */
+ return true;
PPMSM_to_SENSING(prt);
- return;
+ }
+ return false;
case PPMSM_SELECTING_STP:
if(0 == prt->mdelayWhile || !prt->portEnabled || prt->mcheck)
+ {
+ if(dry_run) /* state change */
+ return true;
PPMSM_to_SENSING(prt);
- return;
+ }
+ return false;
case PPMSM_SENSING:
if(!prt->portEnabled || prt->mcheck
|| (rstpVersion(br) && !prt->sendRSTP && prt->rcvdRSTP))
{
+ if(dry_run) /* state change */
+ return true;
PPMSM_to_CHECKING_RSTP(prt);
- return;
+ return false;
}
if(prt->sendRSTP && prt->rcvdSTP)
+ {
+ if(dry_run) /* state change */
+ return true;
PPMSM_to_SELECTING_STP(prt);
- return;
+ }
+ return false;
}
+
+ return false;
}
/* 13.30 Bridge Detection state machine */
/* No need to run, no one condition will be met
* if(!begin)
- * BDSM_run(prt); */
+ * BDSM_run(prt, false); */
}
static void BDSM_to_NOT_EDGE(port_t *prt/*, bool begin*/)
/* No need to run, no one condition will be met
* if(!begin)
- * BDSM_run(prt); */
+ * BDSM_run(prt, false); */
}
static void BDSM_begin(port_t *prt/*, bool begin*/)
BDSM_to_NOT_EDGE(prt/*, begin*/);
}
-static void BDSM_run(port_t *prt)
+static bool BDSM_run(port_t *prt, bool dry_run)
{
per_tree_port_t *cist;
{
case BDSM_EDGE:
if((!prt->portEnabled && !prt->AdminEdgePort) || !prt->operEdge)
+ {
+ if(dry_run) /* state change */
+ return true;
BDSM_to_NOT_EDGE(prt);
- return;
+ }
+ return false;
case BDSM_NOT_EDGE:
cist = GET_CIST_PTP_FROM_PORT(prt);
/* NOTE: 802.1Q-2005 is not clear, which of the per-tree
|| ((0 == prt->edgeDelayWhile) && prt->AutoEdge && prt->sendRSTP
&& cist->proposing)
)
+ {
+ if(dry_run) /* state change */
+ return true;
BDSM_to_EDGE(prt);
- return;
+ }
+ return false;
}
}
/* 13.31 Port Transmit state machine */
-static void PTSM_run(port_t *prt);
-#define PTSM_begin(prt) PTSM_to_TRANSMIT_INIT((prt), true)
+static bool PTSM_run(port_t *prt, bool dry_run);
+#define PTSM_begin(prt) PTSM_to_TRANSMIT_INIT((prt), true, false)
-static void PTSM_to_TRANSMIT_INIT(port_t *prt, bool begin)
+static bool PTSM_to_TRANSMIT_INIT(port_t *prt, bool begin, bool dry_run)
{
+ if(dry_run)
+ {
+ return (prt->PTSM_state != PTSM_TRANSMIT_INIT)
+ || (!prt->newInfo) || (!prt->newInfoMsti)
+ || (0 != prt->txCount);
+ }
+
prt->PTSM_state = PTSM_TRANSMIT_INIT;
prt->newInfo = true;
assign(prt->txCount, 0u);
if(!begin && prt->portEnabled) /* prevent infinite loop */
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
+ return false;
}
static void PTSM_to_TRANSMIT_CONFIG(port_t *prt)
++(prt->txCount);
prt->tcAck = false;
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
}
static void PTSM_to_TRANSMIT_TCN(port_t *prt)
txTcn(prt);
++(prt->txCount);
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
}
static void PTSM_to_TRANSMIT_RSTP(port_t *prt)
++(prt->txCount);
prt->tcAck = false;
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
}
static void PTSM_to_TRANSMIT_PERIODIC(port_t *prt)
prt->newInfoMsti = prt->newInfoMsti
|| mstiDesignatedOrTCpropagatingRootPort;
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
}
static void PTSM_to_IDLE(port_t *prt)
per_tree_port_t *cist = GET_CIST_PTP_FROM_PORT(prt);
prt->helloWhen = cist->portTimes.Hello_Time;
- PTSM_run(prt);
+ PTSM_run(prt, false /* actual run */);
}
-static void PTSM_run(port_t *prt)
+static bool PTSM_run(port_t *prt, bool dry_run)
{
/* bool allTransmitReady; */
per_tree_port_t *ptp;
if(!prt->portEnabled)
{
- PTSM_to_TRANSMIT_INIT(prt, false);
- return;
+ return PTSM_to_TRANSMIT_INIT(prt, false, dry_run);
}
switch(prt->PTSM_state)
case PTSM_TRANSMIT_RSTP:
/* return; */
case PTSM_TRANSMIT_PERIODIC:
+ if(dry_run) /* state change */
+ return true;
PTSM_to_IDLE(prt); /* UnConditional Transition */
- return;
+ return false;
case PTSM_IDLE:
/* allTransmitReady = true; */
ptp = GET_CIST_PTP_FROM_PORT(prt);
if(!ptp->selected || ptp->updtInfo)
{
/* allTransmitReady = false; */
- return;
+ return false;
}
cistRole = ptp->role;
mstiMasterPort = false;
if(!ptp->selected || ptp->updtInfo)
{
/* allTransmitReady = false; */
- return;
+ return false;
}
if(roleMaster == ptp->role)
mstiMasterPort = true;
}
if(0 == prt->helloWhen)
{
+ if(dry_run) /* state change */
+ return true;
PTSM_to_TRANSMIT_PERIODIC(prt);
- return;
+ return false;
}
if(!(prt->txCount < prt->bridge->Transmit_Hold_Count))
- return;
+ return false;
if(prt->sendRSTP)
{ /* implement MSTP */
if(prt->newInfo || (prt->newInfoMsti && !mstiMasterPort))
{
+ if(dry_run) /* state change */
+ return true;
PTSM_to_TRANSMIT_RSTP(prt);
- return;
+ return false;
}
}
else
{ /* fallback to STP */
if(prt->newInfo && (roleDesignated == cistRole))
{
+ if(dry_run) /* state change */
+ return true;
PTSM_to_TRANSMIT_CONFIG(prt);
- return;
+ return false;
}
if(prt->newInfo && (roleRoot == cistRole))
{
+ if(dry_run) /* state change */
+ return true;
PTSM_to_TRANSMIT_TCN(prt);
- return;
+ return false;
}
}
- return;
+ return false;
}
+
+ return false;
}
/* 13.32 Port Information state machine */
#define PISM_LOG(_fmt, _args...) {}
#endif /* PISM_ENABLE_LOG */
-static void PISM_run(per_tree_port_t *ptp);
+static bool PISM_run(per_tree_port_t *ptp, bool dry_run);
#define PISM_begin(ptp) PISM_to_DISABLED((ptp), true)
static void PISM_to_DISABLED(per_tree_port_t *ptp, bool begin)
ptp->selected = false;
if(!begin)
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_AGED(per_tree_port_t *ptp)
ptp->reselect = true;
ptp->selected = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_UPDATE(per_tree_port_t *ptp)
else
prt->newInfoMsti = true;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_SUPERIOR_DESIGNATED(per_tree_port_t *ptp)
ptp->selected = false;
ptp->rcvdMsg = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_REPEATED_DESIGNATED(per_tree_port_t *ptp)
updtRcvdInfoWhile(ptp);
ptp->rcvdMsg = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_INFERIOR_DESIGNATED(per_tree_port_t *ptp)
recordDispute(ptp);
ptp->rcvdMsg = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_NOT_DESIGNATED(per_tree_port_t *ptp)
setTcFlags(ptp);
ptp->rcvdMsg = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_OTHER(per_tree_port_t *ptp)
ptp->rcvdMsg = false;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_CURRENT(per_tree_port_t *ptp)
PISM_LOG("");
ptp->PISM_state = PISM_CURRENT;
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
static void PISM_to_RECEIVE(per_tree_port_t *ptp)
ptp->rcvdInfo = rcvInfo(ptp);
recordMastered(ptp);
- PISM_run(ptp);
+ PISM_run(ptp, false /* actual run */);
}
-static void PISM_run(per_tree_port_t *ptp)
+static bool PISM_run(per_tree_port_t *ptp, bool dry_run)
{
bool rcvdXstMsg, updtXstInfo;
port_t *prt = ptp->port;
if((!prt->portEnabled) && (ioDisabled != ptp->infoIs))
{
+ if(dry_run) /* at least infoIs will change */
+ return true;
PISM_to_DISABLED(ptp, false);
- return;
+ return false;
}
switch(ptp->PISM_state)
case PISM_DISABLED:
if(prt->portEnabled)
{
+ if(dry_run) /* state change */
+ return true;
PISM_to_AGED(ptp);
- return;
+ return false;
}
if(ptp->rcvdMsg)
+ {
+ if(dry_run) /* at least rcvdMsg will change */
+ return true;
PISM_to_DISABLED(ptp, false);
- return;
+ }
+ return false;
case PISM_AGED:
if(ptp->selected && ptp->updtInfo)
+ {
+ if(dry_run) /* state change */
+ return true;
PISM_to_UPDATE(ptp);
- return;
+ }
+ return false;
case PISM_UPDATE:
/* return; */
case PISM_SUPERIOR_DESIGNATED:
case PISM_NOT_DESIGNATED:
/* return; */
case PISM_OTHER:
+ if(dry_run) /* state change */
+ return true;
PISM_to_CURRENT(ptp);
- return;
+ return false;
case PISM_CURRENT:
/*
* Although 802.1Q-2005 does not define rcvdXstMsg and updtXstInfo
}
if(rcvdXstMsg && !updtXstInfo)
{
+ if(dry_run) /* state change */
+ return true;
PISM_to_RECEIVE(ptp);
- return;
+ return false;
}
if((ioReceived == ptp->infoIs) && (0 == ptp->rcvdInfoWhile)
&& !ptp->updtInfo && !rcvdXstMsg)
{
+ if(dry_run) /* state change */
+ return true;
PISM_to_AGED(ptp);
- return;
+ return false;
}
if(ptp->selected && ptp->updtInfo)
+ {
+ if(dry_run) /* state change */
+ return true;
PISM_to_UPDATE(ptp);
- return;
+ }
+ return false;
case PISM_RECEIVE:
switch(ptp->rcvdInfo)
{
case SuperiorDesignatedInfo:
+ if(dry_run) /* state change */
+ return true;
PISM_to_SUPERIOR_DESIGNATED(ptp);
- return;
+ return false;
case RepeatedDesignatedInfo:
+ if(dry_run) /* state change */
+ return true;
PISM_to_REPEATED_DESIGNATED(ptp);
- return;
+ return false;
case InferiorDesignatedInfo:
+ if(dry_run) /* state change */
+ return true;
PISM_to_INFERIOR_DESIGNATED(ptp);
- return;
+ return false;
case InferiorRootAlternateInfo:
+ if(dry_run) /* state change */
+ return true;
PISM_to_NOT_DESIGNATED(ptp);
- return;
+ return false;
case OtherInfo:
+ if(dry_run) /* state change */
+ return true;
PISM_to_OTHER(ptp);
- return;
+ return false;
}
- return;
+ return false;
}
+
+ return false;
}
/* 13.33 Port Role Selection state machine */
-static void PRSSM_run(tree_t *tree);
+static bool PRSSM_run(tree_t *tree, bool dry_run);
#define PRSSM_begin(tree) PRSSM_to_INIT_TREE(tree)
static void PRSSM_to_INIT_TREE(tree_t *tree/*, bool begin*/)
* because transition to this state can be initiated only by BEGIN var.
* In other words, this function is called via xxx_begin macro only.
* if(!begin)
- * PRSSM_run(prt); */
+ * PRSSM_run(prt, false); */
}
static void PRSSM_to_ROLE_SELECTION(tree_t *tree)
setSelectedTree(tree);
/* No need to run, no one condition will be met
- PRSSM_run(tree); */
+ PRSSM_run(tree, false); */
}
-static void PRSSM_run(tree_t *tree)
+static bool PRSSM_run(tree_t *tree, bool dry_run)
{
per_tree_port_t *ptp;
switch(tree->PRSSM_state)
{
case PRSSM_INIT_TREE:
+ if(dry_run) /* state change */
+ return true;
PRSSM_to_ROLE_SELECTION(tree);
- return;
+ return false;
case PRSSM_ROLE_SELECTION:
FOREACH_PTP_IN_TREE(ptp, tree)
if(ptp->reselect)
{
+ if(dry_run) /* at least reselect will change */
+ return true;
PRSSM_to_ROLE_SELECTION(tree);
- return;
+ return false;
}
- return;
+ return false;
}
+
+ return false;
}
/* 13.34 Port Role Transitions state machine */
#define PRTSM_LOG(_fmt, _args...) {}
#endif /* PRTSM_ENABLE_LOG */
-static void PRTSM_runr(per_tree_port_t *ptp, bool recursive_call);
-#define PRTSM_run(ptp) PRTSM_runr((ptp), false)
+static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run);
+#define PRTSM_run(ptp, dry_run) PRTSM_runr((ptp), false, (dry_run))
#define PRTSM_begin(ptp) PRTSM_to_INIT_PORT(ptp)
/* Disabled Port role transitions */
* because transition to this state can be initiated only by BEGIN var.
* In other words, this function is called via xxx_begin macro only.
* if(!begin)
- * PRTSM_runr(ptp, false); */
+ * PRTSM_runr(ptp, false, false); */
}
static void PRTSM_to_DISABLE_PORT(per_tree_port_t *ptp)
ptp->learn = false;
ptp->forward = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DISABLED_PORT(per_tree_port_t *ptp, unsigned int MaxAge)
ptp->sync = false;
ptp->reRoot = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
/* MasterPort role transitions */
setSyncTree(ptp->tree);
ptp->proposed = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_AGREED(per_tree_port_t *ptp)
ptp->sync = false;
ptp->agree = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_SYNCED(per_tree_port_t *ptp)
ptp->synced = true;
ptp->sync = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_RETIRED(per_tree_port_t *ptp)
ptp->reRoot = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_FORWARD(per_tree_port_t *ptp)
assign(ptp->fdWhile, 0u);
ptp->agreed = ptp->port->sendRSTP;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay)
ptp->learn = true;
assign(ptp->fdWhile, forwardDelay);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_DISCARD(per_tree_port_t *ptp, unsigned int forwardDelay)
ptp->disputed = false;
assign(ptp->fdWhile, forwardDelay);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_MASTER_PORT(per_tree_port_t *ptp)
ptp->role = roleMaster;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
/* RootPort role transitions */
setSyncTree(ptp->tree);
ptp->proposed = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ROOT_AGREED(per_tree_port_t *ptp)
else
prt->newInfoMsti = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ROOT_SYNCED(per_tree_port_t *ptp)
ptp->synced = true;
ptp->sync = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_REROOT(per_tree_port_t *ptp)
setReRootTree(ptp->tree);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ROOT_FORWARD(per_tree_port_t *ptp)
assign(ptp->fdWhile, 0u);
ptp->forward = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ROOT_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay)
assign(ptp->fdWhile, forwardDelay);
ptp->learn = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_REROOTED(per_tree_port_t *ptp)
ptp->reRoot = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ROOT_PORT(per_tree_port_t *ptp, unsigned int FwdDelay)
ptp->role = roleRoot;
assign(ptp->rrWhile, FwdDelay);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
/* DesignatedPort role transitions */
else
prt->newInfoMsti = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_AGREED(per_tree_port_t *ptp)
else
prt->newInfoMsti = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_SYNCED(per_tree_port_t *ptp)
ptp->synced = true;
ptp->sync = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_RETIRED(per_tree_port_t *ptp)
ptp->reRoot = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_FORWARD(per_tree_port_t *ptp)
assign(ptp->fdWhile, 0u);
ptp->agreed = ptp->port->sendRSTP;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_LEARN(per_tree_port_t *ptp, unsigned int forwardDelay)
ptp->learn = true;
assign(ptp->fdWhile, forwardDelay);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_DISCARD(per_tree_port_t *ptp, unsigned int forwardDelay)
ptp->disputed = false;
assign(ptp->fdWhile, forwardDelay);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_DESIGNATED_PORT(per_tree_port_t *ptp)
ptp->role = roleDesignated;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
/* AlternatePort and BackupPort role transitions */
ptp->learn = false;
ptp->forward = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_BACKUP_PORT(per_tree_port_t *ptp, unsigned int HelloTime)
assign(ptp->rbWhile, 2 * HelloTime);
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ALTERNATE_PROPOSED(per_tree_port_t *ptp)
setSyncTree(ptp->tree);
ptp->proposed = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ALTERNATE_AGREED(per_tree_port_t *ptp)
else
prt->newInfoMsti = true;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
static void PRTSM_to_ALTERNATE_PORT(per_tree_port_t *ptp, unsigned int forwardDelay)
ptp->sync = false;
ptp->reRoot = false;
- PRTSM_runr(ptp, true);
+ PRTSM_runr(ptp, true, false /* actual run */);
}
-static void PRTSM_runr(per_tree_port_t *ptp, bool recursive_call)
+static bool PRTSM_runr(per_tree_port_t *ptp, bool recursive_call, bool dry_run)
{
/* Following vars do not need recalculating on recursive calls */
static unsigned int MaxAge, FwdDelay, forwardDelay, HelloTime;
switch(ptp->selectedRole)
{
case roleDisabled:
+ if(dry_run) /* at least role will change */
+ return true;
PRTSM_to_DISABLE_PORT(ptp);
- return;
+ return false;
case roleMaster:
+ if(dry_run) /* at least role will change */
+ return true;
PRTSM_to_MASTER_PORT(ptp);
- return;
+ return false;
case roleRoot:
+ if(dry_run) /* at least role will change */
+ return true;
PRTSM_to_ROOT_PORT(ptp, FwdDelay);
- return;
+ return false;
case roleDesignated:
+ if(dry_run) /* at least role will change */
+ return true;
PRTSM_to_DESIGNATED_PORT(ptp);
- return;
+ return false;
case roleAlternate:
case roleBackup:
+ if(dry_run) /* at least role will change */
+ return true;
PRTSM_to_BLOCK_PORT(ptp);
- return;
+ return false;
}
}
{
/* Disabled Port role transitions */
case PRTSM_INIT_PORT:
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DISABLE_PORT(ptp);
- return;
+ return false;
case PRTSM_DISABLE_PORT:
if(ptp->selected && !ptp->updtInfo
&& !ptp->learning && !ptp->forwarding
)
+ {
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DISABLED_PORT(ptp, MaxAge);
- return;
+ }
+ return false;
case PRTSM_DISABLED_PORT:
if(ptp->selected && !ptp->updtInfo
&& (ptp->sync || ptp->reRoot || !ptp->synced
|| (ptp->fdWhile != MaxAge))
)
+ {
+ if(dry_run) /* one of (sync,reRoot,synced,fdWhile) will change */
+ return true;
PRTSM_to_DISABLED_PORT(ptp, MaxAge);
- return;
+ }
+ return false;
/* MasterPort role transitions */
case PRTSM_MASTER_PROPOSED:
/* return; */
case PRTSM_MASTER_LEARN:
/* return; */
case PRTSM_MASTER_DISCARD:
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_PORT(ptp);
- return;
+ return false;
case PRTSM_MASTER_PORT:
if(!(ptp->selected && !ptp->updtInfo))
- return;
+ return false;
if(ptp->reRoot && (0 == ptp->rrWhile))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_RETIRED(ptp);
- return;
+ return false;
}
if((!ptp->learning && !ptp->forwarding && !ptp->synced)
|| (ptp->agreed && !ptp->synced)
|| (ptp->sync && ptp->synced)
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_SYNCED(ptp);
- return;
+ return false;
}
if((allSynced && !ptp->agree)
|| (ptp->proposed && ptp->agree)
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_AGREED(ptp);
- return;
+ return false;
}
if(ptp->proposed && !ptp->agree)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_PROPOSED(ptp);
- return;
+ return false;
}
if(((0 == ptp->fdWhile) || allSynced)
&& ptp->learn && !ptp->forward
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_FORWARD(ptp);
- return;
+ return false;
}
if(((0 == ptp->fdWhile) || allSynced)
&& !ptp->learn
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_LEARN(ptp, forwardDelay);
- return;
+ return false;
}
if(((ptp->sync && !ptp->synced)
|| (ptp->reRoot && (0 != ptp->rrWhile))
&& !prt->operEdge && (ptp->learn || ptp->forward)
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_MASTER_DISCARD(ptp, forwardDelay);
- return;
+ return false;
}
- return;
+ return false;
/* RootPort role transitions */
case PRTSM_ROOT_PROPOSED:
/* return; */
case PRTSM_ROOT_LEARN:
/* return; */
case PRTSM_REROOTED:
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_PORT(ptp, FwdDelay);
- return;
+ return false;
case PRTSM_ROOT_PORT:
if(!(ptp->selected && !ptp->updtInfo))
- return;
+ return false;
if(!ptp->forward && !ptp->reRoot)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_REROOT(ptp);
- return;
+ return false;
}
if((ptp->agreed && !ptp->synced) || (ptp->sync && ptp->synced))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_SYNCED(ptp);
- return;
+ return false;
}
if((allSynced && !ptp->agree) || (ptp->proposed && ptp->agree))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_AGREED(ptp);
- return;
+ return false;
}
if(ptp->proposed && !ptp->agree)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_PROPOSED(ptp);
- return;
+ return false;
}
/* 17.20.10 of 802.1D : reRooted */
reRooted = true;
{
if(!ptp->learn)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_LEARN(ptp, forwardDelay);
- return;
+ return false;
}
else if(!ptp->forward)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_FORWARD(ptp);
- return;
+ return false;
}
}
if(ptp->reRoot && ptp->forward)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_REROOTED(ptp);
- return;
+ return false;
}
if(ptp->rrWhile != FwdDelay)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ROOT_PORT(ptp, FwdDelay);
- return;
+ return false;
}
- return;
+ return false;
/* DesignatedPort role transitions */
case PRTSM_DESIGNATED_PROPOSE:
/* return; */
case PRTSM_DESIGNATED_LEARN:
/* return; */
case PRTSM_DESIGNATED_DISCARD:
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_PORT(ptp);
- return;
+ return false;
case PRTSM_DESIGNATED_PORT:
if(!(ptp->selected && !ptp->updtInfo))
- return;
+ return false;
if(ptp->reRoot && (0 == ptp->rrWhile))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_RETIRED(ptp);
- return;
+ return false;
}
if((!ptp->learning && !ptp->forwarding && !ptp->synced)
|| (ptp->agreed && !ptp->synced)
|| (ptp->sync && ptp->synced)
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_SYNCED(ptp);
- return;
+ return false;
}
if(allSynced && (ptp->proposed || !ptp->agree))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_AGREED(ptp);
- return;
+ return false;
}
if(!ptp->forward && !ptp->agreed && !ptp->proposing
&& !prt->operEdge)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_PROPOSE(ptp);
- return;
+ return false;
}
if(((0 == ptp->fdWhile) || ptp->agreed || prt->operEdge)
&& ((0 == ptp->rrWhile) || !ptp->reRoot) && !ptp->sync
{
if(!ptp->learn)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_LEARN(ptp, forwardDelay);
- return;
+ return false;
}
else if(!ptp->forward)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_FORWARD(ptp);
- return;
+ return false;
}
}
if(((ptp->sync && !ptp->synced)
&& !prt->operEdge && (ptp->learn || ptp->forward)
)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_DESIGNATED_DISCARD(ptp, forwardDelay);
- return;
+ return false;
}
- return;
+ return false;
/* AlternatePort and BackupPort role transitions */
case PRTSM_BLOCK_PORT:
if(ptp->selected && !ptp->updtInfo
&& !ptp->learning && !ptp->forwarding
)
+ {
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay);
- return;
+ }
+ return false;
case PRTSM_BACKUP_PORT:
/* return; */
case PRTSM_ALTERNATE_PROPOSED:
/* return; */
case PRTSM_ALTERNATE_AGREED:
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay);
- return;
+ return false;
case PRTSM_ALTERNATE_PORT:
if(!(ptp->selected && !ptp->updtInfo))
- return;
+ return false;
if((allSynced && !ptp->agree) || (ptp->proposed && ptp->agree))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ALTERNATE_AGREED(ptp);
- return;
+ return false;
}
if(ptp->proposed && !ptp->agree)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ALTERNATE_PROPOSED(ptp);
- return;
+ return false;
}
if((ptp->rbWhile != 2 * HelloTime) && (roleBackup == ptp->role))
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_BACKUP_PORT(ptp, HelloTime);
- return;
+ return false;
}
if((ptp->fdWhile != forwardDelay) || ptp->sync || ptp->reRoot
|| !ptp->synced)
{
+ if(dry_run) /* state change */
+ return true;
PRTSM_to_ALTERNATE_PORT(ptp, forwardDelay);
- return;
+ return false;
}
- return;
+ return false;
}
+
+ return false;
}
/* 13.35 Port State Transition state machine */
-static void PSTSM_run(per_tree_port_t *ptp);
+static bool PSTSM_run(per_tree_port_t *ptp, bool dry_run);
#define PSTSM_begin(ptp) PSTSM_to_DISCARDING((ptp), true)
static void PSTSM_to_DISCARDING(per_tree_port_t *ptp, bool begin)
ptp->forwarding = false;
if(!begin)
- PSTSM_run(ptp);
+ PSTSM_run(ptp, false /* actual run */);
}
static void PSTSM_to_LEARNING(per_tree_port_t *ptp)
MSTP_OUT_set_state(ptp, BR_STATE_LEARNING);
ptp->learning = true;
- PSTSM_run(ptp);
+ PSTSM_run(ptp, false /* actual run */);
}
static void PSTSM_to_FORWARDING(per_tree_port_t *ptp)
ptp->forwarding = true;
/* No need to run, no one condition will be met
- PSTSM_run(ptp); */
+ PSTSM_run(ptp, false); */
}
-static void PSTSM_run(per_tree_port_t *ptp)
+static bool PSTSM_run(per_tree_port_t *ptp, bool dry_run)
{
switch(ptp->PSTSM_state)
{
case PSTSM_DISCARDING:
if(ptp->learn)
+ {
+ if(dry_run) /* state change */
+ return true;
PSTSM_to_LEARNING(ptp);
- return;
+ }
+ return false;
case PSTSM_LEARNING:
if(!ptp->learn)
+ {
+ if(dry_run) /* state change */
+ return true;
PSTSM_to_DISCARDING(ptp, false);
+ }
else if(ptp->forward)
+ {
+ if(dry_run) /* state change */
+ return true;
PSTSM_to_FORWARDING(ptp);
- return;
+ }
+ return false;
case PSTSM_FORWARDING:
if(!ptp->forward)
+ {
+ if(dry_run) /* state change */
+ return true;
PSTSM_to_DISCARDING(ptp, false);
- return;
+ }
+ return false;
}
+
+ return false;
}
/* 13.36 Topology Change state machine */
ptp->port->tcAck = false;
if(!begin)
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
-static void TCSM_to_LEARNING(per_tree_port_t *ptp)
+static bool TCSM_to_LEARNING(per_tree_port_t *ptp, bool dry_run)
{
+ if(dry_run)
+ {
+ if((ptp->TCSM_state != TCSM_LEARNING) || ptp->rcvdTc || ptp->tcProp)
+ return true;
+ if(0 == ptp->MSTID) /* CIST */
+ {
+ port_t *prt = ptp->port;
+ if(prt->rcvdTcn || prt->rcvdTcAck)
+ return true;
+ }
+ return false;
+ }
+
ptp->TCSM_state = TCSM_LEARNING;
if(0 == ptp->MSTID) /* CIST */
ptp->rcvdTc = false;
ptp->tcProp = false;
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
+ return false;
}
static void TCSM_to_DETECTED(per_tree_port_t *ptp)
else
prt->newInfoMsti = true;
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
static void TCSM_to_NOTIFIED_TCN(per_tree_port_t *ptp)
newTcWhile(ptp);
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
static void TCSM_to_NOTIFIED_TC(per_tree_port_t *ptp)
}
setTcPropTree(ptp);
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
static void TCSM_to_PROPAGATING(per_tree_port_t *ptp)
set_fdbFlush(ptp);
ptp->tcProp = false;
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
static void TCSM_to_ACKNOWLEDGED(per_tree_port_t *ptp)
set_TopologyChange(ptp->tree, false);
ptp->port->rcvdTcAck = false;
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
static void TCSM_to_ACTIVE(per_tree_port_t *ptp)
{
ptp->TCSM_state = TCSM_ACTIVE;
- TCSM_run(ptp);
+ TCSM_run(ptp, false /* actual run */);
}
-static void TCSM_run(per_tree_port_t *ptp)
+static bool TCSM_run(per_tree_port_t *ptp, bool dry_run)
{
bool active_port;
port_t *prt = ptp->port;
{
case TCSM_INACTIVE:
if(ptp->learn && !ptp->fdbFlush)
- TCSM_to_LEARNING(ptp);
- return;
+ {
+ if(dry_run) /* state change */
+ return true;
+ TCSM_to_LEARNING(ptp, false /* actual run */);
+ }
+ return false;
case TCSM_LEARNING:
active_port = (roleRoot == ptp->role)
|| (roleDesignated == ptp->role)
|| (roleMaster == ptp->role);
if(active_port && ptp->forward && !prt->operEdge)
{
+ if(dry_run) /* state change */
+ return true;
TCSM_to_DETECTED(ptp);
- return;
+ return false;
}
if(ptp->rcvdTc || prt->rcvdTcn || prt->rcvdTcAck || ptp->tcProp)
{
- TCSM_to_LEARNING(ptp);
- return;
+ return TCSM_to_LEARNING(ptp, dry_run);
}
else if(!active_port && !(ptp->learn || ptp->learning))
+ {
+ if(dry_run) /* state change */
+ return true;
TCSM_to_INACTIVE(ptp, false);
- return;
+ }
+ return false;
case TCSM_NOTIFIED_TCN:
+ if(dry_run) /* state change */
+ return true;
TCSM_to_NOTIFIED_TC(ptp);
- return;
+ return false;
case TCSM_DETECTED:
/* return; */
case TCSM_NOTIFIED_TC:
case TCSM_PROPAGATING:
/* return; */
case TCSM_ACKNOWLEDGED:
+ if(dry_run) /* state change */
+ return true;
TCSM_to_ACTIVE(ptp);
- return;
+ return false;
case TCSM_ACTIVE:
active_port = (roleRoot == ptp->role)
|| (roleDesignated == ptp->role)
|| (roleMaster == ptp->role);
if(!active_port || prt->operEdge)
{
- TCSM_to_LEARNING(ptp);
- return;
+ if(dry_run) /* state change */
+ return true;
+ TCSM_to_LEARNING(ptp, false /* actual run */);
+ return false;
}
if(prt->rcvdTcn)
{
+ if(dry_run) /* state change */
+ return true;
TCSM_to_NOTIFIED_TCN(ptp);
- return;
+ return false;
}
if(ptp->rcvdTc)
{
+ if(dry_run) /* state change */
+ return true;
TCSM_to_NOTIFIED_TC(ptp);
- return;
+ return false;
}
if(ptp->tcProp/* && !prt->operEdge */)
{
+ if(dry_run) /* state change */
+ return true;
TCSM_to_PROPAGATING(ptp);
- return;
+ return false;
}
if(prt->rcvdTcAck)
{
+ if(dry_run) /* state change */
+ return true;
TCSM_to_ACKNOWLEDGED(ptp);
- return;
+ return false;
}
- return;
+ return false;
}
+
+ return false;
}
/* Execute BEGIN state. We do not define BEGIN variable
/* 13.33 Port Role Selection state machine */
FOREACH_TREE_IN_BRIDGE(tree, br)
- PRSSM_run(tree);
+ PRSSM_run(tree, false /* actual run */);
/* 13.34 Port Role Transitions state machine */
FOREACH_PTP_IN_PORT(ptp, prt)
br_state_machines_run(br);
}
-/* Run each state machine */
-static void br_state_machines_run(bridge_t *br)
+/* Run each state machine.
+ * Return false iff all state machines in dry run indicate that
+ * state will not be changed. Otherwise return true.
+ */
+static bool __br_state_machines_run(bridge_t *br, bool dry_run)
{
port_t *prt;
per_tree_port_t *ptp;
tree_t *tree;
- if(!br->bridgeEnabled)
- return;
-
/* 13.28 Port Receive state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
- PRSM_run(prt);
+ {
+ if(PRSM_run(prt, dry_run) && dry_run)
+ return true;
+ }
/* 13.29 Port Protocol Migration state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
- PPMSM_run(prt);
+ {
+ if(PPMSM_run(prt, dry_run) && dry_run)
+ return true;
+ }
/* 13.30 Bridge Detection state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
- BDSM_run(prt);
+ {
+ if(BDSM_run(prt, dry_run) && dry_run)
+ return true;
+ }
/* 13.31 Port Transmit state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
- PTSM_run(prt);
+ {
+ if(PTSM_run(prt, dry_run) && dry_run)
+ return true;
+ }
/* 13.32 Port Information state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
{
FOREACH_PTP_IN_PORT(ptp, prt)
- PISM_run(ptp);
+ {
+ if(PISM_run(ptp, dry_run) && dry_run)
+ return true;
+ }
}
/* 13.33 Port Role Selection state machine */
FOREACH_TREE_IN_BRIDGE(tree, br)
- PRSSM_run(tree);
+ {
+ if(PRSSM_run(tree, dry_run) && dry_run)
+ return true;
+ }
/* 13.34 Port Role Transitions state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
{
FOREACH_PTP_IN_PORT(ptp, prt)
- PRTSM_run(ptp);
+ {
+ if(PRTSM_run(ptp, dry_run) && dry_run)
+ return true;
+ }
}
/* 13.35 Port State Transition state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
{
FOREACH_PTP_IN_PORT(ptp, prt)
- PSTSM_run(ptp);
+ {
+ if(PSTSM_run(ptp, dry_run) && dry_run)
+ return true;
+ }
}
/* 13.36 Topology Change state machine */
FOREACH_PORT_IN_BRIDGE(prt, br)
{
FOREACH_PTP_IN_PORT(ptp, prt)
- TCSM_run(ptp);
+ {
+ if(TCSM_run(ptp, dry_run) && dry_run)
+ return true;
+ }
}
+
+ return false;
+}
+
+/* Run state machines until their state stabilizes.
+ * Do not consume more than 1 second.
+ */
+static void br_state_machines_run(bridge_t *br)
+{
+ struct timeval tv, tv_end;
+ signed long delta;
+
+ if(!br->bridgeEnabled)
+ return;
+
+ gettimeofday(&tv_end, NULL);
+ ++(tv_end.tv_sec);
+
+ do {
+ if(!__br_state_machines_run(br, true /* dry run */))
+ return;
+ __br_state_machines_run(br, false /* actual run */);
+
+ /* Check for the timeout */
+ gettimeofday(&tv, NULL);
+ if(0 < (delta = tv.tv_sec - tv_end.tv_sec))
+ return;
+ if(0 == delta)
+ {
+ delta = tv.tv_usec - tv_end.tv_usec;
+ if(0 < delta)
+ return;
+ }
+ } while(true);
}