Skip to main content

OVS Phần 20: Troubleshooting Nâng Cao — Debug Flow, Datapath, Performance Tuning Thực Chiến

Phần 20/21 trong loạt Open vSwitch (OVS) — nối tiếp Phần 19, bài cuối trước khi series khép lại ở Bài 21 (tổng kết OVS vs fabric vật lý). Suốt 19 bài trước, bạn đã học rải rác gần chục công cụ khác nhau — ovs-vsctl show ở Bài 5, ovs-ofctl dump-flows ở Bài 6, ovs-appctl dpctl/dump-flows ở Bài 3, ofproto/trace ở Bài 12, tcpdump ở Bài 9/13 — mỗi công cụ xuất hiện đúng lúc cần minh họa một khái niệm cụ thể, không có bài nào gộp chúng lại thành một quy trình debug hoàn chỉnh. Bài này làm đúng việc đó: tổng hợp toolbox đã học, đào sâu ba công cụ thật sự mới (vlog/set, coverage/show, ovs-tcpdump), và áp dụng vào hai case study thực chiến. Đọc xong, Bài 21 sẽ chốt lại toàn bộ series bằng câu hỏi kiến trúc: overlay terminate ở OVS hay ở fabric vật lý.

Mục tiêu bài học: sau bài này bạn có trong tay một quy trình debug OVS có thứ tự — từ cấu hình (OVSDB) tới flow (OpenFlow) tới cache datapath tới NIC vật lý — và biết rõ đây là quy trình tự tổng hợp từ đúng kiến trúc series đã dạy, không phải tài liệu chính thức OVS công bố (một sự thật đáng ngạc nhiên: không hề có trang "OVS Troubleshooting Guide" nào trên docs.openvswitch.org); bạn dùng thành thạo ba công cụ mới (vlog/set chỉnh log level, coverage/show/memory/show đọc counter runtime, ovs-tcpdump tự động hóa Mirror của Bài 16); và bạn phân biệt rạch ròi hai thứ hay bị gộp chung dưới cái tên "performance tuning" — bộ công cụ pmd-perf-show chính thức của OVS (chỉ áp dụng DPDK, Bài 14) và perf Linux thuần (kỹ thuật hệ thống chung, không phải khuyến nghị của dự án OVS).

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

  1. OVS có một quy trình debug "chính thức" hay không, và nếu tự tổng hợp một quy trình từ những gì series đã dạy thì quy trình đó là gì?
  2. vlog/set, coverage/show/memory/show, và ovs-tcpdump dùng để làm gì, và chúng khác gì với các công cụ đã học ở Bài 3/6/12/16?
  3. "Performance tuning" trên OVS thực chất có mấy nhánh, nhánh nào có tài liệu chính thức, nhánh nào không?

Mục lục


1. Toolbox đã học rải rác qua các bài trước: tổng hợp theo từng layer

Trước khi thêm bất kỳ công cụ mới nào, hãy nhìn lại đúng những gì series đã trang bị — rải rác qua chín bài khác nhau, chưa bài nào gộp chung thành một bảng. Cột "Layer" dưới đây dùng đúng ba tầng kiến trúc Bài 3 đã dạy (OVSDB → OpenFlow → datapath) cộng thêm tầng NIC vật lý:

Công cụHọc ở đâuKiểm tra layer nàoVai trò đã học
ovs-vsctl show, ovsdb-client dumpBài 5OVSDB (config state)Xem bridge/port/VLAN đã cấu hình đúng ý định chưa
ovs-vsctl get bridge br0 datapath_typeBài 13OVSDBXác nhận đang chạy datapath nào — quyết định công cụ nào dùng được ở bước sau
ovs-ofctl dump-flows, add-flowBài 6OpenFlow (flow state, table=0)Đọc/sửa flow table OpenFlow một bảng
ovs-ofctl -O OpenFlowNN dump-flows (multi-table), goto_table, resubmitBài 12OpenFlow (nhiều bảng)Đọc pipeline nhiều table, hiểu từng cột cookie/duration/idle_age/priority
ovs-appctl ofproto/trace <bridge> <fields>Bài 12OpenFlow (giả lập)Mô phỏng một packet đi qua pipeline mà không cần traffic thật — công cụ debug quan trọng nhất đã học
ovs-appctl dpctl/show -s, dpctl/dump-flowsBài 3Datapath (cache kernel/userspace)Xem flow cache thật sự đang forward packet, khác hẳn OpenFlow flow
tcpdumpBài 9, Bài 13NIC/interface vật lýXác nhận packet thật đã ra/vào đúng interface, thấy outer header tunnel, NAT đã translate
ovs-appctl dpif-netdev/pmd-perf-show, pmd-rxq-showBài 14Datapath (hiệu năng PMD)Thống kê CPU/cycles của PMD thread — chỉ áp dụng datapath DPDK

Ba dòng cuối cùng — cũng thuộc "layer datapath/NIC" nhưng hoàn toàn mới, chưa bài nào dùng tới — chính là nội dung Mục 3-5 của bài này:

Công cụMới ở Bài 20Vai trò
ovs-appctl vlog/setMục 3Chỉnh log level runtime của ovs-vswitchd, theo từng module
ovs-appctl coverage/show, memory/showMục 4Counter sự kiện nội bộ + thống kê bộ nhớ
ovs-appctl ofproto/listMục 3-4Liệt kê tên bridge hợp lệ để dùng với ofproto/trace khi có nhiều bridge
ovs-tcpdumpMục 5Tự động tạo/dọn mirror port rồi chạy tcpdump — bọc quanh cơ chế Mirror Bài 16

Nhìn vào hai bảng cạnh nhau, có một sự thật đáng chú ý: toàn bộ công cụ nền tảng để debug OVS đã nằm sẵn trong series từ Bài 3 đến Bài 16 — bài này không dạy bạn cách "nhìn" vào OVS theo cách nào mới, chỉ dạy thêm ba công cụ phụ trợ và quan trọng hơn: thứ tự dùng chúng.


2. Quy trình debug 5 bước: tự tổng hợp từ kiến trúc, không phải quy trình OVS công bố

💡 Hình dung như thế này: một bác sĩ khám bệnh nhân đau bụng không nhảy thẳng vào mổ. Bước 1 là hỏi bệnh sử — bệnh nhân định ăn gì, uống thuốc gì (đúng như OVSDB: ý định cấu hình, chưa nói gì về hành vi thật). Bước 2 là đối chiếu với phác đồ — theo đúng triệu chứng này, quy trình chuẩn nói phải làm gì (đúng như OpenFlow: luật bạn đã viết ra, ai đọc lại cũng hiểu). Bước 3 là xét nghiệm máu ngay lúc này — cơ thể bệnh nhân đang thực sự ở trạng thái nào, không phải trạng thái phác đồ giả định (đúng như datapath: cache runtime, có thể lệch khỏi ý định ban đầu nếu chưa kịp cập nhật). Bước 4 là nhìn trực tiếp vào vết thương — bằng chứng vật lý cuối cùng, không thể cãi (đúng như tcpdump: packet có thật sự ra khỏi NIC hay không). Chỉ khi cả bốn bước đều "bình thường" mà bệnh nhân vẫn đau, bác sĩ mới lật hồ sơ nội bộ bệnh viện — nhật ký, xét nghiệm lịch sử — để tìm bất thường không lộ ra ở khám lâm sàng.

Trước khi vào quy trình, một sự thật cần nói thẳng: tự tra docs.openvswitch.org sẽ không tìm thấy trang nào tên "OVS Troubleshooting Guide". Hai trang gần nhất, và cả hai đều không phải một quy trình debug có thứ tự:

  • Reporting Bugs — một checklist thông tin cần đính kèm khi báo lỗi cho dự án, không phải hướng dẫn tự debug: "The Open vSwitch version number (as output by ovs-vswitchd --version)... The kernel version on which Open vSwitch is running (from /proc/version)... The output of ovs-dpctl show... the output of ovs-ofctl show <bridge> for each <bridge>..." — đúng bốn thứ này (version, kernel, dpctl show, ofctl show), nhưng thiếu hẳn OVSDB và tcpdump, và không có gợi ý nào về thứ tự kiểm tra.
  • Common Configuration Issues (FAQ) — dạng hỏi-đáp từng tình huống cụ thể (mất kết nối khi thêm port, loop mạng, cổng OpenFlow hiện -1...), khuyến nghị chung nhất chỉ là "Check the ovs-vswitchd log for details" — không phải một framework debug tổng quát.

Quy trình 5 bước dưới đây, vì vậy, là một cách tổng hợp sư phạm tự rút ra từ đúng kiến trúc ba tầng series đã dạy (OVSDB ở Bài 5, OpenFlow ở Bài 6/12, datapath ở Bài 3) cộng thêm tcpdump làm lớp xác nhận vật lý cuối cùng — không phải quy trình do dự án OVS công bố. Đây là điểm khác biệt quan trọng cần nói rõ trước khi dùng nó như một "chân lý":

BướcCâu hỏiCông cụHọc ở
1Config đúng ý định chưa?ovs-vsctl show, ovsdb-client dumpBài 5
2Flow OpenFlow có match đúng kỳ vọng chưa?ovs-ofctl dump-flows, ovs-appctl ofproto/traceBài 6, 12
3Datapath cache phản ánh đúng flow OpenFlow chưa, hay đang cache hành vi cũ?ovs-appctl dpctl/dump-flows -m, dpctl/show -sBài 3
4Packet có thật sự rời/tới đúng NIC không?tcpdump, ovs-tcpdumpBài 9/13, Mục 5
5(Chỉ khi 1-4 đều "bình thường" mà vẫn lỗi) ovs-vswitchd nội bộ đang làm gì?ovs-appctl vlog/set, đọc ovs-vswitchd.log, coverage/showMục 3, 4
Quy Trình Debug 5 Bước — Tự Tổng Hợp Từ Kiến TrúcKhông phải quy trình OVS công bố chính thức — xem Mục 2Bước 1 — OVSDBovs-vsctl show / ovsdb-client dumpSai ý định (VD: tag=20thay vì 10) → dừng, sửa OVSDBBước 2 — OpenFlowdump-flows / ofproto tracePriority trùng / thiếu flow →dừng, sửa flow ruleBước 3 — Datapathdpctl/dump-flows -m, dpctl/show -sCache lệch flow OpenFlow →chờ revalidator hoặc điều tra tiếpBước 4 — NIC vật lýtcpdump / ovs-tcpdumpPacket không ra khỏi NIC →lỗi nằm ngoài OVS (cáp, driver...)Cả 4 bước đều "bình thường" mà vẫn lỗi?Bước 5 — vlog/set + đọc ovs-vswitchd.log + coverage/show (Mục 3-4)Tìm được nguyên nhân → sửa đúng layer đóVẫn không tìm ra sau bước 5? Đây là lúc dùng checklist "Reporting Bugs" chính thức(version, /proc/version, ovs-dpctl show, ovs-ofctl show) để báo lên cộng đồng OVS

Một lưu ý về thứ tự: quy trình trên đi từ tầng ít tốn thời gian nhất tới tầng tốn thời gian nhất, không phải từ tầng "quan trọng nhất". Kiểm tra OVSDB chỉ mất một câu lệnh và loại trừ ngay lớp lỗi phổ biến nhất (gõ nhầm giá trị cấu hình); tới lúc cần ofproto/trace hay đọc log dbg, bạn đã tiết kiệm được rất nhiều thời gian không phải dò trong hàng nghìn dòng log ngay từ đầu.


3. Công cụ mới vlog/set: chỉnh log level runtime, không cần khởi động lại daemon

💡 Hình dung như thế này: mặc định, ovs-vswitchd ghi log giống một máy quay an ninh chỉ bật chế độ "ghi sự kiện quan trọng" — đủ dùng ngày thường, nhưng khi có sự cố cụ thể bạn cần "tua lại ở độ phân giải cao" đúng đúng khu vực nghi ngờ, không phải bật độ phân giải cao cho toàn bộ camera trong tòa nhà (sẽ tốn ổ cứng và khiến bạn phải lọc qua hàng triệu khung hình không liên quan). vlog/set chính là nút "tăng độ phân giải" đó — bật theo đúng module, không cần khởi động lại cả hệ thống camera.

Man page ovs-appctl(8) xác nhận cú pháp:

ovs-appctl vlog/set module[:facility[:level]]
  • module — tên component nội bộ (ofproto, dpif, netdev, ofproto_dpif, vswitchd...) — danh sách đầy đủ nên lấy trực tiếp trên máy đang chạy bằng vlog/list, không học thuộc lòng.
  • facility — đích ghi: console | syslog | file.
  • level — mức chi tiết: off | emer | err | warn | info | dbg.

Man page ghi rõ hành vi khi không truyền spec nào: "Sets logging levels. Without any spec, sets the log level for every module and destination to dbg." — đây chính là điều cần cảnh báo: chạy trần ovs-appctl vlog/set không tham số trên một host production sẽ bật dbg cho toàn bộ module và toàn bộ đích ghi cùng lúc, khiến /var/log/openvswitch/ovs-vswitchd.log phình rất nhanh. Luôn giới hạn đúng module nghi ngờ:

# Chỉ bật dbg cho tầng dịch OpenFlow → datapath (nghi ngờ lỗi ở đây), ghi ra file, không đụng console/syslog
sudo ovs-appctl vlog/set ofproto_dpif:file:dbg
# Xem lại module nào đang ở mức nào — luôn chạy sau khi set để xác nhận đúng phạm vi vừa bật
sudo ovs-appctl vlog/list

Hai lệnh liên quan nên biết cùng nhóm: vlog/list"Lists the known logging modules and their current levels" — để xác nhận đúng phạm vi đang bật trước khi đọc log; và vlog/reopen — dùng sau khi logrotate đã xoay file log, ép daemon đóng rồi mở lại đúng file mới thay vì tiếp tục ghi vào file đã bị đổi tên. Sau khi debug xong, luôn trả log level về mặc định (ovs-appctl vlog/set ofproto_dpif:file:info hoặc khởi động lại daemon) — quên bước này là nguyên nhân phổ biến khiến một host chạy dbg toàn cục hàng tháng trời mà không ai để ý.

File log thật nằm ở đâu? Tài liệu FAQ Common Configuration Issues xác nhận đường dẫn mặc định trên gói Debian/Red Hat: "Check the ovs-vswitchd log for details (Debian and Red Hat packaging for Open vSwitch put it in /var/log/openvswitch/ovs-vswitchd.log)" — đây chính xác là file mà mọi thay đổi vlog/set:file:... tác động tới.


4. Công cụ mới coverage/show và memory/show: đọc counter sự kiện nội bộ

💡 Hình dung như thế này: nếu ovs-ofctl dump-flows/dpctl/dump-flows là đồng hồ đo lưu lượng trên từng tuyến ống nước cụ thể (bao nhiêu nước chảy qua đúng ống A trong giờ qua), thì coverage/show là bảng đo độ rung của toàn bộ máy bơm trung tâm — nó không nói ống nào đang chảy, mà nói bộ phận cơ khí nào bên trong máy bơm đang phải hoạt động dồn dập hơn bình thường. Một counter tăng vọt là dấu hiệu "máy đang gắng sức ở đâu đó", chưa chỉ đích danh nguyên nhân — đúng lý do vì sao Mục 2 xếp nhóm công cụ này vào bước 5, chỉ dùng khi bốn bước khám lâm sàng đầu không ra manh mối.

Man page ovs-vswitchd(8) mô tả coverage/show: "Displays the averaged per-second rates for the last few seconds, the last minute and the last hour, and the total counts of all of the coverage counters." Đây là một loại số liệu hoàn toàn khác hai loại counter bạn đã quen: không phải n_packets/n_bytes trên một flow cụ thể (Bài 6), cũng không phải hit/missed tổng quát của dpctl/show -s (Bài 3) — coverage/show đếm tần suất một loại sự kiện nội bộ xảy ra, ví dụ một nhánh code cụ thể trong ovs-vswitchd được gọi bao nhiêu lần mỗi giây.

sudo ovs-appctl coverage/show

Output là một danh sách dài, mỗi dòng một counter, dạng <tên_counter> <tổng>/sec: <5s> <1min> <1h> total: <tổng cộng>. Bản thân mã nguồn OVS định nghĩa hàng trăm counter như vậy rải khắp codebase (macro COVERAGE_DEFINE(...)) — không có ý nghĩa gì nếu học thuộc tên, nhưng vài counter liên quan trực tiếp tới đúng chủ đề "flow miss/upcall" của bài này xác nhận được từ chính mã nguồn dự án (ofproto/ofproto-dpif-upcall.c, github.com/openvswitch/ovs):

CounterÝ nghĩa suy ra từ tên + ngữ cảnh code
upcall_flow_limit_hitDatapath chạm giới hạn động số lượng flow — kèm log message "upcall: datapath reached the dynamic limit of %u flows" ngay trong cùng file
upcall_flow_limit_killOVS chủ động gỡ bớt flow để giữ dưới giới hạn
revalidate_missed_dp_flowRevalidator (Bài 3) kỳ vọng một datapath flow còn tồn tại nhưng không tìm thấy
revalidate_missing_dp_flowTương tự — flow đã biến mất khỏi datapath ngoài dự kiến của revalidator
handler_duplicate_upcallMột upcall bị xử lý trùng lặp

⚠️ Minh bạch: tên các counter trên đã xác nhận đúng tồn tại trong mã nguồn OVS hiện hành (không phải suy đoán), nhưng ý nghĩa cụ thể ở đây là suy luận hợp lý từ tên biến + ngữ cảnh, không phải trích nguyên văn một dòng chú thích chính thức — bản thân các dòng COVERAGE_DEFINE(...) trong mã nguồn không kèm comment giải thích chi tiết. Cách xác nhận chắc chắn nhất, và cũng là cách thực chiến duy nhất đáng tin: chạy ovs-appctl coverage/show | grep -Ei 'upcall|revalidate' trên chính lab của bạn, cố tình tái hiện Case study idle_timeout ở Bài tập cuối bài, rồi quan sát counter nào tăng bất thường so với lúc traffic ổn định — đó mới là bằng chứng thật, không phải tên biến suông.

memory/show ít trọng tâm hơn cho debug flow, nhưng đáng biết: "Displays some basic statistics about ovs-vswitchd's memory usage." — hữu ích khi nghi ngờ ovs-vswitchd đang rò rỉ bộ nhớ (ví dụ do một cơ chế cache nào đó phình lên bất thường theo thời gian, như cache_max_flows của IPFIX đã học ở Bài 16 nếu cấu hình sai).

Một công cụ nhỏ đáng nhắc cùng nhóm khi debug trên host có nhiều bridge: ovs-appctl ofproto/list — man page: "Lists the names of the running ofproto instances. These are the names that may be used on ofproto/trace." Trước khi gõ ofproto/trace <bridge> ... (Bài 12), chạy lệnh này trước để chắc chắn không gõ nhầm tên bridge trên một host có br-int, br-tun, br-ex cùng tồn tại (đúng tình huống Neutron/OVN đã thấy ở Bài 17-19).


5. Công cụ mới ovs-tcpdump: tự động hóa cơ chế Mirror đã học ở Bài 16

💡 Hình dung như thế này: tự dựng Mirror bằng tay ở Bài 16 giống việc muốn nghe một cuộc gọi, bạn phải tự đi nối dây tổng đài, ngồi nghe, rồi tự nhớ tháo dây ra sau khi xong — quên đúng bước cuối, dây nối vẫn treo đó âm thầm nhiều tháng. ovs-tcpdump giống một cái kẹp nghe cầm tay có sẵn: cắm vào, nghe, rút kẹp ra là mạch tự ngắt — không có bước nào để quên.

Bài 16 đã dựng tay một Mirror record trong OVSDB — tạo record, gán select_src_port/output_port, rồi tự chạy tcpdump trên port đích, và tự nhớ xóa mirror sau khi debug xong (ovs-vsctl clear Bridge br0 mirrors). ovs-tcpdump là tiện ích chính thức đóng gói cùng OVS, tự động hóa đúng ba bước đó thành một lệnh. Trang tài liệu chính thức mô tả: "creates switch mirror ports in the ovs-vswitchd daemon and executes tcpdump to listen against those ports."

sudo ovs-tcpdump -i veth0-ovs -n

Lệnh trên tự tạo một mirror port tạm cho veth0-ovs, chạy tcpdump với đúng cú pháp bạn truyền vào phía sau (-n ở đây là option gốc của tcpdump, không phải của ovs-tcpdump), và khi bạn Ctrl+C thoát tcpdump, ovs-tcpdump tự dọn mirror port đã tạo — không còn nguy cơ quên ovs-vsctl clear Bridge br0 mirrors như khi tự tay dựng ở Bài 16.

Hai option đáng chú ý:

  • --span"If specified, mirror all ports (optional)" — thay vì chỉ mirror đúng một port, mirror toàn bộ traffic qua bridge.
  • --filter"If specified, only mirror packets that match the provided OpenFlow filter" — lọc theo đúng cú pháp match field đã học ở Bài 6/12, tránh phải bắt toàn bộ traffic rồi lọc lại bằng tay ở tầng tcpdump.

Yêu cầu quyền hạn, trích nguyên văn lý do kỹ thuật: "under Linux-based kernels, tap devices do not receive packets unless the specific tuntap device has been opened by an application. This requires CAP_NET_ADMIN privileges, so the ovs-tcpdump command must be run as a user with such permissions (this is usually a super-user)." Một giới hạn cần biết trước khi dùng: "ovs-tcpdump will not allow multiple mirrors for the same port" — không chạy được hai phiên ovs-tcpdump cùng lúc trên cùng một port nguồn.

So với tcpdump chạy trực tiếp trên interface (Bài 9/13): cách đó chỉ dùng được khi bạn còn quyền truy cập trực tiếp interface cần bắt gói (ví dụ veth/namespace trong lab) — trên một switch production nơi bạn không SSH được vào chính namespace của workload, ovs-tcpdump (hoặc tự dựng Mirror như Bài 16) là cách duy nhất để "nhìn thấy" traffic mà không cần chạm vào endpoint đang chạy traffic đó.

Mirror Port: Thủ Công (Bài 16) vs Tự Động (ovs-tcpdump)Cùng một cơ chế OVSDB Mirror — khác số bước con người phải tự nhớ làmBài 16 — thủ công (3 bước)Bài 20 — ovs-tcpdump (1 lệnh)1. Tạo Mirror record trong OVSDBselect_src_port / output_port2. Chạy tcpdump trên mirror portquan sát traffic thủ công3. Tự nhớ xóa mirror — dễ quên!ovs-vsctl clear Bridge br0 mirrorssudo ovs-tcpdump -i veth0-ovs -nTự tạo mirror, tự chạy tcpdump —Ctrl+C là tự dọn mirror ngay lập tứcGộp cả 3 bước bên trái vào 1 lệnhRủi ro: mirror rác tồn tại mãi trên OVSDBKhông có bước nào để quên

