From 0758aa1b91d7c7cac679d651dc3f607caaf9b7cf Mon Sep 17 00:00:00 2001 From: bingwang Date: Sun, 13 Nov 2022 17:14:28 -0800 Subject: [PATCH] Add testcases to verify separated DSCP_TO_TC_MAP on T1 --- tests/common/fixtures/duthost_utils.py | 98 +++++++++++++++++++ tests/qos/qos_sai_base.py | 43 ++++++++- tests/qos/test_qos_sai.py | 124 ++++++++++++++++++++++++- tests/saitests/sai_qos_tests.py | 74 ++++++++------- 4 files changed, 298 insertions(+), 41 deletions(-) diff --git a/tests/common/fixtures/duthost_utils.py b/tests/common/fixtures/duthost_utils.py index 61969bb0aa0..1bdeab24451 100644 --- a/tests/common/fixtures/duthost_utils.py +++ b/tests/common/fixtures/duthost_utils.py @@ -4,6 +4,7 @@ import collections import ipaddress import time +import json from tests.common.helpers.assertions import pytest_assert from tests.common.utilities import wait_until from jinja2 import Template @@ -412,3 +413,100 @@ def utils_create_test_vlans(duthost, cfg_facts, vlan_ports_list, vlan_intfs_dict )) logger.info("Commands: {}".format(cmds)) duthost.shell_cmds(cmds=cmds) + + +@pytest.fixture(scope='module') +def dut_qos_maps(rand_selected_dut): + """ + A module level fixture to get QoS map from DUT host. + Return a dict + { + "dscp_to_tc_map": { + "0":"1", + ... + }, + "tc_to_queue_map": { + "0":"0" + }, + ... + } + or an empty dict if failed to parse the output + """ + maps = {} + try: + # port_qos_map + maps['port_qos_map'] = json.loads(rand_selected_dut.shell("sonic-cfggen -d --var-json 'PORT_QOS_MAP'")['stdout']) + # dscp_to_tc_map + maps['dscp_to_tc_map'] = json.loads(rand_selected_dut.shell("sonic-cfggen -d --var-json 'DSCP_TO_TC_MAP'")['stdout']) + # tc_to_queue_map + maps['tc_to_queue_map'] = json.loads(rand_selected_dut.shell("sonic-cfggen -d --var-json 'TC_TO_QUEUE_MAP'")['stdout']) + # tc_to_priority_group_map + maps['tc_to_priority_group_map'] = json.loads(rand_selected_dut.shell("sonic-cfggen -d --var-json 'TC_TO_PRIORITY_GROUP_MAP'")['stdout']) + # tc_to_dscp_map + maps['tc_to_dscp_map'] = json.loads(rand_selected_dut.shell("sonic-cfggen -d --var-json 'TC_TO_DSCP_MAP'")['stdout']) + except: + pass + return maps + + +def separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps): + """ + A helper function to check if separated DSCP_TO_TC_MAP is applied to + downlink/unlink ports. + """ + dscp_to_tc_map_names = set() + for port_name, qos_map in dut_qos_maps['port_qos_map'].iteritems(): + if port_name == "global": + continue + dscp_to_tc_map_names.add(qos_map.get("dscp_to_tc_map", "")) + if len(dscp_to_tc_map_names) > 1: + return True + return False + + +def load_dscp_to_pg_map(duthost, port, dut_qos_maps): + """ + Helper function to calculate DSCP to PG map for a port. + The map is derived from DSCP_TO_TC_MAP + TC_TO_PG_MAP + return a dict like {0:0, 1:1...} + """ + try: + port_qos_map = dut_qos_maps['port_qos_map'] + dscp_to_tc_map_name = port_qos_map[port]['dscp_to_tc_map'].split('|')[-1].strip(']') + tc_to_pg_map_name = port_qos_map[port]['tc_to_pg_map'].split('|')[-1].strip(']') + # Load dscp_to_tc_map + dscp_to_tc_map = dut_qos_maps['dscp_to_tc_map'][dscp_to_tc_map_name] + # Load tc_to_pg_map + tc_to_pg_map = dut_qos_maps['tc_to_priority_group_map'][tc_to_pg_map_name] + # Calculate dscp to pg map + dscp_to_pg_map = {} + for dscp, tc in dscp_to_tc_map.items(): + dscp_to_pg_map[dscp] = tc_to_pg_map[tc] + return dscp_to_pg_map + except: + logger.error("Failed to retrieve dscp to pg map for port {} on {}".format(port, duthost.hostname)) + return {} + + +def load_dscp_to_queue_map(duthost, port, dut_qos_maps): + """ + Helper function to calculate DSCP to Queue map for a port. + The map is derived from DSCP_TO_TC_MAP + TC_TO_QUEUE_MAP + return a dict like {0:0, 1:1...} + """ + try: + port_qos_map = dut_qos_maps['port_qos_map'] + dscp_to_tc_map_name = port_qos_map[port]['dscp_to_tc_map'].split('|')[-1].strip(']') + tc_to_queue_map_name = port_qos_map[port]['tc_to_queue_map'].split('|')[-1].strip(']') + # Load dscp_to_tc_map + dscp_to_tc_map = dut_qos_maps['dscp_to_tc_map'][dscp_to_tc_map_name][dscp_to_tc_map_name] + # Load tc_to_queue_map + tc_to_queue_map = dut_qos_maps['tc_to_queue_map'][tc_to_queue_map_name] + # Calculate dscp to queue map + dscp_to_queue_map = {} + for dscp, tc in dscp_to_tc_map.items(): + dscp_to_queue_map[dscp] = tc_to_queue_map[tc] + return dscp_to_queue_map + except: + logger.error("Failed to retrieve dscp to queue map for port {} on {}".format(port, duthost.hostname)) + return {} diff --git a/tests/qos/qos_sai_base.py b/tests/qos/qos_sai_base.py index 8bd5c982e56..e3a24b4f616 100644 --- a/tests/qos/qos_sai_base.py +++ b/tests/qos/qos_sai_base.py @@ -11,6 +11,7 @@ from tests.common.dualtor.mux_simulator_control import toggle_all_simulator_ports, get_mux_status, check_mux_status, validate_check_result from tests.common.dualtor.constants import UPPER_TOR, LOWER_TOR from tests.common.utilities import check_qos_db_fv_reference_with_table +from tests.common.fixtures.duthost_utils import dut_qos_maps, separated_dscp_to_tc_map_on_uplink from tests.common.utilities import wait_until logger = logging.getLogger(__name__) @@ -467,8 +468,8 @@ def __buildTestPorts(self, request, testPortIds, testPortIps, src_port_ids, dst_ @pytest.fixture(scope='class', autouse=True) def dutConfig( - self, request, duthosts, rand_one_dut_hostname, tbinfo, - enum_frontend_asic_index, lower_tor_host, dualtor_ports + self, request, duthosts, enum_rand_one_per_hwsku_frontend_hostname, + enum_frontend_asic_index, lower_tor_host, tbinfo, dualtor_ports, dut_qos_maps ): """ Build DUT host config pertaining to QoS SAI tests @@ -484,12 +485,18 @@ def dutConfig( if 'dualtor' in tbinfo['topo']['name']: duthost = lower_tor_host else: - duthost = duthosts[rand_one_dut_hostname] + duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname] dut_asic = duthost.asic_instance(enum_frontend_asic_index) dutLagInterfaces = [] dutPortIps = {} testPortIps = {} + uplinkPortIds = [] + uplinkPortIps = [] + uplinkPortNames = [] + downlinkPortIds = [] + downlinkPortIps = [] + downlinkPortNames = [] mgFacts = duthost.get_extended_minigraph_facts(tbinfo) topo = tbinfo["topo"]["name"] @@ -537,12 +544,13 @@ def dutConfig( testPortIps = self.__assignTestPortIps(mgFacts) elif topo in self.SUPPORTED_T1_TOPOS: + use_separated_upkink_dscp_tc_map = separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps) for iface,addr in dut_asic.get_active_ip_interfaces(tbinfo).items(): vlan_id = None if iface.startswith("Ethernet"): if "." in iface: - iface, vlan_id = iface.split(".") - portIndex = mgFacts["minigraph_ptf_indices"][iface] + portName, vlan_id = iface.split(".") + portIndex = mgFacts["minigraph_ptf_indices"][portName] portIpMap = {'peer_addr': addr["peer_ipv4"]} if vlan_id is not None: portIpMap['vlan_id'] = vlan_id @@ -554,6 +562,18 @@ def dutConfig( portIndex = mgFacts["minigraph_ptf_indices"][portName] portIpMap = {'peer_addr': addr["peer_ipv4"]} dutPortIps.update({portIndex: portIpMap}) + # If the leaf router is using separated DSCP_TO_TC_MAP on uplink/downlink ports. + # we also need to test them separately + if use_separated_upkink_dscp_tc_map: + neighName = mgFacts["minigraph_neighbors"].get(portName, {}).get("name", "").lower() + if 't0' in neighName: + downlinkPortIds.append(portIndex) + downlinkPortIps.append(addr["peer_ipv4"]) + downlinkPortNames.append(portName) + elif 't2' in neighName: + uplinkPortIds.append(portIndex) + uplinkPortIps.append(addr["peer_ipv4"]) + uplinkPortNames.append(portName) testPortIds = sorted(dutPortIps.keys()) else: @@ -604,6 +624,19 @@ def dutConfig( testPortIds = dualTorPortIndexes testPorts = self.__buildTestPorts(request, testPortIds, testPortIps, src_port_ids, dst_port_ids) + # Update the uplink/downlink ports to testPorts + testPorts.update({ + "uplink_port_ids": uplinkPortIds, + "uplink_port_ips": uplinkPortIps, + "uplink_port_names": uplinkPortNames, + "downlink_port_ids": downlinkPortIds, + "downlink_port_ips": downlinkPortIps, + "downlink_port_names": downlinkPortNames + }) + dutinterfaces = {} + for port, index in mgFacts["minigraph_ptf_indices"].items(): + if 'Ethernet-Rec' not in port and 'Ethernet-IB' not in port: + dutinterfaces[index] = port yield { "dutInterfaces" : { index: port for port, index in mgFacts["minigraph_ptf_indices"].items() diff --git a/tests/qos/test_qos_sai.py b/tests/qos/test_qos_sai.py index d893121d660..7b78ce498ff 100644 --- a/tests/qos/test_qos_sai.py +++ b/tests/qos/test_qos_sai.py @@ -25,7 +25,8 @@ import time import json -from tests.common.fixtures.conn_graph_facts import fanout_graph_facts, conn_graph_facts # lgtm[py/unused-import] +from tests.common.fixtures.conn_graph_facts import fanout_graph_facts, conn_graph_facts +from tests.common.fixtures.duthost_utils import dut_qos_maps, separated_dscp_to_tc_map_on_uplink, load_dscp_to_pg_map # lgtm[py/unused-import] from tests.common.fixtures.ptfhost_utils import copy_ptftests_directory # lgtm[py/unused-import] from tests.common.fixtures.ptfhost_utils import copy_saitests_directory # lgtm[py/unused-import] from tests.common.fixtures.ptfhost_utils import change_mac_addresses # lgtm[py/unused-import] @@ -853,17 +854,18 @@ def testQosSaiLossyQueueVoq( setup_markings_dut(duthost, localhost, **original_voq_markings) def testQosSaiDscpQueueMapping( - self, ptfhost, dutTestParams, dutConfig + self, duthost, ptfhost, dutTestParams, dutConfig, dut_qos_maps ): """ Test QoS SAI DSCP to queue mapping Args: + duthost (AnsibleHost): The DUT host ptfhost (AnsibleHost): Packet Test Framework (PTF) dutTestParams (Fixture, dict): DUT host test params dutConfig (Fixture, dict): Map of DUT config containing dut interfaces, test port IDs, test port IPs, and test ports - + dut_qos_maps(Fixture): A fixture, return qos maps on DUT host Returns: None @@ -872,6 +874,10 @@ def testQosSaiDscpQueueMapping( """ if "backend" in dutTestParams["topo"]: pytest.skip("Dscp-queue mapping is not supported on {}".format(dutTestParams["topo"])) + + # Skip the regular dscp to pg mapping test. Will run another test case instead. + if separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps): + pytest.skip("Skip this test since separated DSCP_TO_TC_MAP is applied") testParams = dict() testParams.update(dutTestParams["basicParams"]) @@ -890,6 +896,59 @@ def testQosSaiDscpQueueMapping( testParams=testParams ) + @pytest.mark.parametrize("direction", ["downstream", "upstream"]) + def testQosSaiSeparatedDscpQueueMapping(self, duthost, ptfhost, dutTestParams, dutConfig, direction, dut_qos_maps): + """ + Test QoS SAI DSCP to queue mapping. + We will have separated DSCP_TO_TC_MAP for uplink/downlink ports on T1 if PCBB enabled. + This test case will generate both upstream and downstream traffic to verify the behavior + + Args: + duthost (AnsibleHost): The DUT host + ptfhost (AnsibleHost): Packet Test Framework (PTF) + dutTestParams (Fixture, dict): DUT host test params + dutConfig (Fixture, dict): Map of DUT config containing dut interfaces, test port IDs, test port IPs, + and test ports + direction (str): upstream/downstream + dut_qos_maps(Fixture): A fixture, return qos maps on DUT host + Returns: + None + + Raises: + RunAnsibleModuleFail if ptf test fails + """ + # Only run this test when separated DSCP_TO_TC_MAP is defined + if not separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps): + pytest.skip("Skip this test since separated DSCP_TO_TC_MAP is not applied") + + testParams = dict() + testParams.update(dutTestParams["basicParams"]) + testParams.update({ + "hwsku": dutTestParams['hwsku'], + "dual_tor_scenario": True + }) + if direction == "downstream": + testParams.update({ + "dst_port_id": dutConfig["testPorts"]["downlink_port_ids"][0], + "dst_port_ip": dutConfig["testPorts"]["downlink_port_ips"][0], + "src_port_id": dutConfig["testPorts"]["uplink_port_ids"][0], + "src_port_ip": dutConfig["testPorts"]["uplink_port_ips"][0] + }) + testParams.update({"leaf_downstream": True}) + else: + testParams.update({ + "dst_port_id": dutConfig["testPorts"]["uplink_port_ids"][0], + "dst_port_ip": dutConfig["testPorts"]["uplink_port_ips"][0], + "src_port_id": dutConfig["testPorts"]["downlink_port_ids"][0], + "src_port_ip": dutConfig["testPorts"]["downlink_port_ips"][0] + }) + testParams.update({"leaf_downstream": False}) + + self.runPtfTest( + ptfhost, testCase="sai_qos_tests.DscpMappingPB", + testParams=testParams + ) + def testQosSaiDot1pQueueMapping( self, ptfhost, dutTestParams, dutConfig ): @@ -1256,17 +1315,18 @@ def testQosSaiQSharedWatermark( ) def testQosSaiDscpToPgMapping( - self, request, ptfhost, dutTestParams, dutConfig, + self, duthost, request, ptfhost, dutTestParams, dutConfig, dut_qos_maps ): """ Test QoS SAI DSCP to PG mapping ptf test Args: + duthost (AnsibleHost): The DUT host ptfhost (AnsibleHost): Packet Test Framework (PTF) dutTestParams (Fixture, dict): DUT host test params dutConfig (Fixture, dict): Map of DUT config containing dut interfaces, test port IDs, test port IPs, and test ports - + dut_qos_maps(Fixture): A fixture, return qos maps on DUT host Returns: None @@ -1276,6 +1336,9 @@ def testQosSaiDscpToPgMapping( disableTest = request.config.getoption("--disable_test") if disableTest: pytest.skip("DSCP to PG mapping test disabled") + # Skip the regular dscp to pg mapping test. Will run another test case instead. + if separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps): + pytest.skip("Skip this test since separated DSCP_TO_TC_MAP is applied") if "backend" in dutTestParams["topo"]: pytest.skip("Dscp-PG mapping is not supported on {}".format(dutTestParams["topo"])) @@ -1293,6 +1356,57 @@ def testQosSaiDscpToPgMapping( testParams=testParams ) + @pytest.mark.parametrize("direction", ["downstream", "upstream"]) + def testQosSaiSeparatedDscpToPgMapping(self, duthost, request, ptfhost, dutTestParams, dutConfig, direction, dut_qos_maps): + """ + Test QoS SAI DSCP to PG mapping ptf test. + Since we are using different DSCP_TO_TC_MAP on uplink/downlink port, the test case also need to + run separately + + Args: + duthost (AnsibleHost) + ptfhost (AnsibleHost): Packet Test Framework (PTF) + dutTestParams (Fixture, dict): DUT host test params + dutConfig (Fixture, dict): Map of DUT config containing dut interfaces, test port IDs, test port IPs, + and test ports + direction (str): downstream or upstream + dut_qos_maps(Fixture): A fixture, return qos maps on DUT host + Returns: + None + + Raises: + RunAnsibleModuleFail if ptf test fails + """ + if not separated_dscp_to_tc_map_on_uplink(duthost, dut_qos_maps): + pytest.skip("Skip this test since separated DSCP_TO_TC_MAP is not applied") + + testParams = dict() + testParams.update(dutTestParams["basicParams"]) + if direction == "downstream": + testParams.update({ + "dst_port_id": dutConfig["testPorts"]["downlink_port_ids"][0], + "dst_port_ip": dutConfig["testPorts"]["downlink_port_ips"][0], + "src_port_id": dutConfig["testPorts"]["uplink_port_ids"][0], + "src_port_ip": dutConfig["testPorts"]["uplink_port_ips"][0] + }) + src_port_name = dutConfig["testPorts"]["uplink_port_names"][0] + else: + testParams.update({ + "dst_port_id": dutConfig["testPorts"]["uplink_port_ids"][0], + "dst_port_ip": dutConfig["testPorts"]["uplink_port_ips"][0], + "src_port_id": dutConfig["testPorts"]["downlink_port_ids"][0], + "src_port_ip": dutConfig["testPorts"]["downlink_port_ips"][0] + }) + src_port_name = dutConfig["testPorts"]["downlink_port_names"][0] + + testParams['dscp_to_pg_map'] = load_dscp_to_pg_map(duthost, src_port_name, dut_qos_maps) + + self.runPtfTest( + ptfhost, testCase="sai_qos_tests.DscpToPgMapping", + testParams=testParams + ) + + def testQosSaiDwrrWeightChange( self, ptfhost, dutTestParams, dutConfig, dutQosConfig, updateSchedProfile diff --git a/tests/saitests/sai_qos_tests.py b/tests/saitests/sai_qos_tests.py index 857907a9c53..351d779b734 100644 --- a/tests/saitests/sai_qos_tests.py +++ b/tests/saitests/sai_qos_tests.py @@ -253,8 +253,9 @@ def runTest(self): src_port_id = int(self.test_params['src_port_id']) src_port_ip = self.test_params['src_port_ip'] src_port_mac = self.dataplane.get_mac(0, src_port_id) - dual_tor_scenario = self.test_params.get('dual_tor_scenario') - dual_tor = self.test_params.get('dual_tor') + dual_tor_scenario = self.test_params.get('dual_tor_scenario', None) + dual_tor = self.test_params.get('dual_tor', None) + leaf_downstream = self.test_params.get('leaf_downstream', None) exp_ip_id = 101 exp_ttl = 63 pkt_dst_mac = router_mac if router_mac != '' else dst_port_mac @@ -334,36 +335,36 @@ def runTest(self): # dual_tor_scenario: represents whether the device is deployed into a dual ToR scenario # dual_tor: represents whether the source and destination ports are configured with additional lossless queues # According to SONiC configuration all dscp are classified to queue 1 except: - # Normal scenario Dual ToR scenario - # All ports Normal ports Ports with additional lossless queues - # dscp 8 -> queue 0 queue 0 queue 0 - # dscp 5 -> queue 2 queue 1 queue 1 - # dscp 3 -> queue 3 queue 3 queue 3 - # dscp 4 -> queue 4 queue 4 queue 4 - # dscp 46 -> queue 5 queue 5 queue 5 - # dscp 48 -> queue 6 queue 7 queue 7 - # dscp 2 -> queue 1 queue 1 queue 2 - # dscp 6 -> queue 1 queue 1 queue 6 + # Normal scenario Dual ToR scenario Leaf router with separated DSCP_TO_TC_MAP + # All ports Normal ports Ports with additional lossless queues downstream (source is T2) upstream (source is T0) + # dscp 8 -> queue 0 queue 0 queue 0 queue 0 queue 0 + # dscp 5 -> queue 2 queue 1 queue 1 queue 1 queue 1 + # dscp 3 -> queue 3 queue 3 queue 3 queue 3 queue 3 + # dscp 4 -> queue 4 queue 4 queue 4 queue 4 queue 4 + # dscp 46 -> queue 5 queue 5 queue 5 queue 5 queue 5 + # dscp 48 -> queue 6 queue 7 queue 7 queue 7 queue 7 + # dscp 2 -> queue 1 queue 1 queue 2 queue 1 queue 2 + # dscp 6 -> queue 1 queue 1 queue 6 queue 1 queue 6 # rest 56 dscps -> queue 1 # So for the 64 pkts sent the mapping should be the following: - # queue 1 56 + 2 = 58 56 + 3 = 59 56 + 1 = 57 - # queue 2/6 1 0 1 - # queue 3/4 1 1 1 - # queue 5 1 1 1 - # queue 7 0 1 1 + # queue 1 56 + 2 = 58 56 + 3 = 59 56 + 1 = 57 59 57 + # queue 2/6 1 0 1 0 0 + # queue 3/4 1 1 1 1 1 + # queue 5 1 1 1 1 1 + # queue 7 0 1 1 1 1 # LAG ports can have LACP packets on queue 0, hence using >= comparison assert(queue_results[QUEUE_0] >= 1 + queue_results_base[QUEUE_0]) assert(queue_results[QUEUE_3] == 1 + queue_results_base[QUEUE_3]) assert(queue_results[QUEUE_4] == 1 + queue_results_base[QUEUE_4]) assert(queue_results[QUEUE_5] == 1 + queue_results_base[QUEUE_5]) - if dual_tor or not dual_tor_scenario: + if dual_tor or (dual_tor_scenario == False) or (leaf_downstream == False): assert(queue_results[QUEUE_2] == 1 + queue_results_base[QUEUE_2]) assert(queue_results[QUEUE_6] == 1 + queue_results_base[QUEUE_6]) else: assert(queue_results[QUEUE_2] == queue_results_base[QUEUE_2]) assert(queue_results[QUEUE_6] == queue_results_base[QUEUE_6]) if dual_tor_scenario: - if not dual_tor: + if (dual_tor == False) or leaf_downstream: assert(queue_results[QUEUE_1] == 59 + queue_results_base[QUEUE_1]) else: assert(queue_results[QUEUE_1] == 57 + queue_results_base[QUEUE_1]) @@ -502,24 +503,35 @@ def runTest(self): src_port_id = int(self.test_params['src_port_id']) src_port_ip = self.test_params['src_port_ip'] src_port_mac = self.dataplane.get_mac(0, src_port_id) + dscp_to_pg_map = self.test_params.get('dscp_to_pg_map', None) + print >> sys.stderr, "dst_port_id: %d, src_port_id: %d" % (dst_port_id, src_port_id) print >> sys.stderr, "dst_port_mac: %s, src_port_mac: %s, src_port_ip: %s, dst_port_ip: %s" % (dst_port_mac, src_port_mac, src_port_ip, dst_port_ip) exp_ip_id = 100 exp_ttl = 63 - # According to SONiC configuration all dscps are classified to pg 0 except: - # dscp 3 -> pg 3 - # dscp 4 -> pg 4 - # So for the 64 pkts sent the mapping should be -> 62 pg 0, 1 for pg 3, and 1 for pg 4 - lossy_dscps = range(0, 64) - lossy_dscps.remove(3) - lossy_dscps.remove(4) - pg_dscp_map = { - 3 : [3], - 4 : [4], - 0 : lossy_dscps - } + if not dscp_to_pg_map: + # According to SONiC configuration all dscps are classified to pg 0 except: + # dscp 3 -> pg 3 + # dscp 4 -> pg 4 + # So for the 64 pkts sent the mapping should be -> 62 pg 0, 1 for pg 3, and 1 for pg 4 + lossy_dscps = list(range(0, 64)) + lossy_dscps.remove(3) + lossy_dscps.remove(4) + pg_dscp_map = { + 3: [3], + 4: [4], + 0: lossy_dscps + } + else: + pg_dscp_map = {} + for dscp, pg in dscp_to_pg_map.items(): + if pg in pg_dscp_map: + pg_dscp_map[int(pg)].append(int(dscp)) + else: + pg_dscp_map[int(pg)] = [int(dscp)] + print >> sys.stderr, pg_dscp_map try: