使用什么算法从基本CIDR获取子CIDR?

时间:2017-03-29 21:36:05

标签: java algorithm network-programming cidr

我有一个VPC,让我们说它的CIDR块是10.0.0.0/16。我在那个VPC中有几个随机子网。他们的CIDR可能类似于10.0.128.0 / 19,10.0.32.0 / 19,10.0.208.0/22。子网的CIDR块必须由VPC的CIDR块覆盖。此外,不允许子网之间的CIDR重叠。

我的问题是: 鉴于这样的VPC和子网,如何为我想要创建的新子网找到具有特定大小的良好 CIDR块(假设为/ 22)。从我的角度来看,意味着更好地利用空间。假设我只想要一个小的CIDR块,它不应该在VPC CIDR的中间返回一个CIDR,这可以防止将来放置潜在的大CIDR块。欢迎的其他定义。任何初始状态都不能保证。

我不知道是否有针对此类问题的标准算法。我目前正在考虑的是使用二叉树。左子项表示0,右子表示1.所有叶子表示正在使用的CIDR块。要获得新的CIDR块,问题基本上是在某个级别创建一个离开取决于所需的块大小。如何创建一个叶子我还不知道。

顺便说一下,我正在编写Java代码。我找不到这个库。如果有现有的图书馆,请告诉我!

2 个答案:

答案 0 :(得分:1)

二叉树是正确的结构,但它不需要下到叶级别。只在需要时将其取下。树中的每个叶子表示分配或可用块。根据定义,每个CIDR块的大小是2的幂。因此,如果一个节点/块有子节点,它只有两个。如果节点有子节点(不是叶子),则其块可用。

所以,你的顶级块及其初始分配就像这样(为了便于绘制而从左边缘表示的树。***标记已分配的块。[我可能在这里找到了一些东西,但是基本的想法应该是清楚的:每个/ 16有两个/ 17个孩子,每个/ 17有两个/ 18个孩子,等等,除非该节点可用,在这种情况下它没有孩子。]):

                    /---- 10.0.0.0/19
                    |
            /---  10.0.0.0/18
            |       |
            |       \---- 10.0.32.0/19***
            |
     /--- 10.0.0.0/17
    |       \
    |        ---- 10.0.64.0/18
    |
  10.0.0.0/16
    |
    |               /---- 10.0.128.0/19***
    |               |
    |       /---- 10.0.128.0/18
    |       |       |
    |       |       \---- 10.0.160.0/19
    |       |
     \--- 10.0.128.0/17
            |
            |               /---- 10.0.192.0/20
            |               |
            |       /---- 10.0.192.0/19
            |       |       |
            |       |       |               /---- 10.0.208.0/22***
            |       |       |               |
            |       |       |       /---- 10.0.208.0/21
            |       |       |       |       |
            |       |       |       |       \---- 10.0.212.0/22
            |       |       |       |        
            |       |       \---- 10.0.208.0/20
            |       |               |
            |       |               \---- 10.0.216.0/21
            |       |
            \---- 10.0.192.0/18
                    |
                    \---- 10.0.224.0/19

因此,例如,要查找/ 24的块,首先遍历树(以任何顺序),查找大小为/ 24的块。如果你找到一个,你就完成了;标记它已分配并返回它。在遍历期间,跟踪您找到的最小块更大的块大于/ 24。 (显然,如果您到达树中任何小于/ 24的节点,则不需要再进行其子树遍历,因为该大小只会从那里下移。)

如果找不到一个完全为/ 24的那个,那么你会转到你保存的那个大小比/ 24大的块。然后,您将该块切成两半,将其替换为两个半尺寸块。抓住其中任何一个(任意)。如果是/ 24你已经完成了。如果没有,你可以直接裁掉两个块,依此类推。最终,你会找到一个/ 24。

假设大小比/ 24大的最小块是/ 21。通过以这种方式递归地雕刻它,你将把/ 21雕刻成:两个/ 24个(你分配一个,一个仍然可用),一个可用/ 23,一个可用/ 22。

如果一个块返回给你,你可以将它与它的伴随块组合,如果该块可用(即一个叶子而没有标记为已分配)。如果您可以将其与其伴侣结合使用,那么可能能够将其父母与父母的双胞胎结合起来。

(顺便说一下,这与@ mcdowella的答案兼容;只是添加细节。)

答案 1 :(得分:0)

我想如果你能找到Knuth对https://en.wikipedia.org/wiki/Buddy_memory_allocation的描述(在#34;计算机编程的艺术"第一卷),你会看到各种属性证明了它,并且它们可能适用于你正在考虑的那种基于树的分配器,我认为这可以归结为类似的东西。

将可用的地址范围跟踪为一组大小为2的幂的块,以2的幂的倍数对齐。如果您有两个可以合并的块来生成下一个最大尺寸的合法块,那么您应该这样做。

当询问地址空间块时,从集合中可能的最小块分配它,并分配一个大小为2的幂的块。如果在分配后剩余空间,请将其转换为两个大小块的地址对齐功率。

如果向您返回先前分配的地址空间块,请将其添加到大小为2的幂块中,如果可能,将其与其邻居块(其伙伴)合并。