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
};
![](http://blog.csdn.net/hsly_support/article/details/file:/C:/Users/luoye/AppData/Local/Temp/enhtmlclip/Image(3).png)
这里关键之处得到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的整体结构如图所示,先有个整体印象:
![](http://blog.csdn.net/hsly_support/article/details/file:/C:/Users/luoye/AppData/Local/Temp/enhtmlclip/Image(4).png)
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标签已解析,内封的协议类型被更新,这次能够走进新的协议类型处理流程中去了
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
};
![](http://blog.csdn.net/hsly_support/article/details/file:/C:/Users/luoye/AppData/Local/Temp/enhtmlclip/Image(3).png)
这里关键之处得到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的整体结构如图所示,先有个整体印象:
![](http://blog.csdn.net/hsly_support/article/details/file:/C:/Users/luoye/AppData/Local/Temp/enhtmlclip/Image(4).png)
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标签已解析,内封的协议类型被更新,这次能够走进新的协议类型处理流程中去了
相关文章推荐
- linux网络协议栈分析笔记6-IP层的处理2
- linux网络协议栈分析笔记5-IP层的处理1
- linux网络协议栈分析笔记14-路由4-FIB3
- linux网络协议栈分析笔记8-arp邻居子系统1
- Linux 网络协议栈开发代码分析篇之VLAN(三)—— VLAN收发处理
- linux网络协议栈分析笔记13-路由3-FIB2
- eCos学习笔记之中断处理代码分析
- 统计分析学习笔记——图像处理中的统计应用案例
- linux网络协议栈分析笔记10-arp邻居子系统3
- linux内核分析笔记----中断和中断处理程序
- 网络配置过程分析(linux网络协议栈笔记)
- Linux邻居协议 学习笔记 之二 通用邻居处理函数对应的数据结构的分析
- linux网络协议栈分析(二)
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_local_deliver)
- 【Linux4.1.12源码分析】协议栈报文接收之IP层处理分析(ip_forward)
- Lighttpd1.4.20源码分析 笔记 fdevent系统-连接socket及超时处理
- linux网络协议栈分析笔记3-网桥2
- 数字语音信号处理学习笔记——语音信号的短时频域分析(2)
- Linux网络协议栈分析——从设备驱动到链路层
- 【Linux4.1.12源码分析】协议栈gro收包之MAC层处理