Niko Akhmalul Ananto
Niko Akhmalul Ananto
Published on 2026-04-13 / 71 Visits
2
0

Integrasi OVS OVN SDN multi-host Libvirt

Virtual Machine with OVN topology

Setelah membaca artikel dari Aditiya Rakhman tentang Konfigurasi OVS pada vm Libvirt, membuat saya beminat untuk mengulik tools yang sangat berhubungan erat dengan OVS, yaitu Open Virtual Network (OVN). OVN dipakai di platform virtualization solution dan container solution yang lumayan besar seperti Openstack, RHOSP, Openshift dan LXD. Sebelum lanjut membahas OVN, silahkan pelajari OVS dari blog hasil tulisan saudara Aditiya Rakhman di laman berikut:

https://www.isiotak.com/archives/konfigurasi-ovs-dengan-vm-libvirt

Oke, kita lanjut.

1. Apa itu OVN (Open Virtual Network)?

Secara sederhana, OVN adalah "Control Plane", sedangkan OVS (Open vSwitch) adalah "Data Plane". OVS murni adalah virtual switch yang hanya tau cara memindahkan paket dari port A ke port B. Dulu, kalau kita pakai OVS antar node, kita harus setting tunneling manual, bikin routing pakai Linux iptables, dan mengatur DHCP sendiri. Sangat sulit apabila jumlah node sudah banyak. Lalu muncul OVN yang merubah itu semua.

OVN adalah sistem SDN (Software-Defined Networking) bawaan resmi dari OVS. OVN memungkinkan kita mendesain topologi jaringan secara logical (membuat virtual switch, virtual router, NAT, Load Balancer) didalam sebuah database terpusat, selanjutnya OVN akan secara otomatis mengubah desain tersebut menjadi aturan OpenFlow dan menyebarkannya ke seluruh OVS di setiap host.

Fungsi dan Fitur Utama OVN

OVN menjalankan beberapa fungsi krusial:

  • Distributed Routing (Routing Terdistribusi): Berbeda dengan router tradisional yang melempar proses routing ke satu host network, OVN membuat virtual router yang terdistribusi ke semua host hypervisor. Ketika vm di host 1 ingin berkomunikasi ke vm dengan network yang berbeda di host 2 ataupun sebaliknya, proses routing dieksekusi langsung oleh OVS di source host sebelum masuk ke tunneling, sehingga mengurangi latency dan membagi beban proses routing.

  • Overlay Networking (Tunneling Otomatis): OVN secara dinamis membuat dan mengelola Tunnel Geneve antar hypervisor. Traffic antar vm dibungkus dengan aman melewati jaringan fisik (management network) tanpa perlu mengubah konfigurasi switch fisik.

  • Native Network Services: OVN tidak lagi bergantung pada network namespace (netns) Linux atau iptables host untuk fitur seperti DHCP, DNS, ataupun NAT. Semua diproses murni secara komputasi di level OpenFlow pipeline OVS.

  • High Availability (Gateway Chassis): Untuk traffic yang keluar ke internet (North-South), OVN mendukung sistem Active-Passive (Gateway Chassis) menggunakan protokol BFD. Jika host yang bertugas sebagai pintu keluar internet mati, host lain akan langsung mengambil alih (Failover) tanpa memutus koneksi jaringan internal.

2. Integrasi OVN SDN ke OVS network multi-host Libvirt

Disclaimer: Integrasi OVN ke OVS Libvirt hanya sekedar riset untuk memperdalam pemahaman networking Openstack. Untuk implementasi dan pemakaian sehari-hari akan menyulitkan dan tidak secara native didukung oleh Libvirt. Untuk pemakaian homelab opsi best practice gunakan incus atau proxmox yang terintegrasi dengan baik untuk penggunaan OVN SDN di multi-host hypervisor.

Workspace

topology will implement

Dua host dengan Ubuntu 24.04 LTS masing-masing terpasang 3 interface:

  • ens3 - 192.168.122.0/24 : jalur sumber internet untuk host hypervisor

  • ens4 - 192.168.133.0/24 : jalur tunnel OVN

  • ens5 - 192.168.144.0/24 : jalur external vm

host-1 punya ip 192.168.122.11/24 dan 192.168.133.11/24. Interface ens5 dibiarkan kosong.

host-2 punya ip 192.168.122.12/24 dan 192.168.133.12/24. Interface ens5 dibiarkan kosong.

Install Package

Host 1

apt update && apt -y full-upgrade

