From b7ef68b02f6d295ff10f94493b87ed6770837a13 Mon Sep 17 00:00:00 2001 From: Longxiang Lyu Date: Thu, 16 Dec 2021 01:51:42 +0000 Subject: [PATCH] Add sentinel TLV Signed-off-by: Longxiang Lyu --- src/link_prober/IcmpPayload.cpp | 50 +++++++++------------ src/link_prober/IcmpPayload.h | 73 ++++++++++++++++++------------ src/link_prober/LinkProber.cpp | 80 ++++++++++++++++++--------------- src/link_prober/LinkProber.h | 1 + test/LinkProberTest.cpp | 29 ++++++------ 5 files changed, 126 insertions(+), 107 deletions(-) diff --git a/src/link_prober/IcmpPayload.cpp b/src/link_prober/IcmpPayload.cpp index 2690275a..4b309621 100644 --- a/src/link_prober/IcmpPayload.cpp +++ b/src/link_prober/IcmpPayload.cpp @@ -32,25 +32,33 @@ namespace link_prober { // -// ---> TlvPayload(); +// static members +// +boost::uuids::uuid IcmpPayload::mGuid; +uint32_t IcmpPayload::mCookie = 0x47656d69; +uint32_t IcmpPayload::mVersion = 0; + // -// struct constructor +// ---> TlvCommand(); // -TlvPayload::TlvPayload(uint8_t tlv_type) : - type(tlv_type) +// struct TlvCommand constructor +// +TlvCommand::TlvCommand() : + type(tlvtype), length(htons(1)), command(static_cast (Command::COMMAND_SWITCH_ACTIVE)) { - if (tlv_type == 0) - { - new (&cmdtlv) TlvCommand(); - } } // -// static members +// ---> TlvSentinel(); // -boost::uuids::uuid IcmpPayload::mGuid; -uint32_t IcmpPayload::mCookie = 0x47656d69; -uint32_t IcmpPayload::mVersion = 0; +// struct TlvSentinel constructor +// +TlvSentinel::TlvSentinel() : + type(tlvtype), length(htons(1)) +{ +} + + // // ---> IcmpPayload(); @@ -60,27 +68,11 @@ uint32_t IcmpPayload::mVersion = 0; IcmpPayload::IcmpPayload() : cookie(htonl(mCookie)), version(htonl(mVersion)), - seq(0), - tlv(0) + seq(0) { memcpy(uuid, mGuid.data, sizeof(uuid)); } -// -// ---> getPayloadSize() -// -// return the actual payload size -// -unsigned int IcmpPayload::getPayloadSize() -{ - unsigned int size = sizeof(IcmpPayload); - if (tlv.type == static_cast (TlvType::TLV_COMMAND)) - { - size += sizeof(TlvCommand) - sizeof(TlvPayload); - } - return size; -} - // // ---> generateGuid() // diff --git a/src/link_prober/IcmpPayload.h b/src/link_prober/IcmpPayload.h index 7fe8c941..7a269897 100644 --- a/src/link_prober/IcmpPayload.h +++ b/src/link_prober/IcmpPayload.h @@ -42,6 +42,25 @@ __BEGIN_DECLS namespace link_prober { +/** + *@enum TlvType + * + *@brief Supported TLV types + */ +enum TlvType: uint8_t { + TLV_COMMAND = 1, + TLV_SENTINEL = 0x0f, + TLV_COUNT +}; + +#define TlvHead \ + uint8_t type; \ + uint16_t length + +struct Tlv +{ + TlvHead; +}; /** *@enum Command @@ -55,15 +74,6 @@ enum class Command: uint8_t { Count }; -/** - *@enum TlvType - * - *@brief Supported TLV types - */ -enum class TlvType: uint8_t { - TLV_COMMAND -}; - /** *@struct TlvCommand * @@ -71,22 +81,35 @@ enum class TlvType: uint8_t { */ struct TlvCommand { - uint8_t type = 0; - uint16_t length = htons(1); - uint8_t command = static_cast (Command::COMMAND_NONE); + TlvHead; + uint8_t command; + static const uint8_t tlvtype = TlvType::TLV_COMMAND; + + /** + *@method TlvCommand + * + *@brief struct TlvCommand default constructor + */ + TlvCommand(); } __attribute__((packed)); /** - *@union TlvPayload + *@struct TlvCommand * - *@brief Union to support multiple TLV structs + *@brief Build command TLV */ -union TlvPayload +struct TlvSentinel { - uint8_t type; - TlvCommand cmdtlv; + TlvHead; + uint8_t padding = 0; + static const uint8_t tlvtype = TlvType::TLV_SENTINEL; - TlvPayload(uint8_t tlv_type = 0); + /** + *@method TlvSentinel + * + *@brief struct TlvSentinel default constructor + */ + TlvSentinel(); } __attribute__((packed)); /** @@ -99,7 +122,6 @@ struct IcmpPayload { uint32_t version; uint8_t uuid[8]; uint64_t seq; - TlvPayload tlv; /** *@method IcmpPayload @@ -108,15 +130,6 @@ struct IcmpPayload { */ IcmpPayload(); - /** - *@method getPayloadSize - * - *@brief get the ICMP payload size based on the tlv contained - * - *@return the ICMP payload actual size - */ - unsigned int getPayloadSize(); - /** *@method generateGuid * @@ -171,6 +184,10 @@ struct IcmpPayload { static_assert(sizeof(IcmpPayload) % 2 == 0, "ICMP Payload size should be even sized, please add zero padding"); +static_assert(sizeof(TlvCommand) % 2 == 0, "TLV size should be even sized, please add zero padding"); + +static_assert(sizeof(TlvSentinel) % 2 == 0, "TLV size should be even sized, please add zero padding"); + static_assert(sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) < MUX_MAX_ICMP_BUFFER_SIZE, "Buffer Size doesn't fit Link Prober ICMP packet with its payload"); diff --git a/src/link_prober/LinkProber.cpp b/src/link_prober/LinkProber.cpp index 78a382f7..c44e6d3a 100644 --- a/src/link_prober/LinkProber.cpp +++ b/src/link_prober/LinkProber.cpp @@ -232,18 +232,18 @@ void LinkProber::handleUpdateEthernetFrame() // void LinkProber::handleSendSwitchCommand() { - IcmpPayload *icmpPayload = reinterpret_cast ( - mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) - ); - icmpPayload->tlv.cmdtlv.command = static_cast (Command::COMMAND_SWITCH_ACTIVE); + new (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload)) TlvCommand(); + new (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvCommand)) TlvSentinel(); icmphdr *icmpHeader = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr)); - computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(*icmpPayload)); + computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvCommand) + sizeof(TlvSentinel)); + mTxPacketSize = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvCommand) + sizeof(TlvSentinel); sendHeartbeat(); - icmpPayload->tlv.cmdtlv.command = static_cast (Command::COMMAND_NONE); - computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(*icmpPayload)); + new (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload)) TlvSentinel(); + computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvSentinel)); + mTxPacketSize = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvSentinel); // inform the composite state machine about commend send completion boost::asio::io_service::strand &strand = mLinkProberStateMachine.getStrand(); @@ -269,13 +269,7 @@ void LinkProber::sendHeartbeat() if (!mSuspendTx) { updateIcmpSequenceNo(); boost::system::error_code errorCode; - IcmpPayload *icmpPayload = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr)); - mStream.write_some( - boost::asio::buffer( - mTxBuffer.data(), sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + icmpPayload->getPayloadSize() - ), - errorCode - ); + mStream.write_some(boost::asio::buffer(mTxBuffer.data(), mTxPacketSize), errorCode); if (errorCode) { MUXLOGTRACE(mMuxPortConfig.getPortName() + ": Failed to send heartbeat!"); @@ -314,28 +308,42 @@ void LinkProber::handleRecv( mMuxPortConfig.getPortName() % mMuxPortConfig.getBladeIpv4Address().to_string() ); - if (icmpPayload->tlv.type == static_cast (TlvType::TLV_COMMAND)) + bool isMatch = memcmp(icmpPayload->uuid, IcmpPayload::getGuidData(), sizeof(icmpPayload->uuid)); + if (isMatch) { - if (memcmp(icmpPayload->uuid, IcmpPayload::getGuidData(), sizeof(icmpPayload->uuid)) == 0) { - MUXLOGTRACE(boost::format("%s: Matching Guid") % mMuxPortConfig.getPortName()); - // echo reply for an echo request generated by this/active ToR - mRxSelfSeqNo = mTxSeqNo; - mLinkProberStateMachine.postLinkProberStateEvent(LinkProberStateMachine::getIcmpSelfEvent()); - } else { - // echo reply for an echo request generated by peer ToR - mRxPeerSeqNo = mTxSeqNo; - mLinkProberStateMachine.postLinkProberStateEvent(LinkProberStateMachine::getIcmpPeerEvent()); - if (ntohl(icmpPayload->tlv.cmdtlv.command) == static_cast (Command::COMMAND_SWITCH_ACTIVE)) { - boost::asio::io_service::strand &strand = mLinkProberStateMachine.getStrand(); - boost::asio::io_service &ioService = strand.context(); - ioService.post(strand.wrap(boost::bind( - static_cast - (&LinkProberStateMachine::processEvent), - &mLinkProberStateMachine, - LinkProberStateMachine::getSwitchActiveRequestEvent() - ))); + MUXLOGTRACE(boost::format("%s: Matching Guid") % mMuxPortConfig.getPortName()); + // echo reply for an echo request generated by this/active ToR + mRxSelfSeqNo = mTxSeqNo; + mLinkProberStateMachine.postLinkProberStateEvent(LinkProberStateMachine::getIcmpSelfEvent()); + } + + uint8_t tlvStartOffset = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload); + while (tlvStartOffset + sizeof(Tlv) < MUX_MAX_ICMP_BUFFER_SIZE) + { + Tlv *currentTlv = reinterpret_cast (mTxBuffer.data() + tlvStartOffset); + if (currentTlv->type == TlvType::TLV_COMMAND) { + TlvCommand *tlvCommand = reinterpret_cast (mTxBuffer.data() + tlvStartOffset); + if (!isMatch) { + if (tlvCommand->command == static_cast (Command::COMMAND_SWITCH_ACTIVE)) { + boost::asio::io_service::strand &strand = mLinkProberStateMachine.getStrand(); + boost::asio::io_service &ioService = strand.context(); + ioService.post(strand.wrap(boost::bind( + static_cast + (&LinkProberStateMachine::processEvent), + &mLinkProberStateMachine, + LinkProberStateMachine::getSwitchActiveRequestEvent() + ))); + } } + tlvStartOffset += sizeof(TlvCommand); + } else if (currentTlv->type == TlvType::TLV_SENTINEL) { + // sentinel TLV, stop processing + break; + } else { + // unknown TLV type, ignore + break; } + } } else { // Unknown ICMP packet, ignore. @@ -556,11 +564,13 @@ void LinkProber::initializeSendBuffer() iphdr *ipHeader = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header)); icmphdr *icmpHeader = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr)); IcmpPayload *icmpPayload = new (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr)) IcmpPayload(); + TlvSentinel *tlvSentinel = new (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload)) TlvSentinel(); + mTxPacketSize = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvSentinel); ipHeader->ihl = sizeof(iphdr) >> 2; ipHeader->version = IPVERSION; ipHeader->tos = 0xb8; - ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + icmpPayload->getPayloadSize()); + ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvSentinel)); ipHeader->id = static_cast (rand()); ipHeader->frag_off = 0; ipHeader->ttl = 64; @@ -575,7 +585,7 @@ void LinkProber::initializeSendBuffer() icmpHeader->un.echo.id = htons(mMuxPortConfig.getServerId()); icmpHeader->un.echo.sequence = htons(mTxSeqNo); - computeChecksum(icmpHeader, sizeof(icmphdr) + icmpPayload->getPayloadSize()); + computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(*icmpPayload) + sizeof(*tlvSentinel)); } // diff --git a/src/link_prober/LinkProber.h b/src/link_prober/LinkProber.h index c4b87af2..a4a30e3f 100644 --- a/src/link_prober/LinkProber.h +++ b/src/link_prober/LinkProber.h @@ -369,6 +369,7 @@ class LinkProber int mSocket = 0; + std::size_t mTxPacketSize; std::array mTxBuffer; std::array mRxBuffer; diff --git a/test/LinkProberTest.cpp b/test/LinkProberTest.cpp index 9288880c..778475e9 100644 --- a/test/LinkProberTest.cpp +++ b/test/LinkProberTest.cpp @@ -23,7 +23,6 @@ #include #include - #include "common/MuxException.h" #include "link_prober/IcmpPayload.h" #include "LinkProberTest.h" @@ -64,14 +63,13 @@ TEST_F(LinkProberTest, InitializeSendBuffer) iphdr *ipHeader = reinterpret_cast (txBuffer.data() + sizeof(ether_header)); icmphdr *icmpHeader = reinterpret_cast (txBuffer.data() + sizeof(ether_header) + sizeof(iphdr)); - link_prober::IcmpPayload *icmpPayload = new ( - txBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) - ) link_prober::IcmpPayload(); + link_prober::IcmpPayload *icmpPayload = reinterpret_cast (txBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr)); + link_prober::TlvSentinel *tlvSentinel = reinterpret_cast (txBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(*icmpPayload)); EXPECT_TRUE(ipHeader->ihl == sizeof(iphdr) >> 2); EXPECT_TRUE(ipHeader->version == IPVERSION); EXPECT_TRUE(ipHeader->tos == 0xb8); - EXPECT_TRUE(ipHeader->tot_len == htons(sizeof(iphdr) + sizeof(icmphdr) + icmpPayload->getPayloadSize())); + EXPECT_TRUE(ipHeader->tot_len == htons(sizeof(iphdr) + sizeof(icmphdr) + sizeof(link_prober::IcmpPayload) + sizeof(link_prober::TlvSentinel))); EXPECT_TRUE(ipHeader->frag_off == 0); EXPECT_TRUE(ipHeader->ttl == 64); EXPECT_TRUE(ipHeader->protocol == IPPROTO_ICMP); @@ -86,40 +84,41 @@ TEST_F(LinkProberTest, InitializeSendBuffer) EXPECT_TRUE(icmpPayload->cookie == htonl(link_prober::IcmpPayload::getCookie())); EXPECT_TRUE(icmpPayload->version == htonl(link_prober::IcmpPayload::getVersion())); - EXPECT_TRUE(icmpPayload->tlv.type == 0); - EXPECT_TRUE(icmpPayload->tlv.cmdtlv.length == htons(1)); - EXPECT_TRUE(icmpPayload->tlv.cmdtlv.command == static_cast (link_prober::Command::COMMAND_NONE)); EXPECT_TRUE(memcmp( icmpPayload->uuid, link_prober::IcmpPayload::getGuidData(), sizeof(icmpPayload->uuid) ) == 0); + + EXPECT_TRUE(tlvSentinel->type == link_prober::TlvType::TLV_SENTINEL); + EXPECT_TRUE(tlvSentinel->length == htons(1)); + EXPECT_TRUE(tlvSentinel->padding == 0); } TEST_F(LinkProberTest, CalculateChecksum) { - link_prober::IcmpPayload *icmpPayload = new ( + link_prober::IcmpPayload *icmpPayload = reinterpret_cast ( getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) - ) link_prober::IcmpPayload(); + ); boost::uuids::uuid guid = boost::lexical_cast ("44f49d86-c312-414b-b6a1-be82901ac459"); memcpy(icmpPayload->uuid, guid.data, sizeof(icmpPayload->uuid)); initializeSendBuffer(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 12354); + EXPECT_TRUE(icmpHeader->checksum == 12339); } TEST_F(LinkProberTest, UpdateEthernetFrame) { - link_prober::IcmpPayload *icmpPayload = new ( + link_prober::IcmpPayload *icmpPayload = reinterpret_cast ( getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) - ) link_prober::IcmpPayload(); + ); boost::uuids::uuid guid = boost::lexical_cast ("44f49d86-c312-414b-b6a1-be82901ac459"); memcpy(icmpPayload->uuid, guid.data, sizeof(icmpPayload->uuid)); handleUpdateEthernetFrame(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 12354); + EXPECT_TRUE(icmpHeader->checksum == 12339); } TEST_F(LinkProberTest, UpdateSequenceNo) @@ -137,7 +136,7 @@ TEST_F(LinkProberTest, UpdateSequenceNo) handleUpdateSequenceNumber(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 12098); + EXPECT_TRUE(icmpHeader->checksum == 12083); EXPECT_TRUE(getRxSelfSeqNo() + 1 == ntohs(icmpHeader->un.echo.sequence)); EXPECT_TRUE(getRxPeerSeqNo() + 1 == ntohs(icmpHeader->un.echo.sequence));