<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>分包 · XB 现场笔记</title><link>https://www.xbcatm.com/zh/tags/%E5%88%86%E5%8C%85/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://www.xbcatm.com/zh/tags/%E5%88%86%E5%8C%85/index.xml" rel="self" type="application/rss+xml"/><item><title>IPv6 路由器报告超大报文，由源端决定怎样适应路径</title><link>https://www.xbcatm.com/zh/posts/ipv6-fragmentation-happens-at-source/</link><pubDate>Wed, 06 Oct 2027 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/posts/ipv6-fragmentation-happens-at-source/</guid><description>捕获 Packet Too Big 反馈，分别学习双向 MTU，并观察分片在经过路由器之前已经离开发送端。</description><content:encoded>&lt;p&gt;IPv6 路由器在向目的地转发报文时，不会替它进行分片。如果报文大于下一条链路所能承载的大小，路由器通常丢弃它，并发送 ICMPv6 Packet Too Big 反馈。源端随后可以调整报文大小，或在适当情况下通过 IPv6 分片扩展头发送分片；这些分片在目的端重组。明确各阶段由谁负责，是判断超大报文故障的基础。&lt;/p&gt;
&lt;h2 id="坏掉的样子"&gt;坏掉的样子&lt;/h2&gt;
&lt;p&gt;假定路由器会自动拆开过大的 IPv6 包，会掩盖与大小相关的故障。相同地址与路由上，小 echo 可以成功，大 echo 却失败。端点本地接口可能支持原始大小，中间链路却不支持。应检查整条路径约束，不能仅因接口配置了 MTU 1500，就推断该大小能够端到端通过，也不能用一次小探测成功替代完整大小检查。&lt;/p&gt;
&lt;p&gt;Packet Too Big 反馈缺失，会使经典发现更难学到这个限制。分片被过滤，或者其中一片丢失，也可能阻止正确重组。能够生成分片扩展头，不证明沿途策略都允许相应报文。不能把源端分片当作正确路径大小与必要控制流量的万能替代，它有自己的交付条件，需要通过对应流量验证，而不是只检查发送选项已经开启。&lt;/p&gt;
&lt;p&gt;反方向也有自己的路径估计。请求发送端学到 MTU，不会自动教会响应端怎样发送较大回复。因此双向 echo 测试需要分别了解两个方向。TCP 分段还不同于 IP 分片：TCP 发送端学到限制后，可以构造更小的段，而不必把每个 IP 包再分片。应先确定观察的是哪一层的切分，避免看到多个包就统称为分片。&lt;/p&gt;
&lt;h2 id="快速验证"&gt;快速验证&lt;/h2&gt;
&lt;p&gt;将脚本保存为 &lt;code&gt;check-ipv6-fragmentation.py&lt;/code&gt;，准备 Docker 后运行 &lt;code&gt;python3 check-ipv6-fragmentation.py&lt;/code&gt;。此前实验使用 Python 3.11.16、iproute2 6.1.0、iputils ping 和 tcpdump 4.99.3，运行于 Linux 6.12.76；本轮未重跑网络实验，以下为保留的历史观察。NET_ADMIN 与 SYS_ADMIN 支持四个嵌套命名空间。两台路由器和两个端点使用新建 veth，不修改宿主接口或路由：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;tempfile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TemporaryDirectory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nn"&gt;uuid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;recipe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FROM python@sha256:528257d48c1da0dcecc2e725d1ae34498d60c965f1241e39cd6a85a8859bdf84&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends iproute2=6.1.0-3 iputils-ping=3:20221126-1+deb12u1 nftables=1.0.6-2+deb12u2 tcpdump=4.99.3-1 traceroute=1:2.1.2-1 procps=2:4.0.2-3 &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;CMD [&amp;#34;python3&amp;#34;]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;from contextlib import ExitStack,contextmanager
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;from pathlib import Path
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;from tempfile import TemporaryDirectory
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;import json,os,select,signal,subprocess,time
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def run(*args,check=True,input=None,timeout=8):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; result=subprocess.run(args,input=input,capture_output=True,text=True,timeout=timeout)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if check:assert result.returncode==0,(args,result.returncode,result.stdout,result.stderr)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; return result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def ns(name,*args,**kwargs):return run(&amp;#39;ip&amp;#39;,&amp;#39;netns&amp;#39;,&amp;#39;exec&amp;#39;,name,*args,**kwargs)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def ip(name,*args,**kwargs):return ns(name,&amp;#39;ip&amp;#39;,*args,**kwargs)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def stop(process):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if process.poll() is None:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; process.terminate()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; try:process.wait(timeout=2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; except subprocess.TimeoutExpired:process.kill();process.wait(timeout=2)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def spawn(stack,command):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; process=subprocess.Popen(command,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; stack.callback(stop,process);return process
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def line(process,timeout=3):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert select.select([process.stdout],[],[],timeout)[0],&amp;#39;child response deadline exceeded&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; value=process.stdout.readline();assert value,process.stderr.read();return value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;@contextmanager
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def lab():
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; with TemporaryDirectory(prefix=&amp;#39;mtu-path-&amp;#39;) as directory,ExitStack() as stack:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; root=Path(directory);proc=root/&amp;#39;proc&amp;#39;;proc.mkdir();run(&amp;#39;mount&amp;#39;,&amp;#39;-t&amp;#39;,&amp;#39;proc&amp;#39;,&amp;#39;proc&amp;#39;,str(proc));stack.callback(run,&amp;#39;umount&amp;#39;,str(proc))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for name in [&amp;#39;client&amp;#39;,&amp;#39;r1&amp;#39;,&amp;#39;r2&amp;#39;,&amp;#39;target&amp;#39;]:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; run(&amp;#39;ip&amp;#39;,&amp;#39;netns&amp;#39;,&amp;#39;add&amp;#39;,name);stack.callback(run,&amp;#39;ip&amp;#39;,&amp;#39;netns&amp;#39;,&amp;#39;delete&amp;#39;,name,check=False);ip(name,&amp;#39;link&amp;#39;,&amp;#39;set&amp;#39;,&amp;#39;lo&amp;#39;,&amp;#39;up&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; def setting(name,key,value):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert name in [&amp;#39;client&amp;#39;,&amp;#39;r1&amp;#39;,&amp;#39;r2&amp;#39;,&amp;#39;target&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; path=proc/&amp;#39;sys&amp;#39;/key.replace(&amp;#39;.&amp;#39;,&amp;#39;/&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ns(name,&amp;#39;python3&amp;#39;,&amp;#39;-c&amp;#39;,f&amp;#39;from pathlib import Path; p=Path({str(path)!r});p.write_text({str(value)!r});assert p.read_text().strip()=={str(value)!r}&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; yield root,stack,setting
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def topology(setting,ipv6=False):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; links=[(&amp;#39;client&amp;#39;,&amp;#39;c0&amp;#39;,&amp;#39;r1&amp;#39;,&amp;#39;a0&amp;#39;,1,2,1,1500),(&amp;#39;r1&amp;#39;,&amp;#39;a1&amp;#39;,&amp;#39;r2&amp;#39;,&amp;#39;b0&amp;#39;,2,1,2,1280),(&amp;#39;r2&amp;#39;,&amp;#39;b1&amp;#39;,&amp;#39;target&amp;#39;,&amp;#39;t0&amp;#39;,3,1,2,1500)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for left,left_if,right,right_if,network,left_host,right_host,mtu in links:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; run(&amp;#39;ip&amp;#39;,&amp;#39;link&amp;#39;,&amp;#39;add&amp;#39;,left_if,&amp;#39;type&amp;#39;,&amp;#39;veth&amp;#39;,&amp;#39;peer&amp;#39;,&amp;#39;name&amp;#39;,right_if)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for name,interface,host in [(left,left_if,left_host),(right,right_if,right_host)]:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; run(&amp;#39;ip&amp;#39;,&amp;#39;link&amp;#39;,&amp;#39;set&amp;#39;,interface,&amp;#39;netns&amp;#39;,name);ip(name,&amp;#39;link&amp;#39;,&amp;#39;set&amp;#39;,interface,&amp;#39;mtu&amp;#39;,str(mtu))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; address=f&amp;#39;2001:db8:&lt;/span&gt;&lt;span class="si"&gt;{network}&lt;/span&gt;&lt;span class="s2"&gt;::&lt;/span&gt;&lt;span class="si"&gt;{host}&lt;/span&gt;&lt;span class="s2"&gt;/64&amp;#39; if ipv6 else f&amp;#39;10.210.&lt;/span&gt;&lt;span class="si"&gt;{network}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;{host}&lt;/span&gt;&lt;span class="s2"&gt;/30&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; ip(name,&amp;#39;addr&amp;#39;,&amp;#39;add&amp;#39;,address,&amp;#39;dev&amp;#39;,interface,*([&amp;#39;nodad&amp;#39;] if ipv6 else []));ip(name,&amp;#39;link&amp;#39;,&amp;#39;set&amp;#39;,interface,&amp;#39;up&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; family=&amp;#39;-6&amp;#39; if ipv6 else &amp;#39;-4&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for name in [&amp;#39;r1&amp;#39;,&amp;#39;r2&amp;#39;]:setting(name,&amp;#39;net.ipv6.conf.all.forwarding&amp;#39; if ipv6 else &amp;#39;net.ipv4.ip_forward&amp;#39;,1)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; routes=[(&amp;#39;client&amp;#39;,&amp;#39;default&amp;#39;,&amp;#39;2001:db8:1::1&amp;#39; if ipv6 else &amp;#39;10.210.1.1&amp;#39;),(&amp;#39;target&amp;#39;,&amp;#39;default&amp;#39;,&amp;#39;2001:db8:3::1&amp;#39; if ipv6 else &amp;#39;10.210.3.1&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; (&amp;#39;r1&amp;#39;,&amp;#39;2001:db8:3::/64&amp;#39; if ipv6 else &amp;#39;10.210.3.0/30&amp;#39;,&amp;#39;2001:db8:2::2&amp;#39; if ipv6 else &amp;#39;10.210.2.2&amp;#39;),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; (&amp;#39;r2&amp;#39;,&amp;#39;2001:db8:1::/64&amp;#39; if ipv6 else &amp;#39;10.210.1.0/30&amp;#39;,&amp;#39;2001:db8:2::1&amp;#39; if ipv6 else &amp;#39;10.210.2.1&amp;#39;)]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for name,destination,gateway in routes:ip(name,family,&amp;#39;route&amp;#39;,&amp;#39;add&amp;#39;,destination,&amp;#39;via&amp;#39;,gateway)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if ipv6:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; deadline=time.monotonic()+4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; while any(&amp;#39;tentative&amp;#39; in ip(name,&amp;#39;-6&amp;#39;,&amp;#39;address&amp;#39;,&amp;#39;show&amp;#39;).stdout for name in [&amp;#39;client&amp;#39;,&amp;#39;r1&amp;#39;,&amp;#39;r2&amp;#39;,&amp;#39;target&amp;#39;]):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert time.monotonic()&amp;lt;deadline,&amp;#39;IPv6 link-local DAD did not finish&amp;#39;;time.sleep(.02)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def nft(name,script):return ns(name,&amp;#39;nft&amp;#39;,&amp;#39;-f&amp;#39;,&amp;#39;-&amp;#39;,input=script)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def counters(name):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; result=&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for item in json.loads(ns(name,&amp;#39;nft&amp;#39;,&amp;#39;-j&amp;#39;,&amp;#39;list&amp;#39;,&amp;#39;ruleset&amp;#39;).stdout)[&amp;#39;nftables&amp;#39;]:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; rule=item.get(&amp;#39;rule&amp;#39;,&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if &amp;#39;comment&amp;#39; in rule:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; for expression in rule[&amp;#39;expr&amp;#39;]:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if &amp;#39;counter&amp;#39; in expression:result[rule[&amp;#39;comment&amp;#39;]]=expression[&amp;#39;counter&amp;#39;][&amp;#39;packets&amp;#39;]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; return result
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def capture(stack,root,name,interface,expression,label):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; path=root/(label+&amp;#39;.pcap&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; process=subprocess.Popen([&amp;#39;ip&amp;#39;,&amp;#39;netns&amp;#39;,&amp;#39;exec&amp;#39;,name,&amp;#39;tcpdump&amp;#39;,&amp;#39;--immediate-mode&amp;#39;,&amp;#39;-Z&amp;#39;,&amp;#39;root&amp;#39;,&amp;#39;-U&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-i&amp;#39;,interface,&amp;#39;-w&amp;#39;,str(path),expression],stdout=subprocess.DEVNULL,stderr=subprocess.PIPE,text=True)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; stack.callback(stop,process);deadline=time.monotonic()+3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; while time.monotonic()&amp;lt;deadline:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert process.poll() is None,&amp;#39;capture exited&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; if select.select([process.stderr],[],[],.1)[0] and &amp;#39;listening on&amp;#39; in process.stderr.readline():return process,path
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; raise AssertionError(&amp;#39;capture did not become ready&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;def captured(process,path):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; process.send_signal(signal.SIGINT);_,diagnostic=process.communicate(timeout=3);assert process.returncode==0,diagnostic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; return run(&amp;#39;tcpdump&amp;#39;,&amp;#39;-nn&amp;#39;,&amp;#39;-vv&amp;#39;,&amp;#39;-r&amp;#39;,str(path)).stdout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;with lab() as (root,stack,setting):
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; topology(setting,ipv6=True);target=&amp;#39;2001:db8:3::2&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; small=ns(&amp;#39;client&amp;#39;,&amp;#39;ping&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-c&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-W&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-s&amp;#39;,&amp;#39;32&amp;#39;,target);assert small.returncode==0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; tap,path=capture(stack,root,&amp;#39;client&amp;#39;,&amp;#39;c0&amp;#39;,&amp;#39;ip6&amp;#39;,&amp;#39;too-big&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; large=ns(&amp;#39;client&amp;#39;,&amp;#39;ping&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-M&amp;#39;,&amp;#39;do&amp;#39;,&amp;#39;-s&amp;#39;,&amp;#39;1400&amp;#39;,&amp;#39;-c&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-W&amp;#39;,&amp;#39;1&amp;#39;,target,check=False)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; feedback=captured(tap,path);assert large.returncode!=0 and &amp;#39;too big&amp;#39; in feedback.lower(),(large.stdout,large.stderr,feedback)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; route=ip(&amp;#39;client&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;route&amp;#39;,&amp;#39;get&amp;#39;,target).stdout;assert &amp;#39;mtu 1280&amp;#39; in route,route
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; reverse=ns(&amp;#39;target&amp;#39;,&amp;#39;ping&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-M&amp;#39;,&amp;#39;do&amp;#39;,&amp;#39;-s&amp;#39;,&amp;#39;1400&amp;#39;,&amp;#39;-c&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-W&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;2001:db8:1::2&amp;#39;,check=False)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; reverse_route=ip(&amp;#39;target&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;route&amp;#39;,&amp;#39;get&amp;#39;,&amp;#39;2001:db8:1::2&amp;#39;).stdout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert reverse.returncode!=0 and &amp;#39;mtu 1280&amp;#39; in reverse_route,(reverse.stdout,reverse.stderr,reverse_route)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; tap,path=capture(stack,root,&amp;#39;client&amp;#39;,&amp;#39;c0&amp;#39;,&amp;#39;ip6 and src 2001:db8:1::2&amp;#39;,&amp;#39;source-fragments&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; fragmented=ns(&amp;#39;client&amp;#39;,&amp;#39;ping&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-M&amp;#39;,&amp;#39;dont&amp;#39;,&amp;#39;-s&amp;#39;,&amp;#39;2000&amp;#39;,&amp;#39;-c&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-W&amp;#39;,&amp;#39;2&amp;#39;,target,check=False)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; trace=captured(tap,path);assert fragmented.returncode==0,(fragmented.stdout,fragmented.stderr,trace)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert &amp;#39;frag (&amp;#39; in trace and trace.count(&amp;#39;frag (&amp;#39;)&amp;gt;=2,trace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; refused=ns(&amp;#39;client&amp;#39;,&amp;#39;ping&amp;#39;,&amp;#39;-6&amp;#39;,&amp;#39;-n&amp;#39;,&amp;#39;-M&amp;#39;,&amp;#39;do&amp;#39;,&amp;#39;-s&amp;#39;,&amp;#39;2000&amp;#39;,&amp;#39;-c&amp;#39;,&amp;#39;1&amp;#39;,&amp;#39;-W&amp;#39;,&amp;#39;1&amp;#39;,target,check=False)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; assert refused.returncode!=0 and &amp;#39;too long&amp;#39; in (refused.stdout+refused.stderr).lower(),(refused.stdout,refused.stderr)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; print(json.dumps({&amp;#39;small_echo&amp;#39;:small.stdout,&amp;#39;oversize_before_learning&amp;#39;:{&amp;#39;stdout&amp;#39;:large.stdout,&amp;#39;stderr&amp;#39;:large.stderr,&amp;#39;returncode&amp;#39;:large.returncode},
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#39;packet_too_big_capture&amp;#39;:feedback,&amp;#39;learned_route&amp;#39;:route,&amp;#39;reverse_path_learning&amp;#39;:reverse.stdout+reverse.stderr,&amp;#39;reverse_route&amp;#39;:reverse_route,&amp;#39;source_fragmented_echo&amp;#39;:fragmented.stdout,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#39;source_side_fragment_capture&amp;#39;:trace,&amp;#39;dont_fragment_after_learning&amp;#39;:{&amp;#39;returncode&amp;#39;:refused.returncode,&amp;#39;stdout&amp;#39;:refused.stdout,&amp;#39;stderr&amp;#39;:refused.stderr}}))
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;xbcatm-mtupath-&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;docker&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;TemporaryDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;);(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Dockerfile&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;build&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-t&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;run&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--rm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-i&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--network&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--cap-add&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NET_ADMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--cap-add&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SYS_ADMIN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--memory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;256m&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--pids-limit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;128&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;python3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;program&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;sort_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-f&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;image&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rm&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;端点链路 MTU 为 1500，中间路由器链路为 1280。静态全局地址使用 nodad，设置过程同时明确等待自动生成的链路本地地址离开 tentative 状态。这个就绪检查避免把最初地址设置延迟误判成转发或 MTU 故障。实验没有声称验证重复地址检测算法本身，只是把网络准备完成作为后续比较的前置条件。&lt;/p&gt;
&lt;p&gt;小 echo 往返首先成功。随后使用 do 策略发送 1400 字节 echo 载荷，加上基础 IPv6 与 ICMPv6 头后，形成 1448 字节报文。它适合源端接口，却超过中间链路。捕获显示原始请求和路由器返回的 Packet Too Big，报告 MTU 1280；客户端路由查询随后记录该值。这样能区分源端本来就拒绝发送，与中间路径发现更小限制。&lt;/p&gt;
&lt;p&gt;目标向客户端发送对应的超大探测，也为反向路径学到 MTU 1280。这一步明确准备较大 echo 回复，不假定一个端点的缓存同时覆盖两个方向。两个失败发现探测都保留在输出中，包含路由器反馈和路由状态，让后续成功所依赖的设置可见。请求方向已经正确，不代表响应方向无需独立检查。&lt;/p&gt;
&lt;p&gt;客户端接着用 dont 策略发送 2000 字节 echo 载荷，允许根据已知上限在源端分片。抓包位于客户端接口，并限定客户端源地址，在两台路由器处理之前，就看到了标识相同的两个分片。工具显示数据偏移为零和 1232 字节，分片数据长度合计 2008，包含 ICMPv6 头。这直接证明分片已由发送端产生，而非后来由路由器拆开。&lt;/p&gt;
&lt;p&gt;目的端重组并完成大小正确的返回交换后，echo 成功。用 do 策略重复相同载荷，则得到本地 message-too-long 错误与 MTU 1280。结果区分了路由器报告此前未知瓶颈、发现后源端主动分片，以及已知较小上限后的本地拒绝。这些是不同失败和交付阶段，不应全都写成同一种“包太大所以网络不通”。&lt;/p&gt;
&lt;h2 id="推荐分片之前先诊断大小与方向"&gt;推荐分片之前，先诊断大小与方向&lt;/h2&gt;
&lt;p&gt;计算包大小时包含所有相关头部。每片还会增加自己的分片头，IPv6 Fragment Offset 字段以八字节为单位，诊断工具却可能显示字节偏移。重建范围时必须统一单位。本例两个源端分片提供具体证据；另一份捕获里没有看到某片，则仍需要接口、方向与捕获时机等上下文，不能直接推断由哪一段网络丢弃。&lt;/p&gt;
&lt;p&gt;IPv6 路由器仍可以作为自身报文的源端，这与替过境流量分片属于不同角色。阅读路由器或隧道端点的捕获时，应保持这个区分。也要区分路径最小链路 MTU 与应用选择的载荷大小：二者通过协议开销及发送端组包策略关联，并非同一个数字。角色和层次明确，才能准确解释设备为何生成某种报文。&lt;/p&gt;
&lt;p&gt;条件允许时，优先让应用和传输行为适应已知路径，并通过真实流量验证必要的分片处理。本例证明源端位置、反馈、路由学习与一次成功的分片 echo，没有验证任意扩展头链、分片过滤策略或所有传输协议在控制消息缺失时的行为。结论应停留在已经观察的范围，后续配置则需要与实际负载相匹配的证据。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8200.html"&gt;RFC 8200 IPv6&lt;/a&gt;，源端分片、分片扩展头与目的端重组，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc8201.html"&gt;RFC 8201 IPv6 Path MTU Discovery&lt;/a&gt;，Packet Too Big 反馈与各方向路径估计，已核验 2026-10-15。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man8/ping.8.html"&gt;Linux ping(8)&lt;/a&gt;，载荷大小与 do/dont 路径 MTU 策略，已核验 2026-10-15。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>