chrestomanci has asked for the wisdom of the Perl Monks concerning the following question:
Greetings wise brothers.
I have been given a list of about 50_000 subnets, and asked to find which if any overlap. The largest is probably a /8, I don't know how small the smallest is, but I know that it must be at least a /24. I am looking for advice on an algorithm to use.
Given the large number of subnets to examine, a pairwise comparison between every pair in the list is clearly impractical.
The best algorithm I can think of, is to represent each subnet in a database as a string representing the known bits, (so 192.168.0.0/16 would be represented as the 16 known bits: 1100000010101000), and then sort by the mask and do substring searches in the database
Another idea I had was to construct a tree of up to 32 levels, and populate it with the networks according to their bit patterns. If when inserting a network I find the space taken, I would have found an overlap.
Any other ideas? Is there a standard way of doing this that google has somehow not found for me?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Algorithom to find overlaping subnets (Internet IPv4)
by rg0now (Chaplain) on Sep 19, 2011 at 12:29 UTC | |
If speed is a concern, then I would go with your "build a tree of up to 32 levels" idea. Such a tree is called a prefix trie, and it is often used in IP routing tables. You can code your own or choose something from CPAN (say, Net::IPTrie or Tree::Trie). Note, however, that checking overlaps is more difficult than your "inserting a network I find the space taken, I would have found an overlap" idea, because not just the node itself, but all its parents must be checked as well. In particular, you have an overlap either if the node corresponding to your subnet is taken or any of its parents is taken. | [reply] [d/l] |
by chrestomanci (Priest) on Sep 20, 2011 at 13:47 UTC | |
Thanks for your informative reply. If I had know that mod::Net::IPTrie or mod::Tree::Trie existed I would have use them, unfortunately I did not know they existed and did not know the terminology to search for them on CPAN, and I thought it would take to long to implement something myself. Instead I wrote some code using string representations of the binary bits in a database using DBIx::Class. My DBIC table defintion looks like this:
Once I have populated the table of subnets, I then search it like this:
Using this algorithm I was able to search through the 50_000 subnets searching for overlaps in about 10 minutes. (On a 3GHz Linux box). | [reply] [d/l] [select] |
|
Re: Algorithom to find overlaping subnets (Internet IPv4)
by Khen1950fx (Canon) on Sep 18, 2011 at 21:58 UTC | |
| [reply] |
|
Re: Algorithom to find overlaping subnets (Internet IPv4)
by BrowserUk (Patriarch) on Sep 19, 2011 at 14:40 UTC | |
An interesting question is what exactly do you mean by overlap? For example: for some applications, a subnet that is entirely contained by another:
Can easily be done away with entirely. But subnets that overlaps but not completely:
Will rarely be able to be coalesced directly into a single subnet (#3), as the 'nearest' subnet that would contain both (#4) will usually also contain addresses not contained in the original set. And given 50_000 inputs, the likely scenario -- in the absence of more specificity regarding the distribution of the subnets -- is that they will form a tree with a few large, 'root' level subnets each containing a hierarchy of smaller subnets:
That suggests a strategy whereby instead of sorting the subnets by start/end address, you should sort them by subnet size. The first (largest) therefore will not be contained by any of the others, so can be removed from the list, and used as the root of a tree. It may of course, overlap with one or more of the next few largest, but except for the rare event where the two can be combined into a single, unextended subnet, they will still be roots of their own subtrees. So my suggestion would be to pick off the biggest ones and remove them from the list very quickly. You can then distribute the rest as subordinate to one (or more) of the roots you picked out. You can then (recursively) process each of those lists, to further divide their lists into smaller third level lists below a few second-level subroots. Rinse and repeat. Subnets entirely contained within a higher level can be easily discarded. The initial sorting by subnet size is very fast. And the first level of recursion very quickly splits the dataset into several or many small subsets that are quickly processed at each new level of recursion. I might have posted code, but I found that testing such is very hard in the absence of a real dataset. Randomly generated datasets are just too random to give meaningful results. Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
by chrestomanci (Priest) on Sep 20, 2011 at 08:17 UTC | |
Thank you for your input, however I think you misunderstand the nature of the problem. By 'Overlapping subnets' I actually mean one subnet that is entirely within another. It is not possible for a subnet to partially overlap another because we are expressing them in CDIR notation, rather than arbitrary ranges. This makes the problem simpler than you allowed for in your analysis. For example, consider the subnet x.y.0.0/16 There are exactly 2 /17 subnets that might fit inside it (x.y.0.0/17 and x.y.128.0/17) and a greater number of smaller subnets. There might also be larger subnets that contain it, but it is impossible to define a subnet (in CDIR notation) that includes some of the address space covered by x.y.0.0/16, and some address space that is not covered. You also talk about merging overlapping subnets. This is not what I am trying to do. The end purpose is to produce a reports of all the overlaps which will be used by the network infrastructure people to reconfigure the routers and DNS/DHCP servers so that the subnets no longer overlap. | [reply] |
by BrowserUk (Patriarch) on Sep 20, 2011 at 14:09 UTC | |
There might also be larger subnets that contain it, but it is impossible to define a subnet (in CDIR notation) that includes some of the address space covered by x.y.0.0/16, and some address space that is not covered. Indeed. I wasn't aware of that property of CIDRs, though I now see it is obvious. You also talk about merging overlapping subnets. This is not what I am trying to do. The end purpose is to produce a reports of all the overlaps which will be used by the network infrastructure people to reconfigure the routers and DNS/DHCP servers so that the subnets no longer overlap. When the infrastructure people get their hands on your report, won't one of the things they might do be to consolidate (say) 0.0.0.0/30 & 0.0.0.4/30 into 0.0.0.0/29 thus reducing router table sizes? Or dropping this lot:
Because they are all already covered by: 0.40.0.0/13? (ie."coalescing" them.) Anyway, thanks for posting an interesting question. I guess if you don't find Re: Algorithom to find overlaping subnets (Internet IPv4) useful, someone else might :) Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
Re: Algorithom to find overlaping subnets (Internet IPv4)
by BrowserUk (Patriarch) on Sep 19, 2011 at 20:11 UTC | |
FWIW: This processes a list of 50e3 randomly generated CIDRs in < 3 minutes:
The (truncated) output produced is:
I produced the datasets using this generator script:
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
by jimpudar (Pilgrim) on Apr 11, 2018 at 05:33 UTC | |
I recently had to work on this problem, and needed a fast implementation. I found the easiest and fastest way was to use a Trie as mentioned by rg0now. I used the random generator which BrowserUk supplied to generate the random dataset. My version processed the dataset in less than two seconds on my 3.8GHz Linux box. I don't have nice sorted output though. It should be trivial to build up a data structure as you go if you need sorted output... Here's the code:
Some truncated sample output:
Anyone see any issues with this? It hasn't been completely battle tested yet :) Best, Jim | [reply] [d/l] [select] |