为什么不“禁止碎片”标志被禁用?

时间:2014-10-18 14:23:07

标签: python sockets python-2.7

我正在尝试使用IP_MTU_DISCOVER对udp数据包碎片设置不同的setsockopt()值的效果,并找到(从man的{​​{1}}页面)我需要将其值设置为ip(7)IP_PMTUDISC_WANT以关闭“请勿片段”标记。但是,当我尝试发送数据包时,我得到IP_PMTUDISC_DONT

socket.error: [Errno 90] Message too long

谢谢

1 个答案:

答案 0 :(得分:2)

让我们首先回顾一下PMTU如何为UDP工作。

  1. IP端点以给定的MTU开始,通常是其直接连接的MTU。
  2. 发送数据包时,端点始终设置DF位。
  3. 如果转接路由器决定在不对数据包进行分段的情况下无法发送数据包,则会返回错误代码为4的ICMP Destination Unreachable数据包和下一跳MTU。
  4. IP端点收到ICMP无法访问并调整其PMTU。
  5. IP端点决定如何处理原始数据包(重新传输,信号应用层,......)。
  6. 这里需要注意的是,PMTU不会自动发生。在您(应用程序)开始发送实际数据之前,没有内置的探测包可以找出MTU。

    因此Linux使用以下标志控制此(对于数据报):

    • IP_PMTUDISC_WANT如上所述执行PMTU。如果应用程序发送的数据包对于已知的MTU而言太大,则套接字层将对其进行分段。传出数据包(包括片段)将设置DF位。
    • IP_PMTUDISC_DONT不要进行PMTU发现。
    • IP_PMTUDISC_DO PMTU发现。如果应用程序发送的数据包对于已知的MTU来说太大,请向应用程序发送错误。
    • IP_PMTUDISC_PROBE设置DF位进行PMTU发现,但忽略当前学习的MTU。因此,如果应用程序发送过大的数据包,它会尝试将其发送出去。这对于不时发送探测以查看PMTU是否没有增加非常有用。

    现在,通知的一部分是IP_PMTUDISC_DONT未指定如果数据包实际上大于您当前的MTU(即您的直接链接之一)该怎么办。所以很可能它将这个选择留给实际必须发送数据包的接口。由于未发送DF位,大多数接口实际上应该对数据包进行分段。但是,您使用链接本地接口,该接口通常是具有较少功能的软件接口。您的发行版可能不支持碎片,因此会发送错误。这是有道理的,从我的机器获取此输出:

    In [6]: s.getsockopt(socket.IPPROTO_IP, 14) #14 = IP_MTU, just wasn't in my python lib.
    Out[6]: 16436
    

    这表明链路本地接口的MTU在网络方面相当庞大,那么为什么要开始支持碎片呢?话虽这么说,在我的系统上,这实际上工作正常。