def verify_traffic_between_dut_and_ap(self,
                                          iperf_server_on_ap,
                                          iperf_client_on_dut,
                                          ip_version=IPV4):
        """Runs IPerf traffic from the iperf client (dut) and the iperf
        server (and vice versa) and verifies traffic was able to pass
        successfully.

        Args:
            iperf_server_on_ap: IPerfServer object, linked to AP
            iperf_client_on_dut: IPerfClient object, linked to DUT
            ip_version: string, the ip version (ipv4 or ipv6)

        Raises:
            ValueError, if invalid ip_version is passed.
            ConnectionError, if traffic is not passed successfully in both
                directions.
        """
        dut_ip_addresses = self.dut.get_interface_ip_addresses(
            iperf_client_on_dut.test_interface)

        iperf_server_ip_address = self.get_iperf_server_address(
            iperf_server_on_ap, ip_version)

        self.log.info(
            'Attempting to pass traffic from DUT to IPerf server (%s).' %
            iperf_server_ip_address)
        tx_file = iperf_client_on_dut.start(iperf_server_ip_address,
                                            '-i 1 -t 3 -J', 'reboot_tx')
        tx_results = iperf_server.IPerfResult(tx_file)
        if not tx_results.avg_receive_rate or tx_results.avg_receive_rate == 0:
            raise ConnectionError(
                'Failed to pass IPerf traffic from DUT to server (%s). TX '
                'Average Receive Rate: %s' %
                (iperf_server_ip_address, tx_results.avg_receive_rate))
        else:
            self.log.info(
                'Success: Traffic passed from DUT to IPerf server (%s).' %
                iperf_server_ip_address)
        self.log.info(
            'Attempting to pass traffic from IPerf server (%s) to DUT.' %
            iperf_server_ip_address)
        rx_file = iperf_client_on_dut.start(iperf_server_ip_address,
                                            '-i 1 -t 3 -R -J', 'reboot_rx')
        rx_results = iperf_server.IPerfResult(rx_file)
        if not rx_results.avg_receive_rate or rx_results.avg_receive_rate == 0:
            raise ConnectionError(
                'Failed to pass IPerf traffic from server (%s) to DUT. RX '
                'Average Receive Rate: %s' %
                (iperf_server_ip_address, rx_results.avg_receive_rate))
        else:
            self.log.info(
                'Success: Traffic passed from IPerf server (%s) to DUT.' %
                iperf_server_ip_address)
    def run_iperf_traffic(self, ip_client, server_address, server_port=5201):
        """Runs traffic between client and ap an verifies throughput.

        Args:
            ip_client: iperf client to use
            server_address: ipv4 address of the iperf server to use
            server_port: port of the iperf server

        Raises:
            TestFailure, if no traffic passes in either direction
        """
        ip_client_identifier = self.get_iperf_client_identifier(ip_client)
        self.log.info(
            'Running traffic from iperf client %s to iperf server %s.' %
            (ip_client_identifier, server_address))
        client_to_ap_path = ip_client.start(
            server_address, '-i 1 -t 10 -J -p %s' % server_port,
            'client_to_soft_ap')

        self.log.info(
            'Running traffic from iperf server %s to iperf client %s.' %
            (server_address, ip_client_identifier))
        ap_to_client_path = ip_client.start(
            server_address, '-i 1 -t 10 -R -J -p %s' % server_port,
            'soft_ap_to_client')
        self.log.info('Getting iperf results')

        client_to_ap_result = iperf_server.IPerfResult(client_to_ap_path)
        ap_to_client_result = iperf_server.IPerfResult(ap_to_client_path)

        if (not client_to_ap_result.avg_receive_rate):
            asserts.fail(
                'Failed to pass traffic from iperf client %s to iperf server %s.'
                % (ip_client_identifier, server_address))

        self.log.info(
            'Passed traffic from iperf client %s to iperf server %s with avg '
            'rate of %s MB/s.' % (ip_client_identifier, server_address,
                                  client_to_ap_result.avg_receive_rate))

        if (not ap_to_client_result.avg_receive_rate):
            asserts.fail(
                'Failed to pass traffic from iperf server %s to iperf client %s.'
                % (server_address, ip_client_identifier))

        self.log.info(
            'Passed traffic from iperf server %s to iperf client %s with avg '
            'rate of %s MB/s.' % (server_address, ip_client_identifier,
                                  ap_to_client_result.avg_receive_rate))