apt install -y cloud-image-utils \
    genisoimage qemu-kvm libvirt-daemon-system \
    libvirt-clients bridge-utils virt-manager

apt install -y openvswitch-common \
    openvswitch-switch ovn-central ovn-common ovn-host

systemctl enable --now ovn-central openvswitch-switch ovn-controller.service

reboot

Host 2

apt update && apt -y full-upgrade

apt install -y cloud-image-utils \
    genisoimage qemu-kvm libvirt-daemon-system \
    libvirt-clients bridge-utils virt-manager

apt install -y openvswitch-common \
    openvswitch-switch ovn-host ovn-common

systemctl enable --now ovn-host openvswitch-switch ovn-controller.service

reboot

Konfigurasi Chassis OVN

Host 1

# setelah reboot
ovn-sbctl set-connection ptcp:6642:0.0.0.0
ovn-nbctl set-connection ptcp:6641:0.0.0.0

ovs-vsctl set open_vswitch . \
  external_ids:ovn-remote=tcp:192.168.133.11:6642 \
  external_ids:ovn-encap-type=geneve \
  external_ids:ovn-encap-ip=192.168.133.11

cat <<EOF> net-ovn.xml
<network>
  <name>net-ovn</name>
  <forward mode='bridge'/>
  <bridge name='br-int'/> <virtualport type='openvswitch'/>
</network>
EOF
virsh net-define net-ovn.xml
virsh net-start net-ovn
virsh net-autostart net-ovn

bridge br-int otomotis terbuat ketika mengintall package ovs & ovn.

Host 2

# setelah reboot
ovs-vsctl set open_vswitch . \
  external_ids:ovn-remote=tcp:192.168.133.11:6642 \
  external_ids:ovn-encap-type=geneve \
  external_ids:ovn-encap-ip=192.168.133.12

cat <<EOF> net-ovn.xml
<network>
  <name>net-ovn</name>
  <forward mode='bridge'/>
  <bridge name='br-int'/> <virtualport type='openvswitch'/>
</network>
EOF
virsh net-define net-ovn.xml
virsh net-start net-ovn
virsh net-autostart net-ovn

Verifikasi

Setelah selesai konfigurasi, kita harus memverifikasi atau memastikan semua konfigurasi telah sesuai.

root@host-1:~# ovn-sbctl show

# contoh output
Chassis "79daa251-b2c5-4aae-a053-9228b064f1df"
    hostname: host-1
    Encap geneve
        ip: "192.168.133.11"
        options: {csum="true"}
Chassis "23a30f8d-fd21-4473-9baf-010f2922406e"
    hostname: host-2
    Encap geneve
        ip: "192.168.133.12"
        options: {csum="true"}

Buat VM dengan net-ovn

Jalankan perintah dibawah pada kedua host yang sebelumnya dibuat.

wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img \
  -P /var/lib/libvirt/images/

Host 1

cat <<EOF > network-config.yaml
version: 2
ethernets:
  ens3:
    match:
      macaddress: "52:54:00:dd:1e:5c"
    set-name: "ens3"
    dhcp4: false
    mtu: 1500
    addresses:
      - 10.101.101.11/24
    routes: 
      - to: default 
        via: 10.101.101.1
    nameservers:
      addresses: ['8.8.8.8', '8.8.4.4']
EOF
cat <<EOF > user-data.yaml
#cloud-config
hostname: vm-1
fqdn: vm-1
users:
  - name: ubuntu
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    shell: /bin/bash
    groups: users
ssh_pwauth: true
disable_root: false
chpasswd:
  list:
    - ubuntu:ubuntu
  expire: false
EOF

cloud-localds -v --network-config=network-config.yaml \
  /var/lib/libvirt/images/vm-1-seed.iso user-data.yaml 

qemu-img create -f qcow2 -F qcow2 -b /var/lib/libvirt/images/noble-server-cloudimg-amd64.img \
  /var/lib/libvirt/images/vm-1-sda.qcow2 20G

virt-install \
  --name vm-1 \
  --memory 1024 \
  --vcpus 1 \
  --disk path=/var/lib/libvirt/images/vm-1-sda.qcow2,device=disk,bus=virtio,format=qcow2 \
  --disk path=/var/lib/libvirt/images/vm-1-seed.iso,device=cdrom \
  --os-variant ubuntu24.04 \
  --network network=net-ovn,mac=52:54:00:dd:1e:5c \
  --graphics none \
  --noautoconsole \
  --import

Host 2

