Skip to main content

OVS Phần 11: QoS Và Rate Limiting — Ingress Policing Đối Chiếu Với QoS/Queue (linux-htb)

Phần 11/21 trong loạt Open vSwitch (OVS) — nối tiếp Phần 10, nơi bạn đã gộp nhiều uplink NIC thành một bond để tăng băng thông và chống đứt liên kết. Bài này xử lý một câu hỏi khác hẳn: giả sử băng thông đã đủ, làm sao đảm bảo một VM ồn ào không nuốt hết băng thông của các VM khác, và loại traffic quan trọng luôn được ưu tiên khi uplink bắt đầu nghẽn — đúng bài toán QoS/policer bạn đã cấu hình trên switch vật lý, giờ chuyển vào OVS. Đây là bài cuối của Module 2 — Trung cấp. Đọc xong, loạt bài sẽ sang Module 3, bắt đầu bằng Bài 12 — OpenFlow pipeline sâu.

Mục tiêu bài học: sau bài này bạn phân biệt rõ ràng hai cơ chế QoS hoàn toàn tách biệt mà OVS cung cấp trong OVSDB — ingress_policing trên Interface và bảng QoS/Queue trong OVSDB — biết chính xác đơn vị đo của từng cơ chế (đây là điểm gây lỗi cấu hình thực tế phổ biến nhất), tự tay dựng được cả hai: rate-limit đơn giản một port bằng ingress_policing, và một hàng đợi linux-htb hai mức ưu tiên có băng thông tối thiểu đảm bảo, và biết thêm một cơ chế thứ ba nằm hẳn ngoài OVSDB — OpenFlow Meters — để rate-limit theo đúng một flow cụ thể.

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

  1. ingress_policing và bảng QoS/Queue khác nhau ở đâu — không chỉ về cú pháp, mà về bản chất cơ chế (policing thuần túy vs traffic shaping có hàng đợi)?
  2. Vì sao trộn nhầm đơn vị giữa hai cơ chế này là lỗi cấu hình dễ gặp nhất, và số liệu chính xác từng cơ chế dùng đơn vị gì?
  3. Muốn traffic thật sự đi vào một hàng đợi cụ thể trong linux-htb, chỉ tạo QoS/Queue record thôi có đủ không, hay còn cần thêm bước nào ở lớp OpenFlow?

Mục lục


1. Từ policer và CoS trên switch vật lý đến ba cơ chế QoS của OVS

Trên một leaf switch vật lý (Juniper/Cisco/Huawei bạn đã vận hành), QoS thường tách thành hai việc khác hẳn nhau, dù người mới hay gộp chung một khái niệm:

  • Policer trên port — một cấu hình đơn giản: "port này không được nhận quá X Mbps, vượt thì drop." Không có khái niệm hàng đợi, không phân biệt loại traffic, chỉ có một ngưỡng duy nhất.
  • CoS/priority queue — phức tạp hơn nhiều: nhiều hàng đợi trên cùng một port vật lý, mỗi hàng đợi ứng với một class traffic (voice, control-plane, best-effort...), mỗi hàng đợi có băng thông tối thiểu đảm bảo và một thứ tự ưu tiên khi tranh chấp băng thông dư.

OVS tái tạo lại đúng hai tầng đó, nhưng bằng ba cơ chế tách biệt nhau, không phải ba chế độ của cùng một tính năng — trong đó riêng hai cơ chế đầu sống hẳn trong OVSDB, còn cơ chế thứ ba thì không:

  1. ingress_policing — một cặp cột (ingress_policing_rate, ingress_policing_burst) nằm ngay trên bảng Interface trong OVSDB. Đây là bản sao gần như y hệt policer đơn giản ở trên: một ngưỡng, vượt thì drop, không có hàng đợi.
  2. Bảng QoSQueue — hai bảng OVSDB riêng, gắn vào một Port qua cột qos. Đây là bản sao của CoS/priority queue: nhiều Queue con bên trong một QoS record, mỗi Queue có băng thông tối thiểu/tối đa và một mức ưu tiên riêng.
  3. OpenFlow Meters — hoàn toàn không có bảng OVSDB nào cả, sống hẳn trong OpenFlow domain: tạo/sửa/xóa bằng ovs-ofctl, gắn trực tiếp vào một flow rule cụ thể thay vì cố định theo cả Interface/Port. Mục 4 nói riêng về cơ chế này, sau khi hai cơ chế OVSDB đã rõ ràng.
Ba Cơ Chế QoS Của OVS — Sống Ở ĐâuHai cơ chế đầu nằm trong OVSDB, cơ chế thứ ba nằm hẳn trong OpenFlowOVSDB — record cấu hình, đọc/ghi qua ovs-vsctlMục 2ingress_policingbảng InterfaceMục 3QoS + Queuebảng Port → QoS → QueueÁp theo cả một Interface/Port — không phân biệt từng flow riêng lẻOpenFlow — qua ovs-ofctlMục 4OpenFlow Meterskhông có bảng OVSDBGắn theo đúng một flow rule cụ thểMục 5 so sánh chi tiết cả ba cơ chế cạnh nhau

💡 Hình dung như thế này: ingress_policing giống một nhân viên bảo vệ đứng ở cổng, chỉ làm đúng một việc — đếm số người đi qua trong một phút, quá ngưỡng thì chặn đứng ở đó, không cần biết ai đang đi qua. Bảng QoS/Queue giống một sân bay có nhiều làn kiểm tra an ninh song song — làn ưu tiên cho khách hạng thương gia (băng thông tối thiểu đảm bảo, ưu tiên cao) và làn phổ thông (chỉ nhận phần còn dư) — cùng một cổng vào, nhưng có tổ chức hàng đợi và phân loại hẳn hoi, chứ không chỉ đơn thuần đếm-và-chặn.

