diff --git a/bgpsim/src/interactive.rs b/bgpsim/src/interactive.rs index 5a61a93..7f339f9 100644 --- a/bgpsim/src/interactive.rs +++ b/bgpsim/src/interactive.rs @@ -65,21 +65,25 @@ where /// be set by `self.set_msg_limit`). fn simulate(&mut self) -> Result<(), NetworkError>; - /// Similarly to the [`Network::simulate`] function, this function will execute all events in the - /// queue. This function provides a hook in the form of a closure that is called before and after + /// Similarly to the [`Network::simulate`] function, this function will execute all events in the + /// queue. This function provides a hook in the form of a closure that is called before and after /// each event is processed. - /// - /// The closure always provides immutable access to both the network and the currently processed - /// event. Furthermore, it enables the user to determine whether it was called before or after + /// + /// The closure always provides immutable access to both the network and the currently processed + /// event. Furthermore, it enables the user to determine whether it was called before or after /// the event was processed based on the value of the third argument. - /// + /// /// If the closure is called *before* the event is processed, the third argument will be `None`. /// If the closure is called *after* the event is processed, the third argument will contain a /// `Some((StepUpdate, Vec))` tuple, where the second element contains a list of events /// that were generated by the event that was just processed. fn simulate_hooked( net: &mut Network, - f: impl FnMut(&Network, &Event, Option<&(StepUpdate

, Vec>)>) -> (), + f: impl FnMut( + &Network, + &Event, + Option<&(StepUpdate

, Vec>)>, + ) -> (), ) -> Result<(), NetworkError>; /// Trigger the timeout event on any router. The router is picked randomly if the feature `rand` @@ -228,44 +232,48 @@ impl, Ospf: OspfImpl> InteractiveNetwork } fn simulate_hooked( - net: &mut Network, - mut f: impl FnMut(&Network, &Event, Option<&(StepUpdate

, Vec>)>) -> (), - ) -> Result<(), NetworkError> - { - 'timeout: loop { - // While there are events in the queue - while let Some(event) = net.queue_mut().pop() { - let event_clone = event.clone(); - - unsafe { - // Straddle the trigger_event function with the pre- and post-event hooks - f(net, &event_clone, None); - let result = net.trigger_event(event)?; - f(net, &event_clone, Some(&result)); - - net.enqueue_events(result.1); - } + net: &mut Network, + mut f: impl FnMut( + &Network, + &Event, + Option<&(StepUpdate

, Vec>)>, + ) -> (), + ) -> Result<(), NetworkError> { + 'timeout: loop { + // While there are events in the queue + while let Some(event) = net.queue_mut().pop() { + let event_clone = event.clone(); - if matches!(event_clone, Event::Ospf { .. }) { - // OSPF event received! Check the BGP session state - net.refresh_bgp_sessions()?; - } - } + // Straddle the trigger_event function with the pre- and post-event hooks + f(net, &event_clone, None); + // Safety: This is safe because we are allowing the network to eventually + // converge by exhausing all events in the queue. The extracted events are + // all immutable and won't be modified. + let result = unsafe { net.trigger_event(event)? }; + f(net, &event_clone, Some(&result)); - // trigger the next timeout event if it exists. - let trigger_router = net.trigger_timeout()?; + net.enqueue_events(result.1); - // if no timeout was triggered, break out of the loop. We are converged! - if trigger_router.is_none() { - break 'timeout; + if matches!(event_clone, Event::Ospf { .. }) { + // OSPF event received! Check the BGP session state + net.refresh_bgp_sessions()?; } } - // remove unreachable OSPF LSAs - net.internal_routers_mut() - .for_each(|r| r.ospf.remove_unreachable_lsas()); + // trigger the next timeout event if it exists. + let trigger_router = net.trigger_timeout()?; + + // if no timeout was triggered, break out of the loop. We are converged! + if trigger_router.is_none() { + break 'timeout; + } + } + + // remove unreachable OSPF LSAs + net.internal_routers_mut() + .for_each(|r| r.ospf.remove_unreachable_lsas()); - Ok(()) + Ok(()) } fn trigger_timeout(&mut self) -> Result, NetworkError> {