前提条件
1.lan pc已经获取了openwrt lan端的ip
2.lan pc已经有openwrt lan的路由表
3.lan pc已经学习到了openwrt lan的mac地址
4.lan pc发送的数据是到互联网
开始
直接看__netif_receive_skb_core,前面的NAPI收包已经上一篇文章已经讲过了。
static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc,
struct packet_type **ppt_prev)
{
....
rx_handler = rcu_dereference(skb->dev->rx_handler);
....
switch (rx_handler(&skb))
....
}
数据包第一次进入桥的时候是要调用rx_handler(&skb)。原因是网卡设备加入桥的时候dev->rx_handler被赋值为了br_handle_frame,在br_add_if()函数中完成。
br_handle_frame()函数[net\bridge\br_input.c]
判断以太帧的目的地址是否为本地链路地址,决定发往本地还是进行转发
is_link_local_ether_addr(dest)
发往本地走:
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
NULL, skb, skb->dev, NULL, br_handle_local_finish);
转发:
rhook = rcu_dereference(br_should_route_hook);
......
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_frame_finish);
在lan pc的假设条件中,已经确定是走本地,目的mac为lan的mac地址。
分析发往本地:
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
NULL, skb, skb->dev, NULL, br_handle_local_finish);
NF_HOOK中桥的NF_BR_LOCAL_IN回调函数
[net\bridge\netfilter\ebtable_filter.c]
static const struct nf_hook_ops ebt_ops_filter[] = {
{
.hook = ebt_in_hook,
.pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_FILTER_BRIDGED,
},
.....
ebt_in_hook是遍历ebtables添加的规则。不是分析的重点
最后调用br_handle_local_finish()函数
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
__br_handle_local_finish(skb);
BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
br_pass_frame_up(skb);
return 0;
}
主要看br_pass_frame_up():
static int br_pass_frame_up(struct sk_buff *skb)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
....
indev = skb->dev;
skb->dev = brdev;
....
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
这里把skb->dev=brdev,然后又走了一遍NF_BR_LOCK_IN,并且设置了indev。最后调用br_netif_receive_skb()
static int
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
{
br_drop_fake_rtable(skb);
return netif_receive_skb(skb);
}
netif_receive_skb()
netif_receive_skb_internal()
__netif_receive_skb()
__netif_receive_skb_one_core()
__netif_receive_skb_core()
最终数据包又回到了文章开头说的__netif_receive_skb_core()函数中处理。这次数据包就不会在调用rx_handler(&skb))了,因为skb->dev被替换成了桥的struct net_device结构体了。这次数据包要进入网络三层协议栈,调用ip_rcv()函数。百度一篇讲netfilter的就可以明白后续如何走到wan口的了。
大致流程图如下: