Exemplo n.º 1
0
    def remove_subscriber_qos(self, imsi: str = "", rule_num: int = -1):
        if not self._enable_qos or not self._initialized:
            LOG.error(
                "remove_subscriber_qos failed imsi %s rule_num %d \
                      failed qos not enabled or uninitialized",
                imsi,
                rule_num,
            )
            return

        imsi = normalizeIMSI(imsi)
        LOG.debug("removing Qos for imsi %s rule_num %d", imsi, rule_num)
        if imsi:
            if imsi not in self._subscriber_map:
                LOG.debug("unable to find imsi %s", imsi)
                return

            if rule_num != -1:
                # delete queue associated with this rule
                if rule_num not in self._subscriber_map[imsi]:
                    LOG.error("unable to find rule_num %d for imsi %s",
                              rule_num, imsi)
                    return

                for (qos_handle,
                     direction) in self._subscriber_map[imsi][rule_num]:
                    self.qos_impl.remove_qos(qos_handle, direction)
                    del self._qos_store[get_json(
                        get_subscriber_key(imsi, rule_num, direction))]

                if len(self._subscriber_map[imsi]) == 1:
                    del self._subscriber_map[imsi]
                else:
                    del self._subscriber_map[imsi][rule_num]

            else:
                # delete all queues associated with this subscriber
                for rule_num, qd_list in self._subscriber_map[imsi].items():
                    for (qos_handle, direction) in qd_list:
                        self.qos_impl.remove_qos(qos_handle, direction)
                        del self._qos_store[get_json(
                            get_subscriber_key(imsi, rule_num, direction))]

                self._subscriber_map.pop(imsi)
        else:
            # delete Qos queues associated with all subscribers
            LOG.info("removing Qos for all subscribers")
            for imsi, rule_map in self._subscriber_map.items():
                for rule_num, qd_list in rule_map.items():
                    for (qos_handle, direction) in qd_list:
                        self.qos_impl.remove_qos(qos_handle, direction)
                        # delete from qos store
                        del self._qos_store[get_json(
                            get_subscriber_key(imsi, rule_num, direction))]
            self._subscriber_map.clear()
Exemplo n.º 2
0
    def add_subscriber_qos(
        self,
        imsi: str,
        rule_num: int,
        direction: FlowMatch.Direction,
        qos_info: QosInfo,
    ):
        if not self._enable_qos or not self._initialized:
            LOG.error(
                "add_subscriber_qos failed imsi %s rule_num %d \
                      direction %d failed qos not enabled or uninitialized",
                imsi,
                rule_num,
                direction,
            )
            return (None, None)

        imsi = normalizeIMSI(imsi)
        LOG.debug("adding qos for imsi %s rule_num %d", imsi, rule_num)
        k = get_subscriber_key(imsi, rule_num, direction)
        qos_handle = self._qos_store.get(get_json(k))
        if qos_handle:
            LOG.debug("qos handle already exists for %s", k)
            return self.qos_impl.get_action_instruction(qos_handle)

        qos_handle = self.qos_impl.add_qos(direction, qos_info)
        if rule_num not in self._subscriber_map[imsi]:
            self._subscriber_map[imsi][rule_num] = []

        self._subscriber_map[imsi][rule_num].append((qos_handle, direction))
        self._qos_store[get_json(k)] = qos_handle
        return self.qos_impl.get_action_instruction(qos_handle)
Exemplo n.º 3
0
 def populate_db(qid_list, old_ambr_list, old_leaf_list, rule_list):
     qos_mgr._redis_store.clear()
     for i, t in enumerate(rule_list):
         k = get_key_json(get_subscriber_key(*t))
         v = get_data_json(
             get_subscriber_data(qid_list[i], old_ambr_list[i],
                                 old_leaf_list[i]))
         qos_mgr._redis_store[k] = v
Exemplo n.º 4
0
    def update_rule(self, ip_addr: str, rule_num: int, d: FlowMatch.Direction,
                    qos_handle: int, ambr: int, leaf: int) -> None:
        k = get_key_json(get_subscriber_key(self.imsi, ip_addr, rule_num, d))
        qos_data = get_data_json(get_subscriber_data(qos_handle, ambr, leaf))
        LOG.debug("Update: %s -> %s", k, qos_data)
        self._redis_store[k] = qos_data

        self._update_rules_map(ip_addr, rule_num, d, qos_data)
