桥数据包转发(八)


上一节,通过流程图以及源代码结合,我们了解到,数据处理函数br_handle_frame_finsh大致的数据包分类发送的过程

这节,简单看一下,数据包的转发过程:

无论是在发往本地还是转发,有一个函数的功能是不能忽略的,就是br_handle_vlan函数

struct sk_buff *br_handle_vlan(struct net_bridge *br,
			       struct net_bridge_vlan_group *vg,
			       struct sk_buff *skb)
{
	struct br_vlan_stats *stats;
	struct net_bridge_vlan *v;
	u16 vid;

	/* If this packet was not filtered at input, let it pass */
	if (!BR_INPUT_SKB_CB(skb)->vlan_filtered)
		goto out;

	/* At this point, we know that the frame was filtered and contains
	 * a valid vlan id.  If the vlan id has untagged flag set,
	 * send untagged; otherwise, send tagged.
	 */
	br_vlan_get_tag(skb, &vid);
	/*find vid from vlan group*/
	v = br_vlan_find(vg, vid);
	/* Vlan entry must be configured at this point.  The
	 * only exception is the bridge is set in promisc mode and the
	 * packet is destined for the bridge device.  In this case
	 * pass the packet as is.
	 */
	if (!v || !br_vlan_should_use(v)) {
		if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
			goto out;
		} else {
			kfree_skb(skb);
			return NULL;
		}
	}
	/*statistacs the vlan if flow and if the vlan_stats_enabled is true */
	if (br->vlan_stats_enabled) {
		stats = this_cpu_ptr(v->stats);
		u64_stats_update_begin(&stats->syncp);
		stats->tx_bytes += skb->len;
		stats->tx_packets++;
		u64_stats_update_end(&stats->syncp);
	}

	if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
		skb->vlan_tci = 0;
out:
	return skb;
}

这个函数的作用很简单就是,数据包是否要带tag,
过程:
在传递进来的vlan group中查找自己所处的vlan
如果该vlan不存在则判断当前模式是否是混杂模式和数据包的设备是否是桥下的设备,选择发包或者丢弃。
如果存在,且vlan是开启的,则统计vlan接口上的数据流量,最后根据vlan出口的标记位进行位运算判断是否要带tag.

然后我们来看一下上节提到的发往本地数据包的处理函数

static int br_pass_frame_up(struct sk_buff *skb)
{
	struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
	struct net_bridge *br = netdev_priv(brdev);
	struct net_bridge_vlan_group *vg;
	struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
    /*统计该桥上的流量*/
	u64_stats_update_begin(&brstats->syncp);
	brstats->rx_packets++;
	brstats->rx_bytes += skb->len;
	u64_stats_update_end(&brstats->syncp);

    /*获取该桥上的vlan组*/
	vg = br_vlan_group_rcu(br);
	/* Bridge is just like any other port.  Make sure the
	 * packet is allowed except in promisc modue when someone
	 * may be running packet capture.
	 */
	if (!(brdev->flags & IFF_PROMISC) &&
	    !br_allowed_egress(vg, skb)) {
		kfree_skb(skb);
		return NET_RX_DROP;
	}
    /*替换掉数据包中的设备信息改为桥设备*/
	indev = skb->dev;
	skb->dev = brdev;
	/*配置数据包vlan的相关信息*/
	skb = br_handle_vlan(br, vg, skb);
	if (!skb)
		return NET_RX_DROP;
    /*进入NF_BR_LOCAL_IN*/
	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
		       dev_net(indev), NULL, skb, indev, NULL,
		       br_netif_receive_skb);
}

这个函数所做的事情很简单,就是配置vlan的相关信息后,然后发往本地的netfilter钩子函数中
最后重新回到netif_recive_skb.如下函数:

static int
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	return netif_receive_skb(skb);
}
再来看看数据包转发的函数

static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
	struct net_bridge_vlan_group *vg;
	struct net_device *indev;

	if (skb_warn_if_lro(skb)) {
		kfree_skb(skb);
		return;
	}
    /*获取vlan组,这个组中有许多的vlanid,br_handle_vlan函数就是要在这个组中查找自己的vid*/
	vg = nbp_vlan_group_rcu(to);
	/*添加vlan的相关配置*/
	skb = br_handle_vlan(to->br, vg, skb);
	if (!skb)
		return;

	indev = skb->dev;
	skb->dev = to->dev;
	skb_forward_csum(skb);
    
	NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD,
		dev_net(indev), NULL, skb, indev, skb->dev,
		br_forward_finish);
}

int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING,
		       net, sk, skb, NULL, skb->dev,
		       br_dev_queue_push_xmit);

}

整个数据包转发的过程与转发到本地的过程类似,只不过所进入的netfilter钩子点不同.


整个分析中不包含数据包从本地发出的数据包

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值