openwisp-ipam icon indicating copy to clipboard operation
openwisp-ipam copied to clipboard

[model/api] Get next available subnet

Open nemesifier opened this issue 5 years ago • 2 comments

Add a way to get the next available subnet via a model method and API, similar to how we already can get the next available IP.

nemesifier avatar May 08 '20 21:05 nemesifier

Hi ! I will be working on this issue.

avii09 avatar Mar 11 '25 17:03 avii09

@nemesifier I wrote this function in /openwisp_ipam/base/models.py:

def get_next_available_subnet(self):
        target_prefix = self.subnet.prefixlen

        if self.master_subnet:
            parent_subnet = ip_network(self.master_subnet.subnet)
        else:
            user_subnet = ip_network(self.subnet)
            new_prefix = max(user_subnet.prefixlen - 4, 0)
            parent_subnet = ip_network((int(user_subnet.network_address), new_prefix))

        existing_subnets = {
            sub.subnet
            for sub in self._meta.model.objects.all()
            if ip_network(sub.subnet).subnet_of(parent_subnet)
        }

        for candidate_subnet in parent_subnet.subnets(new_prefix=target_prefix):
            if any(candidate_subnet.overlaps(existing) for existing in existing_subnets):
                continue
            try:
                self.subnet = candidate_subnet
                self._validate_multitenant_uniqueness()
                self._validate_multitenant_master_subnet()
                self._validate_multitenant_unique_child_subnet()
                self._validate_overlapping_subnets()
                self._validate_master_subnet_consistency()
                return str(candidate_subnet)
            except ValidationError:
                continue

        return None

And I call it as follows:

    def clean(self):
        if not self.subnet:
            return
        
        try:
            self._validate_multitenant_uniqueness()
            self._validate_multitenant_master_subnet()
            self._validate_multitenant_unique_child_subnet()
            self._validate_overlapping_subnets()
            self._validate_master_subnet_consistency()

        except ValidationError as e:
            # Try getting next available subnet
            next_subnet = self.get_next_available_subnet()
            if next_subnet:
                self.subnet = next_subnet
            else:
                raise e

So if 10.0.0.0/24 exists in DB.

  • It will work for 10.0.0.0/0-23 (All parent subnets)
  • It will work for exact match /24
  • It works for up to 2 children subnets /25 and /26. Because I hardcoded the parent subnet.

And currenty it directly saves the next available subnet instead of autofilling and then prompting the user like in add IP address. Which can be fixed after the core logic is decided.

I would like to discuss this further. Especially ideas on how to not hardcode the parent subnet.

pranshustuff avatar Oct 05 '25 00:10 pranshustuff