日期:2014-05-16 浏览次数:21114 次
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链表非空