日期:2014-05-16 浏览次数:21245 次
5.10 TEQL("True" (or "trivial") link equalizer.)
TEQL流控方法是比较特殊的一个算法,在net/sched/sch_teql.c中定义, 使用时不需要tc提供参数, 该算法是构造一个虚拟网卡, 将物理网卡加入到这个虚拟网卡中实现多网卡的流量均衡, 这和bonding有点象, 不过这些物理网卡的都保持各自的地址, 不用相同。
5.10.1 teql操作结构定义
// teql私有数据结构
struct teql_sched_data
{
// 下一个流控节点
struct Qdisc *next;
// 指向teql属主
struct teql_master *m;
// 路由cache
struct neighbour *ncache;
// 数据队列
struct sk_buff_head q;
};
// teql网卡私有数据
struct teql_master
{
// 第一个元素必须是流控操作结构, 这样两个结构指针类型可以互换
struct Qdisc_ops qops;
struct net_device *dev;
// 从流控节点
struct Qdisc *slaves;
struct list_head master_list;
struct net_device_stats stats;
};
一些定义:
// 下一个从流控节点
#define NEXT_SLAVE(q) (((struct teql_sched_data*)qdisc_priv(q))->next)
// 虚拟网卡链表
static LIST_HEAD(master_dev_list);
// 最大平衡器数量, 缺省为1个, 对应虚拟网卡teql0, 可在插入模块时设置该参数
static int max_equalizers = 1;
module_param(max_equalizers, int, 0);
MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
5.10.1 初始化
TEQL没有象其他流控算法那样明确定义流控结构, 而是先定义虚拟网卡, 然后定义该网卡的流控算法为TEQL。
static int __init teql_init(void)
{
int i;
int err = -ENODEV;
// 最多建立max_equalizers个teql*虚拟网卡
for (i = 0; i < max_equalizers; i++) {
struct net_device *dev;
struct teql_master *master;
// 分配teql网卡名, teql_master_setup为网卡初始化函数
dev = alloc_netdev(sizeof(struct teql_master),
"teql%d", teql_master_setup);
if (!dev) {
err = -ENOMEM;
break;
}
// 登记该teql网卡
if ((err = register_netdev(dev))) {
free_netdev(dev);
break;
}
// 初始化teql的流控算法信息
master = netdev_priv(dev);
// 流控算法名称为虚拟网卡名称, 如teql0, 这和其他流控算法不同
strlcpy(master->qops.id, dev->name, IFNAMSIZ);
// 登记该流控操作结构
err = register_qdisc(&master->qops);
if (err) {
// 错误时释放网卡信息
unregister_netdev(dev);
free_netdev(dev);
break;
}
// 将新建虚拟网卡添加到虚拟网卡链表
list_add_tail(&master->master_list, &master_dev_list);
}
return i ? 0 : err;
}
// teql网卡初始化
static __init void teql_master_setup(struct net_device *dev)
{
// teql结构作为网卡私有数据
struct teql_master *master = netdev_priv(dev);
// 流控操作
struct Qdisc_ops *ops = &master->qops;
// 网卡设备回指
master->dev = dev;
ops->priv_size = sizeof(struct teql_sched_data);
// 流控操作结构初始化
ops->enqueue = teql_enqueue;
ops->dequeue = teql_dequeue;
ops->requeue = teql_requeue;
ops->init = teql_qdisc_init;
ops->reset = teql_reset;
ops->destroy = teql_destroy;
ops->owner = THIS_MODULE;
// 虚拟网卡设备初始化
dev->open = teql_master_open;
dev->hard_start_xmit = teql_master_xmit;
dev->stop = teql_master_close;
dev->get_stats = teql_master_stats;
dev->change_mtu = teql_master_mtu;
dev->type = ARPHRD_VOID;
dev->mtu = 1500;
dev->tx_queue_len = 100;
// 缺省虚拟网卡是不响应ARP信息的
dev->flags = IFF_NOARP;
// 硬件头长度至少32, 也可能是48或96
dev->hard_header_len = LL_MAX_HEADER;
SET_MODULE_OWNER(dev);
}
// teql释放
static void __exit teql_exit(void)
{
struct teql_master *master, *nxt;
// 遍历虚拟网卡链表
list_for_each_entry_safe(master, nxt, &master_dev_list, master_list) {
// 从链表中断开
list_del(&master->master_list);
// 释放流控操作
unregister_qdisc(&master->qops);
// 从系统网卡链表断开
unregister_netdev(master->dev);
// 释放网卡
free_netdev(master->dev);
}
}
5.10.3 初始化
// 初始化是将物理网卡和虚拟网卡联系起来, 但不需要其他参数
// 在使用TC定义某物理网卡的流控为teql算法时调用
// 这里的sch应该是使用teql的ops的流控
static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
{
// 物理网卡
struct net_device *dev = sch->dev;
// m->dev是虚拟网卡
struct teql_master *m = (struct teql_master*)sch->ops;
// teql私有数据
struct teql_sched_data *q = qdisc_priv(sch);
// 如果物理网卡硬件地址长度超过虚拟网卡硬件地址长度, 失败
// 虚拟网卡硬件地址应该能容纳物理网卡硬件地址
if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL;
// 物理网卡和虚拟网卡相同, 回环了
if (m->dev == dev)
return -ELOOP;
// teql属主
q->m = m;
// 初始化数据包队列
skb_queue_head_init(&q->q);
// slave链表非空