无类流控qdisc之bfifo和pfifo


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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值