00001
00002
00003 import interface
00004 import event
00005 from twisted.internet import reactor
00006 from twisted.internet.defer import inlineCallbacks
00007 import ip_rule
00008 import config
00009 import time
00010 import sys
00011 import radio_manager
00012 import logging_config
00013 import socket
00014 import system
00015 import re
00016 from netlink_monitor import netlink_monitor, IFSTATE, RunCommand
00017 from async_helpers import mainThreadCallback
00018
00019 summary_logger = logging_config.get_logger_stream_for_file('console.summary')
00020
00021 class RULEID:
00022 LOCAL=100
00023 FIRST_IFACE=50
00024 TUNNEL=150
00025 BLOCK_TUNNEL=175
00026 DEFAULT=200
00027 BLOCK_NON_TUNNEL=250
00028
00029 class InterfaceSelector:
00030 def __init__(self):
00031 self.interfaces = {}
00032 self.update_event = event.Event()
00033 self.update_interval = 1
00034 self.radio_manager = radio_manager.RadioManager()
00035 self.inactive_penalty = config.get_parameter('inactive_penalty', 50)
00036 self.forced_interface = ""
00037 self.tunnel_interface = config.get_parameter('tunnel_interface', "")
00038 self.use_tunnel = True
00039 self.active_interfaces = []
00040
00041 self.basestation = config.get_parameter('base_station')
00042
00043
00044
00045
00046
00047
00048
00049
00050 self.local_net_rules = []
00051 for (i, subnet) in enumerate(config.get_parameter('local_networks')):
00052 self.local_net_rules.append(ip_rule.IpRule(RULEID.LOCAL+i))
00053 self.local_net_rules[i].add('to', subnet, 'lookup', 'main')
00054
00055
00056 if self.tunnel_interface:
00057 self.vpn_rule = ip_rule.IpRule(RULEID.DEFAULT)
00058
00059
00060 system.system('ip', 'route', 'flush', 'table', str(RULEID.DEFAULT))
00061 netlink_monitor.get_state_publisher(self.tunnel_interface,
00062 IFSTATE.LINK).subscribe(self._refresh_default_route)
00063
00064
00065
00066 interface_names = config.get_parameter('interfaces').keys()
00067 ifaceid = RULEID.FIRST_IFACE
00068 for iface in interface_names:
00069 try:
00070 new_iface = self.interfaces[iface] = interface.construct(iface, ifaceid)
00071 new_iface.score = InterfaceSelector.TERRIBLE_INTERFACE
00072 new_iface.prescore = InterfaceSelector.TERRIBLE_INTERFACE
00073 ifaceid += 1
00074 except interface.NoType:
00075 print >> sys.stderr, "Interface %s has no type."%iface
00076 sys.exit(1)
00077 except interface.UnknownType, e:
00078 print >> sys.stderr, "Interface %s has unknown type %s."%(iface, e)
00079 sys.exit(1)
00080 except:
00081 print >> sys.stderr, "Error creating interface %s."%iface
00082 raise
00083
00084
00085 for i in self.interfaces.itervalues():
00086 if isinstance(i, interface.WirelessInterface):
00087 self.radio_manager.add_iface(i)
00088
00089
00090 self.tun_ip_rules = [ip_rule.IpRule(RULEID.TUNNEL+i) for i in range(len(self.interfaces) + 1)]
00091
00092
00093 self.shutting_down = False
00094 self._periodic_update()
00095 reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
00096
00097 def _shutdown(self):
00098 self.shutting_down = True
00099
00100 for tir in self.tun_ip_rules:
00101 tir.set()
00102 for lnr in self.local_net_rules:
00103 lnr.set()
00104
00105 @mainThreadCallback
00106 def set_mode(self, ssid = "", bssid = "", sel_interface = "", use_tunnel = True, band = 3, scan_only = False):
00107 print >> sys.stderr, "Dynamic reconfiguration ssid: %s bssid: %s iface: %s tun: %s band: %s scan_only: %s"%(ssid, bssid, sel_interface, use_tunnel, band, scan_only)
00108 self.goodness_weight = config.get_parameter('ping_weighting', 0.5)
00109 self.radio_manager.set_mode(ssid, bssid, band, scan_only, sel_interface)
00110 self.forced_interface = sel_interface
00111 self.use_tunnel = use_tunnel
00112 if self.tunnel_interface:
00113 if use_tunnel:
00114 self.vpn_rule.set('lookup', str(RULEID.DEFAULT))
00115 else:
00116 self.vpn_rule.set()
00117
00118 def _refresh_default_route(self, old_state, new_state):
00119 if new_state:
00120 system.system('ip', 'route', 'replace', 'table', str(RULEID.DEFAULT), 'default', "dev", self.tunnel_interface)
00121
00122 def _periodic_update(self):
00123 if self.shutting_down:
00124 return
00125 self.periodic_update_handle = reactor.callLater(self.update_interval, self._periodic_update)
00126
00127
00128 for iface in self.interfaces.values():
00129 iface.update(self.update_interval)
00130
00131
00132 self.radio_manager.update()
00133
00134
00135 self.rank_interfaces()
00136
00137
00138 self.update_event.trigger()
00139
00140 @inlineCallbacks
00141 def set_tun_rules(self, selected_interfaces):
00142
00143
00144 use_tunnel = self.use_tunnel
00145
00146
00147
00148
00149
00150
00151
00152
00153 if use_tunnel:
00154 try:
00155 self.basestation_ip = socket.gethostbyname(self.basestation)
00156 except socket.error:
00157 use_tunnel = False
00158
00159 for i, iface in enumerate(selected_interfaces):
00160 if use_tunnel:
00161 self.tun_ip_rules[i].set('to', self.basestation_ip, 'lookup', iface.tableid)
00162 else:
00163 self.tun_ip_rules[i].set('lookup', iface.tableid)
00164
00165 last_rule = len(selected_interfaces)
00166
00167 if use_tunnel:
00168 self.tun_ip_rules[last_rule].set('to', self.basestation_ip, 'blackhole')
00169 last_rule += 1
00170
00171
00172 for tir in self.tun_ip_rules[last_rule:]:
00173 yield tir.set()
00174
00175 TERRIBLE_INTERFACE = -1e1000
00176
00177 def score_interface(self, iface):
00178
00179
00180
00181
00182 if iface.goodness <= 0 and self.forced_interface != iface.iface:
00183 iface.prescore = iface.score = InterfaceSelector.TERRIBLE_INTERFACE
00184 return
00185
00186
00187
00188 if self.forced_interface and self.forced_interface != iface.iface:
00189 iface.prescore = iface.score = InterfaceSelector.TERRIBLE_INTERFACE
00190 return
00191
00192 iface.prescore = iface.score = self.goodness_weight * iface.goodness + (1 - self.goodness_weight) * iface.reliability + iface.priority
00193 if not iface.active:
00194 iface.score -= self.inactive_penalty
00195
00196 def rank_interfaces(self):
00197
00198 interfaces = self.interfaces.values()
00199 for iface in interfaces:
00200 self.score_interface(iface)
00201
00202
00203 interfaces.sort(key = lambda iface: iface.score, reverse = True)
00204 active_interfaces = [ iface for iface in interfaces if iface.score != self.TERRIBLE_INTERFACE ]
00205
00206 for iface in interfaces:
00207 if iface in active_interfaces:
00208 iface.rank = active_interfaces.index(iface)
00209 else:
00210 iface.rank = -1
00211
00212
00213 self.set_tun_rules(active_interfaces)
00214
00215
00216 now = time.time()
00217 print >> summary_logger
00218 print >> summary_logger, time.ctime(now), now
00219
00220 for rank, iface in enumerate(interfaces):
00221
00222 iface.timeout_time = now
00223 active = "active" if iface.active else ""
00224 rule = "rule " if iface in active_interfaces else "norule"
00225 print >> summary_logger, "#% 2i %10.10s %7.1f %7.3f %7.3f %17.17s %7.3f %3.0f %s %s"% \
00226 (rank, iface.prettyname, (iface.timeout_time - now), iface.score, iface.prescore, iface.bssid, iface.goodness, iface.reliability, rule, active)
00227
00228 self.active_interfaces = active_interfaces