Commit 514712db by Bach Dániel Committed by Bach Dániel

code refactoring

parent f6dc0c99
...@@ -5,11 +5,12 @@ import json ...@@ -5,11 +5,12 @@ import json
import logging import logging
from ovs import Switch from ovs import Switch
from utils import (NETNS, ns_exec, sudo, ADDRESSES,
dhcp_no_free_re, dhcp_ack_re)
DHCP_LOGFILE = getenv('DHCP_LOGFILE', '/var/log/syslog') DHCP_LOGFILE = getenv('DHCP_LOGFILE', '/var/log/syslog')
VLAN_CONF = getenv('VLAN_CONF', 'vlan.conf') VLAN_CONF = getenv('VLAN_CONF', 'vlan.conf')
FIREWALL_CONF = getenv('FIREWALL_CONF', 'firewall.conf') FIREWALL_CONF = getenv('FIREWALL_CONF', 'firewall.conf')
from utils import NETNS, ns_exec, sudo, ADDRESSES, UPLINK
celery = Celery('tasks', backend='amqp', ) celery = Celery('tasks', backend='amqp', )
celery.conf.update(CELERY_TASK_RESULT_EXPIRES=300, celery.conf.update(CELERY_TASK_RESULT_EXPIRES=300,
...@@ -20,9 +21,7 @@ logger = logging.getLogger(__name__) ...@@ -20,9 +21,7 @@ logger = logging.getLogger(__name__)
@task(name="firewall.reload_firewall") @task(name="firewall.reload_firewall")
def reload_firewall(data4, data6, onstart=False): def reload_firewall(data4, data6, save_config=True):
print "fw"
ns_exec(NETNS, ('/sbin/ip6tables-restore', '-c'), ns_exec(NETNS, ('/sbin/ip6tables-restore', '-c'),
'\n'.join(data6['filter']) + '\n') '\n'.join(data6['filter']) + '\n')
...@@ -30,40 +29,41 @@ def reload_firewall(data4, data6, onstart=False): ...@@ -30,40 +29,41 @@ def reload_firewall(data4, data6, onstart=False):
('\n'.join(data4['filter']) + '\n' + ('\n'.join(data4['filter']) + '\n' +
'\n'.join(data4['nat']) + '\n')) '\n'.join(data4['nat']) + '\n'))
if onstart is False: if save_config:
with open(FIREWALL_CONF, 'w') as f: with open(FIREWALL_CONF, 'w') as f:
json.dump([data4, data6], f) json.dump([data4, data6], f)
logger.info("Firewall configuration is reloaded.")
@task(name="firewall.reload_firewall_vlan") @task(name="firewall.reload_firewall_vlan")
def reload_firewall_vlan(data, onstart=False): def reload_firewall_vlan(data, save_config=True):
print "fw vlan" # Add additional addresses from config
for k, v in ADDRESSES.items(): for k, v in ADDRESSES.items():
data[k]['addresses'] = data[k]['addresses'] + v data[k]['addresses'] += v
try:
data[UPLINK[0]] = {'interfaces': UPLINK}
except:
pass
br = Switch('firewall') br = Switch('firewall')
br.migrate(data) br.migrate(data)
if onstart is False:
if save_config:
with open(VLAN_CONF, 'w') as f: with open(VLAN_CONF, 'w') as f:
json.dump(data, f) json.dump(data, f)
GATEWAY = getenv('GATEWAY', '152.66.243.254')
try: try:
ns_exec(NETNS, ('/sbin/ip', 'ro', 'add', 'default', 'via', GATEWAY)) ns_exec(NETNS, ('/sbin/ip', 'ro', 'add', 'default', 'via',
ns_exec(NETNS, ('/sbin/ip', 'ro', 'add', '10.12.0.0/22', getenv('GATEWAY', '152.66.243.254')))
'via', '10.12.255.253'))
except: except:
pass pass
logger.info("Interface (vlan) configuration is reloaded.")
@task(name="firewall.reload_dhcp") @task(name="firewall.reload_dhcp")
def reload_dhcp(data): def reload_dhcp(data):
print "dhcp" with open('/etc/dhcp/dhcpd.conf.generated', 'w') as f:
with open('/tools/dhcp3/dhcpd.conf.generated', 'w') as f:
f.write("\n".join(data) + "\n") f.write("\n".join(data) + "\n")
sudo(('/etc/init.d/isc-dhcp-server', 'restart')) sudo(('/etc/init.d/isc-dhcp-server', 'restart'))
logger.info("DHCP configuration is reloaded.")
def ipset_save(data): def ipset_save(data):
...@@ -88,8 +88,8 @@ def ipset_restore(l_add, l_del): ...@@ -88,8 +88,8 @@ def ipset_restore(l_add, l_del):
ipset = [] ipset = []
ipset.append('create blacklist hash:ip family inet hashsize ' ipset.append('create blacklist hash:ip family inet hashsize '
'4096 maxelem 65536') '4096 maxelem 65536')
ipset = ipset + ['add blacklist %s' % x for x in l_add] ipset += ['add blacklist %s' % x for x in l_add]
ipset = ipset + ['del blacklist %s' % x for x in l_del] ipset += ['del blacklist %s' % x for x in l_del]
ns_exec(NETNS, ('/usr/sbin/ipset', 'restore', '-exist'), ns_exec(NETNS, ('/usr/sbin/ipset', 'restore', '-exist'),
'\n'.join(ipset) + '\n') '\n'.join(ipset) + '\n')
...@@ -97,26 +97,9 @@ def ipset_restore(l_add, l_del): ...@@ -97,26 +97,9 @@ def ipset_restore(l_add, l_del):
@task(name="firewall.reload_blacklist") @task(name="firewall.reload_blacklist")
def reload_blacklist(data): def reload_blacklist(data):
print "blacklist"
l_add, l_del = ipset_save(data) l_add, l_del = ipset_save(data)
ipset_restore(l_add, l_del) ipset_restore(l_add, l_del)
logger.info("Blacklist configuration is reloaded.")
# 2013-06-26 12:16:59 DHCPACK on 10.4.0.14 to 5c:b5:24:e6:5c:81
# (android_b555bfdba7c837d) via vlan0004
dhcp_ack_re = re.compile(r'\S DHCPACK on (?P<ip>[0-9.]+) to '
r'(?P<mac>[a-zA-Z0-9:]+) '
r'(\((?P<hostname>[^)]+)\) )?'
r'via (?P<interface>[a-zA-Z0-9]+)')
# 2013-06-25 11:08:38 DHCPDISCOVER from 48:5b:39:8e:82:78
# via vlan0005: network 10.5.0.0/16: no free leases
dhcp_no_free_re = re.compile(r'\S DHCPDISCOVER '
r'from (?P<mac>[a-zA-Z0-9:]+) '
r'via (?P<interface>[a-zA-Z0-9]+):')
@task(name="firewall.get_dhcp_clients") @task(name="firewall.get_dhcp_clients")
...@@ -153,9 +136,8 @@ def start_firewall(): ...@@ -153,9 +136,8 @@ def start_firewall():
with open(FIREWALL_CONF, 'r') as f: with open(FIREWALL_CONF, 'r') as f:
data4, data6 = json.load(f) data4, data6 = json.load(f)
reload_firewall(data4, data6, True) reload_firewall(data4, data6, True)
except: except Exception as e:
print 'nemsikerult:(' logger.error('Unhandled exception: %s', unicode(e))
# raise
def start_networking(): def start_networking():
...@@ -163,13 +145,13 @@ def start_networking(): ...@@ -163,13 +145,13 @@ def start_networking():
with open(VLAN_CONF, 'r') as f: with open(VLAN_CONF, 'r') as f:
data = json.load(f) data = json.load(f)
reload_firewall_vlan(data, True) reload_firewall_vlan(data, True)
except: except Exception as e:
print 'nemsikerult:(' logger.error('Unhandled exception: %s', unicode(e))
# raise
def main(): def main():
start_networking() start_networking()
start_firewall() start_firewall()
main() main()
from netaddr import IPNetwork from netaddr import IPNetwork
from subprocess import CalledProcessError
import logging import logging
from utils import NETNS, sudo, ns_exec, MAC from utils import NETNS, sudo, ns_exec, HA
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class IPDevice:
def __init__(self, devname): class Interface(object):
self.devname = devname def __init__(self, name, data, with_show=False):
# {"interfaces": ["eth1"], "tag": 2, "trunks": [1, 2, 3],
# "type": "internal", "addresses": ["193.006.003.130/24", "None"]}
self.name = name
self.is_veth = data.get('type', 'external') == 'internal'
try:
self.untagged = int(data['tag'])
except (TypeError, KeyError):
self.untagged = None
try:
self.tagged = frozenset(int(i) for i in data['trunks'])
except (TypeError, KeyError):
self.tagged = frozenset()
if with_show:
data['addresses'] = self.show()
try:
self.addresses = frozenset(IPNetwork(i) for i in data['addresses']
if i != 'None')
except (TypeError, KeyError):
self.addresses = frozenset()
def __repr__(self):
return '<Interface: %s veth=%s| %s>' % (
self.name, self.is_veth, (self.untagged, self.tagged,
self.addresses))
def __eq__(self, other):
return self.__dict__ == other.__dict__
def __hash__(self):
r = reduce(lambda acc, x: acc ^ hash(x),
(self.name, self.is_veth, self.untagged, self.tagged), 0)
return r
@property
def external_name(self):
if self.is_veth:
return '%s-EXTERNAL' % self.name
else:
return self.name
def _run(self, *args): def _run(self, *args):
args = ('/sbin/ip', 'addr', ) + args args = ('/sbin/ip', 'addr', ) + args
...@@ -14,40 +59,46 @@ class IPDevice: ...@@ -14,40 +59,46 @@ class IPDevice:
def show(self): def show(self):
retval = [] retval = []
for line in self._run('show', self.devname, try:
for line in self._run('show', self.name,
'scope', 'global').splitlines(): 'scope', 'global').splitlines():
t = line.split() t = line.split()
if len(t) > 0 and t[0] in ('inet', 'inet6'): if len(t) > 0 and t[0] in ('inet', 'inet6'):
retval.append(IPNetwork(t[1])) retval.append(IPNetwork(t[1]))
logging.debug('[ip-%s] show: %s' % (self.devname, str(retval))) except CalledProcessError:
pass
logger.debug('[ip-%s] show: %s' % (self.name, str(retval)))
return retval return retval
def delete(self, address): def delete_address(self, address):
self._run('del', str(address), 'dev', self.devname) self._run('del', str(address), 'dev', self.name)
def add(self, address): def add_address(self, address):
self._run('add', str(address), 'dev', self.devname) self._run('add', str(address), 'dev', self.name)
def up(self): def up(self):
ns_exec(NETNS, ('/sbin/ip', 'link', 'set', 'up', self.devname)) if self.is_veth:
ns_exec(NETNS, ('/sbin/ip', 'link', 'set', 'up', self.name))
sudo(('/sbin/ip', 'link', 'set', 'up', self.external_name))
def migrate(self, new_addresses): def migrate(self):
old_addresses = [str(x) for x in self.show()] old_addresses = [str(x) for x in self.show()]
new_addresses = [str(x) for x in new_addresses] new_addresses = [str(x) for x in self.addresses]
delete = list(set(old_addresses) - set(new_addresses)) to_delete = list(set(old_addresses) - set(new_addresses))
add = list(set(new_addresses) - set(old_addresses)) to_add = list(set(new_addresses) - set(old_addresses))
logging.debug('[ip-%s] delete: %s' % (self.devname, str(delete))) logger.debug('[ip-%s] delete: %s' % (self.name, str(to_delete)))
logging.debug('[ip-%s] add: %s' % (self.devname, str(add))) logger.debug('[ip-%s] add: %s' % (self.name, str(to_add)))
for i in delete: for i in to_delete:
self.delete(i) self.delete_address(i)
for i in add: for i in to_add:
self.add(i) self.add_address(i)
class Switch: class Switch(object):
def __init__(self, brname): def __init__(self, brname):
self.brname = brname self.brname = brname
try: try:
...@@ -64,98 +115,86 @@ class Switch: ...@@ -64,98 +115,86 @@ class Switch:
return sudo(args) return sudo(args)
def list_ports(self): def list_ports(self):
retval = {} ovs = {}
bridge = None bridge = None
port = None port = None
for line in self._run('show').splitlines(): for line in self._run('show').splitlines():
t = line.split() t = line.split()
if t[0] == 'Bridge': if t[0] == 'Bridge':
bridge = t[1] bridge = t[1]
retval[bridge] = {} ovs[bridge] = {}
elif t[0] == 'Port': elif t[0] == 'Port':
port = t[1].replace('"', '') # valahol idezojel van port = t[1].replace('"', '') # valahol idezojel van
retval[bridge][port] = {} if port.endswith('-EXTERNAL'):
retval[bridge][port]['interfaces'] = [] port = port.rstrip('-EXTERNAL')
elif t[0] == 'Interface': type = 'internal'
interface = t[1].replace('"', '') # valahol idezojel van else:
retval[bridge][port]['interfaces'].append(interface) type = 'external'
ovs[bridge][port] = {'type': type}
elif t[0] == 'tag:': elif t[0] == 'tag:':
tag = int(t[1]) ovs[bridge][port]['tag'] = int(t[1])
retval[bridge][port]['tag'] = tag
elif t[0] == 'type:':
retval[bridge][port]['type'] = t[1]
elif t[0] == 'trunks:': elif t[0] == 'trunks:':
trunks = [int(p.strip('[,]')) for p in t[1:]] trunks = [int(p.strip('[,]')) for p in t[1:]]
retval[bridge][port]['trunks'] = trunks ovs[bridge][port]['trunks'] = trunks
return retval.get(self.brname, {}) # Create Interface objects
return [Interface(name, data, with_show=True)
def add_port(self, name, interfaces, tag, trunks, internal=True): for name, data in ovs.get(self.brname, {}).items()
if len(interfaces) > 1: if name != self.brname]
# bond
params = ['add-bond', self.brname, def add_port(self, interface):
name] + interfaces + ['tag=%d' % int(tag)] params = ['add-port', self.brname, interface.external_name]
else: if interface.untagged and not interface.tagged:
params = ['add-port', self.brname, name] params.append('tag=%d' % int(interface.untagged))
if tag is not None and (trunks is None or len(trunks) == 0): if interface.tagged:
params = params + ['tag=%d' % int(tag)] params.append('trunks=%s' % list(interface.tagged))
if internal:
params = params + ['--', 'set', 'Interface', interfaces[0],
'type=internal', 'mac=%s' % MAC]
if trunks is not None and len(trunks) > 0:
params.append('trunks=%s' % trunks)
self._run(*params) self._run(*params)
if not internal: # move interface into namespace
try: try:
self._setns(name) if interface.is_veth:
sudo(('/sbin/ip', 'link', 'add', interface.external_name,
'type', 'veth', 'peer', 'name', interface.name))
self._setns(interface.name)
except: except:
pass pass
def delete_port(self, name): def delete_port(self, interface):
self._run('del-port', self.brname, name) self._run('del-port', self.brname, interface.external_name)
if interface.is_veth:
try:
sudo(('/sbin/ip', 'link', 'del', interface.external_name))
except CalledProcessError:
pass
def migrate(self, new_ports): def migrate(self, new_ports):
old_ports = self.list_ports() old_interfaces = self.list_ports()
add = [] new_interfaces = [Interface(port, data)
delete = [] for port, data in new_ports.items()]
for port, data in new_ports.items(): add = [i for i in new_interfaces
if port not in old_ports: if i not in old_interfaces]
# new port delete = [i for i in old_interfaces
add.append(port) if i not in new_interfaces]
elif (old_ports[port].get('tag', None) !=
new_ports[port].get('tag', None) or add = list(set(new_interfaces).difference(set(old_interfaces)))
old_ports[port].get('trunks', None) != delete = list(set(old_interfaces).difference(set(new_interfaces)))
new_ports[port].get('trunks', None) or
old_ports[port].get('interfaces', None) != logger.debug('[ovs delete]: %s' % delete)
new_ports[port].get('interfaces', None)): logger.debug('[ovs add]: %s' % add)
# modified port
delete.append(port) for interface in delete:
add.append(port) self.delete_port(interface)
delete = delete + list(set(old_ports.keys()) - for interface in add:
set(new_ports.keys())) self.add_port(interface)
delete.remove(self.brname)
for interface in new_interfaces:
logging.debug('[ovs delete: %s' % (delete, ))
logging.debug('[ovs] add: %s' % (add, ))
for i in delete:
if not i.startswith('gre'):
self.delete_port(i)
for i in add:
internal = new_ports[i].get('type', '') == 'internal'
tag = new_ports[i].get('tag', None)
trunks = new_ports[i].get('trunks', [])
interfaces = new_ports[i]['interfaces']
self.add_port(i, interfaces, tag, trunks, internal)
for port, data in new_ports.items():
interface = IPDevice(devname=port)
try: try:
interface.migrate([IPNetwork(x) if interface.is_veth or not HA:
for x in data.get('addresses', [])
if x != 'None'])
if data.get('type', '') == 'internal':
interface.up() interface.up()
except: except CalledProcessError as e:
pass logger.warning(e)
try:
interface.migrate()
except CalledProcessError as e:
logger.warning(e)
...@@ -2,6 +2,7 @@ from os import getenv, devnull ...@@ -2,6 +2,7 @@ from os import getenv, devnull
import subprocess as sp import subprocess as sp
import logging import logging
import json import json
import re
logging.basicConfig() logging.basicConfig()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -9,8 +10,23 @@ logger.setLevel(logging.DEBUG) ...@@ -9,8 +10,23 @@ logger.setLevel(logging.DEBUG)
NETNS = getenv('NETNS', 'fw') NETNS = getenv('NETNS', 'fw')
MAC = getenv('MAC') MAC = getenv('MAC')
UPLINK = json.loads(getenv('UPLINK', '[]'))
ADDRESSES = json.loads(getenv('ADDRESSES', '{}')) ADDRESSES = json.loads(getenv('ADDRESSES', '{}'))
HA = bool(getenv('HA', False))
# 2013-06-26 12:16:59 DHCPACK on 10.4.0.14 to 5c:b5:24:e6:5c:81
# (android_b555bfdba7c837d) via vlan0004
dhcp_ack_re = re.compile(r'\S DHCPACK on (?P<ip>[0-9.]+) to '
r'(?P<mac>[a-zA-Z0-9:]+) '
r'(\((?P<hostname>[^)]+)\) )?'
r'via (?P<interface>[a-zA-Z0-9]+)')
# 2013-06-25 11:08:38 DHCPDISCOVER from 48:5b:39:8e:82:78
# via vlan0005: network 10.5.0.0/16: no free leases
dhcp_no_free_re = re.compile(r'\S DHCPDISCOVER '
r'from (?P<mac>[a-zA-Z0-9:]+) '
r'via (?P<interface>[a-zA-Z0-9]+):')
def sudo(args, stdin=None): def sudo(args, stdin=None):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment