日期:2014-05-16 浏览次数:21062 次
8.10 mirred(mirror and redirection)
packet mirroring and redirect actions
mirred动作是对数据进行镜像和重定向操作, 将数据包从指定网卡发出, 在net/sched/act_mirred.c中定义
8.10.1 数据结构和动作操作结构
/* include/linux/tc_act/tc_ipt.h */
struct tc_mirred
{
tc_gen;
// 动作
int eaction; /* one of IN/EGRESS_MIRROR/REDIR */
// 数据包发出网卡索引号
__u32 ifindex; /* ifindex of egress port */
};
/* include/net/tc_act/tc_ipt.h */
// mirred动作结构
struct tcf_mirred {
struct tcf_common common;
int tcfm_eaction;
int tcfm_ifindex;
int tcfm_ok_push;
struct net_device *tcfm_dev;
};
#define to_mirred(pc) \
container_of(pc, struct tcf_mirred, common)
/* net/sched/act_ipt.c */
static struct tcf_hashinfo mirred_hash_info = {
.htab = tcf_mirred_ht,
.hmask = MIRRED_TAB_MASK,
.lock = &mirred_lock,
};
// mirred动作操作结构
static struct tc_action_ops act_mirred_ops = {
// 名称
.kind = "mirred",
.hinfo = &mirred_hash_info,
// 类型
.type = TCA_ACT_MIRRED,
.capab = TCA_CAP_NONE,
.owner = THIS_MODULE,
.act = tcf_mirred,
.dump = tcf_mirred_dump,
.cleanup = tcf_mirred_cleanup,
// 查找, 通用函数
.lookup = tcf_hash_search,
.init = tcf_mirred_init,
// 遍历, 通用函数
.walk = tcf_generic_walker
};
8.10.2 初始化
static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est,
struct tc_action *a, int ovr, int bind)
{
struct rtattr *tb[TCA_MIRRED_MAX];
struct tc_mirred *parm;
struct tcf_mirred *m;
struct tcf_common *pc;
struct net_device *dev = NULL;
int ret = 0;
int ok_push = 0;
// 解析参数, 保存于tb数组, 失败返回
if (rta == NULL || rtattr_parse_nested(tb, TCA_MIRRED_MAX, rta) < 0)
return -EINVAL;
// 必须要有MIRRED参数
if (tb[TCA_MIRRED_PARMS-1] == NULL ||
RTA_PAYLOAD(tb[TCA_MIRRED_PARMS-1]) < sizeof(*parm))
return -EINVAL;
parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]);
// 如果定义了网卡索引号
if (parm->ifindex) {
// 查找相应的网卡设备结构
dev = __dev_get_by_index(parm->ifindex);
if (dev == NULL)
return -ENODEV;
switch (dev->type) {
// 以下类型的网卡扩展硬件头, 这些通常是虚拟网卡
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6:
case ARPHRD_SIT:
case ARPHRD_IPGRE:
case ARPHRD_VOID:
case ARPHRD_NONE:
ok_push = 0;
break;
default:
// 其他类型网卡需要扩展硬件头
ok_push = 1;
break;
}
}
// 根据索引号查找common节点, 绑定到a节点(priv)
pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
if (!pc) {
// 如果节点为空
// 必须要有网卡参数
if (!parm->ifindex)
return -EINVAL;
// 创建新的common节点
pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
&mirred_idx_gen, &mirred_hash_info);
if (unlikely(!pc))
return -ENOMEM;
// 新建标志
ret = ACT_P_CREATED;
} else {
// ovr是替代标志, 如果不是替代操作, 对象已经存在, 操作失败
if (!ovr) {
tcf_mirred_release(to_mirred(pc), bind);
return -EEXIST;
}
}
// 转换为mirred动作结构
m = to_mirred(pc);
spin_lock_bh(&m->tcf_lock);
// 动作
m->tcf_action = parm->action;
// 实际动作
m->tcfm_eaction = parm->eaction;
if (parm->ifindex) {
// 填充网卡参数
m->tcfm_ifindex = parm->ifindex;
// 如果不是新建操作, 减少网卡计数, 因为已经引用过了
if (ret != ACT_P_CREATED)
dev_put(m->tcfm_dev);
// 网卡
m->tcfm_dev = dev;
dev_hold(dev);
// 硬件头扩展标志
m->tcfm_ok_push = ok_push;
}
spin_unlock_bh(&m->tcf_lock);
// 如果是新建节点, 插入哈希表
if (ret == ACT_P_CREATED)
tcf_hash_insert(pc, &mirred_hash_info);
return ret;
}
8.10.3 动作
// 将数据包从指定网卡发出
static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
struct tcf_result *res)
{
// mirred动作结构
struct tcf_mirred *m = a->priv;
struct net_device *dev;
struct sk_buff *skb2 = NULL;
// 数据包自身的动作信息
u32 at = G_TC_AT(skb->tc_verd);
spin_lock(&m->tcf_lock);
// 网卡
dev = m->tcfm_dev;
// 最后使用时间
m->tcf_tm.lastuse = jiffies;
if (!(dev->flags&IFF_UP) ) {
// 如果该网卡没运行, 丢包
if (net_ratelimit())
printk("mirred to Houston: device %s is gone!\n",
de