cat <<EOF > network-config.yaml
version: 2
ethernets:
  ens3:
    match:
      macaddress: "52:54:00:cc:8c:e1"
    set-name: "ens3"
    dhcp4: false
    mtu: 1500
    addresses:
      - 10.101.101.12/24
    routes: 
      - to: default 
        via: 10.101.101.1
    nameservers:
      addresses: ['8.8.8.8', '8.8.4.4']
EOF
cat <<EOF > user-data.yaml
#cloud-config
hostname: vm-2
fqdn: vm-2
users:
  - name: ubuntu
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    shell: /bin/bash
    groups: users
ssh_pwauth: true
disable_root: false
chpasswd:
  list:
    - ubuntu:ubuntu
  expire: false
EOF

cloud-localds -v --network-config=network-config.yaml \
  /var/lib/libvirt/images/vm-2-seed.iso user-data.yaml 

qemu-img create -f qcow2 -F qcow2 -b /var/lib/libvirt/images/noble-server-cloudimg-amd64.img \
  /var/lib/libvirt/images/vm-2-sda.qcow2 20G

virt-install \
  --name vm-2 \
  --memory 1024 \
  --vcpus 1 \
  --disk path=/var/lib/libvirt/images/vm-2-sda.qcow2,device=disk,bus=virtio,format=qcow2 \
  --disk path=/var/lib/libvirt/images/vm-2-seed.iso,device=cdrom \
  --os-variant ubuntu24.04 \
  --network network=net-ovn,mac=52:54:00:cc:8c:e1 \
  --graphics none \
  --noautoconsole \
  --import

Verifikasi

Setelah selesai konfigurasi, pastikan IP dan MAC address tiap vm sudah sesuai dengan konfigurasi diatas

virsh console vm-1 # username:ubuntu password:ubuntu

ubuntu@vm-1:~$ ip a sh ens3
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:dd:1e:5c brd ff:ff:ff:ff:ff:ff
    inet 10.101.101.11/24 brd 10.101.101.255 scope global ens3
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fedd:1e5c/64 scope link 
       valid_lft forever preferred_lft forever

ubuntu@vm-2:~$ ip a sh ens3
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:cc:8c:e1 brd ff:ff:ff:ff:ff:ff
    inet 10.101.101.12/24 brd 10.101.101.255 scope global ens3
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fecc:8ce1/64 scope link 
       valid_lft forever preferred_lft forever

# pastikan mac address sama dengan yang ada di tap device dan terdaftar sebagai port ovs
## cek nama tap device vm di host 1
root@host-1:~# virsh dumpxml vm-1 |grep "type='bridge'" -A 10
    <interface type='bridge'>
      <mac address='52:54:00:dd:1e:5c'/>
      <source network='net-ovn' portid='c563de63-0c78-481c-8278-a65d51fd671f' bridge='br-int'/>
      <virtualport type='openvswitch'>
        <parameters interfaceid='92402eee-edac-451e-becf-87c2e53c7c10'/>
      </virtualport>
      <target dev='vnet4'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

## cek iface-id tap device di ovs sudah sama dengan interfaceid di dumpxml
root@host-1:~# ovs-vsctl get interface vnet4 external_ids:iface-id 
"92402eee-edac-451e-becf-87c2e53c7c10"

## cek mac address tap device di ovs sudah sama dengan di dumpxml dan di dalam vm
root@host-1:~# ovs-vsctl get interface vnet4 external_ids:attached-mac
"52:54:00:dd:1e:5c"

## cek nama tap device vm di host 2
root@host-2:~# virsh dumpxml vm-2 |grep "type='bridge'" -A 10
    <interface type='bridge'>
      <mac address='52:54:00:cc:8c:e1'/>
      <source network='net-ovn' portid='21d2fd51-a52f-4c16-9ead-eb352a065ac8' bridge='br-int'/>
      <virtualport type='openvswitch'>
        <parameters interfaceid='850b961f-b038-4eaf-9b66-817958a8d7e9'/>
      </virtualport>
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

## cek iface-id tap device di ovs sudah sama dengan interfaceid interface-id di dumpxml
root@host-2:~# ovs-vsctl get interface vnet0 external_ids:iface-id
"850b961f-b038-4eaf-9b66-817958a8d7e9"

## cek mac address tap device di ovs sudah sama dengan di dumpxml dan di dalam vm
root@host-2:~# ovs-vsctl get interface vnet0 external_ids:attached-mac
"52:54:00:cc:8c:e1"

Logic internal

