Software Defined Networking

Production engineering guide for software defined networking covering patterns, implementation strategies, and operational best practices.

Software Defined Networking (SDN) decouples the control plane from the data plane in network infrastructure, enabling centralized, programmable management of network behavior. It matters when network policies must adapt rapidly to changing workloads—such as cloud-scale microservices, dynamic service discovery, or multi-tenant environments—where traditional, hardware-centric routing and switching fall short.

Centralized Control and Policy Management

In SDN, network devices (switches, routers, firewalls) forward traffic based on rules installed by a controller. The controller exposes a programmable interface—typically over HTTP or gRPC—to define how traffic flows through the network. This interface is the primary mechanism for setting up and modifying network behavior.

The controller maintains a global view of the network, including topology, device states, and flow tables. A common pattern is for the controller to expose a REST API for managing flows, with endpoints like POST /flows and GET /devices/{id}/flows. Clients use this API to install, modify, and delete forwarding rules.

Installing a Flow Rule

To forward all TCP traffic from subnet 10.0.0.0/24 to a server at 10.0.1.10, a client sends a JSON payload to the controller:

POST /flows
{
  "device": "switch-01",
  "priority": 100,
  "match": {
    "in_port": 1,
    "eth_type": 2048,
    "ip_proto": 6,
    "nw_src": "10.0.0.0/24"
  },
  "actions": [
    {
      "type": "OUTPUT",
      "port": 2
    },
    {
      "type": "SET_FIELD",
      "field": "ipv4_dst",
      "value": "10.0.1.10"
    }
  ]
}

The controller responds with a 201 Created status and an id for the flow. If the device field is missing or invalid, the response includes a 400 Bad Request body:

{
  "error": "device_not_found",
  "message": "Switch 'switch-01' is not registered in the controller",
  "details": {
    "available_switches": [
      "switch-01", "switch-02", "switch-03"
    ]
  }
}

Flow Table Management and Priority Conflicts

Flow tables are ordered by priority. When multiple rules match a packet, the controller selects the rule with the highest priority. A common failure mode occurs when priorities are misaligned: a low-priority rule for all HTTP traffic overrides a high-priority rule for a specific service.

To debug, use the controller’s /flows?device=switch-01 endpoint, which returns all installed flows with their priority, match conditions, and actions. The response includes a last_updated timestamp for each flow, useful for tracking changes.

When a flow conflicts with another, the controller logs a flow_overlap event. The event includes the conflicting flow IDs, matched fields, and the packet that triggered the conflict. This helps identify when a new rule silently overrides an existing one.

Dynamic Topology and Service Discovery

Network topology is not static. SDN controllers discover devices through protocols like LLDP or OpenFlow’s HELLO messages. When a new switch connects, it sends a HELLO message to the controller, which responds with a FEATURES_REPLY message, including supported capabilities.

Handling Device Connectivity Changes

When a switch goes down, the controller updates its view and immediately reprograms the network. The controller triggers a device_down event, which includes the switch’s ID, current flow table, and a list of connected hosts.

To react to connectivity changes, clients use a streaming API over WebSockets or Server-Sent Events (SSE). A client subscribes to device state changes with:

GET /events?types=device_state&devices=switch-01,switch-02

The server responds with a stream of events:

{
  "type": "device_state",
  "device": "switch-01",
  "state": "DOWN",
  "timestamp": "2024-01-15T12:34:56Z",
  "details": {
    "last_seen": "2024-01-15T12:34:50Z",
    "reason": "link_failure",
    "interface": "eth0"
  }
}

Clients use this to trigger actions: rerouting traffic, updating service registries, or triggering health checks.

Programmable Data Plane with OpenFlow

OpenFlow is the de facto standard for communicating between the controller and switches. It defines messages for configuring flow tables, querying device state, and handling packet-in events.

Packet-In Handling

When a switch receives a packet that does not match any flow rule, it sends a PACKET_IN message to the controller. The message includes the packet data, input port, and metadata like VLAN ID and ingress timestamp.

The controller responds with a FLOW_MOD message to install a new rule. For example, when a client sends a GET /service/redis request, the controller installs a rule for all traffic to the Redis server:

{
  "command": "ADD",
  "table_id": 0,
  "priority": 80,
  "match": {
    "eth_type": 2048,
    "ip_proto": 6,
    "ipv4_dst": "192.168.1.10"
  },
  "actions": [
    {
      "type": "OUTPUT",
      "port": 3
    }
  ],
  "idle_timeout": 300,
  "hard_timeout": 1800
}

The idle_timeout and hard_timeout fields are critical: idle_timeout triggers a flow entry’s expiration after no packets match it for the specified time, while hard_timeout expires the flow after the absolute time since creation. A common mistake is confusing the two: a flow with idle_timeout: 300 but no hard_timeout may persist indefinitely, causing stale flows.

Flow Table State and Memory Pressure

Switches have limited memory for flow tables. When the table is full, the controller receives a FLOW_MOD response with a TABLE_FULL status. The controller can then evict older entries using DELETE or MODIFY commands.

To monitor flow table usage, clients query /stats/flow-table?device=switch-01:

{
  "device": "switch-01",
  "table_id": 0,
  "entries": 1024,
  "max_entries": 2048,
  "memory_used": 2150400,
  "memory_total": 4194304,
  "utilization": 0.512
}

A high utilization value indicates memory pressure. If entries exceeds max_entries, the controller triggers a table_full event.

Network Virtualization and Overlay Tunnels

SDN enables logical network overlays over physical underlays. The most common overlay is VXLAN, which encapsulates Ethernet frames in UDP packets. The controller installs rules to handle encapsulation and decapsulation.

Configuring VXLAN Tunnels

