Posted on
Artificial Intelligence

Artificial Intelligence VLAN Management

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

Artificial Intelligence VLAN Management with Bash: Detect, Decide, and Deploy

Your VLANs are multiplying. What started as a neat set of 10 is now 200+, spread across trunks and servers, with odd traffic bursts and “mystery” tags showing up at 3 AM. One mis-tag and a compliance report lights up. You don’t need a whole new SDN stack to tame this—just the right blend of Linux tooling, Bash, and a pinch of machine learning.

In this article you’ll learn how to:

  • Inventory and validate VLAN state in seconds

  • Detect anomalous VLAN behavior with an unsupervised model

  • Apply intent-based VLAN provisioning safely (with dry-runs)

  • Close the loop by notifying your team or auto-remediating

All from the command line, on any mainstream Linux distribution.


Why AI for VLAN Management?

  • Scale and churn: VLAN counts grow with microservices, VMs, and multi-tenant hosts. Manual tracking breaks down.

  • Drift and risk: Trunks accrete tags. Orphaned VLANs and wrong pvids silently increase blast radius.

  • Signal in noise: Traffic patterns vary by time and tenant. Unsupervised ML spots unusual VLAN behavior faster than eyeballing counters.

  • Bash-first: You can capture, model, and act with lightweight scripts and familiar tools—no vendor lock-in.


Prerequisites and Installation

You’ll need:

  • iproute2 (usually preinstalled: ip, bridge)

  • lldpd (optional but handy)

  • jq (JSON parsing)

  • tshark (Wireshark CLI) for VLAN-aware capture

  • Python 3 + pip for a tiny ML helper (scikit-learn, pandas)

Install on your distro:

  • Debian/Ubuntu:
sudo apt update
sudo apt install -y lldpd jq tshark python3 python3-pip
  • Fedora/RHEL/CentOS Stream:
sudo dnf install -y lldpd jq wireshark-cli python3 python3-pip
  • openSUSE/SLE:
sudo zypper install -y lldpd jq wireshark-cli python3 python3-pip

Create a virtual environment for Python bits:

python3 -m venv ~/venvs/ai-vlan
source ~/venvs/ai-vlan/bin/activate
pip install -U pip pandas scikit-learn

Note: Packet capture may require root. For non-root capture:

  • On Debian/Ubuntu: sudo dpkg-reconfigure wireshark-common then add your user to wireshark.

  • Or set capabilities: sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' $(which dumpcap)


1) Inventory and Validate VLAN State

Start by creating a current, machine-readable map of VLANs per interface. The bridge command can emit JSON we’ll slice with jq.

Save as vlan_inventory.sh:

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

OUT_CSV=${1:-vlan_inventory.csv}
OUT_JSON=${2:-vlan_inventory.json}

