Mengatasi Masalah “Port Hilang” pada Kartu Intel X710 di VPP (Error 11: Resource temporarily unavailable)

Bagi para network engineer yang membangun high-performance router menggunakan Vector Packet Processing (VPP) bersama kartu jaringan Intel X710, galat Error 11 saat proses booting mungkin sudah tidak asing lagi. Masalah ini sering kali muncul secara acak dan membuat salah satu port kartu X710 “hilang” dari VPP.

Artikel ini merangkum investigasi mendalam mengenai akar permasalahan tersebut secara definitif, membongkar mitos penyebabnya, serta menyajikan solusi bersih tanpa harus melakukan flashing firmware yang berisiko bricked.

1. Gejala dan Dampak

Saat layanan VPP dimulai (start), galat ini muncul di log dengan karakteristik sebagai berikut:

dpdk: PCI_BUS: Unable to reset device! Error: 11 (Resource temporarily unavailable)
dpdk: PCI_BUS: 0000:01:00.0 setup device failed
dpdk: PCI_BUS: Requested device 0000:01:00.0 cannot be used

Frekuensi: Muncul secara acak pada sekitar 10–25% percobaan restart VPP.

Target: Hampir selalu terjadi pada port pertama (0000:01:00.0).

Dampak: VPP tetap berjalan normal, tetapi salah satu antarmuka fisik X710 gagal diinisialisasi oleh DPDK dan tidak muncul di konsol VPP.

2. Akar Masalah Definitif (Terbukti secara Low-Level)

Berdasarkan penelusuran menggunakan kprobe pada kernel Linux, rantai kejadian yang memicu galat ini adalah sebagai berikut:

  1. Saat VPP melakukan start, DPDK menginisialisasi perangkat dan memanggil fungsi ioctl(VFIO_DEVICE_RESET).
  2. Di sisi kernel, panggilan ini diteruskan ke vfio_pci_ioctl_reset() $\rightarrow$ pci_try_reset_function() $\rightarrow$ pci_dev_trylock().
  3. Fungsi pci_dev_trylock() bersifat non-blocking (mengambil device_trylock dan pci_cfg_access_trylock). Jika dev->mutex sedang dipegang oleh proses lain, fungsi ini langsung gagal dan mengembalikan kode -EAGAIN (Error 11).
  4. DPDK menganggap galat selain EINVAL sebagai kondisi fatal, sehingga perangkat dibatalkan dan port pun hilang.

Siapa Pemegang Mutex Tersebut?

Pelaku di balik layar adalah systemd-journald.

Setiap kali journald memproses pesan kernel dari /dev/kmsg, ia melakukan resolve pada perangkat terkait dan membaca /sys/bus/pci/devices/<bdf>/uevent. Proses pembacaan ini mengambil device_lock() (dev->mutex) yang sama persis dengan yang dibutuhkan oleh proses reset VFIO.

Karena murni masalah timing (irisan waktu dalam orde mikrodetik) dan DPDK selalu memproses fungsi pertama (.0) terlebih dahulu, tabrakan mutex ini hampir selalu terjadi di port pertama.

3. Solusi Utama: Menonaktifkan Pembacaan KMsg pada Journald

Karena akar masalahnya adalah perebutan akses mutex antara pembacaan /dev/kmsg oleh systemd-journald dan perintah reset VFIO oleh DPDK, solusi paling elegan adalah menghentikan pembacaan /dev/kmsg tanpa harus mematikan fungsi Function Level Reset (FLR) perangkat keras.

Cukup buat satu file konfigurasi drop-in untuk journald di /etc/systemd/journald.conf.d/99-vpp-no-kmsg.conf:

[Journal]
ReadKMsg=no

Cara Pemasangan:

mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/99-vpp-no-kmsg.conf <<'EOF'
[Journal]
ReadKMsg=no
EOF

systemctl daemon-reload
systemctl restart systemd-journald
systemctl restart vpp

Verifikasi:

systemd-analyze cat-config systemd/journald.conf | grep -i ReadKMsg  # Pastikan bernilai ReadKMsg=no
vppctl show interface | grep -c TenGigabitEthernet                  # Pastikan port bernilai 2
journalctl -u vpp --since "-10 min" | grep -c "Unable to reset device" # Harus bernilai 0

Catatan Dampak: Pesan log kernel tidak lagi disimpan secara otomatis ke dalam basis data journal systemd, namun tetap tersedia secara real-time melalui perintah dmesg. Log layanan aplikasi lain (seperti VPP, SSH, dan FRR) tetap tercatat normal di journal.

4. Alternatif Pendekatan (Opsional)

Jika Anda memerlukan log kernel tetap masuk ke journal, terdapat dua alternatif metode lain (pilih salah satu, jangan digabungkan):

Alternatif A: Mematikan Reset VFIO saat Setup (reset_method)