Điểm quan trọng cần khắc vào đầu trước khi vào chi tiết: hai cơ chế OVSDB đầu tiên này không thay thế nhau, và không đọc chung một đơn vị đo — nhầm cái này sang cái kia là nguồn lỗi cấu hình QoS phổ biến nhất trên OVS, sẽ nói kỹ ở Mục 2 và 3.


2. Ingress policing: rate limit đơn giản ngay trên Interface

ingress_policing cấu hình trực tiếp trên bảng Interface — không cần tạo thêm record nào khác, không đụng tới OpenFlow. Đúng theo mô tả chính thức: "A policing policy can be configured on an interface to drop packets that arrive at a higher rate than the configured value." Cơ chế bên dưới là token bucket kinh điển, tài liệu mô tả rất cụ thể quy trình:

  • Kích thước "xô" (bucket) tương ứng với ingress_policing_burst, ban đầu đầy.
  • Mỗi khi có gói tin tới, kích thước gói (quy đổi ra token) được so với số token hiện có trong xô — đủ token thì trừ đi và forward, không đủ thì drop.
  • Xô được nạp lại token liên tục theo tốc độ ingress_policing_rate, khi nào chưa đầy.
Token Bucket — Cách ingress_policing Quyết Định Forward/DropGói tin đến interfaceĐủ token trong bucketcho kích thước gói này?Đủ — forwardtrừ token vừa dùngThiếu — DROPkhông chờ, không xếp hàngBucket nạp token liên tục theo ingress_policing_rate (kbps)Dung lượng tối đa của bucket = ingress_policing_burst (kb)

Hai cột duy nhất cần biết, trích đúng schema vswitchd/vswitch.xml:

  • ingress_policing_rate: "Maximum rate for data received on this interface, in kbps. Data received faster than this rate is dropped. Set to 0 (the default) to disable policing."
  • ingress_policing_burst: "Maximum burst size for data received on this interface, in kb. The default burst size if set to 0 is 8000 kbit." Tài liệu nói thêm: "Specifying a value that is numerically at least as large as 80% of ingress_policing_rate helps TCP come closer to achieving the full rate."

Chú ý chữ "received" trong cả hai định nghĩa: policing áp dụng cho traffic đi vào đúng interface đó — nếu bạn set ingress_policing_rate trên interface nối với vNIC của một VM, bạn đang giới hạn những gì VM đó gửi đi (traffic VM gửi ra chính là traffic "arrive"/"received" tại phía OVS của interface), y hệt một policer ingress trên port access của switch vật lý chỉ áp cho traffic đi vào từ thiết bị cắm ở đầu kia.

Cú pháp cấu hình đúng ví dụ chính thức:

# Giới hạn traffic mà interface vif1.0 được phép gửi vào OVS ở mức 10 Mbps,
# burst tối đa 8000 kbit (≈ mức mặc định nếu để burst=0)
sudo ovs-vsctl set interface vif1.0 ingress_policing_rate=10000
sudo ovs-vsctl set interface vif1.0 ingress_policing_burst=8000

Một biến thể mới hơn cùng nhóm, ít gặp hơn nhưng đáng biết: ingress_policing_kpkts_rate/ingress_policing_kpkts_burst — policing theo số gói/giây (kpps, 1 kpps = 1000 pps) thay vì theo bit/giây, dùng token bucket tương tự nhưng mỗi gói chỉ tiêu tốn đúng một token bất kể kích thước. Bài này tập trung vào cặp rate/burst theo bit vì đó là trường hợp phổ biến nhất.

Một cảnh báo đáng nhớ nằm ngay trong chính schema, dễ bị bỏ qua vì không nằm trong phần mô tả 2 cột chính: policing có thể phối hợp rất tệ với một số giao thức mạng, đặc biệt với gói IP bị phân mảnh (fragmented). Các fragment của cùng một gói IP gốc luôn được gửi sát nhau thành một chùm; nếu lúc đó bucket gần cạn, token bucket rất dễ chỉ cho đúng một fragment lọt qua rồi drop hết phần còn lại — và bản thân IP không có cách nào để bên nhận chỉ xin gửi lại đúng các fragment còn thiếu. Hệ quả tùy giao thức tầng trên: TCP sẽ retransmit lại toàn bộ gói gốc (lặp lại đúng vấn đề, có thể không bao giờ đi lọt), còn một số giao thức dựa trên UDP sẽ coi như mất gói vĩnh viễn mà không hề hay biết. Vì lý do này, đừng vội kết luận ingress_policing "phá mạng" khi thấy traffic phân mảnh rớt bất thường — đây là hành vi tài liệu đã ghi nhận trước, không phải bug.

ingress_policing không có khái niệm hàng đợi hay ưu tiên — chỉ một ngưỡng duy nhất, vượt là drop ngay, không có chỗ nào cho "traffic quan trọng được ưu tiên hơn traffic khác." Muốn phân loại nhiều class traffic khác nhau trên cùng một port, đó chính xác là việc bảng QoS/Queue giải quyết — Mục 3.


3. Bảng QoS và Queue: traffic shaping có hàng đợi, ưu tiên, và băng thông tối thiểu

Khác hẳn ingress_policing (chỉ hai cột đơn giản), cơ chế thứ hai gồm hai bảng OVSDB riêng phối hợp với nhau và gắn vào một Port (không phải Interface) qua cột qos:

  • QoS — record mô tả "chính sách" tổng: loại classifier nào, tổng băng thông tối đa, và một map từ queue-id sang các Queue record.
  • Queue — từng hàng đợi con, mang cấu hình băng thông riêng (min-rate, max-rate, priority...).

