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