Mengosongkan metode reset membuat ioctl mengembalikan -EINVAL, yang ditoleransi oleh DPDK sehingga tidak memicu galat fatal.

  • Konfigurasi Drop-in (/etc/systemd/system/vpp.service.d/50-no-reset.conf):
[Service]
ExecStartPre=/bin/sh -c 'for f in /sys/bus/pci/devices/0000:01:00.0/reset_method /sys/bus/pci/devices/0000:01:00.1/reset_method; do echo "" > $f; done'
  • Trade-off: Perangkat tidak di-FLR sama sekali saat start maupun stop.

Alternatif B: Skrip Guard & Auto-Retry

Memasang skrip pengawas (ExecStartPost) yang mendeteksi jika port X710 belum lengkap, lalu memerintahkan systemd untuk melakukan restart otomatis hingga port siap.

Skrip Pengawas: /usr/local/sbin/vpp-x710-guard.sh

Buat dan simpan file tersebut dengan isi lengkap berikut:

#!/bin/bash
# vpp-x710-guard.sh
#
# Tujuan: mendeteksi kasus "satu port X710 hilang" yang terjadi karena race di
# kernel saat VPP start. Di log VPP muncul:
#     dpdk: PCI_BUS: Unable to reset device! Error: 11 (Resource temporarily unavailable)
#     dpdk: PCI_BUS: 0000:01:00.0 setup device failed
#     dpdk: PCI_BUS: Requested device 0000:01:00.0 cannot be used
#
# Sebabnya: DPDK memanggil VFIO_DEVICE_RESET; di kernel jalur ini memakai
# pci_try_reset_function() yang mengembalikan -EAGAIN bila lock device PCI
# sedang dipegang konteks kernel lain (race, ~20-30% kejadian, hanya bila
# kedua fungsi X710 dipakai). DPDK menganggap ini fatal dan melewati device
# itu, sehingga port hilang.
#
# Skrip ini dipasang sebagai ExecStartPost. Ia menunggu sampai jumlah port X710
# yang diharapkan muncul. Jika sampai timeout belum lengkap, skrip keluar
# non-zero -> systemd (Restart=always) mengulang start VPP sampai port lengkap.
#
# Logika:
#   - Selama VPP belum menyajikan interface sama sekali, tunggu sampai WAIT detik
#     (menangani VPP yang masih start).
#   - Begitu sudah ada >=1 interface, beri GRACE detik agar port lain menyusul.
#     Bila setelah GRACE jumlah belum lengkap, anggap race -> gagal cepat.
# Ini membuat deteksi gagal cepat (~GRACE detik) tanpa salah nilai saat VPP
# masih membuat interface satu per satu.

set -u

SOCK=/run/vpp/cli.sock
VPPCTL=/usr/bin/vppctl
WANT=${VPP_X710_GUARD_WANT:-2}    # jumlah port X710 yang diharapkan
WAIT=${VPP_X710_GUARD_WAIT:-60}   # detik maksimum menunggu VPP muncul
GRACE=${VPP_X710_GUARD_GRACE:-6}  # detik tunggu ekstra setelah port pertama muncul

have=0
grace=0
i=0
while [ "$i" -lt "$WAIT" ]; do
    have=$("$VPPCTL" -s "$SOCK" show interface 2>/dev/null \
            | grep -c 'TenGigabitEthernet')
    if [ "$have" -ge "$WANT" ]; then
        exit 0
    fi
    if [ "$have" -ge 1 ]; then
        grace=$(( grace + 1 ))
        [ "$grace" -ge "$GRACE" ] && break
    fi
    i=$(( i + 1 ))
    sleep 1
done

echo "vpp-x710-guard: port X710 terdeteksi $have, diharapkan $WANT -> minta restart VPP" >&2
exit 1

Buat file systemd override /etc/systemd/system/vpp.service.d/override.conf

Isi:

[Service]
ExecStartPost=/usr/local/sbin/vpp-x710-guard.sh
RestartSec=5
TimeoutStartSec=180

Uji beban (opsional, cepat):

for i in $(seq 1 50); do
  systemctl reset-failed vpp >/dev/null 2>&1
  systemctl restart vpp >/dev/null 2>&1
  for j in $(seq 1 100); do
    [ "$(timeout 3 vppctl show interface 2>/dev/null | grep -c TenGigabitEthernet)" -ge 2 ] && break
    sleep 0.2
  done
  printf '.'
done; echo
journalctl -u vpp --since "-5 min" | grep -c "Unable to reset device"   # -> 0

Kesimpulan

Galat Error 11 pada inisialisasi DPDK dan X710 bukanlah kerusakan perangkat keras (hardware failure) ataupun cacat fatal pada firmware, melainkan bentrok timing akses mutex kernel akibat aktivitas systemd-journald. Dengan menyetel ReadKMsg=no, sistem operasi terbebas dari race condition, performa dataplane VPP tetap terjaga, dan stabilitas server kembali normal seratus persen.