คอนฟิก QoS บนลีนุกซ์ด้วย HTB

หากคุณใช้ลีนุกซ์เป็น gateway หรือ router เชื่อมต่อระหว่างเน็ตเวิร์ก เช่นระหว่างภายในบริษัทและอินเตอร์เน็ต และต้องการควบคุมปริมาณการส่งข้อมูล Traffic Control หรือ QoS เช่นกำหนดว่าให้ใคร (ip, port) สามารถใช้ bandwidth ได้เท่าไรบ้าง

เท่าที่ผู้เขียนทดลองมา คิดว่าการใช้คำสั่ง tc คอนฟิกการใช้ bandwidth ด้วย HTB บนลีนุกซ์ น่าจะเป็นวิธีการคอนฟิกที่ง่ายที่สุด และยังสามารถกำหนดรายละเอียดในการคอนฟิกได้ค่อนข้างละเอียดอีกด้วย


คุณสมบัติการทำ traffic control หรือ QoS อยู่ใน kernel ซึ่งลีนุกซ์ส่วนใหญ่จะรวม (compile) ฟังก์ชั่น (CONFIG_NET_SCH*) นี้ไว้ใน kernel ด้วยอยู่แล้ว เวลาจะเปิดใช้การควบคุมนี้ เราก็แค่ใช้คำสั่ง tc เพื่อแสดงหรือแก้ไขคอนฟิกค่าต่างๆ

สำหรับ CentOS 6 คำสั่ง tc อยู่ในชุดแพ็คเกจ iproute ซึ่งส่วนใหญ่ติดตั้งเป็นดีฟอลต์มาอยู่แล้ว แต่ถ้ายังไม่มีก็ใช้ yum install iproute

เนื่องจากรายละเอียด คำอธิบายหลักการ ของการทำ Traffic Control หรือ QoS ค่อนข้างเยอะมาก ในที่นี้ขออธิบายเฉพาะส่วนที่ต้องใช้เท่านั้น

คำสั่ง tc  (traffic control) ใช้ในการแสดงค่าหรือแก้ไขคอนฟิกการควบคุมปริมาณการส่งข้อมูล

qdisc (queueing discipline) วิธีการจัดลำดับคิวในการส่งข้อมูลออกจากพอร์ต โดยดีฟอลต์จะเป็นแบบ pfifo (Pure First In, First Out) คือข้อมูลใดมาก่อน ก็ถูกส่งออกไปก่อน

การคอนฟิก traffic control บนลีนุกซ์ เป็นการเปลี่ยนวิธีการจัดลำดับคิว (qdisc) ในการส่งข้อมูลออกจากพอร์ต คือแทนที่จะใช้แบบ pfifo ให้เปลี่ยนไปใช้แบบอื่น เช่นในที่นี้เราจะเปลี่ยนไปใช้แบบ HTB (Hierarchy  Token  Bucket)

หมายเหตุ วิธีการแบบอื่นที่นิยมกันคือ CBQ (Class  Based  Queueing)

คำเตือน ทดลองให้เข้าใจหลักการก่อนคอนฟิกบน gateway หรือ router ที่ใช้งานจริง!

 

คอนฟิก qdisc

ใช้คำสั่ง tc qdisc เพื่อดูดีฟอลต์คอนฟิก ก่อนการเปลี่ยนแปลง

[root@cent6-router ~]# tc qdisc
qdisc pfifo_fast 0: dev eth0 root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev eth1 root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

หากต้องการดูเฉพาะพอร์ต ให้ระบุออปชั่น show dev eth0

[root@cent6-router ~]# tc qdisc show dev eth0
qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

ใช้คำสั่ง tc qdisc add เพื่อคอนฟิกเปลี่ยนวิธีการทำ qdisc ให้เป็นแบบ HTB ต้องระบุชื่อพอร์ตที่ต้องการแก้ไขด้วย เช่น eth0

[root@cent6-router ~]# tc qdisc add dev eth0 root handle 1: htb default 12

ใช้คำสั่ง tc qdisc show ดูคอนฟิกหลังการเปลี่ยน

[root@cent6-router ~]# tc qdisc show dev eth0
qdisc htb 1: root refcnt 2 r2q 10 default 12 direct_packets_stat 21

ตัวเลขหลัง handle คือ class id ในที่นี้คือ 1: จะใช้ในการอ้างอิงคอนฟิก root class (เขียนเต็มๆ คือ 1:0)

ส่วนตัวเลขหลังคำว่า default ในที่นี้คือ 12 คือเลข class id ไว้สำหรับเป็นดีฟอลต์คลาส สำหรับ traffic ที่ไม่สามารถจัดเข้ากลุ่มไหนได้  (เขียนเต็มๆ คือ 1:12)

 

