Menggunakan DPDK

Halaman ini menjelaskan cara menggunakan Data Plane Development Kit (DPDK) di instance Compute Engine U4C.

Tentang DPDK melalui AF_XDP

Data Plane Development Kit (DPDK) adalah framework untuk aplikasi yang membutuhkan performa tinggi dan memerlukan pemrosesan paket yang cepat, latensi rendah, dan performa yang konsisten. DPDK mengabaikan stack jaringan kernel Linux dan berjalan langsung di ruang pengguna. Anda dapat menjalankan DPDK di instance U4C menggunakan arsitektur AF_XDP.

DPDK menyediakan Driver Mode Polling AF_XDP (PMD), yang merupakan perangkat virtual (vdev) yang memungkinkan aplikasi DPDK berjalan di atas AF_XDP dalam mode salin atau mode tanpa salin. Untuk mengetahui informasi selengkapnya, lihat Driver Mode Polling AF_XDP dalam dokumentasi DPDK. Tidak seperti deployment umum di Compute Engine, DPDK melalui AF_XDP di instance U4C tidak memerlukan konfigurasi VFIO, UIO, atau dpdk-devbind.py.

Penggunaan DPDK dengan Solusi ULL mencakup dukungan untuk pengarahan alur. Anda dapat mengabaikan hashing Receive Side Scaling (RSS) default dengan mengarahkan alur traffic tertentu langsung ke antrean penerimaan (RX)yang ditentukan. Solusi ULL mendukung pengarahan alur 3-tuple (protokol, alamat IP tujuan, dan port tujuan) untuk traffic unicast dan multicast ULL.

Sebelum memulai

Sebelum menggunakan DPDK di instance Compute Engine U4C, Anda harus memenuhi persyaratan berikut.

Membuat instance U4C

Jika belum melakukannya, buat instance bare metal U4C. Lihat Membuat ULL instance Compute Engine.

Menghubungkan ke instance menggunakan SSH

Jika belum melakukannya, hubungkan ke instance menggunakan SSH.

Beralih ke pengguna root

Perintah dan skrip dalam prosedur berikut mengubah setelan tingkat sistem, parameter kernel, dan antarmuka jaringan. Agar berhasil menjalankannya, Anda harus mengeksekusinya sebagai pengguna root. Anda dapat beralih ke shell root dengan menjalankan sudo su, atau menambahkan sudo sebelum menjalankan perintah sesuai kebutuhan.

Menginstal DPDK di instance U4C

Untuk menginstal DPDK di instance U4C, ikuti langkah-langkah berikut:

  1. Konfigurasikan dependensi untuk penginstalan DPDK:

    apt-get update && apt-get upgrade -yq
    apt-get install -yq build-essential ninja-build python3-pip \
        linux-headers-$(uname -r) pkg-config libnuma-dev
    pip install pyelftools meson
    
  2. Instal DPDK.

    wget https://fast.dpdk.org/rel/dpdk-VERSION.tar.xz
    tar xvf dpdk-VERSION.tar.xz
    cd dpdk-VERSION

    Ganti VERSION dengan versi DPDK yang ingin Anda instal, seperti 26.07. Jika diperlukan, lihat halaman Download DPDK.

  3. Untuk membuat DPDK dengan contoh:

    meson setup -Dexamples=all build
    ninja -C build install; ldconfig
    

Mengonfigurasi antarmuka jaringan untuk AF_XDP

Untuk menggunakan AF_XDP di Google Virtual NIC (gVNIC), Anda harus menyesuaikan fitur driver default untuk menyiapkan antarmuka jaringan.

Anda dapat melakukan langkah-langkah ini secara manual atau menggunakan skrip konfigurasi otomatis. Pilih salah satu tab berikut:

Manual

