4. Pseudocode Walk-Through
中文导读: 本节对应 RFC 9957 的 4. Pseudocode Walk-Through 部分, 对应文档标题为 RFC 9957 - 用于保持低时延的 DOCSIS 队列保护算法. 下方若包含英文 RFC 原文, 注册表名称, 字段名, 算法名, 对象标识符, 媒体类型, 邮箱地址, URL, 代码, ABNF, ASN.1, YANG, JSON, XML, 测试向量或参考文献条目, 均按规范原样保留, 因为这些内容需要与 RFC 文本, IANA 注册表, 实现代码或验证工具逐字一致. 中文段落用于说明本节的作用, 阅读重点和实现含义, 不改变任何协议语义或注册值.
本页包含机器可读或接近机器可读的规范材料. 对 ASN.1, YANG, JSON Schema, XML Schema, 伪代码, 注册模板, 常量表和算法标识符, 翻译时必须保留关键字, 类型名, OID, namespace, 枚举值, 字段名和语法结构. 实现者应把这些块视为生成代码, 配置模型, 验证输入或一致性测试的依据.
补充实现说明: 本页英文比例高, 是因为主要内容属于可复制的规范材料或实现材料. 在这类页面中, 语法关键字, 缩进, 字符串字面量, 枚举值, 路径, OID, namespace, JSON member, YANG leaf, ASN.1 type 和错误文本都可能被测试工具, 代码生成器或互操作实现直接消费. 因此, 译文只在代码块外说明结构和用途, 不在代码块内替换术语. 实现者应结合正文的语义说明检查默认值, 约束, 必选字段, 扩展点和安全影响, 并用原样保留的块进行验证.
本页保留核心 DOCSIS QProt pseudocode 和变量名, 包括 MAX_RATE, QPROTECT_ON, CRITICALqL_us, CRITICALqLSCORE_us, LG_AGING, qdelay, probNative, packet.uflow, qLscore, pick_bucket(), fill_bucket(), calcProbNative() 和 qprotect().
4.1. Input Parameters, Constants, and Variables
// Input Parameters
MAX_RATE; // Configured maximum sustained rate [b/s]
QPROTECT_ON; // Queue Protection is enabled [Default: TRUE]
CRITICALqL_us; // LL queue threshold delay [µs] Default: MAXTH_us
CRITICALqLSCORE_us;// The threshold queuing score [Default: 4000 µs]
LG_AGING; // The aging rate of the q'ing score [Default: 19]
// as log base 2 of the congestion-rate [lg(B/s)]
// Constants
AGING = pow(2, (LG_AGING-30) ) * T_RES;
CRITICALqL = CRITICALqL_us * 1000;
CRITICALqLSCORE = CRITICALqLSCORE_us * 1000/T_RES;
CRITICALqLPRODUCT = CRITICALqL * CRITICALqLSCORE;
qLSCORE_MAX = 5E9 / T_RES;
ATTEMPTS = 2;
BI_SIZE = 5;
NBUCKETS = pow(2, BI_SIZE);
MASK = NBUCKETS-1;
EXIT_SUCCESS = 0;
EXIT_SANCTION = 1;
MAX_FRAME_SIZE = 2000;
FLOOR = 2 * 8 * MAX_FRAME_SIZE * 10^9 / MAX_RATE;
struct bucket {
id; // identifier of flow using bucket
t_exp; // expiry time in units of T_RES
};
struct bucket buckets[NBUCKETS+1];
重要的 public variables 和 packet variables 包括 qdelay, probNative, packet, packet.size, packet.uflow 和 qdelayL(...). Flow identifier 通常是 5-tuple, 或者在 IPsec ESP 使用 Security Parameter Index (SPI) 时为 4-tuple.
4.2. qprotect()
qprotect(packet, ...) {
bckt_id;
qLscore;
qdelay = qL.qdelay(...);
probNative = calcProbNative(qdelay);
bckt_id = pick_bucket(packet.uflow);
qLscore = fill_bucket(buckets[bckt_id], packet.size, probNative);
if ( ( ( qdelay > CRITICALqL )
&& ( qdelay * qLscore > CRITICALqLPRODUCT ) )
|| ( qLscore >= qLSCORE_MAX ) )
return EXIT_SANCTION;
else
return EXIT_SUCCESS;
}
4.2.2. pick_bucket()
pick_bucket(uflw) {
h32 = hash32(uflw);
hsav = NBUCKETS;
now = get_time_now();
for (j=0; j<ATTEMPTS; j++) {
h = h32 & MASK;
if (buckets[h].id == uflw) {
if (buckets[h].t_exp <= now)
buckets[h].t_exp = now;
return h;
}
else if ((hsav == NBUCKETS) && (buckets[h].t_exp <= now)) {
hsav = h;
}
h32 >>= BI_SIZE;
}
if (hsav != NBUCKETS) {
buckets[hsav].t_exp = now;
} else {
if (buckets[hsav].t_exp <= now)
buckets[hsav].t_exp = now;
}
buckets[hsav].id = uflw;
return hsav;
}
额外的 NBUCKETS bucket 是默认的 "dregs" bucket. 如果 ATTEMPTS=2 且 BI_SIZE=5, 则有 32 个 non-default buckets.
4.2.3. fill_bucket()
fill_bucket(bckt_id, pkt_sz, probNative) {
now = get_time_now();
qLscore = min(buckets[bckt_id].t_exp - now
+ probNative * pkt_sz / AGING, qLSCORE_MAX);
buckets[bckt_id].t_exp = now + qLscore;
return qLscore;
}
4.2.4. calcProbNative()
calcProbNative(qdelay){
if ( qdelay >= MAXTH ) {
probNative = MAX_PROB;
} else if ( qdelay > MINTH ) {
probNative = MAX_PROB * (qdelay - MINTH)/RANGE;
} else {
probNative = 0;
}
return probNative;
}