Exemplo n.º 5
0
    def _testSanity(self, mock_meter_get_action_inst, mock_tc_get_action_inst,
                    mock_meter_cls, mock_traffic_cls):
        ''' This test verifies that qos configuration gets programmed correctly
        for addition and deletion of a single subscriber and a single rule,
        We additionally verify if the clean_restart wipes out everything '''

        # mock unclean state in qos
        prior_qids = {
            self.ul_intf: [
                2,
            ],
            self.dl_intf: [
                3,
            ]
        }
        if self.config["qos"]["impl"] == QosImplType.LINUX_TC:
            mock_traffic_cls.read_all_classes.side_effect = (
                lambda intf: prior_qids[intf])

        qos_mgr = QosManager(MagicMock, asyncio.new_event_loop(), self.config)
        qos_mgr._qos_store = {}
        qos_mgr._setupInternal()
        imsi, rule_num, d, qos_info = "imsi1234", 0, 0, QosInfo(100000, 100000)

        # add new subscriber qos queue
        qos_mgr.add_subscriber_qos(imsi, rule_num, d, qos_info)
        k = get_json(get_subscriber_key(imsi, rule_num, d))

        exp_id = qos_mgr.qos_impl._start_idx
        self.assertTrue(qos_mgr._qos_store[k] == exp_id)
        self.assertTrue(qos_mgr._subscriber_map[imsi][rule_num] == (exp_id, d))

        # add the same subscriber and ensure that we didn't create another
        # qos config for the subscriber
        qos_mgr.add_subscriber_qos(imsi, rule_num, d, qos_info)
        self.assertTrue(qos_mgr._subscriber_map[imsi][rule_num] == (exp_id, d))

        # verify if traffic class was invoked properly
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterAddQos(mock_meter_get_action_inst, mock_meter_cls,
                                   d, exp_id, qos_info)
            self.verifyMeterCleanRestart(mock_meter_cls)
        else:
            self.verifyTcAddQos(mock_tc_get_action_inst, mock_traffic_cls, d,
                                exp_id, qos_info)
            self.verifyTcCleanRestart(prior_qids, mock_traffic_cls)

        # remove the subscriber qos and verify things are cleaned up
        qos_mgr.remove_subscriber_qos(imsi, rule_num)
        self.assertTrue(len(qos_mgr._qos_store) == 0)
        self.assertTrue(imsi not in qos_mgr._subscriber_map)

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, d, exp_id)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, d, exp_id)
Exemplo n.º 6
0
    def remove_rule(self, rule_num: int) -> None:
        session_with_rule = self.find_session_with_rule(rule_num)
        if session_with_rule:
            for (d, _) in self.rules[rule_num]:
                k = get_subscriber_key(self.imsi, session_with_rule.ip_addr,
                                       rule_num, d)
                del self._qos_store[get_json(k)]

        del self.rules[rule_num]
        session_with_rule.rules.remove(rule_num)
Exemplo n.º 7
0
    def update_rule(self, ip_addr: str, rule_num: int, d: FlowMatch.Direction,
                    qos_handle: int) -> None:
        k = get_subscriber_key(self.imsi, ip_addr, rule_num, d)
        self._qos_store[get_json(k)] = qos_handle

        if rule_num not in self.rules:
            self.rules[rule_num] = []

        session = self.get_or_create_session(ip_addr)
        session.rules.add(rule_num)
        self.rules[rule_num].append((d, qos_handle))
Exemplo n.º 8
0
 def testQosKeyUtils(self):
     k = get_subscriber_key("1234", '1.1.1.1', 10, 0)
     j = get_key_json(k)
     self.assertTrue(get_key(j) == k)
Exemplo n.º 9
0
    def _testUncleanRestartWithApnAMBR(self, mock_meter_cls, mock_traffic_cls):
        """This test verifies all tests cases from _testUncleanRestart for APN
        AMBR configs.
        """
        loop = asyncio.new_event_loop()
        qos_mgr = QosManager(MagicMock, loop, self.config)
        qos_mgr._redis_store = {}

        def populate_db(qid_list, old_ambr_list, old_leaf_list, rule_list):
            qos_mgr._redis_store.clear()
            for i, t in enumerate(rule_list):
                k = get_key_json(get_subscriber_key(*t))
                v = get_data_json(
                    get_subscriber_data(
                        qid_list[i],
                        old_ambr_list[i],
                        old_leaf_list[i],
                    ),
                )
                qos_mgr._redis_store[k] = v

        MockSt = namedtuple("MockSt", "meter_id")
        dummy_meter_ev_body = [MockSt(11), MockSt(13), MockSt(2), MockSt(15)]

        def tc_read(intf):
            if intf == self.ul_intf:
                return [
                    (30, 3000), (15, 1500),
                    (300, 3000), (150, 1500),
                    (3000, 65534), (1500, 65534),
                ]
            else:
                return [
                    (13, 1300), (11, 1100),
                    (130, 1300), (110, 1100),
                    (1300, 65534), (1100, 65534),
                ]

        # prepopulate qos_store
        old_qid_list = [2, 11, 13, 30]
        old_leaf_list = [20, 110, 130, 300]
        old_ambr_list = [200, 1100, 1300, 3000]

        old_rule_list = [
            ("1", '1.1.1.1', 0, 0), ("1", '1.1.1.2', 1, 0),
            ("1", '1.1.1.3', 2, 1), ("2", '1.1.1.4', 0, 0),
        ]
        populate_db(old_qid_list, old_ambr_list, old_leaf_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        # verify that qos_handle 20 not found in system is purged from map
        qid_list = []
        for _, v in qos_mgr._redis_store.items():
            _, qid, _, _ = get_data(v)
            qid_list.append(qid)

        logging.debug("qid_list %s", qid_list)
        self.assertNotIn(20, qid_list)

        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_called_with(MagicMock, 15)
        else:
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 15, False)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 150, False)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 1500, True)

        # add a new rule to the qos_mgr and check if it is assigned right id
        imsi, rule_num, d, qos_info = "3", 0, 0, QosInfo(100000, 100000)
        qos_mgr.impl.get_action_instruction = MagicMock
        qos_mgr.add_subscriber_qos(imsi, '', 10, rule_num, d, qos_info)
        k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))

        exp_id = 3  # since start_idx 2 is already used
        d3 = get_data_json(get_subscriber_data(exp_id + 1, exp_id - 1, exp_id))

        self.assertEqual(qos_mgr._redis_store[k], d3)
        self.assertEqual(qos_mgr._subscriber_state[imsi].rules[rule_num][0], (d, d3))

        # delete the restored rule - ensure that it gets cleaned properly
        purge_imsi = "1"
        purge_rule_num = 1
        purge_qos_handle = 2
        qos_mgr.remove_subscriber_qos(purge_imsi, purge_rule_num)
        self.assertTrue(purge_rule_num not in qos_mgr._subscriber_state[purge_imsi].rules)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_called_with(MagicMock, purge_qos_handle)
        else:
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 11, False)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 110, False)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 1100, True)

        # case 2 - check with empty qos configs, qos_map gets purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        populate_db(old_qid_list, old_ambr_list, old_leaf_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            MockSt = namedtuple("MockSt", "meter_id")
            qos_mgr.impl._fut = loop.create_future()
            qos_mgr.impl.handle_meter_config_stats([])
        else:
            mock_traffic_cls.read_all_classes.side_effect = lambda _: []

        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        self.assertTrue(not qos_mgr._redis_store)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_not_called()
        else:
            mock_traffic_cls.delete_class.assert_not_called()

        # case 3 - check with empty qos_map, all qos configs get purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        qos_mgr._redis_store.clear()

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.impl._fut = loop.create_future()
            qos_mgr.impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        logging.debug("case three")
        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        self.assertTrue(not qos_mgr._redis_store)
        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 2)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 15)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 13)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 11)
        else:
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 15, False)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 150, False)

            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 13, False)
            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 130, False)

            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 11, False)
            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 110, False)
