| # QUIC network simulator | |
| This directory contains a discrete event network simulator which QUIC code uses | |
| for testing congestion control and other transmission control code that requires | |
| a network simulation for tests on QuicConnection level of abstraction. | |
| ## Actors | |
| The core of the simulator is the Simulator class, which maintains a virtual | |
| clock and an event queue. Any object in a simulation that needs to schedule | |
| events has to subclass Actor. Subclassing Actor involves: | |
| 1. Calling the `Actor::Actor(Simulator*, std::string)` constructor to establish | |
| the name of the object and the simulator it is associated with. | |
| 2. Calling `Schedule(QuicTime)` to schedule the time at which `Act()` method is | |
| called. `Schedule` will only cause the object to be rescheduled if the time | |
| for which it is currently scheduled is later than the new time. | |
| 3. Implementing `Act()` method with the relevant logic. The actor will be | |
| removed from the event queue right before `Act()` is called. | |
| Here is a simple example of an object that outputs simulation time into the log | |
| every 100 ms. | |
| ```c++ | |
| class LogClock : public Actor { | |
| public: | |
| LogClock(Simulator* simulator, std::string name) : Actor(simulator, name) { | |
| Schedule(clock_->Now()); | |
| } | |
| ~LogClock() override {} | |
| void Act() override { | |
| QUIC_LOG(INFO) << "The current time is " | |
| << clock_->Now().ToDebuggingValue(); | |
| Schedule(clock_->Now() + QuicTime::Delta::FromMilliseconds(100)); | |
| } | |
| }; | |
| ``` | |
| A QuicAlarm object can be used to schedule events in the simulation using | |
| `Simulator::GetAlarmFactory()`. | |
| ## Ports | |
| The simulated network transfers packets, which are modelled as an instance of | |
| struct `Packet`. A packet consists of source and destination address (which are | |
| just plain strings), a transmission timestamp and the UDP-layer payload. | |
| The simulation uses the push model: any object that wishes to transfer a packet | |
| to another component in the simulation has to explicitly do it itself. Any | |
| object that can accept a packet is called a *port*. There are two types of | |
| ports: unconstrained ports, which can always accept packets, and constrained | |
| ports, which signal when they can accept a new packet. | |
| An endpoint is an object that is connected to the network and can both receive | |
| and send packets. In our model, the endpoint always receives packets as an | |
| unconstrained port (*RX port*), and always writes packets to a constrained port | |
| (*TX port*). | |
| ## Links | |
| The `SymmetricLink` class models a symmetric duplex links with finite bandwidth | |
| and propagation delay. It consists of a pair of identical `OneWayLink`s, which | |
| accept packets as a constrained port (where constrain comes from the finiteness | |
| of bandwidth) and outputs them into an unconstrained port. Two endpoints | |
| connected via a `SymmetricLink` look like this: | |
| ```none | |
| Endpoint A Endpoint B | |
| +-----------+ SymmetricLink +-----------+ | |
| | | +------------------------------+ | | | |
| | +---------+ | +------------------------+ | +---------+ | | |
| | | RX port <-----| OneWayLink *<-----| TX port | | | |
| | +---------+ | +------------------------+ | +---------+ | | |
| | | | | | | | |
| | +---------+ | +------------------------+ | +---------+ | | |
| | | TX port |----->* OneWayLink |-----> RX port | | | |
| | +---------+ | +------------------------+ | +---------+ | | |
| | | +------------------------------+ | | | |
| +-----------+ +-----------+ | |
| ( -->* denotes constrained port) | |
| ``` | |
| In most common scenario, one of the endpoints is going to be a QUIC endpoint, | |
| and another is going to be a switch port. | |
| ## Other objects | |
| Besides `SymmetricLink`, the simulator provides the following objects: | |
| * `Queue` allows to convert a constrained port into an unconstrained one by | |
| buffering packets upon arrival. The queue has a finite size, and once the | |
| queue is full, the packets are silently dropped. | |
| * `Switch` simulates a multi-port learning switch with a fixed queue for each | |
| output port. | |
| * `QuicEndpoint` allows QuicConnection to be run over the simulated network. | |
| * `QuicEndpointMultiplexer` allows multiple connections to share the same | |
| network endpoint. |