| OLD | NEW |
| 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import common, fnmatch, logging, os, re, string, threading, time | 5 import common, fnmatch, logging, os, re, string, threading, time |
| 6 | 6 |
| 7 from autotest_lib.server import autotest, hosts, subcommand | 7 from autotest_lib.server import autotest, hosts, subcommand |
| 8 from autotest_lib.server import site_bsd_router | 8 from autotest_lib.server import site_bsd_router |
| 9 from autotest_lib.server import site_linux_router | 9 from autotest_lib.server import site_linux_router |
| 10 from autotest_lib.server import site_host_attributes | 10 from autotest_lib.server import site_host_attributes |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 by adding a new class and auto-selecting it in __init__. | 61 by adding a new class and auto-selecting it in __init__. |
| 62 | 62 |
| 63 The WiFiTest class could be generalized to handle clients other than | 63 The WiFiTest class could be generalized to handle clients other than |
| 64 ChromeOS; this would useful for systems that use Network Manager or | 64 ChromeOS; this would useful for systems that use Network Manager or |
| 65 wpa_supplicant directly. | 65 wpa_supplicant directly. |
| 66 """ | 66 """ |
| 67 | 67 |
| 68 def __init__(self, name, steps, config): | 68 def __init__(self, name, steps, config): |
| 69 self.name = name | 69 self.name = name |
| 70 self.steps = steps | 70 self.steps = steps |
| 71 self.keyvals = {} | 71 self.perf_keyvals = {} |
| 72 | 72 |
| 73 router = config['router'] | 73 router = config['router'] |
| 74 self.router = hosts.create_host(router['addr']) | 74 self.router = hosts.create_host(router['addr']) |
| 75 # NB: truncate SSID to 32 characters | 75 # NB: truncate SSID to 32 characters |
| 76 self.defssid = self.__get_defssid(router['addr'])[0:32] | 76 self.defssid = self.__get_defssid(router['addr'])[0:32] |
| 77 | 77 |
| 78 defaults = config.get('defaults', {}) | 78 defaults = config.get('defaults', {}) |
| 79 self.deftimeout = defaults.get('timeout', 30) | 79 self.deftimeout = defaults.get('timeout', 30) |
| 80 self.defpingcount = defaults.get('pingcount', 10) | 80 self.defpingcount = defaults.get('pingcount', 10) |
| 81 self.defwaittime = str(defaults.get('netperf_wait_time', 3)) | 81 self.defwaittime = str(defaults.get('netperf_wait_time', 3)) |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 self.server = None; | 125 self.server = None; |
| 126 # NB: wifi address must be set if not reachable from control | 126 # NB: wifi address must be set if not reachable from control |
| 127 self.server_wifi_ip = server['wifi_addr'] | 127 self.server_wifi_ip = server['wifi_addr'] |
| 128 | 128 |
| 129 # potential bg thread for ping untilstop | 129 # potential bg thread for ping untilstop |
| 130 self.ping_thread = None | 130 self.ping_thread = None |
| 131 | 131 |
| 132 # potential bg thread for client network monitoring | 132 # potential bg thread for client network monitoring |
| 133 self.client_netdump_thread = None | 133 self.client_netdump_thread = None |
| 134 self.__client_discover_commands(client) | 134 self.__client_discover_commands(client) |
| 135 self.netperf_iter = 0 | |
| 136 self.firewall_rules = [] | 135 self.firewall_rules = [] |
| 137 | 136 |
| 137 # Find all repeated steps and create iterators for them |
| 138 self.iterated_steps = {} |
| 139 step_names = [step[0] for step in steps] |
| 140 for step_name in list(set(step_names)): |
| 141 if step_names.count(step_name) > 1: |
| 142 self.iterated_steps[step_name] = 0 |
| 138 | 143 |
| 139 def cleanup(self, params): | 144 def cleanup(self, params): |
| 140 """ Cleanup state: disconnect client and destroy ap """ | 145 """ Cleanup state: disconnect client and destroy ap """ |
| 141 self.disconnect({}) | 146 self.disconnect({}) |
| 142 self.wifi.destroy({}) | 147 self.wifi.destroy({}) |
| 143 self.client_netdump_stop({}) | 148 self.client_netdump_stop({}) |
| 144 self.firewall_cleanup({}) | 149 self.firewall_cleanup({}) |
| 145 | 150 |
| 146 | 151 |
| 147 def __client_discover_commands(self, client): | 152 def __client_discover_commands(self, client): |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 in this class or the ancillary router class and invoked with | 186 in this class or the ancillary router class and invoked with |
| 182 the supplied parameter dictionary. | 187 the supplied parameter dictionary. |
| 183 """ | 188 """ |
| 184 for s in self.steps: | 189 for s in self.steps: |
| 185 method = s[0] | 190 method = s[0] |
| 186 if len(s) > 1: | 191 if len(s) > 1: |
| 187 params = s[1] | 192 params = s[1] |
| 188 else: | 193 else: |
| 189 params = {} | 194 params = {} |
| 190 | 195 |
| 196 # What should perf data be prefixed with? |
| 197 if 'perf_prefix' in params: |
| 198 self.prefix = '%s_%s' % (method, params.pop('perf_prefix')) |
| 199 elif method in self.iterated_steps: |
| 200 self.prefix = '%s_%d' % (method, self.iterated_steps[method]) |
| 201 self.iterated_steps[method] += 1 |
| 202 else: |
| 203 self.prefix = method |
| 204 |
| 191 logging.info("%s: step '%s' params %s", self.name, method, params) | 205 logging.info("%s: step '%s' params %s", self.name, method, params) |
| 192 | 206 |
| 193 func = getattr(self, method, None) | 207 func = getattr(self, method, None) |
| 194 if func is None: | 208 if func is None: |
| 195 func = getattr(self.wifi, method, None) | 209 func = getattr(self.wifi, method, None) |
| 196 if func is not None: | 210 if func is not None: |
| 197 try: | 211 try: |
| 198 func(params) | 212 func(params) |
| 199 except Exception, e: | 213 except Exception, e: |
| 200 logging.error("%s: Step '%s' failed: %s; abort test", | 214 logging.error("%s: Step '%s' failed: %s; abort test", |
| 201 self.name, method, str(e)) | 215 self.name, method, str(e)) |
| 202 self.cleanup(params) | 216 self.cleanup(params) |
| 203 raise e | 217 raise e |
| 204 break | 218 break |
| 205 else: | 219 else: |
| 206 logging.error("%s: Step '%s' unknown; abort test", | 220 logging.error("%s: Step '%s' unknown; abort test", |
| 207 self.name, method) | 221 self.name, method) |
| 208 self.cleanup(params) | 222 self.cleanup(params) |
| 209 break | 223 break |
| 210 | 224 |
| 211 # Other cleanup steps might be optional, but this is mandatory | 225 # Other cleanup steps might be optional, but this is mandatory |
| 212 self.client_netdump_stop({}) | 226 self.client_netdump_stop({}) |
| 213 | 227 |
| 214 | 228 |
| 215 def write_keyvals(self, job): | 229 def write_keyvals(self, job): |
| 216 job.write_perf_keyval(self.keyvals) | 230 job.write_perf_keyval(self.perf_keyvals) |
| 217 | 231 |
| 232 def write_perf(self, data): |
| 233 for key, value in data.iteritems(): |
| 234 self.perf_keyvals['%s_%s' % (self.prefix, key)] = value |
| 218 | 235 |
| 219 def __get_ipaddr(self, host, ifnet): | 236 def __get_ipaddr(self, host, ifnet): |
| 220 # XXX gotta be a better way to do this | 237 # XXX gotta be a better way to do this |
| 221 result = host.run("%s %s" % (self.client_cmd_ifconfig, ifnet)) | 238 result = host.run("%s %s" % (self.client_cmd_ifconfig, ifnet)) |
| 222 m = re.search('inet addr:([^ ]*)', result.stdout) | 239 m = re.search('inet addr:([^ ]*)', result.stdout) |
| 223 if m is None: | 240 if m is None: |
| 224 raise error.TestFail("No inet address found") | 241 raise error.TestFail("No inet address found") |
| 225 return m.group(1) | 242 return m.group(1) |
| 226 | 243 |
| 227 | 244 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 243 result = self.client.run('python "%s" "%s" "%s" "%s" "%d" "%d"' % | 260 result = self.client.run('python "%s" "%s" "%s" "%s" "%d" "%d"' % |
| 244 (script_client_file, | 261 (script_client_file, |
| 245 params.get('ssid', self.wifi.get_ssid()), | 262 params.get('ssid', self.wifi.get_ssid()), |
| 246 params.get('security', ''), | 263 params.get('security', ''), |
| 247 params.get('psk', ''), | 264 params.get('psk', ''), |
| 248 params.get('assoc_timeout', self.deftimeout), | 265 params.get('assoc_timeout', self.deftimeout), |
| 249 params.get('config_timeout', self.deftimeout))).stdout.rstrip() | 266 params.get('config_timeout', self.deftimeout))).stdout.rstrip() |
| 250 | 267 |
| 251 result_times = re.match("OK ([0-9\.]*) ([0-9\.]*) .*", result) | 268 result_times = re.match("OK ([0-9\.]*) ([0-9\.]*) .*", result) |
| 252 | 269 |
| 253 self.keyvals['connect_config_s'] = result_times.group(1) | 270 self.write_perf({'config_s': result_times.group(1), |
| 254 self.keyvals['connect_assoc_s'] = result_times.group(2) | 271 'assoc_s': result_times.group(2)}) |
| 255 for k in ('multiple_attempts', 'clear_error', 'fast_fail'): | 272 for k in ('already_connected', 'clear_error', 'fast_fail', |
| 273 'get_prop', 'in_progress', 'lost_dbus', 'multiple_attempts'): |
| 256 if re.search(k, result) is not None: | 274 if re.search(k, result) is not None: |
| 257 self.keyvals[k] = 'true' | 275 self.write_perf({k:'true'}) |
| 258 | 276 |
| 259 print "%s: %s" % (self.name, result) | 277 print "%s: %s" % (self.name, result) |
| 260 | 278 |
| 261 # fetch IP address of wireless device | 279 # fetch IP address of wireless device |
| 262 self.client_wifi_ip = self.__get_ipaddr(self.client, self.client_wlanif) | 280 self.client_wifi_ip = self.__get_ipaddr(self.client, self.client_wlanif) |
| 263 logging.info("%s: client WiFi-IP is %s", self.name, self.client_wifi_ip) | 281 logging.info("%s: client WiFi-IP is %s", self.name, self.client_wifi_ip) |
| 264 # TODO(sleffler) not right for non-mac80211 devices | 282 # TODO(sleffler) not right for non-mac80211 devices |
| 265 # TODO(sleffler) verify debugfs is mounted @ /sys/kernel/debug | 283 # TODO(sleffler) verify debugfs is mounted @ /sys/kernel/debug |
| 266 self.client_debugfs_path = "/sys/kernel/debug/ieee80211/%s/netdev:%s" \ | 284 self.client_debugfs_path = "/sys/kernel/debug/ieee80211/%s/netdev:%s" \ |
| 267 % ("phy0", self.client_wlanif) | 285 % ("phy0", self.client_wlanif) |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 stats['max'] = m.group(4) | 435 stats['max'] = m.group(4) |
| 418 return stats | 436 return stats |
| 419 | 437 |
| 420 | 438 |
| 421 def __print_pingstats(self, label, stats): | 439 def __print_pingstats(self, label, stats): |
| 422 logging.info("%s: %s%s/%s, %s%% loss, rtt %s/%s/%s", | 440 logging.info("%s: %s%s/%s, %s%% loss, rtt %s/%s/%s", |
| 423 self.name, label, stats['xmit'], stats['recv'], stats['loss'], | 441 self.name, label, stats['xmit'], stats['recv'], stats['loss'], |
| 424 stats['min'], stats['avg'], stats['max']) | 442 stats['min'], stats['avg'], stats['max']) |
| 425 | 443 |
| 426 | 444 |
| 427 def __ping_prefix(self, params): | |
| 428 if 'name' in params: | |
| 429 return params['name'] | |
| 430 | |
| 431 args = [] | |
| 432 for k, v in params.items(): | |
| 433 if k != 'count': | |
| 434 args.append('%s_%s' % (k, v)) | |
| 435 return '/'.join(args) | |
| 436 | |
| 437 | |
| 438 def client_ping(self, params): | 445 def client_ping(self, params): |
| 439 """ Ping the server from the client """ | 446 """ Ping the server from the client """ |
| 440 ping_ip = params.get('ping_ip', self.server_wifi_ip) | 447 ping_ip = params.get('ping_ip', self.server_wifi_ip) |
| 441 count = params.get('count', self.defpingcount) | 448 count = params.get('count', self.defpingcount) |
| 442 # set timeout for 3s / ping packet | 449 # set timeout for 3s / ping packet |
| 443 result = self.client.run("ping %s %s" % \ | 450 result = self.client.run("ping %s %s" % \ |
| 444 (self.__ping_args(params), ping_ip), timeout=3*int(count)) | 451 (self.__ping_args(params), ping_ip), timeout=3*int(count)) |
| 445 | 452 |
| 446 stats = self.__get_pingstats(result.stdout) | 453 stats = self.__get_pingstats(result.stdout) |
| 447 prefix = 'client_ping_%s_' % self.__ping_prefix(params) | 454 self.write_perf(stats) |
| 448 for k,v in stats.iteritems(): | |
| 449 self.keyvals[prefix + k] = v | |
| 450 self.__print_pingstats("client_ping ", stats) | 455 self.__print_pingstats("client_ping ", stats) |
| 451 | 456 |
| 452 | 457 |
| 453 def client_ping_bg(self, params): | 458 def client_ping_bg(self, params): |
| 454 """ Ping the server from the client """ | 459 """ Ping the server from the client """ |
| 455 ping_ip = params.get('ping_ip', self.server_wifi_ip) | 460 ping_ip = params.get('ping_ip', self.server_wifi_ip) |
| 456 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) | 461 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) |
| 457 self.ping_thread = HelperThread(self.client, cmd) | 462 self.ping_thread = HelperThread(self.client, cmd) |
| 458 self.ping_thread.start() | 463 self.ping_thread.start() |
| 459 | 464 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 471 self.__unreachable("server_ping") | 476 self.__unreachable("server_ping") |
| 472 return | 477 return |
| 473 ping_ip = params.get('ping_ip', self.client_wifi_ip) | 478 ping_ip = params.get('ping_ip', self.client_wifi_ip) |
| 474 count = params.get('count', self.defpingcount) | 479 count = params.get('count', self.defpingcount) |
| 475 # set timeout for 3s / ping packet | 480 # set timeout for 3s / ping packet |
| 476 result = self.server.run("%s %s %s" % \ | 481 result = self.server.run("%s %s %s" % \ |
| 477 (self.server_ping_cmd, self.__ping_args(params), | 482 (self.server_ping_cmd, self.__ping_args(params), |
| 478 ping_ip), timeout=3*int(count)) | 483 ping_ip), timeout=3*int(count)) |
| 479 | 484 |
| 480 stats = self.__get_pingstats(result.stdout) | 485 stats = self.__get_pingstats(result.stdout) |
| 481 prefix = 'server_ping_' + self.__ping_prefix(params) | 486 self.write_perf(stats) |
| 482 for k,v in stats.iteritems(): | |
| 483 self.keyvals['server_ping_' + k] = v | |
| 484 self.__print_pingstats("server_ping ", stats) | 487 self.__print_pingstats("server_ping ", stats) |
| 485 | 488 |
| 486 | 489 |
| 487 def server_ping_bg(self, params): | 490 def server_ping_bg(self, params): |
| 488 """ Ping the client from the server """ | 491 """ Ping the client from the server """ |
| 489 if self.server is None: | 492 if self.server is None: |
| 490 self.__unreachable("server_ping_bg") | 493 self.__unreachable("server_ping_bg") |
| 491 return | 494 return |
| 492 ping_ip = params.get('ping_ip', self.client_wifi_ip) | 495 ping_ip = params.get('ping_ip', self.client_wifi_ip) |
| 493 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) | 496 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 # Run netperf command and receive command results | 619 # Run netperf command and receive command results |
| 617 t0 = time.time() | 620 t0 = time.time() |
| 618 results = client['host'].run("%s %s" % (client['cmd'], netperf_args)) | 621 results = client['host'].run("%s %s" % (client['cmd'], netperf_args)) |
| 619 actual_time = time.time() - t0 | 622 actual_time = time.time() - t0 |
| 620 logging.info('actual_time: %f', actual_time) | 623 logging.info('actual_time: %f', actual_time) |
| 621 | 624 |
| 622 # Close up whatever firewall rules we created for netperf | 625 # Close up whatever firewall rules we created for netperf |
| 623 for rule in np_rules: | 626 for rule in np_rules: |
| 624 self.__firewall_close(rule) | 627 self.__firewall_close(rule) |
| 625 | 628 |
| 626 # Results are prefixed with the iteration or a caller-defined name | 629 self.write_perf({'test':test, 'mode':mode, 'actual_time':actual_time}) |
| 627 prefix = 'Netperf_%s_' % params.get('name', str(self.netperf_iter)) | |
| 628 self.netperf_iter += 1 | |
| 629 | |
| 630 self.keyvals[prefix + 'test'] = test | |
| 631 self.keyvals[prefix + 'mode'] = mode | |
| 632 self.keyvals[prefix + 'actual_time'] = actual_time | |
| 633 | 630 |
| 634 logging.info(results) | 631 logging.info(results) |
| 635 | 632 |
| 636 lines = results.stdout.splitlines() | 633 lines = results.stdout.splitlines() |
| 637 | 634 |
| 638 # Each test type has a different form of output | 635 # Each test type has a different form of output |
| 639 if test in ['TCP_STREAM', 'TCP_MAERTS', 'TCP_SENDFILE']: | 636 if test in ['TCP_STREAM', 'TCP_MAERTS', 'TCP_SENDFILE']: |
| 640 """Parses the following (works for both TCP_STREAM, TCP_MAERTS and | 637 """Parses the following (works for both TCP_STREAM, TCP_MAERTS and |
| 641 TCP_SENDFILE) and returns a singleton containing throughput. | 638 TCP_SENDFILE) and returns a singleton containing throughput. |
| 642 | 639 |
| 643 TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to \ | 640 TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to \ |
| 644 foo.bar.com (10.10.10.3) port 0 AF_INET | 641 foo.bar.com (10.10.10.3) port 0 AF_INET |
| 645 Recv Send Send | 642 Recv Send Send |
| 646 Socket Socket Message Elapsed | 643 Socket Socket Message Elapsed |
| 647 Size Size Size Time Throughput | 644 Size Size Size Time Throughput |
| 648 bytes bytes bytes secs. 10^6bits/sec | 645 bytes bytes bytes secs. 10^6bits/sec |
| 649 | 646 |
| 650 87380 16384 16384 2.00 941.28 | 647 87380 16384 16384 2.00 941.28 |
| 651 """ | 648 """ |
| 652 self.keyvals[prefix + 'Throughput'] = float(lines[6].split()[4]) | 649 self.write_perf({'Throughput':float(lines[6].split()[4])}) |
| 653 elif test == 'UDP_STREAM': | 650 elif test == 'UDP_STREAM': |
| 654 """Parses the following and returns a touple containing throughput | 651 """Parses the following and returns a touple containing throughput |
| 655 and the number of errors. | 652 and the number of errors. |
| 656 | 653 |
| 657 UDP UNIDIRECTIONAL SEND TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ | 654 UDP UNIDIRECTIONAL SEND TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ |
| 658 to foo.bar.com (10.10.10.3) port 0 AF_INET | 655 to foo.bar.com (10.10.10.3) port 0 AF_INET |
| 659 Socket Message Elapsed Messages | 656 Socket Message Elapsed Messages |
| 660 Size Size Time Okay Errors Throughput | 657 Size Size Time Okay Errors Throughput |
| 661 bytes bytes secs # # 10^6bits/sec | 658 bytes bytes secs # # 10^6bits/sec |
| 662 | 659 |
| 663 129024 65507 2.00 3673 0 961.87 | 660 129024 65507 2.00 3673 0 961.87 |
| 664 131072 2.00 3673 961.87 | 661 131072 2.00 3673 961.87 |
| 665 """ | 662 """ |
| 666 udp_tokens = lines[5].split() | 663 udp_tokens = lines[5].split() |
| 667 self.keyvals[prefix + 'Throughput'] = float(udp_tokens[5]) | 664 self.write_perf({'Throughput':float(udp_tokens[5]), |
| 668 self.keyvals[prefix + 'Errors'] = float(udp_tokens[4]) | 665 'Errors':float(udp_tokens[4])}) |
| 669 elif test in ['TCP_RR', 'TCP_CRR', 'UDP_RR']: | 666 elif test in ['TCP_RR', 'TCP_CRR', 'UDP_RR']: |
| 670 """Parses the following which works for both rr (TCP and UDP) | 667 """Parses the following which works for both rr (TCP and UDP) |
| 671 and crr tests and returns a singleton containing transfer rate. | 668 and crr tests and returns a singleton containing transfer rate. |
| 672 | 669 |
| 673 TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ | 670 TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ |
| 674 to foo.bar.com (10.10.10.3) port 0 AF_INET | 671 to foo.bar.com (10.10.10.3) port 0 AF_INET |
| 675 Local /Remote | 672 Local /Remote |
| 676 Socket Size Request Resp. Elapsed Trans. | 673 Socket Size Request Resp. Elapsed Trans. |
| 677 Send Recv Size Size Time Rate | 674 Send Recv Size Size Time Rate |
| 678 bytes Bytes bytes bytes secs. per sec | 675 bytes Bytes bytes bytes secs. per sec |
| 679 | 676 |
| 680 16384 87380 1 1 2.00 14118.53 | 677 16384 87380 1 1 2.00 14118.53 |
| 681 16384 87380 | 678 16384 87380 |
| 682 """ | 679 """ |
| 683 self.kevals[prefix + 'Trasnfer_Rate'] = float(lines[6].split()[5]) | 680 self.write_perf({'Trasnfer_Rate':float(lines[6].split()[5])}) |
| 684 else: | 681 else: |
| 685 raise error.TestError('Unhandled test') | 682 raise error.TestError('Unhandled test') |
| 686 | 683 |
| 687 return True | 684 return True |
| 688 | 685 |
| 689 | 686 |
| 690 def client_netperf(self, params): | 687 def client_netperf(self, params): |
| 691 """ Run netperf on the client against the server """ | 688 """ Run netperf on the client against the server """ |
| 692 self.__run_netperf('client', params) | 689 self.__run_netperf('client', params) |
| 693 | 690 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 if server_addr is None and hasattr(client_attributes, 'server_addr'): | 802 if server_addr is None and hasattr(client_attributes, 'server_addr'): |
| 806 server_addr = client_attributes.server_addr | 803 server_addr = client_attributes.server_addr |
| 807 if server_addr is not None: | 804 if server_addr is not None: |
| 808 server['addr'] = server_addr; | 805 server['addr'] = server_addr; |
| 809 # TODO(sleffler) check for wifi_addr when no control address | 806 # TODO(sleffler) check for wifi_addr when no control address |
| 810 | 807 |
| 811 # tag jobs w/ the router's address on the control network | 808 # tag jobs w/ the router's address on the control network |
| 812 config['tagname'] = router['addr'] | 809 config['tagname'] = router['addr'] |
| 813 | 810 |
| 814 return config | 811 return config |
| OLD | NEW |