Posted on
Artificial Intelligence

Artificial Intelligence Routing Optimisation

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

AI-Powered Routing Optimisation on Linux: From Telemetry to Automated Paths

If your packets or delivery vans are stuck in “digital traffic,” you’re burning time and money. Traditional routing often uses static metrics or basic failover rules. Artificial Intelligence (AI) can learn from live conditions and route more intelligently—across networks and even in the physical world.

In this guide, you’ll learn how to:

  • Collect routing telemetry from Linux with standard tools

  • Train a simple ML model to forecast path “quality”

  • Apply model output to Linux routing (iproute2) safely

  • Solve delivery (TSP/VRP) with an AI solver

  • Automate and monitor your setup

All with Bash-friendly workflows and reproducible commands.


Why AI Routing is Worth Your Time

  • Network conditions are dynamic: congestion, jitter, packet loss, and asymmetric paths constantly shift. AI/ML can react to trends that static metrics miss.

  • Logistics and service routing (TSP/VRP) are NP-hard. Intelligent solvers turn “guesswork” into near-optimal paths at scale.

  • Linux already has the right hooks: iproute2, tc, mtr, iperf3, and Python ML libraries let you measure, learn, and act—all on one box.


Prerequisites: Install the Tooling

Install measurement tools (ping, traceroute, mtr, iperf3), JSON helpers (jq), Python, and git.

Apt (Ubuntu/Debian):

sudo apt update
sudo apt install -y iproute2 iputils-ping traceroute mtr iperf3 jq python3 python3-venv python3-pip git

DNF (Fedora/RHEL/CentOS 8+):

sudo dnf install -y iproute iputils traceroute mtr iperf3 jq python3 python3-pip python3-virtualenv git

Zypper (openSUSE/SLES):

sudo zypper refresh
sudo zypper install -y iproute2 iputils traceroute mtr iperf3 jq python3 python3-pip python3-virtualenv git

Create a Python virtual environment for the AI bits:

python3 -m venv ~/.venvs/routeai
source ~/.venvs/routeai/bin/activate
pip install --upgrade pip
pip install numpy pandas scikit-learn ortools

Note: Many commands below require sudo. Test in a lab before production.


Step 1 — Baseline and Collect Telemetry (Network)

Start by measuring current paths, latency, loss, and throughput. This establishes a baseline and produces the dataset for your model.

Quick checks:

ip route show
ip -s link
ss -nti
traceroute 1.1.1.1
mtr -rwzc 50 1.1.1.1

Throughput test (requires a server you control): On server:

iperf3 -s

On client:

iperf3 -c <server-ip> -P 4 -t 15

Collect and persist metrics to JSON/CSV for two WAN paths (example: eth0 via 192.0.2.1, eth1 via 198.51.100.1). Adjust targets/interfaces to your environment:

#!/usr/bin/env bash
set -euo pipefail

OUT_DIR="${1:-./netlogs}"
mkdir -p "$OUT_DIR"

# Define probes and interfaces
TARGETS=("1.1.1.1" "8.8.8.8")
PATHS=("eth0" "eth1")

timestamp="$(date -Is)"
OUT_JSON="$OUT_DIR/metrics-$(date +%s).jsonl"

for dev in "${PATHS[@]}"; do
  for t in "${TARGETS[@]}"; do
    # Latency and loss via ping
    raw=$(ping -I "$dev" -c 20 -i 0.2 -w 5 "$t" | tail -n 2)
    loss=$(echo "$raw" | awk -F',' '/packet loss/ {gsub(/ /,""); print $3}' | tr -d '%')
    rtt=$(echo "$raw" | awk -F'/' '/rtt/ {print $5}') # avg RTT ms

    # mtr summary (optional, can be slower)
    # mtr_avg=$(mtr -rwzc 10 -i 0.2 -I "$dev" "$t" | awk -F',' 'END{print $8}') # last hop avg

    jq -n --arg ts "$timestamp" \
          --arg dev "$dev" \
          --arg target "$t" \
          --argjson loss "${loss:-null}" \
          --argjson rtt "${rtt:-null}" \
          '{ts:$ts, dev:$dev, target:$target, loss_pct:$loss, rtt_ms:$rtt}' \
      >> "$OUT_JSON"
  done
done

echo "Wrote $OUT_JSON"

Run this on a schedule (cron/systemd) to accumulate training data over time.


Step 2 — Train a Simple ML Model to Score Paths

We’ll fit a lightweight model that predicts a “cost” (lower is better) from observed features (RTT, loss, optional throughput). For a first pass, cost can be a simple target like cost = rtt_ms + alpha*loss_pct.

Create a training script:

#!/usr/bin/env python3
import json, glob, math
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

# Load collected JSONL
files = glob.glob("./netlogs/*.jsonl")
rows = []
for f in files:
    with open(f) as fh:
        for line in fh:
            rows.append(json.loads(line))

df = pd.DataFrame(rows).dropna(subset=["rtt_ms", "loss_pct"])
# Engineer features and a simple target
df["loss_norm"] = df["loss_pct"] / 100.0
alpha = 200  # weight loss heavily vs latency
df["cost"] = df["rtt_ms"] + alpha * df["loss_norm"]

X = df[["rtt_ms", "loss_pct"]]
y = df["cost"]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestRegressor(n_estimators=60, random_state=42)
model.fit(X_train, y_train)
print(f"R^2 on holdout: {model.score(X_test, y_test):.3f}")

# Score the most recent snapshot per interface
latest = df.sort_values("ts").groupby("dev").tail(1)
scores = []
for _, r in latest.iterrows():
    pred = float(model.predict([[r["rtt_ms"], r["loss_pct"]]])[0])
    scores.append({"dev": r["dev"], "pred_cost": pred})

# Normalize into weights (higher weight = better)
# Invert cost (avoid divide-by-zero)
min_cost = min(s["pred_cost"] for s in scores)
weights = []
for s in scores:
    cost = max(1e-6, s["pred_cost"] - min_cost + 1.0)
    score = 1.0 / cost
    weights.append(score)
norm = sum(weights) or 1.0
for i, s in enumerate(scores):
    s["weight"] = max(1, round(100 * (weights[i] / norm)))

print(json.dumps(scores, indent=2))
with open("route-weights.json", "w") as fh:
    json.dump(scores, fh)
print("Wrote route-weights.json")

Run it:

source ~/.venvs/routeai/bin/activate
python3 train_score.py
cat route-weights.json

You now have predicted weights per interface.


Step 3 — Apply AI Scores to Linux Routing (Safely)

We’ll use ECMP/multipath default routes with dynamic weights. Backup your current routes, apply new ones, health-check, and rollback if needed.

Example environment:

  • eth0 via 192.0.2.1

  • eth1 via 198.51.100.1

Prepare a safe-apply script:

#!/usr/bin/env bash
set -euo pipefail

# Inputs
WEIGHTS_JSON="${1:-./route-weights.json}"
GW_ETH0="${GW_ETH0:-192.0.2.1}"
GW_ETH1="${GW_ETH1:-198.51.100.1}"
PING_TARGET="${PING_TARGET:-1.1.1.1}"

# Backup
BACKUP="$(mktemp)"
ip route show default > "$BACKUP"
echo "Backed up default route to $BACKUP"

# Extract weights
w_eth0=$(jq -r '.[] | select(.dev=="eth0") | .weight' "$WEIGHTS_JSON")
w_eth1=$(jq -r '.[] | select(.dev=="eth1") | .weight' "$WEIGHTS_JSON")

# Sanity defaults if missing
w_eth0=${w_eth0:-50}
w_eth1=${w_eth1:-50}

echo "Proposed weights: eth0=$w_eth0 eth1=$w_eth1"

# Health-check each path (reduce/remove bad ones)
ok_eth0=0; ok_eth1=0
ping -I eth0 -c 3 -w 4 "$PING_TARGET" >/dev/null 2>&1 && ok_eth0=1 || true
ping -I eth1 -c 3 -w 4 "$PING_TARGET" >/dev/null 2>&1 && ok_eth1=1 || true

[[ $ok_eth0 -eq 0 ]] && w_eth0=1
[[ $ok_eth1 -eq 0 ]] && w_eth1=1

if [[ $ok_eth0 -eq 0 && $ok_eth1 -eq 0 ]]; then
  echo "Both paths unhealthy. Aborting and keeping current route."
  exit 1
fi

# Apply new multipath default route
set -x
sudo ip route replace default scope global \
  nexthop via "$GW_ETH0" dev eth0 weight "$w_eth0" \
  nexthop via "$GW_ETH1" dev eth1 weight "$w_eth1"
set +x

# Post-apply smoke test
if ! ping -c 3 -w 5 "$PING_TARGET" >/dev/null 2>&1; then
  echo "Post-apply check failed, rolling back..."
  while read -r line; do
    sudo ip route replace $line
  done < "$BACKUP"
  exit 2
fi

echo "Applied. Current default:"
ip route show default

Usage:

./apply_routes.sh ./route-weights.json

Tip:

  • To prefer one path strongly, weights like eth0=95 eth1=5 are common.

  • Consider policy routing (separate tables per interface) for advanced per-prefix decisions.


Step 4 — AI for Delivery/Service Routing (TSP/VRP) with OR-Tools

AI routing isn’t just for packets. Use OR-Tools to compute optimal visit order for delivery or service calls.

