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. """ store = MobilityStore(get_default_client(), False, 3980) store.dhcp_gw_info.read_default_gw() ip_allocator = IpAllocatorPool(store) ipv6_allocator = IPv6AllocatorPool(store, session_prefix_alloc_mode='RANDOM') self._allocator = IPAddressManager(ip_allocator, ipv6_allocator, store, recycling_interval) 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([], 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([], 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([], 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([], self._allocator.remove_ip_blocks(self._block, force=False)) self._allocator.release_ip_address('SID0', ip0) self.assertEqual([], 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))
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.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.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(None)) 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 StaticIPAllocationTests(unittest.TestCase): """ Test class for the Mobilityd Static IP Allocator """ RECYCLING_INTERVAL_SECONDS = 0.01 def _new_ip_allocator(self, recycling_interval): """ Creates and sets up an IPAllocator with the given recycling interval. """ store = MobilityStore(fakeredis.FakeStrictRedis()) ipv4_allocator = IpAllocatorPool(store) ipv6_allocator = IPv6AllocatorPool( store, session_prefix_alloc_mode='RANDOM', ) ipv6_allocator = IPAllocatorStaticWrapper( store, subscriberdb_rpc_stub=MockedSubscriberDBStub(), ip_allocator=ipv6_allocator, ipv6=True, ) 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('2021::0/54') 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_ipv6_for_subscriber(self): """ test get_ip_for_sid without any assignment """ sid = 'IMSI11' with self.assertRaises(SubscriberDBStaticIPValueError): ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) def test_get_ipv6_for_subscriber_with_apn(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) ip0_returned = self._allocator.get_ip_for_sid(sid) # check if retrieved ip is the same as the one allocated ip0_ipaddr = ipaddress.ip_address(assigned_ip) self.assertEqual(ip0, ip0_returned) self.assertEqual(ip0, ip0_ipaddr) self.check_type(sid, IPType.STATIC) ip_block = ipaddress.ip_network(ip0_ipaddr) self.assertIn(ip_block, self._allocator._store.assigned_ip_blocks) self._allocator.release_ip_address(sid, ip0_ipaddr) time.sleep(2) self.assertNotIn(ip_block, self._allocator._store.assigned_ip_blocks) def test_get_ipv6_for_subscriber_with_different_apn(self): """ test get_ip_for_sid with different APN assigned ip""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn="xyz", ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_apn(self): """ test wildcard apn""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_and_exact_apn(self): """ test IP assignement from multiple APNs""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' assigned_ip_wild = '2022::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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_invalid_ip(self): """ test invalid data from DB """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::hh' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_multi_apn_but_no_match(self): """ test IP assignment from multiple APNs""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' assigned_ip_wild = '2022::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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_incomplete_sub(self): """ test IP assignment from subscriber without non_3gpp config""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" MockedSubscriberDBStub.add_incomplete_sub(sid=imsi) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_no_apn(self): """ test wildcard apn""" imsi = 'IMSI110' sid = imsi + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn="*", ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_dot(self): """ test get_ip_for_sid with static IP """ apn = 'magma.ipv6' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_and_no_exact_apn(self): """ test IP assignement from multiple APNs""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' assigned_ip_wild = '2022::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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_and_exact_apn_no_ip(self): """ test IP assignement from multiple APNs""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip_wild = '2022::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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1: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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_only_wildcard_apn_gw(self): """ test wildcard apn""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1:1" 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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw_vlan(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1: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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw_invalid_ip(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1:1g" 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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw_nul_ip(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' 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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw_nul_mac(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1:1" 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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_wildcard_apn_gw(self): """ test wildcard apn""" apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1:1" 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 = "2022::3:3:3" 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, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_with_gw_invalid_vlan(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' gw_ip = "2022::1:1: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, version=IPAddress.IPV6) def test_get_ipv6_for_subscriber_with_apn_dup_assignment(self): """ test duplicate static IPs """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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 + ",ipv6" MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) with self.assertRaises(DuplicateIPAssignmentError): ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) def test_get_ipv6_for_2_subscribers_with_apn(self): """ test duplicate static IPs """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2022::1' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6) 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 = '2022::1:1' sid1 = imsi1 + '.' + apn1 + ",ipv6" MockedSubscriberDBStub.add_sub(sid=imsi1, apn=apn1, ip=assigned_ip1) ip1, _ = self._allocator.alloc_ip_address(sid1, version=IPAddress.IPV6) 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_ipv6_for_subscriber_with_apn_overlap_ip_pool(self): """ test get_ip_for_sid with static IP """ apn = 'magma' imsi = 'IMSI110' sid = imsi + '.' + apn + ",ipv6" assigned_ip = '2021::2022:1' MockedSubscriberDBStub.add_sub(sid=imsi, apn=apn, ip=assigned_ip) with self.assertRaises(DuplicateIPAssignmentError): ip0, _ = self._allocator.alloc_ip_address(sid, version=IPAddress.IPV6)
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(get_default_client(), False, 3980) 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