Eliot is a code generation tool for network fault injection.
It transforms a declarative behavioral network specification defined as a DAG, into C++ code that is compiled into a standalone tool. The generated code is compiled together with a provided backend implementation. A traits file provides the linking layer between the generated code and the backend, allowing the generated model to interact with the fault injector backend.
Requirements: Python >= 3.10, Ninja build system, C++20 compiler, CMake.
# Clone the repository
git clone https://github.com/Samo2003/Eliot.git
cd Eliot
# Create virtual environment
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -e .For development install with development dependencies:
pip install -e ".[dev]"You can install the required system dependencies on Ubuntu using:
sudo apt update
sudo apt install python3 python3-venv g++ cmake ninja-buildThe following commands assume that the virtual environment is activated.
| Command | Description |
|---|---|
generate |
Generate pipeline code using a custom backend and traits file |
benchmark |
Generate code using the benchmark backend |
profile |
Generate code configured for profiling |
test |
Generate code using the testing backend |
schema |
Print the JSON schema for DAG specifications |
Note: The benchmark, profile, and test commands only work with editable installation (pip install -e .), as they rely on example backends and traits included in the repository.
| Option | Default | Description |
|---|---|---|
-d | --dag |
None | Path to the DAG specification file (YAML or JSON) |
-t | --traits |
None | Path to the traits file (C++ header) |
-b | --backend |
None | Path to the backend directory containing CMakeLists.txt |
-o | --output |
. |
Path to the output directory for generated code and binary file |
-h | --help |
None | Show help message and exit |
To define the target network behavior you need to create a DAG specification file in YAML or JSON format. Example files can be found in examples/dags/. The exact arguments and structures of each node can be found in classes defined in src/eliot/DAG/.
The model is designed to be extensible: new actions, conditions, and value generators can be added by defining the corresponding DAG model class and code-generation template.
You need to specify a traits file defining an adapter layer between your backend and the generated code. The file traits/TraitsTemplate.hpp contains required methods together with their explanations. Other files in the traits/ directory serve as examples.
The repository also contains several lightweight backend implementations in mocks/. See mocks/README.md for a short overview.
To generate the code and binary file, run:
eliot generate \
--dag <path_to_dag> \
--traits <path_to_traits_file> \
--backend <path_to_backend_directory>The generated code will be placed by default in the current directory under generated/, and the compiled binary will be copied to ./eliot-run. You can change the output directory by adding the --output <path_to_output_directory> argument to the command above.
Example of the generate command:
eliot generate \
--dag examples/dags/drop_every_second.yaml \
--traits traits/MockTraits.hpp \
--backend mocks/mockThis command generates code for a DAG specification that drops every second packet, using a mock backend and traits file. The target behavior can be tested using the following commands:
In terminal 1 execute eliot-run to start the generated binary:
./eliot-run examples/backend_config.jsonNote: The examples/backend_config.json file contains the configuration for ports and IP addresses of the mock backend, which is used in this example.
In terminal 2 execute the receiver script to accept packets:
python examples/receiver.pyIn terminal 3 execute the sender script to send packets:
python examples/sender.py --count 10This will send 10 ICMP packets from the sender to the receiver. The generated code will drop every second packet, so only 5 packets will be received by the receiver. You can modify the DAG specification to change the behavior or test different scenarios.
For more details about the examples see examples/README.md.
To execute the tests run:
pytest -n autoThe tests are located in the tests/ directory. They consist of end-to-end tests to verify the complete generation and execution pipeline. Each test consists of generating code from DAG specification, building a binary file, sending defined packet sequences and validating the provided constraints.
For details on adding new test cases, see tests/README.md.
If you execute the tests without required system dependencies installed, first install them and then rerun the tests using the --clean flag to ensure that all generated code is removed and regenerated with the new dependencies:
pytest --clean -n autoNote: For normal test execution, use the first mentioned command as it results in a faster test execution by reusing CMake build files.
Some source code comments were generated using ChatGPT.