Exemplo n.º 10
0
    def testApnAmbrSanity(
        self,
        mock_tc_get_action_inst,
        mock_traffic_cls,
    ):
        """ This test verifies that qos configuration gets programmed correctly
        for addition and deletion of a single subscriber and a single rule,
        We additionally verify if the clean_restart wipes out everything """
        self.config["qos"]["impl"] = QosImplType.LINUX_TC
        # mock unclean state in qos
        prior_qids = {self.ul_intf: [(2, 0)], self.dl_intf: [(3, 0)]}
        mock_traffic_cls.read_all_classes.side_effect = lambda intf: prior_qids[intf]

        qos_mgr = QosManager(MagicMock, asyncio.new_event_loop(), self.config)
        qos_mgr._redis_store = {}
        qos_mgr._setupInternal()
        ambr_ul, ambr_dl = 250000, 500000
        imsi, ip_addr, rule_num, qos_info = ("1234", '1.1.1.1', 1, QosInfo(50000, 100000))

        # add new subscriber qos queue
        qos_mgr.add_subscriber_qos(imsi, ip_addr, ambr_ul, rule_num, FlowMatch.UPLINK, qos_info)
        qos_mgr.add_subscriber_qos(imsi, ip_addr, ambr_dl, rule_num, FlowMatch.DOWNLINK, qos_info)

        k1 = get_key_json(get_subscriber_key(imsi, ip_addr, rule_num, FlowMatch.UPLINK))
        k2 = get_key_json(get_subscriber_key(imsi, ip_addr, rule_num, FlowMatch.DOWNLINK))

        ambr_ul_exp_id = qos_mgr.impl._start_idx
        ul_exp_id = qos_mgr.impl._start_idx + 2
        ambr_dl_exp_id = qos_mgr.impl._start_idx + 3
        dl_exp_id = qos_mgr.impl._start_idx + 5

        qid_info_ul = get_subscriber_data(ul_exp_id, ul_exp_id - 2, ul_exp_id - 1)
        qid_info_dl = get_subscriber_data(dl_exp_id, dl_exp_id - 2, dl_exp_id - 1)
        self.assertEqual(get_data(qos_mgr._redis_store[k1]), qid_info_ul)
        self.assertEqual(get_data(qos_mgr._redis_store[k2]), qid_info_dl)
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][0] == (0, get_data_json(qid_info_ul)))
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][1] == (1, get_data_json(qid_info_dl)))

        self.assertEqual(len(qos_mgr._subscriber_state[imsi].sessions), 1)
        self.assertEqual(qos_mgr._subscriber_state[imsi].sessions[ip_addr].ambr_dl, ambr_dl_exp_id)
        self.assertEqual(qos_mgr._subscriber_state[imsi].sessions[ip_addr].ambr_dl_leaf, ambr_dl_exp_id + 1)

        self.assertEqual(qos_mgr._subscriber_state[imsi].sessions[ip_addr].ambr_ul_leaf, ambr_ul_exp_id + 1)

        # add the same subscriber and ensure that we didn't create another
        # qos config for the subscriber
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.UPLINK, qos_info)
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.DOWNLINK, qos_info)

        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][0] == (0, get_data_json(qid_info_ul)))
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][1] == (1, get_data_json(qid_info_dl)))

        # verify if traffic class was invoked properly
        self.verifyTcAddQos(
            mock_tc_get_action_inst, mock_traffic_cls, FlowMatch.UPLINK,
            ul_exp_id, qos_info, parent_qid=ambr_ul_exp_id,
        )
        self.verifyTcAddQos(
            mock_tc_get_action_inst, mock_traffic_cls, FlowMatch.DOWNLINK,
            dl_exp_id, qos_info, parent_qid=ambr_dl_exp_id,
        )
        self.verifyTcCleanRestart(prior_qids, mock_traffic_cls)

        # remove the subscriber qos and verify things are cleaned up
        qos_mgr.remove_subscriber_qos(imsi, rule_num)
        self.assertTrue(len(qos_mgr._redis_store) == 0)
        self.assertTrue(imsi not in qos_mgr._subscriber_state)

        self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.UPLINK, ambr_ul_exp_id, True)
        self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.UPLINK, ul_exp_id)
        self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.DOWNLINK, ambr_dl_exp_id, True)
        self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.DOWNLINK, dl_exp_id)
