1use std::cell::RefCell;
2use std::net::Ipv4Addr;
34use self::codel_queue::CoDelQueue;
5use crate::core::worker::Worker;
6use crate::network::PacketDevice;
7use crate::network::packet::PacketRc;
8use crate::utility::{Magic, ObjectCounter};
9mod codel_queue;
1011use shadow_shim_helper_rs::emulated_time::EmulatedTime;
1213/// A router assists with moving packets between hosts across the simulated
14/// network.
15pub struct Router {
16 magic: Magic<Self>,
17 _counter: ObjectCounter,
18 address: Ipv4Addr,
19/// Packets inbound to the host from the simulated network.
20inbound_packets: RefCell<CoDelQueue>,
21}
2223impl Router {
24/// Create a new router for a host that will help route packets between it
25 /// and other hosts. The `address` must uniquely identify this router to the
26 /// host that owns it.
27pub fn new(address: Ipv4Addr) -> Router {
28 Router {
29 magic: Magic::new(),
30 address,
31 _counter: ObjectCounter::new("Router"),
32 inbound_packets: RefCell::new(CoDelQueue::new()),
33 }
34 }
3536fn push_inner(&self, packet: PacketRc, now: EmulatedTime) {
37self.magic.debug_check();
38self.inbound_packets.borrow_mut().push(packet, now);
39 }
4041fn pop_inner(&self, now: EmulatedTime) -> Option<PacketRc> {
42self.magic.debug_check();
43self.inbound_packets.borrow_mut().pop(now)
44 }
4546/// Routes the packet from the source host through the virtual internet to
47 /// the destination host.
48fn route_outgoing_packet(&self, packet: PacketRc) {
49// TODO: move Worker::send_packet to here?
50Worker::with_active_host(|src_host| Worker::send_packet(src_host, packet)).unwrap();
51 }
5253/// Routes the packet from the virtual internet into our CoDel queue, which
54 /// can then be received by the destiantion host by calling pop().
55pub fn route_incoming_packet(&self, packet: PacketRc) {
56self.push_inner(packet, Worker::current_time().unwrap())
57 }
58}
5960impl PacketDevice for Router {
61fn get_address(&self) -> Ipv4Addr {
62self.address
63 }
6465fn pop(&self) -> Option<PacketRc> {
66// When the host calls pop, we provide the next packet from the CoDel queue.
67self.pop_inner(Worker::current_time().unwrap())
68 }
6970fn push(&self, packet: PacketRc) {
71// When the host calls push, we send to the virtual internet.
72self.route_outgoing_packet(packet);
73 }
74}
7576#[cfg(test)]
77mod tests {
78use super::*;
79use crate::network::tests::mock_time_millis;
8081#[test]
82fn empty() {
83let now = mock_time_millis(1000);
84let router = Router::new(Ipv4Addr::UNSPECIFIED);
85assert!(router.inbound_packets.borrow().peek().is_none());
86assert!(router.pop_inner(now).is_none());
87 }
8889#[test]
90// Ignore in miri for use of c::packet* functions.
91#[cfg_attr(miri, ignore)]
92fn push_pop_simple() {
93let now = mock_time_millis(1000);
94let router = Router::new(Ipv4Addr::UNSPECIFIED);
9596const N: usize = 10;
9798for _ in 1..=N {
99 router.push_inner(PacketRc::new_ipv4_udp_mock(), now);
100assert!(router.inbound_packets.borrow().peek().is_some());
101 }
102for _ in 1..=N {
103assert!(router.inbound_packets.borrow().peek().is_some());
104assert!(router.pop_inner(now).is_some());
105 }
106107assert!(router.inbound_packets.borrow().peek().is_none());
108assert!(router.pop_inner(now).is_none());
109 }
110}