6. Performance tuning: ranh giới giữa tooling DPDK chính thức và Linux perf không chính thức

Đây là điểm dễ gây hiểu lầm nhất nếu chỉ đọc tên bài "performance tuning thực chiến" mà không phân biệt rõ hai nhánh hoàn toàn khác nhau.

Nhánh 1 — datapath DPDK, có tooling chính thức. Bài 14 đã đào sâu đầy đủ: ovs-appctl dpif-netdev/pmd-perf-show, pmd-rxq-show, pmd-stats-clear, và cột other_config:pmd-sleep-max. Đây là bộ công cụ profiling duy nhất do chính dự án OVS xây dựng và tài liệu hóa — nhưng chỉ áp dụng khi bridge đang chạy datapath_type=netdev với port type=dpdk. Nếu bạn đang debug hiệu năng trên một bridge kernel datapath thông thường (mặc định của hầu hết cài đặt, kể cả toàn bộ lab từ Bài 4 tới giờ), nhóm lệnh này không chạy được — chúng gắn chặt với PMD thread, một khái niệm chỉ tồn tại trong dpif-netdev.

Nhánh 2 — kernel datapath, không có tooling chính thức tương đương. Đây là sự thật cần nói thẳng: tìm khắp docs.openvswitch.orggithub.com/openvswitch/ovs không ra bất kỳ trang nào hướng dẫn dùng perf (Linux) để profile ovs-vswitchd, và cũng không có công cụ nội bộ nào của OVS đóng vai trò tương đương pmd-perf-show cho kernel datapath. Điều đó không có nghĩa là bạn không thể dùng perf:

# Khả thi về mặt kỹ thuật — ovs-vswitchd vẫn là một tiến trình Linux bình thường
sudo perf top -p $(pidof ovs-vswitchd)

— nhưng đây là kỹ thuật hệ thống Linux chung, áp dụng được cho bất kỳ tiến trình nào đang chạy trên máy, không phải một khuyến nghị hay tính năng do dự án OVS công bố. Việc dùng nó có ích thật (thấy hàm nào trong ovs-vswitchd đang ngốn CPU nhiều nhất — ví dụ nghi ngờ revalidator hay upcall handler đang quá tải), nhưng khi đọc kết quả, bạn đang tự diễn giải một profile CPU generic, không có tài liệu chính thức nào giải thích "hàm X chiếm 40% nghĩa là gì đối với OVS" — khác hẳn pmd-perf-show, nơi mỗi số liệu (% sleep, avg cycles/pkt) đều có sẵn ngữ cảnh chính thức để diễn giải.

Bảng tóm tắt ranh giới:

DPDK (dpif-netdev)Kernel datapath (dpif-netlink, mặc định)
Tooling profilingpmd-perf-show, pmd-rxq-showchính thức, có tài liệu OVSKhông có tương đương chính thức
Dùng perf Linux được khôngĐược, nhưng thường không cần vì đã có tooling riêngĐược, nhưng là kỹ thuật hệ thống chung, không phải khuyến nghị OVS
Diễn giải kết quảCó ngữ cảnh chính thức (Bài 14)Tự diễn giải, không có tài liệu OVS hỗ trợ
Số liệu benchmark cụ thểKhông công bố benchmark phổ quát (đã nói ở Bài 14)Tương tự — không có con số Mpps/latency chung áp dụng mọi phần cứng

Kết luận thực chiến: nếu bạn nghi ngờ ovs-vswitchd đang là nút thắt CPU trên một host DPDK, dùng đúng bộ công cụ Bài 14 trước tiên — nó được thiết kế riêng cho việc này. Nếu host chạy kernel datapath và nghi ngờ tương tự, perf/top/htop là lựa chọn hợp lý, nhưng hãy trình bày nó đúng bản chất khi báo cáo lại đồng đội: một quan sát hệ thống chung, không phải một chẩn đoán "theo đúng chuẩn OVS".

Performance Tuning: Ranh Giới Chính Thức vs Không Chính ThứcCùng mục tiêu tìm nút thắt CPU — chỉ một nhánh có tooling do OVS công bốDPDK (dpif-netdev)Kernel datapath (dpif-netlink, mặc định)Tooling profilingpmd-perf-show, pmd-rxq-show —chính thức, có tài liệu OVS(đã học ở Bài 14)Không có tương đươngchính thức cho kernel datapathDùng perf Linux được không?Được, nhưng thườngkhông cần vì đã cótooling riêng (Bài 14)Được, nhưng là kỹ thuậthệ thống chung — không phảikhuyến nghị của OVSDiễn giải kết quảCó ngữ cảnh chính thứcđể diễn giải số liệu(% sleep, cycles/pkt — Bài 14)Tự diễn giải theo kinh nghiệm— không có tài liệu OVShỗ trợ đọc kết quảNghi ngờ CPU nút thắt trên DPDK? Dùng Bài 14 trước tiên.Trên kernel datapath? perf/top là quan sát hệ thống chung, không phải chẩn đoán chuẩn OVS.

7. Case study 1: flow priority conflict, lộ ngay ở bước OpenFlow

