Skip to main content

OVS Phần 14: DPDK — Userspace Datapath Tăng Tốc, Khi Nào Thật Sự Cần

Phần 14/21 trong loạt Open vSwitch (OVS) — nối tiếp Phần 13, nơi Mục 2 đã dùng đúng lệnh sudo ovs-vsctl get bridge br0 datapath_type để phân biệt một bridge đang chạy kernel datapath (trả về chuỗi rỗng, tương đương system) hay userspace datapath (trả về netdev). Bài 14 đào sâu đúng nhánh netdev đó, khi nó được tăng tốc bằng DPDK — công nghệ đã được nhắc tên (chưa giải thích) từ Bài 3. Đây là bài thứ ba của Module 3 — Nâng cao, sau OpenFlow pipeline sâu (Bài 12) và connection tracking (Bài 13). Sau bài này, Bài 15 sẽ chuyển sang hardware offload (TC flower, SmartNIC) — bước tiếp theo tự nhiên khi ngay cả DPDK cũng chưa đủ, cần đẩy hẳn việc forward xuống phần cứng chuyên dụng.

Mục tiêu bài học: sau bài này bạn phân biệt được chính xác vị trí của DPDK trong ba loại datapath đã học ở Bài 3, hiểu đúng cơ chế poll-mode driver (PMD) và việc bypass kernel network stack khiến đường đi packet nhanh hơn, nắm được các yêu cầu hạ tầng bắt buộc (hugepages, NIC hỗ trợ PMD, CPU core cô lập) cùng tên cột cấu hình chính xác trong OVSDB (dpdk-init, pmd-cpu-mask, dpdk-socket-mem...), và tự đánh giá được khi nào DPDK đáng đánh đổi, khi nào không.

Ba câu hỏi mà bài này trả lời:

  1. DPDK nằm ở đâu trong ba loại datapath đã học ở Bài 3, và vì sao nó không phải một datapath thứ tư tách biệt?
  2. Cơ chế nào (poll-mode driver, bypass kernel) khiến đường đi packet qua DPDK nhanh hơn userspace thường, và đổi lại phải trả giá gì?
  3. Yêu cầu hạ tầng tối thiểu để bật được OVS-DPDK là gì, và khi nào việc không dùng DPDK mới là lựa chọn đúng?

Mục lục


1. Ba loại datapath: định vị DPDK trong bức tranh đã học ở Bài 3

Bài 3 đã liệt kê bảng ba cấu hình datapath phổ biến — nhắc lại nguyên văn để bài này có điểm tựa chính xác, không phải nhớ lại mơ hồ:

Loại datapathdatapath_type khi tạo bridgeThực thi ở đâu
Kernelsystem (hoặc để trống — Bài 13 đã xác nhận chuỗi rỗng tương đương system)Module kernel openvswitch.ko
Userspace thuầnnetdevHoàn toàn trong tiến trình ovs-vswitchd (dpif-netdev), không cần nạp kernel module
Userspace + DPDKnetdev (giống trên) + port khai type=dpdkVẫn dpif-netdev, nhưng port đọc/ghi thẳng NIC qua poll-mode driver DPDK

Điểm quan trọng nhất — đúng thứ Bài 3 đã cảnh báo trước và Bài 13 xác nhận lại bằng nguồn chính thức khác: userspace thuần và userspace+DPDK dùng chung một giá trị datapath_type=netdev, không có giá trị datapath_type=dpdk riêng. Tài liệu Releases FAQ mô tả đúng một datapath userspace duy nhất, DPDK chỉ là một trong các loại thiết bị nó hỗ trợ: "This datapath supports conventional system devices as well as DPDK and AF_XDP devices when support for those is built. This is the only datapath that works on NetBSD, FreeBSD and Mac OSX." Nói cách khác: bật DPDK không đổi datapath_type, mà đổi loại port bạn thêm vào một bridge netdev đã có sẵn — chi tiết cú pháp ở Mục 4.

Cũng cần nhắc lại đúng cảnh báo Bài 1 và Bài 13 đã trích từ tài liệu chính thức, vì nó dễ bị nhầm với DPDK: "Open vSwitch with userspace datapath and non DPDK devices is considered experimental and comes with a cost in performance." — userspace không DPDK (dùng NIC thường qua AF_PACKET/tap) là thử nghiệm và chậm; userspace DPDK mới là cấu hình được thiết kế để chạy production ở throughput cao, đúng chủ đề bài này.

Về mặt lịch sử hỗ trợ, DPDK không phải bổ sung mới — bảng tương thích chính thức trong Releases FAQ liệt kê ngược tới tận OVS 2.2.x build cùng DPDK 1.6, và mỗi nhánh OVS từ đó tới nay (bản mới nhất trong bảng: OVS 4.0.x với DPDK 25.11.2) đều ghi rõ đúng một phiên bản DPDK tương thích để build cùng.


2. Vì sao DPDK nhanh hơn: poll-mode driver và bypass kernel network stack

💡 Hình dung như thế này: driver kernel thường giống một nhân viên trực tổng đài — ngồi yên, không làm gì cả, chỉ nhấc máy khi chuông reo (ngắt phần cứng/interrupt báo có gói tới), xử lý xong lại ngồi yên chờ tiếp. Một PMD (poll-mode driver) thread giống một nhân viên đứng ngay cạnh cửa, cứ vài micro giây lại hé mắt nhìn ra ngoài xem có ai đến chưa — dù không có ai bấm chuông, không có tín hiệu báo nào cả, nhân viên đó vẫn liên tục "tự đi hỏi" thay vì đợi được gọi. Cách thứ hai tốn sức hơn hẳn nếu không có khách, nhưng khi khách đến dồn dập, nhân viên đó phản ứng ngay lập tức — không mất thời gian chờ chuông reo, xử lý ngắt, đánh thức CPU.

Đây đúng là cơ chế thật, không phải phép ẩn dụ suông. Tài liệu chính thức của dự án DPDK định nghĩa PMD bằng đúng thuật ngữ "không dùng ngắt": "The DPDK includes Poll Mode Drivers (PMDs) for 1 GbE, 10 GbE and 40 GbE, and para virtualized virtio Ethernet controllers which are designed to work without asynchronous, interrupt-based signaling mechanisms." Tài liệu PMD Threads của chính OVS mô tả công việc cụ thể của một PMD thread: "Poll Mode Driver (PMD) threads are the threads that do the heavy lifting for userspace switching. They perform tasks such as continuous polling of input ports for packets, classifying packets once received, and executing actions on the packets once they are classified." — ba việc: poll liên tục, phân loại packet, thực thi action, tất cả chạy trong đúng một vòng lặp userspace, không có bước "chờ kernel báo".

Vế thứ hai của tốc độ — bypass kernel network stack — nằm ở cách NIC được gắn vào hệ thống. Với datapath kernel, NIC dùng driver kernel thông thường (ví dụ ixgbe, i40e), packet phải đi qua toàn bộ kernel network stack trước khi tới được openvswitch.ko. Với DPDK, NIC được bind trực tiếp vào userspace qua UIO hoặc VFIO thay vì driver kernel thông thường — tài liệu cài đặt chính thức khuyến nghị VFIO cho bản DPDK mới: "VFIO is preferred to the UIO driver when using recent versions of DPDK." Một khi NIC đã bind qua VFIO, kernel network stack hoàn toàn không còn tham gia vào đường đi của packet đó nữa — PMD thread trong chính tiến trình ovs-vswitchd đọc/ghi thẳng bộ nhớ NIC.

Tài liệu cài đặt DPDK mô tả đúng công việc và bản chất "CPU bound" của một PMD thread: "A poll mode driver (pmd) thread handles the I/O of all DPDK interfaces assigned to it. A pmd thread shall poll the ports for incoming packets, switch the packets and send to tx port. A pmd thread is CPU bound, and needs to be have affinity set to isolated cores for optimum performance. Even though a PMD thread may exist, the thread only starts consuming CPU cycles if there is at least one receive queue assigned to the pmd." — câu cuối đáng chú ý: một PMD thread tồn tại không có nghĩa nó tự động tốn CPU, chỉ khi có ít nhất một Rx queue được gán cho nó thì việc poll liên tục mới thật sự bắt đầu (và từ đó dẫn thẳng tới cái giá phải trả ở Mục 5).

Đường Đi Packet: Kernel Datapath So Với Userspace + DPDKDPDK không phải datapath thứ ba — vẫn là datapath userspace (netdev) của Bài 3, chỉ đổi cách đọc NICKernel datapath (datapath_type=system)Userspace + DPDK (netdev, port type=dpdk)NIC vật lý nhận góiNIC vật lý nhận gói (PMD-capable)Ngắt phần cứng (interrupt) đánh thứcCPU, driver kernel xử lý (ixgbe, i40e)Không ngắt — NIC bind qua UIO/VFIOthẳng vào tiến trình ovs-vswitchdKernel network stack chuyển góivào openvswitch.koPMD thread trong ovs-vswitchdliên tục poll NIC (Mục 2)openvswitch.ko tra datapath flow —chỉ 1 tầng megaflow (Bài 3)dpif-netdev tra EMC rồi megaflowngay trong userspace (Bài 3)Forward ra port đích — vẫn đúng OpenFlow pipeline đã học (Bài 6, 12)Khác biệt cốt lõi: DPDK bỏ hẳn "đường vòng" qua driver kernel + ngắt, đổi lại bằng core CPU polling liên tục (Mục 5)

