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:
- 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ì?
vlog/set,coverage/show/memory/show, vàovs-tcpdumpdù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?- "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
- 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ố
- 3. Công cụ mới vlog/set: chỉnh log level runtime, không cần khởi động lại daemon
- 4. Công cụ mới coverage/show và memory/show: đọc counter sự kiện nội bộ
- 5. Công cụ mới ovs-tcpdump: tự động hóa cơ chế Mirror đã học ở Bài 16
- 6. Performance tuning: ranh giới giữa tooling DPDK chính thức và Linux perf không chính thức
- 7. Case study 1: flow priority conflict, lộ ngay ở bước OpenFlow
- 8. Case study 2: VLAN mismatch, lỗi lộ ở OVSDB nhưng im lặng ở OpenFlow
- Bài tập cuối bài
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 ở đâu | Kiểm tra layer nào | Vai trò đã học |
|---|---|---|---|
ovs-vsctl show, ovsdb-client dump | Bài 5 | OVSDB (config state) | Xem bridge/port/VLAN đã cấu hình đúng ý định chưa |
ovs-vsctl get bridge br0 datapath_type | Bài 13 | OVSDB | Xá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-flow | Bài 6 | OpenFlow (flow state, table=0) | Đọc/sửa flow table OpenFlow một bảng |
ovs-ofctl -O OpenFlowNN dump-flows (multi-table), goto_table, resubmit | Bài 12 | OpenFlow (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 12 | OpenFlow (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-flows | Bài 3 | Datapath (cache kernel/userspace) | Xem flow cache thật sự đang forward packet, khác hẳn OpenFlow flow |
tcpdump | Bài 9, Bài 13 | NIC/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-show | Bài 14 | Datapath (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 20 | Vai trò |
|---|---|---|
ovs-appctl vlog/set | Mục 3 | Chỉnh log level runtime của ovs-vswitchd, theo từng module |
ovs-appctl coverage/show, memory/show | Mục 4 | Counter sự kiện nội bộ + thống kê bộ nhớ |
ovs-appctl ofproto/list | Mục 3-4 | Liệt kê tên bridge hợp lệ để dùng với ofproto/trace khi có nhiều bridge |
ovs-tcpdump | Mục 5 | Tự độ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 ofovs-dpctl show... the output ofovs-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ước | Câu hỏi | Công cụ | Học ở |
|---|---|---|---|
| 1 | Config đúng ý định chưa? | ovs-vsctl show, ovsdb-client dump | Bài 5 |
| 2 | Flow OpenFlow có match đúng kỳ vọng chưa? | ovs-ofctl dump-flows, ovs-appctl ofproto/trace | Bài 6, 12 |
| 3 | Datapath cache phản ánh đúng flow OpenFlow chưa, hay đang cache hành vi cũ? | ovs-appctl dpctl/dump-flows -m, dpctl/show -s | Bài 3 |
| 4 | Packet có thật sự rời/tới đúng NIC không? | tcpdump, ovs-tcpdump | Bà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/show | Mục 3, 4 |
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-vswitchdghi 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/setchí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ằngvlog/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-flowslà đồ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/showlà 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_hit | Datapath 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_kill | OVS chủ động gỡ bớt flow để giữ dưới giới hạn |
revalidate_missed_dp_flow | Revalidator (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_flow | Tương tự — flow đã biến mất khỏi datapath ngoài dự kiến của revalidator |
handler_duplicate_upcall | Mộ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ạyovs-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-tcpdumpgiố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ầngtcpdump.
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 đó.
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.org và github.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 profiling | pmd-perf-show, pmd-rxq-show — chính thức, có tài liệu OVS | Khô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".
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-appctlcà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-vsctlkhông ra kết quả,sudoyê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 topologybr0/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 đã đủ.
8. Case study 2: VLAN mismatch, lỗi lộ ở OVSDB nhưng im lặng ở OpenFlow
Tình huống: ns1 và ns2 đá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ậtin_port(2)), và vì mỗi access port bị khóa cứng đúng một VLAN trong OVSDB,in_portgián tiếp mã hóa VLAN membership dù không có một trườngvlantườ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ứapush_vlan(...)— đây là action chuẩn OpenFlow, man pageovs-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
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ử:
- Trên lab
br0(Bài 4-6), xóa flow catch-all hiện có và thêm lại vớiidle_timeoutrất ngắn:sudo ovs-ofctl add-flow br0 "priority=100,idle_timeout=2,actions=NORMAL". - Gửi ping từ
ns1sangns2vớ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.2thay 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. - 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). - 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. - Á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 đúngidle_timeout=2bạ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. - Đố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.orgghi 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ăngother_config:max-idlelên50000(50 giây). Tự áp dụng: xóa flowidle_timeout=2vừa thêm, quay về flow catch-all không cóidle_timeout(mặc định0, không tự hết hạn — đúng Bài 12 đã học), và verify flow trongdpctl/dump-flowskhô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 ofovs-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-idlelên50000— Common 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ệtdpctl/*, 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/reopen— ovs-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ầuCAP_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-clearchỉ á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-tcpdumptự động hóa — đã học đầy đủ ở Bài 16. action=NORMALxử lý VLAN nội bộ, không lộ flow rule riêng — đã học ở Bài 6;max-idle/max-revalidatormặ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ý.