本文主要是介绍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
这篇关于FQ队列detached流管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!