00001
00002
00003 import system
00004 from twisted.internet.defer import inlineCallbacks, DeferredLock
00005 from twisted.internet import reactor
00006 from state_publisher import CompositeStatePublisher
00007 from netlink_monitor import netlink_monitor, IFSTATE
00008 import ip_rule
00009
00010
00011
00012 class _DhcpSetterCommon:
00013
00014
00015 def __init__(self):
00016 self._lock = DeferredLock()
00017 self.is_shutdown = False
00018 reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
00019
00020 @inlineCallbacks
00021 def _cb(self, old_state, new_state):
00022 if self.is_shutdown:
00023 return
00024 yield self._lock.acquire()
00025 try:
00026 yield self._locked_cb(old_state, new_state)
00027 finally:
00028 self._lock.release()
00029
00030 @inlineCallbacks
00031 def _shutdown(self):
00032
00033 yield self._cb(None, None)
00034 self.is_shutdown = True
00035
00036 class DhcpAddressSetter(_DhcpSetterCommon):
00037 def __init__(self, iface, state_pub):
00038 _DhcpSetterCommon.__init__(self)
00039 self.iface = iface
00040 self._iface_status_pub = netlink_monitor.get_status_publisher(iface)
00041 state_pub.subscribe(self._cb)
00042
00043 @inlineCallbacks
00044 def _locked_cb(self, old_state, new_state):
00045
00046 if new_state is None or old_state is not None:
00047 if self._iface_status_pub.get() >= IFSTATE.PLUGGED:
00048 yield system.system('ifconfig', self.iface, '0.0.0.0')
00049
00050 if new_state is not None:
00051 ip = new_state['ip']
00052 ip_slashed = new_state['ip_slashed']
00053 yield system.system('ip', 'addr', 'add', ip_slashed, 'dev', self.iface)
00054
00055 yield system.system('arping', '-q', '-c', '1', '-A', '-I', self.iface, ip)
00056 yield system.system('arping', '-q', '-c', '1', '-U', '-I', self.iface, ip)
00057
00058 class DhcpRouteSetter(_DhcpSetterCommon):
00059 def __init__(self, iface, table, state_pub):
00060 _DhcpSetterCommon.__init__(self)
00061 self.iface = iface
00062 self.table = str(table)
00063 self._iface_status_pub = netlink_monitor.get_status_publisher(iface)
00064 CompositeStatePublisher(lambda (addr, dhcp): None if not addr else dhcp, [
00065 netlink_monitor.get_state_publisher(iface, IFSTATE.ADDR),
00066 state_pub
00067 ]).subscribe(self._cb)
00068
00069 @inlineCallbacks
00070 def _locked_cb(self, old_state, new_state):
00071 if self._iface_status_pub.get() >= IFSTATE.PLUGGED:
00072 yield system.system('ip', 'route', 'flush', 'table', self.table, 'dev', self.iface)
00073
00074 if new_state:
00075 gateway = new_state['gateway']
00076 ip = new_state['ip']
00077 network_slashed = new_state['network_slashed']
00078 yield system.system('ip', 'route', 'add', 'table', self.table, 'default', 'dev', self.iface, 'via', gateway, 'src', ip, 'onlink')
00079 yield system.system('ip', 'route', 'add', 'table', self.table, network_slashed, 'dev', self.iface, 'src', ip)
00080
00081 class DhcpSourceRuleSetter:
00082 def __init__(self, iface, table, priority):
00083 self._ip_rule = ip_rule.IpRule(priority)
00084 self.table = str(table)
00085 self.state_pub = self._ip_rule.state_pub
00086 netlink_monitor.get_state_publisher(iface, IFSTATE.ADDR).subscribe(self._cb)
00087
00088 def _cb(self, old_state, new_state):
00089 if new_state:
00090 ip = new_state[0]
00091 self._ip_rule.set('table', self.table, 'from', ip+"/32")
00092 else:
00093 self._ip_rule.set()