⚠️ Minh bạch về lab: môi trường viết bài này không có ovs-vsctl/ovs-ofctl/ovs-appctl cài sẵn và không có quyền root để dựng namespace/veth/OVS bridge thật (đã tự kiểm tra ngay trước khi viết: which ovs-vsctl không ra kết quả, sudo yêu cầu mật khẩu không có sẵn) — khác với phần lớn bài trước của series, nơi lab đã chạy thật trên máy viết bài. Hai case study dưới đây dùng lại đúng nguyên topology br0/ns1(10.0.0.1, veth0-ovs=port 1)/ns2(10.0.0.2, veth1-ovs=port 2) đã dựng thật ở Bài 4-6, và case B (priority conflict) tái sử dụng đúng kịch bản Bài 12 đã đề bài. Output CLI dưới đây, trừ các câu trích nguyên văn tài liệu chính thức, là suy luận có căn cứ từ kiến trúc + các output thật đã ghi nhận ở Bài 3/5/6/12, không phải chạy thật trong lúc viết bài này — đúng tinh thần minh bạch Bài 19 đã áp dụng khi không dựng được cluster K8s thật. Nếu bạn có máy Linux với quyền root, dựng lại đúng lab Bài 4/5 rồi tự chạy từng bước dưới đây để lấy output thật của chính bạn.

Tình huống: một đồng nghiệp thêm một flow rule mới lên br0 để tạm thời chặn ICMP phục vụ một bài test, nhưng gõ nhầm priority trùng với một flow NORMAL đã có sẵn, thay vì đặt cao hơn hẳn. Sau đó traffic giữa ns1/ns2 chập chờn — lúc thông, lúc không, không có quy luật rõ ràng khi thử lại nhiều lần.

Bước 1 — OVSDB: ovs-vsctl show không cho thấy gì bất thường — bridge, port, VLAN đều đúng như thiết kế. Đây là dấu hiệu đầu tiên cho biết lỗi không nằm ở tầng cấu hình, đi tiếp bước 2.

Bước 2 — OpenFlow: đây là nơi bug lộ ra ngay lập tức.

sudo ovs-ofctl -O OpenFlow13 dump-flows br0
# Output minh họa — dựa trên đúng cấu trúc output thật đã thấy ở Bài 6/12, số liệu cụ thể chỉ mang tính ví dụ
cookie=0x0, duration=920.4s, table=0, n_packets=88, n_bytes=8624, priority=150,icmp,in_port=1 actions=NORMAL
cookie=0x0, duration=41.2s, table=0, n_packets=3, n_bytes=294, priority=150,icmp,in_port=1 actions=drop

Hai flow cùng priority=150, cùng match in_port=1,icmp — đúng tình huống Bài 12 Mục 6 đã cảnh báo trước bằng lời: "OpenFlow leaves behavior undefined when two or more flows with the same priority can match a single packet". "Undefined" ở đây không phải lý thuyết suông — nó giải thích chính xác triệu chứng "chập chờn, không có quy luật" mà đồng nghiệp báo lại: không có gì đảm bảo OVS luôn chọn cùng một flow giữa các lần chạy, nên kết quả quan sát được (thông/không thông) không nhất quán.

Xác nhận thêm bằng ofproto/trace (Bài 12) — chạy lại nhiều lần liên tiếp với cùng một input để tự kiểm chứng tính "undefined":

sudo ovs-appctl ofproto/trace br0 "in_port=1,icmp,nw_src=10.0.0.1,nw_dst=10.0.0.2"

Nếu kết quả actions: đổi giữa các lần chạy (khi thì NORMAL, khi thì drop) dù input truyền vào giống hệt nhau, đó là bằng chứng trực tiếp, không cần suy luận, cho đúng hành vi "undefined" vừa nêu.

Nguyên nhân đã tìm ra ở bước 2 — dừng lại, không cần xuống tới datapath hay NIC. Sửa bằng cách tách rõ hai priority (đúng gợi ý Bài 12 Bài tập 2):

sudo ovs-ofctl -O OpenFlow13 del-flows br0 "in_port=1,icmp"
sudo ovs-ofctl -O OpenFlow13 add-flow br0 "priority=150,icmp,in_port=1,actions=drop"
sudo ovs-ofctl -O OpenFlow13 add-flow br0 "priority=100,in_port=1,icmp,actions=NORMAL"

Đây là case dễ nhất trong hai case — lỗi lộ ngay ở bước thứ hai của quy trình, minh họa đúng lý do vì sao quy trình 5 bước đi tuần tự từ tầng rẻ nhất: không cần chạm tới dpctl/tcpdump gì cả, dump-flows một dòng lệnh đã đủ.

Priority Conflict: Lộ Ngay Ở Bước 2, Dừng SớmKhông phải mọi case đều cần đi hết cả 4 bước đầuOVSDBBình thường:bridge/port/VLANđúng thiết kếovs-vsctl showOpenFlow2 flow cùngpriority=150,cùng match icmpDỪNG LẠI— sửa ở đâyDatapathKhông cầnkiểm tra tới đâynguyên nhân đã rõNICKhông cầnkiểm tra tới đâynguyên nhân đã rõBài học chính: quy trình 5 bước đi từ tầng rẻ nhất tới tầng tốn thời gian nhất —tìm ra nguyên nhân ở đâu thì dừng lại sửa ở đó, không cần đi hết cả 4 bước

8. Case study 2: VLAN mismatch, lỗi lộ ở OVSDB nhưng im lặng ở OpenFlow

Tình huống: ns1ns2 đáng lẽ cùng VLAN 10 (đúng cấu hình Bài 5 đã dựng), nhưng sau một lần chỉnh sửa vội, ns1 ping ns2 không còn thông. Không ai đổi flow OpenFlow nào cả — nghi ngờ đầu tiên nên rơi vào tầng nào?

Bước 1 — OVSDB, lỗi lộ ra trong một câu lệnh:

sudo ovs-vsctl show
# Output minh họa — cấu trúc đúng theo ovs-vsctl show thật đã thấy ở Bài 4-5
Bridge br0
Port veth0-ovs
tag: 10
Interface veth0-ovs
Port veth1-ovs
tag: 20
Interface veth1-ovs

