Linux内核中流量控制(23)

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: [email protected]
来源:http://yfydz.cublog.cn
8.7 ipt动作操作结构

ipt是借用了netfilter的目标操作, 根据netfilter的target结果作为是否接受还是丢弃数据包, 不过感觉意义不大, 因为这破坏了协议栈的分层处理, 要丢包的话直接在上层就丢了就算了。代码在net/sched/act_ipt.c中定义。

8.7.1 数据结构和动作操作结构
/* include/net/tc_act/tc_ipt.h */
// ipt动作结构
struct tcf_ipt {
// 通用结构
 struct tcf_common common;
// hook点
 u32   tcfi_hook;
// target名称
 char   *tcfi_tname;
// target指针
 struct xt_entry_target *tcfi_t;
};
#define to_ipt(pc) \
 container_of(pc, struct tcf_ipt, common)

/* net/sched/act_ipt.c */

static struct tcf_hashinfo ipt_hash_info = {
 .htab = tcf_ipt_ht,
 .hmask = IPT_TAB_MASK,
 .lock = &ipt_lock,
};

// ipt动作操作结构
static struct tc_action_ops act_ipt_ops = {
// 名称
 .kind  = "ipt",
 .hinfo  = &ipt_hash_info,
// 类型
 .type  = TCA_ACT_IPT,
 .capab  = TCA_CAP_NONE,
 .owner  = THIS_MODULE,
 .act  = tcf_ipt,
 .dump  = tcf_ipt_dump,
 .cleanup = tcf_ipt_cleanup,
// 查找, 通用函数
 .lookup  = tcf_hash_search,
 .init  = tcf_ipt_init,
// 遍历, 通用函数
 .walk  = tcf_generic_walker
};
 

8.7.2 初始化
 
static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est,
   struct tc_action *a, int ovr, int bind)
{
 struct rtattr *tb[TCA_IPT_MAX];
 struct tcf_ipt *ipt;
 struct tcf_common *pc;
 struct ipt_entry_target *td, *t;
 char *tname;
 int ret = 0, err;
 u32 hook = 0;
 u32 index = 0;
// 解析输入参数
 if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0)
  return -EINVAL;
// 需要有hook参数
 if (tb[TCA_IPT_HOOK-1] == NULL ||
     RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32))
  return -EINVAL;
// 需要有target参数
 if (tb[TCA_IPT_TARG-1] == NULL ||
     RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t))
  return -EINVAL;
// netfilter目标
 td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]);
// 检查target参数大小是否合法
 if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size)
  return -EINVAL;
// 索引号
 if (tb[TCA_IPT_INDEX-1] != NULL &&
     RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32))
  index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]);
// 根据索引号查找common节点, 绑定到a节点(priv)
 pc = tcf_hash_check(index, a, bind, &ipt_hash_info);
 if (!pc) {
// 如果为空, 创建新的common节点
  pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
         &ipt_idx_gen, &ipt_hash_info);
  if (unlikely(!pc))
   return -ENOMEM;
  ret = ACT_P_CREATED;
 } else {
// ovr是替代标志, 如果不是替代操作, 对象已经存在, 操作失败
  if (!ovr) {
// 释放
   tcf_ipt_release(to_ipt(pc), bind);
   return -EEXIST;
  }
 }
//
 ipt = to_ipt(pc);
// hook点
 hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]);
 err = -ENOMEM;
// 分配缓冲区保存目标名称
 tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
 if (unlikely(!tname))
  goto err1;
// 解析iptables表的名称, 缺省为mangle表
 if (tb[TCA_IPT_TABLE - 1] == NULL ||
     rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ)
  strcpy(tname, "mangle");
// 分配目标空间
 t = kmalloc(td->u.target_size, GFP_KERNEL);
 if (unlikely(!t))
  goto err2;
// 复制目标结构相关参数
 memcpy(t, td, td->u.target_size);

