概述
文章目录
- 数据结构
- 私有数据对象: fifo_sched_data
- tc参数
- bfifo
- qdisc操作集: bfifo_qdisc_ops
- 初始化: fifo_init()
- 入队列: bfifo_enqueue()
- 出队列: qdisc_dequeue_head()
- pfifo
- qdisc操作集: pfifo_qdisc_ops
- 入队列: pfifo_enqueue()
bfifo和pfifo是内核内置实现的两个非常简单的无类qdisc,数据包按照FIFO策略入队出队,它们唯一的可配置参数就是队列最大长度limit。
bfifo以字节为单位控制FIFO策略,pfifo以数据包为单位控制FIFO策略。
数据结构
私有数据对象: fifo_sched_data
/*
* Special case version of FIFO queue for use by netem.
* It queues in order based on timestamps in skb's
*/
struct fifo_sched_data {
u32 limit; // fifo队列长度,bfifo单位是字节,pfifo单位是报文数
psched_time_t oldest;
};
tc参数
非常简单,具体参考tc-bfifo(8)。
bfifo
qdisc操作集: bfifo_qdisc_ops
struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
.id = "bfifo",
.priv_size = sizeof(struct fifo_sched_data),
.enqueue = bfifo_enqueue,
.dequeue = qdisc_dequeue_head,
.peek = qdisc_peek_head,
.drop = qdisc_queue_drop,
.init = fifo_init,
.reset = qdisc_reset_queue,
.change = fifo_init,
.dump = fifo_dump,
.owner = THIS_MODULE,
};
初始化: fifo_init()
static int fifo_init(struct Qdisc *sch, struct nlattr *opt)
{
struct fifo_sched_data *q = qdisc_priv(sch);
if (opt == NULL) { // 使用默认参数初始化
// 默认报文数使用网络设备的发送队列最大限制报文数
u32 limit = qdisc_dev(sch)->tx_queue_len ? : 1;
if (sch->ops == &bfifo_qdisc_ops)
// bfifo需要将报文数转换为字节
limit *= qdisc_dev(sch)->mtu;
q->limit = limit;
} else { // 使用配置参数初始化
// tc_fifo_qopt结构体只包含一个limit参数
struct tc_fifo_qopt *ctl = nla_data(opt);
if (nla_len(opt) < sizeof(*ctl))
return -EINVAL;
q->limit = ctl->limit;
}
return 0;
}
入队列: bfifo_enqueue()
static int bfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
struct fifo_sched_data *q = qdisc_priv(sch);
// 如果没有超过限制,则放入队列末尾,否则丢包
if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= q->limit))
return qdisc_enqueue_tail(skb, sch);
return qdisc_reshape_fail(skb, sch);
}
static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch)
{
return __qdisc_enqueue_tail(skb, sch, &sch->q);
}
static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch,
struct sk_buff_head *list)
{
__skb_queue_tail(list, skb);
sch->qstats.backlog += qdisc_pkt_len(skb);
sch->bstats.bytes += qdisc_pkt_len(skb);
sch->bstats.packets++;
return NET_XMIT_SUCCESS;
}
出队列: qdisc_dequeue_head()
使用qdisc通用的出队列函数。
static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
{
return __qdisc_dequeue_head(sch, &sch->q);
}
static inline struct sk_buff *__qdisc_dequeue_head(struct Qdisc *sch,
struct sk_buff_head *list)
{
struct sk_buff *skb = __skb_dequeue(list);
if (likely(skb != NULL))
sch->qstats.backlog -= qdisc_pkt_len(skb);
return skb;
}
pfifo
qdisc操作集: pfifo_qdisc_ops
struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
.id = "pfifo",
.priv_size = sizeof(struct fifo_sched_data),
.enqueue = pfifo_enqueue,
.dequeue = qdisc_dequeue_head,
.peek = qdisc_peek_head,
.drop = qdisc_queue_drop,
.init = fifo_init,
.reset = qdisc_reset_queue,
.change = fifo_init,
.dump = fifo_dump,
.owner = THIS_MODULE,
};
初始化和出队列操作和bfifo相同,不再赘述。
入队列: pfifo_enqueue()
static int pfifo_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
struct fifo_sched_data *q = qdisc_priv(sch);
// 比较的是数据包个数
if (likely(skb_queue_len(&sch->q) < q->limit))
return qdisc_enqueue_tail(skb, sch);
return qdisc_reshape_fail(skb, sch);
}
最后
以上就是超帅老虎为你收集整理的无类流控qdisc之bfifo和pfifo数据结构tc参数bfifopfifo的全部内容,希望文章能够帮你解决无类流控qdisc之bfifo和pfifo数据结构tc参数bfifopfifo所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复