Editing Traffic shaping with tc

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
Sometimes it's necessary to limit traffic bandwidth from and to a [[container]].
+
Sometimes it's necessary to limit traffic bandwidth from and to a [[VE]].
 
You can do it using ordinary <code>tc</code> tool.
 
You can do it using ordinary <code>tc</code> tool.
  
 
== Packet routes ==
 
== Packet routes ==
First of all, a few words about how packets travel from and to a [[container]].
+
First of all, a few words about how packets travel from and to a [[VE]].
Suppose we have [[Hardware Node]] (HN) with a container (CT) on it, and this
+
Suppose we have [[Hardware Node]] (HN) with a VE on it, and this VE talks
container talks to some Remote Host (RH). HN has one "real" network interface
+
to some Remote Host (RH). HN has one "real" network interface <tt>eth0</tt> and,  
<tt>eth0</tt> and,  
 
 
thanks to OpenVZ, there is also "virtual" network interface <tt>venet0</tt>.
 
thanks to OpenVZ, there is also "virtual" network interface <tt>venet0</tt>.
Inside the container we have interface <tt>venet0:0</tt>.
+
Inside the VE we have interface <tt>venet0:0</tt>.
  
 
<pre>
 
<pre>
 
     venet0:0              venet0    eth0
 
     venet0:0              venet0    eth0
CT >------------->-------------> HN >--------->--------> RH
+
VE >------------->-------------> HN >--------->--------> RH
  
 
     venet0:0              venet0    eth0
 
     venet0:0              venet0    eth0
CT <-------------<-------------< HN <---------<--------< RH
+
VE <-------------<-------------< HN <---------<--------< RH
 
</pre>
 
</pre>
  
 
== Limiting outgoing bandwidth ==
 
== Limiting outgoing bandwidth ==
We can limit container outgoing bandwidth by setting the <tt>tc</tt> filter on <tt>eth0</tt>.
+
We can limit VE outgoing bandwidth by setting the <tt>tc</tt> filter on <tt>eth0</tt>.
 
<pre>
 
<pre>
 
DEV=eth0
 
DEV=eth0
Line 28: Line 27:
 
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
 
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
 
</pre>
 
</pre>
X.X.X.X is an IP address of container.
+
X.X.X.X is an IP address of VE.
  
 
== Limiting incoming bandwidth ==
 
== Limiting incoming bandwidth ==
Line 40: Line 39:
 
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
 
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
 
</pre>
 
</pre>
Note that <code>X.X.X.X</code> is an IP address of container.
+
Note that <code>X.X.X.X</code> is an IP address of VE.
  
== Limiting CT to HN talks ==
+
== Limiting VE to HN talks ==
As you can see, two filters above don't limit [[container]] to [[HN]] talks.
+
As you can see, two filters above don't limit [[VE]] to [[HN]] talks.
I mean a [[container]] can emit as much traffic as it wishes. To make such a limitation from the [[HN]],
+
I mean a [[VE]] can emit as much traffic as it wishes. To make such a limitation from the [[HN]],
 
it is necessary to use <tt>tc</tt> police on <tt>venet0</tt>:
 
it is necessary to use <tt>tc</tt> police on <tt>venet0</tt>:
 
<pre>
 
<pre>
Line 51: Line 50:
 
</pre>
 
</pre>
  
== Limiting packets per second rate from container ==
+
== Limiting packets per second rate from VE ==
To prevent dos atacks from the container you can limit packets per second rate using iptables.
+
To prevent dos atacks from the VE you can limit packets per second rate using iptables.
<source lang="bash">
+
<pre>
 
DEV=eth0
 
DEV=eth0
 
iptables -I FORWARD 1 -o $DEV -s X.X.X.X -m limit --limit 200/sec -j ACCEPT
 
iptables -I FORWARD 1 -o $DEV -s X.X.X.X -m limit --limit 200/sec -j ACCEPT
 
iptables -I FORWARD 2 -o $DEV -s X.X.X.X -j DROP
 
iptables -I FORWARD 2 -o $DEV -s X.X.X.X -j DROP
</source>
+
</pre>
Here <code>X.X.X.X</code> is an IP address of container.
+
Here <code>X.X.X.X</code> is an IP address of VE
 
 
== An alternate approach using HTB ==
 
 
 