// 初始化目标
 if ((err = ipt_init_target(t, tname, hook)) < 0)
  goto err3;
 spin_lock_bh(&ipt->tcf_lock);
 if (ret != ACT_P_CREATED) {
// 如果不是新建, 释放老节点参数
  ipt_destroy_target(ipt->tcfi_t);
  kfree(ipt->tcfi_tname);
  kfree(ipt->tcfi_t);
 }
// 参数赋值
 ipt->tcfi_tname = tname;
 ipt->tcfi_t     = t;
 ipt->tcfi_hook  = hook;
 spin_unlock_bh(&ipt->tcf_lock);
// 新建节点, 插入哈希表
 if (ret == ACT_P_CREATED)
  tcf_hash_insert(pc, &ipt_hash_info);
 return ret;

错误处理, 释放各种动态分配的参数
err3:
 kfree(t);
err2:
 kfree(tname);
err1:
 kfree(pc);
 return err;
}

// 初始化目标
static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
{
 struct ipt_target *target;
 int ret = 0;
// 根据名称查找target
 target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision);
// 找不到则失败
 if (!target)
  return -ENOENT;
 t->u.kernel.target = target;
// target通用检查, 检查合适的大小, 表名, hook, 协议等信息
 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
         table, hook, 0, 0);
 if (ret)
  return ret;
// 执行target自己的检查函数
 if (t->u.kernel.target->checkentry
     && !t->u.kernel.target->checkentry(table, NULL,
                t->u.kernel.target, t->data,
            hook)) {
  module_put(t->u.kernel.target->me);
  ret = -EINVAL;
 }
 return ret;
}
 
8.7.3 动作

static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
     struct tcf_result *res)
{
 int ret = 0, result = 0;
// 动作结构
 struct tcf_ipt *ipt = a->priv;
 if (skb_cloned(skb)) {
// 如果是克隆包, 重新分配数据空间形成一个独立的数据包
  if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
   return TC_ACT_UNSPEC;
 }
 spin_lock(&ipt->tcf_lock);
// 统计参数更新
 ipt->tcf_tm.lastuse = jiffies;
 ipt->tcf_bstats.bytes += skb->len;
 ipt->tcf_bstats.packets++;
 /* yes, we have to worry about both in and out dev
  worry later - danger - this API seems to have changed
  from earlier kernels */
 /* iptables targets take a double skb pointer in case the skb
  * needs to be replaced. We don't own the skb, so this must not
  * happen. The pskb_expand_head above should make sure of this */
// 执行target函数
 ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL,
         ipt->tcfi_hook,
         ipt->tcfi_t->u.kernel.target,
         ipt->tcfi_t->data);
 switch (ret) {
 case NF_ACCEPT:
// 接受
  result = TC_ACT_OK;
  break;
 case NF_DROP:
// 拒绝
  result = TC_ACT_SHOT;
  ipt->tcf_qstats.drops++;
  break;
 case IPT_CONTINUE:
// 继续
  result = TC_ACT_PIPE;
  break;
 default:
// 缺省也是接受
  if (net_ratelimit())
   printk("Bogus netfilter code %d assume ACCEPT\n", ret);
  result = TC_POLICE_OK;
  break;
 }
 spin_unlock(&ipt->tcf_lock);
 return result;
}

8.7.4 输出

static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
// 数据包缓冲区位置
 unsigned char *b = skb->tail;
// ipt动作结构
 struct tcf_ipt *ipt = a->priv;
 struct ipt_entry_target *t;
 struct tcf_t tm;
 struct tc_cnt c;
 /* for simple targets kernel size == user size
 ** user name = target name
 ** for foolproof you need to not assume this
 */
// 分配target结构, 只是用于中转处理
 t = kmalloc(ipt->tcfi_t->u.user.target_size, GFP_ATOMIC);
 if (unlikely(!t))
  goto rtattr_failure;
// 统计值
 c.bindcnt = ipt->tcf_bindcnt - bind;
 c.refcnt = ipt->tcf_refcnt - ref;
// 拷贝target结构
 memcpy(t, ipt->tcfi_t, ipt->tcfi_t->u.user.target_size);
// 拷贝target名称
 strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
// target
 RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t);
// 索引号
 RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index);
// hook点
 RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook);
// 统计值
 RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
// 网卡名称
 RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname);
// 时间参数
 tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install);
 tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse);
 tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires);
 RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
// 释放刚分配的target
 kfree(t);
 return skb->len;
rtattr_failure:
 skb_trim(skb, b - skb->data);
 kfree(t);
 return -1;
}
 
8.7.5 清除

// 只是tcf_ipt_release的转换函数
static int tcf_ipt_cleanup(struct tc_action *a, int bind)
{
// ipt动作结构
 struct tcf_ipt *ipt = a->priv;
 return tcf_ipt_release(ipt, bind);
}

// ipt释放操作
static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
{
 int ret = 0;
 if (ipt) {
// 减少绑定数
  if (bind)
   ipt->tcf_bindcnt--;
// 减少引用数
  ipt->tcf_refcnt--;
// 绑定数和引用数都为0后释放ipt动作结构
  if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) {
// 释放目标
   ipt_destroy_target(ipt->tcfi_t);
// 释放target名称
   kfree(ipt->tcfi_tname);
// 释放target空间
   kfree(ipt->tcfi_t);
// 释放动作结构节点
   tcf_hash_destroy(&ipt->common, &ipt_hash_info);
   ret = ACT_P_DELETED;
  }
 }
 return ret;
}

static void ipt_destroy_target(struct ipt_entry_target *t)
{
// 调用target的destroy函数, 其实有此成员函数的target不多
 if (t->u.kernel.target->destroy)
  t->u.kernel.target->destroy(t->u.kernel.target, t->data);
// 减少module计数
        module_put(t->u.kernel.target->me);
}

8.8 gact(Generic actions)

gact定义一个通用的TC动作处理结果方法, 代码在net/sched/act_gact.c中定义.

8.8.1 数据结构和动作操作结构
/* include/net/tc_act/tc_gact.h */
// GACT动作结构
struct tcf_gact {
 struct tcf_common common;
#ifdef CONFIG_GACT_PROB
        u16   tcfg_ptype;
        u16   tcfg_pval;
        int   tcfg_paction;
#endif
};
#define to_gact(pc) \
 container_of(pc, struct tcf_gact, common)
/* include/linux/tc_act/tc_gact.h */
#define TCA_ACT_GACT 5
struct tc_gact
{
// TC通用数据
 tc_gen;
};
#define tc_gen \
 __u32                 index; \
 __u32                 capab; \
 int                   action; \
 int                   refcnt; \
 int                   bindcnt
struct tc_gact_p
{
#define PGACT_NONE              0
#define PGACT_NETRAND           1
#define PGACT_DETERM            2
#define MAX_RAND                (PGACT_DETERM + 1 )
 __u16                 ptype;
 __u16                 pval;
 int                   paction;
};

/* net/sched/act_gact.c */

// GACT哈希表信息结构
static struct tcf_hashinfo gact_hash_info = {
 .htab = tcf_gact_ht,
 .hmask = GACT_TAB_MASK,
 .lock = &gact_lock,
};
 
// gact动作操作结构
static struct tc_action_ops act_gact_ops = {
 .kind  = "gact",
// 哈希表信息
 .hinfo  = &gact_hash_info,
 .type  = TCA_ACT_GACT,
 .capab  = TCA_CAP_NONE,
 .owner  = THIS_MODULE,
 .act  = tcf_gact,
 .dump  = tcf_gact_dump,
 .cleanup = tcf_gact_cleanup,
// 通用函数
 .lookup  = tcf_hash_search,
 .init  = tcf_gact_init,
// 通用函数
 .walk  = tcf_generic_walker
};

8.8.2 初始化