예제 #3
0
    def process_iperf_results(self):
        """Get the iperf results and process.

        Returns:
             throughput: the average throughput during tests.
        """
        # Get IPERF results and add this to the plot title
        RESULTS_DESTINATION = os.path.join(
            self.iperf_server.log_path,
            'iperf_client_output_{}.log'.format(self.current_test_name))
        PULL_FILE = '{} {}'.format(TEMP_FILE, RESULTS_DESTINATION)
        self.dut.adb.pull(PULL_FILE)
        # Calculate the average throughput
        if self.use_client_output:
            iperf_file = RESULTS_DESTINATION
        else:
            iperf_file = self.iperf_server.log_files[-1]
        try:
            iperf_result = ipf.IPerfResult(iperf_file)
            throughput = (math.fsum(iperf_result.instantaneous_rates[:-1]) /
                          len(iperf_result.instantaneous_rates[:-1])) * 8
            self.log.info('The average throughput is {}'.format(throughput))
        except ValueError:
            self.log.warning('Cannot get iperf result. Setting to 0')
            throughput = 0
        return throughput
예제 #4
0
    def get_iperf_result(self):
        """Pulls the iperf json output from device.

        Returns:
            An IPerfResult object based on the iperf run output.
        """
        dest = os.path.join(self.iperf_server.log_path, "iperf.txt")
        self.dut.adb.pull(pmc_iperf_json_file, " ", dest)
        result = ip_server.IPerfResult(dest)
        self.dut.adb.shell("rm %s" % pmc_iperf_json_file)
        return result
예제 #5
0
    def run_throughput_stability_test(self, testcase_params):
        """Main function to test throughput stability.

        The function sets up the AP in the correct channel and mode
        configuration and runs an iperf test to measure throughput.

        Args:
            testcase_params: dict containing test specific parameters
        Returns:
            test_result: dict containing test result and meta data
        """
        # Run test and log result
        # Start iperf session
        self.log.info('Starting iperf test.')
        llstats_obj = wputils.LinkLayerStats(self.dut)
        llstats_obj.update_stats()
        self.iperf_server.start(tag=str(testcase_params['atten_level']))
        current_rssi = wputils.get_connected_rssi_nb(
            dut=self.dut,
            num_measurements=self.testclass_params['iperf_duration'] - 1,
            polling_frequency=1,
            first_measurement_delay=1,
            disconnect_warning=1,
            ignore_samples=1)
        client_output_path = self.iperf_client.start(
            testcase_params['iperf_server_address'],
            testcase_params['iperf_args'], str(testcase_params['atten_level']),
            self.testclass_params['iperf_duration'] + TEST_TIMEOUT)
        current_rssi = current_rssi.result()
        server_output_path = self.iperf_server.stop()
        # Set attenuator to 0 dB
        for attenuator in self.attenuators:
            attenuator.set_atten(0)
        # Parse and log result
        if testcase_params['use_client_output']:
            iperf_file = client_output_path
        else:
            iperf_file = server_output_path
        try:
            iperf_result = ipf.IPerfResult(iperf_file)
        except:
            asserts.fail('Cannot get iperf result.')
        llstats_obj.update_stats()
        curr_llstats = llstats_obj.llstats_incremental.copy()
        test_result = collections.OrderedDict()
        test_result['testcase_params'] = testcase_params.copy()
        test_result['ap_settings'] = self.access_point.ap_settings.copy()
        test_result['attenuation'] = testcase_params['atten_level']
        test_result['iperf_result'] = iperf_result
        test_result['rssi_result'] = current_rssi
        test_result['llstats'] = curr_llstats
        self.testclass_results.append(test_result)
        return test_result
예제 #6
0
    def run_iperf_server(self, network):
        """Run iperf RX throughput after connection.

        Args:
            params: Dictionary with network info.

        Returns:
            rvr_result: Dict containing rvr_results
        """
        rvr_result = []
        self.iperf_server.start(tag="RX_client_{}_angle{}_{}dB".format(
            self.ssid, self.angle[self.ag], self.DB))
        wait_time = 5
        SSID = network[WifiEnums.SSID_KEY]
        self.log.info("Starting iperf traffic RX through {}".format(SSID))
        time.sleep(wait_time)
        port_arg = "-p {} -J -R {}".format(
            self.iperf_server.port, self.rvr_test_params["iperf_port_arg"])
        success, data = self.dut.run_iperf_client(
            self.rvr_test_params["iperf_server_address"],
            port_arg,
            timeout=self.rvr_test_params["iperf_duration"] + self.TEST_TIMEOUT)
        # Parse and log result
        client_output_path = os.path.join(
            self.iperf_server.log_path,
            "IperfDUT,{},RX_server_{}_angle{}_{}dB".format(
                self.iperf_server.port, self.ssid, self.angle[self.ag],
                self.DB))
        with open(client_output_path, 'w') as out_file:
            out_file.write("\n".join(data))
        self.iperf_server.stop()

        iperf_file = client_output_path
        try:
            iperf_result = ipf.IPerfResult(iperf_file)
            curr_throughput = (math.fsum(iperf_result.instantaneous_rates[
                self.rvr_test_params["iperf_ignored_interval"]:-1]) / len(
                    iperf_result.instantaneous_rates[
                        self.rvr_test_params["iperf_ignored_interval"]:-1])
                               ) * 8 * (1.024**2)
        except:
            self.log.warning(
                "ValueError: Cannot get iperf result. Setting to 0")
            curr_throughput = 0
        rvr_result.append(curr_throughput)
        self.log.info("RX Throughput at {0:.2f} dB is {1:.2f} Mbps".format(
            self.DB, curr_throughput))

        self.log.debug(pprint.pformat(data))
        asserts.assert_true(success, "Error occurred in iPerf traffic.")
        return rvr_result
예제 #7
0
    def process_iperf_results(self, dut, log, iperf_servers, test_name):
        """Gets the iperf results from the phone and computes the average rate

        Returns:
             throughput: the average throughput (Mbit/s).
        """
        # Stopping the server (as safety to get the result file)
        iperf_servers[self.server_idx].stop()
        time.sleep(1)

        # Get IPERF results and add this to the plot title
        RESULTS_DESTINATION = os.path.join(
            iperf_servers[self.server_idx].log_path,
            'iperf_client_output_{}.log'.format(test_name))

        PULL_FILE = '{} {}'.format(self.results_filename_phone,
                                   RESULTS_DESTINATION)
        dut.adb.pull(PULL_FILE)

        # Calculate the average throughput
        if self.use_client_output:
            iperf_file = RESULTS_DESTINATION
        else:
            iperf_file = iperf_servers[self.server_idx].log_files[-1]
        try:
            iperf_result = ipf.IPerfResult(iperf_file)

            # Get instantaneous rates after measuring starts
            samples = iperf_result.instantaneous_rates[self.start_meas_time:-1]

            # Convert values to Mbit/s
            samples = [rate * 8 * (1.024**2) for rate in samples]

            # compute mean, var and max_dev
            mean = statistics.mean(samples)
            var = statistics.variance(samples)
            max_dev = 0
            for rate in samples:
                if abs(rate - mean) > max_dev:
                    max_dev = abs(rate - mean)

            log.info('The average throughput is {}. Variance is {} and max '
                     'deviation is {}.'.format(
                         round(mean, 2), round(var, 2), round(max_dev, 2)))

        except:
            log.warning('Cannot get iperf result.')
            mean = 0

        return mean