คอนฟิก class, filter

ขั้นต่อมาต้องจัดแบ่งกลุ่มข้อมูลหรือ traffic ที่จะส่ง และคอนฟิกค่า bandwidth ที่ให้ใช้ได้

class แรกที่คอนฟิก เรียกว่า root class คือกำหนดความเร็ว (rate) ที่จะส่งข้อมูลออกจากพอร์ต เช่นต้องการให้ส่งได้ไม่เกิน 10 Mbps (10 เมกะบิตต่อวินาที)

ใช้คำสั่ง tc class add เพื่อเพิ่มคอนฟิก

[root@cent6-router ~]# tc class add dev eth0 parent 1: classid 1:1 htb rate 10000kbit

ตัวเลขหลัง parent ในที่นี้คือ 1: คือ root class id ที่ระบุหลังคำว่า handle ตอนคอนฟิกเปลี่ยน qdisc เป็น htb

ตัวเลขหลัง classid ในที่นี้คือ 1:1 เป็น id ของ class นี้สำหรับอ้างอิงเป็น parent ของ class อื่นๆ ต่อไป

rate คือความเร็วในการส่งข้อมูล

หมายเหตุ หน่วยของการคอนฟิก rate อาจเป็นที่สับสนกันบ้าง

  • kbps    Kilobytes per second
  • mbps   Megabytes per second
  • kbit      Kilobits per second
  • mbit    Megabits per second

เพื่อให้เปรียบเทียบได้ง่ายกับความเร็วของพอร์ต ที่นิยมระบุเป็น bit per second แนะนำให้คอนฟิกระบุหน่วยใช้เป็น bit เช่น kbit, mbit

ใช้คำสั่ง tc class show เพื่อดูคอนฟิกที่เปลี่ยนแปลง

[root@cent6-router ~]# tc class show dev eth0
class htb 1:1 root prio 0 rate 10000Kbit ceil 10000Kbit burst 1600b cburst 1600b

สร้าง class ย่อย ระบุ id 1:10 ภายใต้ parent class 1:1 (root class) ระบุ rate หรือความเร็วที่ส่งได้ที่ 5Mbit/s หรือ 5,000 Kilobit/s

[root@cent6-router ~]# tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5000kbit

ใช้คำสั่ง tc class show เพื่อดูคอนฟิกที่เปลี่ยนแปลง

[root@cent6-router ~]# tc class show dev eth0
class htb 1:10 parent 1:1 prio 0 rate 5000Kbit ceil 5000Kbit burst 1600b cburst 1600b
class htb 1:1 root rate 10000Kbit ceil 10000Kbit burst 1600b cburst 1600b

ใช้คำสั่ง tc filter add คอนฟิก filter เพื่อระบุประเภท traffic ที่จะถูกจัดเข้า class อาจระบุเป็น ip ทั้ง src (source) หรือ dst (destination) หรืออาจระบุ protocol หรือเลขพอร์ต (port number)

เช่นต้องการให้ traffic ที่ส่งไปยัง ip 192.168.5.6 ให้ถูกจัดเข้า class 1:10

[root@cent6-router ~]# tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
                         match ip dst 192.168.5.6 flowid 1:10

 

ใช้คำสั่ง tc filter show เพื่อดูคอนฟิก filter ที่เปลี่ยนแปลง

[root@cent6-router ~]# tc filter show dev eth0
filter parent 1: protocol ip pref 1 u32
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:10
  match c0a80506/ffffffff at 16

ทดลองใช้ ssh เพื่อ transfer ไฟล์ test-data.bin ไปยังเครื่อง ip 192.168.5.6

[root@cent6-router ~]# scp test-data.bin 192.168.5.6:/tmp/
root@192.168.5.6's password:
test-data.bin                                            16%   48MB 607.2KB/s   06:51 ETA

สังเกตว่า ความเร็วในการส่งข้อมูลจะถูกจำกัดสูงสุดไว้เท่ากับค่าคอนฟิก ceil ใน class

หมายเหตุ หากไม่ได้ระบุออปชั่น ceil ตอนคอนฟิก tc class add ค่า ceil จะเท่ากับค่า rate ที่ระบุไว้

ความเร็วที่แสดงในคำสั่ง scp หน่วยเป็น KB/s คือ Kilo Bytes per Second ถ้าแปลเป็น bits per second ต้องคูณด้วย 8 ก็จะได้ประมาณ 4,857 Kilo bits per second ใกล้เคียงกับค่า ceil ที่คอนฟิกไว้

