diff --git a/src/link_prober/IcmpPayload.cpp b/src/link_prober/IcmpPayload.cpp index 4b309621..2d76acce 100644 --- a/src/link_prober/IcmpPayload.cpp +++ b/src/link_prober/IcmpPayload.cpp @@ -38,28 +38,6 @@ boost::uuids::uuid IcmpPayload::mGuid; uint32_t IcmpPayload::mCookie = 0x47656d69; uint32_t IcmpPayload::mVersion = 0; -// -// ---> TlvCommand(); -// -// struct TlvCommand constructor -// -TlvCommand::TlvCommand() : - type(tlvtype), length(htons(1)), command(static_cast (Command::COMMAND_SWITCH_ACTIVE)) -{ -} - -// -// ---> TlvSentinel(); -// -// struct TlvSentinel constructor -// -TlvSentinel::TlvSentinel() : - type(tlvtype), length(htons(1)) -{ -} - - - // // ---> IcmpPayload(); // diff --git a/src/link_prober/IcmpPayload.h b/src/link_prober/IcmpPayload.h index 738e65b4..54e730e1 100644 --- a/src/link_prober/IcmpPayload.h +++ b/src/link_prober/IcmpPayload.h @@ -83,13 +83,6 @@ struct TlvCommand TlvHead; uint8_t command; static const uint8_t tlvtype = TlvType::TLV_COMMAND; - - /** - *@method TlvCommand - * - *@brief struct TlvCommand default constructor - */ - TlvCommand(); } __attribute__((packed)); /** @@ -100,15 +93,7 @@ struct TlvCommand struct TlvSentinel { TlvHead; - uint8_t padding = 0; static const uint8_t tlvtype = TlvType::TLV_SENTINEL; - - /** - *@method TlvSentinel - * - *@brief struct TlvSentinel default constructor - */ - TlvSentinel(); } __attribute__((packed)); /** @@ -183,10 +168,6 @@ 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 366d3835..01660776 100644 --- a/src/link_prober/LinkProber.cpp +++ b/src/link_prober/LinkProber.cpp @@ -232,22 +232,22 @@ void LinkProber::handleUpdateEthernetFrame() // void LinkProber::handleSendSwitchCommand() { - new (mTxBuffer.data() + mPacketHeaderSize + sizeof(IcmpPayload)) TlvCommand(); - new (mTxBuffer.data() + mPacketHeaderSize + sizeof(IcmpPayload) + sizeof(TlvCommand)) TlvSentinel(); + resetTxBufferTlv(); + appendTlvCommand(Command::COMMAND_SWITCH_ACTIVE); + appendTlvSentinel(); - size_t totalPayloadSize = sizeof(IcmpPayload) + sizeof(TlvCommand) + sizeof(TlvSentinel); + size_t totalPayloadSize = mTxPacketSize - mPacketHeaderSize; iphdr *ipHeader = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header)); icmphdr *icmpHeader = reinterpret_cast (mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr)); computeChecksum(icmpHeader, sizeof(icmphdr) + totalPayloadSize); - mTxPacketSize = mPacketHeaderSize + totalPayloadSize; ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + totalPayloadSize); sendHeartbeat(); - new (mTxBuffer.data() + mPacketHeaderSize + sizeof(IcmpPayload)) TlvSentinel(); - totalPayloadSize = sizeof(IcmpPayload) + sizeof(TlvSentinel); + resetTxBufferTlv(); + appendTlvSentinel(); + totalPayloadSize = mTxPacketSize - mPacketHeaderSize; computeChecksum(icmpHeader, sizeof(icmphdr) + totalPayloadSize); - mTxPacketSize = mPacketHeaderSize + totalPayloadSize; ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + totalPayloadSize); // inform the composite state machine about commend send completion @@ -285,16 +285,16 @@ void LinkProber::sendHeartbeat() } // -// ---> handleTlvCommandRecv(size_t offset, bool isPeer); +// ---> handleTlvCommandRecv(Tlv *tlvPtr,, bool isPeer); // // handle packet reception // void LinkProber::handleTlvCommandRecv( - size_t offset, + Tlv *tlvPtr, bool isPeer ) { - TlvCommand *tlvCommand = reinterpret_cast (mTxBuffer.data() + offset); + TlvCommand *tlvCommand = reinterpret_cast (tlvPtr); if (isPeer) { if (tlvCommand->command == static_cast (Command::COMMAND_SWITCH_ACTIVE)) { boost::asio::io_service::strand &strand = mLinkProberStateMachine.getStrand(); @@ -327,6 +327,12 @@ void LinkProber::handleRecv( mRxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) ); + MUXLOGTRACE(boost::format("%s: Got data from: %s, size: %d") % + mMuxPortConfig.getPortName() % + boost::asio::ip::address_v4(ntohl(ipHeader->saddr)).to_string() % + (bytesTransferred - sizeof(iphdr) - sizeof(ether_header)) + ); + IcmpPayload *icmpPayload = reinterpret_cast ( mRxBuffer.data() + mPacketHeaderSize ); @@ -347,14 +353,14 @@ void LinkProber::handleRecv( mLinkProberStateMachine.postLinkProberStateEvent(LinkProberStateMachine::getIcmpSelfEvent()); } - uint8_t tlvStartOffset = mPacketHeaderSize + sizeof(IcmpPayload); + size_t nextTlvOffset = mTlvStartOffset; + size_t nextTlvSize = 0; bool stopProcessTlv = false; - while (tlvStartOffset + sizeof(Tlv) <= bytesTransferred) { - Tlv *currentTlv = reinterpret_cast (mTxBuffer.data() + tlvStartOffset); - size_t currentTlvLength = ntohs(currentTlv->length); - switch (currentTlv->type) { + while ((nextTlvSize = findNextTlv(nextTlvOffset, bytesTransferred)) > 0 && !stopProcessTlv) { + Tlv *nextTlvPtr = reinterpret_cast (mRxBuffer.data() + nextTlvOffset); + switch (nextTlvPtr->type) { case TlvType::TLV_COMMAND: { - handleTlvCommandRecv(tlvStartOffset, !isMatch); + handleTlvCommandRecv(nextTlvPtr, !isMatch); break; } case TlvType::TLV_SENTINEL: { @@ -363,27 +369,26 @@ void LinkProber::handleRecv( break; } default: { - // unknonw TLV, try to skip - if (currentTlvLength == 0) { + // try to skip unknown TLV with valid length(>0) + if (nextTlvSize == sizeof(Tlv)) { stopProcessTlv = true; break; } } - tlvStartOffset += sizeof(Tlv) + currentTlvLength; - } - if (stopProcessTlv) { - break; } + nextTlvOffset += nextTlvSize; + } + + if (nextTlvOffset < bytesTransferred) { + size_t BytesNotProcessed = bytesTransferred - nextTlvOffset; + MUXLOGTRACE(boost::format("%s: %d bytes in RxBuffer not processed") % + mMuxPortConfig.getPortName() % + BytesNotProcessed + ); } } else { // Unknown ICMP packet, ignore. } - - MUXLOGTRACE(boost::format("%s: Got data from: %s, size: %d") % - mMuxPortConfig.getPortName() % - boost::asio::ip::address_v4(ntohl(ipHeader->saddr)).to_string() % - (bytesTransferred - sizeof(iphdr) - sizeof(ether_header)) - ); // start another receive to consume as much as possible of backlog packets if any startRecv(); } @@ -530,11 +535,15 @@ void LinkProber::startTimer() uint32_t LinkProber::calculateChecksum(uint16_t *data, size_t size) { uint32_t sum = 0; - size_t offset = 0; - do { - sum += ntohs(data[offset++]); - } while (offset < size); + while (size > 1) { + sum += ntohs(*data++); + size -= sizeof(uint16_t); + } + + if (size) { + sum += ntohs(static_cast ((*reinterpret_cast (data)))); + } return sum; } @@ -560,7 +569,7 @@ void LinkProber::computeChecksum(icmphdr *icmpHeader, size_t size) { icmpHeader->checksum = 0; mIcmpChecksum = calculateChecksum( - reinterpret_cast (icmpHeader), size / 2 + reinterpret_cast (icmpHeader), size ); addChecksumCarryover(&icmpHeader->checksum, mIcmpChecksum); } @@ -574,7 +583,7 @@ void LinkProber::computeChecksum(iphdr *ipHeader, size_t size) { ipHeader->check = 0; mIpChecksum = calculateChecksum( - reinterpret_cast (ipHeader), size / 2 + reinterpret_cast (ipHeader), size ); addChecksumCarryover(&ipHeader->check, mIpChecksum); } @@ -593,14 +602,16 @@ 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() + mPacketHeaderSize) IcmpPayload(); - TlvSentinel *tlvSentinel = new (mTxBuffer.data() + mPacketHeaderSize + sizeof(IcmpPayload)) TlvSentinel(); - mTxPacketSize = mPacketHeaderSize + sizeof(IcmpPayload) + sizeof(TlvSentinel); + + new (mTxBuffer.data() + mPacketHeaderSize) IcmpPayload(); + resetTxBufferTlv(); + appendTlvSentinel(); + size_t totalPayloadSize = mTxPacketSize - mPacketHeaderSize; ipHeader->ihl = sizeof(iphdr) >> 2; ipHeader->version = IPVERSION; ipHeader->tos = 0xb8; - ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload) + sizeof(TlvSentinel)); + ipHeader->tot_len = htons(sizeof(iphdr) + sizeof(icmphdr) + totalPayloadSize); ipHeader->id = static_cast (rand()); ipHeader->frag_off = 0; ipHeader->ttl = 64; @@ -615,7 +626,7 @@ void LinkProber::initializeSendBuffer() icmpHeader->un.echo.id = htons(mMuxPortConfig.getServerId()); icmpHeader->un.echo.sequence = htons(mTxSeqNo); - computeChecksum(icmpHeader, sizeof(icmphdr) + sizeof(*icmpPayload) + sizeof(*tlvSentinel)); + computeChecksum(icmpHeader, sizeof(icmphdr) + totalPayloadSize); } // @@ -635,4 +646,50 @@ void LinkProber::updateIcmpSequenceNo() addChecksumCarryover(&icmpHeader->checksum, mIcmpChecksum); } +// +// ---> findNextTlv +// +// Find next TLV to process in rxBuffer +// +size_t LinkProber::findNextTlv(size_t readOffset, size_t bytesTransferred) +{ + size_t tlvSize = 0; + if (readOffset + sizeof(Tlv) <= bytesTransferred) { + Tlv *tlvPtr = reinterpret_cast (mRxBuffer.data() + readOffset); + tlvSize = (sizeof(Tlv) + ntohs(tlvPtr->length)); + } + return tlvSize; +} + +// +// ---> appendTlvCommand +// +// Append TlvCommand to the end of txBuffer +// +size_t LinkProber::appendTlvCommand(Command commandType) +{ + assert(mTxPacketSize + sizeof(TlvCommand) <= MUX_MAX_ICMP_BUFFER_SIZE); + TlvCommand *tlvCommand = reinterpret_cast (mTxBuffer.data() + mTxPacketSize); + tlvCommand->type = TlvCommand::tlvtype; + tlvCommand->length = htons(1); + tlvCommand->command = static_cast (Command::COMMAND_SWITCH_ACTIVE); + mTxPacketSize += sizeof(TlvCommand); + return sizeof(TlvCommand); +} + +// +// ---> appendTlvSentinel +// +// Append TlvSentinel to the end of txBuffer +// +size_t LinkProber::appendTlvSentinel() +{ + assert(mTxPacketSize + sizeof(TlvSentinel) <= MUX_MAX_ICMP_BUFFER_SIZE); + TlvSentinel *tlvSentinel = reinterpret_cast (mTxBuffer.data() + mTxPacketSize); + tlvSentinel->type = TlvSentinel::tlvtype; + tlvSentinel->length = 0; + mTxPacketSize += sizeof(TlvSentinel); + return sizeof(TlvSentinel); +} + } /* namespace link_prober */ diff --git a/src/link_prober/LinkProber.h b/src/link_prober/LinkProber.h index d372749d..8e82ffb7 100644 --- a/src/link_prober/LinkProber.h +++ b/src/link_prober/LinkProber.h @@ -193,13 +193,13 @@ class LinkProber * *@brief handle TLV command * - *@param offset (in) start offset for TlvCommand struct in mRxBuffer + *@param tlvPtr (in) Tlv ptr points to the start of TlvCommand in mRxBuffer *@param isPeer (in) True if the reply received is from the peer ToR * *@return none */ void handleTlvCommandRecv( - size_t offset, + Tlv *tlvPtr, bool isPeer ); @@ -353,10 +353,44 @@ class LinkProber * *@brief getter for TxBuffer used for testing * - *@return CRC checksum + *@return tx buffer */ std::array getTxBuffer() {return mTxBuffer;}; + /** + *@method findNextTlv + * + *@brief Find next TLV in rxBuffer starting at readOffset + * + *@param readOffset (in) starting offset to read + *@param bytesTransferred (in) total bytes received in rxBuffer + * + *@return the next TLV size + */ + size_t findNextTlv(size_t readOffset, size_t bytesTransferred); + + void resetTxBufferTlv() {mTxPacketSize = mTlvStartOffset;}; + + /** + *@method appendTlvCommand + * + *@brief append TlvCommand to txBuffer + * + *@param commandType (in) command type + * + *@return the appended TLV size + */ + size_t appendTlvCommand(Command commandType = Command::COMMAND_SWITCH_ACTIVE); + + /** + *@method appendTlvSentinel + * + *@brief append TlvSentinel to txBuffer + * + *@return the appended TLV size + */ + size_t appendTlvSentinel(); + friend class test::LinkProberTest; private: @@ -375,6 +409,7 @@ class LinkProber uint32_t mIpChecksum = 0; static const size_t mPacketHeaderSize = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr); + static const size_t mTlvStartOffset = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(IcmpPayload); boost::asio::io_service::strand mStrand; boost::asio::deadline_timer mDeadlineTimer; diff --git a/test/LinkProberTest.cpp b/test/LinkProberTest.cpp index a3d666ed..531c3879 100644 --- a/test/LinkProberTest.cpp +++ b/test/LinkProberTest.cpp @@ -14,13 +14,6 @@ * limitations under the License. */ -/* - * LinkProberTest.cpp - * - * Created on: May 12, 2021 - * Author: taahme - */ - #include #include #include "common/MuxException.h" @@ -48,6 +41,18 @@ LinkProberTest::LinkProberTest() : mMuxConfig.setTimeoutIpv4_msec(1); } +size_t LinkProberTest::appendTlvCommand(link_prober::Command commandType) { + return mLinkProber.appendTlvCommand(commandType); +} + +size_t LinkProberTest::appendTlvSentinel() { + return mLinkProber.appendTlvSentinel(); +} + +size_t LinkProberTest::findNextTlv(size_t readOffset, size_t bytesTransferred) { + return mLinkProber.findNextTlv(readOffset, bytesTransferred); +} + TEST_F(LinkProberTest, InitializeSendBuffer) { initializeSendBuffer(); @@ -73,7 +78,7 @@ TEST_F(LinkProberTest, InitializeSendBuffer) EXPECT_TRUE(ipHeader->frag_off == 0); EXPECT_TRUE(ipHeader->ttl == 64); EXPECT_TRUE(ipHeader->protocol == IPPROTO_ICMP); - EXPECT_TRUE(ipHeader->check == 62663); + EXPECT_TRUE(ipHeader->check == 62919); EXPECT_TRUE(ipHeader->saddr == htonl(mFakeMuxPort.getMuxPortConfig().getLoopbackIpv4Address().to_v4().to_uint())); EXPECT_TRUE(ipHeader->daddr == htonl(mFakeMuxPort.getMuxPortConfig().getBladeIpv4Address().to_v4().to_uint())); @@ -91,8 +96,7 @@ TEST_F(LinkProberTest, InitializeSendBuffer) ) == 0); EXPECT_TRUE(tlvSentinel->type == link_prober::TlvType::TLV_SENTINEL); - EXPECT_TRUE(tlvSentinel->length == htons(1)); - EXPECT_TRUE(tlvSentinel->padding == 0); + EXPECT_TRUE(tlvSentinel->length == 0); } TEST_F(LinkProberTest, CalculateChecksum) @@ -105,7 +109,7 @@ TEST_F(LinkProberTest, CalculateChecksum) initializeSendBuffer(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 12099); + EXPECT_TRUE(icmpHeader->checksum == 12100); } TEST_F(LinkProberTest, UpdateEthernetFrame) @@ -118,7 +122,7 @@ TEST_F(LinkProberTest, UpdateEthernetFrame) handleUpdateEthernetFrame(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 12099); + EXPECT_TRUE(icmpHeader->checksum == 12100); } TEST_F(LinkProberTest, UpdateSequenceNo) @@ -136,7 +140,7 @@ TEST_F(LinkProberTest, UpdateSequenceNo) handleUpdateSequenceNumber(); icmphdr *icmpHeader = reinterpret_cast (getTxBuffer().data() + sizeof(ether_header) + sizeof(iphdr)); - EXPECT_TRUE(icmpHeader->checksum == 11843); + EXPECT_TRUE(icmpHeader->checksum == 11844); EXPECT_TRUE(getRxSelfSeqNo() + 1 == ntohs(icmpHeader->un.echo.sequence)); EXPECT_TRUE(getRxPeerSeqNo() + 1 == ntohs(icmpHeader->un.echo.sequence)); @@ -185,6 +189,44 @@ TEST_F(LinkProberTest, UpdateToRMac) EXPECT_TRUE(ipHeader->daddr == htonl(ipAddress.to_v4().to_uint())); } +TEST_F(LinkProberTest, ReadWriteTlv) +{ + initializeSendBuffer(); + size_t tlvStartOffset = sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr) + sizeof(link_prober::IcmpPayload); + // check initial tx buffer packet size + EXPECT_TRUE(getTxPacketSize() == tlvStartOffset + sizeof(link_prober::TlvSentinel)); + + // build txBuffer + resetTxBufferTlv(); + EXPECT_TRUE(appendTlvCommand(link_prober::Command::COMMAND_SWITCH_ACTIVE) == sizeof(link_prober::TlvCommand)); + EXPECT_TRUE(appendTlvSentinel() == sizeof(link_prober::TlvSentinel)); + EXPECT_TRUE(getTxPacketSize() == tlvStartOffset + sizeof(link_prober::TlvCommand) + sizeof(link_prober::TlvSentinel)); + + // build rxBuffer + size_t bytesTransferred = getTxPacketSize(); + memcpy(getRxBufferData(), getTxBufferData(), bytesTransferred); + + // start read TLV from rxBuffer + size_t rxReadOffset = tlvStartOffset; + size_t tlvSize = findNextTlv(rxReadOffset, bytesTransferred); + link_prober::TlvCommand *tlvCommand = reinterpret_cast (getRxBufferData() + rxReadOffset); + EXPECT_TRUE(tlvSize == sizeof(link_prober::TlvCommand)); + EXPECT_TRUE(tlvCommand->type == link_prober::TlvCommand::tlvtype); + EXPECT_TRUE(tlvCommand->length == htons(1)); + EXPECT_TRUE(tlvCommand->command == static_cast (link_prober::Command::COMMAND_SWITCH_ACTIVE)); + rxReadOffset += tlvSize; + + tlvSize = findNextTlv(rxReadOffset, bytesTransferred); + link_prober::TlvSentinel *tlvSentinel = reinterpret_cast (getRxBufferData() + rxReadOffset); + EXPECT_TRUE(tlvSize == sizeof(link_prober::TlvSentinel)); + EXPECT_TRUE(tlvSentinel->type == link_prober::TlvSentinel::tlvtype); + EXPECT_TRUE(tlvSentinel->length == 0); + rxReadOffset += tlvSize; + + tlvSize = findNextTlv(rxReadOffset, bytesTransferred); + EXPECT_TRUE(tlvSize == 0); +} + TEST_F(LinkProberTest, InitializeException) { EXPECT_THROW(initialize(), common::SocketErrorException); diff --git a/test/LinkProberTest.h b/test/LinkProberTest.h index f505020e..f70aaef0 100644 --- a/test/LinkProberTest.h +++ b/test/LinkProberTest.h @@ -14,13 +14,6 @@ * limitations under the License. */ -/* - * LinkProberTest.h - * - * Created on: May 12, 2021 - * Author: Tamer Ahmed - */ - #ifndef LINKPROBERTEST_H_ #define LINKPROBERTEST_H_ @@ -42,7 +35,14 @@ class LinkProberTest: public ::testing::Test void initializeSendBuffer() {mLinkProber.initializeSendBuffer();}; void handleUpdateEthernetFrame() {mLinkProber.handleUpdateEthernetFrame();}; void handleUpdateSequenceNumber() {mLinkProber.updateIcmpSequenceNo();}; + void resetTxBufferTlv() {mLinkProber.resetTxBufferTlv();}; + size_t getTxPacketSize() {return mLinkProber.mTxPacketSize;}; + size_t appendTlvCommand(link_prober::Command commandType); + size_t appendTlvSentinel(); + size_t findNextTlv(size_t readOffset, size_t bytesTransferred); std::array getTxBuffer() {return mLinkProber.getTxBuffer();}; + uint8_t *getTxBufferData() {return mLinkProber.mTxBuffer.data();}; + uint8_t *getRxBufferData() {return mLinkProber.mRxBuffer.data();}; uint16_t getRxSelfSeqNo() {return mLinkProber.mRxSelfSeqNo;}; uint16_t getRxPeerSeqNo() {return mLinkProber.mRxPeerSeqNo;};