예제 #8
0
    def run_iperf_server(self, network):
        """Run iperf RX throughput after connection.

        Args:
            params: Dictionary with network info.

        Returns:
            iot_result: dict containing iot_results
        """
        if "iperf_server_address" in self.user_params:

            # Add iot_result
            iot_result = []
            self.iperf_server.start(
                tag="RX_client_{}".format(self.current_test_name))
            wait_time = 5
            SSID = network[WifiEnums.SSID_KEY]
            self.log.info("Starting iperf traffic RX through {}".format(SSID))
            time.sleep(wait_time)
            port_arg = "-p {} -J -R {}".format(self.iperf_server.port,
                                               self.iperf_port_arg)
            success, data = self.dut.run_iperf_client(
                self.iperf_server_address, port_arg)
            client_output_path = os.path.join(
                self.iperf_server.log_path,
                "IperfDUT,{},RX_server_{}".format(self.iperf_server.port,
                                                  self.current_test_name))
            with open(client_output_path, 'w') as out_file:
                out_file.write("\n".join(data))
            self.iperf_server.stop()

            iperf_file = client_output_path
            try:
                iperf_result = ipf.IPerfResult(iperf_file)
                curr_throughput = math.fsum(iperf_result.instantaneous_rates)
            except:
                self.log.warning(
                    "ValueError: Cannot get iperf result. Setting to 0")
                curr_throughput = 0
            iot_result.append(curr_throughput)
            self.log.info("Throughput is {0:.2f} Mbps".format(curr_throughput))

            self.log.debug(pprint.pformat(data))
            asserts.assert_true(success, "Error occurred in iPerf traffic.")
            return iot_result
    def run_iperf_test(self, testcase_params):
        """Main function for iperf roaming tests.

        Args:
            testcase_params: dict including all test params encoded in test
            name
        Returns:
            result: dict containing all test results and meta data
        """
        self.log.info('Starting iperf test.')
        self.iperf_server.start(extra_args='-i {}'.format(IPERF_INTERVAL))
        self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
        if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
            iperf_server_address = self.dut_ip
        else:
            iperf_server_address = wputils.get_server_address(
                self.remote_server, self.dut_ip, '255.255.255.0')
        iperf_args = '-i {} -t {} -J'.format(
            IPERF_INTERVAL, testcase_params['atten_waveforms']['length'])
        if not isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
            iperf_args = iperf_args + ' -R'
        iperf_future = wputils.start_iperf_client_nb(
            self.iperf_client, iperf_server_address, iperf_args, 0,
            testcase_params['atten_waveforms']['length'] + MED_SLEEP)
        rssi_future = wputils.get_connected_rssi_nb(
            self.dut,
            int(testcase_params['atten_waveforms']['length'] /
                testcase_params['rssi_polling_frequency']),
            testcase_params['rssi_polling_frequency'])
        self.run_attenuation_waveform(testcase_params)
        client_output_path = iperf_future.result()
        server_output_path = self.iperf_server.stop()
        if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
            iperf_file = server_output_path
        else:
            iperf_file = client_output_path
        iperf_result = ipf.IPerfResult(iperf_file)
        instantaneous_rates = [
            rate * 8 * (1.024**2) for rate in iperf_result.instantaneous_rates
        ]
        return {
            'throughput': instantaneous_rates,
            'rssi_result': rssi_future.result(),
            'ap_settings': self.access_point.ap_settings,
        }
예제 #10
0
    def measure_throughput_and_power(self, direction):

        # Start iperf locally
        self.log.info("Starting iperf server.")
        self.iperf_server.start()

        self.log.info("Starting iperf client on the phone.")
        iperf_args = '-i 1 -t %d' % self.iperf_duration
        if direction == DIRECTION_DOWNLINK:
            iperf_args = iperf_args + ' -R'
        iperf_args = iperf_args + ' > /dev/null'

        wputils.run_iperf_client_nonblocking(self.ad, self.ip, iperf_args)

        # Collect power data
        self.log.info("Starting sampling with monsoon.")
        file_path, current = wputils.monsoon_data_collect_save(
            self.ad, self.mon_info, self.current_test_name, bug_report=0)

        # Collect iperf data

        # Give some time for iperf to finish
        time.sleep(self.iperf_offset)

        self.iperf_server.stop()

        throughput = 0
        try:
            iperf_result = ipf.IPerfResult(self.iperf_server.log_files[-1])

            if direction == DIRECTION_DOWNLINK:
                if iperf_result.avg_send_rate is not None:
                    throughput = iperf_result.avg_send_rate * 8
            elif direction == DIRECTION_UPLINK:
                if iperf_result.avg_receive_rate is not None:
                    throughput = iperf_result.avg_receive_rate * 8
        except:
            pass

        self.log.info("Average receive rate: %sMbps", throughput)

        return [throughput, current]
