def cleanup(self): """Cleanup sockets and network interfaces""" # Signal to end connection msg = TrafficRequest(TrafficRequestType.EXIT) msg.send(self.sc_out) # Close out network ifaces # For now multiple UEs with mixed ip addresses is not supported # so check the version of the first ip address # TODO: Add support for handling multiple UE with mixed ipv4 and ipv6 # addresses intf = TrafficTest._net_iface_ipv4 for instance in self.instances: if instance.ip.version == 6: intf = TrafficTest._net_iface_ipv6 break net_iface = TrafficTest._iproute.link_lookup( ifname=intf, ) if net_iface: net_iface_index = net_iface[0] # For some reason the first call to flush this address flushes all # the addresses brought up during testing. But subsequent flushes # do nothing if the address doesn't exist for instance in self.instances: TrafficTest._iproute.flush_addr( index=net_iface_index, address=instance.ip.exploded, ) # Do socket cleanup self.sc_in.close() self.sc_out.close() self.sc.shutdown(socket.SHUT_RDWR) # Ensures safe socket closure self.sc.close()
def cleanup(self): """Cleanup sockets and network interfaces""" # Signal to end connection msg = TrafficRequest(TrafficRequestType.EXIT) msg.send(self.sc_out) # Close out network ifaces net_iface = TrafficTest._iproute.link_lookup( ifname=TrafficTest._net_iface, ) if net_iface: net_iface_index = net_iface[0] # For some reason the first call to flush this address flushes all # the addresses brought up during testing. But subsequent flushes # do nothing if the address doesn't exist for instance in self.instances: TrafficTest._iproute.flush_addr( index=net_iface_index, address=instance.ip.exploded, ) # Do socket cleanup self.sc_in.close() self.sc_out.close() self.sc.shutdown(socket.SHUT_RDWR) # Ensures safe socket closure self.sc.close()
def recv_req(self, level=logging.DEBUG): ''' Receive an object from the client over the socket connection Args: level (int): the logging level to use; defaults to logging.DEBUG Return message, payload tuple extracted from the message ''' msg = TrafficMessage.recv(self.rfile) if not msg: # Empty message -- treat as EXIT request self._login.warning('Received empty message, treating as EXIT') msg = TrafficRequest(TrafficRequestType.EXIT) self._login.log(level, msg) return msg.message, msg.id, msg.payload
def _run(self): ''' Run the traffic test Sets up traffic test with remote traffic server and local ifaces, then runs the runner hook into the trfgen binary and collects the results to cache Will block until the test ends ''' # Create a snapshot of the test's states, in case they get changed or # wiped in a later operation. Basically, render tests immune to later # operations after the test has started. with self._test_lock: instances = copy.deepcopy(self._instances) test_ids = copy.deepcopy(self._test_ids) try: # Set up sockets and associated streams sc = socket.create_connection(self._remote_server) sc_in = sc.makefile('rb') sc_out = sc.makefile('wb') # Set up network ifaces and get UL port assignments for DL aliases = () for instance in instances: aliases += (TrafficTest._iface_up(instance.ip),) if not instance.is_uplink: # Assign a local port for the downlink UE server instance.port = TrafficTest._get_port() # Create and send TEST message msg = TrafficRequest( TrafficRequestType.TEST, payload=instances) msg.send(sc_out) # Receive SERVER message and update test instances msg = TrafficMessage.recv(sc_in) assert msg.message is TrafficResponseType.SERVER r_id = msg.id # Remote server test identifier server_instances = msg.payload # (TrafficServerInstance, ...) # Locally keep references to arguments passed into trfgen args = [None] * len(instances) # Post-SERVER, pre-START logic for i in range(len(instances)): instance = instances[i] server_instance = server_instances[i] # Add ip network route net_iface_index = TrafficTest._iproute.link_lookup( ifname=TrafficTest._net_iface)[0] server_instance_network = \ TrafficTest._network_from_ip(server_instance.ip, 8) TrafficTest._iproute.route( 'replace', dst=server_instance_network.exploded, iif=net_iface_index, oif=net_iface_index, scope='link') # Add arp table entry os.system('/usr/sbin/arp -s %s %s' % ( server_instance.ip.exploded, server_instance.mac)) if instance.is_uplink: # Port should be the port of the remote for uplink instance.port = server_instance.port else: args[i] = self._run_test( test_ids[i], server_instance.ip, instance.ip, instance.port) # Send START for the given r_id msg = TrafficRequest( TrafficRequestType.START, identifier=r_id) msg.send(sc_out) # Wait for STARTED response msg = TrafficMessage.recv(sc_in) assert msg.message is TrafficResponseType.STARTED assert msg.id == r_id # Post-STARTED, pre-RESULTS logic for i in range(len(instances)): instance = instances[i] if instance.is_uplink: args[i] = self._run_test( test_ids[i], server_instances[i].ip, instance.ip, server_instances[i].port) # Wait for RESULTS message msg = TrafficMessage.recv(sc_in) assert msg.message is TrafficResponseType.RESULTS assert msg.id == r_id results = msg.payload # Signal to end connection msg = TrafficRequest(TrafficRequestType.EXIT) msg.send(sc_out) # Close out network ifaces net_iface_index = TrafficTest._iproute.link_lookup( ifname=TrafficTest._net_iface)[0] # For some reason the first call to flush this address flushes all # the addresses brought up during testing. But subsequent flushes # do nothing if the address doesn't exist for i in range(len(instances)): TrafficTest._iproute.flush_addr(index=net_iface_index, address=instances[i].ip.exploded) # Do socket cleanup sc_in.close() sc_out.close() sc.shutdown(socket.SHUT_RDWR) # Ensures safe socket closure sc.close() # Cache results after cleanup with self._test_lock: self._results = results finally: # Signal that we're done self._done.set()
def _run(self): """Run the traffic test Sets up traffic test with remote traffic server and local ifaces, then runs the runner hook into the trfgen binary and collects the results to cache Will block until the test ends """ # Create a snapshot of the test's states, in case they get changed or # wiped in a later operation. Basically, render tests immune to later # operations after the test has started. with self._test_lock: self.instances = copy.deepcopy(self._instances) test_ids = copy.deepcopy(self._test_ids) try: # Set up sockets and associated streams self.sc = socket.create_connection(self._remote_server) self.sc_in = self.sc.makefile("rb") self.sc_out = self.sc.makefile("wb") self.sc.settimeout(IPERF_DATA_TIMEOUT_SEC) # Flush all the addresses left by previous failed tests net_iface = 0 # For now multiple UEs with mixed ip addresses is not supported # so check the version of the first ip address # TODO: Add support for handling multiple UE with mixed ipv4 and ipv6 # addresses for instance in self.instances: if instance.ip.version == 4: net_iface = TrafficTest._net_iface_ipv4 else: net_iface = TrafficTest._net_iface_ipv6 break net_iface_index = TrafficTest._iproute.link_lookup( ifname=net_iface, )[0] for instance in self.instances: TrafficTest._iproute.flush_addr( index=net_iface_index, address=instance.ip.exploded, ) # Set up network ifaces and get UL port assignments for DL for instance in self.instances: if instance.ip.version == 4: (TrafficTest._iface_up_ipv4(instance.ip),) else: (TrafficTest._iface_up_ipv6(instance.ip),) if not instance.is_uplink: # Assign a local port for the downlink UE server instance.port = TrafficTest._get_port() # Create and send TEST message msg = TrafficRequest( TrafficRequestType.TEST, payload=self.instances, ) msg.send(self.sc_out) # Receive SERVER message and update test instances msg = TrafficMessage.recv(self.sc_in) assert msg.message is TrafficResponseType.SERVER r_id = msg.id # Remote server test identifier server_instances = msg.payload # (TrafficServerInstance, ...) # Locally keep references to arguments passed into trfgen num_instances = len(self.instances) args = [None for _ in range(num_instances)] # Post-SERVER, pre-START logic for i in range(num_instances): instance = self.instances[i] server_instance = server_instances[i] # Add ip network route net_iface_index = TrafficTest._iproute.link_lookup( ifname=net_iface, )[0] server_instance_network = TrafficTest._network_from_ip( server_instance.ip, 8, ) TrafficTest._iproute.route( "replace", dst=server_instance_network.exploded, iif=net_iface_index, oif=net_iface_index, scope="link", ) # Add arp table entry if server_instance.ip.version == 4: os.system( "/usr/sbin/arp -s %s %s" % ( server_instance.ip.exploded, server_instance.mac, ), ) else: os.system( 'ip -6 neigh add %s lladdr %s dev eth3' % ( server_instance.ip.exploded, server_instance.mac, ), ) if instance.is_uplink: # Port should be the port of the remote for uplink instance.port = server_instance.port else: args[i] = self._run_test( test_ids[i], server_instance.ip, instance.ip, instance.port, ) # Send START for the given r_id msg = TrafficRequest( TrafficRequestType.START, identifier=r_id, ) msg.send(self.sc_out) # Wait for STARTED response msg = TrafficMessage.recv(self.sc_in) assert msg.message is TrafficResponseType.STARTED assert msg.id == r_id # Post-STARTED, pre-RESULTS logic for i in range(num_instances): instance = self.instances[i] if instance.is_uplink: args[i] = self._run_test( test_ids[i], server_instances[i].ip, instance.ip, server_instances[i].port, ) # Wait for RESULTS message msg = TrafficMessage.recv(self.sc_in) assert msg.message is TrafficResponseType.RESULTS assert msg.id == r_id results = msg.payload # Call cleanup to close network interfaces and open sockets self.cleanup() # Cache results after cleanup with self._test_lock: self._results = results except ConnectionRefusedError as e: print("Running iperf data failed. Error: " + str(e)) self.is_trf_server_connection_refused = True except socket.timeout: print("Running iperf data failed with timeout") TrafficUtil.need_to_close_iperf3_server = True self.cleanup() except Exception as e: print("Running iperf data failed. Error: " + str(e)) TrafficUtil.need_to_close_iperf3_server = True self.cleanup() finally: # Signal that we're done self._done.set()