openwrt 数据帧如何从lan转到wan

前提条件

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口的了。

大致流程图如下:

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值