FQ队列detached流管理

对于FQ中的流结构,如果其没有任何要发送的报文,即其为空,将其设置为detached状态,这样的流结构即不在new_flow链表,也不在old_flow链表。在detach设置函数中,不仅将其next指向固定的地址(静态变量detached的地址),而且,记录下其进入detached状态的时间戳。

/* special value to mark a detached flow (not on old/new list) */
static struct fq_flow detached, throttled;

static void fq_flow_set_detached(struct fq_flow *f)
{
    f->next = &detached;
    f->age = jiffies;
}

static bool fq_flow_is_detached(const struct fq_flow *f)
{
    return f->next == &detached;
}

1. FQ流初始化detached状态

在函数fq_classify中,新创建出来的fq流结构,初始化为detached状态,还没有加入到new_flows或者old_flows链表中。

static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
{
    struct rb_node **p, *parent;
    struct sock *sk = skb->sk;
    struct rb_root *root;
    struct fq_flow *f;

    ...
    root = &q->fq_root[hash_ptr(sk, q->fq_trees_log)];
    ...
    p = &root->rb_node;
    ...

    f = kmem_cache_zalloc(fq_flow_cachep, GFP_ATOMIC | __GFP_NOWARN);
    if (unlikely(!f)) {
        q->stat_allocation_errors++;
        return &q->internal;
    }
    fq_flow_set_detached(f);
    f->sk = sk;

在函数fq_enqueue中,对于处在detached状态的流结构,由于其接收到了新的报文,将其添加到new_flows链表的尾部。

static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
{   
    struct fq_sched_data *q = qdisc_priv(sch);
    struct fq_flow *f;
    
    if (unlikely(sch->q.qlen >= sch->limit))
        return qdisc_drop(skb, sch, to_free);

    f = fq_classify(skb, q);
    ...

    f->qlen++;
    qdisc_qstats_backlog_inc(sch, skb);
    if (fq_flow_is_detached(f)) {
        struct sock *sk = skb->sk;
        
        fq_flow_add_tail(&q->new_flows, f);
        ...

2. Detached状态设置

在函数fq_dequeue中,如果流结构为空,不包含任何报文,并且old_flows不为空,将其由new_flows链表移动到old_flows链表的尾部。否则,以上条件不成立,即此流结构原本就位于old_flows链表中,或者old_flows链表为空,将此流结构设置为detached状态。

static struct sk_buff *fq_dequeue(struct Qdisc *sch)
{
    ...

    skb = fq_dequeue_head(sch, f);
    if (!skb) {
        head->first = f->next;
        /* force a pass through old_flows to prevent starvation */
        if ((head == &q->new_flows) && q->old_flows.first) {
            fq_flow_add_tail(&q->old_flows, f);
        } else {
            fq_flow_set_detached(f);
            q->inactive_flows++;
        }
        goto begin;
    }

3. 回收Detach流结构

如下函数fq_gc_candidate,如果流结构处于detached状态,并且已经超过3秒钟,可进行回收。

/* limit number of collected flows per round */
#define FQ_GC_MAX 8
#define FQ_GC_AGE (3*HZ)

static bool fq_gc_candidate(const struct fq_flow *f)
{
    return fq_flow_is_detached(f) &&
           time_after(jiffies, f->age + FQ_GC_AGE);
}

在函数fq_gc中,调用以上fq_gc_candidate函数,判断是否可回收当前流结构,fq_gc每次调用时最多释放8个(FQ_GC_MAX)流结构。

static void fq_gc(struct fq_sched_data *q, struct rb_root *root, struct sock *sk)
{
    struct fq_flow *f, *tofree[FQ_GC_MAX];
    struct rb_node **p, *parent;
    int fcnt = 0;

    p = &root->rb_node;
    parent = NULL;
    while (*p) {
        parent = *p;

        f = rb_entry(parent, struct fq_flow, fq_node);
        if (f->sk == sk)
            break;

        if (fq_gc_candidate(f)) {
            tofree[fcnt++] = f;
            if (fcnt == FQ_GC_MAX)
                break;
        }

内核版本 5.0

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