Exemplo n.º 1
0
    def alloc_ip_address(self, sid):
        """ Allocate an IP address from the free list

        Assumption: one IP per UE and one-to-one mappings between SID and IP.
        At most one IP address can be allocated for a UE at any given time.

        Args:
            sid (string): universal subscriber id

        Returns:
            ipaddress.ip_address: IP address allocated

        Raises:
            NoAvailableIPError: if run out of available IP addresses
            DuplicatedIPAllocationError: if an IP has been allocated to a UE
                with the same IMSI
        """
        with self._lock:
            # if an IP is reserved for the UE, this IP could be in the state of
            # ALLOCATED, RELEASED or REAPED.
            if sid in self._sid_ips_map:
                old_ip = self._sid_ips_map[sid][0]
                if self._test_ip_state(old_ip, IPState.ALLOCATED):
                    raise DuplicatedIPAllocationError(
                        "An IP has been allocated for this IMSI")
                elif self._test_ip_state(old_ip, IPState.RELEASED):
                    ip_desc = self._mark_ip_state(old_ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s RELEASED => ALLOCATED", sid,
                                  old_ip)
                elif self._test_ip_state(old_ip, IPState.REAPED):
                    ip_desc = self._mark_ip_state(old_ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s REAPED => ALLOCATED", sid,
                                  old_ip)
                else:
                    assert False, "Unexpected internal state"
                logging.info("Allocating the same IP %s for sid %s", old_ip,
                             sid)

                IP_ALLOCATED_TOTAL.inc()
                return old_ip

            # if an IP is not yet allocated for the UE, allocate a new IP
            if self._get_ip_count(IPState.FREE):
                ip_desc = self._pop_ip_from_state(IPState.FREE)
                ip_desc.sid = sid
                ip_desc.state = IPState.ALLOCATED
                self._add_ip_to_state(ip_desc.ip, ip_desc, IPState.ALLOCATED)
                self._sid_ips_map[sid].append(ip_desc.ip)
                assert len(self._sid_ips_map[sid]) == 1, \
                        "Only one IP per SID is supported"

                IP_ALLOCATED_TOTAL.inc()
                return ip_desc.ip
            else:
                logging.error("Run out of available IP addresses")
                raise NoAvailableIPError("No available IP addresses")
Exemplo n.º 2
0
    def alloc_ip_address(self, sid: str, version: int = IPAddress.IPV4) -> \
            Tuple[ip_address, int]:
        """ Allocate an IP address from the free list

        Assumption: one-to-one mappings between SID and IP.

        Args:
            sid (string): universal subscriber id
            version (int): version of IP to allocate

        Returns:
            ipaddress.ip_address: IP address allocated

        Raises:
            NoAvailableIPError: if run out of available IP addresses
            DuplicatedIPAllocationError: if an IP has been allocated to a UE
                with the same IMSI
        """

        with self._lock:
            # if an IP is reserved for the UE, this IP could be in the state of
            # ALLOCATED, RELEASED or REAPED.
            if sid in self._store.sid_ips_map:
                old_ip_desc = self._store.sid_ips_map[sid]
                if self.is_ip_in_state(old_ip_desc.ip, IPState.ALLOCATED):
                    # MME state went out of sync with mobilityd!
                    # Recover gracefully by allocating the same IP
                    logging.warning(
                        "Re-allocate IP %s for sid %s without "
                        "MME releasing it first ip-state-map", old_ip_desc.ip,
                        sid)

                    # TODO: enable strict checking after root causing the
                    # issue in MME
                    # raise DuplicatedIPAllocationError(
                    #     "An IP has been allocated for this IMSI")
                elif self.is_ip_in_state(old_ip_desc.ip, IPState.RELEASED):
                    ip_desc = self._store.ip_state_map.mark_ip_state(
                        old_ip_desc.ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s RELEASED => ALLOCATED", sid,
                                  old_ip_desc.ip)
                elif self.is_ip_in_state(old_ip_desc.ip, IPState.REAPED):
                    ip_desc = self._store.ip_state_map.mark_ip_state(
                        old_ip_desc.ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s REAPED => ALLOCATED", sid,
                                  old_ip_desc.ip)
                else:
                    raise AssertionError("Unexpected internal state")

                logging.info("Allocating the same IP %s for sid %s",
                             old_ip_desc.ip, sid)
                IP_ALLOCATED_TOTAL.inc()
                return old_ip_desc.ip, old_ip_desc.vlan_id

            # Now try to allocate it from underlying allocator.
            allocator = self.ip_allocator if version == IPAddress.IPV4 \
                else self.ipv6_allocator
            ip_desc = allocator.alloc_ip_address(sid, 0)
            existing_sid = self.get_sid_for_ip(ip_desc.ip)
            if existing_sid:
                error_msg = "Dup IP: {} for SID: {}, which already is " \
                            "assigned to SID: {}".format(ip_desc.ip,
                                                         sid,
                                                         existing_sid)
                logging.error(error_msg)
                raise DuplicateIPAssignmentError(error_msg)

            self._store.ip_state_map.add_ip_to_state(ip_desc.ip, ip_desc,
                                                     IPState.ALLOCATED)
            self._store.sid_ips_map[sid] = ip_desc

            logging.debug("Allocating New IP: %s", str(ip_desc))
            IP_ALLOCATED_TOTAL.inc()
            return ip_desc.ip, ip_desc.vlan_id
Exemplo n.º 3
0
    def alloc_ip_address(self, sid):
        """ Allocate an IP address from the free list

        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
            DuplicatedIPAllocationError: if an IP has been allocated to a UE
                with the same IMSI
        """
        with self._lock:
            # if an IP is reserved for the UE, this IP could be in the state of
            # ALLOCATED, RELEASED or REAPED.
            if sid in self._sid_ips_map:
                old_ip = self._sid_ips_map[sid][0]
                if self._test_ip_state(old_ip, IPState.ALLOCATED):
                    # MME state went out of sync with mobilityd!
                    # Recover gracefully by allocating the same IP
                    logging.warn("Re-allocate IP %s for sid %s without "
                                 "MME releasing it first", old_ip, sid)
                    # TODO: enable strict checking after root causing the
                    # issue in MME
                    # raise DuplicatedIPAllocationError(
                    #     "An IP has been allocated for this IMSI")
                elif self._test_ip_state(old_ip, IPState.RELEASED):
                    ip_desc = self._mark_ip_state(old_ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s RELEASED => ALLOCATED",
                                  sid, old_ip)
                elif self._test_ip_state(old_ip, IPState.REAPED):
                    ip_desc = self._mark_ip_state(old_ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s REAPED => ALLOCATED",
                                  sid, old_ip)
                else:
                    raise AssertionError("Unexpected internal state")
                logging.info("Allocating the same IP %s for sid %s",
                             old_ip, sid)

                IP_ALLOCATED_TOTAL.inc()
                return old_ip

            # if an IP is not yet allocated for the UE, allocate a new IP
            if self._get_ip_count(IPState.FREE):
                ip_desc = self._pop_ip_from_state(IPState.FREE)
                ip_desc.sid = sid
                ip_desc.state = IPState.ALLOCATED
                self._add_ip_to_state(ip_desc.ip, ip_desc, IPState.ALLOCATED)
                self._sid_ips_map[sid].append(ip_desc.ip)
                assert len(self._sid_ips_map[sid]) == 1, \
                    "Only one IP per SID is supported"

                IP_ALLOCATED_TOTAL.inc()
                return ip_desc.ip
            else:
                logging.error("Run out of available IP addresses")
                raise NoAvailableIPError("No available IP addresses")
Exemplo n.º 4
0
    def alloc_ip_address(self, sid: str) -> ip_address:
        """ Allocate an IP address from the free list

        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
            DuplicatedIPAllocationError: if an IP has been allocated to a UE
                with the same IMSI
        """

        with self._lock:
            # if an IP is reserved for the UE, this IP could be in the state of
            # ALLOCATED, RELEASED or REAPED.

            if sid in self.sid_ips_map:
                old_ip_desc = self.sid_ips_map[sid]
                if self.ip_state_map.test_ip_state(old_ip_desc.ip,
                                                   IPState.ALLOCATED):
                    # MME state went out of sync with mobilityd!
                    # Recover gracefully by allocating the same IP
                    logging.warning(
                        "Re-allocate IP %s for sid %s without "
                        "MME releasing it first ip-state-map", old_ip_desc.ip,
                        sid)

                    # TODO: enable strict checking after root causing the
                    # issue in MME
                    # raise DuplicatedIPAllocationError(
                    #     "An IP has been allocated for this IMSI")
                elif self.ip_state_map.test_ip_state(old_ip_desc.ip,
                                                     IPState.RELEASED):
                    ip_desc = self.ip_state_map.mark_ip_state(
                        old_ip_desc.ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s RELEASED => ALLOCATED", sid,
                                  old_ip_desc.ip)
                elif self.ip_state_map.test_ip_state(old_ip_desc.ip,
                                                     IPState.REAPED):
                    ip_desc = self.ip_state_map.mark_ip_state(
                        old_ip_desc.ip, IPState.ALLOCATED)
                    ip_desc.sid = sid
                    logging.debug("SID %s IP %s REAPED => ALLOCATED", sid,
                                  old_ip_desc.ip)
                else:
                    raise AssertionError("Unexpected internal state")

                logging.info("Allocating the same IP %s for sid %s",
                             old_ip_desc.ip, sid)
                IP_ALLOCATED_TOTAL.inc()
                return old_ip_desc.ip

            # Now try to allocate it from underlying allocator.
            ip_desc = self.ip_allocator.alloc_ip_address(sid)
            ip_desc.sid = sid
            ip_desc.state = IPState.ALLOCATED
            self.ip_state_map.add_ip_to_state(ip_desc.ip, ip_desc,
                                              IPState.ALLOCATED)
            self.sid_ips_map[sid] = ip_desc

            IP_ALLOCATED_TOTAL.inc()
            return ip_desc.ip