static int tcf_gact_init(struct rtattr *rta, struct rtattr *est,
                         struct tc_action *a, int ovr, int bind)
{
 struct rtattr *tb[TCA_GACT_MAX];
 struct tc_gact *parm;
 struct tcf_gact *gact;
 struct tcf_common *pc;
 int ret = 0;

// 解析输入参数, 结果保存到tb数组, 失败则返回
 if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0)
  return -EINVAL;
// 解析参数
 if (tb[TCA_GACT_PARMS - 1] == NULL ||
     RTA_PAYLOAD(tb[TCA_GACT_PARMS - 1]) < sizeof(*parm))
  return -EINVAL;
 parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]);
// PROB参数
 if (tb[TCA_GACT_PROB-1] != NULL)
#ifdef CONFIG_GACT_PROB
  if (RTA_PAYLOAD(tb[TCA_GACT_PROB-1]) < sizeof(struct tc_gact_p))
   return -EINVAL;
#else
  return -EOPNOTSUPP;
#endif
// 根据索引号查找common结构
 pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
 if (!pc) {
// 没找到的话新建一个
  pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
         bind, &gact_idx_gen, &gact_hash_info);
  if (unlikely(!pc))
   return -ENOMEM;
  ret = ACT_P_CREATED;
 } else {
// 找到的话检查是否是替代操作, 否则失败, 对象已经存在
  if (!ovr) {
   tcf_hash_release(pc, bind, &gact_hash_info);
   return -EEXIST;
  }
 }
// 获取GACT结构指针
 gact = to_gact(pc);
 spin_lock_bh(&gact->tcf_lock);
// 填写GACT结构参数
// 动作结果
 gact->tcf_action = parm->action;
#ifdef CONFIG_GACT_PROB
 if (tb[TCA_GACT_PROB-1] != NULL) {
  struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]);
  gact->tcfg_paction = p_parm->paction;
  gact->tcfg_pval    = p_parm->pval;
  gact->tcfg_ptype   = p_parm->ptype;
 }
#endif
 spin_unlock_bh(&gact->tcf_lock);
// 如果是新建节点, 插入哈希表
 if (ret == ACT_P_CREATED)
  tcf_hash_insert(pc, &gact_hash_info);
 return ret;
}
 
8.8.3 动作

static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
{
// GACT动作结构为a的私有数据
 struct tcf_gact *gact = a->priv;
// 缺省动作是拒绝
 int action = TC_ACT_SHOT;
 spin_lock(&gact->tcf_lock);
#ifdef CONFIG_GACT_PROB
// 如果定义了GACT_PROB内核选项
// gact_rand是一个动作函数指针数组, 对应一些动作函数, 会有些随机因素在里面
 if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL)
  action = gact_rand[gact->tcfg_ptype](gact);
 else
  action = gact->tcf_action;
#else
// 否则就直接是TC规则中定义的动作类型
 action = gact->tcf_action;
#endif
// 统计数更新
 gact->tcf_bstats.bytes += skb->len;
 gact->tcf_bstats.packets++;
// 如果是丢包, 增加丢包数
 if (action == TC_ACT_SHOT)
  gact->tcf_qstats.drops++;
// 结构上次使用时间
 gact->tcf_tm.lastuse = jiffies;
 spin_unlock(&gact->tcf_lock);
 return action;
}

其中gact_rand数组定义如下:
typedef int (*g_rand)(struct tcf_gact *gact);
static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ };
// 随机动作
static int gact_net_rand(struct tcf_gact *gact)
{
// pval作为一个随机处理因素, 在非0情况下会有一定随机性选择tcfg_paction动作,
// 其他情况下选择tcfg_action
 if (!gact->tcfg_pval || net_random() % gact->tcfg_pval)
  return gact->tcf_action;
 return gact->tcfg_paction;
}

// 确定性动作
static int gact_determ(struct tcf_gact *gact)
{
// pval作为一个处理因素, 在非0情况下会有一定根据当前统计数选择tcfg_paction动作,
// 其他情况下选择tcfg_action
 if (!gact->tcfg_pval || gact->tcf_bstats.packets % gact->tcfg_pval)
  return gact->tcf_action;
 return gact->tcfg_paction;
}