To connect two virtual networks across multiple physical switches, the controller sets up VXLAN tunnels. The process involves:

  1. Creating a VXLAN tunnel endpoint (VTEP) on each physical switch.
  2. Installing flow rules for ingress and egress traffic.

A client configures a VXLAN network with a POST /networks request:

{
  "name": "web-frontend",
  "type": "vxlan",
  "vni": 10001,
  "gateway": "10.10.1.1",
  "subnet": "10.10.1.0/24",
  "endpoints": [
    {
      "device": "switch-01",
      "ip": "192.168.1.10"
    },
    {
      "device": "switch-02",
      "ip": "192.168.1.11"
    }
  ]
}

The controller responds with a 201 Created and assigns a network_id. It then installs flow rules on each switch to handle encapsulation and forwarding.

On switch-01, the controller installs:

{
  "device": "switch-01",
  "table_id": 0,
  "priority": 50,
  "match": {
    "in_port": 1,
    "eth_type": 2048,
    "ipv4_src": "10.10.1.0/24"
  },
  "actions": [
    {
      "type": "SET_FIELD",
      "field": "vxlan_vni",
      "value": 10001
    },
    {
      "type": "OUTPUT",
      "port": 4
    }
  ]
}

For egress, it installs a rule to decapsulate VXLAN packets:

{
  "device": "switch-01",
  "table_id": 0,
  "priority": 40,
  "match": {
    "in_port": 4,
    "vxlan_vni": 10001
  },
  "actions": [
    {
      "type": "DECAP",
      "encap_type": "vxlan"
    },
    {
      "type": "OUTPUT",
      "port": 1
    }
  ]
}

Overlay Failure Modes

VXLAN tunnels can fail silently. A common issue is mismatched VNI values: a packet sent with VNI 10001 arrives at a switch expecting VNI 10002. The switch drops the packet, and the controller logs a vxlan_vni_mismatch event.

Another failure mode occurs when a VTEP IP is unreachable. The controller detects this by sending periodic PING messages over the VXLAN tunnel. If a VTEP does not respond within a timeout (default 5 seconds), the controller marks the tunnel as down and reroutes traffic.

When a new VTEP joins, the controller sends a VXLAN_ADD_ENDPOINT message to all switches, instructing them to update their forwarding tables. The message includes the VTEP’s IP and the associated VNI.

End-to-End Network Policy Enforcement

SDN enables fine-grained, policy-based networking. Policies are defined as declarative rules that the controller applies across the network.

Defining and Applying a Network Policy

A network policy defines how traffic is filtered and routed across the network. A client defines a policy for a Kubernetes cluster with:

POST /policies
{
  "name": "microservices-traffic",
  "description": "Enforce traffic between frontend and backend services",
  "rules": [
    {
      "source": "frontend",
      "destination": "backend",
      "protocol": "tcp",
      "port": 8080,
      "action": "forward",
      "priority": 100
    },
    {
      "source": "api-gateway",
      "destination": "database",
      "protocol": "tcp",
      "port": 5432,
      "action": "rate_limit",
      "rate": 1000
    }
  ]
}

The controller evaluates each rule and installs the necessary flow rules on the appropriate switches. It also creates a policy_status resource, which tracks the policy’s state.

Policy Evaluation and Conflict Resolution

The controller evaluates policies in order. If multiple policies apply to the same traffic, it resolves conflicts using a priority system. A rule with priority: 100 takes precedence over one with priority: 50.

When a policy is applied, the controller logs a policy_applied event with the policy ID and a list of devices affected. If a rule fails to install on a device, the controller logs a policy_install_failure event:

{
  "type": "policy_install_failure",
  "policy_id": "microservices-traffic",
  "device": "switch-01",
  "error": "flow_table_full",
  "details": {
    "flow_id": "flow-123",
    "message": "Could not install flow: table full"
  }
}

The controller can then trigger an automatic rollback or alerting.

Integration with Existing Systems

SDN controllers integrate with external systems via standard protocols and formats.

Using REST APIs for Automation

A CI/CD pipeline uses the SDN controller’s REST API to configure network behavior during deployment. After deploying a new version of a service, it runs:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "service": "user-api",
    "version": "v2.1.0",
    "network": "internal",
    "tags": ["prod", "canary"]
  }' \
  http://sdn-controller.local/v1/deployments

The controller responds with a 202 Accepted and a deployment_id. The pipeline polls /deployments/{id} until the status is complete.

Monitoring and Observability

The controller exposes metrics over HTTP. Clients use GET /metrics to retrieve key performance indicators:

{
  "controller": {
    "uptime": 12345678,
    "devices_registered": 42,
    "flows_installed": 1284,
    "events_processed": 45678
  },
  "switches": {
    "switch-01": {
      "flow_table_utilization": 0.72,
      "active_flows": 213,
      "last_seen": "2024-01-15T12:34:56Z"
    },
    "switch-02": {
      "flow_table_utilization": 0.93,
      "active_flows": 301,
      "last_seen": "2024-01-15T12:34:54Z"
    }
  }
}

The flow_table_utilization metric is critical: values above 0.8 indicate potential performance degradation. When a switch’s utilization exceeds 0.9, the controller logs a switch_overloaded event, which includes a list of most-used flow rules.

Error Handling and Recovery

When a controller fails, switches fall back to their local flow tables. The controller can be configured with a backup_controller field in its HELLO message. If the primary controller fails, switches automatically connect to the backup.

If a switch cannot reach any controller, it enters a standalone mode. The controller detects this through heartbeat messages. When a switch comes back online, the controller sends a RESUME message, which includes a list of pending flow modifications.

Common Pitfalls and Sharp Edges

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.