数据包VLAN标签的剥离和添加

使用vconfig或者ip命令创建的802.1q虚拟设备, 并不会负责vlan标签的剥离和添加。其操作位于数据包的接收和发送流程中。

vconfig add eth0 10
或者
ip link add link eth0 eth0.10 type vlan id 10


vlan标签的剥离是在数据包接收函数__netif_receive_skb_core中处理,skb_vlan_untag函数最终执行untag标签剥离操作。首先将vlan协议类型(ETH_P_8021Q/ETH_P_8021AD)保存在skb的vlan_proto中,将vlan_tci(标签控制信息)保存在skb的vlan_tci中,之后将skb的data跳过VLAN信息字段(VLAN_HLEN - 4字节),即进行vlan标签剥离。


static inline void __vlan_hwaccel_put_tag(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
{
    skb->vlan_proto = vlan_proto;
    skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
}
struct sk_buff *skb_vlan_untag(struct sk_buff *skb)
{
    vhdr = (struct vlan_hdr *)skb->data;
    vlan_tci = ntohs(vhdr->h_vlan_TCI);
    __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci);
	skb_pull_rcsum(skb, VLAN_HLEN);
}


数据包发送过程中,__dev_queue_xmit函数在执行发送操作的时候调用validate_xmit_skb添加vlan标签。sch_direct_xmit函数同样会调用validate_xmit_skb验证函数,但是由于vlan设备在创建的时候IFF_NO_QUEUE标志,不会进入流控系统,所以vlan数据包最终是由__dev_queue_xmit直接发送。__vlan_hwaccel_push_inside函数将vlan标签插入到数据包中。


void vlan_setup(struct net_device *dev)
{
    dev->priv_flags     |= IFF_802_1Q_VLAN | IFF_NO_QUEUE;
}

static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb)
{
    skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, skb_vlan_tag_get(skb));
}

static struct sk_buff *validate_xmit_vlan(...)
{
    skb = __vlan_hwaccel_push_inside(skb);
}
static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
{
    skb = validate_xmit_vlan(skb, features);
}


内核版本  linux-4.14.4



你可能感兴趣的:(网桥子系统)