Schema xác nhận đúng quan hệ này. Cột qos trên Port: "Quality of Service (QoS) configuration for this port." Cột queues trên QoS: "A map from queue numbers to Queue records... Queue 0 is the 'default queue.' It is used by OpenFlow output actions when no specific queue has been set." — chi tiết quan trọng: nếu queue 0 không được cấu hình riêng, OVS tự động coi như nó tồn tại với cấu hình rỗng (từ bản 1.6 trở đi, tránh việc "không cấu hình gì" vô tình làm rớt hết traffic không match queue nào).

Quan Hệ 3 Bảng OVSDB: Port → QoS → QueueTạo record thôi chưa đủ — traffic chỉ vào đúng Queue khi có flow set_queue (Mục 3)Port (veth-up)cột qos trỏ tới 1 QoS recordcột qosQoS recordtype=linux-htb, max-rate=...cột queues = map queue-id → QueueQueue 0 (q-high)min-rate=500Mbps, priority=0bit/s trần, không phải kbpsQueue 1 (q-low)min-rate=100Mbps, priority=10priority lớn hơn = nhường trướcChỉ 3 bảng này thôi thì traffic vẫn rơi vào queue 0 mặc định — cần thêm flow OpenFlow set_queue

Loại QoS: không chỉ có linux-htb

Cột type trên bảng QoS liệt kê nhiều loại hơn outline sơ bộ thường nhắc tới. Nguyên văn schema, các loại hiện có:

typeBản chất
linux-htbLinux "hierarchy token bucket" classifier — phân cấp, có min-rate/max-rate/priority per queue
linux-hfscLinux "Hierarchical Fair Service Curve" — thuật toán lập lịch dựa trên đường cong dịch vụ, khác cách tiếp cận với HTB
linux-sfq"Stochastic Fairness Queueing" — chia công bằng theo flow, không có min/max-rate per queue
linux-codel / linux-fq_codelCác thuật toán chống bufferbloat ("Controlled Delay") của kernel Linux
linux-netem"Network Emulator" — giả lập độ trễ/mất gói/jitter, dùng để test chứ không phải QoS production
linux-noopKhông làm gì cả — dùng khi muốn tự quản lý QoS bằng công cụ khác (tc thủ công), không để OVS đụng vào
egress-policerPolicer egress cho port kiểu userspace/DPDK, dùng thư viện rte_meter của DPDK
trtcm-policerPolicer hai cấp theo RFC 4115 (Two-Rate Three-Color Marker) — đánh dấu màu Green/Yellow/Red, Red bị drop, cũng dành cho port DPDK

Chi tiết đáng chú ý nhất trong bảng trên: linux-htb/linux-hfsc là các Linux traffic-control (tc) classifier thật, nên chỉ áp dụng đúng nghĩa cho port được backed bởi một netdevice kernel thật (physical NIC, veth, tap...). Với port kiểu DPDK (userspace datapath), OVS không thể gọi tc — đó là lý do tồn tại riêng egress-policer/trtcm-policer, hai loại được thiết kế "cho userspace port types with DPDK." Đây chính là bản chất cả hệ thống mà tài liệu FAQ chính thức nói thẳng — nguyên văn: "Open vSwitch does not implement QoS itself. Instead, it can configure some, but not all, of the QoS features built into the Linux kernel." Với port DPDK, không có "Linux kernel QoS" nào để cấu hình, nên cần cơ chế policer riêng chạy hoàn toàn trong userspace.

Cấu hình linux-htb: đơn vị là bit/s, không phải kbps

Đây là phần cần đọc chậm nhất bài, vì đơn vị khác hẳn ingress_policing. Trên QoS (nhóm cấu hình chung cho linux-htb/linux-hfsc):

  • other_config:max-rate: "Maximum rate shared by all queued traffic, in bit/s. Optional. If not specified, for physical interfaces, the default is the link rate. For other interfaces or if the link rate cannot be determined, the default is currently 10 Gbps." — chú ý vế sau: với port không phải NIC vật lý (veth, internal...), hoặc khi OVS không dò được tốc độ link, trần mặc định không phải "vô hạn" mà là 10 Gbps cứng.

Trên từng Queue con (nhóm cấu hình riêng cho linux-htb):

  • other_config:min-rate: "Minimum guaranteed bandwidth, in bit/s."
  • other_config:max-rate: "Maximum allowed bandwidth, in bit/s. Optional... If unspecified, defaults to no limit."
  • other_config:burst: "Burst size, in bits. This is the maximum amount of 'credits' that a queue can accumulate while it is idle."
  • other_config:priority: "A queue with a smaller priority will receive all the excess bandwidth that it can use before a queue with a larger value receives any... Defaults to 0 if unspecified."

Đây chính là điểm dễ gây lỗi thực tế nhất trong toàn bài: ingress_policing_rate đo bằng kbps (kilobit/giây), còn min-rate/max-rate của QoS/Queue đo bằng bit/s trần — không phải kbit/s. Một giá trị other-config:max-rate=1000000 nhìn qua tưởng là "1 Gbps" (theo thói quen nghĩ bằng nghìn như ingress_policing), nhưng thực chất chỉ là 1.000.000 bit/s = 1 Mbps — lệch 1000 lần so với ý định thật. Muốn 1 Gbps thật sự, phải viết đủ max-rate=1000000000. Không có cách nào khác để phát hiện lỗi này ngoài việc luôn tự hỏi "mình vừa gõ bao nhiêu số 0" mỗi khi chuyển qua lại giữa hai cơ chế.

