Пример #1
0
 def _stubs(self):
     with self.context.session.begin():
         subnet = db_api.subnet_create(self.context, cidr="192.168.0.0/24")
         db_api.ip_address_create(self.context,
                                  address=self.addr,
                                  subnet_id=subnet["id"])
     yield
Пример #2
0
 def _stubs(self):
     with self.context.session.begin():
         subnet = db_api.subnet_create(self.context,
                                       cidr="192.168.0.0/24")
         db_api.ip_address_create(self.context,
                                  address=self.addr,
                                  subnet_id=subnet["id"])
     yield
Пример #3
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(self.context, None, False, None, None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Пример #4
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(context=self.context, limit=None,
                                     page_reverse=False, sorts=['id'],
                                     marker_obj=None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Пример #5
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(context=self.context,
                                     limit=None,
                                     page_reverse=False,
                                     sorts=['id'],
                                     marker_obj=None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Пример #6
0
 def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id):
     with self.context.session.begin():
         subnet = db_api.subnet_find(self.context,
                                     None,
                                     False,
                                     None,
                                     None,
                                     cidr=subnet_cidr).all()
         ip = dict(subnet_id=subnet[0].id,
                   network_id=net_id,
                   version=ip_version,
                   address=netaddr.IPAddress(ip_address))
         db_api.ip_address_create(self.context, **ip)
Пример #7
0
    def _allocate_from_subnet(self, context, net_id, subnet,
                              port_id, reuse_after, ip_address=None, **kwargs):
        ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])

            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address:
            raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                        net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context, address=next_ip, subnet_id=subnet["id"],
                    deallocated=0, version=subnet["ip_version"],
                    network_id=net_id)
                address["deallocated"] = 0
        except Exception:
            # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None
            #               here when there's an IP conflict
            if ip_address:
                raise exceptions.IpAddressInUse(ip_address=next_ip,
                                                net_id=net_id)
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #8
0
    def _stubs(self, network, subnet, address, lock=False):
        self.ipam = quark.ipam.QuarkIpamANY()
        with self.context.session.begin():
            next_ip = subnet.pop("next_auto_assign_ip", 0)
            net_mod = db_api.network_create(self.context, **network)
            subnet["network"] = net_mod
            sub_mod = db_api.subnet_create(self.context, **subnet)

            address["network_id"] = net_mod["id"]
            address["subnet_id"] = sub_mod["id"]
            ip = db_api.ip_address_create(self.context, **address)
            address.pop("address")
            ip = db_api.ip_address_update(self.context, ip, **address)

            # NOTE(asadoughi): update after cidr constructor has been invoked
            db_api.subnet_update(self.context,
                                 sub_mod,
                                 next_auto_assign_ip=next_ip)

        if lock:
            db_api.lock_holder_create(self.context,
                                      ip,
                                      name="testlock",
                                      type="ip_address")
        yield net_mod
Пример #9
0
    def _allocate_ips_from_subnets(self, context, net_id, subnets,
                                   ip_address=None):
        new_addresses = []
        for subnet in subnets:
            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            # Creating this IP for the first time
            next_ip = None
            if ip_address:
                next_ip = ip_address
                address = db_api.ip_address_find(
                    context, network_id=net_id, ip_address=next_ip,
                    used_by_tenant_id=context.tenant_id, scope=db_api.ONE)
                if address:
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)
            else:
                next_ip = self._iterate_until_available_ip(
                    context, subnet, net_id, ip_policy_cidrs)

            context.session.add(subnet)
            address = db_api.ip_address_create(
                context, address=next_ip, subnet_id=subnet["id"],
                version=subnet["ip_version"], network_id=net_id)
            address["deallocated"] = 0
            new_addresses.append(address)
        return new_addresses
Пример #10
0
    def allocate_ip_address(self, context, net_id, port_id, reuse_after,
                            version=None, ip_address=None):
        elevated = context.elevated()
        if ip_address:
            ip_address = netaddr.IPAddress(ip_address)

        address = db_api.ip_address_find(
            elevated, network_id=net_id, reuse_after=reuse_after,
            deallocated=True, scope=db_api.ONE, ip_address=ip_address)
        if address:
            return db_api.ip_address_update(
                elevated, address, deallocated=False, deallocated_at=None)

        subnet = self._choose_available_subnet(
            elevated, net_id, ip_address=ip_address, version=version)

        # Creating this IP for the first time
        next_ip = None
        if ip_address:
            next_ip = ip_address
        else:
            address = True
            while address:
                next_ip_int = int(subnet["next_auto_assign_ip"])
                next_ip = netaddr.IPAddress(next_ip_int)
                if subnet["ip_version"] == 4:
                    next_ip = next_ip.ipv4()
                subnet["next_auto_assign_ip"] = next_ip_int + 1
                address = db_api.ip_address_find(
                    elevated,
                    network_id=net_id,
                    ip_address=next_ip,
                    tenant_id=elevated.tenant_id,
                    scope=db_api.ONE)

        # TODO(mdietz): this is a hack until we have IP policies
        ip_int = int(next_ip)
        first_ip = netaddr.IPAddress(int(subnet["first_ip"]))
        last_ip = netaddr.IPAddress(int(subnet["last_ip"]))
        if subnet["ip_version"] == 4:
            first_ip = first_ip.ipv4()
            last_ip = last_ip.ipv4()
        first_ip = int(first_ip)
        last_ip = int(last_ip)

        diff = ip_int - first_ip
        if diff < 2:
            next_ip = netaddr.IPAddress(ip_int + (2 - diff))
        if ip_int == last_ip:
            raise exceptions.IpAddressGenerationFailure(net_id=net_id)
        if next_ip not in netaddr.IPNetwork(subnet["cidr"]):
            raise exceptions.IpAddressGenerationFailure(net_id=net_id)

        address = db_api.ip_address_create(
            elevated, address=next_ip, subnet_id=subnet["id"],
            version=subnet["ip_version"], network_id=net_id)

        return address
