- Timestamp:
- 11/20/12 16:02:34 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cgi-bin/IPDB.pm
r547 r554 656 656 ## IPDB::allocateBlock() 657 657 # Does all of the magic of actually allocating a netblock 658 # Requires database handle, block to allocate, custid, type, city, 659 # description, notes, circuit ID, block to allocate from, private data 658 # Requires a database handle, and a hash containing the block to allocate, routing depth, custid, 659 # type, city, block to allocate from, and optionally a description, notes, circuit ID, 660 # and private data 660 661 # Returns a success code and optional error message. 661 662 sub allocateBlock { 662 my ($dbh,undef,undef,$custid,$type,$city,$desc,$notes,$circid,$privdata,$nodeid) = @_; 663 664 my $cidr = new NetAddr::IP $_[1]; 665 my $alloc_from = new NetAddr::IP $_[2]; 663 my $dbh = shift; 664 665 my %args = @_; 666 667 $args{cidr} = new NetAddr::IP $args{cidr}; 668 $args{alloc_from} = new NetAddr::IP $args{alloc_from}; 669 670 $args{desc} = '' if !$args{desc}; 671 $args{notes} = '' if !$args{notes}; 672 $args{circid} = '' if !$args{circid}; 673 $args{privdata} = '' if !$args{privdata}; 674 $args{vrf} = '' if !$args{vrf}; 675 666 676 my $sth; 667 677 668 $desc = '' if !$desc;669 $notes = '' if !$notes;670 $circid = '' if !$circid;671 $privdata = '' if !$privdata;672 673 678 # Snag the "type" of the freeblock (alloc_from) "just in case" 674 $sth = $dbh->prepare("select routed from freeblocks where cidr='$a lloc_from'");679 $sth = $dbh->prepare("select routed from freeblocks where cidr='$args{alloc_from}'"); 675 680 $sth->execute; 676 681 my ($alloc_from_type) = $sth->fetchrow_array; 677 682 678 683 # To contain the error message, if any. 679 my $msg = "Unknown error allocating $ cidr as '$type'";684 my $msg = "Unknown error allocating $args{cidr} as '$disp_alloctypes{$args{type}}'"; 680 685 681 686 # Enable transactions and error handling … … 683 688 local $dbh->{RaiseError} = 1; # step on our toes by accident. 684 689 685 if ($ type=~ /^.i$/) {686 $msg = "Unable to assign static IP $ cidr to $custid";690 if ($args{type} =~ /^.i$/) { 691 $msg = "Unable to assign static IP $args{cidr} to $args{custid}"; 687 692 eval { 688 # We have to do this in two parts because otherwise we lose 689 # the ability to return the IP assigned. Should that change, 690 # the commented SQL statement below may become usable. 691 # update poolips set custid='$custid',city='$city',available='n', 692 # description='$desc',notes='$notes',circuitid='$circid' 693 # where ip=(select ip from poolips where pool='$alloc_from' 694 # and available='y' order by ip limit 1); 695 696 if ($cidr) { 697 my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($cidr) ); 698 if ($isavail eq 'n') { 699 die "IP already allocated. Deallocate and reallocate, or update the entry\n"; 700 } 701 if (!$isavail) { 702 die "IP is not in an IP pool.\n"; 703 } 704 } else { 705 ($cidr) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip", 706 undef, ($alloc_from) ); 707 } 708 $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=? ". 709 "WHERE ip=?", undef, ($custid, $city, $desc, $notes, $circid, $privdata, $cidr) ); 693 if ($args{cidr}) { # IP specified 694 my ($isavail) = $dbh->selectrow_array("SELECT available FROM poolips WHERE ip=?", undef, ($args{cidr}) ); 695 die "IP is not in an IP pool.\n" 696 if !$isavail; 697 die "IP already allocated. Deallocate and reallocate, or update the entry\n" 698 if $isavail eq 'n'; 699 } else { # IP not specified, take first available 700 ($args{cidr}) = $dbh->selectrow_array("SELECT ip FROM poolips WHERE pool=? AND available='y' ORDER BY ip", 701 undef, ($args{alloc_from}) ); 702 } 703 $dbh->do("UPDATE poolips SET custid=?,city=?,available='n',description=?,notes=?,circuitid=?,privdata=?,vrf=? ". 704 "WHERE ip=?", undef, ($args{custid}, $args{city}, $args{desc}, $args{notes}, $args{circid}, 705 $args{privdata}, $args{vrf}, $args{cidr}) ); 710 706 711 707 # node hack 712 if ($nodeid && $nodeid ne '') { 713 $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)"); 714 $sth->execute("$cidr",$nodeid); 708 if ($args{nodeid} && $args{nodeid} ne '') { 709 $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) ); 715 710 } 716 711 # end node hack … … 723 718 return ('FAIL',$msg); 724 719 } else { 725 return ('OK',"$ cidr");720 return ('OK',"$args{cidr}"); 726 721 } 727 722 728 723 } else { # end IP-from-pool allocation 729 724 730 if ($ cidr == $alloc_from) {725 if ($args{cidr} == $args{alloc_from}) { 731 726 # Easiest case- insert in one table, delete in the other, and go home. More or less. 732 727 # insert into allocations values (cidr,custid,type,city,desc) and … … 735 730 736 731 eval { 737 $msg = "Unable to allocate $ cidr as '$disp_alloctypes{$type}'";738 if ($type eq 'rm') { 739 $sth = $dbh->prepare("update freeblocks set routed='y',city='$city'".740 " where cidr='$cidr'");741 $sth->execute;742 $sth = $dbh->prepare("insert into routed (cidr,maskbits,city)".743 " values ('$cidr',".$cidr->masklen.",'$city')");744 $sth->execute;732 $msg = "Unable to allocate $args{cidr} as '$disp_alloctypes{$args{type}}'"; 733 734 # Munge freeblocks 735 if ($args{type} =~ /^(.)[mc]$/) { 736 # special case - block is a routed or container/"reserve" block 737 my $rtype = $1; 738 $dbh->do("UPDATE freeblocks SET routed=?,rdepth=rdepth+1,city=?,parent=? WHERE cidr=? AND rdepth=?", 739 undef, ($rtype, $args{city}, $args{cidr}, $args{cidr}, $args{rdepth})); 745 740 } else { 746 # common stuff for end-use, dialup, dynDSL, pools, etc, etc. 747 748 # special case - block is a container/"reserve" block 749 if ($type =~ /^(.)c$/) { 750 $sth = $dbh->prepare("update freeblocks set routed='$1' where cidr='$cidr'"); 751 $sth->execute; 752 } else { 753 # "normal" case 754 $sth = $dbh->prepare("delete from freeblocks where cidr='$cidr'"); 755 $sth->execute; 756 } 757 $sth = $dbh->prepare("insert into allocations". 758 " (cidr,custid,type,city,description,notes,maskbits,circuitid,privdata)". 759 " values (?,?,?,?,?,?,?,?,?)"); 760 $sth->execute("$cidr", $custid, $type, $city, $desc, $notes, $cidr->masklen, $circid, $privdata); 761 762 # And initialize the pool, if necessary 763 # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available 764 # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed. 765 if ($type =~ /^.p$/) { 766 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr"; 767 my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"all"); 768 die $rmsg if $code eq 'FAIL'; 769 } elsif ($type =~ /^.d$/) { 770 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr"; 771 my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"normal"); 772 die $rmsg if $code eq 'FAIL'; 773 } 774 775 } # routing vs non-routing netblock 741 # "normal" case 742 $dbh->do("DELETE FROM freeblocks WHERE cidr=? AND rdepth=?", undef, ($args{cidr}, $args{rdepth})); 743 } 744 745 # get old freeblocks parent/depth/routed for new entries 746 my ($fparent) = $dbh->selectrow_array("SELECT parent,city,routed FROM freeblocks". 747 " WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth})); 748 749 # Insert the allocations entry 750 $dbh->do("INSERT INTO allocations ". 751 "(cidr,parent,vrf,rdepth,custid,type,city,description,notes,circuitid,privdata)". 752 " VALUES (?,?,?,?,?,?,?,?,?,?,?)", undef, 753 ($args{cidr}, $fparent, $args{vrf}, $args{rdepth}, $args{custid}, $args{type}, $args{city}, 754 $args{desc}, $args{notes}, $args{circid}, $args{privdata}) ); 755 756 # And initialize the pool, if necessary 757 # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available 758 # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed. 759 if ($args{type} =~ /^.p$/) { 760 $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}"; 761 my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "all"); 762 die $rmsg if $code eq 'FAIL'; 763 } elsif ($args{type} =~ /^.d$/) { 764 $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}"; 765 my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "normal"); 766 die $rmsg if $code eq 'FAIL'; 767 } 776 768 777 769 # node hack 778 if ($nodeid && $nodeid ne '') { 779 $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)"); 780 $sth->execute("$cidr",$nodeid); 770 if ($args{nodeid} && $args{nodeid} ne '') { 771 $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) ); 781 772 } 782 773 # end node hack … … 794 785 795 786 # Hard case. Allocation is smaller than free block. 796 my $wantmaskbits = $ cidr->masklen;797 my $maskbits = $a lloc_from->masklen;787 my $wantmaskbits = $args{cidr}->masklen; 788 my $maskbits = $args{alloc_from}->masklen; 798 789 799 790 my @newfreeblocks; # Holds free blocks generated from splitting the source freeblock. … … 803 794 # block is in, and repeat until the wanted block is equal to one of the halves. 804 795 my $i=0; 805 my $tmp_from = $a lloc_from; # So we don't munge $alloc_from796 my $tmp_from = $args{alloc_from}; # So we don't munge $args{alloc_from} 806 797 while ($maskbits++ < $wantmaskbits) { 807 798 my @subblocks = $tmp_from->split($maskbits); 808 $newfreeblocks[$i++] = (($ cidr->within($subblocks[0])) ? $subblocks[1] : $subblocks[0]);809 $tmp_from = ( ($ cidr->within($subblocks[0])) ? $subblocks[0] : $subblocks[1] );799 $newfreeblocks[$i++] = (($args{cidr}->within($subblocks[0])) ? $subblocks[1] : $subblocks[0]); 800 $tmp_from = ( ($args{cidr}->within($subblocks[0])) ? $subblocks[0] : $subblocks[1] ); 810 801 } # while 811 802 812 803 # Begin SQL transaction block 813 804 eval { 814 $msg = "Unable to allocate $cidr as '$disp_alloctypes{$type}'"; 805 $msg = "Unable to allocate $args{cidr} as '$disp_alloctypes{$args{type}}'"; 806 807 # Get old freeblocks parent/depth/routed for new entries 808 my ($fparent,$fcity,$wasrouted) = $dbh->selectrow_array("SELECT parent,city,routed FROM freeblocks". 809 " WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth}) ); 815 810 816 811 # Delete old freeblocks entry 817 $sth = $dbh->prepare("delete from freeblocks where cidr='$alloc_from'"); 818 $sth->execute(); 819 820 # now we have to do some magic for routing blocks 821 if ($type eq 'rm') { 822 823 # Insert the new freeblocks entries 824 # Note that non-routed blocks are assigned to <NULL> 825 # and use the default value for the routed column ('n') 826 $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city)". 827 " values (?, ?, '<NULL>')"); 828 foreach my $block (@newfreeblocks) { 829 $sth->execute("$block", $block->masklen); 830 } 831 832 # Insert the entry in the routed table 833 $sth = $dbh->prepare("insert into routed (cidr,maskbits,city)". 834 " values ('$cidr',".$cidr->masklen.",'$city')"); 835 $sth->execute; 836 # Insert the (almost) same entry in the freeblocks table 837 $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)". 838 " values ('$cidr',".$cidr->masklen.",'$city','y')"); 839 $sth->execute; 840 841 } else { # done with alloctype == rm 842 843 # Insert the new freeblocks entries 844 # Along with some more HairyPerl(TM): 845 # if $alloc_type_from is p 846 # OR 847 # $type matches /^(.)r$/ 848 # inserted value for routed column should match. 849 # This solves the case of inserting an arbitrary block into a 850 # "Reserve-for-routed-DSL" block. Which you really shouldn't 851 # do in the first place, but anyway... 852 $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)". 853 " values (?, ?, (select city from routed where cidr >>= '$cidr'),'". 854 ( ( ($alloc_from_type =~ /^(p)$/) || ($type =~ /^(.)r$/) ) ? "$1" : 'y')."')"); 855 foreach my $block (@newfreeblocks) { 856 $sth->execute("$block", $block->masklen); 857 } 858 # Special-case for reserve/"container" blocks - generate 859 # the "extra" freeblocks entry for the container 860 if ($type =~ /^(.)c$/) { 861 $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)". 862 " values ('$cidr',".$cidr->masklen.",'$city','$1')"); 863 $sth->execute; 864 } 865 # Insert the allocations entry 866 $sth = $dbh->prepare("insert into allocations (cidr,custid,type,city,". 867 "description,notes,maskbits,circuitid,privdata)". 868 " values (?,?,?,?,?,?,?,?,?)"); 869 $sth->execute("$cidr", $custid, $type, $city, $desc, $notes, $cidr->masklen, $circid, $privdata); 870 871 # And initialize the pool, if necessary 872 # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available 873 # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed. 874 if ($type =~ /^.p$/) { 875 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr"; 876 my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"all"); 877 die $rmsg if $code eq 'FAIL'; 878 } elsif ($type =~ /^.d$/) { 879 $msg = "Could not initialize IPs in new $disp_alloctypes{$type} $cidr"; 880 my ($code,$rmsg) = initPool($dbh,$cidr,$type,$city,"normal"); 881 die $rmsg if $code eq 'FAIL'; 882 } 883 884 } # done with netblock alloctype != rm 812 $dbh->do("DELETE FROM freeblocks WHERE cidr=? AND rdepth=?", undef, ($args{alloc_from}, $args{rdepth}) ); 813 814 # Insert new list of smaller free blocks left over 815 $sth = $dbh->prepare("INSERT INTO freeblocks (cidr,city,routed,vrf,parent,rdepth) VALUES (?,?,?,?,?,?)"); 816 foreach my $block (@newfreeblocks) { 817 $sth->execute($block, $fcity, $wasrouted, $args{vrf}, $fparent, $args{rdepth}); 818 } 819 820 # For routed/container types, add a freeblock within the allocated block so we can subdivide it further 821 if ($args{type} =~ /(.)[mc]/) { # rm and .c types - containers 822 my $rtype = $1; 823 $sth->execute($args{cidr}, $args{city}, $rtype, $args{vrf}, $args{cidr}, $args{rdepth}+1); 824 } 825 826 # Insert the allocations entry 827 $dbh->do("INSERT INTO allocations ". 828 "(cidr,parent,vrf,rdepth,custid,type,city,description,notes,circuitid,privdata)". 829 " VALUES (?,?,?,?,?,?,?,?,?,?,?)", undef, 830 ($args{cidr}, $fparent, $args{vrf}, $args{rdepth}, $args{custid}, $args{type}, $args{city}, 831 $args{desc}, $args{notes}, $args{circid}, $args{privdata}) ); 832 833 # And initialize the pool, if necessary 834 # PPPoE pools (currently dialup, DSL, and WiFi) get all IPs made available 835 # "DHCP" or "real-subnet" pools have the net, gw, and bcast IPs removed. 836 if ($args{type} =~ /^.p$/) { 837 $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}"; 838 my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "all"); 839 die $rmsg if $code eq 'FAIL'; 840 } elsif ($args{type} =~ /^.d$/) { 841 $msg = "Could not initialize IPs in new $disp_alloctypes{$args{type}} $args{cidr}"; 842 my ($code,$rmsg) = initPool($dbh, $args{cidr}, $args{type}, $args{city}, "normal"); 843 die $rmsg if $code eq 'FAIL'; 844 } 885 845 886 846 # node hack 887 if ($nodeid && $nodeid ne '') { 888 $sth = $dbh->prepare("INSERT INTO noderef (block,node_id) VALUES (?,?)"); 889 $sth->execute("$cidr",$nodeid); 847 if ($args{nodeid} && $args{nodeid} ne '') { 848 $dbh->do("INSERT INTO noderef (block,node_id) VALUES (?,?)", undef, ($args{cidr}, $args{nodeid}) ); 890 849 } 891 850 # end node hack 851 892 852 $dbh->commit; 893 853 }; # end eval
Note:
See TracChangeset
for help on using the changeset viewer.