Một ràng buộc kỹ thuật khác của riêng linux-htb/linux-hfsc, cũng nằm ngay trong schema: "linux-htb may use queue_ids less than 61440." — queue-id từ 61440 trở lên không dùng được với hai loại classifier này.

Cột dscp trên Queue (không thuộc nhóm other_config) cho phép đánh dấu lại DSCP của traffic đi qua chính hàng đợi đó khi ra khỏi OVS: "If set, Open vSwitch will mark all traffic egressing this Queue with the given DSCP bits." — cầu nối trực tiếp với khái niệm DSCP/CoS bạn đã quen dùng để phân loại traffic trên switch vật lý.

Chỉ tạo Queue thôi chưa đủ — cần OpenFlow chọn hàng đợi

Đây là cái bẫy thứ hai, tài liệu FAQ chính thức nêu thẳng bằng một tình huống thực tế: nếu bạn tạo xong QoS/Queue nhưng không cài thêm gì ở lớp OpenFlow, "all of the packets to eth0 are going to the 'default queue', which is not what we want." Tạo hàng đợi trong OVSDB chỉ là "khai báo hàng đợi tồn tại" — quyết định gói tin nào đi vào hàng đợi nào là việc của action set_queue trong một flow OpenFlow, đúng đúng ranh giới OVSDB-vs-OpenFlow đã dựng từ Bài 1: OVSDB tạo khung xương (hàng đợi tồn tại), OpenFlow quyết định luồng nào chảy vào khung xương đó. Cú pháp chính thức:

sudo ovs-ofctl add-flow br0 "in_port=5,actions=set_queue:123,normal"

Mục 7 sẽ dựng lại chính xác luồng hai bước này (tạo Queue → cài flow set_queue) cho một cấu hình hai mức ưu tiên thật.


4. OpenFlow Meters: cơ chế thứ ba, nằm hẳn trong OpenFlow

Hai cơ chế ở Mục 2 và 3 đều bắt đầu bằng một record trong OVSDB. OVS còn một cơ chế QoS/rate-limit thứ ba nằm ở vị trí hoàn toàn khác: không có bảng OVSDB nào tên Meter — toàn bộ vòng đời (tạo, sửa, xóa, gắn vào flow) đi qua ovs-ofctl, sống đúng trong "OpenFlow domain" mà Bài 1 đã tách bạch với OVSDB.

💡 Hình dung như thế này: nếu ingress_policingQoS/Queue giống hai loại biển báo giới hạn tốc độ cắm cố định ngay tại cổng vào bãi đỗ xe — ai đi qua cổng đó cũng bị áp — thì Meter giống một máy đo tốc độ cầm tay mà người điều phối (từng flow OpenFlow) tự quyết định lúc nào mang ra dùng, đo đúng luồng xe nào, gắn tạm cho luồng đó ngay trong lúc điều phối, chứ không phải một thứ cắm cố định ở cổng.

Hỗ trợ Meters trong OVS trải qua ba giai đoạn tách biệt, đúng theo FAQ chính thức: giao thức (OpenFlow protocol support) từ OVS 2.0, hiện thực trong userspace datapath từ OVS 2.7, và hiện thực trong kernel datapath từ OVS 2.10. Về mặt chuẩn OpenFlow, Meters chỉ tồn tại từ OpenFlow 1.3 trở lên — vì OVS mặc định chạy OpenFlow 1.0, mọi lệnh ovs-ofctl liên quan Meters đều cần thêm cờ -O OpenFlow13 (hoặc cao hơn), khác hẳn ingress_policing/QoS/Queue vốn không đụng gì tới version OpenFlow.

Cú pháp tạo một meter (Meter Syntax, ovs-ofctl(8)): chọn đơn vị kbps hoặc pktps cho toàn bộ rate/burst của meter đó, rồi khai ít nhất một "band" — mỗi band là một ngưỡng rate cụ thể kèm hành động thực hiện khi vượt ngưỡng đó. Hiện tại tài liệu chỉ liệt kê đúng một loại band là drop, nghĩa là Meters trong OVS hiện tại thuần túy là policing (drop khi vượt rate), không có khái niệm "hàng đợi ưu tiên" như QoS/Queue:

# Tạo meter id=1, đơn vị kbps, giới hạn 1000 kbps = 1 Mbps, bật thống kê
sudo ovs-ofctl -O OpenFlow13 add-meter br0 \
"meter=1,kbps,burst,stats,bands=type=drop,rate=1000,burst_size=100"

Gắn meter vào đúng một flow bằng action/instruction meter:meter_id — đây là điểm khác biệt lớn nhất so với hai cơ chế OVSDB: ingress_policing áp cho cả một Interface, set_queue áp cho cả một Port (qua chọn queue), còn Meter áp cho đúng một flow rule cụ thể, match càng hẹp thì Meter càng chỉ ảnh hưởng đúng traffic đó:

sudo ovs-ofctl -O OpenFlow13 add-flow br0 "in_port=1,meter=1,actions=normal"

Verify bằng đúng nhóm lệnh Meter table đã liệt kê ở đầu mục:

sudo ovs-ofctl -O OpenFlow13 dump-meters br0
# ===== Output minh họa =====
OFPST_METER_CONFIG reply (OF1.3) (xid=0x2):
meter=1 kbps burst stats bands=
type=drop rate=1000 burst_size=100
# =============================

(Output minh họa — cấu trúc đúng theo ovs-ofctl(8), số liệu chỉ mang tính ví dụ.)

