跳到主要内容

8. 测试负载流传输和测量状态反馈消息 (Test Load Stream Transmission and Measurement Status Feedback Messages)

本节描述协议的数据阶段 (Data phase). 发送方和接收方的角色取决于测试方向是从服务器到客户端, 还是反向进行.

8.1. 负载 PDU 和角色 (Load PDU and Roles)

测试过程中, 一个端点会根据发送速率表 (Sending Rate Table) 中的传输参数发送负载 PDU (Load PDU), 另一个端点则发送状态反馈 (Status Feedback) 消息, 用于传达接收方处的流量状况. 当服务器发送状态反馈消息时, 这些消息还会包含来自发送速率表的最新传输参数, 客户端应 (SHALL) 使用这些参数.

收到负载 PDU 时, 接收方应 (SHALL) 执行以下操作:

  1. 验证消息大小大于或等于图 9 中所示的 struct loadHdr 大小.

  2. 如果正在使用可选的 checkSum 字段, 则按照第 5.6 节所述, 验证整条消息中负载 PDU 头部部分的校验和 (checksum).

  3. 确认 PDU ID 为 0xBEEF (负载 PDU).

如果上述任一检查失败, 消息应 (SHALL) 被视为无效.

每次收到有效的负载 PDU 时, 接收方的看门狗定时器 (watchdog timer) 都应 (SHALL) 被重置. 如果正在使用 checkSum, 有效性也包括对 checkSum 的验证. 关于各端点处理看门狗超时到期的方式, 见第 9 节中的非优雅测试停止. 注意, 看门狗定时器的目的仅是检测连接故障或严重拥塞状况.

当服务器作为发送方角色发送负载 PDU 时, 它应 (SHALL) 通过当前选定的索引直接使用发送速率表中的传输参数. 该索引是基于其收到的状态反馈消息中的反馈间接确定的.

然而, 当客户端作为发送方角色发送负载 PDU 时, 它应 (SHALL) 使用服务器在其周期性状态反馈消息中传达的离散传输参数, 而不是直接引用发送速率表. 这种方式允许服务器控制各个发送速率, 以及用于决定何时和如何调整速率的算法.

服务器使用一种负载速率调整算法, 该算法会评估在负载 PDU 接收方本地取得的测量结果. 当客户端是接收方时, 信息通过周期性状态反馈消息传达给服务器. 当服务器是接收方时, 信息会被直接使用, 不过它也会通过服务器的周期性状态反馈消息传达给客户端. 这种方式是本协议独有的; 它能够搜索最大 IP 容量, 并指定其他测试工具所不具备的特定发送方行为. 虽然该算法依赖本协议, 但它本身并不是协议的组成部分.

默认算法 (B; 见 [Y.1540]) 通过 3 条路径决定下一个发送速率:

  1. 不存在损伤 (无序列错误且延迟变化较低) 时, 提高发送速率.

  2. 存在低水平损伤 (无序列错误但延迟变化水平较高) 时, 维持相同发送速率.

  3. 损伤水平高于为此目的设置的阈值并推断出"拥塞"时, 降低发送速率.

算法 B 还具有 2 种提高/降低发送速率的模式:

  • 高速模式 (fast), 用于快速达到较高发送速率, 但在根据测量结果推断出"拥塞"时也会快速退避. 如果连续反馈间隔中序列号异常数量超过阈值, 和/或所有连续间隔都包含上限延迟变化阈值异常, 则足以在一次测试中声明发生"拥塞". 连续反馈间隔的阈值应 (SHALL) 可配置, 默认值为 3 个间隔.

  • 单步模式 (single-step, slow), 其中所有速率调整都使用发送速率表中的最小增量或减量, 即 1 步. 在第一次根据测得损伤推断出"拥塞"之后, 单步模式会继续使用.

[TR-471] 中定义了一个可选的 (OPTIONAL) 负载速率调整算法, 指定为 C. 算法 C 的运行方式和模式与 B 类似, 但 C 在高速模式中使用乘法式增长以快速达到千兆范围, 并提供在测试期间重试高速模式的选项. 这会提高动态或易出错接入中的测量准确度, 例如无线电接入.

另一方面, 测试配置可以 (MAY) 使用客户端请求的固定发送速率, 通过字段 srIndexConf 指定.

客户端可以 (MAY) 在其测试激活请求 (Test Activation Request) 中传达所需的固定速率.

