Linux協議棧對vlan的處理
阿新 • • 發佈:2019-01-10
(基於linux-2.6.x)
從程式碼上看,Linux對VLAN的處理方式如下。
1. vlan的處理,主要是依靠網絡卡本身。
有的網絡卡不支援vlan,如老的3com網絡卡3c501。
intel的ixgb(PRO/10GbE)和e1000(PRO/1000)網絡卡是支援vlan的。
其他的一些網絡卡驅動,從程式碼上來看,還未完整支援。
例如,有個網絡卡驅動(原始碼檔案:drivers\net\spider_net.c),
vlan相關程式碼上的註釋上說,/* further enhancement... yet to do */
2. 網絡卡對vlan的處理
VLAN tag插入/移除 都是由網絡卡完成的。
vlan報文的過濾也是由網絡卡完成的。
Linux協議棧通過驅動中的介面,註冊vlan相關資訊。
驅動再將這些資訊寫到晶片中。
rtl8169_rx_vlan_tag(desc, skb);
if (likely(polling))
napi_gro_receive(&tp->napi, skb);
else
netif_rx(skb);
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
從註釋及程式碼可以看出,就是將vlan_tci記錄到skb中,這樣協議棧能知道這個報文的vlan資訊,從而進行相應的處理。
3. Linux對vlan報文的處理(VLAN tag已經剝掉了)
上一步的工作完成後,接下來的工作有兩種情況。
a)報文不是vlan報文,則驅動程式呼叫netif_receive_skb對報文進行處理。
其處理流程在《Linux協議棧程式碼閱讀筆記(三)報文接收》中有描述。
b)報文是vlan報文(不過已經不帶VLAN tag了),則驅動程式呼叫vlan_hwaccel_receive_skb對報文進行處理,vlan tag通過 引數傳遞給vlan_hwaccel_receive_skb。
vlan_hwaccel_receive_skb則簡單的以如下形式呼叫__vlan_hwaccel_rx。
__vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
__vlan_hwaccel_rx先根據vlan tag為報文做優先順序賦值。
然後將低層程式碼誤以為vlan報文的目的mac不是本機的錯誤糾正過來。
從程式碼上看,Linux對VLAN的處理方式如下。
1. vlan的處理,主要是依靠網絡卡本身。
有的網絡卡不支援vlan,如老的3com網絡卡3c501。
intel的ixgb(PRO/10GbE)和e1000(PRO/1000)網絡卡是支援vlan的。
其他的一些網絡卡驅動,從程式碼上來看,還未完整支援。
例如,有個網絡卡驅動(原始碼檔案:drivers\net\spider_net.c),
vlan相關程式碼上的註釋上說,/* further enhancement... yet to do */
2. 網絡卡對vlan的處理
VLAN tag插入/移除 都是由網絡卡完成的。
vlan報文的過濾也是由網絡卡完成的。
Linux協議棧通過驅動中的介面,註冊vlan相關資訊。
驅動再將這些資訊寫到晶片中。
因此,網絡卡驅動從網絡卡接收佇列中收到的報文,已經不帶VLAN tag了。
下面是r8169.c網絡卡驅動收到報文後,做的部分處理。
由於驅動收到的報文,已經不帶vlan tag,因此skb->protocol的值就是普通的乙太網型別。
skb->protocol = eth_type_trans(skb, dev);rtl8169_rx_vlan_tag(desc, skb);
if (likely(polling))
napi_gro_receive(&tp->napi, skb);
else
netif_rx(skb);
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
再看看rtl8169_rx_vlan_tag幹了什麼。下面貼出相關程式碼:
/** * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting * @skb: skbuff to tag * @vlan_tci: VLAN TCI to insert * * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest */ static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, u16 vlan_tci) { skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci; return skb; } static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb) { u32 opts2 = le32_to_cpu(desc->opts2); if (opts2 & RxVlanTag) __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff)); desc->opts2 = 0; }
從註釋及程式碼可以看出,就是將vlan_tci記錄到skb中,這樣協議棧能知道這個報文的vlan資訊,從而進行相應的處理。
因為vlan tag被硬體剝掉了,軟體不知道vlan資訊,因此這裡的程式碼將剝掉的vlan資訊記錄到SKB中,供協議棧使用。
3. Linux對vlan報文的處理(VLAN tag已經剝掉了)
上一步的工作完成後,接下來的工作有兩種情況。
a)報文不是vlan報文,則驅動程式呼叫netif_receive_skb對報文進行處理。
其處理流程在《Linux協議棧程式碼閱讀筆記(三)報文接收》中有描述。
b)報文是vlan報文(不過已經不帶VLAN tag了),則驅動程式呼叫vlan_hwaccel_receive_skb對報文進行處理,vlan tag通過 引數傳遞給vlan_hwaccel_receive_skb。
vlan_hwaccel_receive_skb則簡單的以如下形式呼叫__vlan_hwaccel_rx。
__vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
__vlan_hwaccel_rx先根據vlan tag為報文做優先順序賦值。
然後將低層程式碼誤以為vlan報文的目的mac不是本機的錯誤糾正過來。
接下來,__vlan_hwaccel_rx呼叫netif_receive_skb。這就將處理流程收斂到與a)相同的路線上去了:)