Networking -- Quick Reference
Key Numbers
| Parameter | Value | Notes |
|---|---|---|
| GENEVE overhead | 50 bytes (14 Eth + 20 IP + 8 UDP + 8 GENEVE) | OVN-Kubernetes default overlay |
| VXLAN overhead | 50 bytes | Same as GENEVE |
| MTU (standard) | 1500 | Physical NIC default |
| MTU (jumbo frames) | 9000 | Recommended for storage + overlay |
| Effective MTU (overlay, std) | 1450 (1500 - 50 overhead) | Pod/VM sees this MTU |
| Effective MTU (overlay, jumbo) | 8950 (9000 - 50 overhead) | Pod/VM sees this MTU |
| GENEVE UDP port | 6081 | Must be open between all nodes |
| OVN Northbound DB port | 6641 | Control plane |
| OVN Southbound DB port | 6642 | Control plane |
| Kubernetes API port | 6443 | Must be reachable from all nodes |
| NodePort range | 30000-32767 | Default; configurable |
| Pod CIDR (OpenShift default) | 10.128.0.0/14 | ~262k IPs; /23 per node = 512 pods/node |
| Service CIDR (OpenShift default) | 172.30.0.0/16 | ~65k ClusterIPs |
| MetalLB L2 failover time | 10-30 s | Depends on gratuitous ARP propagation |
| MetalLB BGP convergence | 1-3 s | Depends on BGP timers (hold/keepalive) |
| SR-IOV max VFs per PF | 64-128 (NIC-dependent) | Intel E810: 128 VFs; Mellanox CX-6: 127 |
| SR-IOV latency vs virtio | ~3-5 us vs ~15-30 us (one-way) | SR-IOV = near-native |
| SR-IOV throughput | Line rate (25/100 Gbps) | Bypasses software stack entirely |
| virtio-net throughput | 10-20 Gbps typical | With vhost-net acceleration |
| DPDK throughput | Line rate | Userspace networking, high CPU cost |
| OVN-K Services implementation | OVN load balancers (no kube-proxy) | Native in OVN Southbound DB |
Decision Matrix
| Scenario | Recommended Approach | Notes |
|---|---|---|
| Primary VM NIC (default) | masquerade mode on pod network |
Simple, works with any CNI, live-migratable |
| VM needs pod IP directly | bridge mode on pod network |
No NAT; pod IP = VM IP; sidecar containers cannot share IP |
| High-throughput VM (>10 Gbps) | SR-IOV (sriov mode via Multus) |
Near-native perf; blocks live migration |
| Low-latency trading/HFT | SR-IOV + DPDK inside guest | Requires SR-IOV NIC + DPDK-capable guest driver |
| VLAN-attached VM | Multus + bridge CNI + VLAN ID | NetworkAttachmentDefinition with VLAN tag |
| Multiple NICs per VM | Multus secondary interfaces | Each additional NIC = separate NAD |
| External L4 service (stable IP) | MetalLB LoadBalancer Service | L2 for simple; BGP for redundancy |
| External L7 service (HTTP/S) | OpenShift Route / Ingress | HAProxy-based; TLS termination built-in |
| Internal L4 load balancing | ClusterIP Service | kube-proxy/OVN handles DNAT to backends |
| East-west micro-segmentation | NetworkPolicy | Per-namespace; default-deny recommended |
| Cluster-wide default deny | AdminNetworkPolicy | Cluster-scoped, admin-only |
| MetalLB L2 vs BGP | L2 = simple (no router config); BGP = production (multi-speaker, fast failover) | BGP needs ToR router peering |
| Dedicated migration network | Multus NAD for KubeVirt migration | Separate VLAN + NICs for migration traffic |
| Dedicated storage network | Multus NAD or separate physical NIC | ODF cluster network on dedicated interface |
Essential Commands
| Task | VMware/NSX | OVE (OVN-Kubernetes) | Azure Local (SDN) |
|---|---|---|---|
| List VM IPs | govc vm.ip my-vm |
oc get vmi my-vm -o jsonpath='{.status.interfaces}' |
Get-VMNetworkAdapter -VMName my-vm |
| List pod network | N/A | oc get pods -o wide |
N/A |
| Show node network config | esxcfg-nics -l |
oc get nncp (NodeNetworkConfigurationPolicy) |
Get-NetAdapter -CimSession $node |
| Show network state | N/A | oc get nnce (NodeNetworkConfigurationEnactment) |
Get-NetIPConfiguration |
| List network attachments | Port groups | oc get net-attach-def -A |
Get-VMSwitch |
| Create VLAN network | Add port group | oc apply -f nad-vlan100.yaml |
Add-VMSwitch -NetAdapterName |
| Show OVN topology | N/A | oc exec -n openshift-ovn-kubernetes ovnkube-node-xxx -- ovn-nbctl show |
N/A |
| Show OVS flows | N/A | oc exec -n openshift-ovn-kubernetes ovnkube-node-xxx -- ovs-ofctl dump-flows br-int |
N/A |
| List Services | N/A | oc get svc -A |
N/A |
| Show Service endpoints | N/A | oc get endpoints my-svc |
N/A |
| Show NetworkPolicies | NSX DFW rules | oc get networkpolicy -A |
Get-NetworkControllerAccessControlList |
| MetalLB status | N/A | oc get ipaddresspool -n metallb-system |
N/A |
| MetalLB speaker logs | N/A | oc logs -n metallb-system -l component=speaker |
N/A |
| SR-IOV VF status | N/A | oc get sriovnetworknodestates -n openshift-sriov-network-operator |
N/A |
| SR-IOV policy | N/A | oc get sriovnetworknodepolicy -n openshift-sriov-network-operator |
N/A |
| DNS lookup (in-cluster) | N/A | oc exec debug-pod -- nslookup my-svc.my-ns.svc.cluster.local |
N/A |
| Trace packet path | net-dvs -l |
oc exec ovnkube-node-xxx -- ovn-trace <datapath> '<flow>' |
Test-NetConnection |
| Check connectivity | vmkping |
oc exec debug-pod -- curl -v http://my-svc:8080 |
Test-NetConnection -Port 443 |
| Debug node network | esxcli network |
oc debug node/<node> -- chroot /host ip a |
Get-NetAdapter -CimSession $node |
| NMState bond/VLAN config | N/A | oc apply -f nncp-bond0-vlan100.yaml |
New-NetLbfoTeam |
Architecture at a Glance (OVE/OVN-Kubernetes)
+===============================================================================+
| VM Guest OS |
| eth0: 10.0.2.2/24 (masquerade, mgmt) eth1: 192.168.100.5/24 (SR-IOV) |
| virtio-net VFIO passthrough |
+===============================================================================+
| virt-launcher Pod |
| tap0 ---> linux bridge ---> NAT (iptables DNAT/SNAT) ---> eth0 (pod iface) |
| [no software path for SR-IOV -- direct hardware access via VFIO] |
+===============================================================================+
| Node Network Stack |
| veth pair: pod eth0 <---> br-int (Open vSwitch) |
| OVS bridge br-int handles: |
| - Pod-to-pod switching (local) |
| - GENEVE encap/decap (remote pods) |
| - Service DNAT (OVN load balancer, replaces kube-proxy) |
| - NetworkPolicy ACLs |
+===============================================================================+
| OVN Control Plane |
| Northbound DB (6641): logical switches, routers, ACLs, LBs |
| Southbound DB (6642): compiled flows, chassis bindings |
| ovn-controller (per node): translates SB DB -> OVS OpenFlow rules |
+===============================================================================+
| Physical NIC |
| eno1: GENEVE overlay (pod traffic, UDP 6081) MTU 9000 recommended |
| eno2: SR-IOV PF (VFs allocated to VMs) VLAN trunk to ToR switch |
| Bond0: optional LACP bond for overlay NICs |
+===============================================================================+
| Physical Network (Spine-Leaf) |
| ToR Switch: VLAN trunks, GENEVE transport, BGP peering (MetalLB) |
+===============================================================================+
Network Troubleshooting Quick Checks
1. VM has no network connectivity
# Check pod network interface inside the virt-launcher pod
oc exec virt-launcher-my-vm-xxxxx -- ip a
# Check if OVN port binding exists for this pod
oc exec -n openshift-ovn-kubernetes ovnkube-node-xxx -- ovn-nbctl list Logical_Switch_Port | grep my-vm
# Check CNI events on the pod
oc describe pod virt-launcher-my-vm-xxxxx | grep -A5 Events
2. Service not reachable (ClusterIP or LoadBalancer)
# Check service endpoints are populated (empty = selector mismatch or pods not ready)
oc get endpoints my-svc -n my-ns
# Check OVN load balancer for this service
oc exec -n openshift-ovn-kubernetes ovnkube-node-xxx -- ovn-nbctl list Load_Balancer | grep <cluster-ip>
# Test from inside cluster
oc run debug --rm -it --image=nicolaka/netshoot -- curl -v http://my-svc.my-ns:8080
3. MetalLB external IP not reachable
# Check IPAddressPool has available IPs
oc get ipaddresspool -n metallb-system -o yaml
# Check which speaker owns the IP (L2 mode: only one speaker answers ARP)
oc logs -n metallb-system -l component=speaker | grep "announcing"
# Check ARP on the physical network (from a host on the same L2 segment)
# arping -I eth0 <external-ip>
4. SR-IOV VF not available / VM stuck pending
# Check SriovNetworkNodeState for available VFs on the node
oc get sriovnetworknodestates -n openshift-sriov-network-operator <node> -o yaml
# Check SriovNetworkNodePolicy is applied and VFs are created
oc get sriovnetworknodepolicy -n openshift-sriov-network-operator
# Check node for VF allocation (device plugin)
oc describe node <node> | grep -A5 "openshift.io/sriov"
5. DNS resolution failing inside VM/Pod
# Check CoreDNS pods are running
oc get pods -n openshift-dns
# Test DNS from inside a debug pod
oc run dns-test --rm -it --image=busybox -- nslookup kubernetes.default.svc.cluster.local
# Check CoreDNS logs for errors
oc logs -n openshift-dns -l dns.operator.openshift.io/daemonset-dns=default --tail=30
NetworkAttachmentDefinition Examples
VLAN bridge (L2 access to physical VLAN):
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan100-prod
namespace: production
spec:
config: |
{
"cniVersion": "0.3.1",
"type": "bridge",
"bridge": "br-vlan100",
"vlan": 100,
"ipam": { "type": "static" }
}
SR-IOV network:
apiVersion: sriovnetwork.openshift.io/v1
kind: SriovNetwork
metadata:
name: sriov-storage-net
namespace: openshift-sriov-network-operator
spec:
ipam: '{ "type": "static" }'
networkNamespace: production
resourceName: sriov_storage_vf
vlan: 200
VM using both default + secondary network:
spec:
template:
spec:
networks:
- name: default
pod: {} # Pod network (masquerade)
- name: storage-net
multus:
networkName: sriov-storage-net # SR-IOV secondary
domain:
devices:
interfaces:
- name: default
masquerade: {}
- name: storage-net
sriov: {}