예제 #11
0
def get_iperf_results(iperf_server_obj):
    """Get the iperf results and process.

    Args:
        iperf_server_obj: the IperfServer object
    Returns:
         throughput: the average throughput during tests.
    """
    # Get IPERF results and add this to the plot title
    iperf_file = iperf_server_obj.log_files[-1]
    try:
        iperf_result = ipf.IPerfResult(iperf_file)
        # Compute the throughput in Mbit/s
        if iperf_result.error == IPERF_CLIENT_ERROR:
            rates = []
            for item in iperf_result.result['intervals']:
                rates.append(item['sum']['bits_per_second'] / 8 / 1024 / 1024)
            throughput = ((math.fsum(rates) / len(rates))) * 8 * (1.024**2)
        else:
            throughput = (math.fsum(iperf_result.instantaneous_rates) / len(
                iperf_result.instantaneous_rates)) * 8 * (1.024**2)
    except (ValueError, TypeError):
        throughput = 0
    return throughput
    def run_rvr_test(self, testcase_params):
        """Test function to run RvR.

        The function runs an RvR test in the current device/AP configuration.
        Function is called from another wrapper function that sets up the
        testbed for the RvR test

        Args:
            testcase_params: dict containing test-specific parameters
        Returns:
            rvr_result: dict containing rvr_results and meta data
        """
        self.log.info('Start running RvR')
        # Refresh link layer stats before test
        llstats_obj = wputils.LinkLayerStats(self.dut)
        zero_counter = 0
        throughput = []
        llstats = []
        rssi = []
        for atten in testcase_params['atten_range']:
            for dev in self.android_devices:
                if not wputils.health_check(dev, 5, 50):
                    asserts.skip('DUT health check failed. Skipping test.')
            # Set Attenuation
            for attenuator in self.attenuators:
                attenuator.set_atten(atten, strict=False)
            # Refresh link layer stats
            llstats_obj.update_stats()
            # Setup sniffer
            if self.testbed_params['sniffer_enable']:
                self.sniffer.start_capture(
                    network=testcase_params['test_network'],
                    chan=int(testcase_params['channel']),
                    bw=int(testcase_params['mode'][3:]),
                    duration=self.testclass_params['iperf_duration'] / 5)
            # Start iperf session
            self.iperf_server.start(tag=str(atten))
            rssi_future = wputils.get_connected_rssi_nb(
                self.dut, self.testclass_params['iperf_duration'] - 1, 1, 1)
            client_output_path = self.iperf_client.start(
                testcase_params['iperf_server_address'],
                testcase_params['iperf_args'], str(atten),
                self.testclass_params['iperf_duration'] + self.TEST_TIMEOUT)
            server_output_path = self.iperf_server.stop()
            rssi_result = rssi_future.result()
            current_rssi = {
                'signal_poll_rssi': rssi_result['signal_poll_rssi']['mean'],
                'chain_0_rssi': rssi_result['chain_0_rssi']['mean'],
                'chain_1_rssi': rssi_result['chain_1_rssi']['mean']
            }
            rssi.append(current_rssi)
            # Stop sniffer
            if self.testbed_params['sniffer_enable']:
                self.sniffer.stop_capture(tag=str(atten))
            # Parse and log result
            if testcase_params['use_client_output']:
                iperf_file = client_output_path
            else:
                iperf_file = server_output_path
            try:
                iperf_result = ipf.IPerfResult(iperf_file)
                curr_throughput = numpy.mean(iperf_result.instantaneous_rates[
                    self.testclass_params['iperf_ignored_interval']:-1]
                                             ) * 8 * (1.024**2)
            except:
                self.log.warning(
                    'ValueError: Cannot get iperf result. Setting to 0')
                curr_throughput = 0
            throughput.append(curr_throughput)
            llstats_obj.update_stats()
            curr_llstats = llstats_obj.llstats_incremental.copy()
            llstats.append(curr_llstats)
            self.log.info(
                ('Throughput at {0:.2f} dB is {1:.2f} Mbps. '
                 'RSSI = {2:.2f} [{3:.2f}, {4:.2f}].').format(
                     atten, curr_throughput, current_rssi['signal_poll_rssi'],
                     current_rssi['chain_0_rssi'],
                     current_rssi['chain_1_rssi']))
            if curr_throughput == 0 and (
                    current_rssi['signal_poll_rssi'] < -80
                    or numpy.isnan(current_rssi['signal_poll_rssi'])):
                zero_counter = zero_counter + 1
            else:
                zero_counter = 0
            if zero_counter == self.MAX_CONSECUTIVE_ZEROS:
                self.log.info(
                    'Throughput stable at 0 Mbps. Stopping test now.')
                throughput.extend(
                    [0] *
                    (len(testcase_params['atten_range']) - len(throughput)))
                break
        for attenuator in self.attenuators:
            attenuator.set_atten(0, strict=False)
        # Compile test result and meta data
        rvr_result = collections.OrderedDict()
        rvr_result['test_name'] = self.current_test_name
        rvr_result['testcase_params'] = testcase_params.copy()
        rvr_result['ap_settings'] = self.access_point.ap_settings.copy()
        rvr_result['fixed_attenuation'] = self.testbed_params[
            'fixed_attenuation'][str(testcase_params['channel'])]
        rvr_result['attenuation'] = list(testcase_params['atten_range'])
        rvr_result['total_attenuation'] = [
            att + rvr_result['fixed_attenuation']
            for att in rvr_result['attenuation']
        ]
        rvr_result['rssi'] = rssi
        rvr_result['throughput_receive'] = throughput
        rvr_result['llstats'] = llstats
        return rvr_result
    def throughput_stability_test_func(self, channel, mode):
        """Main function to test throughput stability.

        The function sets up the AP in the correct channel and mode
        configuration and runs an iperf test to measure throughput.

        Args:
            channel: Specifies AP's channel
            mode: Specifies AP's bandwidth/mode (11g, VHT20, VHT40, VHT80)
        Returns:
            test_result: dict containing test result and meta data
        """
        #Initialize RvR test parameters
        test_result = {}
        # Configure AP
        band = self.access_point.band_lookup_by_channel(channel)
        self.access_point.set_channel(band, channel)
        self.access_point.set_bandwidth(band, mode)
        self.log.info("Access Point Configuration: {}".format(
            self.access_point.ap_settings))
        # Set attenuator to test level
        self.log.info("Setting attenuation to {} dB".format(self.atten_level))
        [
            self.attenuators[i].set_atten(self.atten_level)
            for i in range(self.num_atten)
        ]
        # Connect DUT to Network
        self.main_network[band]["channel"] = channel
        wutils.reset_wifi(self.dut)
        wutils.wifi_connect(self.dut, self.main_network[band], num_of_tries=5)
        time.sleep(5)
        # Run test and log result
        # Start iperf session
        self.log.info("Starting iperf test.")
        self.iperf_server.start(tag=str(self.atten_level))
        try:
            client_output = ""
            client_status, client_output = self.dut.run_iperf_client(
                self.testbed_params["iperf_server_address"],
                self.iperf_args,
                timeout=self.test_params["iperf_duration"] + TEST_TIMEOUT)
        except:
            self.log.warning("TimeoutError: Iperf measurement timed out.")
        client_output_path = os.path.join(
            self.iperf_server.log_path,
            "iperf_client_output_{}".format(self.current_test_name))
        with open(client_output_path, 'w') as out_file:
            out_file.write("\n".join(client_output))
        self.iperf_server.stop()
        # Set attenuator to 0 dB
        [self.attenuators[i].set_atten(0) for i in range(self.num_atten)]
        # Parse and log result
        if self.use_client_output:
            iperf_file = client_output_path
        else:
            iperf_file = self.iperf_server.log_files[-1]
        try:
            iperf_result = ipf.IPerfResult(iperf_file)
        except:
            self.log.warning("ValueError: Cannot get iperf result.")
            iperf_result = None
        test_result["ap_settings"] = self.access_point.ap_settings.copy()
        test_result["attenuation"] = self.atten_level
        test_result["iperf_result"] = iperf_result
        return test_result
예제 #14
0
    def _run_traffic(self,
                     uuid,
                     client,
                     server_ip,
                     server_port,
                     active_streams,
                     stream_results,
                     access_category=None,
                     bandwidth=None,
                     stream_time=DEFAULT_STREAM_TIME,
                     start_time=None):
        """Runs an iperf3 stream.

        1. Adds stream UUID to active_streams
        2. Runs stream
        3. Saves results to stream_results
        4. Removes stream UUID from active_streams

        Args:
            uuid: UUID object, identifier for stream
            client: IPerfClient object on device
            server_ip: string, ip address of IPerfServer for stream
            server_port: int, port of the IPerfServer for stream
            active_streams: multiprocessing.Manager.dict, which holds stream
                UUIDs of active streams on the device
            stream_results: multiprocessing.Manager.dict, which maps stream
                UUIDs of streams to IPerfResult objects
            access_category: string, WMM access category to use with iperf
                (AC_BK, AC_BE, AC_VI, AC_VO). Unset if None.
            bandwidth: int, bandwidth in mbps to use with iperf. Implies UDP.
                Unlimited if None.
            stream_time: int, time in seconds, to run iperf stream
            start_time: float, time, seconds since epoch, at which to start the
                stream (for better synchronicity). If None, start immediately.
        """
        active_streams[uuid] = True
        # SSH sessions must be started within the process that is going to
        # use it.
        if type(client) == iperf_client.IPerfClientOverSsh:
            with utils.SuppressLogOutput():
                client.start_ssh()

        ac_flag = ''
        bandwidth_flag = ''
        time_flag = '-t %s' % stream_time

        if access_category:
            ac_flag = ' -S %s' % DEFAULT_AC_TO_TOS_TAG_MAP[access_category]

        if bandwidth:
            bandwidth_flag = ' -u -b %sM' % bandwidth

        iperf_flags = '-p %s -i 1 %s%s%s -J' % (server_port, time_flag,
                                                ac_flag, bandwidth_flag)
        if not start_time:
            start_time = time.time()
        time_str = datetime.fromtimestamp(start_time).strftime('%H:%M:%S.%f')
        self.log.info(
            'At %s, starting %s second stream to %s:%s with (AC: %s, Bandwidth: %s)'
            % (time_str, stream_time, server_ip, server_port, access_category,
               bandwidth if bandwidth else 'Unlimited'))

        # If present, wait for stream start time
        if start_time:
            current_time = time.time()
            while current_time < start_time:
                current_time = time.time()
        path = client.start(server_ip, iperf_flags, '%s' % uuid)
        stream_results[uuid] = iperf_server.IPerfResult(
            path, reporting_speed_units='mbps')

        if type(client) == iperf_client.IPerfClientOverSsh:
            client.close_ssh()
        active_streams.pop(uuid)