为什么不在包含 NDP 邻居请求的 IPv6 数据包中放置单播地址而不是被请求节点的多播地址?

网络工程 ipv6 协议理论 多播 民进党
2021-07-14 23:57:00

这是为什么 NDP Neighbor Solicitation 消息被发送到被请求节点地址的后续问题.

总结:假设我会发送一个 IPv6 数据包并将我想知道的主机的单播地址作为目标地址。然后我将此数据包放入以太网帧中,并将多播 MAC 地址33:33:xx:xx:xx:xx作为目的地。接收主机的 NIC 将接受该帧并将其发送以供进一步处理。内核将根据(IPv6 单播)目标地址接受或拒绝数据包,而无需查看. 这样看起来效率会更高。为什么邻居发现不能像这样工作?

这个问题似乎在评论中得到了解决:IPv6 请求节点组播地址是组播 MAC 地址的基础,因此 IPv6 数据包中的目标字段需要是请求节点组播地址。但是协议设计者是决定 ND应该像这样工作,还是ND像这样工作是否有技术必要性

(我可以用这种方法想到的一个问题是,当我请求不在同一链路上的设备的全局单播地址时,路由器可能会将我的数据包路由到链路之外,这将是不需要的行为。)

4个回答

IPv6 邻居发现的目的是在连接的子网上获取一个已知的 IPv6 地址并获得相应的 MAC 地址。这使您能够将 L3 IPv6 数据包封装在 L2 帧中并在 L2 介质上发送。

这与 IPv4 ARP 非常相似,您可以在连接的子网上获取已知的 IPv4 地址,并获取相应的 MAC 地址。

诀窍是,您需要通过发送 L2 帧来获取您的信息。您需要具有该帧的有效 L2 目标地址。但是您还没有该帧的 L2 单播目的地。

让我们看一下 IPv4 ARP 示例:

这是来自 192.168.0.10 的 192.168.0.19 的 IPv4 ARP:

For reference:
192.168.0.10 = c0a8 000a
192.168.0.19 = c0a8 0013
My ethernet = 685b 3589 0a04

[iMac:~] droot% sudo tcpdump arp -x
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on pktap, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
18:58:01.528290 ARP, Request who-has 192.168.0.19 tell 192.168.0.10, length 28
    0x0000:  ffff ffff ffff 685b 3589 0a04 0806 0001
    0x0010:  0800 0604 0001 685b 3589 0a04 c0a8 000a
    0x0020:  0000 0000 0000 c0a8 0013

在上面的例子中,为了保证帧会被目的地解码,目的地有一个未知的 L2 MAC 地址,ARP 将 L2 以太网帧发送到目的地 ff.ff.ff.ff.ff.ff,以太网广播地址。

这种 1982 年设计的 ARP 协议 (RFC 826) 效率低下。每个 ARP 请求都会导致子网上每个主机的中断。

IPv6 的设计者希望做得更好。 他们只希望预期目的地“侦听”邻居发现数据包。 他们很乐意将以太网帧的目的地设为 IPv6 目的地。

问题一:目的MAC地址为48位。IPv6 地址是 128 位。

这是来自 fe80::c0e:acdb:30a3:482c 的链路本地地址 fe80::aaaa:aaaa:aaaa:aaaa 的 IPv6 邻居发现/请求请求

[iMac:~] droot% sudo tcpdump -x -v icmp6 && ip6 == 135
Password:
tcpdump: data link type PKTAP
tcpdump: listening on pktap, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
19:33:58.748554 IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) imac.local > ff02::1:ffaa:aaaa: [icmp6 sum ok] ICMP6, neighbor solicitation, length 32, who has fe80::aaaa:aaaa:aaaa:aaaa
      source link-address option (1), length 8 (1): 68:5b:35:89:0a:04
    0x0000:  3333 ffaa aaaa 685b 3589 0a04 86dd 6000
    0x0010:  0000 0020 3aff fe80 0000 0000 0000 0c0e
    0x0020:  acdb 30a3 482c ff02 0000 0000 0000 0000
    0x0030:  0001 ffaa aaaa 8700 4cfc 0000 0000 fe80
    0x0040:  0000 0000 0000 aaaa aaaa aaaa aaaa 0101
    0x0050:  685b 3589 0a04

第一个改进是,这实际上是一个发往 IPv6 多播地址 ff02::1:ffaa:aaaa 的 ICMPv6 数据包。我们不需要为每个第 2 层技术定义一个单独的类似 ARP 的协议。我们使用 L3-multicast 并定义一个 L3-multicast to L2-multicast 协议。IPv6 邻居发现使用 ICMPv6 消息类型 135。

