Ejemplo n.º 1
0
    def test_ordering_subnets_find_allocc_when_counts_unequal_size_equal(self):
        models = []
        cidrs = ["0.0.0.0/31", "1.1.1.0/31", "2.2.2.0/31"]
        for cidr in cidrs:
            last = netaddr.IPNetwork(cidr).last
            models.append(self._create_models(cidr, 4, last))

        with self._fixtures(models) as net:
            self._create_ip_address("2.2.2.1", 4, "2.2.2.0/31", net["id"])
            self._create_ip_address("2.2.2.2", 4, "2.2.2.0/31", net["id"])
            self._create_ip_address("1.1.1.1", 4, "1.1.1.0/31", net["id"])

            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            self.assertEqual(subnets[0][0].cidr, "2.2.2.0/31")
            self.assertEqual(subnets[0][1], 2)
            self.assertEqual(subnets[1][0].cidr, "1.1.1.0/31")
            self.assertEqual(subnets[1][1], 1)
            self.assertEqual(subnets[2][0].cidr, "0.0.0.0/31")
            self.assertEqual(subnets[2][1], 0)

            subnets = db_api.subnet_find_ordered_by_least_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            self.assertEqual(subnets[0][0].cidr, "0.0.0.0/31")
            self.assertEqual(subnets[0][1], 0)
            self.assertEqual(subnets[1][0].cidr, "1.1.1.0/31")
            self.assertEqual(subnets[1][1], 1)
            self.assertEqual(subnets[2][0].cidr, "2.2.2.0/31")
            self.assertEqual(subnets[2][1], 2)
Ejemplo n.º 2
0
    def test_ordering_subnets_ip_version(self):
        """Order by ip_version primarily.

        Order by ip_version primarily, even when IPv4 is less full than IPv6
        subnet.
        """
        cidr4 = "0.0.0.0/30"  # 2 bits
        last4 = netaddr.IPNetwork(cidr4).last
        cidr6 = "fffc::/127"  # 1 bits
        last6 = netaddr.IPNetwork(cidr6).last
        with self._fixtures([
                self._create_models(cidr4, 4, last4),
                self._create_models(cidr6, 6, last6)
        ]) as net:
            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(subnets[0][0].ip_version, 4)
            self.assertEqual(subnets[1][0].ip_version, 6)

            subnets = db_api.subnet_find_ordered_by_least_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(subnets[0][0].ip_version, 4)
            self.assertEqual(subnets[1][0].ip_version, 6)
Ejemplo n.º 3
0
    def test_ordering_subnets_ip_version(self):
        """Order by ip_version primarily.

        Order by ip_version primarily, even when IPv4 is less full than IPv6
        subnet.
        """
        cidr4 = "0.0.0.0/30"  # 2 bits
        last4 = netaddr.IPNetwork(cidr4).last
        cidr6 = "fffc::/127"  # 1 bits
        last6 = netaddr.IPNetwork(cidr6).last
        with self._fixtures([
            self._create_models(cidr4, 4, last4),
            self._create_models(cidr6, 6, last6)
        ]) as net:
            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(subnets[0][0].ip_version, 4)
            self.assertEqual(subnets[1][0].ip_version, 6)

            subnets = db_api.subnet_find_ordered_by_least_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(subnets[0][0].ip_version, 4)
            self.assertEqual(subnets[1][0].ip_version, 6)
Ejemplo n.º 4
0
    def test_ordering_subnets_find_allocc_when_counts_unequal_size_equal(self):
        models = []
        cidrs = ["0.0.0.0/31", "1.1.1.0/31", "2.2.2.0/31"]
        for cidr in cidrs:
            last = netaddr.IPNetwork(cidr).last
            models.append(self._create_models(cidr, 4, last))

        with self._fixtures(models) as net:
            self._create_ip_address("2.2.2.1", 4, "2.2.2.0/31", net["id"])
            self._create_ip_address("2.2.2.2", 4, "2.2.2.0/31", net["id"])
            self._create_ip_address("1.1.1.1", 4, "1.1.1.0/31", net["id"])

            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            self.assertEqual(subnets[0][0].cidr, "2.2.2.0/31")
            self.assertEqual(subnets[0][1], 2)
            self.assertEqual(subnets[1][0].cidr, "1.1.1.0/31")
            self.assertEqual(subnets[1][1], 1)
            self.assertEqual(subnets[2][0].cidr, "0.0.0.0/31")
            self.assertEqual(subnets[2][1], 0)

            subnets = db_api.subnet_find_ordered_by_least_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            self.assertEqual(subnets[0][0].cidr, "0.0.0.0/31")
            self.assertEqual(subnets[0][1], 0)
            self.assertEqual(subnets[1][0].cidr, "1.1.1.0/31")
            self.assertEqual(subnets[1][1], 1)
            self.assertEqual(subnets[2][0].cidr, "2.2.2.0/31")
            self.assertEqual(subnets[2][1], 2)
