lldp的接收状态机,参见lldp标准文档。该实现代码和标准文档基本一致,变量名和函数名都大部分相同。
int rxProcessFrame(struct lldp_port *lldp_port) { … … /* 主要是验证报文的正确性:具体要验证报文的目的地址以及报文类型字段 */ /* As per section 10.3.1, verify the destination and ethertype */ expect_hdr.dst[0] = 0x01; expect_hdr.dst[1] = 0x80; expect_hdr.dst[2] = 0xc2; expect_hdr.dst[3] = 0x00; expect_hdr.dst[4] = 0x00; expect_hdr.dst[5] = 0x0e; expect_hdr.ethertype = htons(0x88cc); ether_hdr = (struct eth_hdr *)&lldp_port->rx.frame[0]; debug_printf(DEBUG_INT, "LLPDU Dst: "); debug_hex_printf(DEBUG_INT, (uint8_t *)ether_hdr->dst, 6); debug_printf(DEBUG_EXCESSIVE, "Expect Dst: "); debug_hex_printf(DEBUG_EXCESSIVE, (uint8_t *)expect_hdr.dst, 6); /* Validate the frame's destination */ if( ether_hdr->dst[0] != expect_hdr.dst[0] || ether_hdr->dst[1] != expect_hdr.dst[1] || ether_hdr->dst[2] != expect_hdr.dst[2] || ether_hdr->dst[3] != expect_hdr.dst[3] || ether_hdr->dst[4] != expect_hdr.dst[4] || ether_hdr->dst[5] != expect_hdr.dst[5] ) { debug_printf(DEBUG_NORMAL, "[ERROR] This frame is incorrectly addressed to: "); debug_hex_printf(DEBUG_NORMAL, (uint8_t *)ether_hdr->dst, 6); debug_printf(DEBUG_NORMAL, "[ERROR] This frame should be addressed to: "); debug_hex_printf(DEBUG_NORMAL, (uint8_t *)expect_hdr.dst, 6); debug_printf(DEBUG_NORMAL, "[ERROR] statsFramesInTotal will *NOT* be incremented\n"); badFrame++; } debug_printf(DEBUG_INT, "LLPDU Src: "); debug_hex_printf(DEBUG_INT, (uint8_t *)ether_hdr->src, 6); debug_printf(DEBUG_INT, "LLPDU Ethertype: %x\n", htons(ether_hdr->ethertype)); debug_printf(DEBUG_EXCESSIVE, "Expect Ethertype: %x\n", htons(expect_hdr.ethertype)); /* Validate the frame's ethertype */ if(ether_hdr->ethertype != expect_hdr.ethertype) { debug_printf(DEBUG_NORMAL, "[ERROR] This frame has an incorrect ethertype of: '%x'.\n", htons(ether_hdr->ethertype)); badFrame++; } if(!badFrame) { lldp_port->rx.statistics.statsFramesInTotal ++; } … … /* 请注意lldp报文TLV的格式,前7个bits为tlv类型字段,后9个位数据长度字段。 */ /* Grab the first 9 bits */ tlv_length = htons(*tlv_hdr) & 0x01FF; /* Then shift to get the last 7 bits */ tlv_type = htons(*tlv_hdr) >> 9; /* lldp报文中tlv最少为4个,分别为Chasis ID TLV、Port ID TLV、TTL TLV、End TLV */ /* Validate as per 802.1AB section 10.3.2*/ if(num_tlvs <= 3) { if(num_tlvs != tlv_type) { debug_printf(DEBUG_NORMAL, "[ERROR] TLV number %d should have tlv_type %d, but is actually %d\n", num_tlvs, num_tlvs, tlv_type); debug_printf(DEBUG_NORMAL, "[ERROR] statsFramesDiscardedTotal and statsFramesInErrorsTotal will be incremented as per 802.1AB 10.3.2\n"); lldp_port->rx.statistics.statsFramesDiscardedTotal++; lldp_port->rx.statistics.statsFramesInErrorsTotal++; badFrame++; } } /* 缓存lldp报文中tlv的值 */ tlv->type = tlv_type; tlv->length = tlv_length; if(tlv->length > 0) tlv->info_string = calloc(1, tlv_length); /* 如果LLDP中的tlv为TTL,那么则更新rx.timers.rxTTL的值 */ if(tlv_type == TIME_TO_LIVE_TLV) { if(tlv_length != 2) { debug_printf(DEBUG_NORMAL, "[ERROR] TTL TLV has an invalid length! Should be '2', but is '%d'\n", tlv_length); #ifndef WIN32 #warning We should actually discard this frame and print out an error... #warning Write a unit test to stress this #endif // WIN32 } else { lldp_port->rx.timers.rxTTL = htons(*(uint16_t *)&tlv_info_string[0]); msap_ttl_tlv = tlv; debug_printf(DEBUG_EXCESSIVE, "rxTTL is: %d\n", lldp_port->rx.timers.rxTTL); } } if(tlv->info_string) { memset(tlv->info_string, 0x0, tlv_length); memcpy(tlv->info_string, tlv_info_string, tlv_length); } /* Validate the TLV */ if(validate_tlv[tlv_type] != NULL) { debug_printf(DEBUG_EXCESSIVE, "Found a validator for TLV type %d.\n", tlv_type); debug_hex_dump(DEBUG_EXCESSIVE, tlv->info_string, tlv->length); if(validate_tlv[tlv_type](tlv) != XVALIDTLV) { badFrame++; } } else { // NOTE: Any organizationally specific TLVs should get processed through validate_generic_tlv debug_printf(DEBUG_EXCESSIVE, "Didn't find specific validator for TLV type %d. Using validate_generic_tlv.\n", tlv_type); if(validate_generic_tlv(tlv) != XVALIDTLV) { badFrame++; } } … … /* 将之前缓存的lldp报文中tlv加入到tlv_list中 */ cached_tlv = initialize_tlv(); if(tlvcpy(cached_tlv, tlv) != 0) { debug_printf(DEBUG_TLV, "Error copying TLV for MSAP cache!\n"); } debug_printf(DEBUG_EXCESSIVE, "Adding exploded TLV to MSAP TLV list.\n"); // Now we can start stuffing the msap data... ;) add_tlv(cached_tlv, &tlv_list); /* 如果是CHASSIS_ID_TLV和PORT_ID_TLV,那么则缓存它们的值。并将它们拼接为msap_id */ if(tlv_type == CHASSIS_ID_TLV) { debug_printf(DEBUG_NORMAL, "Copying TLV1 for MSAP Processing...\n"); msap_tlv1 = initialize_tlv(); tlvcpy(msap_tlv1, tlv); } else if(tlv_type == PORT_ID_TLV) { debug_printf(DEBUG_NORMAL, "Copying TLV2 for MSAP Processing...\n"); msap_tlv2 = initialize_tlv(); tlvcpy(msap_tlv2, tlv); //Minus 2, for the chassis id subtype and port id subtype... // IEEE 802.1AB specifies that the MSAP shall be composed of // The value of the subtypes. msap_id = calloc(1, msap_tlv1->length - 1 + msap_tlv2->length - 1); if(msap_id == NULL) { debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__); } // Copy the first part of the MSAP memcpy(msap_id, &msap_tlv1->info_string[1], msap_tlv1->length - 1); // Copy the second part of the MSAP memcpy(&msap_id[msap_tlv1->length - 1], &msap_tlv2->info_string[1], msap_tlv2->length - 1); msap_length = (msap_tlv1->length - 1) + (msap_tlv2->length - 1); debug_printf(DEBUG_MSAP, "MSAP TLV1 Length: %d\n", msap_tlv1->length); debug_printf(DEBUG_MSAP, "MSAP TLV2 Length: %d\n", msap_tlv2->length); debug_printf(DEBUG_MSAP, "MSAP is %d bytes: ", msap_length); debug_hex_printf(DEBUG_MSAP, msap_id, msap_length); debug_hex_dump(DEBUG_MSAP, msap_id, msap_length); // Free the MSAP pieces destroy_tlv(&msap_tlv1); destroy_tlv(&msap_tlv2); msap_tlv1 = NULL; msap_tlv2 = NULL; /* 指示有新的邻居信息到来*/ have_msap = 1; } … … if(have_msap) { #ifndef WIN32 #warning We need to verify whether this is actually the case. #endif // WIN32 lldp_port->rxChanges = TRUE; debug_printf(DEBUG_TLV, "We have a(n) %d byte MSAP!\n", msap_length); /* 创建一条新的保存邻居信息的lldp_msap结构体,并将之前缓存的tlv信息复制到其中。然后更新该端口对应的lldp_port结构体中的lldp_msap信息。亦即更新该底层端口对应的邻居信息。 */ msap_cache = calloc(1, sizeof(struct lldp_msap)); msap_cache->id = msap_id; msap_cache->length = msap_length; msap_cache->tlv_list = tlv_list; msap_cache->next = NULL; msap_cache->ttl_tlv = msap_ttl_tlv; msap_ttl_tlv = NULL; //debug_printf(DEBUG_MSAP, "Iterating MSAP Cache...\n"); //iterate_msap_cache(msap_cache); //debug_printf(DEBUG_MSAP, "Updating MSAP Cache...\n"); debug_printf(DEBUG_MSAP, "Setting rxInfoTTL to: %d\n", lldp_port->rx.timers.rxTTL); msap_cache->rxInfoTTL = lldp_port->rx.timers.rxTTL; update_msap_cache(lldp_port, msap_cache); if(msap_tlv1 != NULL) { debug_printf(DEBUG_NORMAL, "Error: msap_tlv1 is still allocated!\n"); free(msap_tlv1); msap_tlv1 = NULL; } if(msap_tlv2 != NULL) { debug_printf(DEBUG_NORMAL, "Error: msap_tlv2 is still allocated!\n"); free(msap_tlv2); msap_tlv2 = NULL; } } else { debug_printf(DEBUG_NORMAL, "[ERROR] No MSAP for TLVs in Frame!\n"); } /* Report frame errors */ if(badFrame) { rxBadFrameInfo(badFrame); } return badFrame; }
rxProcessFrame主要是提取了报文中的tlv,解析为对应的lldp_tlv节点,并缓存相应的信息,最终构造lldp_msap结构体。并更新邻居信息。而在update_msap_cache函数中,会判断rxProcessFrame函数构造的lldp_msap在本端口的lldp_msap链表中是否存在。若存在,那么直接进行替换(不检查是否完全完全相等,简便的做法)。若不存在,则说明是一个新邻居,那么完成邻居信息结构体lldp_msap的链表插入工作。
在lldp报文中tlv被组织为7bit的type字段,9bit的length字段。这种组织方式,在存储tlv时,极为不便。这里将这种组织方式转化为lldp_tlv的组织方式。type和length都可以使用现有的数据类型表示,方便程序的编写。