Linux内核中游量控制(23)

Linux内核中流量控制(23)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源: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-&g

Linux内核中游量控制(23)

相关文章:

你感兴趣的文章:

标签云: