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

Linux内核中流量控制(21)

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

7.12 route

route分类是根据数据包的路由信息进行分类的, 路由信息中会带tclassid参数用于分类, 代码在net/sched/cls_route.c中定义, 只支持IPV4。

7.12.1 数据结构和过滤器操作结构

// route 快速映射结构, 相当于分类结果的cache
struct route4_fastmap
{
 struct route4_filter *filter;
 u32   id;
 int   iif;
};

// route头结构
struct route4_head
{
// 16个快速映射结构
 struct route4_fastmap fastmap[16];
// 257个bucket链表
 struct route4_bucket *table[256+1];
};
struct route4_bucket
{
 /* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */
 struct route4_filter *ht[16+16+1];
};

// route过滤器结构
struct route4_filter
{
// 链表中的下一项
 struct route4_filter *next;
// ID
 u32   id;
// 网卡索引号
 int   iif;
// 分类结构
 struct tcf_result res;
// TCF扩展
 struct tcf_exts  exts;
// 句柄
 u32   handle;
// 所在的bucket
 struct route4_bucket *bkt;
};
#define ROUTE4_FAILURE ((struct route4_filter*)(-1L))
static struct tcf_ext_map route_ext_map = {
 .police = TCA_ROUTE4_POLICE,
 .action = TCA_ROUTE4_ACT
};

static struct tcf_ext_map tcindex_ext_map = {
 .police = TCA_TCINDEX_POLICE,
 .action = TCA_TCINDEX_ACT
};
 
// 分类操作结构
static struct tcf_proto_ops cls_route4_ops = {
 .next  = NULL,
 .kind  = "route",
 .classify = route4_classify,
 .init  = route4_init,
 .destroy = route4_destroy,
 .get  = route4_get,
 .put  = route4_put,
 .change  = route4_change,
 .delete  = route4_delete,
 .walk  = route4_walk,
 .dump  = route4_dump,
 .owner  = THIS_MODULE,
};

7.12.2 一些哈希函数

// 快速映射表位置哈希
static __inline__ int route4_fastmap_hash(u32 id, int iif)
{
// 取ID的低4位, 结果在0~15之间
 return id&0xF;
}

// 进入方向路由哈希
static __inline__ int route4_hash_to(u32 id)
{
// 取ID的低8位, 结果在0~255之间
 return id&0xFF;
}

// 来源方向路由哈希
static __inline__ int route4_hash_from(u32 id)
{
// 取ID的16~19位, 结果在0~15之间
 return (id>>16)&0xF;
}
// 网卡索引号哈希
static __inline__ int route4_hash_iif(int iif)
{
// 取网卡索引号的16~19位再加16, 结果在16~31之间
 return 16 + ((iif>>16)&0xF);
}

// 外卡哈希, 返回外卡哈希表号:32
static __inline__ int route4_hash_wild(void)
{
 return 32;
}

// 插入哈希, 从哈希表中删除时计算
static inline u32 to_hash(u32 id)
{
// 取低8位
 u32 h = id&0xFF;
// 第15位为1的话哈希值增加256
 if (id&0x8000)
  h += 256;
// 结果范围应该是0~511
 return h;
}

// 来源哈希, 插入哈希表时计算
static inline u32 from_hash(u32 id)
{
// 高16位清零
 id &= 0xFFFF;
// 低16位全1的话返回32, 外卡值
 if (id == 0xFFFF)
  return 32;
// 如果第15位为0
 if (!(id & 0x8000)) {
// 超过255的话返回256
  if (id > 255)
   return 256;
// 否则返回低4位, 范围为0~15
  return id&0xF;
 }
// 第15位为1
// 返回低4位加16, 范围为16~31
 return 16 + (id&0xF);
}

7.12.3 初始化

// 空函数
static int route4_init(struct tcf_proto *tp)
{
 return 0;
}
 
7.12.4 分类

// 分类结果处理宏
#define ROUTE4_APPLY_RESULT()     \
{        \
// 要返回的分类结果
 *res = f->res;      \
 if (tcf_exts_is_available(&f->exts)) {   \
// 执行TCF扩展操作
  int r = tcf_exts_exec(skb, &f->exts, res); \
  if (r < 0) {     \
// 操作失败, 不需要将结果进cache, 继续循环
   dont_cache = 1;    \
   continue;    \
  }      \
  return r;     \
 } else if (!dont_cache)     \
// 将结果进cache,
  route4_set_fastmap(head, id, iif, f);  \
 return 0;      \
}

static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
      struct tcf_result *res)
{
// route头节点
 struct route4_head *head = (struct route4_head*)tp->root;
 struct dst_entry *dst;
 struct route4_bucket *b;
 struct route4_filter *f;
 u32 id, h;
 int iif, dont_cache = 0;

// 如果数据包路由项为空, 分类失败
 if ((dst = skb->dst) == NULL)
  goto failure;
// 类别ID
 id = dst->tclassid;
// 如果头节点空, 用老方法分类
 if (head == NULL)
  goto old_method;
// 网卡索引号
 iif = ((struct rtable*)dst)->fl.iif;
// 根据ID和网卡索引号计算快速映射哈希值
 h = route4_fastmap_hash(id, iif);
// 如果快速映射表中元素和此ID和网卡匹配, 而且过滤结构有效
 if (id == head->fastmap[h].id &&
     iif == head->fastmap[h].iif &&
     (f = head->fastmap[h].filter) != NULL) {
// 如果是错误分类, 返回失败
  if (f == ROUTE4_FAILURE)
   goto failure;
// 否则返回分类结构, 分类成功
  *res = f->res;
  r