【lwip】07-鏈路層收發以太網數據幀源碼分析( 三 )

7.8 虛擬局域網VLAN源碼分析7.8.1 以太網標準幀和VLAN幀的區別以太網標準數據幀報文及帶VLAN標簽的以太網標準數據幀報文的差異:

【lwip】07-鏈路層收發以太網數據幀源碼分析

文章插圖
VLAN字段是插入在以太網首部字段中 。再看代碼實現,就明白了 。
7.8.2 以太網發送帶VLAN數據幀VLAN字段數據結構:
  • TPID和TCI字段倒置 。就是為了代碼簡易 。
/** VLAN header inserted between ethernet header and payload * if 'type' in ethernet header is ETHTYPE_VLAN. * See IEEE802.Q */struct eth_vlan_hdr {PACK_STRUCT_FIELD(u16_t prio_vid);PACK_STRUCT_FIELD(u16_t tpid);} PACK_STRUCT_STRUCT;組建帶VLAN標簽的以太網幀代碼段:
  • 因為只能偏移整個以太網幀首部,多偏移了類型字段的兩個字節 。
  • 所以按上述VLAN數據結構來看,ACK_STRUCT_FIELD(u16_t tpid);實際指向的是以太網類型字段 。
  • 而為了兼容后面代碼一致性 , eth_type_be = PP_HTONS(ETHTYPE_VLAN);才是真正的VLAN的TPID字段 。
vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR); /* 這里注意偏移 。了解帶VLAN標簽的以太網幀報文就知道下面的操作 */vlanhdr->tpid= eth_type_be; /* 以太網的類型字段 */vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); /* VLAN標簽的TCI字段 */eth_type_be = PP_HTONS(ETHTYPE_VLAN); /* 這里才是VLAN的TPID字段(代碼實現的手法) */7.8.3 以太網接收帶VLAN數據幀ethernet_input()接收到數據幀時VLAN部分代碼處理:
如果對VLAN不感興趣 , 上面代碼可以直接忽略VLAN部分,這樣會更加便于分析 。
其中檢查過濾VLAN , 有三種方式(僅能選其一),優先級又高到低,描述如下:
  • LWIP_HOOK_VLAN_CHECK:VLAN鉤子函數,檢查當前數據幀是否是需要的VLAN 。被ethernet_input()函數調用 。
  • ETHARP_VLAN_CHECK_FN:也是檢查當前數據幀是否是需要的VLAN 。返回1表示接受該數據幀 。
  • ETHARP_VLAN_CHECK:指定一個VLAN ID,整個協議棧只接收該VLAN的流量 。
7.8.4 開啟VLAN功能ETHARP_SUPPORT_VLAN/** * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) * that returns 1 to accept a packet or 0 to drop a packet. */#if !defined ETHARP_SUPPORT_VLAN || defined __DOXYGEN__#define ETHARP_SUPPORT_VLAN1#endifLWIP_HOOK_VLAN_CHECK鉤子格式說明:
/** * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): * Called from ethernet_input() if VLAN support is enabled * Signature:\code{.c} *int my_hook(struct netif *netif, struct eth_hdr *eth_hdr, struct eth_vlan_hdr *vlan_hdr); * \endcode * Arguments: * - netif: struct netif on which the packet has been received * - eth_hdr: struct eth_hdr of the packet * - vlan_hdr: struct eth_vlan_hdr of the packet * Return values: * - 0: Packet must be dropped. * - != 0: Packet must be accepted. */#ifdef __DOXYGEN__#define LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr)#endif7.9 一個硬件映射到多個IP一個硬件映射到多個IP的實現需要開啟LWIP_ARP_FILTER_NETIF宏并定義LWIP_ARP_FILTER_NETIF_FN()函數 。
LWIP_ARP_FILTER_NETIF_FN()函數會在ethernet_input()以太網接收到數據幀處理時被調用,會根據數據幀的內容更新出的netif 。
該函數代碼實現思路說明:
  • 根據以太網數據幀協議類型區別出IP、ARP或者其它協議 。
  • 再根據協議分析出目標協議地址IP 。
  • 再遍歷netif鏈表,匹配IP 。
注意,該函數調用是在VLAN過濾后才被調用的 。因為VLAN屬于鏈路層,映射多個IP的判斷字段屬于網絡層 。
/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) * to a filter function that returns the correct netif when using multiple * netifs on one hardware interface where the netif's low-level receive * routine cannot decide for the correct netif (e.g. when mapping multiple * IP addresses to one hardware interface). */#ifndef LWIP_ARP_FILTER_NETIF#define LWIP_ARP_FILTER_NETIF 1#endif

推薦閱讀