Sebelum menambahkan network ovn kedalam vm, kita harus setup logic router internal network. Pada step ini saya akan menggunakan network 10.101.101.0/24. Setelah membuat logic, barulah kita menambahkan ovn netowrk kedalam vm kita. Semua eksekusi berawalan ovn dieksekusi didalam Host 1.

# buat logical switch bernama net-ovn
ovn-nbctl ls-add net-ovn

# pasang port vm-1 ke logical switch
# ovn-nbctl lsp-add net-ovn (iface-id/interfaceid vm-1) 
ovn-nbctl lsp-add net-ovn 92402eee-edac-451e-becf-87c2e53c7c10

# ovn-nbctl lsp-set-addresses (iface-id/interfaceid vm-1) "(mac address port) (ip address port)"
ovn-nbctl lsp-set-addresses 92402eee-edac-451e-becf-87c2e53c7c10 \
  "52:54:00:dd:1e:5c 10.101.101.11"

# (opsional, sekedar tambah label device=nama-vm) ovn-nbctl set (iface-id/interfaceid vm-1) external_ids:device=nama-vm
ovn-nbctl set logical_switch_port 92402eee-edac-451e-becf-87c2e53c7c10 \
  external_ids:device=vm-1

# pasang port vm-2 ke logical switch
ovn-nbctl lsp-add net-ovn 850b961f-b038-4eaf-9b66-817958a8d7e9
ovn-nbctl lsp-set-addresses 850b961f-b038-4eaf-9b66-817958a8d7e9 \
  "52:54:00:cc:8c:e1 10.101.101.12"
ovn-nbctl set logical_switch_port 850b961f-b038-4eaf-9b66-817958a8d7e9 \
  external_ids:device=vm-2

Verifikasi

root@host-1:~# ovn-nbctl show
switch 88f264be-060a-460f-a9ae-5e34bd09d470 (net-ovn)
    port 850b961f-b038-4eaf-9b66-817958a8d7e9
        addresses: ["52:54:00:cc:8c:e1 10.101.101.12"]
    port 92402eee-edac-451e-becf-87c2e53c7c10
        addresses: ["52:54:00:dd:1e:5c 10.101.101.11"]

root@host-1:~# ovn-nbctl lsp-list net-ovn
9425e77c-387c-4f41-92d0-67d0cfd6cc11 (850b961f-b038-4eaf-9b66-817958a8d7e9)
e27679dc-9abd-4ba7-abc0-d31c55981c55 (92402eee-edac-451e-becf-87c2e53c7c10)
 
root@host-1:~# ovn-nbctl get logical_switch_port 9425e77c-387c-4f41-92d0-67d0cfd6cc11 external_ids
{device=vm-2}

root@host-1:~# ovn-nbctl get logical_switch_port e27679dc-9abd-4ba7-abc0-d31c55981c55 external_ids
{device=vm-1}


# jika port vm sudah terdaftar seperti diatas, vm sudah bisa terkoneksi satu sama lain walau berbeda host

# test koneksi dari vm-1 di host-1 ke vm-2 di host 2
virsh console vm-1
ping 10.101.101.12 -c4

## di host-2
tcpdump -i any icmp -n

traffic tracing for verification ovn works in vm network

Dari gambar test diatas, terlihat packet masuk ke host 2 dari tunnel Geneve (genev_sys_6081), dikirim ke vm-2 via vnet0 (tap device vm-2). vm-2 balas ping dari vnet0 (tap device vm-2), dan dikirim balik lewat tunnel Geneve (genev_sys_6081). Lanjut berikut test sebaliknya dari vm-2 di host-2 ke vm-1 di host 1.

traffic tracing for verification ovn works in vm network

Dari gambar test di atas, terlihat packet masuk ke host 1 dari tunnel Geneve (genev_sys_6081), dikirim ke vm-1 via vnet4 (tap device vm-1). vm-1 balas ping dari vnet4 (tap device vm-1), dan dikirim balik lewat tunnel Geneve (genev_sys_6081).

Buat logical router di OVN dan pasang port gateway network 10.101.101.0/24

# buat logical router bernama ovn-router
ovn-nbctl lr-add ovn-router

# buat port di sisi logical router (net-ovn), command line:
# ovn-nbctl lsp-add (nama switch) (nama port switch ke router)
# ovn-nbctl lsp-set-type (nama port switch ke router) router
# ovn-nbctl lsp-set-addresses (nama port switch ke router) router
# ovn-nbctl lsp-set-options (nama port switch ke router) router-port=(nama port router ke switch)

