【问题标题】:having trouble returning a best possible interface from a set of routing entries无法从一组路由条目返回最佳接口
【发布时间】:2012-04-01 10:14:01
【问题描述】:

所以我试图从路由条目中返回一个最佳匹配接口。但是,它并不完全按照我想要的方式工作。我以应有的方式返回了 6 个值中的 5 个,但我很确定路由表中有一百万个条目,我的算法将不起作用。 我正在使用二进制搜索来解决这个问题。但是,例如,我要返回的接口的 ipaddress 小于我作为参数传递的 ipaddress,则二进制搜索算法不起作用。结构如下:

struct routeEntry_t
{
    uint32_t ipAddr;
    uint32_t netMask;
    int interface;
};
routeEntry_t routing_table[100000];

假设路由表如下所示:

{ 0x00000000, 0x00000000, 1 }, // [0]

{ 0x0A000000, 0xFF000000, 2 }, // [1]

{ 0x0A010000, 0xFFFF0000, 10 }, // [2]

{ 0x0D010100, 0xFFFFFF00, 4 }, // [3]

{ 0x0B100000, 0xFFFF0000, 3 }, // [4]

{ 0x0A010101, 0xFFFFFFFF, 5 }, // [5]

输入/输出示例:

  1. 常规搜索

输入:0x0D010101 输出:4(条目 [3])

输入:0x0B100505 输出:3(条目 [4])

  1. 要查找任意地址,应转到默认界面。

输入:0x0F0F0F0F 输出:1(条目 [0])

  1. 要查找与多个条目匹配的地址,请取最佳匹配。

输入:0x0A010200 输出:10(条目 [2])

输入:0x0A050001 输出:2(条目 [1])

输入:0x0A010101 输出:5(条目 [5])

但我的输出看起来像 2、3、1、10、1、5。我不明白我在哪里搞砸了。你能解释一下我在哪里做错了吗?任何帮助都会很棒。提前致谢。然而,这就是我的算法的样子(假设条目已排序):

int interface(uint32_t ipAddr)

{ int 开始 = 0;

int end = SIZE-1;

int mid = 0;

vector<int> matched_entries;

vector<int>::iterator it;

matched_entries.reserve(SIZE);

it = matched_entries.begin();


if (start > end)
    return -1;

while (start <= end)
{
    mid = start + ((end-start)/2);

    if (routing_table[mid].ipAddr == ipAddr)
        return routing_table[mid].interface;
    else if (routing_table[mid].ipAddr > ipAddr)
    {
        uint32_t result = routing_table[mid].netMask & ipAddr;
        if (result == routing_table[mid].ipAddr)
        {
            matched_entries.push_back(mid);
        }
        end = mid-1;
    }
    else
    {
        uint32_t result = routing_table[mid].netMask & ipAddr;
        if (result == routing_table[mid].ipAddr)
        {
            matched_entries.insert(it,mid);
        }
        start = mid+1;
    }
}


int matched_ip = matched_entries.back();
if (routing_table[matched_ip].netMask & ipAddr)
    return routing_table[matched_ip].interface;
else
    return routing_table[0].interface;  

}

【问题讨论】:

    标签: interface routing ip-address netmask


    【解决方案1】:

    “正确”接口是具有最具体网络掩码的条目,其 IP 地址与您的输入在同一子网中。

    让我们更详细地了解网络掩码是什么,以及它们是如何工作的。

    符号

    虽然网络掩码通常以点分十进制或十六进制表示,但 IPv4 网络掩码的二进制表示始终是 32 位;也就是说,它与 IP 地址的长度完全相同。网络掩码始终以零个或多个1 位开头,并用0 位填充以完成其32 位长度。当网络掩码应用于 IP 地址时,它们会一点一点地“排列”。 IP 地址中对应于网络掩码中1 位的位决定了IP 地址的网络号;与网络掩码中的0 位对应的那些决定了设备号

    目的

    网络掩码用于将地址空间划分为更小的子网。同一子网上的设备可以直接使用 TCP/IP 协议栈相互通信。不同子网上的设备必须使用一个或多个路由器在它们之间转发数据。因为它们将子网相互隔离,所以网络掩码是创建设备逻辑分组的自然方式。例如,公司内的每个地点或部门可能有自己的子网,或者每种类型设备(打印机、PC、)可能有自己的子网。

    示例网络掩码:

    255.255.255.128FF FF FF 101111 11111111 11111111 11111000 0000
    此网络掩码指定 IP 地址的前 25 位确定网络号;最后 7 位确定设备编号。这意味着可以有 225 个不同的子网,每个子网有 27 = 128 个设备。*

    255.255.255.0    → FF FF FF 001111 1111 1111 1111 1111 1111 0000 0000
    此网络掩码指定一个包含 224 个子网的地址空间,每个子网有 28 = 256 个单独的地址。这是一种非常常见的配置——如此普遍以至于它被简单地称为“C 类”网络。

    255.255.192.0    → FF FF FC 001111 1111 1111 1111 1111 1100 0000 0000
    此网络掩码指定 222 个子网,每个子网有 210 = 1024 个地址。它可能在一个大公司内部使用,每个部门都有数百台设备,这些设备应该在逻辑上组合在一起。

    无效网络掩码(注意内部零):
    255.128.255.0     → FF 80 FF 001111 1111 1000 0000 1111 1111 0000 0000

    计算

    以下是几个示例,说明网络掩码如何确定 IP 地址的网络号和设备号。

      IP 地址:192.168.0.1C0 A8 00 01
    网络掩码:255.255.255.0FF FF FF 00
    此设备位于子网 192.168.0.0。它可以直接与 IP 地址为 192.168.0.x

    格式的其他设备通信

      IP 地址:192.168.0.1    → C0 A8 00 01
    IP地址:192.168.0.130C0 A8 00 82
    网络掩码:255.255.255.128FF FF FF 80
    这两个设备位于不同的子网中,没有路由器就无法相互通信。

      IP 地址:10.10.195.270A 0A C3 1B
    网络掩码:255.255.0.0FF FF 00 00
    这是“B 类”网络上的一个地址,可以与 10.10.0.0 网络上的 216 个地址进行通信。

    您可以看到网络掩码开头的1 位越多,它就越具体。也就是说,更多的1 位会创建一个包含更少设备的“更小”子网。

    把它们放在一起

    像您的路由表一样,包含网络掩码、IP 地址和接口的三元组。 (它还可能包含一个“成本”指标,如果它们都能够将数据路由到特定目的地,则它指示几个接口中的哪一个是“最便宜的”使用。例如,一个可能使用昂贵的专线。)

    为了路由数据包,路由器会找到与数据包目的地最具体匹配的接口。如果(addr &amp; netmask) == (dest &amp; netmask),则地址为addr 和网络掩码mask 的条目与目标IP 地址dest 匹配,其中&amp; 表示按位AND 操作。在英语中,我们想要 两个地址共有的最小子网

    为什么?假设您和一位同事在一家同时拥有公司有线网络和无线网络的大型连锁酒店中。您还连接到公司的 VPN。您的路由表可能如下所示:

    目标网络掩码接口说明 ------------ -------- --------- ----- 公司电子邮件 FFFFFF00 VPN 通过 VPN 路由所有公司流量 有线网络 FFFF0000 到全球其他酒店地址的有线流量 默认 00000000 无线 所有其他流量

    最具体的规则将通过 VPN 安全地路由您的公司电子邮件,即使地址恰好也与有线网络匹配。到连锁酒店内其他地址的所有流量都将通过有线网络进行路由。其他所有内容都将通过无线网络发送。



    * 实际上,在每个子网中,都会保留 2 个地址(最高和最低)。全1地址是广播地址:这个地址将数据发送到子网上的每个设备。当设备还没有自己的 IP 地址时,设备使用全零地址来引用自身。为简单起见,我忽略了这些。


    所以算法应该是这样的:

    initialize:
      Sort routing table by netmask from most-specific to least specific.
      Within each netmask, sort by IP address.
    
    search:
      foreach netmask {
        Search IP addresses for (input & netmask) == (IP address & netmask)
        Return corresponding interface if found
      }
      Return default interface
    

    【讨论】:

    • 感谢亚当的回复。但是我不太了解算法的初始化部分(对不起,英语不是我的第一语言)所以当你说从最具体到最不具体时,这是否意味着我应该按降序排序? “在每个网络掩码内,按 IP 地址排序”是什么意思??
    • 另一个问题亚当,你为什么在搜索中返回 IP 地址?
    • 亚当你真棒。我对网络一无所知,但现在我觉得我知道很多。都感谢你兄弟。是的,你帮我解决了这个问题,现在效果很好:-)
    【解决方案2】:

    好的,这就是我的结构和算法现在的样子。它可以工作并给我想要的结果,但是我仍然不知道如何在网络掩码中对 IP 地址进行排序。我使用 STL 排序对网络掩码进行排序。

    struct routeEntry_t
    
    {
    uint32_t ipAddr;
    uint32_t netMask;
    int interface;
    
    bool operator<(const routeEntry_t& lhs) const
    {
        return lhs.netMask < netMask;
    }
    };
    
    const int SIZE = 6;
    
    routeEntry_t routing_table[SIZE];
    
    void sorting()
    {
    //using STL sort from lib: algorithm
    sort(routing_table, routing_table+SIZE);
    }
    
    int interface(uint32_t ipAddr)
    {
    for (int i = 0; i < SIZE; ++i)
    {
        if ((routing_table[i].ipAddr & routing_table[i].netMask) == (ipAddr &   routing_table[i].netMask))
            return routing_table[i].interface;
    }
    return routing_table[SIZE-1].interface;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-02
      • 2019-08-24
      • 2017-12-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-05
      • 2019-12-02
      • 2020-09-22
      相关资源
      最近更新 更多