Changeset 702 for trunk/cgi-bin
- Timestamp:
- 02/23/15 18:16:11 (10 years ago)
- Location:
- trunk/cgi-bin
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/cgi-bin/IPDB.pm
r699 r702 32 32 &getMasterList &getTypeList &getPoolSelect &findAllocateFrom 33 33 &ipParent &subParent &blockParent &getBreadCrumbs &getRoutedCity 34 &allocateBlock &updateBlock & deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP34 &allocateBlock &updateBlock &splitBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP 35 35 &getNodeList &getNodeName &getNodeInfo 36 36 &mailNotify … … 47 47 &getMasterList &getTypeList &getPoolSelect &findAllocateFrom 48 48 &ipParent &subParent &blockParent &getBreadCrumbs &getRoutedCity 49 &allocateBlock &updateBlock & deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP49 &allocateBlock &updateBlock &splitBlock &deleteBlock &getBlockData &getBlockRDNS &getRDNSbyIP 50 50 &getNodeList &getNodeName &getNodeInfo 51 51 &mailNotify … … 1453 1453 1454 1454 1455 ## IPDB::splitBlock() 1456 # Splits an existing allocation into two or more smaller allocations based on a passed netmask 1457 # Duplicates all other data 1458 # Returns an arrayref to a list of hashrefs with ID and CIDR keys for the list of new allocations. 1459 # Should probably commit DNS magic to realign DNS data 1460 sub splitBlock { 1461 my $dbh = shift; 1462 my $id = shift; 1463 my $basetype = shift; 1464 my $newmask = shift; 1465 1466 ##fixme: set errstr on errors so caller can suitably clue-by-four the user 1467 return if $basetype ne 'b'; # only netblocks allowed! 1468 1469 my $binfo = getBlockData($dbh, $id); 1470 return if !$binfo; 1471 1472 return if $newmask !~ /^\d+$/; 1473 1474 my @ret; 1475 my $block = new NetAddr::IP $binfo->{block}; 1476 my $oldmask = $block->masklen; 1477 1478 # Fail if the block to split is "too small" - eg, can't split a v4 /32 at all 1479 # failure modes: 1480 # difference between $oldmask and $newmask is negative or 0 1481 if ($newmask - $oldmask <= 0) { 1482 $errstr = "Can't split a /$oldmask allocation into /$newmask pieces"; 1483 return; 1484 } 1485 # # difference between $oldmask and $newmask is > n, for arbitrary n? 1486 # if ($newmask - $oldmask > 42) { # because 42 1487 # } 1488 # $oldmask > n, for arbitrary n? At least check limits of data type. 1489 if ($block->{isv6}) { 1490 if ($newmask - $oldmask > 128) { 1491 $errstr = "Impossible IPv6 mask length /$newmask requested"; 1492 return; 1493 } 1494 } else { 1495 if ($newmask - $oldmask > 32) { 1496 $errstr = "Impossible IPv4 mask length /$newmask requested"; 1497 return; 1498 } 1499 } 1500 1501 my @newblocks = $block->split($newmask); 1502 1503 local $dbh->{AutoCommit} = 0; 1504 local $dbh->{RaiseError} = 1; 1505 1506 eval { 1507 # line up a list of fields and values. Be nice if there was a handy way to do, 1508 # direct in SQL, something like 1509 # "INSERT INTO foo (f1,f2,f3) VALUES (newf1,(SELECT oldf2,oldf3 FROM foo WHERE baz))" 1510 my @fieldlist = qw(type city description notes circuitid privdata custid swip vrf vlan rdns parent_id master_id); 1511 my $fields_sql = join(',', @fieldlist); 1512 my @vals; 1513 foreach (@fieldlist) { 1514 push @vals, $binfo->{$_}; 1515 } 1516 # note the first block in the split for return 1517 push @ret, {nid => $id, nblock => "$newblocks[0]"}; 1518 1519 # prepare 1520 my $idsth = $dbh->prepare("SELECT currval('allocations_id_seq')"); 1521 my $poolsth = $dbh->prepare("INSERT INTO allocations (cidr, $fields_sql)". 1522 " VALUES (?".',?'x(scalar(@fieldlist)).")"); 1523 my $poolchildsth = $dbh->prepare("UPDATE poolips SET parent_id = ? WHERE ip << ? AND parent_id = ?"); 1524 my $nbsth = $dbh->prepare("DELETE FROM poolips WHERE parent_id = ? AND ip = ?"); 1525 1526 # set up update of existing block 1527 $dbh->do("UPDATE allocations SET cidr = ? WHERE id = ?", undef, ("$newblocks[0]", $id) ); 1528 1529 # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool 1530 if ($binfo->{type} =~ /.d/) { 1531 $newblocks[0]--; 1532 $nbsth->execute($id, $newblocks[0]->addr); 1533 } 1534 1535 # Loop over the new blocks that are not the base block 1536 for (my $i = 1; $i <= $#newblocks; $i++) { 1537 # add the new pool 1538 $poolsth->execute($newblocks[$i], @vals); 1539 # fetch the ID of the entry we just added... 1540 $idsth->execute(); 1541 my ($nid) = $idsth->fetchrow_array(); 1542 # ... so we can pass back the list of blocks and IDs... 1543 push @ret, {nid => $nid, nblock => "$newblocks[$i]"}; 1544 # axe the net, gw, and bcast IPs as necessary when splitting a "normal" pool 1545 if ($binfo->{type} =~ /.d/) { 1546 # net 1547 $nbsth->execute($id, $newblocks[$i]->addr); 1548 $newblocks[$i]++; 1549 # gw 1550 $nbsth->execute($id, $newblocks[$i]->addr); 1551 $newblocks[$i]--; 1552 $newblocks[$i]--; 1553 # bcast 1554 $nbsth->execute($id, $newblocks[$i]->addr); 1555 $newblocks[$i]++; 1556 } 1557 # ... and update the existing IPs with the new parent_id 1558 $poolchildsth->execute($nid, $newblocks[$i], $id); 1559 } 1560 1561 $dbh->commit; 1562 }; 1563 if ($@) { 1564 $errstr = "Error splitting $binfo->{block}: $@"; 1565 $dbh->rollback; 1566 return; 1567 } 1568 1569 return \@ret; 1570 } # end splitBlock() 1571 1572 1455 1573 ## IPDB::deleteBlock() 1456 1574 # Removes an allocation from the database, including deleting IPs -
trunk/cgi-bin/main.cgi
r697 r702 171 171 elsif($webvar{action} eq 'update') { 172 172 update(); 173 } 174 elsif($webvar{action} eq 'split') { 175 prepSplit(); 176 } 177 elsif($webvar{action} eq 'dosplit') { 178 doSplit(); 173 179 } 174 180 elsif($webvar{action} eq 'delete') { … … 965 971 $page->param(maydel => $IPDBacl{$authuser} =~ /d/); 966 972 973 # Need to find internal knobs to twist to actually vary these. (Ab)use "change" flag for now 974 $page->param(maymerge => ($IPDBacl{$authuser} =~ /c/ && $blockinfo->{type} !~ /^.i$/)); 975 if ($IPDBacl{$authuser} =~ /c/ && $blockinfo->{type} !~ /^.i$/) { 976 if ($blockinfo->{type} =~ /^.p$/) { 977 # PPP pools 978 $page->param(maysplit => 1) if $cidr->masklen+1 < $cidr->bits; 979 } elsif ($blockinfo->{type} =~ /.d/) { 980 # Non-PPP pools 981 $page->param(maysplit => 1) if $cidr->masklen+2 < $cidr->bits; 982 } else { 983 # Standard netblocks. Arguably allowing splitting these down to single IPs 984 # doesn't make much sense, but forcing users to apply allocation types 985 # "properly" is worse than herding cats. 986 $page->param(maysplit => 1) if $cidr->masklen < $cidr->bits; 987 } 988 } 989 967 990 } # edit() 968 991 … … 1061 1084 1062 1085 1086 sub prepSplit { 1087 if ($IPDBacl{$authuser} !~ /c/) { 1088 $aclerr = 'splitblock'; 1089 return; 1090 } 1091 1092 my $blockinfo = getBlockData($ip_dbh, $webvar{block}); 1093 1094 if ($blockinfo->{type} =~ /^.i$/) { 1095 $page->param(err => "Can't split a single IP allocation"); 1096 return; 1097 } 1098 1099 # Info about current allocation 1100 $page->param(oldblock => $blockinfo->{block}); 1101 $page->param(block => $webvar{block}); 1102 1103 # Note that there are probably different rules that should be followed to restrict splitting IPv6 blocks; 1104 # strictly speaking it will be exceptionally rare to see smaller than a /64 assigned to a customer, since that 1105 # breaks auto-addressing schemes. 1106 1107 # Generate possible splits 1108 my $block = new NetAddr::IP $blockinfo->{block}; 1109 my $oldmask = $block->masklen; 1110 if ($blockinfo->{type} =~ /^.d$/) { 1111 # Non-PPP pools 1112 if ($oldmask+2 >= $block->bits) { 1113 $page->param(err => "Can't split a standard netblock pool any further"); 1114 return; 1115 } 1116 # Allow splitting down to v4 /30 (which results in one usable IP; dubiously useful) 1117 $page->param(sp4mask => $oldmask+2) if $oldmask+2 <= $block->bits-2; 1118 } elsif ($blockinfo->{type} =~ /.p/) { 1119 # Allow splitting PPP pools down to v4 /31 1120 $page->param(sp4mask => $oldmask+2) if $oldmask+2 <= $block->bits-1; 1121 } else { 1122 # Allow splitting all other non-pool netblocks down to single IPs, which... 1123 # arguably should be *aggregated* in a pool. Except where they shouldn't. 1124 $page->param(sp4mask => $oldmask+2) if $oldmask+2 <= $block->bits; 1125 } 1126 # set the split-in-half mask 1127 $page->param(sp2mask => $oldmask+1); 1128 1129 # Generate possible shrink targets 1130 my @keepers = $block->split($block->masklen+1); 1131 $page->param(newblockA => $keepers[0]); 1132 $page->param(newblockB => $keepers[1]); 1133 } # prepSplit() 1134 1135 1136 sub doSplit { 1137 if ($IPDBacl{$authuser} !~ /c/) { 1138 $aclerr = 'splitblock'; 1139 return; 1140 } 1141 1142 ##fixme: need consistent way to identify "this thing that is this thing" with only the ID 1143 # also applies to other locations 1144 my $blockinfo = getBlockData($ip_dbh, $webvar{block}); 1145 1146 if ($blockinfo->{type} =~ /^.i$/) { 1147 $page->param(err => "Can't split a single IP allocation"); 1148 return; 1149 } 1150 1151 if ($webvar{subact} eq 'split') { 1152 $page->param(issplit => 1); 1153 my $binfo = getBlockData($ip_dbh, $webvar{block}); 1154 $page->param(cidr => $binfo->{block}); 1155 my $block = new NetAddr::IP $binfo->{block}; 1156 my $newblocks = splitBlock($ip_dbh, $webvar{block}, 'b', $webvar{split}); 1157 if ($newblocks) { 1158 $page->param(newblocks => $newblocks); 1159 # and the backlink to the parent container 1160 my $pinfo = getBlockData($ip_dbh, $binfo->{parent_id}); 1161 $page->param(backid => $binfo->{parent_id}); 1162 $page->param(backblock => $pinfo->{block}); 1163 } else { 1164 $page->param(err => $IPDB::errstr); 1165 } 1166 1167 } else { 1168 # Shrink 1169 } 1170 } # doSplit() 1171 1172 1063 1173 # Delete an allocation. 1064 1174 sub remove {
Note:
See TracChangeset
for help on using the changeset viewer.