bridge是一个二层虚拟网络设备,通过brctl命令创建,提供了二层的ebtables,类似于三层的iptables
http://blog.chinaunix.net/uid-28315531-id-3572529.html
https://www.cnblogs.com/morphling/p/3458546.html
注册
module_init(br_init)
static int __init br_init(void)
{
...
err = br_netfilter_init();
...
br_handle_frame_hook = br_handle_frame; // 设置br_handle_frame_hook为br_handle_frame
...
}
int __init br_netfilter_init(void)
{
...
ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
...
}
static struct nf_hook_ops br_nf_ops[] __read_mostly = {
{
.hook = br_nf_pre_routing,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING,
.priority = NF_BR_PRI_BRNF,
},
{
.hook = br_nf_local_in,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_BRNF,
},
{
.hook = br_nf_forward_ip,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_BRNF - 1,
},
{
.hook = br_nf_forward_arp,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_BRNF,
},
{
.hook = br_nf_local_out,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_FIRST,
},
{
.hook = br_nf_post_routing,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
.hooknum = NF_BR_POST_ROUTING,
.priority = NF_BR_PRI_LAST,
},
{
.hook = ip_sabotage_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
},
{
.hook = ip_sabotage_in,
.owner = THIS_MODULE,
.pf = PF_INET6,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP6_PRI_FIRST,
},
};
数据流
以rx为例,eth0收到skb后通过netif_receive_skb()上送协议栈,netif_receive_skb()调用handle_bridge(),handle_bridge()判断skb->dev->br_port是否非空(eth0是否桥接),若是,调用br_handle_frame_hook()即br_handle_frame(),经过NF_BR_PRE_ROUTING链时调用br_nf_pre_routing(),经过NF_INET_PRE_ROUTING链后调用br_nf_pre_routing_finish(),再次经过NF_BR_PRE_ROUTING链,由于NF_BR_PRI_BRNF = 0 < 1,因此不调用br_nf_pre_routing(),直接调用br_handle_frame_finish()
在br_handle_frame_finish()中分两种情况:
1、skb的dmac地址是本机地址:在br_pass_frame_up()中修改skb->dev为网桥,重新交给netif_receive_skb(),此时skb->dev->br_port为空,不走桥接逻辑,直接上送ip_rcv()
2、其它:在br_forward()中转发
int netif_receive_skb(struct sk_buff *skb)
{
...
skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
...
}
static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
struct packet_type **pt_prev, int *ret,
struct net_device *orig_dev)
{
...
return br_handle_frame_hook(port, skb);
}
struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
{
...
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
...
}
static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
...
if (!setup_pre_routing(skb)) // 标记BRNF_NF_BRIDGE_PREROUTING
return NF_DROP;
...
NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
br_nf_pre_routing_finish);
return NF_STOLEN;
...
}
static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
if (skb->nf_bridge &&
!(skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { // 检查标记NF_BR_PRE_ROUTING
return NF_STOP;
}
return NF_ACCEPT;
}
static int br_nf_pre_routing_finish(struct sk_buff *skb)
{
...
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; // 取消标记NF_BR_PRE_ROUTING
...
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish, 1);
...
}
int br_handle_frame_finish(struct sk_buff *skb)
{
...
br_pass_frame_up(br, skb2); // 本地
...
br_forward(dst->dst, skb); // 转发
...
}
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
...
// 修改skb->dev为网桥
skb->dev = brdev;
...
// 重新交给netif_receive_skb()
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
}
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
...
__br_forward(to, skb);
...
}
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
...
// 修改skb->dev为出设备
skb->dev = to->dev;
...
NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
br_forward_finish);
}