[firewall4] Ajout de la QoS sur komaz

This commit is contained in:
Valentin Samir 2013-04-06 14:46:35 +02:00
parent 88ba72332a
commit f07999af6a

View file

@ -16,7 +16,8 @@ import socket
from ipset import IpsetError, Ipset from ipset import IpsetError, Ipset
from iptools import AddrInNet, NetSubnets, IpSubnet, NetInNets from iptools import AddrInNet, NetSubnets, IpSubnet, NetInNets
import subprocess import subprocess
from affich_tools import * import syslog
from affich_tools import anim, OK, cprint
squeeze = os.uname()[2] < '3' squeeze = os.uname()[2] < '3'
@ -31,6 +32,29 @@ dev = hostname in config.firewall.dev.keys() and config.firewall.dev[hostname] o
def pretty_print(table, chain): def pretty_print(table, chain):
anim('\t%s dans %s' % (chain, table)) anim('\t%s dans %s' % (chain, table))
class TcError(Exception):
""" Gestion des erreurs de tc """
def __init__(self,cmd,err_code,output):
self.cmd=cmd
self.err_code=err_code
self.output=output
syslog.syslog(syslog.LOG_ERR,"%s : status %s,%s" % (cmd,err_code,output))
def __str__(self):
return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output)
def tc(cmd, block=True):
""" Interface de tc """
params = ['/sbin/tc']
params.extend(cmd.split())
p = subprocess.Popen(params , stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if block:
status = p.wait()
stdoutdata, stderrdata = p.communicate()
if status:
raise TcError(' '.join(params), status, stdoutdata + stderrdata)
return stdoutdata + stderrdata
class firewall_base(object) : class firewall_base(object) :
def machines(self): def machines(self):
@ -145,6 +169,7 @@ class firewall_base(object) :
} }
self.use_ipset = [self.blacklist_hard, self.test_mac_ip] self.use_ipset = [self.blacklist_hard, self.test_mac_ip]
self.use_tc = []
self._machines = None self._machines = None
self._adherents = None self._adherents = None
@ -374,9 +399,11 @@ class firewall_komaz(firewall_base):
'blacklist_soft' : self.blacklist_soft, 'blacklist_soft' : self.blacklist_soft,
'reseaux_non_routable' : self.reseaux_non_routable, 'reseaux_non_routable' : self.reseaux_non_routable,
'filtrage_ports' : self.filtrage_ports, 'filtrage_ports' : self.filtrage_ports,
'limitation_debit' : self.limitation_debit,
}) })
self.use_ipset.extend([self.blacklist_soft, self.reseaux_non_routable]) self.use_ipset.extend([self.blacklist_soft, self.reseaux_non_routable])
self.use_tc.extend([self.limitation_debit])
self.ipset['reseaux_non_routable'] = { self.ipset['reseaux_non_routable'] = {
'deny' : Ipset("RESEAUX-NON-ROUTABLE-DENY","nethash"), 'deny' : Ipset("RESEAUX-NON-ROUTABLE-DENY","nethash"),
@ -396,9 +423,9 @@ class firewall_komaz(firewall_base):
self.add(table, chain, '-j %s' % self.connexion_secours(table)) self.add(table, chain, '-j %s' % self.connexion_secours(table))
self.add(table, chain, '-p tcp -j CONNMARK --restore-mark') self.add(table, chain, '-p tcp -j CONNMARK --restore-mark')
chain = 'POSTROUNTING' chain = 'POSTROUTING'
self.add(table, chain, '-j %s' % self.clamp_mss(table)) self.add(table, chain, '-j %s' % self.clamp_mss(table))
#TODO QoS self.add(table,chain, '-j %s' % self.limitation_debit(table, run_tc=True))
return return
def filter_table(self): def filter_table(self):
@ -695,6 +722,77 @@ class firewall_komaz(firewall_base):
self.apply(table, chain) self.apply(table, chain)
return chain return chain
def limitation_debit(self, table=None, run_tc=False, apply=False):
chain = 'LIMITATION-DEBIT'
debit_max = config.firewall.debit_max
uplink_speed = '1024mbit'
if table == 'mangle':
pretty_print(table, chain)
self.add(table, chain, '-d 138.231.136.98 -j RETURN')
self.add(table, chain, '-s 138.231.136.98 -j RETURN')
# Classification par defaut pour tous les paquets
for net in NETs['all']:
self.add(table, chain, '-o %s -s %s -j CLASSIFY --set-class 1:10' % (dev['out'], net))
self.add(table, chain, '-o %s -d %s -j CLASSIFY --set-class 1:10' % (dev['fil'], net))
self.add(table, chain, '-o %s -d %s -j CLASSIFY --set-class 1:10' % (dev['wifi'], net))
# Classification pour les appartements
for net in NETs['personnel-ens']:
self.add(table, chain, '-o %s -d %s -j CLASSIFY --set-class 1:3' % (dev['app'], net))
self.add(table, chain, '-o %s -s %s -j CLASSIFY --set-class 1:2' % (dev['out'], net))
print OK
if run_tc:
anim('\tApplication des commandes tc')
for int_key in ['out', 'fil', 'wifi']:
try:
tc('qdisc del dev %s root' % dev[int_key])
except TcError:
pass
tc('qdisc add dev %s root handle 1: htb r2q 1' % dev[int_key])
tc("class add dev %s parent 1: classid 1:1 "
"htb rate %s ceil %s" % (dev[int_key], uplink_speed, uplink_speed))
tc("class add dev %s parent 1:1 classid 1:2 "
"htb rate %skbps ceil %skbps" % (dev[int_key], debit_max, debit_max))
# Classe par defaut
tc('class add dev %s parent 1:2 classid 1:10 '
'htb rate %skbps ceil %skbps prio 1' % (dev[int_key], debit_max, debit_max))
tc('qdisc add dev %s parent 1:10 '
'handle 10: sfq perturb 10' % dev[int_key])
tc('filter add dev %s protocol all parent 10: handle 10 flow hash keys src perturb 30 divisor 1024 baseclass 1:10' % dev[int_key])
for int_key in ['app']:
try:
tc('qdisc del dev %s root' % dev[int_key])
except TcError:
pass
tc('qdisc add dev %s root handle 1: htb r2q 1' % dev[int_key])
tc("class add dev %s parent 1: classid 1:1 "
"htb rate 128kbps ceil 128kbps" % dev[int_key])
# Classe pour l'upload des appartements
tc("class add dev %s parent 1:1 classid 1:2 "
"htb rate 128kbps ceil 128kbps" % dev[int_key])
tc('qdisc add dev %s parent 1:2 '
'handle 2: sfq perturb 10' % dev[int_key])
# Classe pour le download des apparetments
tc("class add dev %s parent 1: classid 1:3 "
"htb rate %skbps ceil %skbps" % (dev[int_key], debit_max/10, debit_max/2))
tc('qdisc add dev %s parent 1:3 '
'handle 3: sfq perturb 10' % dev[int_key])
print OK
if apply:
self.apply(table, chain)
return chain
if __name__ == '__main__' : if __name__ == '__main__' :
firewall = { firewall = {
@ -751,7 +849,9 @@ Pour reconfiguration d'IPs particulières, utiliser generate. """ % \
fw.reloadable[arg](table) fw.reloadable[arg](table)
if fw.reloadable[arg] in fw.use_ipset: if fw.reloadable[arg] in fw.use_ipset:
fw.reloadable[arg](fill_ipset=True) fw.reloadable[arg](fill_ipset=True)
if fw.reloadable[arg] in fw.use_tc:
fw.reloadable[arg](run_tc=True)
anim('\tRestoration d\'iptables') anim('\tRestoration d\'iptables')
fw.restore(noflush=True) fw.restore(noflush=True)
print OK print OK