为什么不是“不要碎片"?标志被禁用? [英] Why isn't "dont fragment" flag getting disabled?

查看:44
本文介绍了为什么不是“不要碎片"?标志被禁用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 udp 数据包碎片上使用 setsockopt() 设置不同的 IP_MTU_DISCOVER 值的效果并发现(来自 man 页面ip(7)) 我需要将它的值设置为 IP_PMTUDISC_WANTIP_PMTUDISC_DONT 以关闭不分段"标志.但是,当我尝试发送数据包时,我收到 socket.error: [Errno 90] Message too long.

I was trying out the effects of setting different IP_MTU_DISCOVER values using setsockopt() on udp packet fragmentation and found out (from man page of ip(7)) that i need to set it's value to IP_PMTUDISC_WANT or IP_PMTUDISC_DONT to turn off "don't fragment" flag. However, i get socket.error: [Errno 90] Message too long when i try to send the packet.

import IN, socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

hostname = 'localhost'
s.connect((hostname, 1060))

s.setsockopt(socket.IPPROTO_IP, IN.IP_MTU_DISCOVER, IN.IP_PMTUDISC_DONT)
mtu = s.getsockopt(socket.IPPROTO_IP, IN.IP_MTU)

print 'MTU:', mtu
s.send('.' * (mtu + 1))
print 'Big packet sent'

谢谢

推荐答案

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

Let's first do a recap of how PMTU works for UDP.

  1. IP 端点以给定的 MTU 开头,通常是其直接连接链路的 MTU.
  2. 发送数据包时,端点总是设置 DF 位.
  3. 如果中转路由器决定它不能在不将数据包分段的情况下发送数据包,它将返回带有错误代码 4 和下一跳 MTU 的 ICMP Destination Unreachable 数据包.
  4. IP 端点收到 ICMP 不可达并调整其 PMTU.
  5. IP 端点决定如何处理原始数据包(重传、信号应用层等).

这里需要特别注意的是 PMTU 不会自动发生.在您(应用程序)开始发送实际数据之前,没有内置的探测数据包会找出 MTU.

Very important to note here is that PMTU does not happen automatically. There is no built-in probe packet that will find out the MTU before you (the application) starts sending actual data.

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

So Linux controls this (for datagrams) using the following flags:

  • IP_PMTUDISC_WANT 如上所述执行 PMTU.如果应用程序发送的数据包对于已知 MTU 来说太大,则套接字层会将其分段.传出数据包(包括片段)将设置 DF 位.
  • IP_PMTUDISC_DONT 不要进行 PMTU 发现.
  • IP_PMTUDISC_DO 进行 PMTU 发现.如果应用程序发送的数据包对于已知 MTU 来说太大,则向应用程序发送错误.
  • IP_PMTUDISC_PROBE 设置 DF 位以进行 PMTU 发现,但忽略当前学习的 MTU.因此,如果应用程序发送了一个太大的数据包,它无论如何都会尝试将其发送出去.这对于不时发送探测以查看 PMTU 是否没有增加很有用.
  • IP_PMTUDISC_WANT Performs PMTU as described above. If the application sends a packet that is too large for the known MTU, the socket layer will fragment it. Outgoing packets (including fragments) will have the DF bit set.
  • IP_PMTUDISC_DONT Don't do PMTU discovery.
  • IP_PMTUDISC_DO Do PMTU discovery. If the application sends a packet that is too large for the known MTU, send an error to the application.
  • IP_PMTUDISC_PROBE Sets the DF bit to do PMTU discovery but ignores the currently learned MTU. So if the application sends a too large packet, it will try to send it out anyway. This is useful to send a probe from time to time to see if the PMTU hasn't increased.

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

Now one part of notice is that IP_PMTUDISC_DONT does not specify what to do if the packet is actually larger than your current MTU, i.e. the one of your direct link. So most likely it leaves this choice up to the interface that actually has to send out the packet. Most interfaces should actually fragment the packet as the DF bit is not sent. However, you use the link-local interface which is a usually a software interface with a bit less capabilities. It is possible that on your distribution this does not support fragmentation and therefore sends the error. This makes sense, take this output from my machine:

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

这表明链路本地接口的 MTU 就网络而言是相当大的,所以为什么要从一开始就支持分段.话虽如此,在我的系统上,这实际上运行良好.

This shows that the MTU for the link-local interface is quite huge in network terms, so why should it bother supporting fragmentation to begin with. That being said, on my system this actually worked fine.

这篇关于为什么不是“不要碎片"?标志被禁用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