Bài này không dựng một lab đầy đủ riêng cho Meters như Mục 6/7 (topology veth/namespace riêng) — về bản chất kỹ thuật (token bucket, drop khi vượt rate), Meters không khác ingress_policing nhiều; điểm đáng nhớ nhất chỉ là vị trí cấu hình (OpenFlow, không phải OVSDB) và khả năng gắn theo từng flow thay vì cố định theo cả Interface/Port. Phối hợp Meters với ct() (connection tracking) hay với OVN là chủ đề nằm ngoài phạm vi bài QoS cơ bản này.


5. Đối chiếu song song ba cơ chế: khi nào dùng cái nào

Tiêu chíingress_policingQoS + Queue (linux-htb)OpenFlow Meters
Cấu hình ở đâuOVSDB — bảng InterfaceOVSDB — Port (qua cột qos) → QoSQueueOpenFlowovs-ofctl add-meter, không có bảng OVSDB nào
Đơn vị ratekbps (kilobit/giây)bit/s trầnkbps hoặc pktps (tự chọn lúc tạo meter)
Đơn vị burstkb (kilobit)bit trầnCùng đơn vị đã chọn cho rate (kbit hoặc kpkts)
Cơ chếToken bucket đơn giản — chỉ policing (drop khi vượt)tc classifier thật (linux-htb/linux-hfsc...) — shaping có hàng đợi thậtToken bucket theo band — hiện chỉ có band type=drop
Nhiều hàng đợi / ưu tiênKhông cóCó — nhiều Queue, mỗi cái có min-rate/max-rate/priority riêngKhông có hàng đợi, nhưng gắn được theo từng flow riêng lẻ
Áp dụng theoCả một InterfaceCả một Port (qua set_queue chọn queue)Đúng một flow rule cụ thể
Cần thêm bước OpenFlow khôngKhông — set xong là có hiệu lực ngay — thiếu set_queue thì mọi traffic rơi vào queue 0 mặc địnhLuôn cần — bản chất Meter chính là 1 phần của flow, cần OpenFlow 1.3+
Áp dụng được cho port DPDK khôngCó (không phụ thuộc tc)Không trực tiếp — cần đổi type=egress-policer/trtcm-policerCó — không phụ thuộc tc, thuần OpenFlow
Dùng khi nàoRate-limit đơn giản một port, không cần phân biệt loại trafficCần đảm bảo băng thông tối thiểu + phân mức ưu tiên nhiều loại traffic trên cùng một uplinkRate-limit đúng một luồng traffic cụ thể (theo match), không muốn đụng OVSDB
Hai Cơ Chế QoS Của OVS Trong OVSDB — Song SongKhông thay thế nhau, không dùng chung đơn vị đo (Meters — Mục 4 — là cơ chế thứ 3, ngoài OVSDB)ingress_policing (Interface)QoS + Queue (Port, linux-htb)Đơn vị rate/burstkbps / kb(kilobit, không phải bit trần)bit/s trần(1 Gbps = 1000000000, không rút gọn)Cơ chếToken bucket — policingchỉ drop khi vượt ngưỡngtc classifier thật (linux-htb)shaping có hàng đợiNhiều hàngđợi / ưu tiênKhông cóCó — mỗi Queue: min-rate/max-rate/priority riêngCần bướcOpenFlow?Không — có hiệu lực ngayCó — thiếu set_queue thìmọi traffic vào queue 0 mặc địnhDùng ingress_policing: rate-limit đơn giản 1 port, không cần phân biệt loại trafficDùng QoS/Queue: cần đảm bảo băng thông tối thiểu + ưu tiên nhiều class traffic trên cùng 1 uplinkPort kiểu DPDK: linux-htb không dùng được — đổi type=egress-policer/trtcm-policerOVS không tự implement QoS — chỉ cấu hình một phần tính năng QoS có sẵn của Linux kernel2 cơ chế OVSDB dùng chung tc bên dưới; Meters (Mục 4) là cơ chế thứ 3, ngoài OVSDB

6. CLI lab: ingress_policing trên một port, verify và test traffic thật

Dựng một bridge với một namespace giữ vai trò "VM đang gửi traffic", theo đúng mẫu veth/namespace đã dùng từ Bài 4/5:

sudo ovs-vsctl add-br br0

# vm1 — phía sẽ bị policing khi gửi traffic vào OVS
sudo ip netns add vm1
sudo ip link add veth0 type veth peer name veth0-ovs
sudo ip link set veth0 netns vm1
sudo ovs-vsctl add-port br0 veth0-ovs
sudo ip link set veth0-ovs up
sudo ip netns exec vm1 ip addr add 10.0.0.1/24 dev veth0
sudo ip netns exec vm1 ip link set veth0 up
sudo ip netns exec vm1 ip link set lo up

# vm2 — phía nhận traffic, không bị policing
sudo ip netns add vm2
sudo ip link add veth1 type veth peer name veth1-ovs
sudo ip link set veth1 netns vm2
sudo ovs-vsctl add-port br0 veth1-ovs
sudo ip link set veth1-ovs up
sudo ip netns exec vm2 ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec vm2 ip link set veth1 up
sudo ip netns exec vm2 ip link set lo up

Set ingress_policing trên veth0-ovs — đúng interface phía OVS nối với vm1 — để giới hạn những gì vm1 được phép gửi vào switch ở mức 10 Mbps:

sudo ovs-vsctl set interface veth0-ovs \
ingress_policing_rate=10000 \
ingress_policing_burst=8000

Verify giá trị đã ghi vào OVSDB thật, dùng lại ovs-vsctl list đã quen từ Bài 5/10:

sudo ovs-vsctl list interface veth0-ovs
# ===== Output minh họa (rút gọn) =====
_uuid : c1a2b3d4-9e3d-4c8a-b716-2a1f9c0d8b71
name : "veth0-ovs"
ingress_policing_burst: 8000
ingress_policing_rate : 10000
type : ""
# =======================================

