หากคุณใช้ลีนุกซ์เป็น 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
ขอบคุณมากครับ