ระหว่างการส่งไฟล์ ลองเปิดอีกหน้าจอ แล้วรันคำสั่ง tc -s class show ออปชั่น -s เพื่อดูสถิติในระหว่างการส่งข้อมูล

[root@cent6-router ~]# tc -s class show dev eth0
class htb 1:10 parent 1:1 prio 0 rate 5000Kbit ceil 5000Kbit burst 1600b cburst 1600b
 Sent 96469187 bytes 66068 pkt (dropped 0, overlimits 0 requeues 0)
 rate 4998Kbit 427pps backlog 0b 222p requeues 0
 lended: 12413 borrowed: 0 giants: 0
 tokens: -217700 ctokens: -217700

class htb 1:1 root rate 10000Kbit ceil 10000Kbit burst 1600b cburst 1600b
 Sent 94961647 bytes 65037 pkt (dropped 0, overlimits 0 requeues 0)
 rate 4998Kbit 427pps backlog 0b 0p requeues 0
 lended: 0 borrowed: 0 giants: 0
 tokens: -89465 ctokens: -89465

 

แต่ถ้าส่งไฟล์ไปยังเครื่องอื่นๆ ที่ไม่อยู่ใน class ที่สร้างไว้ หรือไม่ตรง match กับ filter ที่สร้าง เช่นไฟล์ไปยัง 192.168.5.7

[root@cent6-router ~]# scp test-data.bin 192.168.5.7:/tmp/
192.168.5.7's password:
test-data.bin                                             8%   25MB  24.7MB/s   00:10 ETA

ยังสามารถส่งได้เต็มที่ ตามความเร็วของพอร์ต

หากต้องการจำกัดความเร็วด้วย ต้องสร้าง class ดีฟอลต์สำหรับ traffic อื่นๆ ที่ไม่ถูกจัดหรือ match กับ filter เพื่อถูกจัดเข้า class

[root@cent6-router ~]# tc class add dev eth0 parent 1:1 classid 1:12 htb rate 1000kbit

ดูคอนฟิกหลังแก้ไข

[root@cent6-router ~]# tc class show dev eth0
class htb 1:10 parent 1:1 prio 0 rate 5000Kbit ceil 5000Kbit burst 1600b cburst 1600b
class htb 1:1 root rate 10000Kbit ceil 10000Kbit burst 1600b cburst 1600b
class htb 1:12 parent 1:1 prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b

ทดลอง transfer ไฟล์ไปยังเครื่องอื่นที่ไม่ match กับ filter ที่สร้างไว้อีกครั้ง จะเหลือแค่ไม่เกิน 1000 kilo bit per second เท่านั้น

[root@cent6-router ~]# scp test-data.bin 192.168.5.7:/tmp/
root@192.168.5.7's password:
test-data.bin                                              6%   19MB 117.3KB/s   39:45 ETA

อีกหน้าจอ รันคำสั่ง tc -s class show ออปชั่น -s เพื่อดูสถิติ ระหว่างการส่งข้อมูล

[root@cent6-router ~]# tc -s class show dev eth0
class htb 1:10 parent 1:1 prio 0 rate 5000Kbit ceil 5000Kbit burst 1600b cburst 1600b
 Sent 172935090 bytes 118955 pkt (dropped 0, overlimits 0 requeues 0)
 rate 2304bit 1pps backlog 0b 0p requeues 0
 lended: 24260 borrowed: 0 giants: 0
 tokens: 37000 ctokens: 37000

class htb 1:1 root rate 10000Kbit ceil 10000Kbit burst 1600b cburst 1600b
 Sent 201616269 bytes 138964 pkt (dropped 0, overlimits 0 requeues 0)
 rate 997904bit 87pps backlog 0b 0p requeues 0
 lended: 0 borrowed: 0 giants: 0
 tokens: 18500 ctokens: 18500

class htb 1:12 parent 1:1 prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b
 Sent 30197315 bytes 21063 pkt (dropped 0, overlimits 0 requeues 0)
 rate 998880bit 86pps backlog 0b 194p requeues 0
 lended: 2939 borrowed: 0 giants: 0
 tokens: -1076715 ctokens: -1076715

 

คำอธิบายก็คือ การส่งข้อมูลไปยัง 192.168.5.7 ไม่ match กับ filter ใดๆ เลย ทำให้ตกไปยัง class ดีฟอลต์ที่ระบุไว้ตอนรันคำสั่ง tc qdisc add ซึ่งในที่นี้คือ class 1:12

 

ข้อมูลอ้างอิง

Leave a Reply