我们不能使用 IPv6 单播目的地作为邻居发现目的地,因为我们不知道如何将 128 位 IPv6 单播地址编码为 48 位以太网单播地址。

但是我们可以定义一个规则来从我们的 L3 单播目的地选择一个特定的 L3 多播目的地。来自 RFC4291 https://www.rfc-editor.org/rfc/rfc4291#section-2.7.1

   Solicited-Node multicast address are computed as a function of a
   node's unicast and anycast addresses.  A Solicited-Node multicast
   address is formed by taking the low-order 24 bits of an address
   (unicast or anycast) and appending those bits to the prefix
   FF02:0:0:0:0:1:FF00::/104 resulting in a multicast address in the
   range

         FF02:0:0:0:0:1:FF00:0000

   to

         FF02:0:0:0:0:1:FFFF:FFFF

所以我们对 fe80::aaaa:aaaa:aaaa:aaaa 的 IPv6 单播请求变成了对 ff02::1:ffaa:aaaa 的 ICMPv6 邻居请求请求,ff02::1:ffaa:aaaa 是一个 IPv6 多播地址。

对于 IPv6 L3 多播地址,我们有一个规则:它们可以在 L2 目的地为 33:33:xx:xx:xx:xx 的线路上传输,其中 L3 地址的最后 32 位被转换为 L3 地址的最后 32 位。 L2地址!

这导致此目标 mac 地址:

fe80::aaaa:aaaa:aaaa:aaaa -> ff02::1:ffaa:aaaa  -> 3333.ffaa.aaaa

什么是关于这个凉爽的是,这并不会导致对在网络上的每台主机中断。仅侦听 3333.ffaa.aaaa 的 L2 多播的主机。假设最后 24 位是“随机”(不是真的),那将是 1600 万 (2^24) 个主机中的 1 个。

有一些复杂性,但这只是因为我们有一些规则:

  1. 将 IPv6 L3 单播地址转换为用于邻居请求的 IPv6 L3 组播地址的规则
  2. 将 IPv6 L3 组播地址转换为 L2 组播地址进行传输的规则。

我们不能这样做:

fe80::aaaa:aaaa:aaaa:aaaa (IPv6 unicast)
-> fe80::aaaa:aaaa:aaaa:aaaa (ICMPv6 multicast?)
-> ??

我们只是不知道如何将 IPv6 单播地址转换为 L2 地址。由于我们要从 128 位变为 48 位,因此在某些时候我们必须使用多->一映射。在 IPv4 ARP 中,我们使用以太网广播(all->one)。在 IPv6 中,我们使用 L3 多播/L2 多播(多->一)。

NDP 将在源主机中填充一个表,这样源主机只需在开始时发现目标二层地址,然后就可以向目标发送单播二层帧。

如果目标主机没有向源主机提供其单播第 2 层地址(响应 NDP 请求),而不是通过将有效负载向上发送到网络堆栈来简单地处理 IPv6 数据包,那么源主机将始终需要使用将所有帧发送到目标主机的多播第 2 层地址(主机之间的大多数流量由不止一个帧组成)。这将是低效的,因为交换机需要将所有多播帧转发到所有交换机接口,将流量放置在不需要或不需要的链路上。

效率是因为源只需要请求一次目的二层地址(发送到所有交换机链路),然后它发送的其余帧可以使用单播二层目的地址(交换机将然后只将帧发送到可以找到目的地的单个接口)。

这里的脱节是第 3 层不指定第 2 层信息,也不一定知道第 2 层涉及什么。因此,虽然在逻辑上可能构建一个包含在以太网帧(大概)中的单播 L3 信息的数据包(实际上是帧,因为我们正在深入研究 L2),但您会跳过很多线条并打破几条规则来做到这一点。任何强制执行这些规则的安全策略都会破坏您的“创新优化”。

(提示:这并不像您想象的那么优化。与查看 NS 请求相比,查看要丢弃的 L3 标头只是稍微减少了处理。因为它被发送到第 2 层多播目的地,多个系统当只有一个人想要它时可能会看到它。多播的要点是减少从所有的足迹——IPv4 ARP广播——到一些——IPv6 ND。)

您不能将 NDP 数据包发送到定义的 MAC 地址(因为 NDP 用于知道设备的 MAC 地址是什么),因此您必须使用多播。

对于不在同一链路上的设备的全局单播地址的请求,也是不可能的。如果它不在同一链路上,您将在 FIB 中进行查找,然后使用提供的下一跳(在同一链路上)。