# Requires: iproute2 (bridge), jq
bridge -json vlan show | tee "$OUT_JSON" \
| jq -r '
  ["ifname","vid","is_pvid","is_egress_untagged","state"],
  (.. | objects | select(has("ifname") and has("vlans")) | .ifname as $if |
     .vlans[]? | [ $if, .vlan, ( .pvid // false), ( .egressUntagged // false), ( .state // "unknown") ])
  | @csv' \
> "$OUT_CSV"

echo "Wrote $OUT_CSV and $OUT_JSON"

Run it:

bash vlan_inventory.sh
column -s, -t vlan_inventory.csv | less -S

Tip: Check for drift (e.g., unexpected VLANs on trunk ports), mismatched pvids, and untagged settings that don’t match your standards.

Optional LLDP peek (helps correlate neighbors and expected VLANs):

sudo systemctl enable --now lldpd
sudo lldpcli show neighbors

2) Detect Anomalous VLAN Behavior with Unsupervised ML

We’ll stream VLAN-tagged traffic, compute simple per-VLAN features, and feed them into an Isolation Forest model. No labels needed—great for catching spikes, scans, or leakage between segments.

Collector: vlan_features.sh

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

IFACE=${1:?Usage: $0 <iface> [duration_sec]}
DUR=${2:-300}  # seconds
OUT=${3:-features.csv}

# Header
echo "bucket_start,bucket_end,vlan,pkts,bytes,uniq_src,uniq_dst" > "$OUT"

# Stream and aggregate to 60s buckets
# Fields: time, vlan.id, frame.len, eth.src, eth.dst
sudo timeout "$DUR" tshark -i "$IFACE" -l -T fields \
  -e frame.time_epoch -e vlan.id -e frame.len -e eth.src -e eth.dst \
  -Y "vlan" 2>/dev/null \
| awk -F'\t' '
BEGIN { bucket=0 }
{
  t=$1+0; vid=$2; len=$3+0; s=$4; d=$5;
  if (vid == "" || vid ~ /[A-Za-z]/) next;    # skip empty/bad
  b=int(t/60)*60;                              # 60s bucket
  key=b","(b+59)","vid
  pkts[key]++; bytes[key]+=len;
  src[key","s]=1; dst[key","d]=1;
  buckets[key]=1;
}
END {
  for (k in buckets) {
    # Count unique src/dst per key
    us=0; ud=0;
    for (x in src) if (index(x, k",")==1) us++;
    for (y in dst) if (index(y, k",")==1) ud++;
    split(k, f, ",");
    printf "%s,%s,%s,%d,%d,%d,%d\n", f[1], f[2], f[3], pkts[k]+0, bytes[k]+0, us, ud;
  }
}' >> "$OUT"

echo "Wrote $OUT"

Model: anomaly_iforest.py

#!/usr/bin/env python3
import sys, json
import pandas as pd
from sklearn.ensemble import IsolationForest

import argparse
p = argparse.ArgumentParser()
p.add_argument("--csv", required=True)
p.add_argument("--contamination", type=float, default=0.05, help="Expected outlier fraction")
p.add_argument("--seed", type=int, default=42)
args = p.parse_args()

df = pd.read_csv(args.csv)
if df.empty:
    print(json.dumps({"anomalies": [], "note":"no data"}))
    sys.exit(0)

features = df[["pkts","bytes","uniq_src","uniq_dst"]].fillna(0)
model = IsolationForest(contamination=args.contamination, random_state=args.seed)
df["pred"] = model.fit_predict(features)      # -1 = anomaly
df["score"] = model.decision_function(features)

anom = df[df["pred"] == -1].copy()
# Summarize by VLAN across buckets for a simpler alert
summary = (anom.groupby("vlan")
  .agg(buckets=("vlan","count"),
       worst_score=("score","min"),
       pkts=("pkts","sum"),
       bytes=("bytes","sum"))
  .reset_index()
  .sort_values("worst_score"))

print(json.dumps({"anomalies": summary.to_dict(orient="records")}, indent=2))

Wrapper: detect_anomalies.sh

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

IFACE=${1:-eth0}
DUR=${2:-300}
TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT

bash vlan_features.sh "$IFACE" "$DUR" "$TMP/features.csv" >/dev/null
source ~/venvs/ai-vlan/bin/activate
python3 anomaly_iforest.py --csv "$TMP/features.csv" > "$TMP/out.json"
cat "$TMP/out.json"

# Optional: send to a webhook (Slack example)
if [[ -n "${SLACK_WEBHOOK_URL:-}" ]]; then
  text="AI VLAN anomalies on $(hostname): $(cat "$TMP/out.json")"
  curl -s -X POST -H 'Content-type: application/json' \
    --data "$(jq -n --arg t "$text" '{text:$t}')" \
    "$SLACK_WEBHOOK_URL" >/dev/null || true
fi

Run a quick test window:

bash detect_anomalies.sh eth0 120

Schedule every 5 minutes:

crontab -e
*/5 * * * * /path/to/detect_anomalies.sh eth0 300 >> /var/log/vlan-ai.log 2>&1

What to look for:

  • VLANs with sudden spikes in packets/bytes

  • Unusually high unique MAC counts (scans, flooding, misconfig)

  • VLANs appearing on unexpected interfaces (combine with the inventory)


3) Intent-Based VLAN Provisioning with Dry-Run Safety

Codify desired VLANs, then have Bash reconcile the state. We’ll keep it simple, JSON in, ip/bridge out.

Example intent: intent.json

{
  "interfaces": [
    {
      "parent": "eth0",
      "vlans": [
        {"id": 10, "name": "users", "ipv4": "192.0.2.1/24", "mtu": 1500, "bridge": "br0"},
        {"id": 20, "name": "voice", "ipv4": null,            "mtu": 1500}
      ]
    }
  ]
}

Apply script: apply_intent.sh

#!/usr/bin/env bash
set -euo pipefail
INTENT=${1:?Usage: $0 intent.json}
DRY_RUN=${DRY_RUN:-1}  # set to 0 to apply

apply() {
  echo "+ $*"
  if [[ "${DRY_RUN}" -eq 0 ]]; then
    eval "$@"
  fi
}

# Ensure bridge exists if referenced
for br in $(jq -r '..|objects|select(has("bridge"))|.bridge' "$INTENT" | sort -u); do
  if [[ "$br" != "null" ]]; then
    if ! ip link show "$br" &>/dev/null; then
      apply "ip link add name $br type bridge"
      apply "ip link set $br up"
    fi
  fi
done

# Reconcile VLANs
len=$(jq '.interfaces|length' "$INTENT")
for ((i=0;i<len;i++)); do
  PARENT=$(jq -r ".interfaces[$i].parent" "$INTENT")
  vlen=$(jq ".interfaces[$i].vlans|length" "$INTENT")
  for ((j=0;j<vlen;j++)); do
    VID=$(jq -r ".interfaces[$i].vlans[$j].id" "$INTENT")
    NAME=$(jq -r ".interfaces[$i].vlans[$j].name" "$INTENT")
    IPV4=$(jq -r ".interfaces[$i].vlans[$j].ipv4" "$INTENT")
    MTU=$(jq -r ".interfaces[$i].vlans[$j].mtu" "$INTENT")
    BR=$(jq -r ".interfaces[$i].vlans[$j].bridge" "$INTENT")

    VIF="${PARENT}.${VID}"

    if ip -d link show "$VIF" &>/dev/null; then
      echo "VIF exists: $VIF"
    else
      apply "ip link add link $PARENT name $VIF type vlan id $VID"
    fi

    if [[ "$MTU" != "null" ]]; then
      apply "ip link set dev $VIF mtu $MTU"
    fi

    apply "ip link set dev $VIF up"

    if [[ "$IPV4" != "null" ]]; then
      # avoid duplicate addresses
      if ! ip addr show dev "$VIF" | grep -q "$IPV4"; then
        apply "ip addr add $IPV4 dev $VIF"
      fi
    fi

    if [[ "$BR" != "null" ]]; then
      # ensure master assignment
      if ! bridge link show dev "$VIF" | grep -q "master $BR"; then
        apply "ip link set dev $VIF master $BR"
      fi
    fi
  done
done

echo "Done. DRY_RUN=${DRY_RUN} (set DRY_RUN=0 to enforce)."

Try a dry run:

DRY_RUN=1 bash apply_intent.sh intent.json

Then apply:

sudo DRY_RUN=0 bash apply_intent.sh intent.json

Pro tip:

  • Preflight check for collisions by diffing vlan_inventory.json against intent.json.

  • Store intent.json in Git and run apply_intent.sh in CI after a policy check.


4) Close the Loop: Notify and (Carefully) Auto-Remediate