Bug lộ ngay: veth1-ovs đang tag: 20, không phải tag: 10 như thiết kế — ai đó gõ nhầm khi chỉnh sửa. Về lý thuyết, dừng lại đây và sửa OVSDB đã đủ giải quyết vấn đề. Nhưng bài này đi tiếp một bước nữa để minh họa đúng insight quan trọng nhất của case study: tầng OpenFlow hoàn toàn im lặng về VLAN.

Bước 2 — OpenFlow, không có gì bất thường (đây chính là điểm dễ đi sai hướng):

sudo ovs-ofctl dump-flows br0
# Output minh họa — đúng cấu trúc flow mặc định đã thấy từ Bài 6
cookie=0x0, duration=1204.1s, table=0, n_packets=112, n_bytes=10976, priority=0 actions=NORMAL

Vẫn chỉ đúng một flow priority=0 actions=NORMAL — y hệt một bridge chưa từng gặp sự cố gì. Đây đúng là hệ quả trực tiếp của điều Bài 6 đã dạy: NORMAL mô phỏng hành vi MAC-learning switch truyền thống, bao gồm cả xử lý VLAN theo tag=/trunks= hoàn toàn bên trong ofproto-dpif-xlate, không tách thành flow rule riêng nào hiển thị được qua dump-flows. Người debug chỉ nhìn vào tầng OpenFlow — đúng thói quen sau khi đã quen add-flow/dump-flows ở nhiều bài trước — sẽ không tìm thấy manh mối nào cả ở đây, dù bug đang tồn tại thật.

Bước 3 — Datapath, nơi bắt đầu thấy dấu vết của quyết định VLAN, dù gián tiếp:

sudo ovs-appctl dpctl/dump-flows -m

⚠️ Minh bạch: đúng theo cảnh báo đầu Mục 7, output cụ thể của lệnh này chưa được xác nhận bằng cách chạy thật trong lúc viết bài — chỉ có thể khẳng định chắc chắn hai điều đã verify được từ tài liệu chính thức và từ ví dụ thật ở Bài 3: (1) mọi datapath flow luôn có in_port(N) trong match key (Bài 3 đã thấy ví dụ thật in_port(2)), và vì mỗi access port bị khóa cứng đúng một VLAN trong OVSDB, in_port gián tiếp mã hóa VLAN membership dù không có một trường vlan tường minh nào cho traffic thuần access-to-access không hề mang thẻ 802.1Q trên dây; (2) nếu đường đi packet phải ra một trunk port (ví dụ uplink0 trunks=10,20 đã dựng ở Bài 5), datapath action lúc đó chắc chắn chứa push_vlan(...) — đây là action chuẩn OpenFlow, man page ovs-actions(7) xác nhận: "Pushes a new outermost VLAN onto the packet." Muốn thấy đúng field/action thật trên máy bạn, chạy lệnh này trước và sau khi ping, so sánh hai lần dump — đây là cách xác thực đáng tin duy nhất, không phải đoán tên field từ tài liệu.

Điều quan trọng cần rút ra không phải một tên field cụ thể, mà là: flow cache của datapath phản ánh đúng hệ quả của cấu hình VLAN (dù cách phản ánh có thể khác nhau tùy traffic đi qua access port hay trunk port), trong khi OpenFlow flow table hoàn toàn không đả động gì tới VLAN khi dùng NORMAL.

Bước 4 — NIC, xác nhận cuối cùng bằng bằng chứng vật lý:

sudo ovs-tcpdump -i veth0-ovs -n -e

Cờ -e của tcpdump gốc in cả header lớp 2 — nếu traffic phải đi qua một trunk uplink ở đâu đó trên đường, đây là nơi thấy trực tiếp thẻ 802.1Q thật (vlan 10 hay vlan 20) trên dây, xác nhận packet đang thật sự được gắn VLAN nào, không còn là suy luận từ cấu hình hay cache nữa.

Sửa lỗi — quay lại đúng tầng đã phát hiện bug ở Bước 1:

sudo ovs-vsctl set port veth1-ovs tag=10
sudo ip netns exec ns1 ping -c 3 10.0.0.2 # verify thông lại
VLAN Mismatch: Lộ Rõ Ở Đâu, Im Lặng Ở ĐâuCùng một bug — bốn tầng phản ứng hoàn toàn khác nhauOVSDBLộ rõ ngay:tag: 20 thay vì 10ovs-vsctl showNơi nên dừng lạivà sửaOpenFlow— im lặng —Chỉ priority=0actions=NORMAL,y hệt lúc bình thườngNORMAL xử lý VLANnội bộ, không lộ flowDatapath~Gián tiếp qua in_port,rõ nhất khi có push_vlantrên đường ra trunkCần tự verify trênlab thật (Mục 8)NICBằng chứng vật lýcuối cùng — thấy đúngthẻ 802.1Q trên dâytcpdump -eBài học chính: đừng mặc định "flow table trống nghĩa là không có bug" —với action NORMAL, nhiều loại lỗi (VLAN, MAC learning) không bao giờ hiện ở tầng OpenFlow

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

