class StaticIPAllocationTests(unittest.TestCase):
    """
    Test class for the Mobilityd Static IP Allocator
    """
    RECYCLING_INTERVAL_SECONDS = 1

    @mock.patch("redis.Redis", MockRedis)
    def _new_ip_allocator(self, recycling_interval):
        """
        Creates and sets up an IPAllocator with the given recycling interval.
        """

        store = MobilityStore(get_default_client(), False, 3980)
        ip_allocator = IpAllocatorPool(store)
        ipv4_allocator = IPAllocatorStaticWrapper(
            store,
            subscriberdb_rpc_stub=MockedSubscriberDBStub(),
            ip_allocator=ip_allocator)
        ipv6_allocator = IPv6AllocatorPool(store,
                                           session_prefix_alloc_mode='RANDOM')
        self._allocator = IPAddressManager(ipv4_allocator, ipv6_allocator,
                                           store, recycling_interval)
        self._allocator.add_ip_block(self._block)

    def setUp(self):
        self._block = ipaddress.ip_network('192.168.0.0/24')
        self._new_ip_allocator(self.RECYCLING_INTERVAL_SECONDS)

    def tearDown(self):
        MockedSubscriberDBStub.clear_subs()

    def check_type(self, sid: str, type: IPType):
        ip_desc = self._allocator._store.sid_ips_map[sid]
        self.assertEqual(ip_desc.type, type)
        if type == IPType.IP_POOL:
            ip_block = self._block
        else:
            ip_block = ipaddress.ip_network(ip_desc.ip)
        self.assertEqual(ip_desc.ip_block, ip_block)

    def check_gw_info(self, vlan: Optional[int], gw_ip: str,
                      gw_mac: Optional[str]):
        gw_info_ip = self._allocator._store.dhcp_gw_info.get_gw_ip(vlan)
        self.assertEqual(gw_info_ip, gw_ip)
        gw_info_mac = self._allocator._store.dhcp_gw_info.get_gw_mac(vlan)
        self.assertEqual(gw_info_mac, gw_mac)

    def test_get_ip_for_subscriber(self):
        """ test get_ip_for_sid without any assignment """
        sid = 'IMSI11'
        with self.assertRaises(SubscriberDBStaticIPValueError):
            ip0, _ = self._allocator.alloc_ip_address(sid)

    def test_get_ip_for_subscriber_with_apn(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_different_apn(self):
        """ test get_ip_for_sid with different APN assigned ip"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_apn(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_invalid_ip(self):
        """ test invalid data from DB """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.hh'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(str(ip0), assigned_ip)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_multi_apn_but_no_match(self):
        """ test IP assignment from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="abc",
                                       ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_incomplete_sub(self):
        """ test IP assignment from subscriber without non_3gpp config"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        MockedSubscriberDBStub.add_incomplete_sub(sid=imsi)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_no_apn(self):
        """ test wildcard apn"""
        imsi = 'IMSI110'
        sid = imsi + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_dot(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma.ipv4'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_no_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip_wild))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_exact_apn_no_ip(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn=apn, ip=None)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip_wild))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_apn_with_gw(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:28"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(None, gw_ip, gw_mac)

    def test_get_ip_for_subscriber_with_only_wildcard_apn_gw(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.100"
        gw_mac = "11:22:33:11:77:81"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_with_gw_vlan(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:44"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, gw_mac)

    def test_get_ip_for_subscriber_with_apn_with_gw_invalid_ip(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1333"
        gw_mac = "11:22:33:11:77:76"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_nul_ip(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = ""
        gw_mac = "11:22:33:11:77:45"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_nul_mac(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.24'
        gw_ip = "1.2.3.55"
        gw_mac = None
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, "")

    def test_get_ip_for_subscriber_with_wildcard_apn_gw(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.100"
        gw_mac = "11:22:33:11:77:81"
        vlan = "300"

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        wildcard_assigned_ip = "20.20.20.20"
        wildcard_gw_ip = "1.2.7.7"
        wildcard_gw_mac = "11:22:33:88:77:99"
        wildcard_vlan = "400"

        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn="*",
                                          ip=wildcard_assigned_ip,
                                          gw_ip=wildcard_gw_ip,
                                          gw_mac=wildcard_gw_mac,
                                          vlan=wildcard_vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, gw_mac)
        self.check_gw_info(wildcard_vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_invalid_vlan(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:44"
        vlan = "20000"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        with self.assertRaises(InvalidVlanId):
            ip0, _ = self._allocator.alloc_ip_address(sid)

    def test_get_ip_for_subscriber_with_apn_dup_assignment(self):
        """ test duplicate static IPs """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

        apn = 'magma'
        imsi = 'IMSI999'
        sid = imsi + '.' + apn + ",ipv4"
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)
        with self.assertRaises(DuplicateIPAssignmentError):
            ip0, _ = self._allocator.alloc_ip_address(sid)

    def test_get_ip_for_2_subscribers_with_apn(self):
        """ test duplicate static IPs """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

        apn1 = 'magma'
        imsi1 = 'IMSI999'
        assigned_ip1 = '1.2.3.5'
        sid1 = imsi1 + '.' + apn1 + ",ipv4"
        MockedSubscriberDBStub.add_sub(sid=imsi1, apn=apn1, ip=assigned_ip1)

        ip1, _ = self._allocator.alloc_ip_address(sid1)
        ip1_returned = self._allocator.get_ip_for_sid(sid1)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip1, ip1_returned)
        self.assertEqual(ip1, ipaddress.ip_address(assigned_ip1))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_overlap_ip_pool(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn + ",ipv4"
        assigned_ip = '192.168.0.10'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        with self.assertRaises(DuplicateIPAssignmentError):
            ip0, _ = self._allocator.alloc_ip_address(sid)
class DhcpIPAllocEndToEndTest(unittest.TestCase):
    def setUp(self):
        self._br = "t_up_br0"

        setup_dhcp_server = SCRIPT_PATH + "scripts/setup-test-dhcp-srv.sh"
        subprocess.check_call([setup_dhcp_server, "t0"])

        setup_uplink_br = [
            SCRIPT_PATH + "scripts/setup-uplink-br.sh",
            self._br,
            "t0uplink_p0",
            "t0_dhcp1",
        ]
        subprocess.check_call(setup_uplink_br)

        store = MobilityStore(fakeredis.FakeStrictRedis())
        ipv4_allocator = IPAllocatorDHCP(
            store,
            iface='t0uplink_p0',
            retry_limit=50,
        )
        ipv6_allocator = IPv6AllocatorPool(
            store,
            session_prefix_alloc_mode='RANDOM',
        )
        self._dhcp_allocator = IPAddressManager(
            ipv4_allocator,
            ipv6_allocator,
            store,
            recycling_interval=2,
        )

    def tearDown(self):
        self._dhcp_allocator.ip_allocator.stop_dhcp_sniffer()
        BridgeTools.destroy_bridge(self._br)

    @unittest.skipIf(os.getuid(), reason="needs root user")
    def test_ip_alloc(self):
        sid1 = "IMSI02917"
        ip1, _ = self._dhcp_allocator.alloc_ip_address(sid1)
        threading.Event().wait(2)
        dhcp_gw_info = self._dhcp_allocator._store.dhcp_gw_info
        dhcp_store = self._dhcp_allocator._store.dhcp_store

        self.assertEqual(str(dhcp_gw_info.get_gw_ip()), "192.168.128.211")
        self._dhcp_allocator.release_ip_address(sid1, ip1)

        # wait for DHCP release
        threading.Event().wait(7)
        mac1 = create_mac_from_sid(sid1)
        dhcp_state1 = dhcp_store.get(mac1.as_redis_key(None))

        self.assertEqual(dhcp_state1, None)

        ip1_1, _ = self._dhcp_allocator.alloc_ip_address(sid1)
        threading.Event().wait(2)
        self.assertEqual(str(ip1), str(ip1_1))

        self._dhcp_allocator.release_ip_address(sid1, ip1_1)
        threading.Event().wait(5)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(), [])

        ip1, _ = self._dhcp_allocator.alloc_ip_address("IMSI02918")
        self.assertEqual(str(ip1), "192.168.128.146")
        self.assertEqual(
            self._dhcp_allocator.list_added_ip_blocks(),
            [ip_network('192.168.128.0/24')],
        )

        ip2, _ = self._dhcp_allocator.alloc_ip_address("IMSI029192")
        self.assertNotEqual(ip1, ip2)

        ip3, _ = self._dhcp_allocator.alloc_ip_address("IMSI0432")
        self.assertNotEqual(ip1, ip3)
        self.assertNotEqual(ip2, ip3)
        # release unallocated IP of SID
        ip_unallocated = IPDesc(
            ip=ip3,
            state=IPState.ALLOCATED,
            sid="IMSI033",
            ip_block=ip_network("1.1.1.0/24"),
            ip_type=IPType.DHCP,
        )
        self._dhcp_allocator.ip_allocator.release_ip(ip_unallocated)
        self.assertEqual(
            self._dhcp_allocator.list_added_ip_blocks(),
            [ip_network('192.168.128.0/24')],
        )

        sid4 = "IMSI54321"
        ip4, _ = self._dhcp_allocator.alloc_ip_address(sid4)
        threading.Event().wait(1)
        self._dhcp_allocator.release_ip_address(sid4, ip4)
        self.assertEqual(
            self._dhcp_allocator.list_added_ip_blocks(),
            [ip_network('192.168.128.0/24')],
        )

        # wait for DHCP release
        threading.Event().wait(7)
        mac4 = create_mac_from_sid(sid4)
        dhcp_state = dhcp_store.get(mac4.as_redis_key(None))

        self.assertEqual(dhcp_state, None)
        ip4_2, _ = self._dhcp_allocator.alloc_ip_address(sid4)
        self.assertEqual(ip4, ip4_2)

        try:
            self._dhcp_allocator.release_ip_address(sid1, ip1)
            self.assertEqual("should not", "reach here")
        except MappingNotFoundError:
            pass
Exemple #3
0
class MultiAPNIPAllocationTests(unittest.TestCase):
    """
    Test class for the Mobilityd Multi APN Allocator
    """
    RECYCLING_INTERVAL_SECONDS = 1

    def _new_ip_allocator(self, recycling_interval):
        """
        Creates and sets up an IPAllocator with the given recycling interval.
        """
        config = {
            'recycling_interval': recycling_interval,
            'persist_to_redis': False,
            'redis_port': 6379,
            'multi_apn': True,
        }
        mconfig = MobilityD(ip_allocator_type=MobilityD.IP_POOL,
                            static_ip_enabled=True)

        self._allocator = IPAddressManager(
            recycling_interval=recycling_interval,
            subscriberdb_rpc_stub=MockedSubscriberDBStub(),
            config=config,
            mconfig=mconfig)
        self._allocator.add_ip_block(self._block)

    def setUp(self):
        self._block = ipaddress.ip_network('192.168.0.0/28')
        self._new_ip_allocator(self.RECYCLING_INTERVAL_SECONDS)

    def tearDown(self):
        MockedSubscriberDBStub.clear_subs()

    def check_type(self, sid: str, type1: IPType):
        ip_desc = self._allocator.sid_ips_map[sid]
        self.assertEqual(ip_desc.type, type1)

    def check_vlan(self, sid: str, vlan: str):
        ip_desc = self._allocator.sid_ips_map[sid]
        logging.info("type ip_desc.vlan_id %s vlan %s", type(ip_desc.vlan_id),
                     type(vlan))
        self.assertEqual(ip_desc.vlan_id, vlan)

    def check_gw_info(self, vlan: Optional[int], gw_ip: str,
                      gw_mac: Optional[str]):
        gw_info_ip = self._allocator._dhcp_gw_info.get_gw_ip(vlan)
        self.assertEqual(gw_info_ip, gw_ip)
        gw_info_mac = self._allocator._dhcp_gw_info.get_gw_mac(vlan)
        self.assertEqual(gw_info_mac, gw_mac)

    def test_get_ip_vlan_for_subscriber(self):
        """ test get_ip_for_sid without any assignment """
        sid = 'IMSI11'
        ip0, _ = self._allocator.alloc_ip_address(sid)

        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_vlan_for_subscriber_with_apn(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        vlan = 132
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_different_apn(self):
        """ test get_ip_for_sid with different APN assigned ip"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        vlan = 188
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="xyz",
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)
        self.check_vlan(sid, 0)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_wildcard_apn(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        vlan = 166

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_wildcard_and_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        wild_assigned_ip = '44.2.3.11'

        vlan = 44
        vlan_wild = 66

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=wild_assigned_ip,
                                       vlan=vlan_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn=apn,
                                          ip=assigned_ip,
                                          vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_invalid_ip(self):
        """ test invalid data from DB """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.hh'
        vlan = 111

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(str(ip0), assigned_ip)
        self.check_type(sid, IPType.IP_POOL)
        self.check_vlan(sid, 0)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_multi_apn_but_no_match(self):
        """ test IP assignment from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        vlan = 31
        vlan_wild = 552

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="abc",
                                       ip=assigned_ip,
                                       vlan=vlan_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn="xyz",
                                          ip=assigned_ip,
                                          vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)
        self.check_vlan(sid, 0)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_incomplete_sub(self):
        """ test IP assignment from subscriber without non_3gpp config"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        MockedSubscriberDBStub.add_incomplete_sub(sid=imsi)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)
        self.check_vlan(sid, 0)

    def test_get_ip_vlan_for_subscriber_with_wildcard_no_apn(self):
        """ test wildcard apn"""
        imsi = 'IMSI110'
        sid = imsi
        assigned_ip = '1.2.3.4'
        vlan = 122

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_apn_dot(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma.ipv4'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        vlan = 165

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_wildcard_and_no_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'dsddf'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        wild_assigned_ip = '44.2.3.11'

        vlan = 0
        vlan_wild = 66

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=wild_assigned_ip,
                                       vlan=vlan_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn="xyz",
                                          ip=assigned_ip,
                                          vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(wild_assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan_wild)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_vlan_for_subscriber_with_wildcard_and_exact_apn_no_ip(
            self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        wild_assigned_ip = '44.2.3.11'

        vlan = 44
        vlan_wild = 66

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=wild_assigned_ip,
                                       vlan=vlan_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn=apn,
                                          ip=None,
                                          vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(wild_assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_vlan(sid, vlan_wild)
        self.check_gw_info(vlan, None, None)
Exemple #4
0
class IPAllocatorTests(unittest.TestCase):
    """
    Test class for the Mobilityd IP Allocator
    """

    RECYCLING_INTERVAL_SECONDS = 1

    def _new_ip_allocator(self, recycling_interval):
        """
        Creates and sets up an IPAllocator with the given recycling interval.
        """
        # NOTE: change below to True to run IP allocator tests locally. We
        # don't persist to Redis during normal unit tests since they are run
        # in Sandcastle.
        config = {
            'recycling_interval': recycling_interval,
            'persist_to_redis': False,
            'redis_port': 6379,
        }
        self._allocator = IPAddressManager(
            recycling_interval=recycling_interval,
            allocator_type=MobilityD.IP_POOL,
            config=config)
        self._allocator.add_ip_block(self._block)

    def setUp(self):
        #  need to allocate at least 4 bits, as 13 addresses
        #  are either preallocated or not valid for hosts
        self._block = ipaddress.ip_network('192.168.0.0/28')
        #  192.168.0.0 is not valid host IP
        #  192.168.0.1 to 192.168.0.11 are preallocated
        self._ip0 = ipaddress.ip_address('192.168.0.12')
        self._ip1 = ipaddress.ip_address('192.168.0.13')
        self._ip2 = ipaddress.ip_address('192.168.0.14')
        self._new_ip_allocator(self.RECYCLING_INTERVAL_SECONDS)

    def test_list_added_ip_blocks(self):
        """ test list assigned IP blocks """
        ip_block_list = self._allocator.list_added_ip_blocks()
        self.assertEqual(ip_block_list, [self._block])

    def test_list_empty_ip_block(self):
        """ test list empty ip block """
        ip_list = self._allocator.list_allocated_ips(self._block)
        self.assertEqual(len(ip_list), 0)

    def test_list_unknown_ip_block(self):
        """ test list unknown ip block """
        block = ipaddress.ip_network('10.0.0.0/28')
        with self.assertRaises(IPBlockNotFoundError):
            self._allocator.list_allocated_ips(block)

    def test_alloc_ip_address(self):
        """ test alloc_ip_address """
        ip0 = self._allocator.alloc_ip_address('SID0')
        self.assertTrue(ip0 in [self._ip0, self._ip1, self._ip2])
        self.assertTrue(ip0 in self._allocator.list_allocated_ips(self._block))
        self.assertEqual(self._allocator.get_sid_ip_table(), [('SID0', ip0)])

        ip1 = self._allocator.alloc_ip_address('SID1')
        self.assertTrue(ip1 in [self._ip0, self._ip1, self._ip2])
        self.assertNotEqual(ip1, ip0)
        self.assertEqual({ip0, ip1},
                         set(self._allocator.list_allocated_ips(self._block)))
        self.assertEqual(set(self._allocator.get_sid_ip_table()),
                         {('SID0', ip0), ('SID1', ip1)})

        ip2 = self._allocator.alloc_ip_address('SID2')
        self.assertTrue(ip2 in [self._ip0, self._ip1, self._ip2])
        self.assertNotEqual(ip2, ip0)
        self.assertNotEqual(ip2, ip1)
        self.assertEqual({ip0, ip1, ip2},
                         set(self._allocator.list_allocated_ips(self._block)))
        self.assertEqual(set(self._allocator.get_sid_ip_table()),
                         {('SID0', ip0), ('SID1', ip1), ('SID2', ip2)})

        # allocate from empty free set
        with self.assertRaises(NoAvailableIPError):
            self._allocator.alloc_ip_address('SID3')

    def test_release_ip_address(self):
        """ test release_ip_address """
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')
        ip2 = self._allocator.alloc_ip_address('SID2')

        # release ip
        self._allocator.release_ip_address('SID0', ip0)
        self.assertFalse(
            ip0 in self._allocator.list_allocated_ips(self._block))

        # check not recyled
        self.assertEqual(set(self._allocator.get_sid_ip_table()),
                         {('SID0', ip0), ('SID1', ip1), ('SID2', ip2)})
        with self.assertRaises(NoAvailableIPError):
            self._allocator.alloc_ip_address('SID3')

        # double release
        with self.assertRaises(IPNotInUseError):
            self._allocator.release_ip_address('SID0', ip0)

        # ip does not exist
        with self.assertRaises(MappingNotFoundError):
            non_existing_ip = ipaddress.ip_address('192.168.1.16')
            self._allocator.release_ip_address('SID0', non_existing_ip)

    def test_get_ip_for_subscriber(self):
        """ test get_ip_for_sid """
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')

        ip0_returned = self._allocator.get_ip_for_sid('SID0')
        ip1_returned = self._allocator.get_ip_for_sid('SID1')

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip1, ip1_returned)

    def test_get_ip_for_unknown_subscriber(self):
        """ Getting ip for non existent subscriber should return None """
        self.assertIsNone(self._allocator.get_ip_for_sid('SID0'))

    def test_get_sid_for_ip(self):
        """ test get_sid_for_ip """
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')

        sid0_returned = self._allocator.get_sid_for_ip(ip0)
        sid1_returned = self._allocator.get_sid_for_ip(ip1)

        self.assertEqual('SID0', sid0_returned)
        self.assertEqual('SID1', sid1_returned)

    def test_get_sid_for_unknown_ip(self):
        """ Getting sid for non allocated ip address should return None """
        self.assertIsNone(
            self._allocator.get_sid_for_ip(ipaddress.ip_address('1.1.1.1')))

    def test_allocate_allocate(self):
        """ Duplicated IP requests for the same UE returns same IP """
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID0')
        self.assertEqual(ip0, ip1)

    def test_allocated_release_allocate(self):
        """ Immediate allocation after releasing get the same IP """
        ip0 = self._allocator.alloc_ip_address('SID0')
        self._allocator.release_ip_address('SID0', ip0)
        ip2 = self._allocator.alloc_ip_address('SID0')
        self.assertEqual(ip0, ip2)

    def test_allocate_release_recycle_allocate(self):
        """ Allocation after recycling should get different IPs """
        ip0 = self._allocator.alloc_ip_address('SID0')
        self._allocator.release_ip_address('SID0', ip0)

        # Wait for auto-recycler to kick in
        time.sleep(1.2 * self.RECYCLING_INTERVAL_SECONDS)

        ip1 = self._allocator.alloc_ip_address('SID1')
        ip2 = self._allocator.alloc_ip_address('SID0')
        self.assertNotEqual(ip1, ip2)

    def test_recycle_tombstone_ip_on_timer(self):
        """ test recycle tombstone IP on interval loop """
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')
        ip2 = self._allocator.alloc_ip_address('SID2')
        self._allocator.release_ip_address('SID0', ip0)

        # Wait for auto-recycler to kick in
        time.sleep(2 * self.RECYCLING_INTERVAL_SECONDS)

        ip3 = self._allocator.alloc_ip_address('SID3')
        self.assertEqual(ip0, ip3)

        self._allocator.release_ip_address('SID1', ip1)

        # Wait for auto-recycler to kick in
        time.sleep(2 * self.RECYCLING_INTERVAL_SECONDS)

        ip4 = self._allocator.alloc_ip_address('SID4')
        self.assertEqual(ip1, ip4)

        self._allocator.release_ip_address('SID2', ip2)

        # Wait for auto-recycler to kick in
        time.sleep(2 * self.RECYCLING_INTERVAL_SECONDS)

        ip5 = self._allocator.alloc_ip_address('SID5')
        self.assertEqual(ip2, ip5)

    def test_allocate_unrecycled_IP(self):
        """ Allocation should fail before IP recycling """
        ip0 = self._allocator.alloc_ip_address('SID0')
        self._allocator.alloc_ip_address('SID1')
        self._allocator.alloc_ip_address('SID2')
        self._allocator.release_ip_address('SID0', ip0)
        with self.assertRaises(NoAvailableIPError):
            self._allocator.alloc_ip_address('SID3')

    def test_recycle_tombstone_ip(self):
        """ test recycle tombstone IP """
        self._new_ip_allocator(0)

        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')
        ip2 = self._allocator.alloc_ip_address('SID2')
        self._allocator.release_ip_address('SID0', ip0)
        ip3 = self._allocator.alloc_ip_address('SID3')
        self.assertEqual(ip0, ip3)

        self._allocator.release_ip_address('SID1', ip1)
        ip4 = self._allocator.alloc_ip_address('SID4')
        self.assertEqual(ip1, ip4)

        self._allocator.release_ip_address('SID2', ip2)
        ip5 = self._allocator.alloc_ip_address('SID5')
        self.assertEqual(ip2, ip5)

    def test_remove_unallocated_block(self):
        """ test removing the allocator for an unallocated block """
        self.assertEqual({self._block},
                         self._allocator.remove_ip_blocks(self._block))

    def test_remove_allocated_block_without_force(self):
        """ test removing the allocator for an allocated block unforcibly """
        self._allocator.alloc_ip_address('SID0')
        self.assertEqual(
            set(), self._allocator.remove_ip_blocks(self._block, force=False))

    def test_remove_unforcible_is_default_behavior(self):
        """ test that removing by default is unforcible remove """
        self._allocator.alloc_ip_address('SID0')
        self.assertEqual(set(), self._allocator.remove_ip_blocks(self._block))

    def test_remove_allocated_block_with_force(self):
        """ test removing the allocator for an allocated block forcibly """
        self._allocator.alloc_ip_address('SID0')
        self.assertEqual({self._block},
                         self._allocator.remove_ip_blocks(self._block,
                                                          force=True))

    def test_remove_after_releasing_all_addresses(self):
        """ removing after releasing all allocated addresses """
        self._new_ip_allocator(0)  # Immediately recycle

        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')

        self.assertEqual(
            set(), self._allocator.remove_ip_blocks(self._block, force=False))

        self._allocator.release_ip_address('SID0', ip0)
        self._allocator.release_ip_address('SID1', ip1)

        self.assertEqual({self._block},
                         self._allocator.remove_ip_blocks(self._block,
                                                          force=False))

    def test_remove_after_releasing_some_addresses(self):
        """ removing after releasing all allocated addresses """
        self._new_ip_allocator(0)  # Immediately recycle

        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')

        self.assertEqual(
            set(), self._allocator.remove_ip_blocks(self._block, force=False))

        self._allocator.release_ip_address('SID0', ip0)

        self.assertEqual(
            set(), self._allocator.remove_ip_blocks(self._block, force=False))

        self.assertTrue(
            ip0 not in self._allocator.list_allocated_ips(self._block))
        self.assertTrue(ip1 in self._allocator.list_allocated_ips(self._block))

    def test_reap_after_forced_remove(self):
        """
        test reaping after a forced remove and readding the reaped ips doesn't
        free them
        """
        recycling_interval_seconds = 1  # plenty of time to set up
        self._new_ip_allocator(recycling_interval_seconds)

        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')
        self._allocator.release_ip_address('SID0', ip0)
        self.assertEqual({self._block},
                         self._allocator.remove_ip_blocks(self._block,
                                                          force=True))
        self._allocator.add_ip_block(self._block)
        ip0 = self._allocator.alloc_ip_address('SID0')
        ip1 = self._allocator.alloc_ip_address('SID1')

        # Wait for auto-recycler to kick in
        time.sleep(recycling_interval_seconds)

        # Ensure that released-then-allocated address doesn't get reaped
        self.assertTrue(ip0 in self._allocator.list_allocated_ips(self._block))
        self.assertTrue(ip1 in self._allocator.list_allocated_ips(self._block))
Exemple #5
0
class DhcpIPAllocEndToEndTest(unittest.TestCase):
    def setUp(self):
        self._br = "t_up_br0"

        setup_dhcp_server = SCRIPT_PATH + "scripts/setup-test-dhcp-srv.sh"
        subprocess.check_call([setup_dhcp_server, "t0"])

        setup_uplink_br = [
            SCRIPT_PATH + "scripts/setup-uplink-br.sh", self._br,
            "t0uplink_p0", "t0_dhcp1"
        ]
        subprocess.check_call(setup_uplink_br)

        config = {
            'dhcp_iface': 't0uplink_p0',
            'retry_limit': 50,
            'persist_to_redis': False,
        }
        mconfig = MobilityD(ip_allocator_type=MobilityD.DHCP,
                            static_ip_enabled=False)

        self._dhcp_allocator = IPAddressManager(recycling_interval=2,
                                                config=config,
                                                mconfig=mconfig)

    def tearDown(self):
        self._dhcp_allocator.ip_allocator.stop_dhcp_sniffer()
        BridgeTools.destroy_bridge(self._br)

    @unittest.skipIf(os.getuid(), reason="needs root user")
    def test_ip_alloc(self):
        sid1 = "IMSI02917"
        ip1 = self._dhcp_allocator.alloc_ip_address(sid1)
        threading.Event().wait(2)
        dhcp_gw_info = self._dhcp_allocator._dhcp_gw_info
        dhcp_store = self._dhcp_allocator._dhcp_store

        self.assertEqual(str(dhcp_gw_info.getIP()), "192.168.128.211")
        self._dhcp_allocator.release_ip_address(sid1, ip1)

        # wait for DHCP release
        threading.Event().wait(7)
        mac1 = create_mac_from_sid(sid1)
        dhcp_state1 = dhcp_store.get(mac1.as_redis_key())

        self.assertEqual(dhcp_state1.state_requested, DHCPState.RELEASE)

        ip1_1 = self._dhcp_allocator.alloc_ip_address(sid1)
        threading.Event().wait(2)
        self.assertEqual(str(ip1), str(ip1_1))

        self._dhcp_allocator.release_ip_address(sid1, ip1_1)
        threading.Event().wait(5)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(), [])

        ip1 = self._dhcp_allocator.alloc_ip_address("IMSI02918")
        self.assertEqual(str(ip1), "192.168.128.146")
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        ip2 = self._dhcp_allocator.alloc_ip_address("IMSI029192")
        self.assertNotEqual(ip1, ip2)

        ip3 = self._dhcp_allocator.alloc_ip_address("IMSI0432")
        self.assertNotEqual(ip1, ip3)
        self.assertNotEqual(ip2, ip3)
        # release unallocated IP of SID
        ip_unallocated = IPDesc(ip=ip3,
                                state=IPState.ALLOCATED,
                                sid="IMSI033",
                                ip_block=ip_network("1.1.1.0/24"),
                                ip_type=IPType.DHCP)
        self._dhcp_allocator.ip_allocator.release_ip(ip_unallocated)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        sid4 = "IMSI54321"
        ip4 = self._dhcp_allocator.alloc_ip_address(sid4)
        threading.Event().wait(1)
        self._dhcp_allocator.release_ip_address(sid4, ip4)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        # wait for DHCP release
        threading.Event().wait(7)
        mac4 = create_mac_from_sid(sid4)
        dhcp_state = dhcp_store.get(mac4.as_redis_key())

        self.assertEqual(dhcp_state.state_requested, DHCPState.RELEASE)
        ip4_2 = self._dhcp_allocator.alloc_ip_address(sid4)
        self.assertEqual(ip4, ip4_2)

        try:
            self._dhcp_allocator.release_ip_address(sid1, ip1)
            self.assertEqual("should not", "reach here")
        except MappingNotFoundError:
            pass
class DhcpIPAllocEndToEndTest(unittest.TestCase):
    @mock.patch("redis.Redis", MockRedis)
    def setUp(self):
        self._br = "t_up_br0"

        subprocess.check_call(["redis-cli", "flushall"])

        setup_dhcp_server = SCRIPT_PATH + "scripts/setup-test-dhcp-srv.sh"
        subprocess.check_call([setup_dhcp_server, "t0"])

        setup_uplink_br = [
            SCRIPT_PATH + "scripts/setup-uplink-br.sh", self._br,
            "t0uplink_p0", "8A:00:00:00:00:01"
        ]
        subprocess.check_call(setup_uplink_br)

        config = {
            'dhcp_iface': 't_dhcp0',
            'retry_limit': 50,
            'allocator_type': 'dhcp',
            'persist_to_redis': False,
        }
        self._dhcp_allocator = IPAddressManager(recycling_interval=2,
                                                config=config)
        print("dhcp allocator created")

    def tearDown(self):
        self._dhcp_allocator.ip_allocator.stop_dhcp_sniffer()
        BridgeTools.destroy_bridge(self._br)

    @unittest.skipIf(os.getuid(), reason="needs root user")
    def test_ip_alloc(self):
        sid1 = "IMSI02917"
        ip1 = self._dhcp_allocator.alloc_ip_address(sid1)

        threading.Event().wait(2)
        self._dhcp_allocator.release_ip_address(sid1, ip1)
        threading.Event().wait(2)
        ip1_1 = self._dhcp_allocator.alloc_ip_address(sid1)
        threading.Event().wait(2)
        self.assertEqual(str(ip1), str(ip1_1))

        self._dhcp_allocator.release_ip_address(sid1, ip1_1)
        threading.Event().wait(5)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(), [])

        ip1 = self._dhcp_allocator.alloc_ip_address("IMSI02918")
        self.assertEqual(str(ip1), "192.168.128.146")
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        ip2 = self._dhcp_allocator.alloc_ip_address("IMSI029192")
        self.assertNotEqual(ip1, ip2)

        ip3 = self._dhcp_allocator.alloc_ip_address("IMSI0432")
        self.assertNotEqual(ip1, ip3)
        self.assertNotEqual(ip2, ip3)
        # release unallocated IP of SID
        self._dhcp_allocator.ip_allocator.release_ip("IMSI033", ip3,
                                                     ip_network("1.1.1.0/24"))
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        sid4 = "IMSI54321"
        ip4 = self._dhcp_allocator.alloc_ip_address(sid4)
        threading.Event().wait(1)
        self._dhcp_allocator.release_ip_address(sid4, ip4)
        self.assertEqual(self._dhcp_allocator.list_added_ip_blocks(),
                         [ip_network('192.168.128.0/24')])

        # wait for DHCP release
        threading.Event().wait(20)
        ip4_2 = self._dhcp_allocator.alloc_ip_address(sid4)
        self.assertEqual(ip4, ip4_2)

        try:
            self._dhcp_allocator.release_ip_address(sid1, ip1)
            self.assertEqual("should not", "reach here")
        except MappingNotFoundError:
            pass
class StaticIPAllocationTests(unittest.TestCase):
    """
    Test class for the Mobilityd Static IP Allocator
    """
    RECYCLING_INTERVAL_SECONDS = 1

    def _new_ip_allocator(self, recycling_interval):
        """
        Creates and sets up an IPAllocator with the given recycling interval.
        """
        config = {
            'recycling_interval': recycling_interval,
            'persist_to_redis': False,
            'redis_port': 6379,
        }
        mconfig = MobilityD(ip_allocator_type=MobilityD.IP_POOL,
                            static_ip_enabled=True)

        self._allocator = IPAddressManager(
            recycling_interval=recycling_interval,
            subscriberdb_rpc_stub=MockedSubscriberDBStub(),
            config=config,
            mconfig=mconfig)
        self._allocator.add_ip_block(self._block)

    def setUp(self):
        self._block = ipaddress.ip_network('192.168.0.0/28')
        self._new_ip_allocator(self.RECYCLING_INTERVAL_SECONDS)

    def tearDown(self):
        MockedSubscriberDBStub.clear_subs()

    def check_type(self, sid: str, type: IPType):
        ip_desc = self._allocator.sid_ips_map[sid]
        self.assertEqual(ip_desc.type, type)

    def test_get_ip_for_subscriber(self):
        """ test get_ip_for_sid without any assignment """
        sid = 'IMSI11'
        ip0 = self._allocator.alloc_ip_address(sid)

        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_apn(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_different_apn(self):
        """ test get_ip_for_sid with different APN assigned ip"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_apn(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn=apn, ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_invalid_ip(self):
        """ test invalid data from DB """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.hh'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(str(ip0), assigned_ip)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_multi_apn_but_no_match(self):
        """ test IP assignment from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="abc",
                                       ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_incomplete_sub(self):
        """ test IP assignment from subscriber without non_3gpp config"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        MockedSubscriberDBStub.add_incomplete_sub(sid=imsi)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_no_apn(self):
        """ test wildcard apn"""
        imsi = 'IMSI110'
        sid = imsi
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_dot(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma.ipv4'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0 = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
class StaticIPAllocationTests(unittest.TestCase):
    """
    Test class for the Mobilityd Static IP Allocator
    """
    RECYCLING_INTERVAL_SECONDS = 1

    def _new_ip_allocator(self, recycling_interval):
        """
        Creates and sets up an IPAllocator with the given recycling interval.
        """
        config = {
            'recycling_interval': recycling_interval,
            'persist_to_redis': False,
            'redis_port': 6379,
        }
        mconfig = MobilityD(ip_allocator_type=MobilityD.IP_POOL,
                            static_ip_enabled=True)

        self._allocator = IPAddressManager(
            recycling_interval=recycling_interval,
            subscriberdb_rpc_stub=MockedSubscriberDBStub(),
            config=config,
            mconfig=mconfig)
        self._allocator.add_ip_block(self._block)

    def setUp(self):
        self._block = ipaddress.ip_network('192.168.0.0/28')
        self._new_ip_allocator(self.RECYCLING_INTERVAL_SECONDS)

    def tearDown(self):
        MockedSubscriberDBStub.clear_subs()

    def check_type(self, sid: str, type: IPType):
        ip_desc = self._allocator.sid_ips_map[sid]
        self.assertEqual(ip_desc.type, type)

    def check_gw_info(self, vlan: Optional[int], gw_ip: str,
                      gw_mac: Optional[str]):
        gw_info_ip = self._allocator._dhcp_gw_info.get_gw_ip(vlan)
        self.assertEqual(gw_info_ip, gw_ip)
        gw_info_mac = self._allocator._dhcp_gw_info.get_gw_mac(vlan)
        self.assertEqual(gw_info_mac, gw_mac)

    def test_get_ip_for_subscriber(self):
        """ test get_ip_for_sid without any assignment """
        sid = 'IMSI11'
        ip0, _ = self._allocator.alloc_ip_address(sid)

        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_apn(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_different_apn(self):
        """ test get_ip_for_sid with different APN assigned ip"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_apn(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_invalid_ip(self):
        """ test invalid data from DB """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.hh'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(str(ip0), assigned_ip)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_multi_apn_but_no_match(self):
        """ test IP assignment from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="abc",
                                       ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertNotEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_incomplete_sub(self):
        """ test IP assignment from subscriber without non_3gpp config"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        MockedSubscriberDBStub.add_incomplete_sub(sid=imsi)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.check_type(sid, IPType.IP_POOL)

    def test_get_ip_for_subscriber_with_wildcard_no_apn(self):
        """ test wildcard apn"""
        imsi = 'IMSI110'
        sid = imsi
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_dot(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma.ipv4'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_no_exact_apn(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn="xyz", ip=assigned_ip)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip_wild))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_wildcard_and_exact_apn_no_ip(self):
        """ test IP assignement from multiple  APNs"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip_wild = '22.22.22.22'
        MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip_wild)
        MockedSubscriberDBStub.add_sub_ip(sid=imsi, apn=apn, ip=None)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip_wild))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_with_gw(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:28"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(None, gw_ip, gw_mac)

    def test_get_ip_for_subscriber_with_only_wildcard_apn_gw(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.100"
        gw_mac = "11:22:33:11:77:81"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn="*",
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)

    def test_get_ip_for_subscriber_with_apn_with_gw_vlan(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:44"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, gw_mac)

    def test_get_ip_for_subscriber_with_apn_with_gw_invalid_ip(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1333"
        gw_mac = "11:22:33:11:77:76"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_nul_ip(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = ""
        gw_mac = "11:22:33:11:77:45"
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_nul_mac(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.24'
        gw_ip = "1.2.3.55"
        gw_mac = None
        vlan = "200"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, "")

    def test_get_ip_for_subscriber_with_wildcard_apn_gw(self):
        """ test wildcard apn"""
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.100"
        gw_mac = "11:22:33:11:77:81"
        vlan = "300"

        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        wildcard_assigned_ip = "20.20.20.20"
        wildcard_gw_ip = "1.2.7.7"
        wildcard_gw_mac = "11:22:33:88:77:99"
        wildcard_vlan = "400"

        MockedSubscriberDBStub.add_sub_ip(sid=imsi,
                                          apn="*",
                                          ip=wildcard_assigned_ip,
                                          gw_ip=wildcard_gw_ip,
                                          gw_mac=wildcard_gw_mac,
                                          vlan=wildcard_vlan)

        ip0, _ = self._allocator.alloc_ip_address(sid)
        ip0_returned = self._allocator.get_ip_for_sid(sid)

        # check if retrieved ip is the same as the one allocated
        self.assertEqual(ip0, ip0_returned)
        self.assertEqual(ip0, ipaddress.ip_address(assigned_ip))
        self.check_type(sid, IPType.STATIC)
        self.check_gw_info(vlan, gw_ip, gw_mac)
        self.check_gw_info(wildcard_vlan, None, None)

    def test_get_ip_for_subscriber_with_apn_with_gw_invalid_vlan(self):
        """ test get_ip_for_sid with static IP """
        apn = 'magma'
        imsi = 'IMSI110'
        sid = imsi + '.' + apn
        assigned_ip = '1.2.3.4'
        gw_ip = "1.2.3.1"
        gw_mac = "11:22:33:11:77:44"
        vlan = "20000"
        MockedSubscriberDBStub.add_sub(sid=imsi,
                                       apn=apn,
                                       ip=assigned_ip,
                                       gw_ip=gw_ip,
                                       gw_mac=gw_mac,
                                       vlan=vlan)

        with self.assertRaises(InvalidVlanId):
            ip0, _ = self._allocator.alloc_ip_address(sid)