x386.org

KVM Virtualization (Networking)

Advanced KVM networking configurations

0. Specs


0.0. Definition

KVM Virtualization Tutorial 2 for Debian and Ubuntu Server.

Please refer to the KVM Virtualization Beginner tutorial before reading this one.

This tutorial focuses on KVM networking configurations.

0.1. Infrastructure

  • Server (Host): Debian (12/13) or Ubuntu (24.04/26.04) Server
  • IP: 192.168.1.121
  • Name: elma
  • NIC1: enp3s0
  • NIC2: enx00e04c534458 (USB network adapter)
  • Network1: 192.168.1.0/24 (internet modem/router, first interface)
  • Network2: 10.1.1.0/24 (external switch, second interface)
  • Workstation: Debian 13 or Ubuntu 24.04 LTS Desktop

0.2. Resources

  • ISBN: 978-1-78829-467-6 KVM Virtualization Cookbook by Konstantin Ivanov
  • ISBN: 978-1-83882-871-4 Mastering KVM Virtualization 2nd Ed. by Vedran Dakic, Humble Devassy Chirammal, Prasad Mukhedkar, Anil Vettathu


1. KVM Networks - Configuration Commands


While numerous variations exist, KVM supports three basic network types: - Bridged: VMs appear as physical devices on the network - NAT: VMs share host's IP with network address translation - Isolated: VMs communicate only with each other and host

1.1. Active Networks

List KVM Networks:

virsh net-list

Example output (after Tutorial 1 bridge configuration):

 Name           State    Autostart   Persistent
-------------------------------------------------
 host-bridge    active   yes         yes

Display detailed network information:

virsh net-info NETWORKNAME
virsh net-info host-bridge

Example output:

Name:           host-bridge
UUID:           a67dfcef-86e9-4e4c-832f-bc14443da475
Active:         yes
Persistent:     yes
Autostart:      yes
Bridge:         br0

Display network configuration as XML:

virsh net-dumpxml NETWORKNAME
virsh net-dumpxml host-bridge

Example output:

<network>
  <name>host-bridge</name>
  <uuid>a67dfcef-86e9-4e4c-832f-bc14443da475</uuid>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>

1.2. Adding a Network

To add a network, create an XML configuration file and define it:

virsh net-define XMLFILE

Example: Create a second bridge on the second interface.

First, create the bridge on the host system.

Ubuntu Bridge Configuration

Edit Netplan configuration:

sudo nano /etc/netplan/01-netcfg.yaml

Replace content with (adjust interface names and IPs):

network:
  ethernets:
    enp3s0:
      dhcp4: false
      dhcp6: false
    enx00e04c534458:
      dhcp4: false
      dhcp6: false
  bridges:
    br0:
      interfaces: [ enp3s0 ]
      addresses: [192.168.1.121/24]
      routes:
      - to: default
        via: 192.168.1.1
      mtu: 1500
      nameservers:
        addresses: 
        - 8.8.8.8
        - 8.8.4.4
      parameters:
        stp: true
        forward-delay: 4
      dhcp4: false
      dhcp6: false
    br1:
      interfaces: [ enx00e04c534458 ]
      addresses: [10.1.1.1/24]
      routes:
      - to: 10.1.1.0/24
        via: 10.1.1.1
      mtu: 1500
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]
      dhcp4: false
      dhcp6: false
  version: 2

Apply configuration:

sudo netplan apply

Debian Bridge Configuration

Edit network interfaces file:

sudo nano /etc/network/interfaces

Replace content with (adjust interface names and IPs):

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
# The primary network interface
auto enp3s0
#make sure we don't get addresses on our raw device
iface enp3s0 inet manual
#set up bridge and give it a static ip
auto br0
iface br0 inet static
        address 192.168.1.121
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        bridge_ports enp3s0
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        dns-nameservers 8.8.8.8
auto br1
iface br1 inet static
        address 10.1.1.1
        netmask 255.255.255.0
        network 10.1.1.0
        broadcast 10.1.1.255
        bridge_ports enx00e04c534458
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0

Apply configuration (SSH may disconnect):

sudo systemctl restart networking.service

