跳到主要内容

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 计数的拆分. seqErrOoo 和 seqErrDup 通过比较序列号实现. 实现以最近收到的 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)