Exemplo n.º 11
0
    def _testSanity(
        self,
        mock_meter_get_action_inst,
        mock_tc_get_action_inst,
        mock_meter_cls,
        mock_traffic_cls,
    ):
        """ This test verifies that qos configuration gets programmed correctly
        for addition and deletion of a single subscriber and a single rule,
        We additionally verify if the clean_restart wipes out everything """

        # mock unclean state in qos
        prior_qids = {self.ul_intf: [(2, 0)], self.dl_intf: [(3, 0)]}
        if self.config["qos"]["impl"] == QosImplType.LINUX_TC:
            mock_traffic_cls.read_all_classes.side_effect = lambda intf: prior_qids[intf]

        qos_mgr = QosManager(MagicMock, asyncio.new_event_loop(), self.config)
        qos_mgr._redis_store = {}
        qos_mgr._setupInternal()
        imsi, ip_addr, rule_num, qos_info = "1234", '1.1.1.1', 0, QosInfo(100000, 100000)

        # add new subscriber qos queue
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.UPLINK, qos_info)
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.DOWNLINK, qos_info)

        k1 = get_key_json(get_subscriber_key(imsi, ip_addr, rule_num, FlowMatch.UPLINK))
        k2 = get_key_json(get_subscriber_key(imsi, ip_addr, rule_num, FlowMatch.DOWNLINK))
        ul_exp_id = qos_mgr.impl._start_idx
        dl_exp_id = qos_mgr.impl._start_idx + 1
        ul_qid_info = get_data_json(get_subscriber_data(ul_exp_id, 0, 0))
        dl_qid_info = get_data_json(get_subscriber_data(dl_exp_id, 0, 0))

        self.assertTrue(qos_mgr._redis_store[k1] == ul_qid_info)
        self.assertTrue(qos_mgr._redis_store[k2] == dl_qid_info)
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][0] == (0, ul_qid_info))
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][1] == (1, dl_qid_info))

        # add the same subscriber and ensure that we didn't create another
        # qos config for the subscriber
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.UPLINK, qos_info)
        qos_mgr.add_subscriber_qos(imsi, ip_addr, 0, rule_num, FlowMatch.DOWNLINK, qos_info)

        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][0] == (0, ul_qid_info))
        self.assertTrue(qos_mgr._subscriber_state[imsi].rules[rule_num][1] == (1, dl_qid_info))

        # verify if traffic class was invoked properly
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterAddQos(
                mock_meter_get_action_inst,
                mock_meter_cls,
                FlowMatch.UPLINK,
                ul_exp_id,
                qos_info,
            )
            self.verifyMeterAddQos(
                mock_meter_get_action_inst,
                mock_meter_cls,
                FlowMatch.DOWNLINK,
                dl_exp_id,
                qos_info,
            )
            self.verifyMeterCleanRestart(mock_meter_cls)
        else:
            self.verifyTcAddQos(
                mock_tc_get_action_inst,
                mock_traffic_cls,
                FlowMatch.UPLINK,
                ul_exp_id,
                qos_info,
            )
            self.verifyTcAddQos(
                mock_tc_get_action_inst,
                mock_traffic_cls,
                FlowMatch.DOWNLINK,
                dl_exp_id,
                qos_info,
            )
            self.verifyTcCleanRestart(prior_qids, mock_traffic_cls)

        # remove the subscriber qos and verify things are cleaned up
        qos_mgr.remove_subscriber_qos(imsi, rule_num)
        self.assertTrue(len(qos_mgr._redis_store) == 0)
        self.assertTrue(imsi not in qos_mgr._subscriber_state)

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, FlowMatch.UPLINK, ul_exp_id)
            self.verifyMeterRemoveQos(mock_meter_cls, FlowMatch.DOWNLINK, dl_exp_id)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.UPLINK, ul_exp_id)
            self.verifyTcRemoveQos(mock_traffic_cls, FlowMatch.DOWNLINK, dl_exp_id)