Ejemplo n.º 5
0
    def select_subnet(self, context, net_id, ip_address, segment_id,
                      subnet_ids=None, **filters):
        LOG.info("Selecting subnet(s) - (Step 2 of 3) [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, ip_address=ip_address,
                                segment_id=segment_id, subnet_ids=subnet_ids,
                                ip_version=filters.get("ip_version"))))

        subnets = db_api.subnet_find_ordered_by_most_full(
            context, net_id, segment_id=segment_id, scope=db_api.ALL,
            subnet_id=subnet_ids, **filters)

        if not subnets:
            LOG.info("No subnets found given the search criteria!")

        for subnet, ips_in_subnet in subnets:
            ipnet = netaddr.IPNetwork(subnet["cidr"])
            LOG.info("Trying subnet ID: {0} - CIDR: {1}".format(
                subnet["id"], subnet["_cidr"]))
            if ip_address:
                na_ip = netaddr.IPAddress(ip_address)
                if ipnet.version == 4 and na_ip.version != 4:
                    na_ip = na_ip.ipv4()
                if na_ip not in ipnet:
                    if subnet_ids is not None:
                        LOG.info("Requested IP {0} not in subnet {1}, "
                                 "retrying".format(str(na_ip), str(ipnet)))
                        raise q_exc.IPAddressNotInSubnet(
                            ip_addr=ip_address, subnet_id=subnet["id"])
                    continue

            ip_policy = None
            if not ip_address:
                # Policies don't prevent explicit assignment, so we only
                # need to check if we're allocating a new IP
                ip_policy = subnet.get("ip_policy")

            policy_size = ip_policy["size"] if ip_policy else 0

            if ipnet.size > (ips_in_subnet + policy_size - 1):
                if not ip_address:
                    ip = subnet["next_auto_assign_ip"]
                    # If ip is somehow -1 in here don't touch it anymore
                    if ip != -1:
                        ip += 1
                    # and even then if it is outside the valid range set it to
                    # -1 to be safe
                    if ip < subnet["first_ip"] or ip > subnet["last_ip"]:
                        LOG.info("Marking subnet {0} as full".format(
                            subnet["id"]))
                        ip = -1
                    self._set_subnet_next_auto_assign_ip(context, subnet, ip)
                LOG.info("Subnet {0} - {1} looks viable, returning".format(
                    subnet["id"], subnet["_cidr"]))
                return subnet
            else:
                LOG.info("Marking subnet {0} as full".format(subnet["id"]))
                self._set_subnet_next_auto_assign_ip(context, subnet, -1)
Ejemplo n.º 6
0
 def test_get_subnet_do_not_use_not_returned(self):
     network = dict(name="public", tenant_id="fake", network_plugin="BASE")
     subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
                   cidr="0.0.0.0/24", first_ip=0, last_ip=255,
                   ip_policy=None, tenant_id="fake")
     with self._stubs(network, subnet) as (net, sub1, sub2):
         subnets = db_api.subnet_find_ordered_by_most_full(self.context,
                                                           net["id"]).all()
         self.assertEqual(len(subnets), 1)
         self.assertEqual(subnets[0][0]["id"], "1")
Ejemplo n.º 7
0
 def test_get_subnet_do_not_use_not_returned(self):
     network = dict(name="public", tenant_id="fake", network_plugin="BASE")
     subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
                   cidr="0.0.0.0/24", first_ip=0, last_ip=255,
                   ip_policy=None, tenant_id="fake")
     with self._stubs(network, subnet) as (net, sub1, sub2):
         subnets = db_api.subnet_find_ordered_by_most_full(self.context,
                                                           net["id"]).all()
         self.assertEqual(len(subnets), 1)
         self.assertEqual(subnets[0][0]["id"], "1")
