tree: 2769d0522c7e9ef18db728ddb47c0c55ec06b9de [path history] [tgz]
  3. actor.h
  5. alarm_factory.h
  7. link.h
  9. packet_filter.h
  11. port.h
  13. queue.h
  15. quic_endpoint.h
  17. quic_endpoint_base.h
  20. simulator.h
  23. switch.h
  25. traffic_policer.h

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.


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.

class LogClock : public Actor {
  LogClock(Simulator* simulator, std::string name) : Actor(simulator, name) {
  ~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().


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


The SymmetricLink class models a symmetric duplex links with finite bandwidth and propagation delay. It consists of a pair of identical OneWayLinks, 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:

 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.