Пример #11
0
    def test_create_lock_holder(self):
        kwargs = {"address": netaddr.IPAddress("192.168.2.1")}
        ip_address = db_api.ip_address_create(self.context, **kwargs)
        kwargs = {"type": "ip_address", "name": "because i said so"}
        lock_holder = db_api.lock_holder_create(
            self.context, ip_address, **kwargs)

        self.context.session.refresh(ip_address)
        self.assertEqual(ip_address.lock_id, lock_holder.lock_id)
Пример #12
0
    def _allocate_from_subnet(self,
                              context,
                              net_id,
                              subnet,
                              port_id,
                              reuse_after,
                              ip_address=None,
                              **kwargs):

        LOG.info("Creating a new address in subnet {0} - [{1}]".format(
            subnet["_cidr"],
            utils.pretty_kwargs(network_id=net_id,
                                subnet=subnet,
                                port_id=port_id,
                                ip_address=ip_address)))

        if subnet and subnet["ip_policy"]:
            ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set()
        else:
            ip_policy_cidrs = netaddr.IPSet([])

        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])
            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        LOG.info("Next IP is {0}".format(str(next_ip)))
        if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address:
            LOG.info("Next IP {0} violates policy".format(str(next_ip)))
            raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                        net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context,
                    address=next_ip,
                    subnet_id=subnet["id"],
                    deallocated=0,
                    version=subnet["ip_version"],
                    network_id=net_id,
                    port_id=port_id,
                    address_type=kwargs.get('address_type', ip_types.FIXED))
                address["deallocated"] = 0
                # alexm: instead of notifying billing from here we notify from
                # allocate_ip_address() when it's clear that the IP
                # allocation was successful
        except db_exception.DBDuplicateEntry:
            raise n_exc.IpAddressInUse(ip_address=next_ip, net_id=net_id)
        except db_exception.DBError:
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #13
0
    def allocate_ip_address(self, context, net_id, port_id, reuse_after,
                            version=None, ip_address=None):
        elevated = context.elevated()
        if ip_address:
            ip_address = netaddr.IPAddress(ip_address)

        new_addresses = []
        realloc_ips = self.attempt_to_reallocate_ip(context, net_id,
                                                    port_id, reuse_after,
                                                    version=None,
                                                    ip_address=None)
        if self.is_strategy_satisfied(realloc_ips):
            return realloc_ips
        new_addresses.extend(realloc_ips)
        with context.session.begin(subtransactions=True):
            subnets = self._choose_available_subnet(
                elevated, net_id, version, ip_address=ip_address,
                reallocated_ips=realloc_ips)
            for subnet in subnets:
                ip_policy_rules = models.IPPolicy.get_ip_policy_rule_set(
                    subnet)
                # Creating this IP for the first time
                next_ip = None
                if ip_address:
                    next_ip = ip_address
                    address = db_api.ip_address_find(
                        elevated, network_id=net_id, ip_address=next_ip,
                        used_by_tenant_id=elevated.tenant_id, scope=db_api.ONE)
                    if address:
                        raise exceptions.IpAddressGenerationFailure(
                            net_id=net_id)
                else:
                    next_ip = self._iterate_until_available_ip(
                        elevated, subnet, net_id, ip_policy_rules)

                context.session.add(subnet)
                address = db_api.ip_address_create(
                    elevated, address=next_ip, subnet_id=subnet["id"],
                    version=subnet["ip_version"], network_id=net_id)
                address["deallocated"] = 0
                new_addresses.append(address)

        for addr in new_addresses:
            payload = dict(used_by_tenant_id=addr["used_by_tenant_id"],
                           ip_block_id=addr["subnet_id"],
                           ip_address=addr["address_readable"],
                           device_ids=[p["device_id"] for p in addr["ports"]],
                           created_at=addr["created_at"])
            notifier_api.notify(context,
                                notifier_api.publisher_id("network"),
                                "ip_block.address.create",
                                notifier_api.CONF.default_notification_level,
                                payload)
        return new_addresses
Пример #14
0
    def _allocate_from_v6_subnet(self, context, net_id, subnet,
                                 port_id, ip_address=None, **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        if not (ip_address is None and "mac_address" in kwargs and
                kwargs["mac_address"]):
            return self._allocate_from_subnet(context, net_id, subnet,
                                              ip_address, **kwargs)
        else:
            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            for tries, ip_address in enumerate(
                generate_v6(kwargs["mac_address"]["address"], port_id,
                            subnet["cidr"])):
                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

                ip_address = netaddr.IPAddress(ip_address)

                # NOTE(mdietz): treating the IPSet as a boolean caused netaddr
                #              to attempt to enumerate the entire set!
                if (ip_policy_cidrs is not None and
                        ip_address in ip_policy_cidrs):
                    continue

                with context.session.begin():
                    address = db_api.ip_address_find(
                        context, network_id=net_id, ip_address=ip_address,
                        used_by_tenant_id=context.tenant_id, scope=db_api.ONE,
                        lock_mode=True)

                    if address:
                        return db_api.ip_address_update(
                            context, address, deallocated=False,
                            deallocated_at=None,
                            used_by_tenant_id=context.tenant_id,
                            allocated_at=timeutils.utcnow())

                with context.session.begin():
                    return db_api.ip_address_create(
                        context, address=ip_address,
                        subnet_id=subnet["id"],
                        version=subnet["ip_version"], network_id=net_id)
Пример #15
0
    def test_create_locks_address_exists(self):
        network = db_api.network_create(self.context)
        address_model = db_api.ip_address_create(
            self.context,
            address=netaddr.IPAddress("192.168.10.1"),
            network=network)
        self.context.session.flush()

        addresses = netaddr.IPSet(netaddr.IPNetwork(self.sub_cidr))
        null_routes.create_locks(self.context, [network.id], addresses)
        self.context.session.refresh(address_model)
        self.assertIsNotNone(address_model.lock_id)
Пример #16
0
    def _allocate_from_subnet(self,
                              context,
                              net_id,
                              subnet,
                              port_id,
                              reuse_after,
                              ip_address=None,
                              **kwargs):

        LOG.info("Creating a new address in subnet {0} - [{1}]".format(
            subnet["_cidr"],
            utils.pretty_kwargs(network_id=net_id,
                                subnet=subnet,
                                port_id=port_id,
                                ip_address=ip_address)))

        ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])
            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        LOG.info("Next IP is {0}".format(str(next_ip)))
        if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address:
            LOG.info("Next IP {0} violates policy".format(str(next_ip)))
            raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                        net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context,
                    address=next_ip,
                    subnet_id=subnet["id"],
                    deallocated=0,
                    version=subnet["ip_version"],
                    network_id=net_id,
                    port_id=port_id,
                    address_type=kwargs.get('address_type', ip_types.FIXED))
                address["deallocated"] = 0
        except Exception:
            # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None
            #               here when there's an IP conflict
            if ip_address:
                raise exceptions.IpAddressInUse(ip_address=next_ip,
                                                net_id=net_id)
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #17
0
    def test_delete_locks_doesnt_have_lock(self):
        network = db_api.network_create(self.context)
        address_model = db_api.ip_address_create(
            self.context,
            address=netaddr.IPAddress("192.168.10.1"),
            network=network)
        db_api.lock_holder_create(
            self.context, address_model,
            name="not-null-routes", type="ip_address")
        self.context.session.flush()

        null_routes.delete_locks(self.context, [network.id], [])
        self.context.session.refresh(address_model)
        self.assertIsNotNone(address_model.lock_id)
Пример #18
0
 def _stubs(self, network, subnet, ip_address1, ip_address2, ip_address3):
     with self.context.session.begin():
         net_mod = db_api.network_create(self.context, **network)
         subnet["network"] = net_mod
         sub_mod = db_api.subnet_create(self.context, **subnet)
         # set tenant id to "123"
         ip_address1['network_id'] = net_mod.id
         ip_address1['subnet_id'] = sub_mod.id
         self.context.tenant_id = 123
         ip_address1 = db_api.ip_address_create(self.context, **ip_address1)
         # set tenant_id=456
         ip_address2['network_id'] = net_mod.id
         ip_address2['subnet_id'] = sub_mod.id
         self.context.tenant_id = 456
         ip_address2 = db_api.ip_address_create(self.context, **ip_address2)
         # set tenant id = "123" to test the list of IPs
         ip_address3['network_id'] = net_mod.id
         ip_address3['subnet_id'] = sub_mod.id
         self.context.tenant_id = 123
         ip_address3 = db_api.ip_address_create(self.context, **ip_address3)
     yield net_mod
     with self.context.session.begin():
         db_api.subnet_delete(self.context, sub_mod)
         db_api.network_delete(self.context, net_mod)
Пример #19
0
 def _stubs(self, network, subnet, ip_address1, ip_address2, ip_address3):
     with self.context.session.begin():
         net_mod = db_api.network_create(self.context, **network)
         subnet["network"] = net_mod
         sub_mod = db_api.subnet_create(self.context, **subnet)
         # set tenant id to "123"
         ip_address1['network_id'] = net_mod.id
         ip_address1['subnet_id'] = sub_mod.id
         self.context.tenant_id = 123
         ip_address1 = db_api.ip_address_create(self.context, **ip_address1)
         # set tenant_id=456
         ip_address2['network_id'] = net_mod.id
         ip_address2['subnet_id'] = sub_mod.id
         self.context.tenant_id = 456
         ip_address2 = db_api.ip_address_create(self.context, **ip_address2)
         # set tenant id = "123" to test the list of IPs
         ip_address3['network_id'] = net_mod.id
         ip_address3['subnet_id'] = sub_mod.id
         self.context.tenant_id = 123
         ip_address3 = db_api.ip_address_create(self.context, **ip_address3)
     yield net_mod
     with self.context.session.begin():
         db_api.subnet_delete(self.context, sub_mod)
         db_api.network_delete(self.context, net_mod)
Пример #20
0
    def insert_ip_address(self, ip_address, network_db, subnet_db):
        ip_address_db = db_api.ip_address_create(
            self.context,
            address=ip_address,
            version=ip_address.version,
            subnet_id=subnet_db["id"] if subnet_db else None,
            network_id=network_db["id"])

        ip_address_db["_deallocated"] = True
        ip_address_db["deallocated_at"] = (
            timeutils.utcnow() - datetime.timedelta(seconds=self.REUSE_AFTER))
        self.context.session.add(ip_address_db)
        self.context.session.flush()

        return ip_address_db
Пример #21
0
    def _allocate_from_subnet(self, context, net_id, subnet,
                              port_id, reuse_after, ip_address=None, **kwargs):

        LOG.info("Creating a new address in subnet {0} - [{1}]".format(
            subnet["_cidr"], utils.pretty_kwargs(network_id=net_id,
                                                 subnet=subnet,
                                                 port_id=port_id,
                                                 ip_address=ip_address)))

        if subnet and subnet["ip_policy"]:
            ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set()
        else:
            ip_policy_cidrs = netaddr.IPSet([])

        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])
            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        LOG.info("Next IP is {0}".format(str(next_ip)))
        if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address:
            LOG.info("Next IP {0} violates policy".format(str(next_ip)))
            raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                        net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context, address=next_ip, subnet_id=subnet["id"],
                    deallocated=0, version=subnet["ip_version"],
                    network_id=net_id,
                    port_id=port_id,
                    address_type=kwargs.get('address_type', ip_types.FIXED))
                address["deallocated"] = 0
                # alexm: instead of notifying billing from here we notify from
                # allocate_ip_address() when it's clear that the IP
                # allocation was successful
        except db_exception.DBDuplicateEntry:
            raise n_exc.IpAddressInUse(ip_address=next_ip, net_id=net_id)
        except db_exception.DBError:
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #22
0
    def allocate_ip_address(self, context, net_id, port_id, reuse_after,
                            version=None, ip_address=None):
        elevated = context.elevated()
        if ip_address:
            ip_address = netaddr.IPAddress(ip_address)

        address = db_api.ip_address_find(
            elevated, network_id=net_id, reuse_after=reuse_after,
            deallocated=True, scope=db_api.ONE, ip_address=ip_address)
        if address:
            return db_api.ip_address_update(
                elevated, address, deallocated=False, deallocated_at=None)

        subnet = self._choose_available_subnet(
            elevated, net_id, ip_address=ip_address, version=version)
        ip_policy_rules = self.get_ip_policy_rule_set(subnet)

        # Creating this IP for the first time
        next_ip = None
        if ip_address:
            next_ip = ip_address
            address = db_api.ip_address_find(
                elevated, network_id=net_id, ip_address=next_ip,
                tenant_id=elevated.tenant_id, scope=db_api.ONE)
            if address:
                raise exceptions.IpAddressGenerationFailure(net_id=net_id)
        else:
            address = True
            while address:
                next_ip_int = int(subnet["next_auto_assign_ip"])
                next_ip = netaddr.IPAddress(next_ip_int)
                if subnet["ip_version"] == 4:
                    next_ip = next_ip.ipv4()
                subnet["next_auto_assign_ip"] = next_ip_int + 1
                if ip_policy_rules and next_ip in ip_policy_rules:
                    continue
                address = db_api.ip_address_find(
                    elevated, network_id=net_id, ip_address=next_ip,
                    tenant_id=elevated.tenant_id, scope=db_api.ONE)

        address = db_api.ip_address_create(
            elevated, address=next_ip, subnet_id=subnet["id"],
            version=subnet["ip_version"], network_id=net_id)
        address["deallocated"] = 0

        return address
Пример #23
0
    def test_find_lock_holder(self):
        kwargs = {"address": netaddr.IPAddress("192.168.2.1")}
        ip_address = db_api.ip_address_create(self.context, **kwargs)
        kwargs = {"type": "ip_address", "name": "because i said so"}
        lock_holder = db_api.lock_holder_create(
            self.context, ip_address, **kwargs)

        self.context.session.refresh(ip_address)
        self.assertEqual(ip_address.lock_id, lock_holder.lock_id)

        lock_holders = db_api.lock_holder_find(
            self.context,
            lock_id=ip_address.lock_id, name=kwargs["name"],
            scope=db_api.ALL)
        self.assertEqual(len(lock_holders), 1)
        self.assertEqual(lock_holders[0]["lock_id"], ip_address.lock_id)
        self.assertEqual(lock_holders[0]["name"], kwargs["name"])
Пример #24
0
    def _stubs(self, network, subnet, address):
        self.ipam = quark.ipam.QuarkIpamANY()
        with self.context.session.begin():
            next_ip = subnet.pop("next_auto_assign_ip", 0)
            net_mod = db_api.network_create(self.context, **network)
            subnet["network"] = net_mod
            sub_mod = db_api.subnet_create(self.context, **subnet)

            address["network_id"] = net_mod["id"]
            address["subnet_id"] = sub_mod["id"]
            ip = db_api.ip_address_create(self.context, **address)
            address.pop("address")
            db_api.ip_address_update(self.context, ip, **address)

            # NOTE(asadoughi): update after cidr constructor has been invoked
            db_api.subnet_update(self.context,
                                 sub_mod,
                                 next_auto_assign_ip=next_ip)
        yield net_mod
Пример #25
0
    def _allocate_from_subnet(self,
                              context,
                              net_id,
                              subnet,
                              port_id,
                              reuse_after,
                              ip_address=None,
                              **kwargs):
        ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])

            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        if (ip_policy_cidrs is not None and next_ip in ip_policy_cidrs):
            if not ip_address:
                raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                            net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context,
                    address=next_ip,
                    subnet_id=subnet["id"],
                    deallocated=0,
                    version=subnet["ip_version"],
                    network_id=net_id)
                address["deallocated"] = 0
        except Exception:
            # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None
            #               here when there's an IP conflict
            if ip_address:
                raise exceptions.IpAddressInUse(ip_address=next_ip,
                                                net_id=net_id)
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #26
0
    def _allocate_from_subnet(self, context, net_id, subnet,
                              port_id, reuse_after, ip_address=None, **kwargs):

        LOG.info("Creating a new address in subnet {0} - [{1}]".format(
            subnet["_cidr"], utils.pretty_kwargs(network_id=net_id,
                                                 subnet=subnet,
                                                 port_id=port_id,
                                                 ip_address=ip_address)))

        ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
        next_ip = ip_address
        if not next_ip:
            if subnet["next_auto_assign_ip"] != -1:
                next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1)
            else:
                next_ip = netaddr.IPAddress(subnet["last_ip"])
            if subnet["ip_version"] == 4:
                next_ip = next_ip.ipv4()

        LOG.info("Next IP is {0}".format(str(next_ip)))
        if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address:
            LOG.info("Next IP {0} violates policy".format(str(next_ip)))
            raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip,
                                                        net_id=net_id)
        try:
            with context.session.begin():
                address = db_api.ip_address_create(
                    context, address=next_ip, subnet_id=subnet["id"],
                    deallocated=0, version=subnet["ip_version"],
                    network_id=net_id,
                    port_id=port_id,
                    address_type=kwargs.get('address_type', ip_types.FIXED))
                address["deallocated"] = 0
        except Exception:
            # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None
            #               here when there's an IP conflict
            if ip_address:
                raise exceptions.IpAddressInUse(ip_address=next_ip,
                                                net_id=net_id)
            raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip,
                                                  net_id=net_id)

        return address