8.8.4 输出

static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
// 数据包缓冲区起始位置
 unsigned char *b = skb->tail;
// GACT选项结构
 struct tc_gact opt;
// GACT动作结构
 struct tcf_gact *gact = a->priv;
// 时间参数
 struct tcf_t t;
// 填充GACT选项参数
 opt.index = gact->tcf_index;
 opt.refcnt = gact->tcf_refcnt - ref;
 opt.bindcnt = gact->tcf_bindcnt - bind;
 opt.action = gact->tcf_action;
// 将选项参数拷贝到skb缓冲区
 RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt);
#ifdef CONFIG_GACT_PROB
// 填充GACT_PROB情况下相关数据
 if (gact->tcfg_ptype) {
  struct tc_gact_p p_opt;
  p_opt.paction = gact->tcfg_paction;
  p_opt.pval = gact->tcfg_pval;
  p_opt.ptype = gact->tcfg_ptype;
  RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt);
 }
#endif
// 填写时间
 t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install);
 t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse);
 t.expires = jiffies_to_clock_t(gact->tcf_tm.expires);
// 拷贝到skb缓冲区
 RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t);
// 返回当前数据长度, 注意这里都没有计算netlink信息长度参数
 return skb->len;
rtattr_failure:
 skb_trim(skb, b - skb->data);
 return -1;
}

8.8.5 清除

// 只是相当于tcf_hash_release的包裹函数
static int tcf_gact_cleanup(struct tc_action *a, int bind)
{
 struct tcf_gact *gact = a->priv;
 if (gact)
  return tcf_hash_release(&gact->common, bind, &gact_hash_info);
 return 0;
}
 
8.9 simple
 
simple定义一个简单的TC动作处理结果方法实例, 代码在net/sched/act_simple.c中定义.

8.9.1 数据结构和动作操作结构
 
/* net/sched/act_simple.c */

// simple哈希表信息结构
static struct tcf_hashinfo simp_hash_info = {
 .htab = tcf_simp_ht,
 .hmask = SIMP_TAB_MASK,
 .lock = &simp_lock,
};
 

// simple动作操作结构
// 没有lookup函数
static struct tc_action_ops act_simp_ops = {
 .kind  = "simple",
 .hinfo  = &simp_hash_info,
 .type  = TCA_ACT_SIMP,
 .capab  = TCA_CAP_NONE,
 .owner  = THIS_MODULE,
 .act  = tcf_simp,
 .dump  = tcf_simp_dump,
 .cleanup = tcf_simp_cleanup,
 .init  = tcf_simp_init,
// 通用函数
 .walk  = tcf_generic_walker,
};
 
8.9.2 初始化

static int tcf_simp_init(struct rtattr *rta, struct rtattr *est,
    struct tc_action *a, int ovr, int bind)
{
 struct rtattr *tb[TCA_DEF_MAX];
// 缺省动作结构, simple由于很简单, 没定义自己的动作结构, 直接用缺省的
 struct tc_defact *parm;
 struct tcf_defact *d;
 struct tcf_common *pc;
 void *defdata;
 u32 datalen = 0;
 int ret = 0;
// 解析输入参数, 结果保存到tb数组, 失败则返回
 if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0)
  return -EINVAL;
// 解析参数
 if (tb[TCA_DEF_PARMS - 1] == NULL ||
     RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm))
  return -EINVAL;
// 参数指针
 parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]);
 defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]);
 if (defdata == NULL)
  return -EINVAL;
// 数据长度
 datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]);
 if (datalen <= 0)
  return -EINVAL;
// 根据索引号查找common结构
 pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info);
 if (!pc) {
// 没找到的话新建一个
  pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
         &simp_idx_gen, &simp_hash_info);
  if (unlikely(!pc))
   return -ENOMEM;
  d = to_defact(pc);