UDP PDU 格式布局应 (SHALL) 如下所示 (大端 AB):

 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| pduId | testAction | rxStopped |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| lpduSeqNo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| udpPayload | spduSeqErr |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| spduTime_sec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| spduTime_nsec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| lpduTime_sec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| lpduTime_nsec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rttRespDelay | checkSum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. Payload Content... .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

图 8: 负载 PDU 布局 (Load PDU Layout)

关于负载 PDU 字段的具体细节如下:

pduId: IANA 已分配十六进制值 0xBEEF (第 12.3.1 节).

testAction: 1 个八位字节字段, 指示当前测试动作为 TEST_ACT_TEST (测试进行中), TEST_ACT_STOP1 (优雅终止的第一阶段, 由服务器在本地使用), 或 TEST_ACT_STOP2 (优雅终止的第二阶段, 由服务器发送并由客户端回应). 关于测试终止的更多信息, 见第 9 节.

rxStopped: 1 个八位字节字段. 布尔值, 0 或 1, 用于向远端端点指示本地接收流量 (负载 PDU 或状态 PDU) 已停止. 所有传出的负载 PDU 或状态 PDU 应 (SHALL) 继续声明此指示, 直到再次收到流量或测试被终止. 触发此条件的时间阈值预期为看门狗超时的一个合理比例 (建议默认值为 1 秒).

lpduSeqNo: 4 个八位字节字段, 指示负载 PDU 序列号 (从 1 开始). 用于确定丢失, 乱序和重复总数.

udpPayload: 2 个八位字节字段, 指示 UDP 数据报的总负载大小, 包括负载 PDU 消息头部和负载内容 (即 UDP 套接字读取函数会返回的内容). 如果使用接收截断 (只从协议栈请求负载 PDU 消息头部八位字节), 此字段允许负载 PDU 接收方维护准确的接收统计信息.

spduSeqErr: 2 个八位字节字段, 指示负载 PDU 发送方所见的状态 PDU 丢失计数. 该计数由最近收到的状态 PDU 中的状态 PDU 序列号 (spduSeqNo) 确定. 用于向负载 PDU 接收方传达返回流量 (未加载方向) 正在发生丢失.

spduTime_sec/spduTime_nsec: 两个 4 个八位字节字段, 包含从上一条收到的状态 PDU 中取得的最新 spduTime_sec/spduTime_nsec 副本. 用于负载 PDU 接收方进行 RTT 测量.

lpduTime_sec/lpduTime_nsec: 两个 4 个八位字节字段, 包含负载 PDU 的本地发送时间. 用于负载 PDU 接收方进行单向延迟变化测量.

rttRespDelay: 2 个八位字节字段, 指示 RTT 响应延迟, 用于"调整"原始 RTT. 在负载 PDU 发送方, 它表示从收到最近状态 PDU (取得最新 spduTime_sec/spduTime_nsec 时) 到发送负载 PDU (返回先前取得的 spduTime_sec/spduTime_nsec 时) 之间的毫秒数. 当负载 PDU 接收方计算 RTT 时, 会用本地负载 PDU 接收时间减去复制的状态 PDU 发送时间 (位于负载 PDU 中), 然后从原始 RTT 中减去该值, 以校正由负载 PDU 调度导致的任何响应延迟.

checkSum: 仅覆盖负载 PDU 头部的可选校验和 (指导见第 5.6 节). 该校验和不覆盖负载内容. 计算作为构建 PDU 头部的最后一步执行, 此时 checkSum 字段设置为零.

Payload Content: 全零, 全一, 或伪随机二进制序列.

负载 PDU 应 (SHALL) 按如下方式组织 (后接任何负载内容):

<CODE BEGINS>
//
// Load header for UDP payload of Load PDUs
//
struct loadHdr {
#define LOAD_ID 0xBEEF
uint16_t pduId; // PDU ID
#define TEST_ACT_TEST 0 // Test active
#define TEST_ACT_STOP1 1 // Stop indication used locally by server
#define TEST_ACT_STOP2 2 // Stop indication exchanged with client
uint8_t testAction; // Test action
uint8_t rxStopped; // Receive traffic stopped (BOOL)
uint32_t lpduSeqNo; // Load PDU sequence number
uint16_t udpPayload; // UDP payload (bytes)
uint16_t spduSeqErr; // Status PDU sequence error count
uint32_t spduTime_sec; // Send time in last rx'd status PDU
uint32_t spduTime_nsec; // Send time in last rx'd status PDU
uint32_t lpduTime_sec; // Send time of this Load PDU
uint32_t lpduTime_nsec; // Send time of this Load PDU
uint16_t rttRespDelay; // Response delay for RTT (ms)
uint16_t checkSum; // Header checksum
};
<CODE ENDS>

图 9: 负载 PDU (Load PDU)

8.2. 状态 PDU (Status PDU)

在测试期间, 负载 PDU 接收方应 (SHALL) 按配置的反馈间隔向发送方发送状态 PDU, 但前提是至少已收到 1 个负载 PDU (即有状态可供提供). 在客户端和服务器之间存在较长延迟的测试场景中, 状态 PDU 发送定时器可能会在第一个负载 PDU 到达之前触发. 在这些情况下, 不应 (SHALL NOT) 发送状态 PDU.

当负载 PDU 发送方收到状态 PDU 消息时, 它应 (SHALL) 首先遵循第 6.2 节第 2 段列出的消息验证流程.

每次收到有效的状态 PDU 时, 负载 PDU 发送方的看门狗定时器都应 (SHALL) 被重置. 如果正在使用 checkSum 和/或 authDigest, 有效性也包括对它们的验证. 关于各端点处理看门狗超时到期的方式, 见第 9 节中的非优雅测试停止.

UDP PDU 格式布局应 (SHALL) 如下所示 (大端 AB):

 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rxDatagrams |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rxBytes |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| deltaTime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrLoss |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrOoo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrDup |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarMin |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarMax |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarSum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarCnt |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rttVarMinimum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rttVarMaximum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| accumTime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| pduId | testAction | rxStopped |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| spduSeqNo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. srStruct (28 octets) .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| subIntSeqNo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. sisSav (56 octets) .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrLoss |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrOoo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seqErrDup |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| clockDeltaMin |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarMin |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarMax |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarSum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayVarCnt |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rttMinimum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rttVarSample |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delayMinUpd | reserved1 | reserved2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tiDeltaTime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tiRxDatagrams |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| tiRxBytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| spduTime_sec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| spduTime_nsec |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| reserved3 | reserved4 | authMode |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| authUnixTime |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. authDigest (32 octets) .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| keyId | reservedAuth1 | checkSum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

图 10: 状态 PDU 布局 (Status PDU Layout)

注意, 发送速率结构在第 7 节中定义.

状态反馈消息的主要作用是把负载 PDU 接收方处的流量状况传达给负载 PDU 发送方. 已保存的子间隔统计 (Sub-Interval statistics saved, sisSav) 结构覆盖最近保存的 (已完成的) 子间隔, 而状态 PDU 本身中的类似字段覆盖最近的试验间隔 (trial interval), 即两条状态反馈消息之间并由本状态 PDU 完成的时间段. 无论角色是客户端还是服务器, 这两组统计信息都应 (SHALL) 始终由负载 PDU 接收方填充.

状态 PDU 测量字段的详细信息见 [RFC9097]. 认证和 checkSum 字段遵循与设置请求和响应相同的方法. 关于先前未定义字段的补充信息如下:

pduId: IANA 已分配十六进制值 0xFEED (第 12.3.1 节).

spduSeqNo: 4 个八位字节字段, 包含状态 PDU 序列号 (从 1 开始). 负载 PDU 发送方使用它检测状态 PDU 丢失 (未加载方向). 丢失计数会通过后续负载 PDU 中的 spduSeqErr 传回负载 PDU 接收方.

subIntSeqNo: 4 个八位字节字段, 包含与 sisSav 中所提供统计信息相对应的子间隔序列号 (从 1 开始), 用于最后保存的 (已完成的) 子间隔.

sisSav: 为最近子间隔保存的 (已完成的) 子间隔统计信息, 该子间隔由 subIntSeqNo 指定. 这些统计信息包含以下字段:

rxDatagrams: 4 个八位字节字段, 指示子间隔期间收到的数据报数量.

rxBytes: 8 个八位字节字段, 指示子间隔字节计数 (选择 8 个八位字节是为了防止高速场景下溢出).

deltaTime: 4 个八位字节字段, 指示子间隔的精确持续时间, 单位为 us. 与 rxBytes 一起用于计算接收流量速率.

seqErrLoss/seqErrOoo/seqErrDup: 3 个 4 个八位字节字段, 分别由丢失, 乱序和重复总数填充. 这些字段同时可用于子间隔和试验间隔; 它们是 [TR-471] 表 3 中 SeqErrors 计数的拆分. seqErrOooseqErrDup 通过比较序列号实现. 实现以最近收到的 n 个序列号的回看列表为基础. 每个负载 PDU 序列号都会与此回看列表进行检查. 数值 n 可取决于实现以及部署 UDPSTP 的环境的典型特征, 例如移动网络或 Wi-Fi. 当前选择的默认序列号间隔为 n=32. 特别对于 seqErrOoo, 每个连续收到的更高 seqno 都会把下一个预期 seqno 设置为 seqno+1, 低于该值的任何序列号都被视为乱序 (即延迟). 例如, 给定序列 93, 94, 95, 100, 96, 97, 101, 98, 99, 102, 103, ..., 收到 96, 97, 98 和 99 不会递增下一个预期 seqno, 并且都会被视为乱序.

delayVarMin/delayVarMax/delayVarSum/delayVarCnt: 4 个 4 个八位字节字段, 由所有收到的负载 PDU 的单向延迟变化测量值填充 (其中 avg = sum/cnt). 对于收到的每个负载 PDU, 用本地接收时间减去发送时间 (lpduTime_sec/lpduTime_nsec), 然后通过减去当前 clockDeltaMin 进行归一化. 这些字段同时可用于子间隔和试验间隔.

rttVarMinimum/rttVarMaximum (位于 sisSav 中): 两个 4 个八位字节字段, 由 subIntSeqNo 指定的子间隔中的最小和最大 RTT 延迟变化 (rttVarSample) 填充.

accumTime: 测试的累计时间, 单位为 ms, 基于每个子间隔的持续时间. 等同于测试期间每个状态 PDU 中发送的各个 deltaTime 之和, 但单位为 ms.

clockDeltaMin: 4 个八位字节字段, 指示自测试开始以来的最小时钟增量 (差值). 该值通过从负载 PDU 被接收时的本地时间中减去该负载 PDU 的发送时间 (lpduTime_sec/lpduTime_nsec) 获得. 此值用收到的第一个负载 PDU 初始化, 并在随后每次收到负载 PDU 时更新, 以维护当前 (且持续更新的) 最小值. 如果端点时钟已充分同步, 这将是以 ms 为单位的最小单向延迟. 否则, 此值可能为负, 但对于默认测试持续时间内的单向延迟变化测量仍然有效 (默认值为 10 秒). 如果测试持续时间扩展到数分钟范围, 可能发生显著时钟漂移, 因而可能需要同步的 (或至少经过良好校准的) 时钟.

rttMinimum (位于状态 PDU 中): 4 个八位字节字段, 指示自测试开始以来测得的最小"已调整" RTT. 关于"已调整"测量, 见第 8.1 节中的 rttRespDelay. RTT 通过从该负载 PDU 被接收时的本地时间中减去收到的负载 PDU 中复制的 spduTime_sec/spduTime_nsec 获得. 每次收到带有已更新 spduTime_sec/spduTime_nsec 的负载 PDU 时, 都应 (SHALL) 保持该最小值为当前值 (并持续更新). 该值必须 (MUST) 为正. 在可以建立初始值之前, 且由于零本身也是有效值, 在状态 PDU 中传达该值时应 (SHALL) 将其设置为 STATUS_NODEL.

rttVarSample: 4 个八位字节字段, 指示最近的"已调整" RTT 延迟变化测量值. 关于"已调整"测量, 见第 8.1 节中的 rttRespDelay. RTT 延迟变化通过从每个"已调整"RTT 测量值中减去当前 (且持续更新的) "已调整"RTT 最小值获得. 该最小值作为状态 PDU 中的 rttMinimum 传达, 而每个"已调整"RTT 测量值本身通过从该负载 PDU 被接收时的本地时间中减去收到的负载 PDU 中复制的 spduTime_sec/spduTime_nsec 获得. 注意, 虽然会对收到的每个负载 PDU 测量单向延迟变化, 但 RTT 延迟变化只通过已发送的状态 PDU以及随后收到的, 带有对应更新 spduTime_sec/spduTime_nsec 的第一条负载 PDU 进行采样. 当新值不可用时 (可能由于数据包丢失), 且由于零本身也是有效值, 在状态 PDU 中传达该值时应 (SHALL) 将其设置为 STATUS_NODEL.

