摘要

  • RFC 3542 将套接字持久保存的 IPv6 选项,与只附着于一条消息的辅助数据分开。同名辅助数据只覆盖同名持久选项,其余默认值仍然有效。
  • 这种范围有明确边界:零长度的辅助数据可以让单个数据报暂时不带某项选项;队列中已有的数据报可能缺少后来才请求的接收元数据;TCP 的发送调用也不对应单个传输分段。

设想一个长期存在的 UDP 套接字,应用用它发送诊断流量。程序已经选择出口接口,并设定了应作用于每个数据报的 IPv6 默认选项。现在有一条特殊消息需要换一条路。如果实现把这次例外理解为替换整组默认值,数据报也许确实走上了指定路线,却同时丢掉了应用从未打算更改的其他设置。

RFC 3542 于 2003 年 5 月发布,标题为 Advanced Sockets Application Program Interface (API) for IPv6。它属于 Informational 文档,并不是规定网络线上报文格式的协议标准。它要协调的是应用程序与内核之间的接口:应用能够提出什么请求,而不是网络最终一定发送了什么。一次 API 调用成功,只能证明接口接受了请求,不能单独证明数据报实际发出或抵达了目的地。

看它替代的 RFC 2292,便能理解规则为何改变。早期接口把若干持久选项作为一个集合来设置;与某条消息关联的辅助数据也可能取代这个集合。RFC 3542 将更多选项拆开,让每项控制都可以单独寻址。既然状态从整块配置变成彼此独立的选项,覆盖规则也就不应仍以整组为单位:只有同名选项才被临时替换。

这并非编程风格上的小事,而是例外影响范围的界定。如果套接字保存了出口接口、流量类别和扩展头处理等不同选择,一条针对路由的消息级辅助数据便不应顺便清除其他设置。内核在构造数据报时,合并套接字默认状态与这次窄范围的例外;而“请求已经合并”仍不等于“观察到了实际发出的数据包”。

接口还允许请求一种明确的缺席。应用可将 IPV6_HOPOPTS 设为持久选项,再为某一条消息提供同类型但长度为零的辅助数据,使这一个数据报不携带逐跳选项头。这里的零不是“忘掉全部默认值”,而是一次性关闭一个有名字的选项。除非应用另行改动,下一条数据报仍会回到先前保存的默认值。

接收侧的问题在于时间顺序。应用启用 IPV6_RECVxxx 选项后,recvmsg() 才能把可用的分组信息作为辅助数据返回。如果预期的数据对象没有出现,可能是报文本来就没有相关信息。但 RFC 3542 还提醒:在接收选项启用前已经进入队列的数据报,可能不会带上新请求的元数据。因此,“没有元数据”可能是报文内容的证据,也可能只是观察开始得太迟;不能仅凭这个空缺还原线上事实。

TCP 则划出了数据报类比的边界。RFC 3542 没有为 TCP 定义相同的逐次发送辅助控制,因为应用一次发送调用与线上一个 TCP 分段之间并非一一对应。重传的分段可能使用旧的或新的持久选项,文档不承诺一个它无法与单条消息对应的控制边界。它也没有定义某些可选的 TCP 接收信息,并明确警告不要把这些信息作为访问控制依据。

历史例子也必须标注年代。RFC 3542 展示了 RFC 2460 时期的 IPv6 0 型路由头。如今 IPv6 基础规范是 RFC 8200;旧文档中的例子可以说明当时 API 的表达能力,不能被误读成现在的路由建议。

RFC 3542 的历史核心,是把例外圈得更小:RFC 2292 的整组替换,转为只覆盖同名选项。想证明系统的实际行为,就必须分开记录调用前的套接字状态、这条消息附带的辅助数据、观察到的数据报,以及后续结果。sendmsg() 返回成功,是接口记录了意图;要证明意图成为线上行为,仍需独立的分组观测。

来源