1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import re, socket, subprocess 6 from autotest_lib.client.common_lib import error 7 8 class HostRoute(object): 9 """ 10 Host Route: A utility for retrieving information about our route to a host 11 12 """ 13 14 def __init__(self, host): 15 self.host = host # Remote host 16 self.calculate() 17 18 def calculate(self): 19 output = self.run_command(["ip", "route", "get", self.host]) 20 # This converts "172.22.18.53 via 10.0.0.1 dev eth0 src 10.0.0.200 \n.." 21 # into ("via", "10.0.0.1", "dev", "eth0", "src", "10.0.0.200") 22 route_info = re.split("\s*", output.split("\n")[0].rstrip(' '))[1:] 23 24 # Further, convert the list into a dict {"via": "10.0.0.1", ...} 25 self.route_info = dict(tuple(route_info[i:i+2]) 26 for i in range(0, len(route_info), 2)) 27 28 if 'src' not in self.route_info: 29 raise error.TestFail('Cannot find route to host %s' % self.host) 30 31 class LocalHostRoute(HostRoute): 32 """ 33 Self Host Route: Retrieve host route for the test-host machine 34 35 """ 36 def __init__(self, host): 37 # TODO(pstew): If we could depend on the host having the "ip" command 38 # we would just be able to do this: 39 # 40 # HostRoute.__init__(self, host) 41 # 42 # but alas, we can't depend on this, so we fake it by creating a 43 # socket and figuring out what local address we bound to if we 44 # connected to the client 45 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 46 sock.connect((host, 22)) # NB: Port doesn't matter 47 self.route_info = { 'src': sock.getsockname()[0] } 48 49 def run_command(self, args): 50 return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] 51 52 class RemoteHostRoute(HostRoute): 53 """ 54 Remote Host Route: Retrieve host route for a remote (DUT, server) machine 55 56 """ 57 def __init__(self, remote, host): 58 self.remote = remote 59 HostRoute.__init__(self, host) 60 61 def run_command(self, args): 62 return self.remote.run(' '.join(args)).stdout 63