GitHub Repository: github.com/DanielAgbeni/GARRO
GARRO is a Deep Reinforcement Learning (DRL) routing framework designed for Software-Defined Networks (SDN). It combines a Graph Attention Transformer (GAT) to capture complex network topologies and traffic states with Proximal Policy Optimization (PPO) to dynamically route traffic requests.
This repository implements both Phase 1: Offline Digital Twin Training and Phase 2: Live Mininet Emulation using OS-Ken (a modern, Neutron-optimized fork of the Ryu SDN controller).
The project is structured into three clear planes: the AI Decision Plane, the Control Plane, and the Data/Simulation Plane.
ββββββββββββββββββββββββββββββββ
β Agentic AI Layer β
β - LLM Orchestrator β (Refreshes rewards from intent)
ββββββββββββββββββββββββββββββββ
β
βΌ (Weight updates)
ββββββββββββββββββββββββββββββββ
β AI Decision Plane β
β - PPO + Graph Transformer β (model/)
β - Offline Train Loop β (train_offline.py)
β - Online Deploy Loop β (deploy_online.py)
ββββββββββββββββββββββββββββββββ
β² β
HTTP GET β β HTTP POST
/garro/state β β /garro/flow
β βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SDN Control Plane β
β - OS-Ken OpenFlow 1.3 App β (controller/garro_controller.py)
β - Flask REST API Integration β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β²
β OpenFlow 1.3 (Southbound)
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SDN Data Plane (Phase 2 Emulation) β
β - Mininet Network Emulation β (topologies/mininet_*.py)
β - Open vSwitch (OVS) Kernel Datapath β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-
State Encoder (
model/graph_transformer.py):- Converts the NetworkX topology graph (carrying node CPU/buffer load and edge capacity/delay/utilization metrics) into a PyTorch Geometric (PyG)
Dataobject. - Appends a virtual star node connected to all nodes to aggregate global graph context.
- Runs a 3-layer
TransformerConvnetwork to output a 128-dimensional latent state representation.
- Converts the NetworkX topology graph (carrying node CPU/buffer load and edge capacity/delay/utilization metrics) into a PyTorch Geometric (PyG)
-
PPO Actor-Critic Agent (
model/ppo_agent.py):-
Actor: Predicts routing action probability distributions over candidate
$K$ -shortest paths. - Critic: Estimates the state value function to compute Generalized Advantage Estimations (GAE).
- Optimized for CPU: Pre-computes detached graph representations once per epoch, running the Actor-Critic networks efficiently on mini-batches. It does a single encoder gradient update per epoch to prevent redundant backpropagation and avoid slow CPU runs.
-
Actor: Predicts routing action probability distributions over candidate
-
Digital Twin Environment (
digital_twin/mm1k_env.py):- Implements a standard Gymnasium environment interface.
- Models links as analytical M/M/1/K finite-capacity queues where queue length, packet loss, and latency are calculated deterministically.
- Dynamically tracks ingress/egress rates, buffer occupancies, and links bandwidth.
-
Traffic Generator (
digital_twin/traffic_generator.py):- Generates traffic matrix requests using Poisson arrivals.
- Generates microbursts (temporary elephant flows at 5Γ base rate with a 10% probability) to stress-test routing resilience.
-
OS-Ken Controller Application (
controller/garro_controller.py):- Standard OS-Ken OpenFlow 1.3 controller application.
- Listens to switch connection and link discovery events (via LLDP) to construct and maintain a live NetworkX
DiGraphtopology. - Periodically polls connected switches for port statistics to compute network utilization.
- Integrates an internal Flask web server running on an eventlet green thread to serve a Northbound REST API (
GET /garro/state,GET /garro/topology,POST /garro/flow). - Receives path updates from the AI plane and pushes OpenFlow 1.3 Flow Mod entries along the network switches.
-
Mininet Network Topology (
topologies/mininet_nsfnet.py):- Instantiates a live emulated NSFNET topology with 14 switches and 21 links.
- Attaches one host per switch with configured subnet IPs (
10.0.0.1β10.0.0.14) to allow testing. - Configures propagation delays matching the real physical topology nodes using Mininet TCLinks.
GARRO is configured to run inside a Python virtual environment (garro_env).
Before running training, evaluation, or deployment scripts, activate the virtual environment:
source garro_env/bin/activateDependencies are listed in requirements.txt and are pre-installed in the virtual environment. Key requirements include:
torch(PyTorch 2.3.1+cpu)torch_geometric(PyG)torch_scatter&torch_sparse(configured with matching CPU binaries)networkx(for topology graph representations)gymnasium(RL environment framework)matplotlib&pandas(for visualization and analysis)Flask(for controller REST API integration)
GARRO fully supports native training on Apple Silicon chips (M-series) using Apple's GPU acceleration via Metal Performance Shaders (MPS).
To run training locally on your Mac with GPU/MPS acceleration:
- Ensure you have installed a native macOS python virtual environment.
- Install PyTorch with MPS support:
pip install torch
- Install PyTorch Geometric (PyG) dependencies compatible with your PyTorch macOS version:
pip install torch-scatter torch-sparse -f https://data.pyg.org/whl/torch-$(python -c "import torch; print(torch.__version__)").html pip install torch-geometric - Run the training script normally. The agent will auto-detect your M-series chip and display:
Device : mps (Apple Metal Performance Shaders)in the startup hardware banner:python train_offline.py --topology nsfnet --episodes 10000
Important
Mininet is Linux-only and cannot run natively on macOS. To emulate the network topology on an Apple Silicon Mac, you must run it inside a Linux Virtual Machine (VM). We recommend:
- UTM (Free/Open Source) or Parallels Desktop: Set up an ARM64 Ubuntu Linux VM.
- Run both the OS-Ken Controller and Mininet inside that ARM64 Linux VM.
Train the agent offline in the Digital Twin environment by running train_offline.py.
python train_offline.py --topology <topology_name> --episodes <num_episodes>To present an academically rigorous and reliable project, it is highly recommended to train and evaluate your agent across all three topologies. This proves that the GARRO routing agent can adapt to different types of network layouts (WAN vs. Data Center) and scales (14 to 80 nodes) without overfitting to a single network structure:
- Topology Diversity: Shows the model's ability to handle geographic WAN nodes with high propagation delays (NSFNET, GEANT2) as well as dense, symmetric, low-latency datacenter clusters (Fat-Tree).
- Scale & Convergence Proof: Confirms that the Graph Attention Network (GAT) generalizes well when the network size grows from small (14 switches) to very large (80 switches).
- Load Balancing Resilience: Proves the routing agent can handle highly irregular network links (GEANT2) just as well as standard hierarchical ones.
Depending on your goal (quick testing vs. reliable publication-grade results), use the following recommended parameters:
| Topology | Scale | Checkpoint ID | Sanity Check (Episodes) | Full Convergence (Recommended) | Approx. CPU Time | Key Learning Focus |
|---|---|---|---|---|---|---|
| NSFNET | 14 Nodes, 21 Links | nsfnet |
1,000 | 5,000 - 10,000 | ~15-25 min (GPU) | Basic routing loops, WAN propagation latency awareness. |
| GEANT2 | 24 Nodes, 37 Links | geant2 |
5,000 | 15,000 - 20,000 | ~30-45 min (GPU) | Load balancing under asymmetric constraints & irregular cross-links. |
| Fat-Tree (k=4) | 20 Switches, 32 Links | fat_tree |
5,000 | 20,000 - 50,000 | ~1-2 hours (GPU) | Hierarchical paths, equal-cost multi-path (ECMP) traffic spreading in DCNs. |
- Sanity Check:
python train_offline.py --topology nsfnet --episodes 1000
- Full Reliable Training:
python train_offline.py --topology nsfnet --episodes 10000
- Sanity Check:
python train_offline.py --topology geant2 --episodes 5000
- Full Reliable Training:
python train_offline.py --topology geant2 --episodes 20000
- Sanity Check:
python train_offline.py --topology fat_tree --episodes 5000
- Full Reliable Training:
python train_offline.py --topology fat_tree --episodes 20000
If you do not have a local GPU, you can train the offline model (Phase 1) on Google Colab to speed up the process using a free NVIDIA T4 GPU.
The codebase is designed to automatically optimize hardware resources in a Google Colab notebook environment:
- Automatic GPU Detection (CUDA): The agent (
model/ppo_agent.py) auto-detects Colab's allocated NVIDIA GPU. Neural network forward/backward passes are fully accelerated on the GPU device. - Automatic Mixed Precision (AMP): Under CUDA, PyTorch's
torch.autocastis enabled dynamically. The agent queries hardware support: it utilizesfloat16on standard T4 GPU runtimes and automatically upgrades tobfloat16(Tensor Cores) if running on premium L4/A100 runtimes. This halves VRAM requirements and maximizes matrix multiplication throughput. - Non-Blocking HβD Transfers: A custom
FastGraphConverterpins CPU memory buffers and streams converted Graph state tensors asynchronously (non_blocking=True) to the GPU, overlapping NetworkX-to-PyG conversion with model execution. - JIT Compilation (
torch.compile): The Graph Attention Transformer and Actor-Critic models are JIT-compiled using PyTorch 2.x'smode="reduce-overhead"to optimize the GPU execution graph and fuse kernel operations, boosting overall iteration speeds. - CPU-Thread Pinning: While neural network weights reside on the GPU, the analytical finite queue simulation (
digital_twin/mm1k_env.py) and Poisson-gravity traffic generator (digital_twin/traffic_generator.py) run on the CPU. The training initialization pins PyTorch interop/intra-op threads to use all virtual cores allocated by Colab.
- Go to Google Colab.
- Change the Runtime Type to use a GPU:
- Click Runtime > Change runtime type > Select T4 GPU (or L4/A100 if available) > Click Save.
- Verify the GPU assignment by running this in a cell:
!nvidia-smi
Add this to a notebook cell to mount your Drive so checkpoints aren't lost when your session ends:
from google.colab import drive
drive.mount('/content/drive')Clone your project repository or upload your files to Google Drive, then navigate into the directory:
# Example if using git:
!git clone https://github.com/DanielAgbeni/GARRO schproject
%cd schprojectColab has PyTorch preinstalled, but you must install PyTorch Geometric (PyG) and its dependencies compiled for Colab's specific PyTorch + CUDA version:
import torch
# Automatically detect installed PyTorch and CUDA versions to pull the correct PyG binary wheels
pyg_url = f"https://data.pyg.org/whl/torch-{torch.__version__}.html"
print(f"Installing PyG wheels from: {pyg_url}")
!pip install torch-scatter torch-sparse -f {pyg_url}
!pip install torch-geometric
!pip install gymnasium networkx pyyaml tqdm pandas matplotlib FlaskVerify that PyTorch successfully binds to the GPU device by executing:
import torch
print("GPU Available:", torch.cuda.is_available())
print("Active Device:", torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU")To avoid manual copying and guarantee you don't lose checkpoints if Colab crashes or disconnects, symlink the project's checkpoint folder directly to your Google Drive:
# Create checkpoints folder in Drive
!mkdir -p "/content/drive/MyDrive/garro_checkpoints"
# Delete default local directory (if any) and symlink to Google Drive
!rm -rf /content/schproject/checkpoints
!ln -s "/content/drive/MyDrive/garro_checkpoints" /content/schproject/checkpointsRun the training script using GPU acceleration. Checkpoints will automatically write directly to your Google Drive via the symlink.
-
Start Training from scratch:
!python train_offline.py --topology nsfnet --episodes 10000 -
Resume Training after a disconnect: If Colab times out or you stop the cell, mount your Drive, recreate the symlink (Steps 2 & 5), look in your Drive folder for the latest saved epoch (e.g.
garro_nsfnet_ep3000.pt), and run:!python train_offline.py --topology nsfnet --episodes 10000 --resume checkpoints/garro_nsfnet_ep3000.pt
Note
What happens during Resume?
The agent automatically parses the starting episode index from the filename (e.g., ep3000 -> resumes from episode 3000). It loads the model weights along with the optimizer and gradient scaler states, allowing training to continue seamlessly with correct learning momentum.
Warning
Phase 2 (Live Mininet Emulation) is NOT supported on Google Colab. Mininet relies on loading custom Linux kernel modules (Open vSwitch) and low-level network namespace sandboxes, which are not allowed inside the lightweight Docker containers used by Google Colab. Emulation must always be run on your local Linux machine or WSL2 setup.
Kaggle provides a free NVIDIA Tesla T4 GPU (16 GB VRAM) with 29 GB RAM and up to 12 hours per session β a strong alternative to Google Colab for longer runs (GEANT2 / Fat-Tree). No credit card is required.
Important
Kaggle sessions auto-shutdown after 12 hours. For Fat-Tree (50 000 ep) you must save
a checkpoint and resume in a new session using --checkpoint. Always download your .pt
file before the session ends β use the Output tab in the Kaggle sidebar.
The codebase auto-detects Kaggle's T4 and applies CUDA-optimised overrides:
- CUDA Auto-scaling:
batch_size β 256(or512on T4 Γ2),update_interval β 1024(or2048on T4 Γ2). - AMP
float16: Auto-detected for T4 GPU architecture. - Non-blocking HβD Transfers: Graph state tensors stream asynchronously to the GPU, overlapping CPU simulation with GPU inference.
torch.compileenabled by default: Optimized viacapture_scalar_outputs=Truefor maximum GPU execution speed without graph break stalls.
| Topology | Nodes | ep/s (T4 Γ2) | 10,000 ep ETA |
|---|---|---|---|
| NSFNET | 14 | 10β14 | ~12β15 min |
| GEANT2 | 24 | 5β8 | ~22β30 min |
| Fat-Tree (k=4) | 20 | 3β6 | ~30β45 min |
- Go to kaggle.com and sign in (free account).
- Click + New Notebook.
- In the right sidebar:
- Accelerator β GPU T4 Γ2 β select the dual-GPU option for maximum throughput
- Internet β On
- Persistence β Files only (keeps
/kaggle/working/between sessions)
- Click Save to start the session.
# Cell 1
!git clone https://github.com/DanielAgbeni/GARRO.git /kaggle/working/schproject
%cd /kaggle/working/schproject
!ls -laIf the repo is private, use a Personal Access Token:
!git clone https://YOUR_TOKEN@github.com/DanielAgbeni/GARRO.git /kaggle/working/schproject
Kaggle already ships PyTorch + CUDA. Only install the missing packages:
# Cell 2 β Install project packages and matching PyG CUDA wheels
!pip install -q \
torch-geometric==2.5.3 \
gymnasium==1.2.2 \
networkx==3.6.1 \
numpy==2.4.4 \
matplotlib==3.11.0 \
pyyaml==6.0.3 \
tqdm==4.68.3 \
psutil==7.2.2
import torch
TORCH = torch.__version__.split("+")[0] # e.g. "2.3.1"
CUDA = "cu" + torch.version.cuda.replace(".", "") # e.g. "cu121"
print(f"PyTorch: {TORCH} | CUDA tag: {CUDA}")
!pip install -q \
torch-scatter -f https://data.pyg.org/whl/torch-{TORCH}+{CUDA}.html \
torch-sparse -f https://data.pyg.org/whl/torch-{TORCH}+{CUDA}.html# Cell 3 β Sanity check (dual GPU)
import torch, os, sys
print("CUDA available :", torch.cuda.is_available())
print("GPU count :", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
props = torch.cuda.get_device_properties(i)
print(f" GPU {i} : {props.name} ({props.total_memory/1e9:.1f} GB VRAM)")
sys.path.insert(0, "/kaggle/working/schproject")
print("Python path : OK")Expected output (T4 Γ2):
CUDA available : True
GPU count : 2
GPU 0 : Tesla T4 (15.8 GB VRAM)
GPU 1 : Tesla T4 (15.8 GB VRAM)
# Cell 4 β Configure for T4 Γ2 (compile ON, penalties set per topology)
import yaml, torch
CONFIG_PATH = "/kaggle/working/schproject/config.yaml"
with open(CONFIG_PATH) as f:
cfg = yaml.safe_load(f)
# torch.compile mode="default" + dynamic=True is stable on T4 + PyTorch 2.x
# and gives 10β20% encoder speedup. "reduce-overhead" caused stalls; this does not.
cfg["training"]["compile_model"] = True
# amp_dtype is auto-detected as float16 for T4 β no manual override needed.
# (ppo_agent._autocast_dtype() detects bfloat16 support and falls back to float16)
# Set topology penalty weights (change before each topology run):
cfg["reward_weights"]["hop_weight"] = 0.02 # NSFNET / GEANT2
cfg["reward_weights"]["congestion_weight"] = 1.0 # NSFNET / GEANT2
# Fat-Tree: set 0.05 and 2.0 instead
with open(CONFIG_PATH, "w") as f:
yaml.dump(cfg, f, default_flow_style=False)
print(f"config.yaml patched β compile_model=True, amp_dtype=auto (float16 on T4)")
print(f"GPUs visible to PyTorch: {torch.cuda.device_count()}")Important
With GPU T4 Γ2 the training script automatically:
- Detects both GPUs and wraps encoder + AC-net with
nn.DataParallel - Doubles
batch_sizeβ 512 andupdate_intervalβ 4096 - Applies the linear LR scaling rule (
lr_actorβ 2Γ,lr_criticβ 2Γ) - Prints
[MultiGPU] 2Γ T4 detectedin the banner
No extra flags needed β --no-compile is no longer used.
| Topology | ep/s (single T4) | ep/s (T4 Γ2) | 10,000 ep ETA (Γ2) |
|---|---|---|---|
| NSFNET | 7β10 | 10β14 | ~12β15 min |
| GEANT2 | 3β5 | 5β8 | ~22β30 min |
| Fat-Tree (k=4) | 2β4 | 3β6 | ~30β45 min |
NSFNET (~12β15 min for 10 000 episodes on T4 Γ2):
!cd /kaggle/working/schproject && \
python train_offline.py --topology nsfnet --episodes 10000GEANT2 (~30 min for 20 000 episodes):
!cd /kaggle/working/schproject && \
python train_offline.py --topology geant2 --episodes 20000Fat-Tree (k=4) (~1β1.5 hours for 20 000 episodes):
!cd /kaggle/working/schproject && \
python train_offline.py --topology fat_tree --episodes 20000Tip
Topology-aware penalty weights β update config.yaml β reward_weights
before training each topology to avoid reward scaling bias:
# Wide-area (NSFNET / GEANT2)
cfg["reward_weights"]["hop_weight"] = 0.02
cfg["reward_weights"]["congestion_weight"] = 1.0
# Data-centre (Fat-Tree)
cfg["reward_weights"]["hop_weight"] = 0.05
cfg["reward_weights"]["congestion_weight"] = 2.0# Cell 6 β List all outputs
import os, glob
for f in sorted(glob.glob("/kaggle/working/schproject/checkpoints/*")):
size = os.path.getsize(f) / 1e6
print(f"{os.path.basename(f):50s} {size:.1f} MB")Then click Output in the Kaggle sidebar β download garro_<topology>_final.pt
and training_curve_<topology>.png.
Caution
The session disk is wiped on shutdown if Persistence is off. Always download your checkpoint, or copy it to a Kaggle Dataset for permanent cloud storage.
Upload your saved .pt file as a Kaggle Dataset or re-upload it to the notebook input, then:
# Cell 7 β Resume Fat-Tree from episode 10 000
CHECKPOINT = "/kaggle/working/schproject/checkpoints/garro_fat_tree_ep10000.pt"
!cd /kaggle/working/schproject && \
python train_offline.py \
--topology fat_tree \
--episodes 20000 \
--checkpoint {CHECKPOINT}The script parses the episode index from the filename and resumes the progress bar automatically.
# Cell 8 β Evaluate GARRO vs OSPF / ECMP / Random
CHECKPOINT = "/kaggle/working/schproject/checkpoints/garro_nsfnet_final.pt"
!cd /kaggle/working/schproject && \
python evaluate.py \
--checkpoint {CHECKPOINT} \
--topology nsfnet \
--episodes 500 \
--output-dir evaluation_outputsResults are saved under evaluation_outputs/<run_id>/ as a .csv metrics table
and a .png comparison bar chart.
Warning
Phase 2 (Live Mininet Emulation) is NOT supported on Kaggle. Mininet requires loading custom Linux kernel modules (Open vSwitch) and network namespaces that are blocked in Kaggle's container environment. Phase 2 must be run on a local Linux machine or WSL2 setup.
- Checkpoints: Periodic model weights are saved to
checkpoints/garro_<topology>_ep<N>.pt. - Final Model: The converged weights are saved to
checkpoints/garro_<topology>_final.pt. - Training Curve: A plot of episodic rewards over time is saved to
checkpoints/training_curve_<topology>.png.
During updates, the script outputs the following diagnostic metrics:
- PL (Policy Loss): The surrogate objective of PPO. A stable negative or slightly fluctuating value indicates policy improvement.
- VL (Value Loss): Mean-squared error of the critic. Should trend downwards as the critic learns to accurately estimate state values.
-
Ent (Entropy): Policy diversity. Starts high (~1.6 for
$K=5$ paths) as the agent explores randomly, and should steadily decrease (to ~0.3β0.6) as the agent becomes confident in its routing decisions. -
KL (KL Divergence): Difference between the old and updated policy. PPO clips this; values should stay very low (
$<0.02$ ) to guarantee stable learning.
To evaluate the performance of your trained agent against traditional SDN routing baselines in the Digital Twin, run evaluate.py.
python evaluate.py --checkpoint <path_to_checkpoint> --topology <topology_name> --episodes <num_episodes>- Example:
python evaluate.py \ --checkpoint checkpoints/garro_nsfnet_final.pt \ --topology nsfnet \ --episodes 500
- Compared Baselines:
- OSPF (Open Shortest Path First): A static shortest-path heuristic choosing the path with the minimum delay (Dijkstra).
- ECMP (Equal-Cost Multi-Path): Distributes traffic round-robin across the candidate paths without network utilization awareness.
- Random: Randomly selects path options (defines the lower performance bound).
- Outputs: Each evaluation creates its own folder under
evaluation_outputs/, named with the evaluated checkpoint/model name, topology, episode count, and timestamp. The results are saved aseval_results_<model>_<topology>_ep<episodes>.csvandeval_results_<model>_<topology>_ep<episodes>.pnginside that folder.
Phase 2 runs the DRL agent in a closed loop, routing real traffic demands in an emulated SDN network.
Running Mininet and Open vSwitch (OVS) requires root permissions (sudo) and system-wide packages. They cannot be run inside the Python virtual environment.
- On Ubuntu/Debian:
sudo apt-get update sudo apt-get install mininet openvswitch-switch
- If using WSL2, you must ensure the OVS kernel module or service is started before running:
sudo service openvswitch-switch start
You will need three separate terminal sessions to execute the loop.
Activate the environment and start the OpenFlow controller app. You can use either of the following commands (Option 2 is recommended if the standard command does not work):
Option 1: Standard Command
source garro_env/bin/activate
osken-manager controller/garro_controller.py --observe-linksOption 2: Explicit Python3 Script Command
source garro_env/bin/activate
python3 /usr/bin/osken-manager controller/garro_controller.py --observe-linksLaunch the emulated data plane using system Python.
sudo python topologies/mininet_nsfnet.py(This starts the Mininet prompt mininet> once topology initialization is complete).
Activate the environment and run the deployment loop script pointing to your trained checkpoint file.
source garro_env/bin/activate
python deploy_online.py --checkpoint checkpoints/garro_nsfnet_final.pt --topology nsfnet(The agent will start polling the REST API on port 8080 every 2 seconds, selecting paths, and installing them onto the switches).
Once all three terminal sessions are running, use the Mininet CLI (Terminal B) to generate traffic and verify routing behavior:
Verify that all hosts can reach one another:
mininet> pingallPing from host h1 to host h14 to trigger PPO-driven routing:
mininet> h1 ping h14 -c 10While the ping is running, inspect Terminal C and Terminal A. You will see:
- Terminal C log:
[Deploy] Flow installed: [1, 4, 5, 12, 14] | 10.0.0.1β10.0.0.14 - Terminal A log:
[GARRO] Installed path: [1, 4, 5, 12, 14] for 10.0.0.1 β 10.0.0.14
To inspect the exact OpenFlow rules installed on any switch (e.g. switch s1), run this command in a normal bash shell:
sudo ovs-ofctl -O OpenFlow13 dump-flows s1You will see routing flow rules matching IP source 10.0.0.1 and destination 10.0.0.14 routing packets to the corresponding output ports chosen by the PPO agent.
To run a bandwidth throughput test using iperf:
mininet> h1 iperf -s &
mininet> h14 iperf -c 10.0.0.1 -t 30This generates traffic between h1 and h14 for 30 seconds, forcing the agent to continuously monitor utilization changes and dynamically adjust paths to avoid link congestion.
| Issue | Cause | Fix |
|---|---|---|
AttributeError: module 'os_ken.base.app_manager' has no attribute 'RyuApp' |
legacy Ryu class name conflict | Ensure controller uses app_manager.OSKenApp instead of RyuApp (fixed in repository). |
ModuleNotFoundError: No module named 'os_ken.app.wsgi' |
WSGI module missing/renamed in OS-Ken | Expose APIs using Flask on a background eventlet thread (fixed in repository). |
OVS is not running error in Mininet |
Open vSwitch service inactive | Run sudo service openvswitch-switch start before launching Mininet. |
| Mininet cannot connect to controller | Controller not running or ports bound | Ensure OS-Ken is running in Terminal A first. Check for bound ports: ss -tlnp | grep -E "6633|8080". |
| LLM weight updates fail | .env file does not contain keys |
The agentic layer defaults to standard fallback weights (alpha1..alpha4) if GEMINI_API_KEY is not present, avoiding application crash. |
This project is licensed under the MIT License - see the LICENSE file for details.