(Output minh họa — tên cột đúng theo schema thật, UUID chỉ mang tính ví dụ. ingress_policing_rate=10000 nghĩa là 10000 kbps = 10 Mbps, không phải 10000 Mbps — luôn tự nhắc lại đơn vị là kilobit khi đọc số này.)

Test bằng iperf3, chạy server ở phía không bị policing (vm2), client ở phía bị policing (vm1) — vì ingress_policing chỉ áp cho traffic đi vào OVS từ veth0-ovs, tức traffic vm1 gửi, nên client phải nằm ở vm1:

# Terminal 1 — server, chạy trong vm2
sudo ip netns exec vm2 iperf3 -s

# Terminal 2 — client, chạy trong vm1, gửi TCP hết tốc lực trong 10 giây
sudo ip netns exec vm1 iperf3 -c 10.0.0.2 -t 10

Kỳ vọng đúng theo cơ chế token bucket đã mô tả ở Mục 2: thông lượng TCP báo cáo bởi iperf3 sẽ hội tụ dần về gần mức 10 Mbps đã cấu hình, không phải đạt ngay lập tức và chính xác tuyệt đối — vì TCP cần vài vòng mất gói/backoff để "học" đúng tốc độ khả dụng, đúng đúng lý do tài liệu khuyến nghị đặt ingress_policing_burst ít nhất bằng 80% của rate để giúp TCP tiệm cận tốc độ tối đa nhanh hơn. Số liệu thông lượng thật sự đạt được (bao nhiêu Mbps chính xác, độ trễ hội tụ bao lâu) phụ thuộc kernel, NIC, và tải hệ thống lúc test — cần tự benchmark trên phần cứng thật, không có một con số phổ quát để trích dẫn ở đây. Điều nên tự kiểm khi chạy lab: (1) thông lượng đo được có nằm quanh 10 Mbps chứ không phải tốc độ tối đa của veth (thường hàng Gbps) hay không, (2) đổi ingress_policing_rate=0 rồi chạy lại — thông lượng phải nhảy vọt lên gần tốc độ tối đa của veth, xác nhận 0 thật sự tắt hẳn policing đúng như schema mô tả.

ingress_policing được OVS hiện thực bằng cách cấu hình Linux traffic-control ở tầng dưới trên chính netdevice đó (đúng tinh thần câu FAQ đã trích ở Mục 3: OVS không tự implement QoS mà chỉ cấu hình một phần tính năng QoS có sẵn của Linux kernel), một cách đối chiếu thêm — không bắt buộc — là tự kiểm bằng công cụ tc sẵn có trên máy: sudo tc qdisc show dev veth0-ovs / sudo tc filter show dev veth0-ovs ingress. Cấu trúc qdisc/filter cụ thể tùy phiên bản kernel và OVS đang chạy, nên bài này không in một output cố định cho lệnh này — coi đây là bài tập tự đối chiếu, không phải bước bắt buộc của lab.


7. CLI lab: dựng linux-htb với hai queue ưu tiên khác nhau

Mở rộng đúng topology Mục 6: vm1vm2 giờ đóng vai trò hai nguồn traffic khác mức ưu tiên, cùng chia sẻ một cổng uplink veth-up đi ra "mạng ngoài." Bốn bước sắp làm khớp đúng bốn tầng trong sơ đồ dưới đây — tạo hàng đợi ở OVSDB không tự động có tác dụng, phải có flow OpenFlow set_queue trỏ đúng luồng vào đúng hàng đợi:

Lab Mục 7 — Từ VM Tới Hàng Đợi linux-htbTạo Queue trong OVSDB (bước 1-2) không tự có tác dụng — cần flow set_queue (bước 3)vm1 (ưu tiên cao)vm2 (ưu tiên thấp)Bước 3 — OpenFlow set_queuein_port=vm1→queue:0, vm2→queue:1chọn hàng đợiBước 1 — QoS recordtype=linux-htb, max-rate=1GbpsBước 2 — Queue 0 (q-high)min=500Mbps, priority=0Bước 2 — Queue 1 (q-low)min=100Mbps, max=300Mbps, priority=10veth-up → vm3 (mạng ngoài)Bước 4 — verify bằng ovs-ofctl queue-stats / queue-get-config trên chính port veth-up

Thêm cổng uplink và một namespace vm3 đại diện phía nhận ở đầu bên kia:

sudo ip link add veth-up type veth peer name veth-up-peer
sudo ip link set veth-up up
sudo ip link set veth-up-peer up
sudo ovs-vsctl add-port br0 veth-up

sudo ip netns add vm3
sudo ip link set veth-up-peer netns vm3
sudo ip netns exec vm3 ip addr add 10.0.0.3/24 dev veth-up-peer
sudo ip netns exec vm3 ip link set veth-up-peer up
sudo ip netns exec vm3 ip link set lo up

Bước 1 — tạo QoS record kiểu linux-htb với hai Queue, gắn vào port veth-up, dùng đúng cú pháp transaction --/--id=@name đã quen từ Bài 5 và Bài 10:

sudo ovs-vsctl \
-- set port veth-up qos=@newqos \
-- --id=@newqos create QoS type=linux-htb \
other-config:max-rate=1000000000 \
queues=0=@q-high,1=@q-low \
-- --id=@q-high create Queue \
other-config:min-rate=500000000 \
other-config:max-rate=1000000000 \
other-config:priority=0 \
-- --id=@q-low create Queue \
other-config:min-rate=100000000 \
other-config:max-rate=300000000 \
other-config:priority=10

