日期:2014-05-16  浏览次数:21114 次

Linux内核中流量控制(10)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

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链表非空