Changeset 774


Ignore:
Timestamp:
09/09/15 18:05:19 (9 years ago)
Author:
Kris Deugau
Message:

/trunk

Rearrange, fiddle, and rewrite-ish splitBlock() due to an edge case
with free blocks that wouldn't go away with smaller changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cgi-bin/IPDB.pm

    r773 r774  
    18981898  my $dbh = shift;
    18991899  my %args = @_;
    1900 #  my $id = shift;
    1901 #  my $basetype = shift;
    1902 #  my $newmask = shift;
    19031900
    19041901##fixme:  set errstr on errors so caller can suitably clue-by-four the user
     
    19591956    my $allocsth = $dbh->prepare("INSERT INTO allocations (cidr, $fields_sql)".
    19601957        " VALUES (?".',?'x(scalar(@fieldlist)).")");
     1958    my $allocsth2 = $dbh->prepare(qq(
     1959        INSERT INTO allocations (cidr, $fields_sql)
     1960                SELECT ? AS cidr, $fields_sql
     1961                FROM allocations
     1962                WHERE id = ?
     1963        ) );
    19611964    my $nbsth = $dbh->prepare("DELETE FROM poolips WHERE parent_id = ? AND ip = ?");
    19621965    my $upd_psth = $dbh->prepare("UPDATE allocations SET parent_id = ? WHERE parent_id = ? AND cidr <<= ?");
     
    19671970    my $pool_msth = $dbh->prepare("UPDATE poolips SET master_id = ? WHERE master_id = ? AND ip <<= ?");
    19681971
    1969     # set up update of existing block
    1970     $dbh->do("UPDATE allocations SET cidr = ? WHERE id = ?", undef, ("$newblocks[0]", $args{id}) );
    1971 
    1972     # axe the new bcast IP from the smaller pool at the "base" block, if it's a "normal" pool
    1973     if ($binfo->{type} =~ /.d/) {
    1974       $newblocks[0]--;
    1975       $nbsth->execute($args{id}, $newblocks[0]->addr);
    1976     }
    1977 
    1978     # Holder for freeblocks-to-delete.  Should be impossible to have more than one...
    1979     my %fbdel;
    1980 
    1981     # Loop over the new blocks that are not the base block
    1982     for (my $i = 1; $i <= $#newblocks; $i++) {
    1983       # add the new allocation
    1984       $allocsth->execute($newblocks[$i], @vals);
    1985       # fetch the ID of the entry we just added...
    1986       $idsth->execute();
    1987       my ($nid) = $idsth->fetchrow_array();
    1988       # ... so we can pass back the list of blocks and IDs...
    1989       push @ret, {nid => $nid, nblock => "$newblocks[$i]"};
    1990       # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool
    1991       if ($binfo->{type} =~ /.d/) {
    1992         # net
    1993         $nbsth->execute($args{id}, $newblocks[$i]->addr);
    1994         $newblocks[$i]++;
    1995         # gw
    1996         $nbsth->execute($args{id}, $newblocks[$i]->addr);
    1997         $newblocks[$i]--;
    1998         $newblocks[$i]--;
    1999         # bcast
    2000         $nbsth->execute($args{id}, $newblocks[$i]->addr);
    2001         $newblocks[$i]++;
    2002       } # $binfo->{type} =~ /.d/
    2003 
    2004       # Check for free blocks larger than the new mask length, and split those as needed.
    2005       if ($binfo->{type} =~ /.[cm]/) {
    2006         # get a "list" of freeblocks bigger than the allocation in the parent.  there's only one, right?
    2007         my $fblist = $dbh->selectall_arrayref("SELECT id FROM freeblocks WHERE cidr >> ? AND parent_id = ? ",
    2008             {Slice=>{}}, $newblocks[$i], $args{id});
    2009         if (@$fblist) {
    2010           # create a new freeblock for the new block we created earlier
    2011           $dbh->do(q{
    2012             INSERT INTO freeblocks (cidr, parent_id, master_id, city, routed,vrf)
    2013                 SELECT ? AS cidr, ? AS parent_id, master_id, city, routed, vrf FROM freeblocks
    2014                 WHERE id = ?
    2015             }, undef, ($newblocks[$i], $nid, $fblist->[0]->{id}) );
    2016           $fbdel{$fblist->[0]->{id}}++;
     1972    my @clist;
     1973    _getChildren($dbh, $args{id}, $binfo->{master_id}, \@clist, $block);
     1974
     1975    my @processlist;
     1976    push @processlist, { id => $args{id}, cidr => $block, mask => $block->masklen, type => $binfo->{type} };
     1977    foreach (@clist) {
     1978      $_->{cidr} = new NetAddr::IP $_->{cidr};
     1979      if ($_->{cidr}->masklen < $args{newmask}) {
     1980        $_->{mask} = $_->{cidr}->masklen;
     1981        push @processlist, $_;
     1982      }
     1983    }
     1984
     1985    @processlist = sort { $b->{cidr}->masklen <=> $a->{cidr}->masklen } @processlist;
     1986
     1987    foreach my $pr (@processlist) {
     1988      my @nbset = $pr->{cidr}->split($args{newmask});
     1989
     1990      # set up update of existing block
     1991      $dbh->do("UPDATE allocations SET cidr = ? WHERE id = ?", undef, ("$nbset[0]", $pr->{id}) );
     1992
     1993      # axe the new bcast IP from the smaller pool at the "base" block, if it's a "normal" pool
     1994      if ($pr->{type} =~ /.d/) {
     1995        $nbset[0]--;
     1996        $nbsth->execute($pr->{id}, $nbset[0]->addr);
     1997      }
     1998
     1999      # Holder for freeblocks-to-delete.  Should be impossible to have more than one...
     2000      my %fbdel;
     2001
     2002      # Loop over the new blocks that are not the base block
     2003      for (my $i = 1; $i <= $#nbset; $i++) {
     2004        # add the new allocation
     2005        $allocsth2->execute($nbset[$i], $pr->{id});
     2006
     2007        # fetch the ID of the entry we just added...
     2008        $idsth->execute();
     2009        my ($nid) = $idsth->fetchrow_array();
     2010        # ... so we can pass back the list of blocks and IDs...
     2011        push @ret, {nid => $nid, nblock => "$nbset[$i]"};
     2012        # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool
     2013        if ($pr->{type} =~ /.d/) {
     2014          # net
     2015          $nbsth->execute($pr->{id}, $nbset[$i]->addr);
     2016          $nbset[$i]++;
     2017          # gw
     2018          $nbsth->execute($pr->{id}, $nbset[$i]->addr);
     2019          $nbset[$i]--;
     2020          $nbset[$i]--;
     2021          # bcast
     2022          $nbsth->execute($pr->{id}, $nbset[$i]->addr);
     2023          $nbset[$i]++;
     2024        } # $binfo->{type} =~ /.d/
     2025
     2026        # Check for free blocks larger than the new mask length, and split those as needed.
     2027        if ($pr->{type} =~ /.[cm]/) {
     2028          # get a "list" of freeblocks bigger than the allocation in the parent.  there's only one, right?
     2029          my $fblist = $dbh->selectall_arrayref("SELECT id FROM freeblocks WHERE cidr >> ? AND parent_id = ? ",
     2030            {Slice=>{}}, $nbset[$i], $pr->{id});
     2031          if (@$fblist) {
     2032            # create a new freeblock for the new block we created earlier
     2033            $dbh->do(q{
     2034                INSERT INTO freeblocks (cidr, parent_id, master_id, city, routed,vrf)
     2035                    SELECT ? AS cidr, ? AS parent_id, master_id, city, routed, vrf FROM freeblocks
     2036                    WHERE id = ?
     2037                }, undef, ($nbset[$i], $nid, $fblist->[0]->{id}) );
     2038            $fbdel{$fblist->[0]->{id}}++;
     2039          }
     2040        } # $binfo->{type} =~ /.[cm]/
     2041
     2042        # Reparent allocations, freeblocks, and pool IPs. 
     2043        $upd_psth->execute($nid, $pr->{id}, $nbset[$i]);
     2044        $fb_psth->execute($nid, $pr->{id}, $nbset[$i]);
     2045        $pool_psth->execute($nid, $pr->{id}, $nbset[$i]);
     2046
     2047        # Update master if we've split a master block
     2048        if ($pr->{type} eq 'mm') {
     2049          $upd_msth->execute($nid, $pr->{id}, $nbset[$i]);
     2050          $fb_msth->execute($nid, $pr->{id}, $nbset[$i]);
     2051          $pool_msth->execute($nid, $pr->{id}, $nbset[$i]);
    20172052        }
    2018       } # $binfo->{type} =~ /.[cm]/
    2019 
    2020       # Reparent allocations, freeblocks, and pool IPs. 
    2021       $upd_psth->execute($nid, $args{id}, $newblocks[$i]);
    2022       $fb_psth->execute($nid, $args{id}, $newblocks[$i]);
    2023       $pool_psth->execute($nid, $args{id}, $newblocks[$i]);
    2024 
    2025       # Update master if we've split a master block
    2026       if ($binfo->{type} eq 'mm') {
    2027         $upd_msth->execute($nid, $args{id}, $newblocks[$i]);
    2028         $fb_msth->execute($nid, $args{id}, $newblocks[$i]);
    2029         $pool_msth->execute($nid, $args{id}, $newblocks[$i]);
    2030       }
    20312053
    20322054##fixme:
     2055# 2015/09/09 not sure if the latest rewrite has covered this case complete or not
    20332056# Still missing one edge case - megasplitting a large block such that "many" children also need to be split.
    20342057# I'm going to call this "unsupported" because I really can't imagine a sane reason for doing this.
    20352058# Should probably check and error out at least
    20362059
    2037     } # for (... @newblocks)
    2038 
    2039     $dbh->do("DELETE FROM freeblocks WHERE id IN (".join(',', keys %fbdel).")") if %fbdel;
     2060      } # for (... @nbset)
     2061
     2062      if (%fbdel) {
     2063        my $delfblist = $dbh->selectall_arrayref(q{
     2064            SELECT cidr,parent_id,id FROM freeblocks
     2065            WHERE id in (
     2066            }.join(',', keys %fbdel).")", {Slice=>{}} );
     2067        $dbh->do("DELETE FROM freeblocks WHERE id IN (".join(',', keys %fbdel).")") if %fbdel;
     2068      }
     2069
     2070    } # foreach @processlist
    20402071
    20412072    $dbh->commit;
Note: See TracChangeset for help on using the changeset viewer.