lyj496332184 发表于 2011-07-17 18:42

Linux bridge 对802.1q包的处理

在一款switch设置如下:
vconfig add eth0 1
vconfig add eth0 2

brctl addbr br0

brctl addif br0 eth0.1
brctl addif br0 eth0.2

从eth0.1设备上来的数据包都是打上Tag的,那么在bridge中将包从eth0.1转发到eth0.2时,包中的TAG是如何变化的呢?
从源代码来看:
从eth0.1收到的带TAG的数据包,经过br0之后,最后调用eth0.2的vlan_dev_hard_start_xmit()将包从eth0.2真正的物理设备即eth0发送出去。

vlan_dev_hard_start_xmit()中会根据FLAG来判断是否将包打上自己的TAG即VLAN ID为2.
那么我有个疑问就是:
1. 从eth0.1上来的包经br0转发到eth0.2时是否还带了其自己的VLAN ID即1(进入vlan_dev_hard_start_xmit之前)
2. 如果eth0.2强制加上自己的VLAN TAG,那么是否从eth0.2上出来的数据包会生成两层VLAN TAG(即VLAN TAG1和VLAN TAG2)

请大牛帮忙解惑一下?

smalloc 发表于 2011-07-17 19:32

1不会。ETH0.1设备只负责2个功能,接收从EHT0设备上的带TAG1的包,去TAG.从上层发送的包加TAG.加TAG去TAG的功能实际称呼好象叫VLAN隧道. VLAN的详细确切概念可以看 PERLMAN的 网络互连 一书
2 桥只管按MAC地址,带TAG的叫隧道包,他不能做分辨. 所以问题与桥没关系,只是VLAN虚拟设备设计的问题.
代码显示,不会加而是直接透传发送.


int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
        struct net_device_stats *stats = vlan_dev_get_stats(dev);
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);

        /* Handle non-VLAN frames if they are sent to us, for example by DHCP.
       *
       * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
       * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
       */

        if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) {
                int orig_headroom = skb_headroom(skb);
                unsigned short veth_TCI;

lyj496332184 发表于 2011-07-17 20:07

1. 包是从eth0上收上来的,从驱动来看,这个包是带TAG的,驱动收包后调用netif_receive_skb()将包交给协议栈,这是会调用handle_bridge()进入bridge的处理,所以说进入bridge之后包还是带TAG的,具体不知道到何处会将TAG去掉?
2. vlan dev在初始化时,默认的flag为 VLAN_FLAG_REORDER_HDR,从代码中可以看出,会打上TAG
static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
                                          struct net_device *dev)
{
        int i = skb_get_queue_mapping(skb);
        struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
        unsigned int len;
        int ret;

        /* Handle non-VLAN frames if they are sent to us, for example by DHCP.
       *
       * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
       * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
       */
        if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
          vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR) {
                unsigned int orig_headroom = skb_headroom(skb);
                u16 vlan_tci;

                vlan_dev_info(dev)->cnt_encap_on_xmit++;

                vlan_tci = vlan_dev_info(dev)->vlan_id;
                vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
                skb = __vlan_put_tag(skb, vlan_tci);
                if (!skb) {
                        txq->tx_dropped++;
                        return NETDEV_TX_OK;
                }

                if (orig_headroom < VLAN_HLEN)
                        vlan_dev_info(dev)->cnt_inc_headroom_on_tx++;
        }

nalinaly 发表于 2011-07-26 01:51

vlan_dev_hard_start_xmit()中会根据FLAG来判断是否将包打上自己的TAG即VLAN ID为2.
那么我有个疑问就是:
1. 从eth0.1上来的包经br0转发到eth0.2时是否还带了其自己的VLAN ID即1(进入vlan_dev_hard_start_xmit之前)
2. 如果eth0.2强制加上自己的VLAN TAG,那么是否从eth0.2上出来的数据包会生成两层VLAN TAG(即VLAN TAG1和VLAN TAG2)

请大牛帮忙解惑一下?



1,br0v转发时没有,但是,从eth0.2出去时会再次加上
2,只有一层vlan_Tag,因为eth0.1的包进网桥前会去掉vlan tag
在vlan_skb_recv这个函数里去除vlan

type = skb->protocol;
list_for_each_entry_rcu(ptype,
      &ptype_base, list) {
    if (ptype->type == type &&
      (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
         ptype->dev == orig_dev)) {
      if (pt_prev)
            ret = deliver_skb(skb, pt_prev, orig_dev);
      pt_prev = ptype;
    }
中陷入vlan_skb_recv调用

lyj496332184 发表于 2011-09-18 18:35

bridge模块的处理在vlan之前,所以说根本不会进入到vlan_skb_dev这个函数,所以其实在br处理时,skb中其实是带TAG的。br在处理这个数据包时,会先将skb->data指针跳过vlan tag,而进行处理。

d419192480 发表于 2011-10-26 11:42

帮顶!对于vlan包 先由bridge模块处理后,怎么进入vlan_skb_dev 不清楚。如果是在bridge之前就把vlan tag去掉了的话,具体是在哪里去掉的呢?vlan_skb_dev 是怎么被调用到的?

瀚海书香 发表于 2011-10-26 16:49

本帖最后由 瀚海书香 于 2011-10-26 18:13 编辑

回复 6# d419192480
vlan函数的处理,跟其他协议是类似的,通过dev_add_pack将vlan的处理函数添加到ptype_base中。
在bridge下的vlan数据包的处理流程:(注意是到本地或者本地发出的数据包,转发的数据包是不会进行tag处理的,只是进行简单的指针加减后处理的。nf_bridge_pull_encap_header_rcsum)

netif_receive_skb--->bridge-->vlan-->netif_rx-->bridge

也就是说,vlan的数据包会两次经过bridge。第一次为带tag的vlan数据包,第二次为去掉tag的普通数据包。

d419192480 发表于 2011-10-26 17:15

谢谢回复,可否细说一下
bridge--->vlan ? 这个过程 是在哪里发生的呢?
是在 br_handle_frame_finish 里面发生的吗?
还是在 netif_receive_skb函数里面发生的?

根据你的回复,应该是在netif_receive_skb函数里面,bridge处理完成后发生的。但是bridge处理完成后不是直接goto out了吗? bridge不是会直接转发出去?

瀚海书香 发表于 2011-10-26 18:09

回复 8# d419192480
bridge对于转发的VLAN数据包是不做tag处理的。
对于到本地的数据包和从本地发出的数据包才会做tag的处理,需要虚拟设备的支持。
很久之前看的代码了,大体上记得是这样的流程。看代码的时候需要注意:只有到本地或者本地发出的数据包才会处理tag,并且是需要虚拟设备支持的。

hi.stao 发表于 2011-12-22 18:51

这里面东西貌似都没有讨论清楚,楼主你邮箱是多少?有空探讨一下?

页: [1] 2
查看完整版本: Linux bridge 对802.1q包的处理