3. Yêu cầu hạ tầng: hugepages, NIC hỗ trợ PMD, CPU core cô lập

Ba yêu cầu bắt buộc, không có cái nào tùy chọn nếu muốn DPDK chạy đúng:

Ba Yêu Cầu Hạ Tầng Bắt Buộc — Thiếu Một Là Không Chạy ĐúngHugepagesNIC hỗ trợ PMDCPU core cô lập2MB (hoặc 1GB) thaypage 4KB mặc địnhGiảm TLB miss khiPMD truy cập bufferpacket liên tụcMỗi model NIC cầnđúng PMD driver riêngBind qua UIO/VFIOthay driver kernel(ixgbe, i40e...)isolcpus tách corekhỏi Linux schedulerDành riêng cho PMDthread — nên cùngNUMA node với NICThiếu một trong ba → dpdk_initialized=false, hoặc chạy được nhưng sai hiệu năng kỳ vọng(lệch NUMA giữa core và NIC không làm DPDK từ chối chạy, chỉ âm thầm giảm throughput)

Hugepages. Tài liệu cài đặt chính thức yêu cầu cấp phát trước một số lượng huge page 2MB: "Allocate a number of 2M Huge pages", và lưu ý lượng bộ nhớ cần cấp phát không cố định: "The amount of hugepage memory required can be affected by various aspects of the datapath and device configuration." Lý do kỹ thuật đứng sau yêu cầu này được chính tài liệu hệ thống của dự án DPDK giải thích rõ, gắn trực tiếp với TLB (Translation Lookaside Buffer — bộ nhớ đệm dịch địa chỉ ảo sang địa chỉ vật lý ngay trong CPU): "By using hugepage allocations, performance is increased since fewer pages are needed, and therefore less Translation Lookaside Buffers (TLBs, high speed translation caches), which reduce the time it takes to translate a virtual page address to a physical page address. Without hugepages, high TLB miss rates would occur with the standard 4k page size, slowing performance." Nói ngắn gọn: PMD thread liên tục truy cập một vùng bộ nhớ lớn cho buffer packet; nếu dùng page 4KB tiêu chuẩn, số lượng entry cần tra trong TLB tăng vọt, miss liên tục, mỗi lần miss lại tốn thời gian đi tra bảng trang đầy đủ — hugepage (2MB hoặc 1GB) giảm hẳn số page cần theo dõi, giữ TLB hit cao.

NIC hỗ trợ PMD. DPDK không tự chạy được trên mọi NIC — mỗi NIC vật lý cần đúng một PMD driver tương ứng do dự án DPDK hoặc vendor cung cấp. Bằng chứng trực tiếp từ cấu hình OVS: cột options:dpdk-devargs của Interface — nơi khai địa chỉ PCI của NIC muốn gán làm port DPDK — chỉ có tác dụng "Only supported by the dpdk port type", và tài liệu FAQ nhắc thẳng: "DPDK devices will not be available for use until a valid dpdk-devargs is specified." Danh sách NIC được hỗ trợ cụ thể (Intel, Mellanox, Broadcom...) thay đổi theo từng bản DPDK và nằm ngoài phạm vi bài này — điều cần nhớ là khái niệm, không phải danh sách: trước khi lên kế hoạch OVS-DPDK, phải xác nhận đúng model NIC đang có nằm trong danh sách PMD hỗ trợ của đúng bản DPDK mà bản OVS đang dùng được build cùng (bảng tương thích OVS–DPDK đã trích ở Mục 1).