Пример #27
0
    def test_create_locks_lock_holder_exists(self):
        network = db_api.network_create(self.context)
        address_model = db_api.ip_address_create(
            self.context,
            address=netaddr.IPAddress("192.168.10.1"),
            network=network)
        db_api.lock_holder_create(
            self.context, address_model,
            name=null_routes.LOCK_NAME, type="ip_address")
        self.context.session.flush()

        addresses = netaddr.IPSet(netaddr.IPNetwork(self.sub_cidr))
        null_routes.create_locks(self.context, [network.id], addresses)

        lock_holders = db_api.lock_holder_find(
            self.context,
            lock_id=address_model.lock_id,
            name=null_routes.LOCK_NAME,
            scope=db_api.ALL)
        self.assertEqual(len(lock_holders), 1)
Пример #28
0
def _find_or_create_address(context, network_ids, address):
    address_model = db_api.ip_address_find(
        context,
        network_id=network_ids, address=_to_int(address), scope=db_api.ONE)
    if not address_model:
        query = context.session.query(models.Subnet)
        query = query.filter(models.Subnet.network_id.in_(network_ids))
        query = query.filter(models.Subnet.ip_version == address.version)
        query = query.filter(_to_int(address) >= models.Subnet.first_ip)
        query = query.filter(_to_int(address) <= models.Subnet.last_ip)
        subnet = query.one()
        address_model = db_api.ip_address_create(
            context,
            address=address,
            subnet_id=subnet["id"],
            version=subnet["ip_version"],
            network_id=subnet["network_id"],
            address_type=ip_types.FIXED)
        address_model["deallocated"] = 1
        context.session.add(address_model)
    return address_model
Пример #29
0
    def test_create_lock_holder_already_locked(self):
        kwargs = {"address": netaddr.IPAddress("192.168.2.1")}
        ip_address = db_api.ip_address_create(self.context, **kwargs)
        name = "because i said so"
        kwargs_1 = {"type": "ip_address", "name": name + "1"}
        lock_holder_1 = db_api.lock_holder_create(
            self.context, ip_address, **kwargs_1)
        self.context.session.flush()

        kwargs_2 = {"type": "ip_address", "name": name + "2"}
        self.context.session.refresh(ip_address)
        lock_holder_2 = db_api.lock_holder_create(
            self.context, ip_address, **kwargs_2)
        self.context.session.flush()

        self.context.session.refresh(ip_address)
        self.assertNotEqual(lock_holder_1.id, lock_holder_2.id)
        self.assertEqual(lock_holder_1.name, name + "1")
        self.assertEqual(lock_holder_2.name, name + "2")
        self.assertEqual(lock_holder_1.lock_id, lock_holder_2.lock_id)
        self.assertEqual(ip_address.lock_id, lock_holder_1.lock_id)
Пример #30
0
    def test_ip_address_port_find_service(self):
        net = db_api.network_create(self.context)
        port = db_api.port_create(self.context, network_id=net["id"],
                                  backend_key="", device_id="")
        ip_address = db_api.ip_address_create(
            self.context, address=netaddr.IPAddress("0.0.0.0"))
        self.context.session.flush()

        ip_address = db_api.port_associate_ip(self.context, [port], ip_address)
        ip_address.set_service_for_port(port, "foobar")
        self.context.session.flush()

        ports = ip_api.get_ports_for_ip_address(
            self.context, ip_address["id"],
            filters={"service": "not-foobar"})
        self.assertEqual(len(ports), 0)

        ports = ip_api.get_ports_for_ip_address(
            self.context, ip_address["id"],
            filters={"service": "foobar"})
        self.assertEqual(len(ports), 1)
Пример #31
0
def _find_or_create_address(context, network_ids, address):
    address_model = db_api.ip_address_find(context,
                                           network_id=network_ids,
                                           address=_to_int(address),
                                           scope=db_api.ONE)
    if not address_model:
        query = context.session.query(models.Subnet)
        query = query.filter(models.Subnet.network_id.in_(network_ids))
        query = query.filter(models.Subnet.ip_version == address.version)
        query = query.filter(_to_int(address) >= models.Subnet.first_ip)
        query = query.filter(_to_int(address) <= models.Subnet.last_ip)
        subnet = query.one()
        address_model = db_api.ip_address_create(
            context,
            address=address,
            subnet_id=subnet["id"],
            version=subnet["ip_version"],
            network_id=subnet["network_id"],
            address_type=ip_types.FIXED)
        address_model["deallocated"] = 1
        context.session.add(address_model)
    return address_model
Пример #32
0
    def allocate_ip_address(self,
                            context,
                            net_id,
                            port_id,
                            reuse_after,
                            version=None,
                            ip_address=None):
        elevated = context.elevated()
        if ip_address:
            ip_address = netaddr.IPAddress(ip_address)

        address = db_api.ip_address_find(elevated,
                                         network_id=net_id,
                                         reuse_after=reuse_after,
                                         deallocated=True,
                                         scope=db_api.ONE,
                                         ip_address=ip_address)
        if address:
            return db_api.ip_address_update(elevated,
                                            address,
                                            deallocated=False,
                                            deallocated_at=None)

        subnet = self._choose_available_subnet(elevated,
                                               net_id,
                                               ip_address=ip_address,
                                               version=version)
        ip_policy_rules = self.get_ip_policy_rule_set(subnet)

        # Creating this IP for the first time
        next_ip = None
        if ip_address:
            next_ip = ip_address
            address = db_api.ip_address_find(elevated,
                                             network_id=net_id,
                                             ip_address=next_ip,
                                             tenant_id=elevated.tenant_id,
                                             scope=db_api.ONE)
            if address:
                raise exceptions.IpAddressGenerationFailure(net_id=net_id)
        else:
            address = True
            while address:
                next_ip_int = int(subnet["next_auto_assign_ip"])
                next_ip = netaddr.IPAddress(next_ip_int)
                if subnet["ip_version"] == 4:
                    next_ip = next_ip.ipv4()
                subnet["next_auto_assign_ip"] = next_ip_int + 1
                if ip_policy_rules and next_ip in ip_policy_rules:
                    continue
                address = db_api.ip_address_find(elevated,
                                                 network_id=net_id,
                                                 ip_address=next_ip,
                                                 tenant_id=elevated.tenant_id,
                                                 scope=db_api.ONE)

        address = db_api.ip_address_create(elevated,
                                           address=next_ip,
                                           subnet_id=subnet["id"],
                                           version=subnet["ip_version"],
                                           network_id=net_id)
        address["deallocated"] = 0

        return address
Пример #33
0
    def _allocate_from_v6_subnet(self,
                                 context,
                                 net_id,
                                 subnet,
                                 port_id,
                                 reuse_after,
                                 ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        if not (ip_address is None and "mac_address" in kwargs
                and kwargs["mac_address"]):
            return self._allocate_from_subnet(context, net_id, subnet,
                                              reuse_after, ip_address,
                                              **kwargs)
        else:
            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            for tries, ip_address in enumerate(
                    generate_v6(kwargs["mac_address"]["address"], port_id,
                                subnet["cidr"])):

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    raise exceptions.IpAddressGenerationFailure(net_id=net_id)

                ip_address = netaddr.IPAddress(ip_address)

                # NOTE(mdietz): treating the IPSet as a boolean caused netaddr
                #               to attempt to enumerate the entire set!
                if (ip_policy_cidrs is not None
                        and ip_address in ip_policy_cidrs):
                    continue

                # TODO(mdietz): replace this with a compare-and-swap loop
                with context.session.begin():
                    address = db_api.ip_address_find(context,
                                                     network_id=net_id,
                                                     ip_address=ip_address,
                                                     scope=db_api.ONE,
                                                     reuse_after=reuse_after,
                                                     deallocated=True,
                                                     subnet_id=subnet["id"],
                                                     lock_mode=True)

                    if address:
                        return db_api.ip_address_update(
                            context,
                            address,
                            deallocated=False,
                            deallocated_at=None,
                            used_by_tenant_id=context.tenant_id,
                            allocated_at=timeutils.utcnow())

                # This triggers when the IP is allocated to another tenant,
                # either because we missed it due to our filters above, or
                # in an extremely unlikely race between the find and here.
                try:
                    with context.session.begin():
                        return db_api.ip_address_create(
                            context,
                            address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"],
                            network_id=net_id)
                except db_exception.DBDuplicateEntry:
                    LOG.debug(
                        "Duplicate entry found when inserting subnet_id"
                        " %s ip_address %s", subnet["id"], ip_address)
Пример #34
0
    def _allocate_from_v6_subnet(self, context, net_id, subnet,
                                 port_id, reuse_after, ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        LOG.info("Attempting to allocate a v6 address - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, subnet=subnet,
                                port_id=port_id, ip_address=ip_address)))

        if ip_address:
            LOG.info("IP %s explicitly requested, deferring to standard "
                     "allocation" % ip_address)
            return self._allocate_from_subnet(context, net_id=net_id,
                                              subnet=subnet, port_id=port_id,
                                              reuse_after=reuse_after,
                                              ip_address=ip_address, **kwargs)
        else:
            mac = kwargs.get("mac_address")
            if mac:
                mac = kwargs["mac_address"].get("address")

            if subnet and subnet["ip_policy"]:
                ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set()
            else:
                ip_policy_cidrs = netaddr.IPSet([])

            for tries, ip_address in enumerate(
                    generate_v6(mac, port_id, subnet["cidr"])):

                LOG.info("Attempt {0} of {1}".format(
                    tries + 1, CONF.QUARK.v6_allocation_attempts))

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    LOG.info("Exceeded v6 allocation attempts, bailing")
                    raise ip_address_failure(net_id)

                ip_address = netaddr.IPAddress(ip_address).ipv6()
                LOG.info("Generated a new v6 address {0}".format(
                    str(ip_address)))

                if (ip_policy_cidrs is not None and
                        ip_address in ip_policy_cidrs):
                    LOG.info("Address {0} excluded by policy".format(
                        str(ip_address)))
                    continue

                try:
                    with context.session.begin():
                        address = db_api.ip_address_create(
                            context, address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"], network_id=net_id,
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))
                        return address
                except db_exception.DBDuplicateEntry:
                    # This shouldn't ever happen, since we hold a unique MAC
                    # address from the previous IPAM step.
                    LOG.info("{0} exists but was already "
                             "allocated".format(str(ip_address)))
                    LOG.debug("Duplicate entry found when inserting subnet_id"
                              " %s ip_address %s", subnet["id"], ip_address)
