$search
00001 #! /usr/bin/env python 00002 00003 import sys 00004 import time 00005 import subprocess 00006 import unittest 00007 00008 import roslib; roslib.load_manifest('network_control_tests') 00009 import rospy 00010 import rostest 00011 import math 00012 00013 from network_monitor_udp.linktest import UdpmonsourceHandle 00014 from network_monitor_udp.linktest import LinkTest 00015 from network_monitor_udp.msg import LinktestGoal 00016 from network_traffic_control.projected_link_metrics import get_projected_link_metrics 00017 import dynamic_reconfigure.client 00018 00019 class DynreconfTest(unittest.TestCase): 00020 def __init__(self, *args): 00021 super(DynreconfTest, self).__init__(*args) 00022 rospy.init_node('network_traffic_control_test') 00023 self.srcnode = UdpmonsourceHandle('performance_test') 00024 self.dynclient = dynamic_reconfigure.client.Client("tc_lo") 00025 self.no_traffic_control_params = { 00026 "bandwidth_egress" : 0.0, "bandwidth_ingress" : 0.0, 00027 "latency_egress" : 0.0, "latency_ingress" : 0.0, 00028 "loss_egress" : 0.0, "loss_ingress" : 0.0, 00029 "packet_size" : 1500 } 00030 self.reset_tc_rules_via_dynreconf() 00031 00032 def reset_tc_rules_via_dynreconf(self): 00033 config = self.dynclient.update_configuration(self.no_traffic_control_params) 00034 if config['status'] != "OK": 00035 raise(ValueError(config['errmsg'])) 00036 00037 def setUp(self): 00038 self.srcnode.cancel_all_tests() 00039 00040 def tearDown(self): 00041 self.reset_tc_rules_via_dynreconf() 00042 00043 def test_latency(self): 00044 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0, 00045 sink_ip = "127.0.0.1", sink_port = 12345, 00046 bw_type = LinktestGoal.BW_CONSTANT) 00047 test.start() 00048 time.sleep(3.5) 00049 self.assertTrue(test.done, "Test should have finished already") 00050 self.assertTrue(test.overall_latency < 0.01, 00051 "Expected latency to be < 1ms, instead it was %.2fms"% 00052 (test.overall_latency * 1e3)) 00053 00054 config = self.dynclient.update_configuration({ "latency_egress": 0.03 }) 00055 self.assertTrue(config['status'] == "OK", 00056 "Operation FAILed: " + config['errmsg']) 00057 self.assertAlmostEqual(config['latency_egress'], 0.03, 3, 00058 "Expected latency_egress dynreconf parameter to be ~30ms, instead it was %.2fms"% 00059 (config['latency_egress'] * 1e3)) 00060 00061 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0, 00062 sink_ip = "127.0.0.1", sink_port = 12345, 00063 bw_type = LinktestGoal.BW_CONSTANT) 00064 test.start() 00065 time.sleep(3.5) 00066 self.assertTrue(test.done, "Test should have finished already") 00067 self.assertTrue(test.overall_latency > 0.02 and test.overall_latency < 0.04, 00068 "Expected latency to be ~30ms, instead it was %.2fms"% 00069 (test.overall_latency * 1e3)) 00070 self.assertTrue(test.overall_bandwidth > 0.7e6, 00071 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"% 00072 (test.overall_bandwidth/1e6)) 00073 self.assertTrue(test.overall_loss < 5.0, 00074 "Expected packet loss to be 0%%, instead it was %.2f%%"% 00075 (test.overall_loss)) 00076 00077 config = self.dynclient.update_configuration({ "latency_egress": 0.01, "latency_ingress": 0.05 }) 00078 self.assertTrue(config['status'] == "OK", 00079 "Operation FAILed: " + config['errmsg']) 00080 self.assertAlmostEqual(config['latency_egress'], 0.01, 3, 00081 "Expected latency_egress dynreconf parameter to be ~10ms, instead it was %.2fms"% 00082 (config['latency_egress'] * 1e3)) 00083 self.assertAlmostEqual(config['latency_ingress'], 0.05, 3, 00084 "Expected latency_ingress dynreconf parameter to be ~50ms, instead it was %.2fms"% 00085 (config['latency_ingress'] * 1e3)) 00086 00087 test = self.srcnode.create_test(bw = 1.0*10**6, pktsize = 1500, duration = 3.0, 00088 sink_ip = "127.0.0.1", sink_port = 12345, 00089 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.1) 00090 test.start() 00091 time.sleep(3.5) 00092 self.assertTrue(test.done, "Test should have finished already") 00093 self.assertTrue(test.overall_latency > 0.045 and test.overall_latency < 0.075, 00094 "Expected latency to be ~ 60ms, instead it was %.2fms"% 00095 (test.overall_latency * 1e3)) 00096 self.assertTrue(test.overall_bandwidth > 0.7e6, 00097 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"% 00098 (test.overall_bandwidth/1e6)) 00099 self.assertTrue(test.overall_loss < 5.0, 00100 "Expected packet loss to be 0%%, instead it was %.2f%%"% 00101 (test.overall_loss)) 00102 00103 def test_bandwidth(self): 00104 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0, 00105 sink_ip = "127.0.0.1", sink_port = 12345, 00106 bw_type = LinktestGoal.BW_CONSTANT) 00107 test.start() 00108 time.sleep(3.5) 00109 self.assertTrue(test.done, "Test should have finished already") 00110 self.assertTrue(test.overall_latency < 0.01, 00111 "Expected latency to be < 1ms, instead it was %.2fms"% 00112 (test.overall_latency * 1e3)) 00113 self.assertTrue(test.overall_bandwidth > 2.7e6, 00114 "Expected overall bandwidth to be ~3Mbit/s, instead it was %.2fMbit/s"% 00115 (test.overall_bandwidth/1e6)) 00116 00117 config = self.dynclient.update_configuration({ "bandwidth_egress": 2e6, "bandwidth_ingress": 2e6 }) 00118 self.assertTrue(config['status'] == "OK", 00119 "Operation FAILed: " + config['errmsg']) 00120 self.assertAlmostEqual(config['bandwidth_egress']/1e6, 2.0, 3, 00121 "Expected bandwidth_egress dynreconf parameter to be ~2Mbit/s, instead it was %.2fMbit/s"% 00122 (config['bandwidth_egress']/1e6)) 00123 self.assertAlmostEqual(config['bandwidth_ingress']/1e6, 2.0, 3, 00124 "Expected bandwidth_ingress dynreconf parameter to be ~2Mbit/s, instead it was %.2fMbit/s"% 00125 (config['bandwidth_ingress']/1e6)) 00126 00127 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0, 00128 sink_ip = "127.0.0.1", sink_port = 12345, 00129 bw_type = LinktestGoal.BW_CONSTANT, latencybins = [ 0.01, 0.1, 0.3], 00130 max_return_time = 0.25) 00131 test.start() 00132 time.sleep(3.5) 00133 self.assertTrue(test.done, "Test should have finished already") 00134 self.assertTrue(test.overall_bandwidth > 1.5e6 and test.overall_bandwidth < 2.5e6, 00135 "Expected measured bandwidth to be ~2Mbit/s, instead it was %.2fMbit/s"% 00136 (test.overall_bandwidth/1e6)) 00137 00138 config = self.dynclient.update_configuration({ "bandwidth_ingress": 1e6 }) 00139 00140 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 3.0, 00141 sink_ip = "127.0.0.1", sink_port = 12345, 00142 bw_type = LinktestGoal.BW_CONSTANT) 00143 test.start() 00144 time.sleep(3.5) 00145 self.assertTrue(test.done, "Test should have finished already") 00146 self.assertTrue(test.overall_bandwidth > 0.7e6 and test.overall_bandwidth < 1.3e6, 00147 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"% 00148 (test.overall_bandwidth/1e6)) 00149 00150 def test_bandwidth_latency(self): 00151 config = self.dynclient.update_configuration({ "bandwidth_egress": 1e6, "latency_ingress": 0.03 }) 00152 test = self.srcnode.create_test(bw = 0.7*10**6, pktsize = 1500, duration = 5.0, 00153 sink_ip = "127.0.0.1", sink_port = 12345, 00154 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00155 test.start() 00156 time.sleep(5.5) 00157 self.assertTrue(test.done, "Test should have finished already") 00158 self.assertTrue(test.overall_bandwidth > 0.5e6 and test.overall_bandwidth < 0.9e6, 00159 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"% 00160 (test.overall_bandwidth/1e6)) 00161 self.assertTrue(test.latency.avg() > 0.025 and test.latency.avg() < 0.045, 00162 "Expected latency to be ~30ms (since capacity was not overrun), instead it was %.2fms"% 00163 (test.latency.avg()*1e3)) 00164 test = self.srcnode.create_test(bw = 3.0*10**6, pktsize = 1500, duration = 5.0, 00165 sink_ip = "127.0.0.1", sink_port = 12345, 00166 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00167 test.start() 00168 time.sleep(5.5) 00169 self.assertTrue(test.done, "Test should have finished already") 00170 self.assertTrue(test.overall_bandwidth > 0.8e6 and test.overall_bandwidth < 1.2e6, 00171 "Expected overall bandwidth to be ~1Mbit/s, instead it was %.2fMbit/s"% 00172 (test.overall_bandwidth/1e6)) 00173 expected_latency = 1500.0/(1e6/8) + 0.03 00174 self.assertTrue(test.latency.avg() > expected_latency - 0.005 and test.latency.avg() < expected_latency + 0.005, 00175 "Expected latency to be ~%.2fms (since capacity was not overrun), instead it was %.2fms"% 00176 (expected_latency * 1e3, test.latency.avg()*1e3)) 00177 00178 def test_ingress_egress_loss(self): 00179 config = self.dynclient.update_configuration({ "loss_egress": 20.0, "loss_ingress": 30.0 }) 00180 test = self.srcnode.create_test(bw = 5*10**6, pktsize = 1500, duration = 5.0, 00181 sink_ip = "127.0.0.1", sink_port = 12345, 00182 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00183 test.start() 00184 time.sleep(5.5) 00185 self.assertTrue(test.done, "Test should have finished already") 00186 self.assertTrue(test.loss.avg() > 44.0 - 10.0 and test.loss.avg() < 44.0 + 10.0, 00187 "Expected aggregated loss (ingress+egress) to be ~44%%, instead it was %.2f%%"% 00188 (test.loss.avg())) 00189 00190 def test_packet_size(self): 00191 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0, 00192 sink_ip = "127.0.0.1", sink_port = 12345, 00193 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00194 config = self.dynclient.update_configuration({ "packet_size": 5000, "bandwidth_egress": 1e6 }) 00195 test.start() 00196 time.sleep(3.5) 00197 self.assertTrue(test.done, "Test should have finished already") 00198 self.assertTrue(test.latency.avg() > 0.035 and test.latency.avg() < 0.045, 00199 "Expected latency to be ~40ms, instead it was %.2fms"% 00200 (test.latency.avg()*1e3)) 00201 00202 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0, 00203 sink_ip = "127.0.0.1", sink_port = 12345, 00204 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00205 config = self.dynclient.update_configuration({ "packet_size": 500 }) 00206 00207 test.start() 00208 time.sleep(3.5) 00209 self.assertTrue(test.done, "Test should have finished already") 00210 self.assertTrue(test.latency.avg() > 0.002 and test.latency.avg() < 0.006, 00211 "Expected latency to be ~4ms, instead it was %.2fms"% 00212 (test.latency.avg()*1e3)) 00213 00214 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0, 00215 sink_ip = "127.0.0.1", sink_port = 12345, 00216 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00217 config = self.dynclient.update_configuration({ "bandwidth_ingress": 0.5e6 }) 00218 test.start() 00219 time.sleep(3.5) 00220 self.assertTrue(test.done, "Test should have finished already") 00221 self.assertTrue(test.latency.avg() > 0.008 and test.latency.avg() < 0.015, 00222 "Expected latency to be ~12ms, instead it was %.2fms"% 00223 (test.latency.avg()*1e3)) 00224 00225 test = self.srcnode.create_test(bw = 3*10**6, pktsize = 500, duration = 3.0, 00226 sink_ip = "127.0.0.1", sink_port = 12345, 00227 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00228 config = self.dynclient.update_configuration({ "packet_size": 300 }) 00229 test.start() 00230 time.sleep(3.5) 00231 self.assertTrue(test.done, "Test should have finished already") 00232 self.assertTrue(test.loss.avg() > 95.0, 00233 "Expected loss to be 100% (tc limit smaller than packet size)") 00234 00235 def bandwidth_latency_loss_test(self, direction, bw_tx, bw_limit, latency, loss, 00236 expected_bw = None, expected_loss = None, expected_latency = None): 00237 self.reset_tc_rules_via_dynreconf() 00238 config = self.dynclient.update_configuration({ "bandwidth_" + direction: bw_limit, 00239 "latency_" + direction: latency, 00240 "loss_" + direction: loss }) 00241 00242 self.assertTrue(config['status'] == "OK", 00243 "Operation FAILed: " + config['errmsg']) 00244 00245 test = self.srcnode.create_test(bw = bw_tx, pktsize = 1500, duration = 5.0, 00246 sink_ip = "127.0.0.1", sink_port = 12345, 00247 bw_type = LinktestGoal.BW_CONSTANT, max_return_time = 0.01) 00248 test.start() 00249 time.sleep(5.5) 00250 self.assertTrue(test.done, "Test should have finished already") 00251 00252 (expected_bw, expected_latency, expected_loss) = get_projected_link_metrics(bw_limit, latency, loss, 1500.0, bw_tx) 00253 00254 print "bw_limit: ", bw_limit, "loss: ", loss, "latency: ", latency, "bw_tx: ", bw_tx 00255 print "meas_bw: ", test.bandwidth.avg(), " meas_latency: ", test.latency.avg()*1e3, " meas_loss: ", test.loss.avg() 00256 print "exp_bw", expected_bw, " exp_latency: ", expected_latency * 1e3, " exp_loss: ", expected_loss 00257 self.assertTrue(test.bandwidth.avg() > expected_bw * 0.75 and test.bandwidth.avg() < expected_bw * 1.25, 00258 "Expected measured bandwidth to be ~%.2fMbit/s, instead it was %.2fMbit/s"% 00259 (expected_bw/1e6, test.bandwidth.avg()/1e6)) 00260 self.assertTrue(test.latency.avg() > expected_latency - 0.015 and test.latency.avg() < expected_latency + 0.015, 00261 "Expected latency to be ~%.2fms, instead it was %.2fms"% 00262 (expected_latency * 1e3, test.latency.avg() * 1e3)) 00263 self.assertTrue((test.loss.avg() < 4.0 and expected_loss < 2.0) or 00264 (test.loss.avg() > expected_loss - 10.0 and test.latency.avg() < expected_loss + 10.0), 00265 "Expected loss to be ~%.2f%%, instead it was %.2f%%"% 00266 (expected_loss, test.loss.avg())) 00267 00268 00269 def test_bandwidth_latency_loss(self): 00270 # just bw_limit specified, bw_tx < bw_limit 00271 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6, 00272 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0) 00273 # just bw_limit specified, bw_tx > bw_limit 00274 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6, 00275 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0) 00276 # bw_limit + latency, bw_tx < bw_limit 00277 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6, 00278 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0) 00279 # bw_limit + latency, bw_tx > bw_limit 00280 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6, 00281 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0) 00282 # bw_limit + latency + loss, bw_tx < bw_limit, loss < bw_loss 00283 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6, 00284 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0) 00285 # bw_limit + latency + loss, bw_tx < bw_limit, loss > bw_loss 00286 self.bandwidth_latency_loss_test("egress", bw_tx = 0.5*10**6, 00287 bw_limit=1.0*10**6, latency = 0.03, loss = 50.0) 00288 # bw_limit + latency + loss, bw_tx > bw_limit, loss < bw-loss 00289 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6, 00290 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0) 00291 # bw_limit + latency + loss, bw_tx > bw_limit, loss < bw-loss 00292 self.bandwidth_latency_loss_test("egress", bw_tx = 1.5*10**6, 00293 bw_limit=1.0*10**6, latency = 0.03, loss = 50.0) 00294 # ingress tests 00295 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6, 00296 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0) 00297 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6, 00298 bw_limit=1.0*10**6, latency = 0.0, loss = 0.0) 00299 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6, 00300 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0) 00301 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6, 00302 bw_limit=1.0*10**6, latency = 0.01, loss = 0.0) 00303 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6, 00304 bw_limit=1.0*10**6, latency = 0.02, loss = 0.0) 00305 self.bandwidth_latency_loss_test("ingress", bw_tx = 1.5*10**6, 00306 bw_limit=1.0*10**6, latency = 0.03, loss = 10.0) 00307 self.bandwidth_latency_loss_test("ingress", bw_tx = 0.5*10**6, 00308 bw_limit=1.0*10**6, latency = 0.04, loss = 20.0) 00309 if __name__ == '__main__': 00310 try: 00311 rostest.run('network_control_tests', 'dynreconf_test', DynreconfTest) 00312 except KeyboardInterrupt, e: 00313 pass