【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

推荐阅读