shadow_rs/network/router/
mod.rs1use std::cell::RefCell;
2use std::net::Ipv4Addr;
3
4use 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;
10
11use shadow_shim_helper_rs::emulated_time::EmulatedTime;
12
13pub struct Router {
16    magic: Magic<Self>,
17    _counter: ObjectCounter,
18    address: Ipv4Addr,
19    inbound_packets: RefCell<CoDelQueue>,
21}
22
23impl Router {
24    pub 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    }
35
36    fn push_inner(&self, packet: PacketRc, now: EmulatedTime) {
37        self.magic.debug_check();
38        self.inbound_packets.borrow_mut().push(packet, now);
39    }
40
41    fn pop_inner(&self, now: EmulatedTime) -> Option<PacketRc> {
42        self.magic.debug_check();
43        self.inbound_packets.borrow_mut().pop(now)
44    }
45
46    fn route_outgoing_packet(&self, packet: PacketRc) {
49        Worker::with_active_host(|src_host| Worker::send_packet(src_host, packet)).unwrap();
51    }
52
53    pub fn route_incoming_packet(&self, packet: PacketRc) {
56        self.push_inner(packet, Worker::current_time().unwrap())
57    }
58}
59
60impl PacketDevice for Router {
61    fn get_address(&self) -> Ipv4Addr {
62        self.address
63    }
64
65    fn pop(&self) -> Option<PacketRc> {
66        self.pop_inner(Worker::current_time().unwrap())
68    }
69
70    fn push(&self, packet: PacketRc) {
71        self.route_outgoing_packet(packet);
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79    use crate::network::tests::mock_time_millis;
80
81    #[test]
82    fn empty() {
83        let now = mock_time_millis(1000);
84        let router = Router::new(Ipv4Addr::UNSPECIFIED);
85        assert!(router.inbound_packets.borrow().peek().is_none());
86        assert!(router.pop_inner(now).is_none());
87    }
88
89    #[test]
90    #[cfg_attr(miri, ignore)]
92    fn push_pop_simple() {
93        let now = mock_time_millis(1000);
94        let router = Router::new(Ipv4Addr::UNSPECIFIED);
95
96        const N: usize = 10;
97
98        for _ in 1..=N {
99            router.push_inner(PacketRc::new_ipv4_udp_mock(), now);
100            assert!(router.inbound_packets.borrow().peek().is_some());
101        }
102        for _ in 1..=N {
103            assert!(router.inbound_packets.borrow().peek().is_some());
104            assert!(router.pop_inner(now).is_some());
105        }
106
107        assert!(router.inbound_packets.borrow().peek().is_none());
108        assert!(router.pop_inner(now).is_none());
109    }
110}