Пример #35
0
    def _allocate_from_v6_subnet(self, context, net_id, subnet,
                                 port_id, reuse_after, ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        LOG.info("Attempting to allocate a v6 address - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, subnet=subnet,
                                port_id=port_id, ip_address=ip_address)))

        if ip_address:
            LOG.info("IP %s explicitly requested, deferring to standard "
                     "allocation" % ip_address)
            return self._allocate_from_subnet(context, net_id=net_id,
                                              subnet=subnet, port_id=port_id,
                                              reuse_after=reuse_after,
                                              ip_address=ip_address, **kwargs)
        else:
            mac = kwargs.get("mac_address")
            if mac:
                mac = kwargs["mac_address"].get("address")

            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            for tries, ip_address in enumerate(
                    generate_v6(mac, port_id, subnet["cidr"])):

                LOG.info("Attempt {0} of {1}".format(
                    tries + 1, CONF.QUARK.v6_allocation_attempts))

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    LOG.info("Exceeded v6 allocation attempts, bailing")
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

                ip_address = netaddr.IPAddress(ip_address).ipv6()
                LOG.info("Generated a new v6 address {0}".format(
                    str(ip_address)))

                # NOTE(mdietz): treating the IPSet as a boolean caused netaddr
                #               to attempt to enumerate the entire set!
                if (ip_policy_cidrs is not None and
                        ip_address in ip_policy_cidrs):
                    LOG.info("Address {0} excluded by policy".format(
                        str(ip_address)))
                    continue

                # TODO(mdietz): replace this with a compare-and-swap loop
                with context.session.begin():
                    address = db_api.ip_address_find(
                        context, network_id=net_id, ip_address=ip_address,
                        scope=db_api.ONE, reuse_after=reuse_after,
                        deallocated=True, subnet_id=subnet["id"],
                        lock_mode=True)

                    if address:
                        LOG.info("Address {0} exists, claiming".format(
                            str(ip_address)))
                        return db_api.ip_address_update(
                            context, address, deallocated=False,
                            deallocated_at=None,
                            used_by_tenant_id=context.tenant_id,
                            allocated_at=timeutils.utcnow(),
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))

                # This triggers when the IP is allocated to another tenant,
                # either because we missed it due to our filters above, or
                # in an extremely unlikely race between the find and here.
                try:
                    with context.session.begin():
                        return db_api.ip_address_create(
                            context, address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"], network_id=net_id,
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))
                except db_exception.DBDuplicateEntry:
                    LOG.info("{0} exists but was already "
                             "allocated".format(str(ip_address)))
                    LOG.debug("Duplicate entry found when inserting subnet_id"
                              " %s ip_address %s", subnet["id"], ip_address)
Пример #36
0
 def setUp(self):
     super(QuarkIPAddressFind, self).setUp()
     self.address = netaddr.IPAddress("0.0.0.1")
     db_api.ip_address_create(self.context, address=self.address)
     self.context.session.flush()
Пример #37
0
 def _stubs(self):
     with self.context.session.begin():
         db_api.ip_address_create(self.context,
                                  address=self.addr)
     yield
Пример #38
0
    def _allocate_from_v6_subnet(self, context, net_id, subnet,
                                 port_id, reuse_after, ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        LOG.info("Attempting to allocate a v6 address - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, subnet=subnet,
                                port_id=port_id, ip_address=ip_address)))

        if ip_address:
            LOG.info("IP %s explicitly requested, deferring to standard "
                     "allocation" % ip_address)
            return self._allocate_from_subnet(context, net_id=net_id,
                                              subnet=subnet, port_id=port_id,
                                              reuse_after=reuse_after,
                                              ip_address=ip_address, **kwargs)
        else:
            mac = kwargs.get("mac_address")
            if mac:
                mac = kwargs["mac_address"].get("address")

            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            for tries, ip_address in enumerate(
                    generate_v6(mac, port_id, subnet["cidr"])):

                LOG.info("Attempt {0} of {1}".format(
                    tries + 1, CONF.QUARK.v6_allocation_attempts))

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    LOG.info("Exceeded v6 allocation attempts, bailing")
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

                ip_address = netaddr.IPAddress(ip_address).ipv6()
                LOG.info("Generated a new v6 address {0}".format(
                    str(ip_address)))

                # NOTE(mdietz): treating the IPSet as a boolean caused netaddr
                #               to attempt to enumerate the entire set!
                if (ip_policy_cidrs is not None and
                        ip_address in ip_policy_cidrs):
                    LOG.info("Address {0} excluded by policy".format(
                        str(ip_address)))
                    continue

                # TODO(mdietz): replace this with a compare-and-swap loop
                with context.session.begin():
                    address = db_api.ip_address_find(
                        context, network_id=net_id, ip_address=ip_address,
                        scope=db_api.ONE, reuse_after=reuse_after,
                        deallocated=True, subnet_id=subnet["id"],
                        lock_mode=True)

                    if address:
                        LOG.info("Address {0} exists, claiming".format(
                            str(ip_address)))
                        return db_api.ip_address_update(
                            context, address, deallocated=False,
                            deallocated_at=None,
                            used_by_tenant_id=context.tenant_id,
                            allocated_at=timeutils.utcnow(),
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))

                # This triggers when the IP is allocated to another tenant,
                # either because we missed it due to our filters above, or
                # in an extremely unlikely race between the find and here.
                try:
                    with context.session.begin():
                        return db_api.ip_address_create(
                            context, address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"], network_id=net_id,
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))
                except db_exception.DBDuplicateEntry:
                    LOG.info("{0} exists but was already "
                             "allocated".format(str(ip_address)))
                    LOG.debug("Duplicate entry found when inserting subnet_id"
                              " %s ip_address %s", subnet["id"], ip_address)