Add Bridge to KVM

Create XML configuration for the second bridge:

sudo nano host-bridge2.xml

Fill as below:

<network>
  <name>host-bridge2</name>
  <uuid>c723a80b-d496-460e-9235-9eced7b218cf</uuid>
  <forward mode='bridge'/>
  <bridge name='br1'/>
</network>

Note: Generate a unique UUID with uuidgen if needed.

Define, start, and enable autostart:

virsh net-define host-bridge2.xml
virsh net-start host-bridge2
virsh net-autostart host-bridge2

Now you have two bridges: - br0 for 192.168.1.0/24 network - br1 for 10.1.1.0/24 network

1.3. Stopping and Removing KVM Networks

Stop a KVM Network:

virsh net-destroy NETWORKNAME
virsh net-destroy host-bridge2

Disable autostart:

virsh net-autostart NETWORKNAME --disable
virsh net-autostart host-bridge2 --disable

Remove network definition:

virsh net-undefine NETWORKNAME
virsh net-undefine host-bridge2


2. KVM Networks - Network Types


When creating KVM network XML files, use unique UUID and MAC values for each network.

Generate a random UUID:

uuidgen

Generate a random MAC address (or use online tools like Browserling Random MAC Generator).

2.1. Bridged Networks

Bridged networks connect VMs directly to the host's physical network. VMs appear as separate devices on the same network segment as the host.

Use cases: - Public-facing servers - Services requiring direct network access - Environments with existing DHCP infrastructure

Requirements: 1. Create a bridge in the host's network configuration 2. Define the bridge in KVM via XML

Example XML configuration:

<network>
  <name>host-bridge2</name>
  <uuid>c723a80b-d496-460e-9235-9eced7b218cf</uuid>
  <forward mode='bridge'/>
  <bridge name='br1'/>
</network>

Customization: - Replace host-bridge2 with your network name - Replace UUID with a generated value - Replace br1 with your actual bridge interface name

Network integration: - VMs receive IPs from the same DHCP server as the host - VMs are directly accessible from the network - No NAT translation occurs

2.2. NAT Network

NAT (Network Address Translation) networks allow VMs to access external networks while remaining hidden behind the host's IP address.

Use cases: - Development and testing environments - VMs requiring internet access but not public exposure - Security-focused deployments

Example XML configuration:

<network>
  <name>nat</name>
  <uuid>d589efd6-7d61-4f92-976b-bde62956cca7</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='brnat' stp='on' delay='0'/>
  <mac address='4a:c3:6a:72:c2:30'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.101' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Customization: - Replace nat with your network name - Replace UUID with a generated value - Replace brnat with your preferred bridge name - Replace MAC address with a generated value - Adjust IP subnet and DHCP range as needed

Network behavior: - VMs can initiate connections to external networks - External hosts cannot initiate connections to VMs - Port forwarding can be configured for specific services - Built-in DHCP server provides IP addresses

2.3. Isolated Network

Isolated networks create completely private segments where VMs can communicate only with each other and the host.

Use cases: - Database backends - Internal service communication - Security-sensitive applications - Testing environments requiring network isolation

Example XML configuration:

<network>
  <name>isolated</name>
  <uuid>a67bbbaf-81e9-4e4c-832f-bc14443da475</uuid>
  <bridge name='brisolated' stp='on' delay='0'/>
  <mac address='4a:c3:6a:72:c2:26'/>
  <domain name='myisolateddomain'/>
  <ip address='192.168.20.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.20.101' end='192.168.20.200'/>
    </dhcp>
  </ip>
</network>

Customization: - Replace isolated with your network name - Replace UUID with a generated value - Replace brisolated with your preferred bridge name - Replace MAC address with a generated value - Adjust IP subnet and DHCP range as needed - Set domain name for internal DNS

Security architecture example:

Internet ── [Web Server (dual NIC)] ── [Database Server]
             bridged:192.168.1.x/24    isolated:192.168.20.x/24

Implementation: 1. Web server: One interface in bridged network, one in isolated network 2. Database server: Only isolated network interface 3. Result: Database accessible only via web server

Network characteristics: - No external network access - Built-in DHCP server - Internal DNS resolution via domain name - Complete isolation from external traffic


3. Case Study A: Bridged and Isolated Networks Together


3.1. Specifications

  • Network1: Bridged network on 192.168.1.0/24 (existing)
  • Network2: Isolated network on 192.168.20.0/24 (to create)
  • VM1: Two network interfaces
  • Interface 1: Network1 (bridged)
  • Interface 2: Network2 (isolated)
  • VM2: One network interface
  • Interface: Network2 (isolated)

Architecture: - VM1: Accessible from all network devices (via Network1) - VM2: Accessible only from VM1 (via Network2) - VM1 acts as a gateway between the two networks

3.2. Create the Isolated Network

Create XML configuration file:

nano isolated.xml

Fill as below:

<network>
  <name>isolated</name>
  <uuid>a67bbbaf-81e9-4e4c-832f-bc14443da475</uuid>
  <bridge name='brisolated' stp='on' delay='0'/>
  <mac address='4a:c3:6a:72:c2:26'/>
  <domain name='myisolateddomain'/>
  <ip address='192.168.20.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.20.101' end='192.168.20.200'/>
    </dhcp>
  </ip>
</network>

Define and activate the network:

virsh net-define isolated.xml
virsh net-start isolated
virsh net-autostart isolated

Verify network creation:

virsh net-list --all

3.3. Create VMs with Dual Network Configuration

Create VM1 (dual-homed):

sudo virt-install --name vm1 \
    --connect qemu:///system  --virt-type kvm \
    --memory 1024 --vcpus 1 \
    --disk /srv/kvm/vm1.qcow2,format=qcow2,size=10 \
    --cdrom /srv/isos/ubuntu-24.04.2-live-server-amd64.iso  \
    --network bridge=br0 \
    --network bridge=brisolated \
    --graphics vnc,port=5901,listen=0.0.0.0 \
    --os-variant ubuntu24.04 \
    --noautoconsole

Create VM2 (isolated):

sudo virt-install --name vm2 \
    --connect qemu:///system  --virt-type kvm \
    --memory 1024 --vcpus 1 \
    --disk /srv/kvm/vm2.qcow2,format=qcow2,size=10 \
    --cdrom /srv/isos/ubuntu-24.04.2-live-server-amd64.iso  \
    --network bridge=brisolated \
    --graphics vnc,port=5902,listen=0.0.0.0 \
    --os-variant ubuntu24.04 \
    --noautoconsole

Note for Debian 12 hosts: Replace --os-variant ubuntu24.04 with --os-variant ubuntu22.04.

Connect to VMs from your workstation to complete installation:

3.4. Network Configuration Considerations

Isolated Network Limitations: - VM2 cannot access external networks (including internet) - VM2 cannot receive updates or install packages directly - VM1 can access both networks and act as a gateway

You can install Squid proxy on the host to provide internet access for isolated VMs.


4. Case Study B: Separating Host and VM Access with 2 NICs


Separating host and VM network traffic is a recommended practice for improved security, performance, and management. We'll dedicate one interface for host access and another for VM traffic.

4.1. Specifications

  • Network: 192.168.1.0/24 (single subnet)
  • Host Interfaces:
  • NIC1 (enp3s0): VM traffic via bridge (192.168.1.121)
  • NIC2 (enx00e04c534458): Host management (192.168.1.122)
  • VM Configuration: Single interface on bridged network

Benefits: - Isolate host management traffic from VM traffic - Prevent VM network issues from affecting host access - Simplified firewall rules and monitoring - Better performance isolation

4.2. Host Network Configuration

Configure the server's network interfaces before KVM setup.

Ubuntu Network Configuration

Edit Netplan configuration:

sudo nano /etc/netplan/01-netcfg.yaml

Change as below:

network:
  ethernets:
    enp3s0:
      dhcp4: false
      dhcp6: false
    enx00e04c534458:
      addresses: [192.168.1.122/24]
      routes:
      - to: 192.168.1.0/24
        via: 192.168.1.1
      nameservers:
        addresses: 
        - 8.8.8.8
        - 8.8.4.4
  bridges:
    br0:
      interfaces: [ enp3s0 ]
      addresses: [192.168.1.121/24]
      routes:
      - to: default
        via: 192.168.1.1
      mtu: 1500
      nameservers:
        addresses: 
        - 8.8.8.8
        - 8.8.4.4
      dhcp4: false
      dhcp6: false
  version: 2

Apply configuration and reboot:

sudo netplan apply
sudo reboot

Debian Network Configuration

Edit network interfaces file:

sudo nano /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback

# VM traffic interface (bridged)
auto enp3s0
iface enp3s0 inet manual

# Bridge for VMs
auto br0
iface br0 inet static
        address 192.168.1.121
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        bridge_ports enp3s0
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0
        dns-nameservers 8.8.8.8

# Host management interface
auto enx00e04c534458
iface enx00e04c534458 inet static
        address 192.168.1.122
        netmask 255.255.255.0
        network 192.168.1.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        dns-nameservers 8.8.8.8

Apply configuration (SSH may disconnect):

sudo systemctl restart networking.service

Note: You may need to reboot because of the previous network configurations may cause instability.

Network Verification:

ip addr show br0
ip addr show enx00e04c534458
ping -c 3 192.168.1.1

4.3. KVM Network Configuration

Skip this step if host-bridge already exists. Define the bridged network in KVM:

Create XML configuration:

nano host-bridge.xml

Fill as below:

<network>
  <name>host-bridge</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>

Define and activate network:

virsh net-define host-bridge.xml
virsh net-start host-bridge
virsh net-autostart host-bridge

Verify network creation:

virsh net-list --all
virsh net-info host-bridge

4.4. Create VM on the Bridged Network

Create a VM using the bridged interface:

sudo virt-install --name vm3 \
    --connect qemu:///system  --virt-type kvm \
    --memory 1024 --vcpus 1 \
    --disk /srv/kvm/vm3.qcow2,format=qcow2,size=10 \
    --cdrom /srv/isos/ubuntu-24.04.2-live-server-amd64.iso  \
    --network bridge=br0 \
    --graphics vnc,port=5901,listen=0.0.0.0 \
    --os-variant ubuntu22.04 \
    --noautoconsole

Connect to VM from your workstation:

virt-viewer --connect qemu+ssh://exforge@elma/system vm3

Network Verification: 1. Host should be accessible at 192.168.1.122 2. VM should obtain an IP from 192.168.1.0/24 range 3. Both should have internet access via 192.168.1.1

Firewall Considerations: Consider implementing firewall rules to: - Restrict host management interface access - Separate VM traffic rules - Monitor traffic patterns


5. Case Study C: NAT KVM Network


We will create a VM, in a NAT network.

5.1. Specifications

Create a VM within a NAT (Network Address Translation) network for enhanced security and isolation.

Server Configuration: - Interface 1 (enp3s0): Bridged mode for VMs (as configured in Section 4) - Interface 2 (enx00e04c534458): Standard mode for host management - Additional NAT network for isolated VMs

VM Configuration: - Name: vmn (VM-NAT) - Single interface connected to NAT network - Outbound internet access via NAT - Inbound connections blocked (except port forwarding)

5.2. Host Network Configuration

No changes required if you completed Section 4.2. Verify existing configuration:

ip addr show br0
ip addr show enx00e04c534458

5.3. KVM NAT Network Configuration

Create XML configuration file:

nano nat.xml

Fill as below:

<network>
  <name>nat</name>
  <uuid>d589efd6-7d61-4f92-976b-bde62956cca7</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='brnat' stp='on' delay='0'/>
  <mac address='4a:c3:6a:72:c2:30'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.101' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Important: Generate unique values: - UUID: uuidgen - MAC address: Use a random generator or openssl rand -hex 6 | sed 's/\(..\)/\1:/g; s/.$//'

Define and activate the NAT network:

virsh net-define nat.xml
virsh net-start nat
virsh net-autostart nat

Verify network creation:

virsh net-list --all
virsh net-info nat
virsh net-dumpxml nat

5.4. Create VM on NAT Network

Create the NAT-connected VM:

sudo virt-install --name vmn \
    --connect qemu:///system  --virt-type kvm \
    --memory 1024 --vcpus 1 \
    --disk /srv/kvm/vmn.qcow2,format=qcow2,size=10 \
    --cdrom /srv/isos/ubuntu-24.04.2-live-server-amd64.iso  \
    --network bridge=brnat \
    --graphics vnc,port=5902,listen=0.0.0.0 \
    --os-variant ubuntu24.04 \
    --noautoconsole

Note: For Debian 12 hosts, use --os-variant ubuntu22.04.

5.5. NAT Network Behavior

Outbound Access (VM → External): - VM can initiate connections to external networks - Source IP translated to host's IP (192.168.1.121) - Source ports mapped to 1024-65535 range

Inbound Access (External → VM): - External devices cannot initiate connections to VM - Port forwarding required for specific services - VM remains hidden behind NAT

Internal Network: - DHCP range: 192.168.122.101-254 - Gateway: 192.168.122.1 (host) - DNS: Inherited from host configuration


6. Adding and Removing Networks To/From a VM


Dynamically modify VM network interfaces without recreating the VM.

6.1. Specifications

  • VM Name: vmtest
  • Initial Network: host-bridge (bridge br0)
  • Network to Add: nat (bridge brnat)
  • Network to Remove: host-bridge (bridge br0)

Process: 1. Create VM with bridged network 2. Add NAT network interface 3. Configure new interface on VM 4. Remove original bridged interface

6.2. Create VM with Bridged Network

Create initial VM:

sudo virt-install --name vmtest \
    --connect qemu:///system  --virt-type kvm \
    --memory 1024 --vcpus 1 \
    --disk /srv/kvm/vm.qcow2,format=qcow2,size=10 \
    --cdrom /srv/isos/ubuntu-24.04.2-live-server-amd64.iso  \
    --network bridge=br0 \
    --graphics vnc,port=5902,listen=0.0.0.0 \
    --os-variant ubuntu24.04 \
    --noautoconsole

6.3. Add NAT Network Interface

Add a second network interface to the running VM:

virsh attach-interface vmtest \
    bridge brnat \
    --target ens1 \
    --config

Parameters: - bridge brnat: Network type and bridge name - --target ens1: Interface name inside VM - --config: Persistent after shutdown/start

Restart VM (required for interface activation):

virsh destroy vmtest
virsh start vmtest

Important: virsh reboot may not activate new interfaces; use shutdown/start cycle.

6.4. Configure New Network Interface on VM

Configure the new interface (ens1) on the Ubuntu VM.

On the VM:

Check available interfaces:

ip link show

Configure Netplan (Ubuntu):

sudo nano /etc/netplan/00-installer-config.yaml
network:
  ethernets:
    enp1s0:
      dhcp4: true
    ens1:
      dhcp4: true
  version: 2

For Debian VMs, use `/etc/network/interfaces**:

sudo nano /etc/network/interfaces
auto lo
iface lo inet loopback

auto enp1s0
iface enp1s0 inet dhcp

auto ens1
iface ens1 inet dhcp

Apply configuration:

Ubuntu:

sudo netplan apply

Debian:

sudo systemctl restart networking

Verify network configuration:

ip addr show
ip route show

6.5. Remove Bridged Network Interface

Remove the original bridged interface (enp1s0).

On the VM:

Identify MAC address of interface to remove:

ip link show enp1s0

Example output:

2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 52:54:00:24:58:04 brd ff:ff:ff:ff:ff:ff

MAC Address: 52:54:00:24:58:04

On the Host:

Detach interface using MAC address:

virsh detach-interface vmtest \
    bridge \
    --mac 52:54:00:24:58:04 \
    --config

Parameters: - bridge: Network type - --mac: MAC address of interface to remove - --config: Persistent after shutdown/start

For immediate removal (if VM is running):

virsh detach-interface vmtest \
    bridge \
    --mac 52:54:00:24:58:04 \
    --live \
    --config

Shutdown and start VM (not reboot) to complete removal:

virsh destroy vmtest
virsh start vmtest


x386.org