默认网络设备流量控制


绝大多数的场景下,网络设备都是使用默认的流量控制机制在工作,这篇笔记分析了默认的流量控制机制。

数据结构

排队规则: Qdisc

struct Qdisc
{
   
    // 入队与出队操作
	int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
	struct sk_buff *(*dequeue)(struct Qdisc *dev);
	unsigned		flags;
#define TCQ_F_BUILTIN	1
#define TCQ_F_THROTTLED	2
#define TCQ_F_INGRESS	4
	int	padded; // Qdisc的第一个成员是字节对齐的,这使得开头可能会有一定的padding
	struct Qdisc_ops *ops; // 具体排队规则实现的函数操作集
	struct qdisc_size_table	*stab;
	u32	handle; // 句柄
	u32	parent; // 父节点句柄,通过这两个字段可以构建复杂的排队规则
	atomic_t		refcnt;
	unsigned long		state;
	struct sk_buff		*gso_skb;
	struct sk_buff_head	q;
	struct netdev_queue	*dev_queue;
	struct Qdisc *next_sched;
	struct list_head	list;

	struct gnet_stats_basic	bstats;
	struct gnet_stats_queue	qstats;
	struct gnet_stats_rate_est	rate_est;
	int			(*reshape_fail)(struct sk_buff *skb,
					struct Qdisc *q);

	void *u32_node;

	/* This field is deprecated, but it is still used by CBQ
	 * and it will live until better solution will be invented.
	 */
	struct Qdisc *__parent;
};

默认网络设备排队规则

dev_init_scheduler_queue()

在register_netdevice()中有调用dev_init_scheduler()对网络设备对象中的流量控制字段进行初始化。

static void dev_init_scheduler_queue(struct net_device *dev,
				     struct netdev_queue *dev_queue,
				     void *_qdisc)
{
   
	struct Qdisc *qdisc = _qdisc;

	dev_queue->qdisc = qdisc;
	dev_queue->qdisc_sleeping = qdisc;
}

void dev_init_scheduler(struct net_device *dev)
{
   
    // 将每个发送队列的排队规则都设置为noop_qdisc
	netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc);
	// 将接收队列的排队规则也设置为noop_qdisc
	dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);

    // 初始化watchdog_timer
	setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev);
}

可见,设备注册时,会将所有的发送队列和接收队列的排队规则都设置为noop_qdisc,顾名思义,这个队列什么都不做,仅仅是释放入队列的skb,所以使用该队列是没有办法进行数据包收发的。

dev_activate()

设备打开时,在dev_open()中会调用dev_activate()激活网络设备对象的发送队列,激活后,设备接口层的dev_queue_xmit()才能通过流控机制向网卡发送数据。

void dev_activate(struct net_device *dev)
{
   
	int need_watchdog;

	/* No queueing discipline is attached to device;
	   create default one i.e. pfifo_fast for devices,
	   which need queueing and noqueue_qdisc for
	   virtual interfaces
	 */
	// 如果所有发送队列的排队规则都是noop_qdisc,那么将默认的改为pfifo_fast
	if (dev_all_qdisc_sleeping_noop(dev))
		netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);

	// 没有__LINK_STATE_NOCARRIER标记说明网络设备物理层信号正常,可以发送数据
	if (!netif_carrier_ok(dev))
		/* Delay activation until next carrier-on event */
		return;

	need_watchdog = 0;
	netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog);
	// 设置接收队列排队规则
	transition_one_qdisc(dev, &dev->rx_queue, NULL);

	if (need_watchdog) {
   
		dev->trans_start 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值