Turn insights into action. When the anomaly detector flags a VLAN on an unexpected trunk, you might:

  • Notify your chat room with a compact summary and links to runbooks

  • Remove the offending tag from a trunk (only if guardrails pass)

  • Drop a temporary iptables/nft rule for a noisy VLAN

Example: auto-remove a rogue VLAN from a given trunk if it’s not in your intent (use with caution; dry-run first).

auto_remediate.sh

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

TRUNK=${1:?Usage: $0 <trunk_if>}
INTENT=${2:-intent.json}
DRY_RUN=${DRY_RUN:-1}

# VLANs permitted on this trunk per intent
ALLOW=$(jq -r --arg if "$TRUNK" '
  .interfaces[]? | select(.parent==$if) | .vlans[]?.id' "$INTENT" | sort -n | tr '\n' ' ')
echo "Allowed VLANs on $TRUNK: $ALLOW"

# VLANs currently present
CURRENT=$(bridge -json vlan show dev "$TRUNK" \
  | jq -r '.[0].vlans[]?.vlan' | sort -n | tr '\n' ' ')
echo "Current VLANs on $TRUNK: $CURRENT"

# Compute rogue set
ROGUE=$(comm -13 <(echo "$ALLOW" | tr ' ' '\n') <(echo "$CURRENT" | tr ' ' '\n') | tr '\n' ' ')
if [[ -z "$ROGUE" ]]; then
  echo "No rogue VLANs found."
  exit 0
fi

for vid in $ROGUE; do
  echo "Rogue VLAN $vid on $TRUNK"
  echo "+ bridge vlan del dev $TRUNK vid $vid"
  if [[ "$DRY_RUN" -eq 0 ]]; then
    sudo bridge vlan del dev "$TRUNK" vid "$vid" || true
  fi
done

Run it in dry-run mode first:

DRY_RUN=1 bash auto_remediate.sh eth0

Tie it to alerts: call auto_remediate.sh only if the anomaly JSON also shows the VLAN is not permitted by intent and after human approval (e.g., require a “/approve” in ChatOps).


Real-World Usage Patterns

  • Brownfield servers: Baseline all trunks with vlan_inventory.sh, compare to a CSV of “expected” VLANs, fix drift gradually.

  • Host-based segmentation: Use apply_intent.sh to ensure every host gets the same user/voice/storage VLANs with consistent MTU and bridge membership.

  • Nightly watch: detect_anomalies.sh catches VLANs with midnight scan patterns or data-exfil bursts.

  • Change windows: Dry-run intent, produce a diff, and post it in Slack for peer review before applying.


Conclusion and Next Steps

You don’t need a massive platform to get smart about VLANs. With a handful of Linux tools and a lightweight ML step, you can:

  • Keep accurate, auditable inventory

  • Spot abnormal VLAN behavior fast

  • Apply consistent, versioned intent safely

  • Automate the boring and risky bits, under your control

Next steps:

  • Put these scripts in a Git repo and wire them into CI

  • Add a policy check that fails on disallowed VLAN IDs or untagged trunk ports

  • Expand features (e.g., per-VLAN flow entropy) to improve anomaly signal

  • Export your features to Prometheus/Grafana for ongoing visibility

Have a cool improvement or a tricky VLAN story? Share it with the community—and happy automating!