Trước khi sang yêu cầu thứ ba, cần dừng lại giải nghĩa một khái niệm đã xuất hiện ngầm trong bảng cột other_config ở Mục 4 (pmd-cpu-mask gán "one pmd thread... for each numa node") nhưng chưa được định nghĩa: NUMA (Non-Uniform Memory Access) — kiến trúc máy chủ nhiều CPU socket, trong đó mỗi socket có một dải RAM "gắn liền" (local) với nó; một core truy cập RAM thuộc socket khác (remote) luôn chậm hơn truy cập RAM local. Với DPDK, NIC vật lý cũng "thuộc về" đúng một NUMA node (tùy khe PCIe cắm vào), và tài liệu cài đặt chính thức cảnh báo thẳng hậu quả khi PMD thread và NIC lệch NUMA node: "On NUMA systems, PCI devices are also local to a NUMA node. Unbound rx queues for a PCI device will be assigned to a pmd on it's local NUMA node if a non-isolated PMD exists on that NUMA node. If not, the queue will be assigned to a non-isolated pmd on a remote NUMA node. This will result in reduced maximum throughput on that device and possibly on other devices assigned to that pmd thread." Đây chính xác là lý do dpdk-socket-mem bắt buộc cấp phát hugepage riêng theo từng socket (Mục 4) thay vì một cục bộ nhớ chung — và lý do pmd-cpu-mask nên chọn core cùng NUMA node với NIC đang dùng, không phải core bất kỳ.

CPU core cô lập. Tài liệu cài đặt gợi ý dùng tham số kernel isolcpus để tách hẳn một số core ra khỏi bộ lập lịch (scheduler) của Linux: "The isolcpus option can be used to isolate cores from the Linux scheduler. The isolated cores can then be used to dedicatedly run HPC applications or threads. This helps in better application performance due to zero context switching and minimal cache thrashing. To run platform logic on core 0 and isolate cores between 1 and 19 from scheduler, add isolcpus=1-19 to GRUB cmdline." Đáng chú ý, tài liệu tự thêm một lưu ý làm giảm bớt tính tuyệt đối của khuyến nghị này: "It has been verified that core isolation has minimal advantage due to mature Linux scheduler in some circumstances." — tức isolcpus là thực hành tốt (best practice) để tránh core PMD bị scheduler tranh chấp với tiến trình khác, nhưng không phải lúc nào cũng tạo ra khác biệt lớn, tùy khối lượng công việc thật trên máy.


4. Cấu hình thật: bridge netdev, port dpdk, other_config

Toàn bộ cấu hình DPDK nằm trong cột other_config của bảng Open_vSwitch (không phải bảng Bridge hay Interface) — trích đúng tên cột và mô tả từ ovs-vswitchd.conf.db(5):

Cột other_configÝ nghĩa (trích nguyên văn ovs-vswitchd.conf.db(5))
dpdk-init"Set this value to true or try to enable runtime support for DPDK ports... A value of true will cause the ovs-vswitchd process to abort if DPDK cannot be initialized. A value of try will allow the ovs-vswitchd process to continue running even if DPDK cannot be initialized. The default value is false."
dpdk-lcore-mask"Specifies the CPU cores where dpdk lcore threads should be spawned... Value should be in the form of a hex string (so '0x123') similar to the 'taskset' mask input."
pmd-cpu-mask"Specifies CPU mask for setting the cpu affinity of PMD (Poll Mode Driver) threads... If not specified, one pmd thread will be created for each numa node and pinned to any available core on the numa node by default."
dpdk-socket-mem"Specifies the amount of memory to preallocate from the hugepage pool, on a per-socket basis. The specifier is a comma-separated string, in ascending order of CPU socket."
dpdk-hugepage-dir"Specifies the path to the hugetlbfs mount point. If not specified, this will be guessed by the DPDK library (default is /dev/hugepages)."
dpdk-extra"Specifies additional eal command line arguments for DPDK. The default is empty."

Ba cột đầu là ba thứ thường gõ nhầm lẫn nhau khi mới học nên cần tách rõ: dpdk-init chỉ bật/tắt DPDK; dpdk-lcore-mask cấp core cho các lcore thread nội bộ của thư viện DPDK (message processing, logging — không phải core forward packet, tài liệu ghi rõ "As OVS implements its own threading for the datapath (see other_config:pmd-cpu-mask), DPDK worker threads will be unused"); còn pmd-cpu-mask mới thật sự là cột cấp core cho PMD thread forward packet — đúng chủ thể của toàn bộ Mục 2, 3, 5 bài này.

Ở tầng Interface, cột thêm một port kiểu DPDK dùng type=dpdk cùng options:dpdk-devargs: "Specifies the PCI address associated with the port for physical devices, or the virtual driver to be used for the port when a virtual PMD is intended to be used... Only supported by the dpdk port type." Cú pháp thật, theo đúng ví dụ trong tài liệu cài đặt chính thức:

# Bật DPDK ở tầng Open_vSwitch — bắt buộc trước tiên
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true

# Cấp phát bộ nhớ hugepage cho socket 0 (ví dụ máy 1 socket)
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,0"

# Cấp core cho PMD thread — 0xc = core 2 và 3 (bit 2, bit 3)
sudo ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0xc

# Tạo bridge dùng datapath userspace — bắt buộc trước khi thêm port dpdk
sudo ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev

# Thêm port dpdk, gán đúng địa chỉ PCI của NIC hỗ trợ PMD
sudo ovs-vsctl add-port br0 dpdk-p0 -- set Interface dpdk-p0 type=dpdk options:dpdk-devargs=0000:06:00.0

dpdk-init được ghi rõ "Changing this value requires restarting the daemon" — đổi giá trị này không có hiệu lực ngay, phải khởi động lại ovs-vswitchd. Sau khi khởi động lại, xác nhận DPDK đã khởi tạo thành công bằng đúng hai cột trạng thái (không phải other_config, đây là cột do OVS tự cập nhật) trong bảng Open_vSwitch: dpdk_initialized"True if other_config:dpdk-init is set to true and the DPDK library is successfully initialized" — và dpdk_version"The version of the linked DPDK library."


5. Đánh đổi CPU và khi nào không cần DPDK

Đây là phần dễ bị bỏ qua nhất khi chỉ đọc lướt phần "cấu hình" ở Mục 4: một core được gán cho PMD không còn dùng được cho việc gì khác, kể cả khi hoàn toàn không có traffic. Tài liệu PMD Threads của OVS xác nhận thẳng hành vi mặc định: "PMD threads constantly poll Rx queues which are assigned to them." — "constantly" ở đây không phải cách nói cường điệu, mà là mô tả đúng vòng lặp: PMD thread không có khái niệm "rảnh thì nghỉ" tự nhiên.

Bằng chứng cụ thể hơn nằm ở chính cột cấu hình được thêm vào để giảm bớt hành vi này — other_config:pmd-sleep-max, quy định thời gian ngủ tối đa (micro giây) khi Rx queue không có gói. Giá trị mặc định của cột này được ovs-vswitchd.conf.db(5) ghi rất rõ: "The default value is 0 microseconds, which means that the PMD will not sleep regardless of the load from the Rx queues that it polls." Nói cách khác: nếu không chủ động cấu hình pmd-sleep-max lớn hơn 0, mặc định PMD thread giữ nguyên vòng lặp poll liên tục dù Rx queue có gói hay không — đúng như phần "CPU bound" đã trích ở Mục 2 ("A pmd thread is CPU bound, and needs to be have affinity set to isolated cores for optimum performance"). Đây chính là lý do Mục 3 khuyến nghị isolcpus: core đó cần bị tách hẳn khỏi scheduler thông thường vì nó sẽ không bao giờ "nhường" CPU một cách tự nhiên như một tiến trình bình thường.

PMD Poll Liên Tục Thay Vì Đợi Ngắt (Interrupt)Mặc định pmd-sleep-max = 0 — core PMD giữ tải cao bất kể có traffic hay khôngCPU core thường (interrupt-driven)CPU core cô lập, gán pmd-cpu-maskNIC rảnh → core ở trạng thái nghỉ,gần như 0% tải"constantly poll Rx queues" →gần như luôn ở mức tải caoGói đến → ngắt đánh thứcCPU để xử lýKhông traffic vẫn poll tiếp —trừ khi cấu hình pmd-sleep-max > 0Xử lý xong → nghỉ lại,nhường CPU cho tiến trình khácCore bị isolcpus khỏi scheduler —không chia sẻ được cho việc khácMặc định pmd-sleep-max=0: "the PMD will not sleep regardless of the load from the Rx queues that it polls"→ Đánh đổi: core PMD "hi sinh" hẳn cho OVS — chỉ đáng nếu traffic đủ cao để bù lại

Vậy khi nào không đáng đánh đổi một core CPU nguyên vẹn để lấy tốc độ đó?

  • Traffic thấp hoặc không nhạy cảm latency/throughput ở mức line-rate 10G trở lên — nếu userspace thuần (hoặc thậm chí kernel datapath) đã đủ đáp ứng nhu cầu thật, dành hẳn một core chạy 100% chỉ để tiết kiệm vài micro giây mỗi packet là lãng phí tài nguyên không cần thiết.
  • Môi trường lab/dev — đúng bối cảnh các bài trước của series (veth, network namespace): những interface đó không phải thiết bị PCI thật, không có PMD driver tương ứng, DPDK không chạy được trên chúng theo cách thông thường (ngoại trừ các loại virtual PMD chuyên dụng như vhost-user cho VM, nằm ngoài phạm vi lab CLI đơn giản).
  • Máy nhiều dịch vụ chia sẻ, ít core dư — nếu không thể tách riêng ít nhất 1-2 core hẳn cho PMD mà không ảnh hưởng tới workload khác trên cùng máy, chi phí cơ hội của việc "khóa cứng" core đó thường lớn hơn lợi ích tốc độ mang lại.

Về con số hiệu năng cụ thể, tài liệu chính thức của cả OVS lẫn DPDK không công bố một benchmark phổ quát nào để trích dẫn ở đây — hiệu năng cụ thể tùy phần cứng (NIC, CPU, số core PMD, kích thước gói), cần tự benchmark trên đúng phần cứng dự định triển khai, không có một con số Mpps hay % cải thiện áp dụng chung cho mọi trường hợp.

Nếu chỉ nhớ được một điều sau bài này, hãy nhớ: DPDK không phải một "công tắc tăng tốc" miễn phí — nó đổi lấy tốc độ bằng cách bắt một hoặc nhiều core CPU poll liên tục, mặc định không bao giờ ngủ (pmd-sleep-max=0), bất kể có traffic hay không, và đường đi nhanh hơn đó chỉ đến từ đúng hai cơ chế cụ thể — poll-mode driver thay cho ngắt, và NIC bind thẳng vào userspace qua UIO/VFIO thay cho kernel network stack. Trước khi bật dpdk-init=true, luôn tự hỏi: traffic thật sự có đủ lớn để bù lại một core bị "khóa cứng" vĩnh viễn hay không.


6. Walkthrough CLI dựa trên docs chính thức

Khác với phần lớn CLI lab trước đó của series (dựng trên veth/network namespace, chạy được ngay trên bất kỳ máy Linux nào), phần này không phải một lab chạy được trên môi trường ảo thông thường — DPDK cần NIC vật lý có PCI address thật, driver PMD tương ứng, và hugepage đã cấp phát ở tầng hệ điều hành, những thứ veth/namespace không đáp ứng được (veth không phải thiết bị PCI, không có PMD driver để bind). Toàn bộ các bước dưới đây là walkthrough dựa trên đúng cú pháp trong tài liệu chính thức (Mục 3, 4 đã trích), khuyến nghị test trên phần cứng thật trước khi đưa vào production. Mọi output đều là minh họa dựa trên docs chính thức, chưa test trên phần cứng thật trong bài này.

Sáu Bước Walkthrough — Từ Hạ Tầng Tới PMD Chạy ThậtDựa trên docs chính thức — khuyến nghị test trên phần cứng thậtBước 1Hugepage + bind NIC(tầng OS, trước OVS)Bước 2dpdk-init=true +pmd-cpu-mask (OVSDB)Bước 3verifydpdk_initialized=trueBước 4bridge netdev +port type=dpdkBước 5pmd-rxq-show — PMDnào đang poll core nàoBước 6pmd-perf-show — %sleep, thống kê PMDveth/namespace không dùng được ở đây — cần PCI thật, PMD driver thật, hugepage đã cấp phát

Bước 1 — chuẩn bị hugepages và bind NIC (thực hiện ở tầng hệ điều hành, trước khi đụng tới OVS):

# Cấp phát 1024 huge page 2MB (persistent, ghi vào sysctl.d)
echo 'vm.nr_hugepages=1024' | sudo tee /etc/sysctl.d/hugepages.conf
sudo sysctl -w vm.nr_hugepages=1024

# Xác nhận đã cấp phát
grep HugePages_ /proc/meminfo

# Mount hugetlbfs nếu chưa mount sẵn
sudo mount -t hugetlbfs none /dev/hugepages

# Bind NIC vào VFIO thay vì driver kernel thường (ví dụ NIC tại 0000:06:00.0)
sudo modprobe vfio-pci
sudo dpdk-devbind.py --bind=vfio-pci 0000:06:00.0
# Output minh họa — dựa trên docs.openvswitch.org/en/latest/intro/install/dpdk/, chưa test trên phần cứng thật
HugePages_Total: 1024
HugePages_Free: 1024
HugePages_Rsvd: 0
HugePages_Surp: 0

Bước 2 — bật DPDK và cấu hình core cho ovs-vswitchd:

sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,0"
sudo ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0xc
sudo systemctl restart openvswitch-switch # dpdk-init yêu cầu restart daemon (Mục 4)

Bước 3 — xác nhận DPDK đã khởi tạo thành công qua hai cột trạng thái:

