RED统计信息

使用TC命令查看网络设备ens40的队列统计信息,对于RED队列,显示如下,首先是RED配置参数的显示,其次,为统计信息:

$ tc -d -s qdisc show dev ens40   
qdisc red 8005: root refcnt 2 limit 400000b min 30000b max 100000b ecn harddrop adaptive ewma 5 probability 0.00956593 Scell_log 8
 Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) 
 backlog 0b 0p requeues 0 
  marked 0 early 0 pdrop 0 other 0

RED统计信息对应于内核的处理函数red_dump_stats,主要是4个统计值:marked,early,pdrop和other。

static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
    struct red_sched_data *q = qdisc_priv(sch);
    struct net_device *dev = qdisc_dev(sch);
    struct tc_red_xstats st = {0};

    if (sch->flags & TCQ_F_OFFLOADED) {
        struct tc_red_qopt_offload hw_stats_request = {
            .command = TC_RED_XSTATS,
            .handle = sch->handle,
            .parent = sch->parent,
            {
                .xstats = &q->stats,
            },
        };
        dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, &hw_stats_request);
    }
    st.early = q->stats.prob_drop + q->stats.forced_drop;
    st.pdrop = q->stats.pdrop;
    st.other = q->stats.other;
    st.marked = q->stats.prob_mark + q->stats.forced_mark;

    return gnet_stats_copy_app(d, &st, sizeof(st));

1 marked和early统计值

marked表示标记的报文数量,由两部分组成:prob_mark和forced_mark。参见RED的入队列函数,prob_mark和forced_mark分别对应于RED的RED_PROB_MARK和RED_HARD_MARK两个动作处理,成功对报文进行了标记处理,将相应的计数递增。

static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
{
    struct red_sched_data *q = qdisc_priv(sch);
    struct Qdisc *child = q->qdisc;

    ...
    switch (red_action(&q->parms, &q->vars, q->vars.qavg)) {
    case RED_PROB_MARK:
        qdisc_qstats_overlimit(sch);
        if (!red_use_ecn(q) || !INET_ECN_set_ce(skb)) {
            q->stats.prob_drop++;
            goto congestion_drop;
        }

        q->stats.prob_mark++;
        break;

    case RED_HARD_MARK:
        qdisc_qstats_overlimit(sch);
        if (red_use_harddrop(q) || !red_use_ecn(q) ||
            !INET_ECN_set_ce(skb)) {
            q->stats.forced_drop++;
            goto congestion_drop;
        }

        q->stats.forced_mark++;
        break;

early表示在入队列之前丢弃的报文数量,其由两部分组成:prob_drop和forced_drop。如上所示,如果报文标记失败,报文将被丢弃,增加丢弃计数。对于RED动作RED_HARD_MARK,如果TC命令设置了harddrop选项,不进行报文标记尝试,直接将报文丢弃,增加forced_drop计数。

2 pdrop和other统计值

pdrop表示由于队列限值导致的报文丢弃,如下函数red_enqueue中,入队列函数qdisc_enqueue失败的话,增加pdrop计数。RED本身没有other计数的相关处理。

static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
{
    ret = qdisc_enqueue(skb, child, to_free);
    if (likely(ret == NET_XMIT_SUCCESS)) {
        qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
    } else if (net_xmit_drop_count(ret)) {
        q->stats.pdrop++;
        qdisc_qstats_drop(sch);
    }
    return ret;

3 TC卸载的统计数据

如果网卡执行了TC的RED卸载功能,使用命令字TC_RED_XSTATS,调用网卡驱动接口ndo_setup_tc获取统计数据,赋值到q->stats中(struct red_stats)。

static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
{
    struct red_sched_data *q = qdisc_priv(sch);
    struct net_device *dev = qdisc_dev(sch);
    struct tc_red_xstats st = {0};

    if (sch->flags & TCQ_F_OFFLOADED) {
        struct tc_red_qopt_offload hw_stats_request = {
            .command = TC_RED_XSTATS,
            .handle = sch->handle,
            .parent = sch->parent,
            {
                .xstats = &q->stats,
            },
        };
        dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_RED, &hw_stats_request);
    }

如下Mellanox的网卡驱动用于获取RED统计数据的函数mlxsw_sp_qdisc_get_red_xstats,

static int mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port,
                  struct mlxsw_sp_qdisc *mlxsw_sp_qdisc, void *xstats_ptr)
{
    struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base.red;
    u8 tclass_num = mlxsw_sp_qdisc->tclass_num;
    struct mlxsw_sp_port_xstats *xstats;
    struct red_stats *res = xstats_ptr;
    int early_drops, marks, pdrops;

    xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;

    early_drops = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
    marks = xstats->ecn - xstats_base->prob_mark;
    pdrops = xstats->tail_drop[tclass_num] - xstats_base->pdrop;

    res->pdrop += pdrops;
    res->prob_drop += early_drops;
    res->prob_mark += marks;

    xstats_base->pdrop += pdrops;
    xstats_base->prob_drop += early_drops;
    xstats_base->prob_mark += marks;
    return 0;

内核版本 5.0

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页