Skip to content

Commit

Permalink
Add sentinel TLV
Browse files Browse the repository at this point in the history
Signed-off-by: Longxiang Lyu <lolv@microsoft.com>
  • Loading branch information
lolyu committed Dec 16, 2021
1 parent 189ff90 commit b7ef68b
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 107 deletions.
50 changes: 21 additions & 29 deletions src/link_prober/IcmpPayload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t> (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();
Expand All @@ -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<uint8_t> (TlvType::TLV_COMMAND))
{
size += sizeof(TlvCommand) - sizeof(TlvPayload);
}
return size;
}

//
// ---> generateGuid()
//
Expand Down
73 changes: 45 additions & 28 deletions src/link_prober/IcmpPayload.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -55,38 +74,42 @@ enum class Command: uint8_t {
Count
};

/**
*@enum TlvType
*
*@brief Supported TLV types
*/
enum class TlvType: uint8_t {
TLV_COMMAND
};

/**
*@struct TlvCommand
*
*@brief Build command TLV
*/
struct TlvCommand
{
uint8_t type = 0;
uint16_t length = htons(1);
uint8_t command = static_cast<uint8_t> (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));

/**
Expand All @@ -99,7 +122,6 @@ struct IcmpPayload {
uint32_t version;
uint8_t uuid[8];
uint64_t seq;
TlvPayload tlv;

/**
*@method IcmpPayload
Expand All @@ -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
*
Expand Down Expand Up @@ -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");

Expand Down
80 changes: 45 additions & 35 deletions src/link_prober/LinkProber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,18 +232,18 @@ void LinkProber::handleUpdateEthernetFrame()
//
void LinkProber::handleSendSwitchCommand()
{
IcmpPayload *icmpPayload = reinterpret_cast<IcmpPayload *> (
mTxBuffer.data() + sizeof(ether_header) + sizeof(iphdr) + sizeof(icmphdr)
);
icmpPayload->tlv.cmdtlv.command = static_cast<uint8_t> (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<icmphdr *> (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<uint8_t> (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();
Expand All @@ -269,13 +269,7 @@ void LinkProber::sendHeartbeat()
if (!mSuspendTx) {
updateIcmpSequenceNo();
boost::system::error_code errorCode;
IcmpPayload *icmpPayload = reinterpret_cast<IcmpPayload *> (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!");
Expand Down Expand Up @@ -314,28 +308,42 @@ void LinkProber::handleRecv(
mMuxPortConfig.getPortName() %
mMuxPortConfig.getBladeIpv4Address().to_string()
);
if (icmpPayload->tlv.type == static_cast<uint8_t> (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<uint8_t> (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<void (LinkProberStateMachine::*) (SwitchActiveRequestEvent&)>
(&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<Tlv *> (mTxBuffer.data() + tlvStartOffset);
if (currentTlv->type == TlvType::TLV_COMMAND) {
TlvCommand *tlvCommand = reinterpret_cast<TlvCommand *> (mTxBuffer.data() + tlvStartOffset);
if (!isMatch) {
if (tlvCommand->command == static_cast<uint8_t> (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<void (LinkProberStateMachine::*) (SwitchActiveRequestEvent&)>
(&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.
Expand Down Expand Up @@ -556,11 +564,13 @@ void LinkProber::initializeSendBuffer()
iphdr *ipHeader = reinterpret_cast<iphdr *> (mTxBuffer.data() + sizeof(ether_header));
icmphdr *icmpHeader = reinterpret_cast<icmphdr *> (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<uint16_t> (rand());
ipHeader->frag_off = 0;
ipHeader->ttl = 64;
Expand All @@ -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));
}

//
Expand Down
1 change: 1 addition & 0 deletions src/link_prober/LinkProber.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ class LinkProber

int mSocket = 0;

std::size_t mTxPacketSize;
std::array<uint8_t, MUX_MAX_ICMP_BUFFER_SIZE> mTxBuffer;
std::array<uint8_t, MUX_MAX_ICMP_BUFFER_SIZE> mRxBuffer;

Expand Down
Loading

0 comments on commit b7ef68b

Please sign in to comment.