您的位置:首页 > 理论基础 > 计算机网络

linux网络协议栈分析笔记7-VLAN的处理

2013-04-10 20:10 561 查看
这次先看看VLAN怎么处理的 主要代码目录linux/net/8021q
dev_add_pack(&vlan_packet_type); vlan-802.1q

static struct packet_type vlan_packet_type __read_mostly = {

.type = cpu_to_be16(ETH_P_8021Q),

.func = vlan_skb_recv, /* VLAN receive method */

};

->vlan_skb_recv

->skb = skb_share_check(skb, GFP_ATOMIC); 检查是否有其他协议共享处理此skb
->vhdr = (struct vlan_hdr *)skb->data; 指向VLAN tag字段
vlan_tci = ntohs(vhdr->h_vlan_TCI);

vlan_id = vlan_tci & VLAN_VID_MASK;

struct vlan_hdr {
__be16 h_vlan_TCI; 下图中的Tag Control Info

__be16 h_vlan_encapsulated_proto; 下图中的Len/Etype

};



这里关键之处得到vlan_id
skb->dev = __find_vlan_dev(dev, vlan_id); 通过dev 与 vlan_id获得虚拟vlan dev 重置skb的dev变量

__find_vlan_dev()
->struct vlan_group *grp = __vlan_find_group(real_dev); 寻找vlan group

struct vlan_group {

struct net_device *real_dev; /* The ethernet(like) device 指向真实的dev

* the vlan is attached to.

*/

unsigned int nr_vlans;

struct hlist_node hlist; /* linked list */

struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; vlan设备的管理空间

struct rcu_head rcu;

};

static struct vlan_group *__vlan_find_group(struct net_device *real_dev)

{

struct vlan_group *grp;

struct hlist_node *n;

int hash = vlan_grp_hashfn(real_dev->ifindex); //return ((idx >> VLAN_GRP_HASH_SHIFT) ^ idx) & VLAN_GRP_HASH_MASK;

简单的hash函数,用设备接口索引去hash

hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {

if (grp->real_dev == real_dev) 用真实的dev变量去匹配

return grp;

}

return NULL;

}
摘自网上资料 这个说的很清楚:
数据结构vlan_group_hash是vlan虚拟网卡存储与关联的核心结构:

static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; [net\8021q\vlan.c]

当通过vconfig创建了eth1.1, eth1.2, eth1.100三个虚拟网卡后,vlan_group_hash的整体结构如图所示,先有个整体印象:



vlan_group_hash是大小为32的hash表

而vlan group是合适创建的呢

在添加vlan时,会创建新的vlan虚拟网卡:

register_vlan_device() -> register_vlan_dev()

首先查找网卡是否已存在,这里的real_dev一般是真实的网卡如eth1等。以real_dev->ifindex值作hash,取出vlan_group_hash的表项,由于可能存在多个网卡的hash值相同,因此还要匹配表项的real_dev是否与real_dev相同。

如果不存在相应的表项,则分配表项struct vlan_group,并加入vlan_group_hash

ngrp = grp = vlan_group_alloc(real_dev);

最后,设置vlan_devices_arrays相应元素指向创建的vlan虚拟网卡(如eth1.1)的struct net_device。这里值得注意的是vlan_devices_arrays是二维数组,内核支持的最大vlan数是4096,为了查找效率,应用了二级目录的概念。vlan_devices_arrays指向大小512的数组,数组中每个再指向大小8的数组,像eth1.100则位于第12组的第5个(vlan_devices_arrays[11][4])。

vlan_group_set_device(grp, vlan_id, dev);

以一个例子来说明,当主机收到报文,交由vlan协议模块处理后(vlan_rcv),此时需要更换skb->dev所指向的设备,以使上层协议认为报文是来自于虚拟网卡(比如eth1.1),而不知道网卡eth1的存在。更换设备就需要知道skb->dev更换的目标。这由两个因素决定:skb->dev和vlan_id。skb->dev即报文来自主机的哪个网卡,如来自eth1,则skb->dev->name=”eth1”;vlan_id即vlan号,这在报文中的vlan报文中可以提取出。有了这两个信息,从vlan_group_hash出发,首先根据skb->dev->ifindex查找vlan_group_hash的相应项(eth1),取出vlan_group;然后,根据vlan_id,在vlan_devices_array中查找到虚拟网卡设备(eth1.1)。

一般支持的最大vlan数是4096,为了查询效率,vlan_devices_array并不是一个4096的数组,而是二维数组,将每8个vlan分为一组,共512组,像eth1.100则位于第12组的第5个。

接着分析vlan_skb_recv()
->skb_pull_rcsum(skb, VLAN_HLEN); 跳过VLAN标签
->skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tci); 设置TCI
->vlan_set_encap_proto(skb, vhdr); 设置新的协议类型 从vlan标签解出

->netif_rx(skb); 又见netif_rx ,没错, 此时VLAN标签已解析,内封的协议类型被更新,这次能够走进新的协议类型处理流程中去了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: