Contents

Cilium Hubble Agent: Real-Time Network Topology Monitoring

Cilium Hubble Agent: Real-Time Network Topology Monitoring

cillium-hubble-agent monitors network link states in real time and exposes the topology via REST and WebSocket APIs. It supports two discovery modes: reading from Linux sysfs directly, or querying Cilium’s Hubble observability layer.

Overview

In containerized and Kubernetes environments, network topology is dynamic — links come up and down as pods are scheduled, interfaces are created, and Cilium endpoints change. This agent tracks that state continuously and makes it queryable and streamable.

Discovery Modes

Linux sysfs Mode

Reads link state directly from /sys/class/net/*/operstate for local interface monitoring.

import os
from pathlib import Path

class SysfsDiscovery:
    NET_PATH = Path("/sys/class/net")

    def get_links(self) -> list[dict]:
        links = []
        for iface in self.NET_PATH.iterdir():
            operstate = (iface / "operstate").read_text().strip()
            carrier = self._read_int(iface / "carrier")
            speed = self._read_int(iface / "speed")
            links.append({
                "name": iface.name,
                "state": operstate,
                "carrier": carrier,
                "speed": speed,
            })
        return links

    def _read_int(self, path: Path) -> int | None:
        try:
            return int(path.read_text().strip())
        except (OSError, ValueError):
            return None

Cilium Hubble Mode

Queries Hubble’s gRPC observer API to discover active flows and derive topology from real traffic.

import grpc
from hubble.proto import observer_pb2, observer_pb2_grpc

class HubbleDiscovery:
    def __init__(self, hubble_addr: str = "localhost:4245"):
        self.channel = grpc.insecure_channel(hubble_addr)
        self.stub = observer_pb2_grpc.ObserverStub(self.channel)

    def stream_flows(self, follow: bool = True):
        req = observer_pb2.GetFlowsRequest(
            follow=follow,
            whitelist=[observer_pb2.FlowFilter(
                verdict=[flow_pb2.Verdict.FORWARDED]
            )]
        )
        for flow in self.stub.GetFlows(req):
            yield {
                "src": flow.flow.source.pod_name,
                "dst": flow.flow.destination.pod_name,
                "protocol": flow.flow.l4.WhichOneof("protocol"),
                "namespace": flow.flow.source.namespace,
                "timestamp": flow.flow.time.ToDatetime().isoformat(),
            }

REST API

from fastapi import FastAPI
from .discovery import SysfsDiscovery, HubbleDiscovery

app = FastAPI(title="Hubble Agent")

@app.get("/topology")
async def get_topology():
    """Return current network topology snapshot."""
    return {"links": agent.get_current_topology()}

@app.get("/links")
async def get_links():
    """Return all monitored link states."""
    return {"links": agent.get_links()}

@app.get("/health")
async def health():
    return {"status": "ok", "mode": agent.discovery_mode}

WebSocket Streaming

Clients can subscribe to live topology updates over WebSocket:

from fastapi import WebSocket
import asyncio

@app.websocket("/ws/topology")
async def topology_stream(websocket: WebSocket):
    await websocket.accept()
    try:
        async for update in agent.topology_updates():
            await websocket.send_json(update)
    except Exception:
        await websocket.close()

Example client:

const ws = new WebSocket("ws://agent:8080/ws/topology");
ws.onmessage = (event) => {
    const update = JSON.parse(event.data);
    graph.updateLink(update.src, update.dst, update.state);
};

Deployment

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: hubble-agent
spec:
  selector:
    matchLabels:
      app: hubble-agent
  template:
    spec:
      hostNetwork: true
      containers:
      - name: agent
        image: hubble-agent:latest
        env:
        - name: DISCOVERY_MODE
          value: "hubble"
        - name: HUBBLE_ADDR
          value: "$(NODE_IP):4245"
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: sys
          mountPath: /sys/class/net
          readOnly: true
      volumes:
      - name: sys
        hostPath:
          path: /sys/class/net

Configuration

# config.yaml
discovery:
  mode: hubble          # or "sysfs"
  hubble_addr: "localhost:4245"
  poll_interval: 5      # seconds (sysfs mode)

api:
  host: "0.0.0.0"
  port: 8080

websocket:
  max_clients: 100
  heartbeat_interval: 30

Conclusion

cillium-hubble-agent provides a lightweight, dual-mode approach to network topology monitoring in Kubernetes. Whether you need low-level sysfs polling or rich Cilium Hubble flow data, the REST and WebSocket APIs make it easy to build real-time visualization dashboards on top.

Source: GitHub