Tự tạo case thứ ba — flow-miss churn do idle_timeout quá ngắn — và áp đúng quy trình 5 bước ở Mục 2 để tự tìm ra nguyên nhân, không đọc phần gợi ý dưới đây trước khi tự thử:

  1. Trên lab br0 (Bài 4-6), xóa flow catch-all hiện có và thêm lại với idle_timeout rất ngắn: sudo ovs-ofctl add-flow br0 "priority=100,idle_timeout=2,actions=NORMAL".
  2. Gửi ping từ ns1 sang ns2 với khoảng nghỉ dài hơn 2 giây giữa mỗi gói (ping -i 3 -c 5 10.0.0.2 thay vì mặc định 1 giây) — mô phỏng traffic ngắt quãng, không đủ đều đặn để flow luôn "nóng" trong cache.
  3. Trong lúc ping đang chạy, ở một terminal khác, chạy liên tiếp nhiều lần sudo ovs-appctl dpctl/dump-flows — tự quan sát flow trong datapath có biến mất rồi xuất hiện lại theo đúng nhịp ping hay không (khác hẳn Case study 1-2, nơi flow ổn định nhưng nội dung sai — ở đây flow liên tục bị tạo lại).
  4. Chạy sudo ovs-appctl coverage/show | grep -Ei 'upcall|revalidate' trước và sau một loạt ping — tự đối chiếu con số nào tăng, và tự đánh giá: tên counter đó có khớp với suy luận ở Mục 4 hay không.
  5. Áp đúng quy trình 5 bước: bước 1 (OVSDB) sẽ "bình thường", bước 2 (OpenFlow dump-flows) sẽ thấy đúng idle_timeout=2 bạn vừa đặt — đây là manh mối chính, tự giải thích tại sao con số này (không phải VLAN, không phải priority) là nguyên nhân gây ra hiện tượng bạn quan sát ở bước 3-4.
  6. Đối chiếu với FAQ chính thức: nguyên nhân và cách khắc phục case này đã được docs.openvswitch.org ghi nhận thật cho một tình huống tương tự ở quy mô lớn hơn (packet loss đầu bài kiểm RFC2544 trên traffic generator phần cứng), với khuyến nghị tăng other_config:max-idle lên 50000 (50 giây). Tự áp dụng: xóa flow idle_timeout=2 vừa thêm, quay về flow catch-all không có idle_timeout (mặc định 0, không tự hết hạn — đúng Bài 12 đã học), và verify flow trong dpctl/dump-flows không còn biến mất giữa các lần ping nữa.

Nguồn tham khảo

  • Checklist thông tin báo lỗi ("The Open vSwitch version number... The kernel version... The output of ovs-dpctl show... the output of ovs-ofctl show <bridge>..."), xác nhận đây không phải quy trình debug có thứ tự — Reporting Bugs, docs.openvswitch.org/en/latest/internals/bugs/.
  • Khuyến nghị chung "Check the ovs-vswitchd log for details (Debian and Red Hat packaging for Open vSwitch put it in /var/log/openvswitch/ovs-vswitchd.log)", và case chính thức mất gói đầu bài test RFC2544 do cache chưa "heat" kịp, khuyến nghị tăng max-idle lên 50000Common Configuration Issues, docs.openvswitch.org/en/latest/faq/issues/.
  • Cú pháp dpctl/dump-flows [-m|--more] [--names|--no-names] [dp] [filter=filter] [type=type], "The dp argument to each of these commands is optional when exactly one datapath exists, in which case that datapath is the default"; dpif/dump-flows (nhóm DPIF DEBUGGING COMMANDS, mô tả gần như y hệt dpctl/*, tự nhận là "similar to ovs-dpctl(8) commands"); ofproto/list: "Lists the names of the running ofproto instances. These are the names that may be used on ofproto/trace"; coverage/show: "Displays the averaged per-second rates for the last few seconds, the last minute and the last hour, and the total counts of all of the coverage counters"; memory/show: "Displays some basic statistics about ovs-vswitchd's memory usage"ovs-vswitchd(8), openvswitch.org.
  • Cú pháp vlog/set module[:facility[:level]], "Sets logging levels. Without any spec, sets the log level for every module and destination to dbg"; vlog/list: "Lists the known logging modules and their current levels"; vlog/reopenovs-appctl(8), openvswitch.org.
  • ovs-tcpdump: "creates switch mirror ports in the ovs-vswitchd daemon and executes tcpdump to listen against those ports", --span: "If specified, mirror all ports (optional)", --filter: "If specified, only mirror packets that match the provided OpenFlow filter", yêu cầu CAP_NET_ADMIN ("This requires CAP_NET_ADMIN privileges, so the ovs-tcpdump command must be run as a user with such permissions"), giới hạn "will not allow multiple mirrors for the same port"ovs-tcpdump(8), docs.openvswitch.org/en/latest/ref/ovs-tcpdump.8/.
  • Action push_vlan: "Pushes a new outermost VLAN onto the packet"; pop_vlan/strip_vlan: "Removes the outermost VLAN tag, if any, from the packet"ovs-actions(7), openvswitch.org.
  • Tên các coverage counter liên quan upcall/revalidator (upcall_flow_limit_hit, upcall_flow_limit_kill, revalidate_missed_dp_flow, revalidate_missing_dp_flow, handler_duplicate_upcall) xác nhận tồn tại trong mã nguồn, kèm log message "upcall: datapath reached the dynamic limit of %u flows"ofproto/ofproto-dpif-upcall.c, github.com/openvswitch/ovs.
  • "OpenFlow leaves behavior undefined when two or more flows with the same priority can match a single packet", cú pháp ofproto/trace, và kịch bản priority conflict gốc — đã học đầy đủ ở Bài 12.
  • Bộ công cụ pmd-perf-show/pmd-rxq-show/pmd-stats-clear chỉ áp dụng datapath DPDK, không có tương đương cho kernel datapath — đã học đầy đủ ở Bài 14.
  • Cơ chế Mirror (select_src_port/output_port) mà ovs-tcpdump tự động hóa — đã học đầy đủ ở Bài 16.
  • action=NORMAL xử lý VLAN nội bộ, không lộ flow rule riêng — đã học ở Bài 6; max-idle/max-revalidator mặc định và vai trò revalidator — đã học ở Bài 3; tag=/trunks=/vlan_mode — đã học ở Bài 5; cách tự dựng lab bằng namespace/veth không cần hạ tầng phức tạp — đã học ở Bài 4.

Tiếp theo: Bài 21 — Tổng kết & thiết kế: OVS vs fabric VXLAN-EVPN vật lý.