sudo ovs-vsctl get Open_vSwitch . dpdk_initialized
sudo ovs-vsctl get Open_vSwitch . dpdk_version
# Output minh họa — cấu trúc đúng theo cột thật trong ovs-vswitchd.conf.db(5), chưa test trên phần cứng thật
true
"DPDK 23.11.0"

Nếu bước này trả về false, đúng theo hành vi đã trích ở Mục 4: nếu dpdk-init=true mà DPDK không khởi tạo được (thiếu hugepage, sai driver NIC...), ovs-vswitchd sẽ abort hẳn — kiểm tra log daemon (journalctl -u openvswitch-switch) để biết chính xác bước nào thất bại trước khi thử lại.

Bước 4 — tạo bridge netdev và thêm port dpdk:

sudo ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev
sudo ovs-vsctl add-port br0 dpdk-p0 -- set Interface dpdk-p0 type=dpdk options:dpdk-devargs=0000:06:00.0
sudo ovs-vsctl get bridge br0 datapath_type
# Output minh họa — datapath_type đúng theo cách kiểm tra đã học ở Bài 13
"netdev"

Bước 5 — xem PMD thread đang chạy và Rx queue được gán cho core nào:

sudo ovs-appctl dpif-netdev/pmd-rxq-show
sudo ovs-appctl dpdk/lcore-list
# Output minh họa — cấu trúc đúng theo ovs-vswitchd(8), số liệu tùy máy, chưa test trên phần cứng thật
pmd thread numa_id 0 core_id 2:
isolated : true
port: dpdk-p0 queue-id: 0 pmd usage: 0 %
pmd thread numa_id 0 core_id 3:
isolated : false

Bước 6 — xem thống kê hiệu năng chi tiết của từng PMD thread:

sudo ovs-appctl dpif-netdev/pmd-stats-clear
sudo ovs-appctl dpif-netdev/pmd-perf-show

Kết hợp đúng cách tài liệu PMD Threads minh họa để quan sát tác động của pmd-sleep-max (nếu đã bật khác 0): chạy lại pmd-stats-clear rồi đợi 10 giây trước khi xem pmd-perf-show, phần trăm "sleep iterations" trong output phản ánh đúng tỷ lệ vòng lặp PMD thật sự đã ngủ thay vì poll liên tục — bằng 0 (hoặc gần 0) là dấu hiệu core đó đang chạy đúng hành vi mặc định đã mô tả ở Mục 5.


