[freeside-commits] branch master updated. b79b0ebca0c15ad527de3d589cda36da63b0601e

Mitch Jackson mitch at freeside.biz
Mon Jun 25 13:06:58 PDT 2018


The branch, master has been updated
       via  b79b0ebca0c15ad527de3d589cda36da63b0601e (commit)
       via  5506c3aea73686da65f7caf2acbdca715cc6c1a5 (commit)
      from  7f751940088ed6dabcf6cbcd67993313296b21bc (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b79b0ebca0c15ad527de3d589cda36da63b0601e
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Mon Jun 25 14:09:42 2018 -0500

    RT# 30783 Improve speed of ip address auto-assignment

diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index fa0e42f62..eb84dafc3 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -250,7 +250,7 @@ sub next_free_addr {
     $selfaddr->addr,
     $selfaddr->network->addr,
     $selfaddr->broadcast->addr,
-    FS::IP_Mixin->used_addresses($self)
+    FS::IP_Mixin->used_addresses_in_block($self)
   );
 
   # just do a linear search of the block

commit 5506c3aea73686da65f7caf2acbdca715cc6c1a5
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Mon Jun 25 14:07:52 2018 -0500

    RT# 30783 Add network block enumerating utils

diff --git a/FS/FS/IP_Mixin.pm b/FS/FS/IP_Mixin.pm
index 3ec769313..2d69d9cc1 100644
--- a/FS/FS/IP_Mixin.pm
+++ b/FS/FS/IP_Mixin.pm
@@ -266,9 +266,10 @@ sub router {
 
 =item used_addresses [ BLOCK ]
 
-Returns a list of all addresses (in BLOCK, or in all blocks)
-that are in use.  If called as an instance method, excludes 
-that instance from the search.
+Returns a list of all addresses that are in use by a service.  If called as an
+instance method, excludes that instance from the search.
+
+Does not filter by block, will return ALL used addresses. ref:f197bdbaa1
 
 =cut
 
@@ -283,6 +284,27 @@ sub _used_addresses {
   die "$class->_used_addresses not implemented";
 }
 
+=item used_addresses_in_block [ FS::addr_block ]
+
+Returns a list of all addresses in use within the given L<FS::addr_block>
+
+=cut
+
+sub used_addresses_in_block {
+  my ($self, $block) = @_;
+
+  (
+    $block->ip_gateway ? $block->ip_gateway : (),
+    $block->NetAddr->broadcast->addr,
+    map { $_->_used_addresses_in_block($block, $self ) } @subclasses
+  );
+}
+
+sub _used_addresses_in_block {
+  my $class = shift;
+  die "$class->_used_addresses_in_block not implemented";
+}
+
 =item is_used ADDRESS
 
 Returns a string describing what object is using ADDRESS, or 
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index ba0f61db1..fa0e42f62 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -207,6 +207,23 @@ sub cidr {
   $self->NetAddr->cidr;
 }
 
+=item free_addrs
+
+Returns a sorted list of free addresses in the block.
+
+=cut
+
+sub free_addrs {
+  my $self = shift;
+
+  my %used_addr_map =
+    map {$_ => 1}
+    FS::IP_Mixin->used_addresses_in_block($self),
+    FS::Conf->new()->config('exclude_ip_addr');
+
+  grep { !exists $used_addr_map{$_} } map { $_->addr } $self->NetAddr->hostenum;
+}
+
 =item next_free_addr
 
 Returns a NetAddr::IP object corresponding to the first unassigned address 
@@ -416,4 +433,3 @@ now because that's the smallest block that makes any sense at all.
 =cut
 
 1;
-
diff --git a/FS/FS/svc_IP_Mixin.pm b/FS/FS/svc_IP_Mixin.pm
index c89245fe2..4266a2a5e 100644
--- a/FS/FS/svc_IP_Mixin.pm
+++ b/FS/FS/svc_IP_Mixin.pm
@@ -3,7 +3,8 @@ use base 'FS::IP_Mixin';
 
 use strict;
 use NEXT;
-use FS::Record qw(qsearchs qsearch);
+use Carp qw(croak carp);
+use FS::Record qw(qsearchs qsearch dbh);
 use FS::Conf;
 use FS::router;
 use FS::part_svc_router;
@@ -90,6 +91,9 @@ sub svc_ip_check {
 }
 
 sub _used_addresses {
+
+  # Returns all addresses in use.  Does not filter with $block. ref:f197bdbaa1
+
   my ($class, $block, $exclude) = @_;
   my $ip_field = $class->table_info->{'ip_field'}
     or return ();
@@ -107,6 +111,69 @@ sub _used_addresses {
     });
 }
 
+sub _used_addresses_in_block {
+  my ($class, $block) = @_;
+
+  croak "_used_addresses_in_block() requires an FS::addr_block parameter"
+    unless ref $block && $block->isa('FS::addr_block');
+
+  my $ip_field = $class->table_info->{'ip_field'};
+  if ( !$ip_field ) {
+    carp "_used_addresses_in_block() skipped, no ip_field";
+    return;
+  }
+
+  my $block_na = $block->NetAddr;
+
+  my $octets;
+  if ($block->ip_netmask >= 24) {
+    $octets = 3;
+  } elsif ($block->ip_netmask >= 16) {
+    $octets = 2;
+  } elsif ($block->ip_netmask >= 8) {
+    $octets = 1;
+  }
+
+  #  e.g.
+  # SELECT ip_addr
+  # FROM svc_broadband
+  # WHERE ip_addr != ''
+  #   AND ip_addr != '0e0'
+  #   AND ip_addr LIKE '10.0.2.%';
+  #
+  # For /24, /16 and /8 this approach is fast, even when svc_broadband table
+  # contains 650,000+ ip records.  For other allocations, this approach is
+  # not speedy, but usable.
+  #
+  # Note: A use case like this would could greatly benefit from a qsearch()
+  #       parameter to bypass FS::Record objects creation and just
+  #       return hashrefs from DBI.  200,000 hashrefs are many seconds faster
+  #       than 200,000 FS::Record objects
+  my %qsearch = (
+      table     => $class->table,
+      select    => $ip_field,
+      hashref   => { $ip_field => { op => '!=', value => '' }},
+      extra_sql => " AND $ip_field != '0e0' ",
+  );
+  if ( $octets ) {
+    my $block_str = join('.', (split(/\D/, $block_na->first))[0..$octets-1]);
+    $qsearch{extra_sql} .= " AND $ip_field LIKE ".dbh->quote("${block_str}.%");
+  }
+
+  if ( $block->ip_netmask % 8 ) {
+    # Some addresses returned by qsearch may be outside the network block,
+    # so each ip address is tested to be in the block before it's returned.
+    return
+      grep { $block_na->contains( NetAddr::IP->new( $_ ) ) }
+      map { $_->$ip_field }
+      qsearch( \%qsearch );
+  }
+
+  return
+    map { $_->$ip_field }
+    qsearch( \%qsearch );
+}
+
 sub _is_used {
   my ($class, $addr, $exclude) = @_;
   my $ip_field = $class->table_info->{'ip_field'}

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/IP_Mixin.pm     | 28 ++++++++++++++++++---
 FS/FS/addr_block.pm   | 20 +++++++++++++--
 FS/FS/svc_IP_Mixin.pm | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 111 insertions(+), 6 deletions(-)




More information about the freeside-commits mailing list