一、关键数据结构
对于输出封包,设备的数据结构主要包括两个:输出队列(queue)和输出队列规则(queue discipline)。我们首先来看输出队列(2.6.18内核中无该结构体):
struct netdev_queue {
structnet_device *dev;
structQdisc *qdisc;
unsigned long state;
structQdisc *qdisc_sleeping;
spinlock_t _xmit_lock____cacheline_aligned_in_smp;
int xmit_lock_owner;
unsignedlong trans_start;
unsignedlong tx_bytes;
unsignedlong tx_packets;
unsigned long tx_dropped;
} ____cacheline_aligned_in_smp;
该结构描述了一个输出队列,输出队列其实就是输出封包的缓存队列。每个设备(net_device)有一个或多个输出队列,从设备的定义中我们就可以看出:
struct net_device
{
...
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
// struct list_head qdisc_list; in 2.6.18在发包时获取发送队列方式有修改
unsignedint num_tx_queues;
unsignedint real_num_tx_queues;
structQdisc *qdisc;
unsignedlong tx_queue_len;
spinlock_t tx_global_lock;
....
}
该网络设备结构中,_tx表示了发送队列,num_tx_queues表示发送队列的个数,均在创建网络设备时进行初始化。real_num_tx_queues表示当前活动的发送队列个数,tx_queue_len表示发送队列的最大长度,也即发送队列中正在排队的最大帧个数。qdisc表示了队列规则,该规则用于输出流量控制。其定义如下:
struct Qdisc {
int (*enqueue)(structsk_buff *skb, struct Qdisc *dev);
structsk_buff * (*dequeue)(struct Qdisc *dev);
unsigned flags;
#defineTCQ_F_BUILTIN 1
#defineTCQ_F_INGRESS 2
#defineTCQ_F_CAN_BYPASS 4
#defineTCQ_F_MQROOT 8
#define TCQ_F_WARN_NONWC (1<< 16)
int padded;
structQdisc_ops *ops;
structqdisc_size_table __rcu *stab;
structlist_head list;
u32 handle;
u32 parent;
atomic_t refcnt;
structgnet_stats_rate_est rate_est;
int (*reshape_fail)(structsk_buff *skb,
structQdisc *q);
void *u32_node;
structQdisc *__parent;
struct netdev_queue *dev_queue;
structQdisc *next_sched;
structsk_buff *gso_skb;
unsigned long state;
struct sk_buff_head q;
//sk_buff_head结构体中声明了锁,可直接获得队列的锁(qdisc->q.lock),2.6.18中获得锁方式略有不同(qdisc->dev->queue_lock)
structgnet_stats_basic_packed bstats;
structgnet_stats_queue qstats;
};
该结构体中有enqueue、dequeue及ops函数集,用于操作队列。gso_skb表示分片帧,q表示输出封包。//2.6.18中qdisc结构体无state字段,用net_device结构体的state字段表征状态。
二、初始化输出队列
输出队列的初始化在注册网络设备时完成。用于向内核注册