# buat port di sisi logical router (ovn-router), command line:
# ovn-nbctl lrp-add (nama router) (nama port router ke switch) (mac address bebas untuk gateway) 10.101.101.1/24

ovn-nbctl lsp-add net-ovn net-ovn-to-router
ovn-nbctl lsp-set-type net-ovn-to-router router
ovn-nbctl lsp-set-addresses net-ovn-to-router router
ovn-nbctl lsp-set-options net-ovn-to-router router-port=router-to-net-ovn

ovn-nbctl lrp-add ovn-router router-to-net-ovn 52:54:00:1A:01:01 10.101.101.1/24

# verifikasi konfigurasi terakhir
root@host-1:~# ovn-nbctl show
switch 88f264be-060a-460f-a9ae-5e34bd09d470 (net-ovn)
    port 850b961f-b038-4eaf-9b66-817958a8d7e9
        addresses: ["52:54:00:cc:8c:e1 10.101.101.12"]
    port 92402eee-edac-451e-becf-87c2e53c7c10
        addresses: ["52:54:00:dd:1e:5c 10.101.101.11"]
    port net-ovn-to-router
        type: router
        router-port: router-to-net-ovn
router 8a515a4e-e4e0-481c-9bb8-9f7df45bc7fa (ovn-router)
    port router-to-net-ovn
        mac: "52:54:00:1A:01:01"
        networks: ["10.101.101.1/24"]

Di kondisi sekarang, tiap vm di tiap host sudah bisa hit ke gateway ip internal network 10.101.101.1 dan proses routing tidak keluar dari source host karena router hanyalah logical device desentralisasi.

Test ping vm-1 ke ip 10.101.101.1:

all vm can ping to gateway

Test ping vm-2 ke ip 10.101.101.1:

Test ping vm-2 to gateway ip

Buat port external gateway router

Buat bridge ovs baru dan mapping ke interface ens5

# eksekusi di kedua host
ovs-vsctl add-br br-ex
ovs-vsctl add-port br-ex ens5
ovs-vsctl set open_vswitch . external_ids:ovn-bridge-mappings=physnet:br-ex

Buat logical router dan port localnet untuk menyambungkan ke br-ex (physnet)

# eksekusi di host-1
ovn-nbctl ls-add net-ext
ovn-nbctl lsp-add net-ext ln-external
ovn-nbctl lsp-set-type ln-external localnet
ovn-nbctl lsp-set-addresses ln-external unknown
ovn-nbctl lsp-set-options ln-external network_name=physnet

Buat port external gateway di logical router ovn-router dan sambungkan ke logical router net-ext

ovn-nbctl lrp-add ovn-router router-to-net-ext 52:54:2B:00:20:01 192.168.144.100/24
ovn-nbctl lrp-set-options router-to-net-ext nat-addresses="router"
ovn-nbctl lsp-add net-ext net-ext-to-router
ovn-nbctl lsp-set-type net-ext-to-router router
ovn-nbctl lsp-set-addresses net-ext-to-router router
ovn-nbctl lsp-set-options net-ext-to-router router-port=router-to-net-ext

Menambahkan host-1 sebagai chassis gateway

Untuk menggunakan port external, kita harus membuat external gateway router ovn. Berikut caranya

# Lihat chassis id spesifik node
ovn-sbctl show | grep -B 1 "hostname: host-1" | grep Chassis | awk '{print $2}' | tr -d '"'

# Ikat port eksternal router ke Node 1 (non HA mode)
ovn-nbctl lrp-set-gateway-chassis router-to-net-ext <ID_CHASSIS_HOST-1>

# verifikasi gateway_chassis
root@host-1:~# ovn-sbctl find Port_Binding logical_port=cr-router-to-net-ext
# contoh output
_uuid               : c21c4a85-7e3f-44c4-9c5e-46768075f097
additional_chassis  : []
additional_encap    : []
chassis             : 4728fbcb-1142-4d5a-b5d6-8cc32a61abf1
datapath            : 5900cfd5-b065-41a9-b144-718bb79d8c71
encap               : []
external_ids        : {}
gateway_chassis     : []
ha_chassis_group    : 1195076a-8a45-4d07-bc46-15c04f3b248c
logical_port        : cr-router-to-net-ext
mac                 : ["52:54:2B:00:20:01 192.168.144.100/24"]
mirror_rules        : []
nat_addresses       : []
options             : {always-redirect="true", distributed-port=router-to-net-ext}
parent_port         : []
port_security       : []
requested_additional_chassis: []
requested_chassis   : []
tag                 : []
tunnel_key          : 3
type                : chassisredirect
up                  : true
virtual_parent      : []

root@host-1:~# ovn-nbctl list gateway_chassis
# contoh output
_uuid               : 61159636-2c77-4fcd-9c43-b723aef29785
chassis_name        : "79daa251-b2c5-4aae-a053-9228b064f1df"
external_ids        : {}
name                : router-to-net-ext-79daa251-b2c5-4aae-a053-9228b064f1df
options             : {}
priority            : 0

root@host-1:~# ovn-nbctl list logical_router_port router-to-net-ext
# contoh output
_uuid               : f0025ae8-c376-41b2-bbfd-9498e11005bd
enabled             : []
external_ids        : {}
gateway_chassis     : [61159636-2c77-4fcd-9c43-b723aef29785]
ha_chassis_group    : []
ipv6_prefix         : []
ipv6_ra_configs     : {}
mac                 : "52:54:2B:00:20:01"
name                : router-to-net-ext
networks            : ["192.168.144.100/24"]
options             : {nat-addresses=router}
peer                : []
status              : {hosting-chassis="79daa251-b2c5-4aae-a053-9228b064f1df"}

Mengaktifkan HA (active-backup) chassis gateway

Mengaktifkan HA (active-backup) pada OVN chassis gateway penting karena memastikan gateway tetap tersedia. Jika salah satu jalur/komponen gateway menjadi tidak aktif (contoh: link/chassis bermasalah), peran "active" dapat berpindah ke node "standby" sehingga trafik tetap bisa berjalan dan konektivitas yang terdampak tetap terjaga (failover).

# tambah chassis host-2 sebagai port external gateway dengan priority lebih tinggi
ovn-nbctl lrp-set-gateway-chassis router-to-net-ext <ID_CHASSIS_NODE1> 5
ovn-nbctl lrp-set-gateway-chassis router-to-net-ext <ID_CHASSIS_NODE2> 10

# verifikasi gateway_chassis
root@host-1:~# ovn-sbctl find Port_Binding logical_port=cr-router-to-net-ext
_uuid               : c21c4a85-7e3f-44c4-9c5e-46768075f097
additional_chassis  : []
additional_encap    : []
chassis             : 0bc4d238-bedf-47de-b9c9-2496041c4ce6
datapath            : 5900cfd5-b065-41a9-b144-718bb79d8c71
encap               : []
external_ids        : {}
gateway_chassis     : []
ha_chassis_group    : 1195076a-8a45-4d07-bc46-15c04f3b248c
logical_port        : cr-router-to-net-ext
mac                 : ["52:54:2B:00:20:01 192.168.144.100/24"]
mirror_rules        : []
nat_addresses       : []
options             : {always-redirect="true", distributed-port=router-to-net-ext}
parent_port         : []
port_security       : []
requested_additional_chassis: []
requested_chassis   : []
tag                 : []
tunnel_key          : 3
type                : chassisredirect
up                  : true
virtual_parent      : []

root@host-1:~# ovn-nbctl list gateway_chassis
_uuid               : 3be4ec38-55e6-46c2-a503-e2a5eaa396d7
chassis_name        : "23a30f8d-fd21-4473-9baf-010f2922406e"
external_ids        : {}
name                : router-to-net-ext-23a30f8d-fd21-4473-9baf-010f2922406e
options             : {}
priority            : 10

_uuid               : 61159636-2c77-4fcd-9c43-b723aef29785
chassis_name        : "79daa251-b2c5-4aae-a053-9228b064f1df"
external_ids        : {}
name                : router-to-net-ext-79daa251-b2c5-4aae-a053-9228b064f1df
options             : {}
priority            : 5


# cek dimana port external router aktif
root@host-1:~# ovn-sbctl show
Chassis "23a30f8d-fd21-4473-9baf-010f2922406e"
    hostname: host-2
    Encap geneve
        ip: "192.168.133.12"
        options: {csum="true"}
    Port_Binding cr-router-to-net-ext
    Port_Binding "6b03c288-4618-4639-bac4-964c19ecef16"
Chassis "79daa251-b2c5-4aae-a053-9228b064f1df"
    hostname: host-1
    Encap geneve
        ip: "192.168.133.11"
        options: {csum="true"}
    Port_Binding "ec63f41e-2fd8-48e3-aba3-3747b66316d6"

Dari output ovn-sbctl show terlihat chassis host-2 terdapat port binding cr-router-to-net-ext yang mana inilah si port external gateway router yang aktif.

Buat Default route & SNAT Rule

Menambahkan default route ke ip gateway router fisik dan menambahkan snat rule agar logical router tau kemana harus mengarahkan komunikasi dari vm ke internet.

# tambahkan default route dan rule SNAT
ovn-nbctl lr-route-add ovn-router 0.0.0.0/0 192.168.144.1
ovn-nbctl lr-nat-add ovn-router snat 192.168.144.100 10.101.101.0/24

Buat DNAT Rule

Menambahkan dnat rule agar vm dapat diakses dari host.

#ovn-nbctl lr-nat-add <router_name> dnat <external_ip> <logical_ip>
ovn-nbctl lr-nat-add ovn-router dnat 192.168.144.111 10.101.101.11
ovn-nbctl lr-nat-add ovn-router dnat 192.168.144.112 10.101.101.12

# verifikasi
 ovn-nbctl lr-nat-list ovn-router
TYPE             GATEWAY_PORT          EXTERNAL_IP        EXTERNAL_PORT    LOGICAL_IP          EXTERNAL_MAC         LOGICAL_PORT
dnat                                   192.168.144.111                     10.101.101.11
dnat                                   192.168.144.112                     10.101.101.12
snat                                   192.168.144.100                     10.101.101.0/24

Di kondisi sekarang, vm sudah bisa mengakses internet lewat ip 192.168.144.100 dan bisa diakses lewat ssh ke ip externalnya masing-masing (192.168.144.111 & 192.168.144.112).

3. Verifikasi

Setelah selesai mengkonfigurasi, selanjutnya kita harus memverifikasi untuk memastikan semua fungsi dari konfigurasi yang dibuat sudah benar. Adapun poin-poin testing yang saya buat, yaitu:

  • SSH: Untuk memastikan network pada tiap vm sudah terkoneksi satu sama lain.

  • Ping: Untuk memastikan traffic yang dilewati sudah sesuai dengan konfigurasi.

  • HA (High Availability): Untuk memastikan failover sudah aktif.

Testing pada vm-1

SSH testing

Melakukan verifikasi dengan test ssh dari host 1 ke vm-1. Command yang dipakai seperti ssh biasa, tanpa embel-embel lainnya.

ssh 192.168.144.111 -l ubuntu

ssh testing from host-1 to vm-1

Ping testing

Setelah masuk kedalam vm-1 selanjutnya saya akan coba untuk test ping dari vm-1 ke google.com sekaligus trace traffic dengan tcpdump

ping test from vm-1 to google.com

Dari gambar diatas, ping dari vm-1 ke google.com melawati host-2 terlebih dahulu karena disitulah tempat port external aktif.

Testing pada vm-2

Selanjutanya saya akan coba melakukan testing ssh dan ping pada vm-2

SSH testing

Perintah ssh yang sama, tapi dengan beda IP. Untuk IP vm-2 sebelumnya sudah saya set pada alamat 192.168.144.112 . Jadi dari host-1 saya akan ssh ke IP tersebut. Dan berikut test ssh ke vm-2 dari host-1.

ssh testing from host-1 to vm-2

Ping testing

Setelah masuk kedalam vm-2, saya akan coba hal yang sama seperti vm-1. Saya akan test ping dari vm-2 ke google.com sekaligus trace traffic dengan tcpdump.

ping test from vm-2 to google.com

Dari gambar diatas, ping dari vm-2 ke google.com tidak melawati host-1 sama sekali, meskipun secara TTL terlihat sama saja 63, tapi realnya vm-1 ada overhead masuk tunneling ke host-2 untuk bisa terhubung ke internet.

Test Availability

Test Availability saya lakukan untuk memastikan jika salah satu host mati atau bermasalah, host lain bisa membackup tugas tersebut. Berikut untuk hasil pengujiannya.

Ping Test

Saya akan coba mereproduce case dengan melakukan ping dari vm-2 ketika gateway chassis host-1 dalam keadaan shutoff:

connection between vm 2 with host 2 still connected even host 1 shutoff

Dari gambar diatas, ketika si pemegang ovn-central (host-1) dalam keadaan shutoff, koneksi vm-2 di host-2 tetap lancar jaya.

Selanjutnya kita akan balik kondisinya, test ping dari vm-1 ketika host-2 masih jadi aktif gateway chassis dan host-2 akan di shutotff:

when host-2 shutoff, connection will takeover with host-1

Dari gambar di atas, ketika host-2 sebagai gateway aktif dishutoff, port external gateway berpindah ke host-1 dan koneksi vm-1 ke network external tetap aman setelah port external gateway berpindah.