For details refer to the [http://luxik.cdi.cz/~devik/qos/htb/ HTB Home Page]
 
 
 
<source lang="bash">
 
#!/bin/sh
 
#
 
# Incoming traffic control
 
#
 
CT_IP1=$1
 
CT_IP2=$2
 
DEV=venet0
 
#
 
tc qdisc del dev $DEV root
 
#
 
tc qdisc add dev $DEV root handle 1: htb default 10
 
#
 
tc class add dev $DEV parent 1: classid 1:1 htb rate 100mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:10 htb rate 10mbit ceil 10mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:20 htb rate 20mbit ceil 20mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:30 htb rate 30mbit ceil 30mbit burst 15k
 
#
 
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
 
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
 
tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10
 
#
 
if [ ! -z $CT_IP1 ]; then
 
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dst "$CT_IP1" flowid 1:20
 
fi
 
if [ ! -z $CT_IP2 ]; then
 
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dst "$CT_IP2" flowid 1:30
 
fi
 
#
 
echo;echo "tc configuration for $DEV:"
 
tc qdisc show dev $DEV
 
tc class show dev $DEV
 
tc filter show dev $DEV
 
#
 
# Outgoing traffic control
 
#
 
DEV=eth0
 
#
 
tc qdisc del dev $DEV root
 
#
 
tc qdisc add dev $DEV root handle 1: htb default 10
 
#
 
tc class add dev $DEV parent 1: classid 1:1 htb rate 100mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:10 htb rate 10mbit ceil 10mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:20 htb rate 20mbit ceil 20mbit burst 15k
 
tc class add dev $DEV parent 1:1 classid 1:30 htb rate 30mbit ceil 30mbit burst 15k
 
#
 
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
 
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
 
tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10
 
#
 
if [ ! -z $CT_IP1 ]; then
 
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip src "$CT_IP1" flowid 1:20
 
fi
 
if [ ! -z $CT_IP2 ]; then
 
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip src "$CT_IP2" flowid 1:30
 
fi
 
#
 
echo;echo "tc configuration for $DEV:"
 
tc qdisc show dev $DEV
 
tc class show dev $DEV
 
tc filter show dev $DEV
 
</source>
 
 
 
 
 
 
 
== Autogen rules for CT ==
 
 
 
<source lang="python">
 
#!/usr/bin/env python
 
# -*- coding: utf-8 -*-
 
######################################
 
## by VoidLess, lepus.su
 
######################################
 
import fnmatch
 
import os
 
 
 
######################################
 
## НАСТРОЙКИ СКРИПТА
 
confdir = "/etc/vz/conf/"
 
rulefile = "/etc/vz/shaper/rules.sh"
 
 
 
# шейпятся только эти тарифы
 
table_band = {
 
    #ORIGIN_SAMPLE : канал
 
    "SSD8": "100mbit",
 
    "SSD7": "100mbit",
 
    "SSD6": "100mbit",
 
    "SSD5": "100mbit",
 
    "SSD4": "100mbit",
 
    "SSD3": "100mbit",
 
    "SSD2": "100mbit",
 
    "SSD1": "100mbit"
 
}
 
 
 
######################################
 
## ШАБЛОН СКРИПТА НАСТРОЙКИ ШЕЙПЕРА
 
 
 
fileheader = """#!/bin/bash
 
# shaper configuration file
 
 
 
##### ЧИСТКА ОТ СТАРЫХ ПРАВИЛ #####
 
tc qdisc del dev eth0 root
 
tc -s qdisc ls dev eth0
 
 
 
tc qdisc del dev venet0 root
 
tc -s qdisc ls dev venet0
 
##### ЧИСТКА ОТ СТАРЫХ ПРАВИЛ #####
 
"""
 
 
 
# eth0
 
 
 
eth0header = """
 
DEV=eth0
 
tc qdisc del dev $DEV root 2>/dev/null
 
tc qdisc add dev $DEV root handle 1: htb default 1 r2q 3000
 
tc class add dev $DEV parent 1: classid 1:1 htb rate 1000mbit burst 10mb
 
"""
 
 
 
eth0template = """
 
# vzid {VPSID} tarif {BANDWIDTH} ip {IP}
 
 
 
tc class add dev $DEV parent 1:1 classid 1:{CLASS} htb rate {BANDWIDTH} ceil {BANDWIDTH} burst 1mb
 
tc qdisc add dev $DEV parent 1:{CLASS} handle {CLASS}: sfq perturb 5 #quantum 5000b
 
"""
 
 
 
eth0match = """
 
tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip src {IP} flowid 1:{CLASS}
 
"""
 
 
 
# venet0
 
 
 
venet0header = """
 
DEV=venet0
 
tc qdisc del dev $DEV root 2>/dev/null
 
tc qdisc add dev $DEV root handle 1: htb default 1 r2q 3000
 
tc class add dev $DEV parent 1: classid 1:1 htb rate 1000mbit burst 10mb
 
"""
 
 
 
venet0template = """
 
# vzid {VPSID} tarif {BANDWIDTH} ip {IP}
 
 
 
tc class add dev $DEV parent 1:1 classid 1:{CLASS} htb rate {BANDWIDTH} ceil {BANDWIDTH} burst 1mb
 
tc qdisc add dev $DEV parent 1:{CLASS} handle {CLASS}: sfq perturb 5 #quantum 5000b
 
"""
 
 
 
venet0match = """
 
tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dst {IP} flowid 1:{CLASS}
 
"""
 
 
 
######################################
 
## КОД СКРИПТА
 
# получает список и настройки виртуалок из папки конфигов OpenVZ
 
def getvz():
 
    vzlist = []
 
 
 
    for file in os.listdir(confdir):
 
        if fnmatch.fnmatch(file, '*.conf') and file != "0.conf":
 
            #берем список конфигов
 
            vzid = file.split(".",1)[0]
 
            vztarif = None
 
            vzip = None
 
 
 
            #открываем файл, узнаем название тарифа
 
            with open(confdir + file) as f:
 
                for line in f:
 
                    if line[0]=="#":
 
                        continue
 
 
 
                    ar = line.split("=")
 
 
 
                    if ar[0] == "ORIGIN_SAMPLE":
 
                        vztarif = ar[1].replace('"', '').strip()
 
                        continue
 
 
 
                    if ar[0] == "IP_ADDRESS":
 
                        vzip = ar[1].replace('"', '').strip().split(" ")
 
                        continue
 
 
 
            #если в файле не написан тариф, или он левый, ничего не делаем
 
            if vztarif == None or vzip == None or vztarif not in table_band:
 
                continue
 
           
 
            # в список записываем инфу про все vps
 
            vzlist.append((vzid, table_band[vztarif], vzip))
 
    return vzlist
 
 
 
# записывает команды настройки шейпера в sh файл
 
def genconf(vzlist):
 
    with open(rulefile,"w+") as f:
 
 
 
        # file header
 
        f.write(fileheader)
 
 
 
        # eth0 rules
 
        f.write(eth0header)
 
 
 
        shaper_id = 100
 
        for vz in vzlist:
 
            f.write(eth0template
 
                        .replace("{VPSID}",vz[0])
 
                        .replace("{CLASS}",str(shaper_id))
 
                        .replace("{BANDWIDTH}",vz[1])
 
                        .replace("{IP}",str(vz[2])))
 
            for ip in vz[2]:
 
                f.write(eth0match
 
                            .replace("{VPSID}",vz[0])
 
                            .replace("{CLASS}",str(shaper_id))
 
                            .replace("{IP}",ip))
 
            shaper_id += 1
 
 
 
        # venet0 rules
 
        f.write(venet0header)
 
 
 
        shaper_id = 100
 
        for vz in vzlist:
 
            f.write(venet0template
 
                        .replace("{VPSID}",vz[0])
 
                        .replace("{CLASS}",str(shaper_id))
 
                        .replace("{BANDWIDTH}",vz[1])
 
                        .replace("{IP}",str(vz[2])))
 
            for ip in vz[2]:
 
                f.write(venet0match
 
                            .replace("{VPSID}",vz[0])
 
                            .replace("{CLASS}",str(shaper_id))
 
                            .replace("{IP}",ip))
 
            shaper_id += 1
 
 
 
    # make in runnable
 
    os.chmod(rulefile, 0755)
 
 
 
## основной код скрипта. выполнение функций
 
# получили список VPSок
 
vzlist = getvz()
 
 
 
# сгенерировали скрипт с правилами
 
genconf(vzlist)
 
 
 
# применили правила
 
os.system(rulefile)
 
</source>
 
 
 
  
 
== External links ==
 
== External links ==

Please note that all contributions to OpenVZ Virtuozzo Containers Wiki may be edited, altered, or removed by other contributors. If you don't want your writing to be edited mercilessly, then don't submit it here.
If you are going to add external links to an article, read the External links policy first!

To edit this page, please answer the question that appears below (more info):

Cancel Editing help (opens in new window)