linux内核中VLAN收发处理,linux内核中VLAN收发处理

linux内核中VLAN收发处理

——lvyilong316

VLAN报文格式

基于802.1Q的VLAN帧格式如下:

31b4597155fe5c9c3b476646525284d8.png

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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部