Masih ada satu test lagi yang belum dilakukan yaitu test ping antar vm beda ovn-host ketika si ovn-central dishutoff.

Karena artikel terlalu panjang, mungkin akan saya tulis pada artikel berikutnya.

Sedikit tips troubleshooting:

ketika vm dinyalakan pasca host reboot, biasanya vm jadi tidak bisa ping kemanapun. Untuk fix ini kita perlu define interfaceid di interface bridge network vm lewat virsh edit vm ketika masih shutoff agar sama dengan port id yang sudah didaftarkan di logical switch net-ovn.

contoh:

virsh destroy vm-1
virsh edit vm-1
    <interface type='bridge'>
      <mac address='52:54:00:dd:1e:5c'/>
      <source network='net-ovn' portid='37bb1b1a-54bd-4786-96de-ed7fa826bb24' bridge='br-int'/>
      <!-- AWAL BAGIAN YANG DITAMBAHKAN -->
      <virtualport type='openvswitch'>
        <parameters interfaceid='ec63f41e-2fd8-48e3-aba3-3747b66316d6'/>
      </virtualport>
      <!-- AKHIR BAGIAN YANG DITAMBAHKAN -->
      <target dev='vnet0'/>
      <model type='virtio'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>

virsh start vm-1

4. Kesimpulan

Di tahap ini, kita telah berhasil buat Software-Defined Networking (SDN) menggunakan OVN pada klaster multi-host Libvirt. Secara ringkas, berikut adalah kondisi jaringan yang sudah kita capai:

  • Konektivitas East-West: vm antar host sudah bisa saling berkomunikasi melalui tunnel Geneve yang dikelola secara otomatis oleh OVN.

  • Distributed Routing: Proses routing antar subnet terjadi langsung di level OVS pada masing-masing host tanpa harus dilempar ke router fisik atau satu node pusat (latency rendah).

  • Konektivitas North-South (Internet): Seluruh vm sudah mendapatkan akses internet melalui mekanisme SNAT yang terpusat di Gateway Chassis (host-2).

  • High Availability: Simulasi skema active-backup pada gateway chassis, sehingga jika host yang jadi tempat port external terbinding bermasalah, jalur keluar internet akan otomatis berpindah ke host-1 melalui protokol BFD.

5. Todo

Meskipun fungsionalitas dasar sudah terpenuhi, setup ini masih bisa dioptimalkan lebih jauh untuk mendekati kapabilitas cloud platform seperti OpenStack. Berikut adalah Next Steps untuk pengembangan lab ini:

  1. Implementasi dnat_and_snat rule (1-to-1 NAT): Saat ini vm bisa mengakses internet (outbound) namun masih berbagi satu ip external untuk jalur intenet. Langkah selanjutnya adalah membuat dedicated external port untuk memberikan dnat_and_snat rule. Dengan dnat_and_snat rule vm punya jalur tersendiri untuk akses ke internet tanpa perlu berbagi jalur outbound dengan vm lainnya.

  2. Expose vm dengan Provider Network Mode: Untuk skenario dimana vm membutuhkan performa maksimal atau harus berada dalam satu segmen broadcast dengan router fisik (tanpa melalui overlay tunnel), kita akan coba mengonfigurasi Provider Network. Dalam mode ini, traffic vm akan langsung di-bridging ke interface fisik (ens5) menggunakan localnet port, sehingga vm seolah-olah tertancap langsung pada switch fisik.

  3. Setup Native DHCP Server di OVN: Alih-alih menyetel IP statis secara manual di dalam vm atau menggunakan cloud-init yang kaku, kita akan memanfaatkan Native Network Services dari OVN. Kita akan mengonfigurasi DHCP server langsung di logical router dan mengatur DHCP lease pada tiap port. Hasilnya, vm akan otomatis mendapatkan konfigurasi IP, gateway, dan DNS begitu booting, membuat manajemen IP menjadi jauh lebih efisien dan dinamis.

6. Referensi

https://developers.redhat.com/blog/2018/11/08/how-to-create-an-open-virtual-network-distributed-gateway-router?source=sso#setup_details

https://blog.scottlowe.org/2016/12/09/using-ovn-with-kvm-libvirt/

https://ovn-kubernetes.io/installation/INSTALL.UBUNTU/

https://www.isiotak.com/archives/konfigurasi-ovs-dengan-vm-libvirt

https://documentation.ubuntu.com/public-images/public-images-how-to/use-local-cloud-init-ds/


Comment