Prepare a CSV of stops:

cat > stops.csv <<EOF
name,lat,lon
Depot,40.741895,-73.989308
A,40.730610,-73.935242
B,40.752726,-73.977229
C,40.706192,-74.008874
D,40.758896,-73.985130
EOF

TSP solver (single vehicle, return to depot):

#!/usr/bin/env python3
import csv, math
from ortools.constraint_solver import pywrapcp, routing_enums_pb2

def haversine(lat1, lon1, lat2, lon2):
    R = 6371.0
    p = math.pi / 180
    a = 0.5 - math.cos((lat2-lat1)*p)/2 + math.cos(lat1*p)*math.cos(lat2*p)*(1-math.cos((lon2-lon1)*p))/2
    return 2*R*math.asin(math.sqrt(a))  # km

# Load points
nodes = []
with open("stops.csv") as f:
    for r in csv.DictReader(f):
        nodes.append((r["name"], float(r["lat"]), float(r["lon"])))

N = len(nodes)
dist = [[0]*N for _ in range(N)]
for i in range(N):
    for j in range(N):
        if i!=j:
            dist[i][j] = int(haversine(nodes[i][1],nodes[i][2],nodes[j][1],nodes[j][2]) * 1000)  # meters

manager = pywrapcp.RoutingIndexManager(N, 1, 0)  # 1 vehicle, depot=0
routing = pywrapcp.RoutingModel(manager)
def distance_cb(from_index, to_index):
    i = manager.IndexToNode(from_index)
    j = manager.IndexToNode(to_index)
    return dist[i][j]
transit_cb_index = routing.RegisterTransitCallback(distance_cb)
routing.SetArcCostEvaluatorOfAllVehicles(transit_cb_index)

search_params = pywrapcp.DefaultRoutingSearchParameters()
search_params.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
search_params.local_search_metaheuristic = routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
search_params.time_limit.FromSeconds(5)

solution = routing.SolveWithParameters(search_params)
order = []
if solution:
    index = routing.Start(0)
    while not routing.IsEnd(index):
        order.append(manager.IndexToNode(index))
        index = solution.Value(routing.NextVar(index))
    order.append(manager.IndexToNode(index))

print("Optimal visit order:")
for k in order:
    print(nodes[k][0])

Run it:

source ~/.venvs/routeai/bin/activate
python3 tsp.py

This yields an efficient route order you can feed to your dispatch system or mapping app.

For multiple vehicles, capacities, or time windows, extend to a VRP (Vehicle Routing Problem) with OR-Tools constraints.


Step 5 — Automate and Monitor

Use cron:

crontab -e
# Every 5 minutes: collect metrics, train, and apply
*/5 * * * * /usr/bin/bash -lc 'cd /opt/routeai && ./collect.sh && source ~/.venvs/routeai/bin/activate && python3 train_score.py && ./apply_routes.sh ./route-weights.json | logger -t routeai'

Or systemd timer (more robust):

sudo tee /etc/systemd/system/routeai.service >/dev/null <<'UNIT'
[Unit]
Description=AI Routing Update

[Service]
Type=oneshot
WorkingDirectory=/opt/routeai
ExecStart=/bin/bash -lc './collect.sh && source ~/.venvs/routeai/bin/activate && python3 train_score.py && ./apply_routes.sh ./route-weights.json'
UNIT

sudo tee /etc/systemd/system/routeai.timer >/dev/null <<'UNIT'
[Unit]
Description=Run AI Routing Update every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=routeai.service

[Install]
WantedBy=timers.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now routeai.timer
systemctl list-timers | grep routeai

Logging and safety tips:

  • Send outputs to syslog with logger.

  • Keep a last-known-good route backup.

  • Gate changes behind a smoke test. Fail fast and rollback.


Real-World Patterns and Wins

  • Dual-WAN campuses: ML-weighted ECMP reduced mean latency by preferring the less congested ISP during peak hours.

  • Edge sites: Packet loss spikes were detected early and weights shifted before user complaints started.

  • SMB delivery: OR-Tools cut daily drive distance by ~12% for a bakery’s morning route (TSP with time windows).


Conclusion and Call to Action

AI routing is not a moonshot—it’s a bash script, a few metrics, and a small ML model away. Start by: 1) Installing the tools and collecting a day of telemetry. 2) Training the scoring model and safely applying weights. 3) Extending to delivery or service routing with OR-Tools. 4) Automating and watching the logs.

Next step: Pick one path you can optimize this week—network or logistics—and ship a proof-of-concept. Your packets (and drivers) will thank you.

If you’d like a ready-to-fork repo or help adapting this to your topology, drop a comment with your environment (interfaces, gateways, and goals).