| # 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. |