本文共 3544 字,大约阅读时间需要 11 分钟。
DPDK提供了丰富的基础库,其中就有利用令牌桶来实现meter功能,可以参考例子中的qos_meter。这篇博客主要就是解读这个例子。令牌桶算法分为单速率三色算法和双速率单色算法,单速率只有一个速率桶C桶以及一个EBS。关注点在于报文的突发尺寸,双速率有两个速率桶C和P,更关注突发的报文速率。
首先来看单速率三色,令牌产生的速率是cir,C桶容量为cbs,当C桶满时,再去添加E桶,E桶也满时,令牌丢弃。
在取令牌时,先取C桶,C桶满足,不管E桶,E桶保持不变,C桶减少相应数量令牌返回绿色。
C桶不满,取E桶令牌,E桶满足,E桶减少相应数量令牌返回黄色。E桶也不够,两个桶的令牌数保持不变。返回红色。
main函数:一大堆初始化,主要看app_configure_flow_table这个函数。
static intapp_configure_flow_table(void){ uint32_t i, j; int ret; for (i = 0, j = 0; i < APP_FLOWS_MAX; i ++, j = (j + 1) % RTE_DIM(PARAMS)) { ret = FUNC_CONFIG(&app_flows[i], &PARAMS[j]); if (ret) return ret; } return 0;}FUNC_CONFIG对应的函数为intrte_meter_srtcm_config(struct rte_meter_srtcm *m, struct rte_meter_srtcm_params *params){ uint64_t hz; /* Check input parameters */ if ((m == NULL) || (params == NULL)) { return -1; } if ((params->cir == 0) || ((params->cbs == 0) && (params->ebs == 0))) { return -2; } /* Initialize srTCM run-time structure */ hz = rte_get_tsc_hz(); m->time = rte_get_tsc_cycles(); m->tc = m->cbs = params->cbs; m->te = m->ebs = params->ebs; rte_meter_get_tb_params(hz, params->cir, &m->cir_period, &m->cir_bytes_per_period); RTE_LOG(INFO, METER, "Low level srTCM config: \n" "\tCIR period = %" PRIu64 ", CIR bytes per period = %" PRIu64 "\n", m->cir_period, m->cir_bytes_per_period); return 0;}static voidrte_meter_get_tb_params(uint64_t hz, uint64_t rate, uint64_t *tb_period, uint64_t *tb_bytes_per_period){/*先计算添加一个字节所需的cpu周期数 *如果计算出的结果值太小,说明添加一个字节所需的cpu周期很短。 *如果直接用计算结果,会导致精度不准,所以将更新表的周期数设置为RTE_METER_TB_PERIOD_MIN,每次 *添加的字节数大于1*/ double period = ((double) hz) / ((double) rate); if (period >= RTE_METER_TB_PERIOD_MIN) { *tb_bytes_per_period = 1; *tb_period = (uint64_t) period; } else { *tb_bytes_per_period = (uint64_t) ceil(RTE_METER_TB_PERIOD_MIN / period); *tb_period = (hz * (*tb_bytes_per_period)) / rate; }}app_flows[]的数据类型是struct rte_meter_srtcmstruct rte_meter_srtcm { uint64_t time; /* 最后一次更新C和E桶的时间*/ uint64_t tc; /* C桶当前可用令牌数*/ uint64_t te; /* E桶当前可用令牌数*/ uint64_t cbs; /* cbs数值,C桶的总容量*/ uint64_t ebs; /* ebs数值,E桶的总容量*/ uint64_t cir_period; /* 每隔cir_period*cpu周期,更新C桶*/ uint64_t cir_bytes_per_period; /*每次更新C桶所需添加的令牌数*/};PARAMS:struct rte_meter_srtcm_params app_srtcm_params[] = { {.cir = 1000000 * 46, .cbs = 2048, .ebs = 2048},};#define FUNC_CONFIG rte_meter_srtcm_configrte_meter_srtcm_config(struct rte_meter_srtcm *m, struct rte_meter_srtcm_params *params)这个函数就是对app_flow[]进行赋值
关于cir,cbs,ebs,pbs,pir:
CIR(Committed Information Rate,承诺信息速率):每秒可通过的速率,计量单位为Kbps (以bit 位为单位)。
CBS(Committed Burst Size):承诺突发尺寸突发尺寸,令牌桶的容量,即每次突发所允许的最大的流量尺寸。设置的突发尺寸必须大于最大报文长度。计量单位为byte(字节)。
EBS(Excess Burst Size,超出突发尺寸):即瞬间能够通过的超出突发流量。计量单位为byte(字节)。
初始化完成之后,针对每个包,都会进行颜色判断,色盲模式的判断比较简单,对应的函数如下:
static inline enum rte_meter_colorrte_meter_srtcm_color_blind_check(struct rte_meter_srtcm *m, uint64_t time, uint32_t pkt_len){ uint64_t time_diff, n_periods, tc, te; /* Bucket update */ time_diff = time - m->time; n_periods = time_diff / m->cir_period; m->time += n_periods * m->cir_period;//m->time = time。。强行增加阅读难度,更新m->time /* 先往C桶添加令牌,C桶添加满之后再往E桶添加令牌 */ tc = m->tc + n_periods * m->cir_bytes_per_period; //更新当前C桶可用令牌数 te = m->te; if (tc > m->cbs) { te += (tc - m->cbs); if (te > m->ebs) te = m->ebs; tc = m->cbs; } /* Color logic *///C桶可用令牌足够,返回绿色。 if (tc >= pkt_len) { m->tc = tc - pkt_len; m->te = te; return e_RTE_METER_GREEN; }//C桶不够,用E桶判断。 if (te >= pkt_len) { m->tc = tc; m->te = te - pkt_len; return e_RTE_METER_YELLOW; } m->tc = tc; m->te = te; return e_RTE_METER_RED;}
转载地址:http://yyali.baihongyu.com/