Đọc lại đúng số 0 vừa gõ: max-rate=1000000000 bit/s = 1 Gbps (tổng trần cho cả policy), queue q-high được đảm bảo tối thiểu 500 Mbps và có priority=0 (nhận băng thông dư trước, theo đúng nghĩa "priority nhỏ hơn thắng" đã trích ở Mục 3), queue q-low chỉ đảm bảo tối thiểu 100 Mbps, trần tối đa 300 Mbps, và priority=10 — chỉ nhận phần dư sau khi q-high đã lấy đủ.

Bước 2 — verify hai bảng OVSDB vừa tạo, dùng lại ovs-vsctl list:

sudo ovs-vsctl list qos
sudo ovs-vsctl list queue
# ===== Output minh họa (rút gọn) — list qos =====
_uuid : 7b3e1a22-...
external_ids : {}
other_config : {max-rate="1000000000"}
queues : {0=8f21c3aa-..., 1=9a44d0bb-...}
type : linux-htb
# ==================================================

# ===== Output minh họa (rút gọn) — list queue =====
_uuid : 8f21c3aa-...
dscp : []
external_ids : {}
other_config : {max-rate="1000000000", min-rate="500000000", priority="0"}

_uuid : 9a44d0bb-...
dscp : []
external_ids : {}
other_config : {max-rate="300000000", min-rate="100000000", priority="10"}
# ==================================================

(Output minh họa — tên cột và cấu trúc queues map đúng theo schema thật, UUID chỉ mang tính ví dụ. Cần tự kiểm: UUID trong queues của record qos phải khớp đúng _uuid của hai record queue tương ứng — nếu lệch, transaction ở Bước 1 chưa đúng.)

Bước 3 — cài flow OpenFlow để thật sự chọn hàng đợi, đúng đúng cảnh báo ở Mục 3: chưa có bước này thì mọi traffic đi qua veth-up vẫn rơi hết vào queue 0 mặc định, không "tự động" theo min-rate/priority vừa khai báo. Traffic từ vm1 (đại diện traffic ưu tiên cao) đi vào q-high, traffic từ vm2 (ưu tiên thấp) đi vào q-low:

sudo ovs-ofctl add-flow br0 "in_port=veth0-ovs,actions=set_queue:0,normal"
sudo ovs-ofctl add-flow br0 "in_port=veth1-ovs,actions=set_queue:1,normal"

Bước 4 — verify hàng đợi đã có cấu hình thật ở lớp OpenFlow, và xem thống kê từng hàng đợi:

sudo ovs-ofctl queue-get-config br0 veth-up
# ===== Output minh họa =====
queue-get-config reply
port=veth-up
queue 0: default
queue 1: min_rate=100000Kbps max_rate=300000Kbps
# =============================

(Output minh họa — tài liệu ovs-ofctl(8) lưu ý lệnh này có giá trị thông tin hạn chế vì bản thân OpenFlow chỉ expose một phần cấu hình queue; cấu trúc số liệu đầy đủ nên đối chiếu chéo với ovs-vsctl list queue ở Bước 2, đây mới là nguồn "sự thật" đầy đủ nhất.)

sudo ovs-ofctl queue-stats br0 veth-up
# ===== Output minh họa =====
port veth-up queue 0: bytes=0, packets=0
port veth-up queue 1: bytes=0, packets=0
# =============================

(Output minh họa — cả hai đếm 0 nếu chưa có traffic nào chạy qua sau khi cài flow. Sau khi cho vm1/vm2 gửi traffic thật, số bytes/packets phải tăng — queue nào chưa từng thấy traffic nghĩa là chưa flow nào thật sự dùng đúng set_queue trỏ tới nó, quay lại kiểm Bước 3.)

Tương tự Mục 6, cách đối chiếu thêm ở tầng Linux (không bắt buộc): sudo tc class show dev veth-up sau khi flow đã có traffic thật đi qua — nên thấy các class HTB tương ứng hai queue vừa tạo. Cấu trúc output cụ thể tùy phiên bản kernel, nên không in cố định ở đây; coi đây là bài tập tự đối chiếu chéo giữa lớp OVSDB và lớp Linux thật bên dưới, đúng tinh thần "OVS chỉ là lớp cấu hình gọn cho tc" đã nêu ở Mục 3 và 5.

Nếu chỉ nhớ được một điều sau bài này: ingress_policing là một cặp cột đơn giản trên Interface, chỉ biết drop, đơn vị kbps/kb; QoS/Queue là hai bảng riêng gắn vào Port, biết shape có hàng đợi và ưu tiên thật, đơn vị bit/s trần, và luôn cần thêm một flow OpenFlow set_queue thì hàng đợi mới thật sự có tác dụng — thiếu bước đó, cấu hình QoS/Queue dù đúng cú pháp tuyệt đối vẫn không làm gì cả.


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

  1. Trên lab Mục 6, đổi ingress_policing_burst xuống một giá trị rất nhỏ (ví dụ 100, tức 100 kbit — nhỏ hơn nhiều so với MTU mặc định 1500 byte ≈ 12 kbit của một gói tối đa). Chạy lại iperf3, quan sát thông lượng có tệ hơn rõ rệt so với burst mặc định 8000 không, và giải thích bằng đúng câu trong schema: "The burst size should be at least the size of the interface's MTU."
  2. Trên lab Mục 7, đổi priority của q-low xuống bằng q-high (cả hai cùng priority=0). Cho cả vm1vm2 cùng gửi traffic đồng thời tới vm3 bằng hai phiên iperf3 song song, quan sát cách hai luồng chia nhau băng thông dư so với khi q-low còn giữ priority=10. Ghi lại kết quả quan sát được (không cần số chính xác) — mục tiêu là thấy sự khác biệt định tính, không phải đo benchmark.
  3. Xóa toàn bộ cấu hình QoS đã tạo ở Mục 7 theo đúng trình tự tài liệu khuyến nghị (vì Queue không tự động bị xóa khi QoS bị xóa, và QoS không tự mất khi gỡ khỏi Port):
    sudo ovs-vsctl -- clear port veth-up qos
    sudo ovs-vsctl -- --all destroy qos
    sudo ovs-vsctl -- --all destroy queue
    Verify bằng ovs-vsctl list qosovs-vsctl list queue — cả hai phải trả về rỗng. Giải thích tại sao thứ tự clear port ... qos phải làm trước khi destroy qos (gợi ý: một QoS record đang còn được một Port tham chiếu thì không nên bị xóa trong lúc tham chiếu còn tồn tại).

Nguồn tham khảo

  • ingress_policing_rate: "Maximum rate for data received on this interface, in kbps... Set to 0 (the default) to disable policing."; ingress_policing_burst: "Maximum burst size for data received on this interface, in kb. The default burst size if set to 0 is 8000 kbit.", khuyến nghị burst ≥ 80% rate để TCP đạt tốc độ tối đa; cơ chế token bucket cho cả policing theo bit lẫn theo gói (ingress_policing_kpkts_rate/_burst); cảnh báo policing tương tác xấu với một số giao thức mạng, đặc biệt gói IP phân mảnh, có thể khiến TCP retransmit lặp lại hoặc UDP mất gói vĩnh viễn — mã nguồn schema, vswitch.xml, github.com/openvswitch/ovs.
  • Bảng QoS: cột type liệt kê đầy đủ linux-htb, linux-hfsc, linux-sfq, linux-codel, linux-fq_codel, linux-netem, linux-noop, egress-policer (DPDK, dùng thư viện rte_meter), trtcm-policer (RFC 4115 Two-Rate Three-Color Marker); other_config:max-rate tính bằng bit/s; cột queues với queue 0 là "default queue"; ràng buộc linux-htb/linux-hfsc chỉ dùng queue_id dưới 61440 — mã nguồn schema, vswitch.xml, github.com/openvswitch/ovs.
  • Bảng Queue: other_config:min-rate/max-rate tính bằng bit/s, other_config:burst tính bằng bit, other_config:priority"A queue with a smaller priority will receive all the excess bandwidth that it can use before a queue with a larger value receives any... Defaults to 0 if unspecified"; cột dscp đánh dấu lại DSCP khi egress — mã nguồn schema, vswitch.xml, github.com/openvswitch/ovs.
  • Cột qos trên Port: "Quality of Service (QoS) configuration for this port." — mã nguồn schema, vswitch.xml, github.com/openvswitch/ovs.
  • Nguyên văn: "Open vSwitch does not implement QoS itself. Instead, it can configure some, but not all, of the QoS features built into the Linux kernel."; ví dụ nếu thiếu flow set_queue thì "all of the packets to eth0 are going to the 'default queue', which is not what we want"; hỗ trợ OpenFlow Meters: protocol từ OVS 2.0, hiện thực userspace từ 2.7, kernel datapath từ 2.10 — 2026, FAQ: Quality of Service (QoS) — docs.openvswitch.org.
  • Cú pháp cấu hình ingress_policing (ovs-vsctl set interface vif1.0 ingress_policing_rate=10000) và cookbook đầy đủ tạo QoS/Queue bằng create/set/--id=@name ("Create a linux-htb QoS record that points to a few queues... ovs-vsctl -- set Port eth0 qos=@newqos -- set Port eth1 qos=@newqos -- --id=@newqos create QoS type=linux-htb other-config:max-rate=1000000000 queues=0=@q0,1=@q1 -- --id=@q0 create Queue other-config:min-rate=100000000 other-config:max-rate=100000000..."), cùng cách gỡ cấu hình ("ovs-vsctl clear Port eth1 qos", "ovs-vsctl -- destroy QoS eth0 -- clear Port eth0 qos -- clear Port eth1 qos") — ovs-vsctl(8), man7.org.
  • Ví dụ cú pháp gọi action set_queue từ ovs-ofctl add-flow br0 in_port=5,actions=set_queue:123,normal; lệnh queue-stats ("Prints to the console statistics for the specified queue on port within switch") và queue-get-config (giá trị thông tin hạn chế do bản thân OpenFlow chỉ expose một phần cấu hình queue); cú pháp Meter table commands (add-meter/dump-meters/meter-stats) và Meter Syntax (meter=id, đơn vị kbps/pktps, bands=type=drop,rate=...,burst_size=...), chỉ hoạt động từ OpenFlow 1.3 trở lên — ovs-ofctl(8), openvswitch.org.
  • Mô tả action set_queue: "sets the queue ID to be used for subsequent output actions", được OVS hỗ trợ như một extension ngay trên OpenFlow 1.0 dù bản thân action do OpenFlow 1.1 giới thiệu; action/instruction meter:meter_id: "Apply meter meter_id. If a meter band rate is exceeded, the packet may be dropped, or modified, depending on the meter band type.", do OpenFlow 1.3 giới thiệu như một instruction, đổi thành action từ OpenFlow 1.5 — ovs-actions(7), openvswitch.org.
  • RFC 4115 — Two-Rate Three-Color Marker, cơ sở thuật toán của QoS type trtcm-policer — 07/2005, rfc-editor.org/rfc/rfc4115.

Tiếp theo: Module 3, Bài 12 — OpenFlow pipeline sâu.