Ikuti langkah-langkah berikut untuk setiap antarmuka jaringan yang ingin Anda konfigurasi.

  1. Kurangi jumlah antrean RX dan TX: gVNIC secara default menggunakan jumlah antrean RX dan TX maksimum yang didukung, tetapi Anda harus menguranginya hingga setengah untuk memastikan ada cukup antrean TX untuk traffic kernel normal.

    ethtool -L NIC_NAME rx NUM_SOCKETS \
    tx NUM_SOCKETS

    Ganti kode berikut:

    • NIC_NAME: nama OS antarmuka jaringan, seperti eth1.
    • NUM_SOCKETS: jumlah soket AF_XDP yang akan dikonfigurasi. Tetapkan nilai ini tidak lebih dari setengah antrean maksimum untuk antarmuka. Untuk instance U4C, nilai ini biasanya adalah 8 (setengah dari 16 antrean default). Anda dapat memverifikasi antrean maksimum dengan menjalankan ethtool -l NIC_NAME.
  2. Nonaktifkan GRO dan LRO hardware: Karena gVNIC tidak mendukung XDP multi-buffer, Anda harus menonaktifkan Large Receive Offload (LRO) dan Generic Receive Offload (GRO) hardware:

    ethtool -K NIC_NAME rx-gro-hw off
    ethtool -K NIC_NAME lro off
  3. Kurangi panjang buffer RX: Secara default, driver yang lebih baru memposting buffer 4 KB (4.096 byte) ke antarmuka jaringan untuk RX, tetapi XDP memerlukan panjang buffer 2048:

    ethtool -G NIC_NAME rx-buf-len 2048

Skrip

Atau, Anda dapat menjalankan skrip Bash berikut untuk setiap antarmuka jaringan yang ingin Anda konfigurasi. Skrip ini secara otomatis menyiapkan a antarmuka jaringan tertentu untuk XDP dengan mengurangi jumlah antrean, menonaktifkan offload, dan menyesuaikan panjang buffer RX:

#!/bin/bash
# Usage example: NUM_SOCKETS=8 prep_xdp.sh eth0

DEV=$1
NUM_SOCKETS=${NUM_SOCKETS=1}

# Reduce RX/TX queue counts to the number of AF_XDP sockets
ethtool -L $DEV rx $NUM_SOCKETS tx $NUM_SOCKETS

# Disable LRO/HW-gro
OFFLOAD=$(ethtool -k $DEV | \
grep "rx-gro-hw\|large-receive-offload" | \
grep -v fixed | cut -d ":" -f 1)
ethtool -K $DEV ${OFFLOAD} off

# Reduce RX buffer length to 2048
ethtool -G $DEV rx-buf-len 2048

Menjalankan aplikasi DPDK

Untuk menggunakan PMD AF_XDP, sertakan flag --vdev dalam argumen Environment Abstraction Layer (EAL) aplikasi DPDK Anda.

Contoh perintah berikut mencakup beberapa parameter utama. Untuk mengetahui informasi mendetail tentang penyiapan dan parameter, lihat Driver Mode Polling AF_XDP dalam dokumentasi DPDK.

DPDK_APPLICATION -a PCIE_BDF \
  --vdev=net_af_xdp,iface=NIC_NAME,queue_count=NUM_SOCKETS,start_queue=START_QUEUE,xdp_prog=XDP_PROG \
  -- APPLICATION_ARGS

Ganti kode berikut:

  • DPDK_APPLICATION: biner aplikasi DPDK yang akan dijalankan.
  • PCIE_BDF: alamat PCI antarmuka jaringan. Anda dapat menemukan nilai ini dengan menjalankan ethtool -i NIC_NAME dan memeriksa nilai bus-info, seperti 0000:00:04.0.
  • NIC_NAME: nama OS antarmuka jaringan, seperti eth1.
  • NUM_SOCKETS: jumlah soket AF_XDP yang akan dibuka. Setiap soket terlampir ke satu pasangan antrean. Nilai ini harus cocok dengan jumlah antrean yang Anda konfigurasi di antarmuka.
  • START_QUEUE: indeks antrean awal untuk soket AF_XDP.
  • XDP_PROG: program XDP kustom yang akan dijalankan pada paket yang diterima. Jika dihilangkan, DPDK akan menggunakan program XDP default yang disediakan oleh libxdp.
  • APPLICATION_ARGS: argumen khusus untuk aplikasi DPDK Anda.

Menggunakan fitur driver

