Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- exec /Users/baldur/scala-2.11.7/bin/scala "$0" "$@"
- !#
- val inputRE = """\s*(add|remove)\s+(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)\s*""".r
- def toIP(i1: Int, i2: Int, i3: Int, i4: Int) = (i1 << 24) | (i2 << 16) | (i3 << 8) | i4
- def ipToString(ip: Int): String = f"${(ip>>24)&255}.${(ip>>16)&255}.${(ip>>8)&255}.${ip&255}"
- case class Subnet(ip: Int, prefixLength: Int) {
- override def toString: String = f"${ipToString(ip)}/${prefixLength}"
- }
- def netmask(prefixLength: Int) = if (prefixLength==0) 0 else -1 << (32 - prefixLength)
- // a valid subnet is a subnet where (ip & netmask) == ip
- def makeValid(subnet: Subnet): Subnet =
- subnet.copy(ip = subnet.ip & netmask(subnet.prefixLength))
- // split a subnet into two each with prefixLength+1
- def split(subnet: Subnet): (Subnet,Subnet) = (
- Subnet(subnet.ip, subnet.prefixLength + 1),
- Subnet(subnet.ip + (1 << (31 - subnet.prefixLength)), subnet.prefixLength + 1))
- /*
- subnetList: current set of subnets that shall be expanded
- subnetToAdd: subnet that will be added to subnetList
- returns: set of subnets that includes everything from subnetList plus subnetToAdd
- requirements:
- subnetToAdd is valid
- subnetList is optimal
- subnetList does not contain overlapping subnets
- subnetList does not contain subnets that could be merged
- subnetList does not contain invalid subnets
- return value provides same guaranties
- */
- def add(subnetList: Set[Subnet], subnetToAdd: Subnet): Set[Subnet] = {
- // 1) remove all subnets covered by subnetToAdd
- val subnetList2 = subnetList.filterNot { subnet =>
- subnet.prefixLength >= subnetToAdd.prefixLength &&
- ((subnet.ip & netmask(subnetToAdd.prefixLength)) == subnetToAdd.ip)
- }
- // 2) add subnetToAdd
- val subnetList3 = subnetList2 + subnetToAdd
- // 3) possibly merge subnetToAdd with adjicent subnet
- // 4) recursively perform step 4 until no merge or 0.0.0.0/0
- def merge(subnetList: Set[Subnet], toBeMerged: Subnet): Set[Subnet] = {
- if (toBeMerged.prefixLength == 0) return subnetList
- val supernet = makeValid(Subnet(toBeMerged.ip,toBeMerged.prefixLength-1))
- val (subnet1,subnet2) = split(supernet)
- // either subnet1 or subnet2 will be equal to toBeMerged
- if (subnetList(subnet1) && subnetList(subnet2)) {
- // two subnets found, remove both and add supernet instead
- // then run merge recursively
- merge(subnetList - subnet1 - subnet2 + supernet, supernet)
- } else {
- // done, could not find two subnets to merge
- subnetList
- }
- }
- merge(subnetList3, subnetToAdd)
- }
- /*
- subnetList: current set of subnets that shall be reduced
- subnetToRemove: subnet that will be removed from subnetList
- returns: set of subnets that includes all address space covered by subnetList excluding subnetToRemove
- requirements:
- subnetList is optimal
- subnetList does not contain overlapping subnets
- subnetList does not contain subnets that could be merged
- subnetList does not contain invalid subnets
- return value provides same guaranties
- */
- def remove(subnetList: Set[Subnet], subnetToRemove: Subnet): Set[Subnet] = {
- // 1) remove all subnets covered by subnetToRemove
- val subnetList2 = subnetList.filterNot { subnet =>
- subnet.prefixLength >= subnetToRemove.prefixLength &&
- ((subnet.ip & netmask(subnetToRemove.prefixLength)) == subnetToRemove.ip)
- }
- // 2) find all subnets that covers subnetToRemove
- val subnetCoversList = subnetList2.filter { subnet =>
- (subnetToRemove.ip & netmask(subnet.prefixLength)) == subnet.ip
- }
- // 3) select bestMatch, that is the one of largest prefixLength
- val bestMatch = subnetCoversList.toVector.sortBy(-_.prefixLength).headOption.getOrElse {
- // subnetCoversList is empty so we are done
- return subnetList2
- }
- // 4) remove bestMatch
- val subnetList3 = subnetList2 - bestMatch
- // 5) possibly split bestMatch and add the half that does not cover subnetToRemove
- // 6) recursively perform step 4 until subnet to split is equal to subnetToRemove
- def splitStep(subnetList: Set[Subnet], toBeSplit: Subnet): Set[Subnet] = {
- if (toBeSplit == subnetToRemove) return subnetList
- val (subnet1,subnet2) = split(toBeSplit)
- if ((subnetToRemove.ip & netmask(subnet1.prefixLength)) == subnet1.ip) {
- // add subnet2 and split subnet1
- splitStep(subnetList + subnet2, subnet1)
- } else {
- // add subnet1 and split subnet2
- splitStep(subnetList + subnet1, subnet2)
- }
- }
- splitStep(subnetList3, bestMatch)
- }
- val input = io.Source.stdin.getLines.collect {
- case inputRE(command,i1,i2,i3,i4,l) =>
- (command,makeValid(Subnet(toIP(i1.toInt,i2.toInt,i3.toInt,i4.toInt),l.toInt)))
- }
- val result = input.foldLeft[Set[Subnet]](Set.empty){ case (acc,op) => op match {
- case ("add",subnet: Subnet) => add(acc,subnet)
- case ("remove",subnet: Subnet) => remove(acc,subnet)
- }}
- for(subnet <- result.toVector.sortBy(_.prefixLength).sortBy(_.ip.toLong & 0xffffffffL))
- println(subnet)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement