def __run_traffic(api, config, duthost, all_flow_names, pfcwd_start_delay_sec, exp_dur_sec): """ Start traffic at time 0 and enable PFC watchdog at pfcwd_start_delay_sec Args: api (obj): SNAPPI session config (obj): experiment config (testbed config + flow config) duthost (Ansible host instance): device under test all_flow_names (list): list of names of all the flows pfcwd_start_delay_sec (int): PFC watchdog start delay in second exp_dur_sec (int): experiment duration in second Returns: per-flow statistics (list) """ api.set_config(config) logger.info('Wait for Arp to Resolve ...') wait_for_arp(api, max_attempts=10, poll_interval_sec=2) logger.info('Starting transmit on all flows ...') ts = api.transmit_state() ts.state = ts.START api.set_transmit_state(ts) time.sleep(pfcwd_start_delay_sec) start_pfcwd(duthost) time.sleep(exp_dur_sec - pfcwd_start_delay_sec) attempts = 0 max_attempts = 20 while attempts < max_attempts: request = api.metrics_request() request.flow.flow_names = all_flow_names rows = api.get_metrics(request).flow_metrics """ If all the flows have stopped """ transmit_states = [row.transmit for row in rows] if len(rows) == len(all_flow_names) and\ list(set(transmit_states)) == ['stopped']: time.sleep(SNAPPI_POLL_DELAY_SEC) break else: time.sleep(1) attempts += 1 pytest_assert(attempts < max_attempts, "Flows do not stop in {} seconds".format(max_attempts)) """ Dump per-flow statistics """ request = api.metrics_request() request.flow.flow_names = all_flow_names rows = api.get_metrics(request).flow_metrics logger.info('Stop transmit on all flows ...') ts = api.transmit_state() ts.state = ts.STOP api.set_transmit_state(ts) return rows
def start_pfcwd_after_test(duthosts, rand_one_dut_hostname): """ Ensure that PFC watchdog is enabled with default setting after tests Args: duthosts (pytest fixture) : list of DUTs rand_one_dut_hostname (pytest fixture): DUT hostname Yields: N/A """ yield duthost = duthosts[rand_one_dut_hostname] start_pfcwd(duthost)
def run_pfcwd_multi_node_test(api, testbed_config, port_config_list, conn_data, fanout_data, duthost, dut_port, pause_prio_list, test_prio_list, bg_prio_list, prio_dscp_map, trigger_pfcwd, pattern): """ Run PFC watchdog test in a multi-node (>=3) topoology Args: api (obj): SNAPPI session testbed_config (obj): testbed L1/L2/L3 configuration port_config_list (list): list of port configuration conn_data (dict): the dictionary returned by conn_graph_fact. fanout_data (dict): the dictionary returned by fanout_graph_fact. duthost (Ansible host instance): device under test dut_port (str): DUT port to test pause_prio_list (list): priorities to pause for PFC pause storm test_prio_list (list): priorities of test flows bg_prio_list (list): priorities of background flows prio_dscp_map (dict): Priority vs. DSCP map (key = priority). trigger_pfcwd (bool): if PFC watchdog is expected to be triggered pattern (str): traffic pattern Returns: N/A """ patterns = ['all to all', 'many to one'] if pattern not in patterns: raise ValueError( 'invalid traffic pattern passed in "{}", must be {}'.format( pattern, ' or '.join(['"{}"'.format(src) for src in patterns]))) pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') num_ports = len(port_config_list) pytest_require(num_ports >= 3, "This test requires at least 3 ports") start_pfcwd(duthost) enable_packet_aging(duthost) """ Get the ID of the port to test """ port_id = get_dut_port_id(dut_hostname=duthost.hostname, dut_port=dut_port, conn_data=conn_data, fanout_data=fanout_data) pytest_assert(port_id is not None, 'Fail to get ID for port {}'.format(dut_port)) poll_interval_sec = get_pfcwd_poll_interval(duthost) / 1000.0 detect_time_sec = get_pfcwd_detect_time(host_ans=duthost, intf=dut_port) / 1000.0 if trigger_pfcwd: pfc_storm_dur_sec = poll_interval_sec + detect_time_sec else: pfc_storm_dur_sec = 0.5 * detect_time_sec exp_dur_sec = ceil(pfc_storm_dur_sec + 1) """ Generate traffic config """ test_flow_rate_percent = int(TEST_FLOW_AGGR_RATE_PERCENT / \ (num_ports - 1) / \ len(test_prio_list)) bg_flow_rate_percent = int(BG_FLOW_AGGR_RATE_PERCENT / \ (num_ports - 1) / \ len(bg_prio_list)) __gen_traffic(testbed_config=testbed_config, port_config_list=port_config_list, port_id=port_id, pause_flow_name=PAUSE_FLOW_NAME, pause_prio_list=pause_prio_list, test_flow_name=TEST_FLOW_NAME, test_flow_prio_list=test_prio_list, test_flow_rate_percent=test_flow_rate_percent, bg_flow_name=BG_FLOW_NAME, bg_flow_prio_list=bg_prio_list, bg_flow_rate_percent=bg_flow_rate_percent, data_flow_dur_sec=exp_dur_sec, pfc_storm_dur_sec=pfc_storm_dur_sec, data_pkt_size=DATA_PKT_SIZE, prio_dscp_map=prio_dscp_map, traffic_pattern=pattern) flows = testbed_config.flows all_flow_names = [flow.name for flow in flows] flow_stats = __run_traffic(api=api, config=testbed_config, all_flow_names=all_flow_names, exp_dur_sec=exp_dur_sec) speed_str = testbed_config.layer1[0].speed speed_gbps = int(speed_str.split('_')[1]) __verify_results(rows=flow_stats, speed_gbps=speed_gbps, pause_flow_name=PAUSE_FLOW_NAME, test_flow_name=TEST_FLOW_NAME, bg_flow_name=BG_FLOW_NAME, test_flow_rate_percent=test_flow_rate_percent, bg_flow_rate_percent=bg_flow_rate_percent, data_flow_dur_sec=exp_dur_sec, data_pkt_size=DATA_PKT_SIZE, trigger_pfcwd=trigger_pfcwd, pause_port_id=port_id, tolerance=TOLERANCE_THRESHOLD)
def run_pfcwd_burst_storm_test(api, testbed_config, port_config_list, conn_data, fanout_data, duthost, dut_port, prio_list, prio_dscp_map): """ Test PFC watchdog under bursty PFC storms Args: api (obj): SNAPPI session testbed_config (obj): testbed L1/L2/L3 configuration port_config_list (list): list of port configuration conn_data (dict): the dictionary returned by conn_graph_fact. fanout_data (dict): the dictionary returned by fanout_graph_fact. duthost (Ansible host instance): device under test dut_port (str): DUT port to test prio_list (list): priorities to generate PFC storms and data traffic prio_dscp_map (dict): Priority vs. DSCP map (key = priority). Returns: N/A """ pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') start_pfcwd(duthost) enable_packet_aging(duthost) """ Get the ID of the port to test """ port_id = get_dut_port_id(dut_hostname=duthost.hostname, dut_port=dut_port, conn_data=conn_data, fanout_data=fanout_data) pytest_assert(port_id is not None, 'Fail to get ID for port {}'.format(dut_port)) poll_interval_sec = get_pfcwd_poll_interval(duthost) / 1000.0 detect_time_sec = get_pfcwd_detect_time(host_ans=duthost, intf=dut_port) / 1000.0 restore_time_sec = get_pfcwd_restore_time(host_ans=duthost, intf=dut_port) / 1000.0 burst_cycle_sec = poll_interval_sec + detect_time_sec + restore_time_sec + 0.1 data_flow_dur_sec = ceil(burst_cycle_sec * BURST_EVENTS) pause_flow_dur_sec = poll_interval_sec * 0.5 pause_flow_gap_sec = burst_cycle_sec - pause_flow_dur_sec __gen_traffic(testbed_config=testbed_config, port_config_list=port_config_list, port_id=port_id, pause_flow_prefix=PAUSE_FLOW_PREFIX, pause_flow_dur_sec=pause_flow_dur_sec, pause_flow_count=BURST_EVENTS, pause_flow_gap_sec=pause_flow_gap_sec, data_flow_prefix=DATA_FLOW_PREFIX, data_flow_dur_sec=data_flow_dur_sec, data_pkt_size=DATA_PKT_SIZE, prio_list=prio_list, prio_dscp_map=prio_dscp_map) flows = testbed_config.flows all_flow_names = [flow.name for flow in flows] exp_dur_sec = BURST_EVENTS * poll_interval_sec + 1 flow_stats = __run_traffic(api=api, config=testbed_config, all_flow_names=all_flow_names, exp_dur_sec=exp_dur_sec) __verify_results(rows=flow_stats, data_flow_prefix=DATA_FLOW_PREFIX, pause_flow_prefix=PAUSE_FLOW_PREFIX)
def run_pfcwd_basic_test(api, testbed_config, port_config_list, conn_data, fanout_data, duthost, dut_port, prio_list, prio_dscp_map, trigger_pfcwd): """ Run a basic PFC watchdog test Args: api (obj): SNAPPI session testbed_config (obj): testbed L1/L2/L3 configuration port_config_list (list): list of port configuration conn_data (dict): the dictionary returned by conn_graph_fact. fanout_data (dict): the dictionary returned by fanout_graph_fact. duthost (Ansible host instance): device under test dut_port (str): DUT port to test prio_list (list): priorities of data flows and pause storm prio_dscp_map (dict): Priority vs. DSCP map (key = priority). trigger_pfcwd (bool): if PFC watchdog is expected to be triggered Returns: N/A """ pytest_assert(testbed_config is not None, 'Fail to get L2/3 testbed config') start_pfcwd(duthost) enable_packet_aging(duthost) """ Get the ID of the port to test """ port_id = get_dut_port_id(dut_hostname=duthost.hostname, dut_port=dut_port, conn_data=conn_data, fanout_data=fanout_data) pytest_assert(port_id is not None, 'Fail to get ID for port {}'.format(dut_port)) poll_interval_sec = get_pfcwd_poll_interval(duthost) / 1000.0 detect_time_sec = get_pfcwd_detect_time(host_ans=duthost, intf=dut_port) / 1000.0 restore_time_sec = get_pfcwd_restore_time(host_ans=duthost, intf=dut_port) / 1000.0 if trigger_pfcwd: """ Large enough to trigger PFC watchdog """ pfc_storm_dur_sec = ceil(detect_time_sec + poll_interval_sec + 0.1) flow1_delay_sec = restore_time_sec / 2 flow1_dur_sec = pfc_storm_dur_sec """ Start data traffic 2 after PFC is restored """ flow2_delay_sec = pfc_storm_dur_sec + restore_time_sec + poll_interval_sec flow2_dur_sec = 1 flow1_max_loss_rate = 1 flow1_min_loss_rate = 1- DEVIATION else: pfc_storm_dur_sec = detect_time_sec * 0.5 flow1_delay_sec = pfc_storm_dur_sec * 0.1 flow1_dur_sec = ceil(pfc_storm_dur_sec) """ Start data traffic 2 after the completion of data traffic 1 """ flow2_delay_sec = flow1_delay_sec + flow1_dur_sec + 0.1 flow2_dur_sec = 1 flow1_max_loss_rate = 0 flow1_min_loss_rate = 0 exp_dur_sec = flow2_delay_sec + flow2_dur_sec + 1 """ Generate traffic config """ __gen_traffic(testbed_config=testbed_config, port_config_list=port_config_list, port_id=port_id, pause_flow_name=PAUSE_FLOW_NAME, pause_flow_dur_sec=pfc_storm_dur_sec, data_flow_name_list=[DATA_FLOW1_NAME, DATA_FLOW2_NAME], data_flow_delay_sec_list=[flow1_delay_sec, flow2_delay_sec], data_flow_dur_sec_list=[flow1_dur_sec, flow2_dur_sec], data_pkt_size=DATA_PKT_SIZE, prio_list=prio_list, prio_dscp_map=prio_dscp_map) flows = testbed_config.flows all_flow_names = [flow.name for flow in flows] flow_stats = __run_traffic(api=api, config=testbed_config, all_flow_names=all_flow_names, exp_dur_sec=exp_dur_sec) __verify_results(rows=flow_stats, data_flow_name_list=[DATA_FLOW1_NAME, DATA_FLOW2_NAME], data_flow_min_loss_rate_list=[flow1_min_loss_rate, 0], data_flow_max_loss_rate_list=[flow1_max_loss_rate, 0])