Bagian ini memberikan informasi penggunaan untuk pengarahan alur dan stempel waktu RX.

Pengarahan alur

Anda dapat menggunakan pengarahan alur dengan XDP untuk mengarahkan paket aplikasi ke subset antrean tertentu, sehingga antrean yang tersisa dapat digunakan untuk traffic kernel. Bagian berikut menjelaskan dua pendekatan yang dapat Anda gunakan untuk pemrograman aturan alur.

Memprogram pengarahan alur terlebih dahulu (direkomendasikan)

Karena pemrograman alur langsung menggunakan panggilan ioctl tidak didukung oleh PMD AF_XDP dan memerlukan modifikasi aplikasi DPDK Anda, sebaiknya program aturan alur Anda terlebih dahulu menggunakan ethtool sebelum memulai aplikasi.

Misalnya, untuk memprogram aturan alur yang mengarahkan traffic UDP IPv4 ke antrean 0:

ethtool -N NIC_NAME flow-type udp4 \
  dst-ip DST_IP dst-port DST_PORT action 0 loc 0

Ganti kode berikut:

  • NIC_NAME: nama OS antarmuka jaringan, seperti eth1.
  • DST_IP: alamat IP tujuan traffic yang akan diarahkan.
  • DST_PORT: port tujuan traffic yang akan diarahkan.

Memprogram aturan alur langsung

PMD AF_XDP tidak mendukung pemrograman alur langsung. Untuk menggunakan metode ini, Anda harus mengubah aplikasi DPDK untuk mengirim panggilan ioctl ethtool secara manual.

Sebaiknya hindari pendekatan ini kecuali jika aplikasi Anda menangani sejumlah besar koneksi sementara. gVNIC mendukung hingga 20.000 aturan pengarahan alur 3-tuple; jika Anda memerlukan lebih sedikit aturan dan mengetahui alamat IP dan port tujuan Anda terlebih dahulu, program aturan Anda terlebih dahulu.

Jika Anda harus memprogram aturan secara dinamis, lihat contoh kode C berikut:

Luaskan untuk melihat contoh kode C

struct flow_rule_info {
  uint32_t src_ip;
  uint32_t dst_ip;
  uint16_t src_port;
  uint16_t dst_port;
  uint32_t target_queue;
  uint32_t rule_id;
}

int add_flow_rule(const char *ifname,
                  struct flow_rule_info *rule_info,
                  bool is_5tuple) {
  struct ethtool_rxnfc cmd;
  struct ifreq ifr;
  int fd;

  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd < 0) {
    fprintf(stderr, "Failed to open socket: %s", strerror(fd));
    return -1;
  }

  memset(&cmd, 0, sizeof(cmd));
  memset(&ifr, 0, sizeof(ifr));

  cmd.cmd = ETHTOOL_SRXCLSRLINS;
  cmd.fs.flow_type = UDP_V4_FLOW;

  cmd.fs.h_u.udp_ip4_spec.ip4dst = rule_info->dst_ip;
  cmd.fs.h_u.udp_ip4_spec.pdst = htons(rule_info->dst_port);
  cmd.fs.m_u.udp_ip4_spec.ip4dst = 0xFFFFFFFF;
  cmd.fs.m_u.udp_ip4_spec.pdst = 0xFFFF;

  if (is_5tuple) {
    cmd.fs.h_u.udp_ip4_spec.ip4src = rule_info->src_ip;
    cmd.fs.h_u.udp_ip4_spec.psrc = htons(rule_info->src_port);
    cmd.fs.m_u.udp_ip4_spec.ip4src = 0xFFFFFFFF;
    cmd.fs.m_u.udp_ip4_spec.psrc = 0xFFFF;
  }

  cmd.fs.ring_cookie = rule_info->target_queue;
  cmd.fs.location = rule_info->rule_id;

  strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
  ifr.ifr_data = (void *)&cmd;

  int ret = ioctl(fd, SIOCETHTOOL, &ifr);
  if (ret)
    fprintf(stderr, "Failed to send ioctl: %s\n", strerror(errno));
  close(fd);

  return ret;
}

int try_add_xdp_flow_rule(int port, struct flow_rule_info *rule_info) {
  char dev_name[RTE_ETH_NAME_MAX_LEN];
  char *af_xdp_driver = "net_af_xdp";
  struct rte_eth_dev_info dev_info;
  int err;

  if (!rte_eth_dev_is_valid_port(port)) return -1;

  err = rte_eth_dev_info_get(port, &dev_info);
  if (err) {
    fprintf(stderr, "Error getting info for port %d: %s\n", port,
            strerror(err));
    return retval;
  }

  if (strncmp(dev_info.driver_name, af_xdp_driver,
              strlen(af_xdp_driver)) != 0) {
    fprintf(stderr, "Not an AF_XDP vdev!\n");
    return -EINVAL;
  }

  err = rte_eth_dev_get_name_by_port(port, dev_name);
  if (retval) {
    fprintf(stderr, "Failed to get dev_name: %s\n", strerror(err));
    return retval;
  }

  /* replace ens4 with correct ifname; must be passed in as application argument */
  err = add_flow_rule("ens4", rule_info));
  if (err)
    fprintf("Failed to add flow rule: %s\n", strerror(err));
  return err;
}

/* From somewhere in the application: */
int application_func(...) {
  ...

  struct flow_rule_info *rule_info {
    .src_ip = 0x0a000001,
    .dst_ip = 0x0a000002,
    .src_port = 0x1110,
    .uint16_t dst_port = 0x1011,
    .uint32_t target_queue = 0,
    .uint32_t rule_id = 1,
  };
  try_add_xdp_flow_rule(xdp_port_id, &rule_info, /*is_5tuple=*/false);
  ...
}

Pemrograman RSS

Saat menggunakan pengarahan alur, RSS dapat membantu memberikan isolasi traffic yang lebih baik. Seperti pengarahan alur, Anda dapat mengonfigurasi RSS menggunakan ethtool. Sebaiknya konfigurasi RSS sebelum menjalankan aplikasi Anda.

Contoh berikut menunjukkan cara mengonfigurasi RSS agar berfungsi dengan AF_XDP:

# Example: Kernel queues 0-3, XDP queues 4-7
NUM_SOCKETS=4 bash prep_xdp.sh eth0

# Program flow rules
ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_0 action 4 loc 0
ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_1 action 5 loc 1
ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_2 action 6 loc 2
ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_3 action 7 loc 3
# If there are more ports that the application polls on, flow rules can be added in a round-robin fashion in a script.

# Program RSS
ethtool -X eth0 start 0 equal 4

# Run the application
./path/to/application -a 0000:00:03.0 --vdev net_af_xdp,iface=eth0,start_queue=4,queue_count=4 -- APPLICATION_ARGS

Stempel waktu RX

Meskipun stempel waktu RX tidak didukung di repositori DPDK upstream untuk PMD AF_XDP, Anda dapat menggunakan stempel waktu RX dengan melakukan hal berikut:

  1. Terapkan patch yang diperlukan ke pohon sumber DPDK dan kompilasi ulang sumber DPDK dan aplikasi Anda. Patch ini menambahkan dukungan untuk rte_eth_read_clock dan stempel waktu RX di mbufs yang diterima.

  2. Gunakan program XDP yang memuat stempel waktu ke dalam metadata.

  3. Berikan parameter vdev AF_XDP tambahan berikut saat memulai aplikasi DPDK Anda:

    • xdp_meta_rx_ts_offset: offset byte dari awal metadata XDP tempat nilai stempel waktu RX 64-bit berada.
    • xdp_meta_valid_hint_offset: (Opsional) offset byte yang mencakup kolom flag 1 byte yang menunjukkan apakah stempel waktu valid.
    • xdp_meta_rx_ts_valid_mask: (Opsional) bitmask yang digunakan untuk mengekstrak bit flag yang valid.

      Jika ctx adalah awal metadata, nilai (ctx->data_meta + xdp_meta_valid_hint_offset) & xdp_meta_rx_ts_valid_mask akan menjelaskan apakah stempel waktu valid.

Langkah berikutnya