def _allocate_static_ip(self, sid: str) -> Optional[IPDesc]: """ Check if static IP allocation is enabled and then check subscriber DB for assigned static IP for the SID """ ip_addr_info = self._subscriber_client.get_subscriber_ip(sid) if ip_addr_info is None: return None logging.debug("Found static IP: sid: %s ip_addr_info: %s", sid, str(ip_addr_info)) # Validate static IP is not in any of IP pool. for ip_pool in self._store.assigned_ip_blocks: if ip_addr_info.ip in ip_pool: error_msg = "Static Ip {} Overlap with IP-POOL: {}".format( ip_addr_info.ip, ip_pool) logging.error(error_msg) raise DuplicateIPAssignmentError(error_msg) # update gw info if available. if ip_addr_info.net_info.gw_ip: self._store.dhcp_gw_info.update_ip(ip_addr_info.net_info.gw_ip, ip_addr_info.net_info.vlan) # update mac if IP is present. if ip_addr_info.net_info.gw_mac != "": self._store.dhcp_gw_info.update_mac( ip_addr_info.net_info.gw_ip, ip_addr_info.net_info.gw_mac, ip_addr_info.net_info.vlan) ip_block = ip_network(ip_addr_info.ip) self._store.assigned_ip_blocks.add(ip_block) return IPDesc(ip=ip_addr_info.ip, state=IPState.ALLOCATED, sid=sid, ip_block=ip_block, ip_type=IPType.STATIC, vlan_id=ip_addr_info.net_info.vlan)
def add_ip_block(self, ipblock: ip_network): """ Add a block of IP addresses to the free IP list IP blocks should not overlap. Args: ipblock (ipaddress.ip_network): ip network to add e.g. ipaddress.ip_network("10.0.0.0/24") Raises: OverlappedIPBlocksError: if the given IP block overlaps with existing ones """ for blk in self._assigned_ip_blocks: if ipblock.overlaps(blk): logging.error("Overlapped IP block: %s", ipblock) raise OverlappedIPBlocksError(ipblock) self._assigned_ip_blocks.add(ipblock) # TODO(oramadan) t23793559 HACK reserve the GW address for # gtp_br0 iface and test VM num_reserved_addresses = 11 for ip in ipblock.hosts(): state = IPState.RESERVED if num_reserved_addresses > 0 \ else IPState.FREE ip_desc = IPDesc(ip=ip, state=state, ip_block=ipblock, sid=None) self._ip_state_map.add_ip_to_state(ip, ip_desc, state) if num_reserved_addresses > 0: num_reserved_addresses -= 1
def alloc_ip_address(self, sid: str) -> IPDesc: """ Assumption: one-to-one mappings between SID and IP. Args: sid (string): universal subscriber id Returns: ipaddress.ip_address: IP address allocated Raises: NoAvailableIPError: if run out of available IP addresses """ mac = create_mac_from_sid(sid) LOG.debug("allocate IP for %s mac %s", sid, mac) dhcp_desc = self._dhcp_client.get_dhcp_desc(mac) LOG.debug("got IP from redis: %s", dhcp_desc) if dhcp_allocated_ip(dhcp_desc) is not True: dhcp_desc = self._alloc_ip_address_from_dhcp(mac) if dhcp_allocated_ip(dhcp_desc): ip_block = ip_network(dhcp_desc.subnet) ip_desc = IPDesc(ip_address(dhcp_desc.ip), IPState.ALLOCATED, sid, ip_block) LOG.debug("Got IP after sending DHCP requests: %s", ip_desc) self._assigned_ip_blocks.add(ip_block) return ip_desc else: raise NoAvailableIPError("No available IP addresses From DHCP")
def test_remove_after_releasing_some_addresses(self): """ removing after releasing all allocated addresses """ self._new_ip_allocator(self._block) ip0 = self._allocator.alloc_ip_address('SID0', 0).ip ip1 = self._allocator.alloc_ip_address('SID1', 0).ip ip2 = self._allocator.alloc_ip_address('SID2', 0).ip ip_desc0 = IPDesc(ip=ip0, sid='SID0') ip_desc1 = IPDesc(ip=ip1, sid='SID1') ip_desc2 = IPDesc(ip=ip2, sid='SID2') self._allocator.release_ip(ip_desc0) self._allocator.release_ip(ip_desc1) self._allocator.release_ip(ip_desc2) self.assertEqual({}, self._allocator._store.sid_session_prefix_allocated)
def _allocate_static_ip(self, sid: str) -> IPDesc: """ Check if static IP allocation is enabled and then check subscriber DB for assigned static IP for the SID """ ip_addr = self._subscriber_client.get_subscriber_ip(sid) if ip_addr is None: return None return IPDesc(ip=ip_addr, state=IPState.ALLOCATED, sid=sid, ip_block=ip_addr, ip_type=IPType.STATIC)
def test_release_ipv6_address(self): """ test release_ip_address """ ip0 = self._allocator.alloc_ip_address('SID0', 0).ip # release ip ip_desc = IPDesc(ip=ip0, sid='SID0') self._allocator.release_ip(ip_desc) # double release with self.assertRaises(IPNotInUseError): self._allocator.release_ip(ip_desc)
def alloc_ip_address(self, sid: str, vlan_id: int) -> IPDesc: """ Assumption: one-to-one mappings between SID and IP. Args: sid (string): universal subscriber id vlan_id: vlan of the APN Returns: ipaddress.ip_address: IP address allocated Raises: NoAvailableIPError: if run out of available IP addresses """ mac = create_mac_from_sid(sid) dhcp_desc = self._dhcp_client.get_dhcp_desc(mac, vlan_id) LOG.debug( "allocate IP for %s mac %s dhcp_desc %s", sid, mac, dhcp_desc, ) if not dhcp_desc or not dhcp_allocated_ip(dhcp_desc): dhcp_desc = self._alloc_ip_address_from_dhcp(mac, vlan_id) if dhcp_desc and dhcp_allocated_ip(dhcp_desc): ip_block = ip_network(dhcp_desc.subnet) ip_desc = IPDesc( ip=ip_address(dhcp_desc.ip), state=IPState.ALLOCATED, sid=sid, ip_block=ip_block, ip_type=IPType.DHCP, vlan_id=vlan_id, ) self._store.assigned_ip_blocks.add(ip_block) return ip_desc else: msg = "No available IP addresses From DHCP for SID: {} MAC {}".format( sid, mac, ) raise NoAvailableIPError(msg)
def _allocate_static_ip(self, sid: str) -> Optional[IPDesc]: """ Check if static IP allocation is enabled and then check subscriber DB for assigned static IP for the SID """ ip_addr_info = self._subscriber_client.get_subscriber_ip(sid) if ip_addr_info is None: return None logging.debug("Found static IP: sid: %s ip_addr_info: %s", sid, str(ip_addr_info)) # update gw info if available. if ip_addr_info.gw_ip: self._gw_info.update_ip(ip_addr_info.gw_ip, str(ip_addr_info.vlan)) # update mac if IP is present. if ip_addr_info.gw_mac != "": self._gw_info.update_mac(ip_addr_info.gw_ip, ip_addr_info.gw_mac, str(ip_addr_info.vlan)) ip_block = ip_network(ip_addr_info.ip) self._assigned_ip_blocks.add(ip_block) return IPDesc(ip=ip_addr_info.ip, state=IPState.ALLOCATED, sid=sid, ip_block=ip_block, ip_type=IPType.STATIC, vlan_id=ip_addr_info.vlan)
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