linux内核中VLAN收发处理,linux内核中VLAN收发处理
linux内核中VLAN收发处理
——lvyilong316
VLAN报文格式
基于802.1Q的VLAN帧格式如下:

Type:长度为2字节,取值为0x8100,表示此帧的类型为802.1Q Tag帧。
PRI:长度为3比特,可取0~7之间的值,表示帧的优先级,值越大优先级越高。该优先级主要为QoS差分服务提供参考依据(COS)。
VLAN Identifier (VID): 长度12bits,可配置的VLAN ID取值范围为1~4094。通常vlan 0和vlan 4095预留,vlan1为缺省vlan,一般用于网管
注意:这里的两个Type,前面802.1Q Tag中的Type,指明这个是VLAN报文,其值为0x8100;而对于后面Length/Type中的Type指定的是以太网内层协议的类型,如IP或ARP等。
相关数据结构
1.1 struct vlan_ethhdr
包含vlan头部的二层头部结构体
点击(此处)折叠或打开
struct vlan_ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_vlan_proto; /* Should always be 0x8100 */
__be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */
__be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */
};
1.2 struct vlan_hdr
vlan头部关联的结构体
点击(此处)折叠或打开
struct vlan_hdr {
__be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */
__be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */
};
不支持VLAN的网卡
对于不支持VLAN的网卡,也就不能识别报文中Type为0x8100这个类型有什么特殊之处,网卡驱动会将其当作普通mac帧收上来。注意此时,如果是正常的mac帧(非VLAN),skb->protocol会被设置成mac帧的第13、14字节,也就是(Length/Type)中的Type,而对于VLAN的mac帧来说同样会被设置为mac帧的第13、14字节,但此时是802.1Q Tag中的Type(至于为什么,看下VLAN的格式就明白了)。
所以对于不支持VLAN的网卡收到VLAN mac帧后,skb->protocol是等于0x8100的。有了这个背景再看下面的处理逻辑。
首先,无论什么数据包通过网卡驱动后都会进入netif_receive_skb函数。
下面看netif_receive_skb函数,其中已经出去和VLAN接收的无关逻辑。
int netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
//这里是重点,但是只有网卡支持VLAN时才会设置skb->vlan_tci
if (skb->vlan_tci && vlan_hwaccel_do_receive(skb))
return NET_RX_SUCCESS;
//……
//遍历ptye_all链表,上面的paket_type.type为ETH_P_ALL,
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
ptype->dev == orig_dev) {
if (pt_prev)//注意,此时orig_dev为物理dev,如eth0
//此函数最终调用paket_type.func()
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
//bridge逻辑(可以看到bridge逻辑再VLAN处理之前)
skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
//这里和VLAN没有关系,而是mac-vlan的相关功能,编译内核时选上MAC_VLAN模块,下面才会执行
skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
//这里的type被置为VLAN协议,即0x8100
type = skb->protocol;
//处理ptype_base[ntohs(type)&15]上的所有的packet_type->func()
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type &&
(ptype->dev == null_or_orig || ptype->dev == skb->dev ||
ptype->dev == orig_dev)) {
if (pt_prev)
//此函数最终调用paket_type.func(),由于type为802.1Q的协议,所以会调用其对应的协议处理函数。
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
//……
}
在加载8021q时会注册相应packet_type,同时初始化相关处理函数func。
staticstructpacket_type vlan_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_8021Q),
.func = vlan_skb_recv,/* VLAN receive method */
};
所以接下来会调用vlan_skb_recv函数。
net/8021q/vlan_dev.c
lvlan_skb_recv
int vl
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