Exemplo n.º 12
0
    def _testMultipleSubscribers(
        self,
        mock_meter_get_action_inst,
        mock_tc_get_action_inst,
        mock_meter_cls,
        mock_traffic_cls,
    ):
        """ This test verifies that qos configuration gets programmed correctly
        for addition and deletion of a multiple subscribers and rules.
        we additionally run through different scenarios involving
        - deactivating a rule
        - deactivating a subscriber
        - creating gaps in deletion and verifying that new qos configs get
        programmed properly with appropriate qids
        -  additionally we also verify the idempotency of deletion calls
        and ensure that code doesn't behave incorrectly when same items are
        deleted multiple times
        - Finally we delete everything and verify if that behavior is right"""

        if self.config["qos"]["impl"] == QosImplType.LINUX_TC:
            mock_traffic_cls.read_all_classes.side_effect = lambda intf: []
            mock_traffic_cls.delete_class.side_effect = lambda *args: 0

        qos_mgr = QosManager(MagicMock, asyncio.new_event_loop(), self.config)
        qos_mgr._redis_store = {}
        qos_mgr._setupInternal()
        rule_list1 = [
            ("1", 0, 0),
            ("1", 1, 0),
            ("1", 2, 1),
            ("2", 0, 0),
        ]

        rule_list2 = [
            ("2", 1, 0),
            ("3", 0, 0),
            ("4", 0, 0),
            ("5", 0, 0),
            ("5", 1, 1),
            ("6", 0, 0),
        ]

        start_idx, end_idx = 2, 2 + len(rule_list1)
        id_list = list(range(start_idx, end_idx))
        qos_info = QosInfo(100000, 100000)
        exp_id_dict = {}

        # add new subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list1):
            qos_mgr.add_subscriber_qos(imsi, '', 0, rule_num, d, qos_info)

            exp_id = id_list[i]
            k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))
            exp_id_dict[k] = exp_id
            # self.assertTrue(qos_mgr._redis_store[k] == exp_id)
            qid_info = get_data_json(get_subscriber_data(exp_id, 0, 0))
            self.assertEqual(qos_mgr._subscriber_state[imsi].rules[rule_num][0], (d, qid_info))

            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterAddQos(
                    mock_meter_get_action_inst, mock_meter_cls, d, exp_id, qos_info,
                )
            else:
                self.verifyTcAddQos(
                    mock_tc_get_action_inst, mock_traffic_cls, d, exp_id, qos_info,
                )

        # deactivate one rule
        # verify for imsi1 if rule num 0 gets cleaned up
        imsi, rule_num, d = rule_list1[0]
        k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))
        exp_id = exp_id_dict[k]

        qos_mgr.remove_subscriber_qos(imsi, rule_num)
        self.assertTrue(k not in qos_mgr._redis_store)
        self.assertTrue(not qos_mgr._subscriber_state[imsi].find_rule(rule_num))

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, d, exp_id)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, d, exp_id)

        # deactivate same rule and check if we log properly
        with self.assertLogs("pipelined.qos.common", level="DEBUG") as cm:
            qos_mgr.remove_subscriber_qos(imsi, rule_num)

        error_msg = "unable to find rule_num 0 for imsi 1"
        self.assertTrue(cm.output[1].endswith(error_msg))

        # deactivate imsi
        # verify for imsi1 if rule num 1 and 2 gets cleaned up
        qos_mgr.remove_subscriber_qos(imsi)
        remove_qos_args = []
        for imsi, rule_num, d in rule_list1[1:]:
            if imsi != "1":
                continue

            k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))
            exp_id = exp_id_dict[k]
            self.assertTrue(k not in qos_mgr._redis_store)
            remove_qos_args.append((d, exp_id))

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQosBulk(mock_meter_cls, remove_qos_args)
        else:
            self.verifyTcRemoveQosBulk(mock_traffic_cls, remove_qos_args)

        self.assertTrue("1" not in qos_mgr._subscriber_state)

        # deactivate same imsi again and ensure nothing bad happens

        logging.debug("removing qos")
        with self.assertLogs("pipelined.qos.common", level="DEBUG") as cm:
            qos_mgr.remove_subscriber_qos("1")
        logging.debug("removing qos: done")

        error_msg = "imsi 1 not found"
        self.assertTrue(error_msg in cm.output[-1])

        # now only imsi2 should remain
        assert(len(qos_mgr._subscriber_state) == 1)
        assert(len(qos_mgr._subscriber_state['2'].rules) == 1)
        assert(len(qos_mgr._subscriber_state['2'].rules[0]) == 1)
        existing_qid = qos_mgr._subscriber_state['2'].rules[0][0][1]
        _, existing_qid, _, _ = get_data(existing_qid)

        # add second rule list and delete and verify if things work
        qos_info = QosInfo(100000, 200000)

        # additional 1 is for accomodating the existing imsi2RuleList1Qid
        start_idx, end_idx = 2, 2 + len(rule_list2) + 1
        id_list = [i for i in range(start_idx, end_idx) if i != existing_qid]

        # add new subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list2):
            qos_mgr.add_subscriber_qos(imsi, '', 0, rule_num, d, qos_info)
            exp_id = id_list[i]
            qid_info = get_data_json(get_subscriber_data(exp_id, 0, 0))

            k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))
            self.assertEqual(qos_mgr._redis_store[k], qid_info)
            self.assertEqual(qos_mgr._subscriber_state[imsi].rules[rule_num][0], (d, qid_info))
            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterAddQos(
                    mock_meter_get_action_inst, mock_meter_cls, d, exp_id, qos_info,
                )
            else:
                self.verifyTcAddQos(
                    mock_tc_get_action_inst, mock_traffic_cls, d, exp_id, qos_info,
                )

        # delete the subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list2):
            qos_mgr.remove_subscriber_qos(imsi, rule_num)

            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterRemoveQos(mock_meter_cls, d, id_list[i])
            else:
                self.verifyTcRemoveQos(mock_traffic_cls, d, id_list[i])

        self.assertTrue(len(qos_mgr._subscriber_state) == 1)
        self.assertTrue('2' in qos_mgr._subscriber_state)

        # delete everything
        qos_mgr.remove_subscriber_qos(imsi='2')

        # imsi2 from rule_list1 alone wasn't removed
        imsi, rule_num, d = rule_list1[3]
        k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))
        self.assertTrue(not qos_mgr._redis_store)
        self.assertTrue(not qos_mgr._subscriber_state)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, d, existing_qid)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, d, existing_qid)
Exemplo n.º 13
0
    def _testUncleanRestart(self, mock_meter_cls, mock_traffic_cls):
        """This test verifies the case when we recover the state upon
        restart. We verify the base case of reconciling differences
        between system qos configs and qos_store configs(real code uses
        redis hash, we simply use dict). Additionally we test cases when
        system qos configs were wiped out and qos store state was wiped out
        and ensure that eventually the system and qos store state remains
        consistent"""
        loop = asyncio.new_event_loop()
        qos_mgr = QosManager(loop, self.config, fakeredis.FakeStrictRedis())
        qos_mgr.init_impl(MagicMock)
        qos_mgr._redis_store = {}

        def populate_db(qid_list, rule_list):
            qos_mgr._redis_store.clear()
            for i, t in enumerate(rule_list):
                k = get_key_json(get_subscriber_key(*t))
                v = get_data_json(get_subscriber_data(qid_list[i], 0, 0))
                qos_mgr._redis_store[k] = v

        MockSt = namedtuple("MockSt", "meter_id")
        dummy_meter_ev_body = [MockSt(11), MockSt(13), MockSt(2), MockSt(15)]

        def tc_read(intf):
            if intf == self.ul_intf:
                return [(2, 65534), (15, 65534)]
            else:
                return [(13, 65534), (11, 65534)]

        # prepopulate qos_store
        old_qid_list = [2, 11, 13, 20]
        old_rule_list = [
            ("1", '1.1.1.1', 0, 0),
            ("1", '1.1.1.2', 1, 0),
            ("1", '1.1.1.3', 2, 1),
            ("2", '1.1.1.4', 0, 0),
        ]
        populate_db(old_qid_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        # verify that qos_handle 20 not found in system is purged from map
        qid_list = []
        for _, v in qos_mgr._redis_store.items():
            _, qid, _, _ = get_data(v)
            qid_list.append(qid)

        logging.debug("qid_list %s", qid_list)
        self.assertNotIn(20, qid_list)

        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_called_with(MagicMock, 15)
        else:
            mock_traffic_cls.delete_class.assert_called_with(
                self.ul_intf, 15, False)

        # add a new rule to the qos_mgr and check if it is assigned right id
        imsi, rule_num, d, qos_info = "3", 0, 0, QosInfo(100000, 100000)
        qos_mgr.impl.get_action_instruction = MagicMock
        qos_mgr.add_subscriber_qos(imsi, '', 0, rule_num, d, qos_info)
        k = get_key_json(get_subscriber_key(imsi, '', rule_num, d))

        exp_id = 3  # since start_idx 2 is already used
        d3 = get_data_json(get_subscriber_data(exp_id, 0, 0))

        self.assertEqual(qos_mgr._redis_store[k], d3)
        self.assertEqual(qos_mgr._subscriber_state[imsi].rules[rule_num][0],
                         (d, d3))

        # delete the restored rule - ensure that it gets cleaned properly
        purge_imsi = "1"
        purge_rule_num = 0
        purge_qos_handle = 2
        qos_mgr.remove_subscriber_qos(purge_imsi, purge_rule_num)
        self.assertTrue(
            purge_rule_num not in qos_mgr._subscriber_state[purge_imsi].rules)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_called_with(
                MagicMock, purge_qos_handle)
        else:
            mock_traffic_cls.delete_class.assert_called_with(
                self.ul_intf,
                purge_qos_handle,
                False,
            )

        # case 2 - check with empty qos configs, qos_map gets purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        populate_db(old_qid_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            MockSt = namedtuple("MockSt", "meter_id")
            qos_mgr.impl._fut = loop.create_future()
            qos_mgr.impl.handle_meter_config_stats([])
        else:
            mock_traffic_cls.read_all_classes.side_effect = lambda _: []

        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        self.assertTrue(not qos_mgr._redis_store)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_not_called()
        else:
            mock_traffic_cls.delete_class.assert_not_called()

        # case 3 - check with empty qos_map, all qos configs get purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        qos_mgr._redis_store.clear()

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.impl._fut = loop.create_future()
            qos_mgr.impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        qos_mgr._initialized = False
        qos_mgr._setupInternal()

        self.assertTrue(not qos_mgr._redis_store)
        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 2)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 15)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 13)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 11)
        else:
            mock_traffic_cls.delete_class.assert_any_call(
                self.ul_intf, 2, False)
            mock_traffic_cls.delete_class.assert_any_call(
                self.ul_intf, 15, False)
            mock_traffic_cls.delete_class.assert_any_call(
                self.dl_intf, 13, False)
            mock_traffic_cls.delete_class.assert_any_call(
                self.dl_intf, 11, False)
Exemplo n.º 14
0
 def testQosKeyUtils(self, ):
     k = get_subscriber_key("imsi1234", 10, 0)
     j = get_json(k)
     self.assertTrue(get_key(j) == k)
Exemplo n.º 15
0
    def _testMultipleSubscribers(self, mock_meter_get_action_inst,
                                 mock_tc_get_action_inst, mock_meter_cls,
                                 mock_traffic_cls):
        ''' This test verifies that qos configuration gets programmed correctly
        for addition and deletion of a multiple subscribers and rules.
        we additionally run through different scenarios involving
        - deactivating a rule
        - deactivating a subscriber
        - creating gaps in deletion and verifying that new qos configs get
        programmed properly with appropriate qids
        -  additionally we also verify the idempotency of deletion calls
        and ensure that code doesn't behave incorrectly when same items are
        deleted multiple times
        - Finally we delete everything and verify if that behavior is right'''
        qos_mgr = QosManager(MagicMock, asyncio.new_event_loop(), self.config)
        qos_mgr._qos_store = {}
        qos_mgr._setupInternal()
        rule_list1 = [("imsi1", 0, 0), ("imsi1", 1, 0), ("imsi1", 2, 1),
                      ("imsi2", 0, 0)]

        rule_list2 = [("imsi2", 1, 0), ("imsi3", 0, 0), ("imsi4", 0, 0),
                      ("imsi5", 0, 0), ("imsi5", 1, 1), ("imsi6", 0, 0)]

        start_idx, end_idx = 2, 2 + len(rule_list1)
        id_list = list(range(start_idx, end_idx))
        qos_info = QosInfo(100000, 100000)
        exp_id_dict = {}
        # add new subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list1):
            qos_mgr.add_subscriber_qos(imsi, rule_num, d, qos_info)

            exp_id = id_list[i]
            k = get_json(get_subscriber_key(imsi, rule_num, d))
            exp_id_dict[k] = exp_id

            self.assertTrue(qos_mgr._qos_store[k] == exp_id)
            self.assertTrue(qos_mgr._subscriber_map[imsi][rule_num] == (exp_id,
                                                                        d))

            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterAddQos(mock_meter_get_action_inst,
                                       mock_meter_cls, d, exp_id, qos_info)
            else:
                self.verifyTcAddQos(mock_tc_get_action_inst, mock_traffic_cls,
                                    d, exp_id, qos_info)

        # deactivate one rule
        # verify for imsi1 if rule num 0 gets cleaned up
        imsi, rule_num, d = rule_list1[0]
        k = get_json(get_subscriber_key(imsi, rule_num, d))
        exp_id = exp_id_dict[k]
        qos_mgr.remove_subscriber_qos(imsi, rule_num)
        self.assertTrue(k not in qos_mgr._qos_store)
        self.assertTrue(rule_num not in qos_mgr._subscriber_map[imsi])

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, d, exp_id)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, d, exp_id)

        # deactivate same rule and check if we log properly
        with self.assertLogs('pipelined.qos.common', level='ERROR') as cm:
            qos_mgr.remove_subscriber_qos(imsi, rule_num)
        error_msg = "unable to find rule_num 0 for imsi imsi1"
        self.assertTrue(cm.output[0].endswith(error_msg))

        # deactivate imsi
        # verify for imsi1 if rule num 1 and 2 gets cleaned up
        qos_mgr.remove_subscriber_qos(imsi)
        remove_qos_args = []
        for imsi, rule_num, d in rule_list1[1:]:
            if imsi != "imsi1":
                continue

            k = get_json(get_subscriber_key(imsi, rule_num, d))
            exp_id = exp_id_dict[k]
            self.assertTrue(k not in qos_mgr._qos_store)
            remove_qos_args.append((d, exp_id))

        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQosBulk(mock_meter_cls, remove_qos_args)
        else:
            self.verifyTcRemoveQosBulk(mock_traffic_cls, remove_qos_args)

        self.assertTrue("imsi1" not in qos_mgr._subscriber_map)

        # deactivate same imsi again and ensure nothing bad happens
        with self.assertLogs('pipelined.qos.common', level='DEBUG') as cm:
            qos_mgr.remove_subscriber_qos("imsi1")
        error_msg = "unable to find imsi imsi1"
        self.assertTrue(error_msg in cm.output[-1])

        # now only imsi2 should remain
        self.assertTrue(len(qos_mgr._qos_store) == 1)
        existing_qid = list(qos_mgr._qos_store.values())[0]

        # add second rule list and delete and verify if things work
        qos_info = QosInfo(100000, 200000)

        # additional 1 is for accomodating the existing imsi2RuleList1Qid
        start_idx, end_idx = 2, 2 + len(rule_list2) + 1
        id_list = [i for i in range(start_idx, end_idx) if i != existing_qid]

        # add new subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list2):
            qos_mgr.add_subscriber_qos(imsi, rule_num, d, qos_info)
            exp_id = id_list[i]
            k = get_json(get_subscriber_key(imsi, rule_num, d))
            self.assertTrue(qos_mgr._qos_store[k] == exp_id)
            self.assertTrue(qos_mgr._subscriber_map[imsi][rule_num] == (exp_id,
                                                                        d))
            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterAddQos(mock_meter_get_action_inst,
                                       mock_meter_cls, d, exp_id, qos_info)
            else:
                self.verifyTcAddQos(mock_tc_get_action_inst, mock_traffic_cls,
                                    d, exp_id, qos_info)

        # delete the subscriber qos queues
        for i, (imsi, rule_num, d) in enumerate(rule_list2):
            qos_mgr.remove_subscriber_qos(imsi, rule_num)
            k = get_json(get_subscriber_key(imsi, rule_num, d))
            self.assertTrue(k not in qos_mgr._qos_store)
            self.assertTrue(rule_num not in qos_mgr._subscriber_map[imsi])
            if self.config["qos"]["impl"] == QosImplType.OVS_METER:
                self.verifyMeterRemoveQos(mock_meter_cls, d, id_list[i])
            else:
                self.verifyTcRemoveQos(mock_traffic_cls, d, id_list[i])

        # delete everything
        qos_mgr.remove_subscriber_qos()

        # imsi2 from rule_list1 alone wasn't removed
        imsi, rule_num, d = rule_list1[3]
        k = get_json(get_subscriber_key(imsi, rule_num, d))
        self.assertTrue(not qos_mgr._qos_store)
        self.assertTrue(not qos_mgr._subscriber_map)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            self.verifyMeterRemoveQos(mock_meter_cls, d, existing_qid)
        else:
            self.verifyTcRemoveQos(mock_traffic_cls, d, existing_qid)
Exemplo n.º 16
0
 def populate_db(qid_list, rule_list):
     qos_mgr._qos_store.clear()
     for i, t in enumerate(rule_list):
         k = get_json(get_subscriber_key(*t))
         qos_mgr._qos_store[k] = qid_list[i]
Exemplo n.º 17
0
    def _testUncleanRestart(self, mock_meter_cls, mock_traffic_cls):
        """This test verifies the case when we recover the state upon
        restart. We verify the base case of reconciling differences
        between system qos configs and qos_store configs(real code uses
        redis hash, we simply use dict). Additionally we test cases when
        system qos configs were wiped out and qos store state was wiped out
        and ensure that eventually the system and qos store state remains
        consistent"""
        loop = asyncio.new_event_loop()
        qos_mgr = QosManager(MagicMock, loop, self.config)
        qos_mgr._qos_store = {}

        def populate_db(qid_list, rule_list):
            qos_mgr._qos_store.clear()
            for i, t in enumerate(rule_list):
                k = get_json(get_subscriber_key(*t))
                qos_mgr._qos_store[k] = qid_list[i]

        MockSt = namedtuple("MockSt", "meter_id")
        dummy_meter_ev_body = [MockSt(11), MockSt(13), MockSt(2), MockSt(15)]

        def tc_read(intf):
            if intf == self.ul_intf:
                return [2, 15]
            else:
                return [13, 11]

        # prepopulate qos_store
        old_qid_list = [2, 11, 13, 20]
        old_rule_list = [("1", 0, 0), ("1", 1, 0), ("1", 2, 1), ("2", 0, 0)]
        populate_db(old_qid_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.qos_impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        qos_mgr._setupInternal()

        # run async loop once to ensure ready items are cleared
        loop._run_once()

        # verify that qos_handle 20 not found in system is purged from map
        self.assertFalse([v for _, v in qos_mgr._qos_store.items() if v == 20])

        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_called_with(MagicMock, 15)
        else:
            mock_traffic_cls.delete_class.assert_called_with(self.ul_intf, 15)

        # add a new rule to the qos_mgr and check if it is assigned right id
        imsi, rule_num, d, qos_info = "3", 0, 0, QosInfo(100000, 100000)
        qos_mgr.qos_impl.get_action_instruction = MagicMock
        qos_mgr.add_subscriber_qos(imsi, rule_num, d, qos_info)
        k = get_json(get_subscriber_key(imsi, rule_num, d))

        exp_id = 3  # since start_idx 2 is already used
        self.assertTrue(qos_mgr._qos_store[k] == exp_id)
        self.assertTrue(qos_mgr._subscriber_map[imsi][rule_num][0] == (exp_id,
                                                                       d))

        # case 2 - check with empty qos configs, qos_map gets purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        populate_db(old_qid_list, old_rule_list)

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            MockSt = namedtuple("MockSt", "meter_id")
            qos_mgr.qos_impl._fut = loop.create_future()
            qos_mgr.qos_impl.handle_meter_config_stats([])
        else:
            mock_traffic_cls.read_all_classes.side_effect = lambda _: []

        qos_mgr._setupInternal()

        # run async loop once to ensure ready items are cleared
        loop._run_once()
        self.assertTrue(not qos_mgr._qos_store)
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_not_called()
        else:
            mock_traffic_cls.delete_class.assert_not_called()

        # case 3 - check with empty qos_map, all qos configs get purged
        mock_meter_cls.reset_mock()
        mock_traffic_cls.reset_mock()
        qos_mgr._qos_store.clear()

        # mock future state
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            qos_mgr.qos_impl._fut = loop.create_future()
            qos_mgr.qos_impl.handle_meter_config_stats(dummy_meter_ev_body)
        else:
            mock_traffic_cls.read_all_classes.side_effect = tc_read

        qos_mgr._setupInternal()

        # run async loop once to ensure ready items are cleared
        loop._run_once()

        self.assertTrue(not qos_mgr._qos_store)
        # verify that unreferenced qos configs are purged from the system
        if self.config["qos"]["impl"] == QosImplType.OVS_METER:
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 2)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 15)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 13)
            mock_meter_cls.del_meter.assert_any_call(MagicMock, 11)
        else:
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 2)
            mock_traffic_cls.delete_class.assert_any_call(self.ul_intf, 15)
            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 13)
            mock_traffic_cls.delete_class.assert_any_call(self.dl_intf, 11)