vlan 介紹

簡介
     在Linux中安裝了802.1Q標籤VLAN功能。VLAN是虛擬分配以太網的功能。
使用VLAN ID從物理上將一個以太網分割開。在VLAN環境下,具備相同VLAN ID
就能夠相互通訊,可是即便將LAN線鏈接到相同集線器或交換機上,VLAN ID不一樣
也不能相互通訊。
 
802.1Q的以太幀格式
 
由上圖,惟一的變化是加入了一對2字節字段。第一個2字節是VLAN協議標識符,
它的值老是0x8100.因爲這個數值大於1500,所以,全部的以太網卡都不會將
它解釋成類型(type),而不是長度。第二個2字節包含三個子字段。最主要的是
VLAN標識符字段,它佔用低12位。優先級和CFI的做用不明顯,具體能夠參考【1】的第4.8.5一節。
 
vlan在網卡驅動及協議棧的處理
     以igb網卡爲例,從napi的poll函數開始調用狀況以下:
igb_poll
     ==》
          igb_clean_rx_irq
          ==》
               igb_receive_skb
             
在igb_clean_rx_irq實現中:
5988
5989         if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
5990             test_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &rx_ring->flags))
5991             vlan_tag = be16_to_cpu(rx_desc->wb.upper.vlan);
5992         else
5993             vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
5994
5995         total_bytes += skb->len;
5996         total_packets++;
5997
5998         skb->protocol = eth_type_trans(skb, rx_ring->netdev);
5999
6000         igb_receive_skb(q_vector, skb, vlan_tag);
6001
View Code

第5989到5993行會讀取vlan_tag。api

函數igb_receive_skb的實現以下:網絡

5829 static void igb_receive_skb(struct igb_q_vector *q_vector,
5830                             struct sk_buff *skb,
5831                             u16 vlan_tag)
5832 {
5833     struct igb_adapter *adapter = q_vector->adapter;
5834
5835     if (vlan_tag && adapter->vlgrp)
5836         vlan_gro_receive(&q_vector->napi, adapter->vlgrp,
5837                          vlan_tag, skb);
5838     else
5839         napi_gro_receive(&q_vector->napi, skb);
5840 }
View Code
內核模塊捕獲VLAN
     經過 vlan_gro_receive 和  napi_gro_receive的數據幀是有區別的。當咱們使用命令
vconfig add eth1 22 建立vlan設備後,數據幀將會經過vlan_gro_receive,不然將會經過
napi_gro_receive到達netif_receive_skb。
     對於依然帶有VLAN信息的數據包,捕獲相應的數據包可採用jprobe的方法,按以下實現:
int jpf_netif_receive_skb(struct sk_buff *skb)
{
        unsigned short sport, dport;
        __be32 saddr, daddr;
        char dsthost[16];
        struct iphdr *iph;
        struct tcphdr *tcph;

        skb_linearize(skb);
        iph = (struct iphdr *)(skb->data + 4);
        tcph = (struct tcphdr *)((skb->data + 4) + (iph->ihl << 2));

        if (iph->protocol == IPPROTO_TCP) {
                sport = tcph->source;
                dport = tcph->dest;
                saddr = iph->saddr;
                daddr = iph->daddr;

               snprintf(dsthost, 16, "%pI4", &daddr);
               printk(KERN_INFO "ip is:%s", dsthost);
        }
        jprobe_return();
        return 0;
}
 
struct jprobe jps_netif_receive_skb = {
    .entry = jpf_netif_receive_skb,
    .kp = {
        .symbol_name = "netif_receive_skb",
    }, 
};
View Code
若是vconfig的方式建立了VLAN設備,那麼不須要對skb->data進行4字節的偏移就能夠捕獲到想要的數據包。
 
參考資料
【0】LINUX內核精髓(精通LINUX內核必會的75個技巧)
【1】計算機網絡 第5版 嚴偉,潘愛民譯
相關文章
相關標籤/搜索