//  分配缺省数据, 复制defdata参数
  ret = alloc_defdata(d, datalen, defdata);
  if (ret < 0) {
   kfree(pc);
   return ret;
  }
// 新建标志
  ret = ACT_P_CREATED;
 } else {
// 转换为缺省动作结构
  d = to_defact(pc);
// 找到的话检查是否是替代操作, 否则失败, 对象已经存在
  if (!ovr) {
// 释放simple动作结构
   tcf_simp_release(d, bind);
   return -EEXIST;
  }
// 是替代操作, 进行重新分配结构操作
  realloc_defdata(d, datalen, defdata);
 }
 spin_lock_bh(&d->tcf_lock);
// 设置动作
 d->tcf_action = parm->action;
 spin_unlock_bh(&d->tcf_lock);
// 如果是新建节点, 插入哈希表
 if (ret == ACT_P_CREATED)
  tcf_hash_insert(pc, &simp_hash_info);
 return ret;
}

// 分配缺省数据
static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
{
// 分配空间
 d->tcfd_defdata = kmalloc(datalen, GFP_KERNEL);
 if (unlikely(!d->tcfd_defdata))
  return -ENOMEM;
// 设置数据长度
 d->tcfd_datalen = datalen;
// 拷贝数据
 memcpy(d->tcfd_defdata, defdata, datalen);
 return 0;
}

// 重新分配
static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
{
// 释放原来的defdata
 kfree(d->tcfd_defdata);
// 重新分配新的defdata
 return alloc_defdata(d, datalen, defdata);
}
 
8.9.3 动作

static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
{
// simple只是用缺省动作结构, 为a的私有数据
 struct tcf_defact *d = a->priv;
 spin_lock(&d->tcf_lock);
// 更新结构时间参数
 d->tcf_tm.lastuse = jiffies;
// 更新数据包统计值
 d->tcf_bstats.bytes += skb->len;
 d->tcf_bstats.packets++;
 /* print policy string followed by _ then packet count
  * Example if this was the 3rd packet and the string was "hello"
  * then it would look like "hello_3" (without quotes)
  **/
 printk("simple: %s_%d\n",
        (char *)d->tcfd_defdata, d->tcf_bstats.packets);
 spin_unlock(&d->tcf_lock);
// 返回动作结果
 return d->tcf_action;
}
 
8.9.4 输出

static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
    int bind, int ref)
{
 unsigned char *b = skb->tail;
 struct tcf_defact *d = a->priv;
 struct tc_defact opt;
 struct tcf_t t;
// 填写基本选项参数
// 索引号
 opt.index = d->tcf_index;
// 引用数
 opt.refcnt = d->tcf_refcnt - ref;
// 绑定数
 opt.bindcnt = d->tcf_bindcnt - bind;
// 动作
 opt.action = d->tcf_action;
 RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
// 拷贝defdata
 RTA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata);
// 填写时间参数
// 建立时间
 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
// 上次使用时间
 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
// 到期时间
 t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
 RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t);
 return skb->len;
rtattr_failure:
 skb_trim(skb, b - skb->data);
 return -1;
}
 
8.9.5 清除

// 就是tcf_simp_release的包裹函数
static inline int tcf_simp_cleanup(struct tc_action *a, int bind)
{
 struct tcf_defact *d = a->priv;
 if (d)
  return tcf_simp_release(d, bind);
 return 0;
}
// 释放simple动作结构
static int tcf_simp_release(struct tcf_defact *d, int bind)
{
 int ret = 0;
 if (d) {
// 减少绑定数
  if (bind)
   d->tcf_bindcnt--;
// 减少引用数
  d->tcf_refcnt--;
// 绑定数和引用数都到0
  if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) {
// 释放defdata的缓冲区
   kfree(d->tcfd_defdata);
// 释放节点
   tcf_hash_destroy(&d->common, &simp_hash_info);
   ret = 1;
  }
 }
 return ret;
}

...... 待续 ......

猜你喜欢

转载自cxw06023273.iteye.com/blog/867362
今日推荐