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)
请大牛帮忙解惑一下? 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; 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++;
} 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调用 bridge模块的处理在vlan之前,所以说根本不会进入到vlan_skb_dev这个函数,所以其实在br处理时,skb中其实是带TAG的。br在处理这个数据包时,会先将skb->data指针跳过vlan tag,而进行处理。 帮顶!对于vlan包 先由bridge模块处理后,怎么进入vlan_skb_dev 不清楚。如果是在bridge之前就把vlan tag去掉了的话,具体是在哪里去掉的呢?vlan_skb_dev 是怎么被调用到的? 本帖最后由 瀚海书香 于 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的普通数据包。 谢谢回复,可否细说一下
bridge--->vlan ? 这个过程 是在哪里发生的呢?
是在 br_handle_frame_finish 里面发生的吗?
还是在 netif_receive_skb函数里面发生的?
根据你的回复,应该是在netif_receive_skb函数里面,bridge处理完成后发生的。但是bridge处理完成后不是直接goto out了吗? bridge不是会直接转发出去? 回复 8# d419192480
bridge对于转发的VLAN数据包是不做tag处理的。
对于到本地的数据包和从本地发出的数据包才会做tag的处理,需要虚拟设备的支持。
很久之前看的代码了,大体上记得是这样的流程。看代码的时候需要注意:只有到本地或者本地发出的数据包才会处理tag,并且是需要虚拟设备支持的。 这里面东西貌似都没有讨论清楚,楼主你邮箱是多少?有空探讨一下?
页:
[1]
2