Пример #39
0
    def _allocate_from_v6_subnet(self, context, net_id, subnet,
                                 port_id, reuse_after, ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        if (ip_address or "mac_address" not in kwargs or
                not kwargs["mac_address"]):
            return self._allocate_from_subnet(context, net_id=net_id,
                                              subnet=subnet, port_id=port_id,
                                              reuse_after=reuse_after,
                                              ip_address=ip_address, **kwargs)
        else:
            ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet)
            for tries, ip_address in enumerate(
                generate_v6(kwargs["mac_address"]["address"], port_id,
                            subnet["cidr"])):

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    raise exceptions.IpAddressGenerationFailure(
                        net_id=net_id)

                ip_address = netaddr.IPAddress(ip_address)

                # NOTE(mdietz): treating the IPSet as a boolean caused netaddr
                #               to attempt to enumerate the entire set!
                if (ip_policy_cidrs is not None and
                        ip_address in ip_policy_cidrs):
                    continue

                # TODO(mdietz): replace this with a compare-and-swap loop
                with context.session.begin():
                    address = db_api.ip_address_find(
                        context, network_id=net_id, ip_address=ip_address,
                        scope=db_api.ONE, reuse_after=reuse_after,
                        deallocated=True, subnet_id=subnet["id"],
                        lock_mode=True)

                    if address:
                        return db_api.ip_address_update(
                            context, address, deallocated=False,
                            deallocated_at=None,
                            used_by_tenant_id=context.tenant_id,
                            allocated_at=timeutils.utcnow())

                # This triggers when the IP is allocated to another tenant,
                # either because we missed it due to our filters above, or
                # in an extremely unlikely race between the find and here.
                try:
                    with context.session.begin():
                        return db_api.ip_address_create(
                            context, address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"], network_id=net_id)
                except db_exception.DBDuplicateEntry:
                    LOG.debug("Duplicate entry found when inserting subnet_id"
                              " %s ip_address %s", subnet["id"], ip_address)
Пример #40
0
    def _allocate_from_v6_subnet(self,
                                 context,
                                 net_id,
                                 subnet,
                                 port_id,
                                 reuse_after,
                                 ip_address=None,
                                 **kwargs):
        """This attempts to allocate v6 addresses as per RFC2462 and RFC3041.

        To accomodate this, we effectively treat all v6 assignment as a
        first time allocation utilizing the MAC address of the VIF. Because
        we recycle MACs, we will eventually attempt to recreate a previously
        generated v6 address. Instead of failing, we've opted to handle
        reallocating that address in this method.

        This should provide a performance boost over attempting to check
        each and every subnet in the existing reallocate logic, as we'd
        have to iterate over each and every subnet returned
        """

        LOG.info("Attempting to allocate a v6 address - [{0}]".format(
            utils.pretty_kwargs(network_id=net_id,
                                subnet=subnet,
                                port_id=port_id,
                                ip_address=ip_address)))

        if ip_address:
            LOG.info("IP %s explicitly requested, deferring to standard "
                     "allocation" % ip_address)
            return self._allocate_from_subnet(context,
                                              net_id=net_id,
                                              subnet=subnet,
                                              port_id=port_id,
                                              reuse_after=reuse_after,
                                              ip_address=ip_address,
                                              **kwargs)
        else:
            mac = kwargs.get("mac_address")
            if mac:
                mac = kwargs["mac_address"].get("address")

            if subnet and subnet["ip_policy"]:
                ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set()
            else:
                ip_policy_cidrs = netaddr.IPSet([])

            for tries, ip_address in enumerate(
                    generate_v6(mac, port_id, subnet["cidr"])):

                LOG.info("Attempt {0} of {1}".format(
                    tries + 1, CONF.QUARK.v6_allocation_attempts))

                if tries > CONF.QUARK.v6_allocation_attempts - 1:
                    LOG.info("Exceeded v6 allocation attempts, bailing")
                    raise ip_address_failure(net_id)

                ip_address = netaddr.IPAddress(ip_address).ipv6()
                LOG.info("Generated a new v6 address {0}".format(
                    str(ip_address)))

                if (ip_policy_cidrs is not None
                        and ip_address in ip_policy_cidrs):
                    LOG.info("Address {0} excluded by policy".format(
                        str(ip_address)))
                    continue

                try:
                    with context.session.begin():
                        address = db_api.ip_address_create(
                            context,
                            address=ip_address,
                            subnet_id=subnet["id"],
                            version=subnet["ip_version"],
                            network_id=net_id,
                            address_type=kwargs.get('address_type',
                                                    ip_types.FIXED))
                        # alexm: need to notify from here because this code
                        # does not go through the _allocate_from_subnet() path.
                        notify(context, 'ip.add', address)
                        return address
                except db_exception.DBDuplicateEntry:
                    # This shouldn't ever happen, since we hold a unique MAC
                    # address from the previous IPAM step.
                    LOG.info("{0} exists but was already "
                             "allocated".format(str(ip_address)))
                    LOG.debug(
                        "Duplicate entry found when inserting subnet_id"
                        " %s ip_address %s", subnet["id"], ip_address)