delayMinUpd: 1 个八位字节字段. 布尔值, 0 或 1, 指示由负载 PDU 接收方测得的 clockDeltaMin 和/或 rttMinimum (位于状态 PDU 中) 已更新.

tiDeltaTime/tiRxDatagrams/tiRxBytes: 3 个 4 个八位字节字段, 由以 us 为单位的试验间隔时间以及收到的数据报和字节计数填充. 用于计算试验间隔的接收流量速率.

spduTime_sec/spduTime_nsec: 两个 4 个八位字节字段, 包含状态 PDU 的本地发送时间. 预期负载 PDU 发送方收到这些字段后, 会把它们复制到后续负载 PDU 中的 spduTime_sec/spduTime_nsec. 用于 RTT 测量.

authMode: 与第 6.1 节相同.

authUnixTime: 与第 6.1 节相同.

authDigest: 与第 6.1 节相同.

keyId: 与第 6.1 节相同.

reservedAuth1: 与第 6.1 节相同.

checkSum: 与第 6.1 节相同.

状态反馈消息 PDU (以及所包含的子间隔统计结构) 应 (SHALL) 按如下方式组织:

<CODE BEGINS>
//
// Sub-Interval statistics structure for received traffic information
//
#pragma pack(push, 1)
struct subIntStats {
uint32_t rxDatagrams; // Received datagrams
uint64_t rxBytes; // Received bytes (64 bits)
uint32_t deltaTime; // Time delta (us)
uint32_t seqErrLoss; // Loss sum
uint32_t seqErrOoo; // Out-of-order sum
uint32_t seqErrDup; // Duplicate sum
uint32_t delayVarMin; // Delay variation minimum (ms)
uint32_t delayVarMax; // Delay variation maximum (ms)
uint32_t delayVarSum; // Delay variation sum (ms)
uint32_t delayVarCnt; // Delay variation count
uint32_t rttVarMinimum; // Minimum RTT variation (ms)
uint32_t rttVarMaximum; // Maximum RTT variation (ms)
uint32_t accumTime; // Accumulated time (ms)
};
#pragma pack(pop)
//
// Status Feedback header for UDP payload of status PDUs
//
struct statusHdr {
#define STATUS_ID 0xFEED
uint16_t pduId; // PDU ID
uint8_t testAction; // Test action
uint8_t rxStopped; // Receive traffic stopped (BOOL)
uint32_t spduSeqNo; // Status PDU sequence number
struct sendingRate srStruct; // Sending Rate structure
uint32_t subIntSeqNo; // Sub-Interval sequence number
struct subIntStats sisSav; // Sub-Interval stats saved
uint32_t seqErrLoss; // Loss sum
uint32_t seqErrOoo; // Out-of-order sum
uint32_t seqErrDup; // Duplicate sum
uint32_t clockDeltaMin; // Clock delta minimum (ms)
uint32_t delayVarMin; // Delay variation minimum (ms)
uint32_t delayVarMax; // Delay variation maximum (ms)
uint32_t delayVarSum; // Delay variation sum (ms)
uint32_t delayVarCnt; // Delay variation count
#define STATUS_NODEL UINT32_MAX // No delay data/value
uint32_t rttMinimum; // Min round-trip time sampled (ms)
uint32_t rttVarSample; // Last round-trip time sample (ms)
uint8_t delayMinUpd; // Delay minimum(s) updated (BOOL)
uint8_t reserved1; // (reserved for alignment)
uint16_t reserved2; // (reserved for alignment)
uint32_t tiDeltaTime; // Trial interval delta time (us)
uint32_t tiRxDatagrams; // Trial interval receive datagrams
uint32_t tiRxBytes; // Trial interval receive bytes
uint32_t spduTime_sec; // Send time of this status PDU
uint32_t spduTime_nsec; // Send time of this status PDU
uint16_t reserved3; // (reserved for alignment)
uint8_t reserved4; // (reserved for alignment)
// ========== Integrity Verification ==========
uint8_t authMode; // Authentication mode
uint32_t authUnixTime; // Authentication timestamp
uint8_t authDigest[AUTH_DIGEST_LENGTH];
uint8_t keyId; // Key ID in shared table
uint8_t reservedAuth1; // (reserved for alignment)
uint16_t checkSum; // Header checksum
};
<CODE ENDS>

图 11: 状态 PDU (Status PDU)