Bài tập cuối bài

  1. Trên máy hiện có của bạn (không cần NIC hỗ trợ DPDK), tự đánh giá xem máy có đáp ứng được yêu cầu hạ tầng của Mục 3 hay không: chạy lscpu để đếm số core vật lý/logical (từ đó ước lượng có đủ dư core để "hi sinh" cho PMD hay không), chạy grep Hugepagesize /proc/meminfo để xem kích thước hugepage mặc định của kernel, và chạy lspci | grep -i ethernet (hoặc lspci -nn | grep -i net) để liệt kê NIC đang có — sau đó tự tra cứu tên/mã sản phẩm đó trên trang danh sách NIC hỗ trợ của dự án DPDK (https://core.dpdk.org/supported/) để xác nhận có PMD driver tương ứng hay không. Ghi lại kết luận: máy này hay không đủ điều kiện chạy OVS-DPDK thật.
  2. Giả sử máy có 8 core (đánh số 0-7) và bạn muốn dành đúng core 4 và core 5 cho PMD thread, còn lại để hệ thống dùng bình thường. Tự tính giá trị hex đúng cho other_config:pmd-cpu-mask (gợi ý: bit thứ N tương ứng core N, bit đặt = core đó có PMD — đối chiếu lại cách đọc dpdk-lcore-mask/pmd-cpu-mask đã trích ở Mục 4, tương tự cách đọc mask của taskset) và viết ra đúng câu lệnh ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=... để áp giá trị đó.
  3. Đọc lại đúng câu đã trích ở Mục 4: "A value of true will cause the ovs-vswitchd process to abort if DPDK cannot be initialized. A value of try will allow the ovs-vswitchd process to continue running even if DPDK cannot be initialized." Suy luận và viết ra: nếu bạn đang chuẩn bị nâng cấp một bridge production từ kernel datapath sang DPDK, giữa hai giá trị dpdk-init=truedpdk-init=try, giá trị nào an toàn hơn để thử nghiệm lần đầu trên máy chưa chắc chắn đã cấu hình đúng hugepage/NIC, và vì sao.

Nguồn tham khảo

  • NUMA: "On NUMA systems, PCI devices are also local to a NUMA node. Unbound rx queues for a PCI device will be assigned to a pmd on it's local NUMA node if a non-isolated PMD exists on that NUMA node. If not, the queue will be assigned to a non-isolated pmd on a remote NUMA node. This will result in reduced maximum throughput on that device..."Open vSwitch with DPDK, docs.openvswitch.org.
  • Hugepages: "Allocate a number of 2M Huge pages", "The amount of hugepage memory required can be affected by various aspects of the datapath and device configuration"; VFIO: "VFIO is preferred to the UIO driver when using recent versions of DPDK"; isolcpus: "The isolcpus option can be used to isolate cores from the Linux scheduler... add isolcpus=1-19 to GRUB cmdline" kèm lưu ý "core isolation has minimal advantage due to mature Linux scheduler in some circumstances"; PMD affinity: "A poll mode driver (pmd) thread handles the I/O of all DPDK interfaces assigned to it... A pmd thread is CPU bound, and needs to be have affinity set to isolated cores for optimum performance. Even though a PMD thread may exist, the thread only starts consuming CPU cycles if there is at least one receive queue assigned to the pmd"Open vSwitch with DPDK, docs.openvswitch.org.
  • PMD Threads: "Poll Mode Driver (PMD) threads are the threads that do the heavy lifting for userspace switching. They perform tasks such as continuous polling of input ports for packets, classifying packets once received, and executing actions on the packets once they are classified"; "PMD threads constantly poll Rx queues which are assigned to them. In order to reduce the CPU cycles they use, they can sleep for small periods of time when there is no load or very-low load on all the Rx queues they poll"; lệnh ovs-appctl dpif-netdev/pmd-perf-show, pmd-rxq-show, pmd-stats-clearPMD Threads, docs.openvswitch.org.
  • Cột other_config bảng Open_vSwitch: dpdk-init ("Set this value to true or try to enable runtime support for DPDK ports... A value of true will cause the ovs-vswitchd process to abort if DPDK cannot be initialized. A value of try will allow the ovs-vswitchd process to continue running even if DPDK cannot be initialized. The default value is false"), dpdk-lcore-mask, pmd-cpu-mask, dpdk-socket-mem, dpdk-hugepage-dir, dpdk-extra, pmd-sleep-max ("The default value is 0 microseconds, which means that the PMD will not sleep regardless of the load from the Rx queues that it polls"); cột trạng thái dpdk_initialized ("True if other_config:dpdk-init is set to true and the DPDK library is successfully initialized") và dpdk_version; option dpdk-devargs ("Specifies the PCI address associated with the port for physical devices... Only supported by the dpdk port type") — ovs-vswitchd.conf.db(5), openvswitch.org.
  • Lệnh appctl dpif-netdev/pmd-perf-show, dpif-netdev/pmd-rxq-show, dpif-netdev/pmd-stats-clear, dpdk/lcore-listovs-vswitchd(8), openvswitch.org.
  • "Open vSwitch with userspace datapath and non DPDK devices is considered experimental and comes with a cost in performance"What is Open vSwitch?, docs.openvswitch.org.
  • Datapath userspace: "This datapath supports conventional system devices as well as DPDK and AF_XDP devices when support for those is built. This is the only datapath that works on NetBSD, FreeBSD and Mac OSX"; bảng tương thích DPDK theo từng bản OVS, sớm nhất OVS 2.2.x/DPDK 1.6, mới nhất trong bảng OVS 4.0.x/DPDK 25.11.2 — Releases FAQ, docs.openvswitch.org.
  • "The DPDK includes Poll Mode Drivers (PMDs) for 1 GbE, 10 GbE and 40 GbE, and para virtualized virtio Ethernet controllers which are designed to work without asynchronous, interrupt-based signaling mechanisms"Overview — DPDK Programmer's Guide, doc.dpdk.org.
  • "By using hugepage allocations, performance is increased since fewer pages are needed, and therefore less Translation Lookaside Buffers (TLBs, high speed translation caches), which reduce the time it takes to translate a virtual page address to a physical page address. Without hugepages, high TLB miss rates would occur with the standard 4k page size, slowing performance"System Requirements — DPDK Getting Started Guide for Linux, doc.dpdk.org.
  • Ba loại datapath (kernel/userspace/userspace+DPDK) và Exact Match Cache/megaflow đã giới thiệu ở Bài 3; cách kiểm tra datapath_type của một bridge bằng ovs-vsctl get bridge br0 datapath_type đã dùng ở Bài 13.

Tiếp theo: Module 3, Bài 15 — Hardware offload (TC flower, SmartNIC).