Ejemplo n.º 8
0
    def test_ordering_subnets_find_allocation_counts_when_count_equal(self):
        models = []
        cidrs = ["0.0.0.0/31", "1.1.1.0/31", "2.2.2.0/31"]
        for cidr in cidrs:
            last = netaddr.IPNetwork(cidr).last
            models.append(self._create_models(cidr, 4, last))

        with self._fixtures(models) as net:
            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            for subnet in subnets:
                self.assertIn(subnet[0]["cidr"], cidrs)
Ejemplo n.º 9
0
    def test_ordering_subnets_find_allocation_counts_when_count_equal(self):
        models = []
        cidrs = ["0.0.0.0/31", "1.1.1.0/31", "2.2.2.0/31"]
        for cidr in cidrs:
            last = netaddr.IPNetwork(cidr).last
            models.append(self._create_models(cidr, 4, last))

        with self._fixtures(models) as net:
            subnets = db_api.subnet_find_ordered_by_most_full(
                self.context, net['id'], segment_id=None,
                scope=db_api.ALL).all()
            self.assertEqual(len(subnets), 3)
            for subnet in subnets:
                self.assertIn(subnet[0]["cidr"], cidrs)
Ejemplo n.º 10
0
    def select_subnet(self, context, net_id, ip_address, segment_id,
                      subnet_ids=None, **filters):
        LOG.info("Selecting subnet(s) - (Step 2 of 3) [{0}]".format(
            utils.pretty_kwargs(network_id=net_id, ip_address=ip_address,
                                segment_id=segment_id, subnet_ids=subnet_ids,
                                ip_version=filters.get("ip_version"))))

        with context.session.begin():
            subnets = db_api.subnet_find_ordered_by_most_full(
                context, net_id, segment_id=segment_id, scope=db_api.ALL,
                subnet_id=subnet_ids, **filters)

            if not subnets:
                LOG.info("No subnets found given the search criteria!")

            for subnet, ips_in_subnet in subnets:
                ipnet = netaddr.IPNetwork(subnet["cidr"])
                LOG.info("Trying subnet ID: {0} - CIDR: {1}".format(
                    subnet["id"], subnet["_cidr"]))
                if ip_address:
                    requested_ip = netaddr.IPAddress(ip_address)
                    if ipnet.version == 4 and requested_ip.version != 4:
                        requested_ip = requested_ip.ipv4()
                    if requested_ip not in ipnet:
                        if subnet_ids is not None:
                            LOG.info("Requested IP {0} not in subnet {1}, "
                                     "retrying".format(str(requested_ip),
                                                       str(ipnet)))
                            raise q_exc.IPAddressNotInSubnet(
                                ip_addr=ip_address, subnet_id=subnet["id"])
                        continue

                ip_policy = None
                if not ip_address:
                    # Policies don't prevent explicit assignment, so we only
                    # need to check if we're allocating a new IP
                    ip_policy = subnet.get("ip_policy")

                policy_size = ip_policy["size"] if ip_policy else 0

                if ipnet.size > (ips_in_subnet + policy_size - 1):
                    if not ip_address and subnet["ip_version"] == 4:
                        ip = subnet["next_auto_assign_ip"]
                        # NOTE(mdietz): When atomically updated, this probably
                        #               doesn't need the lower bounds check but
                        #               I'm not comfortable removing it yet.
                        updated = 0
                        if ip < subnet["first_ip"] or ip > subnet["last_ip"]:
                            LOG.info("Marking subnet {0} as full".format(
                                subnet["id"]))
                            updated = db_api.subnet_update_set_full(context,
                                                                    subnet)
                        else:
                            auto_inc = db_api.subnet_update_next_auto_assign_ip
                            updated = auto_inc(context, subnet)

                        if updated:
                            context.session.refresh(subnet)
                        else:
                            # This means the subnet was marked full
                            # while we were checking out policies.
                            # Fall out and go back to the outer retry
                            # loop.
                            return

                    LOG.info("Subnet {0} - {1} {2} looks viable, "
                             "returning".format(subnet["id"], subnet["_cidr"],
                                                subnet["next_auto_assign_ip"]))
                    return subnet
                else:
                    LOG.info("Marking subnet {0} as full".format(subnet["id"]))
                    db_api.subnet_update_set_full(context, subnet)