// Cray-XMP I/O Processor simulator class #include "sim_iop_eth.h" #include "sim_iop.h" #ifndef NOMINMAX #define NOMINMAX #endif #include #include #include #include #include "utils.h" #include //#include #include #include #include #include #include #include #include #if defined(__CYGWIN__) || defined(_WIN32) #include "vtap_win32.h" #else #include "vtap_linux.h" #endif // _WIN32 #if defined(PARTIAL_DEBUG) && defined(_MSC_VER) #pragma optimize ("", off) #endif template class SafeQueue { public: tType Pop() { std::unique_lock Lock(mMutex); while (mQueue.empty()) { mNotifier.wait(Lock); } auto RetVal = mQueue.front(); mQueue.pop(); return RetVal; } void Push(const tType& item) { std::unique_lock Lock(mMutex); mQueue.push(item); Lock.unlock(); mNotifier.notify_one(); } void Push(tType&& item) { std::unique_lock Lock(mMutex); mQueue.push(std::move(item)); Lock.unlock(); mNotifier.notify_one(); } bool Empty() { std::unique_lock Lock(mMutex); return mQueue.empty(); } protected: std::queue mQueue; std::mutex mMutex; std::condition_variable mNotifier; }; typedef std::vector Packet_c; class PacketCaptureThread_c : public Thread_c { public: explicit PacketCaptureThread_c(TapAdapter_c &aAdapter) : mAdapter(aAdapter) {} SafeQueue mPacketQueue; void ReInit() { // TODO: this needs to be re-worked. I don't know what power-state transitions do to this driver // size_t FailCnt = 0; // while (mCaptureHandle == nullptr) { // try { // mCaptureHandle = std::move(std::unique_ptr(PCapOpenLive(mDevice.c_str(), mPromisc, mTimeout, mSnapLen), pcap_close)); // } // catch (std::exception &) { // if (++FailCnt > 100) { // throw; // } // std::this_thread::sleep_for(std::chrono::milliseconds(10)); // } // } } void SetFilterMac(uint64_t aFilterMac) { mFilterMac = aFilterMac; } void SendEthPacket(std::vector &aPacket) { mAdapter.Send(aPacket); } void CancelRead() { mAdapter.CancelRead(); } protected: virtual void Thread() override { while (!IsTerminating()) { try { Packet_c Packet = mAdapter.BlockingReceive(); if (Packet.size() < 24) continue; if (IsPaused()) continue; uint64_t DstMac = 0; for (size_t Idx = 0; Idx < 6; ++Idx) { DstMac = SetBits(DstMac, (5 - Idx) * 8, (5 - Idx) * 8 + 7, Packet[Idx]); } // filter for our MAC, the broadcast and any multi-cast addresses if (DstMac == mFilterMac || DstMac == 0xffffffffff || (DstMac & 0x010000000000) != 0) { mPacketQueue.Push(Packet); } } catch (...) { if (!IsTerminating()) throw; } } } TapAdapter_c &mAdapter; uint64_t mFilterMac; }; // //std::unique_ptr AllDevs(PCapFindAllDevs(), pcap_freealldevs); // //pcap_if_t *SelectedDev = nullptr; //for (pcap_if_t *Dev = AllDevs.get(); Dev; Dev = Dev->next) { // if (aInterfaceName == Dev->name) { // SelectedDev = Dev; // break; // } // if (Dev->description != nullptr && aInterfaceName == Dev->description) { // SelectedDev = Dev; // break; // } //} //if (SelectedDev == nullptr) throw Generic_x() << "Can't find requested interface: " << aInterfaceName; // //PacketCaptureThread_c Thread(SelectedDev->name, true, 1000); // //int LinkType = Thread.GetLinkType(); //if (LinkType != DLT_EN10MB) throw Generic_x() << "Only Ethernet interfaces are supported"; // //std::cout << "\nlistening on " << SelectedDev->description << "..." << std::endl; // //AllDevs = nullptr; // This will free our structure // //Thread.Start(); // //while (!_kbhit()) { // if (!Thread.mPacketQueue.Empty()) { // Packet_c Packet = Thread.mPacketQueue.Pop(); // // convert the timestamp to readable format // time_t LocalSeconds = Packet.mTimeStamp.tv_sec; // struct tm *LocalTime = localtime(&LocalSeconds); // char TimeString[16]; // strftime(TimeString, sizeof TimeString, "%H:%M:%S", LocalTime); // // std::cout << TimeString << "," << Packet.mTimeStamp.tv_usec << " captured bytes: " << Packet.mPacketData.size() << " bytes on the wire: " << Packet.mWireLength << std::endl; // for (size_t Ofs = 0; Ofs < std::min(Packet.mPacketData.size(), size_t(512)); ++Ofs) { // if (Ofs % 32 == 0) { // if (Ofs != 0) std::cout << std::endl; // std::cout << "\t"; // } // std::cout << std::noshowbase << std::uppercase << std::hex << std::setw(2) << std::setfill('0') << int(Packet.mPacketData[Ofs]) << " "; // } // std::cout << std::endl; // } //} //Thread.Terminate(); //Thread.join(); void DumpPacket(CLogger_c &aLogger, CAddr_t aAddr, const Mainframe_c &aMainframe, const char *aHeader) { LogLine_c Line = aLogger << setloglevel(LogLevel_IoTrace); if (Line.good()) { Line << aHeader << std::endl; for (size_t Ofs = 0; Ofs < (53 + 7) / 8; ++Ofs) { CInt_t Data = aMainframe.MemReadNoWatchpoint(CAddr_t(aAddr + Ofs)); Line << HexPrinter(SwapBytes(Data)) << " "; if (Ofs % 4 == 3) Line << std::endl; } Line << std::endl; } } static void DumpMem(CLogger_c &aLogger, const char *aHeader, CAddr_t aBuffer, size_t aLength, Mainframe_c &aMainframe) { const size_t cLineSize = 4; auto TraceLine = aLogger << setloglevel(LogLevel_IoTrace) << aHeader << std::endl; CAddr_t End = aBuffer + CAddr_t(aLength); for (CAddr_t Addr = aBuffer; Addr < End; Addr += cLineSize) { CInt_t Data[cLineSize]; for (size_t j = 0; j < cLineSize; ++j) { if (Addr + j >= End) break; Data[j] = aMainframe.MemReadNoWatchpoint(CAddr_t(Addr + j)); } if (TraceLine.good()) { TraceLine << HexPrinter(Addr) << " : "; for (size_t j = 0; j < cLineSize; ++j) { if (Addr + j >= End) break; TraceLine << HexPrinter(SwapBytes(Data[j])) << " "; } TraceLine << " - "; for (size_t j = 0; j < cLineSize; ++j) { if (Addr + j >= End) break; TraceLine << AsciiDumpPrinter(SwapBytes(Data[j])) << " "; } TraceLine << std::endl; } } TraceLine << std::endl; } void SimIopEth_c::HandleTxPacket(size_t aQueueIdx) { if (mPacketCaptureThread == nullptr) return; CAddr_t Base = CAddr_t(CpOutQAddr + 3 + aQueueIdx * cEtherPacketSize / sizeof(CInt_t)); CInt_t EntryHead = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(Base)); uint32_t PayloadSize = uint32_t(GetBits(EntryHead, 0, 31)); uint16_t ErrorCode = uint16_t(GetBits(EntryHead, 32, 47)); uint16_t Error = uint16_t(GetBits(EntryHead, 48, 63)); CAddr_t PayloadStart = CAddr_t(Base + 1); mLogger << setloglevel(LogLevel_IoTrace) << "Output queue packet # " << DecPrinter(aQueueIdx) << " Error: " << DecPrinter(Error) << " ErrorCode: " << DecPrinter(ErrorCode) << " Size: " << DecPrinter(PayloadSize) << std::endl; // 3 words of queue header and 1 word of entry header. There are also 2 bytes of padding at the beginning of the payload and length rouned up to the next word DumpMem(mLogger, "ETH PACKET", PayloadStart, (PayloadSize + 2 + 7) / 8, mParent.GetMainframe()); // For now, let's process and reply to ARP requests // 59113654 IOP0.ETH20: Output queue packet # 1 Error: 0 ErrorCode : 0 Size : 60 // 59113654 IOP0.ETH20 : ETH PACKET // 59113654 IOP0.ETH20 : 0x0083DDC7 : 0x0000FFFFFFFFFFFF 0x0000000000000806 0x0001080006040001 0xFEDCBA987654C0A8 - ........ ........ ........ ....vT.. // 59113654 IOP0.ETH20 : 0x0083DDCB : 0x0001000000000000 0xC0A8006400000000 0x0000000000000000 0x0000000000000000 - ........ ...d.... ........ ........ // Copy out the packet std::vector TxPacket(PayloadSize); for (size_t Idx = 0; Idx < PayloadSize; ++Idx) { TxPacket[Idx] = mParent.GetMainframe().MemReadNoWatchpointByType(CAddr_t(PayloadStart * 8 + 2 + Idx)); } // Patch up src MAC for (size_t Idx = 0; Idx < 6; ++Idx) { TxPacket[6 + Idx] = uint8_t(GetBits(mSimMacAddr, (5 - Idx) * 8, (5 - Idx) * 8 + 7)); } mPacketsSent++; mBytesSent += PayloadSize; mPacketCaptureThread->SendEthPacket(TxPacket); } void SimIopEth_c::Tick() { if (mPacketCaptureThread != nullptr && !mPacketCaptureThread->IsPaused()) HandleRxPacket(); } void SimIopEth_c::HandleRxPacket() { using namespace SimIopEth_n; if (mPacketCaptureThread == nullptr) return; // TODO: how to get hand-shake with the consumer??? CInt_t ReplyRdIdx = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpInQAddr + 0))); CInt_t ReplyWrIdx = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpInQAddr + 1))); CInt_t ReplyContSize = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpInQAddr + 2))); uint32_t ReplyCont = uint32_t(GetBits(ReplyContSize, 32, 63)); uint32_t ReplySize = uint32_t(GetBits(ReplyContSize, 0, 31)); CAddr_t ReplyBase = CAddr_t(CpInQAddr + 3 + ReplyWrIdx * cEtherPacketSize / sizeof(CInt_t)); CAddr_t ReplyPayloadStart = CAddr_t(ReplyBase + 1); CInt_t NextReplyWrIdx = (ReplyWrIdx + 1) % ReplySize; // TODO: this might be a bit sub-optimal for handling full/empty dis-ambiguation bool PacketsQueued = false; if (!mPacketCaptureThread->mPacketQueue.Empty() && NextReplyWrIdx != ReplyRdIdx) { Packet_c Packet = mPacketCaptureThread->mPacketQueue.Pop(); uint64_t DstMac = 0; size_t ReplyPayloadSize = Packet.size(); mPacketsReceived++; mBytesReceived += uint32_t(ReplyPayloadSize); if (ReplyPayloadSize <= cEtherPacketSize) { mParent.GetMainframe().MemWrite(ReplyBase, SwapBytes(uint64_t(ReplyPayloadSize))); // We signal no error or error-code // Create a local array of the payload, rouded up to full QWORD // std::vector Payload(2); // Payload[0] = 0; Payload[1] = 0; // Payload.insert(Payload.begin() + 2, Packet.begin(), Packet.end()); // Payload.resize(((Payload.size() + 7) / 8) * 8); // for (size_t Idx = 0; Idx < Payload.size() / 8; ++Idx) { // mParent.GetMainframe().MemWrite(CAddr_t(ReplyPayloadStart + Idx), *(CInt_t*)(&Payload[Idx])); // } mParent.GetMainframe().MemWrite(CAddr_t(ReplyPayloadStart * 8 + 0), uint8_t(0)); mParent.GetMainframe().MemWrite(CAddr_t(ReplyPayloadStart * 8 + 1), uint8_t(0)); for (size_t Idx = 0; Idx < ReplyPayloadSize; ++Idx) { mParent.GetMainframe().MemWrite(CAddr_t(ReplyPayloadStart * 8 + 2 + Idx), Packet[Idx]); } mLogger << setloglevel(LogLevel_IoTrace) << "Input queue packet # " << DecPrinter(ReplyWrIdx) << " Size: " << DecPrinter(ReplyPayloadSize) << std::endl; // 3 words of queue header and 1 word of entry header. There are also 2 bytes of padding at the beginning of the payload and length rouned up to the next word DumpMem(mLogger, "ETH REPLY PACKET", ReplyPayloadStart, (ReplyPayloadSize + 2 + 7) / 8, mParent.GetMainframe()); PacketsQueued = true; ReplyWrIdx = NextReplyWrIdx; NextReplyWrIdx = (ReplyWrIdx + 1) % ReplySize; } } if (PacketsQueued) { mParent.GetMainframe().MemWrite(CAddr_t(CpInQAddr + 1), SwapBytes(ReplyWrIdx)); IopEPacket_c Response = mParent.GenerateResponse(); Response.SetSize(7); SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response if (mParent.GetIopRevision() == IopRevision_e::IOSE) { SetBitsInPlace(Response.Data(1), DestIdRange, 0x4331); // 'C1' SetBitsInPlace(Response.Data(1), SourceIdRange, 0x004d); // 'M' } else { // For IOSD, the reversal will happen during transmission SetBitsInPlace(Response.Data(1), DestIdRange, 0x004d); // 'M' SetBitsInPlace(Response.Data(1), SourceIdRange, 0x4331); // 'C1' } //SetBitsInPlace(Response.Data(1), PathOwnerRange, 0); SetBitsInPlace(Response.Data(1), IopNumberRange, 0xff); // All 1-s, but why??? SetBitsInPlace(Response.Data(1), ChannelNumberRange, mChannelId); SetBitsInPlace(Response.Data(1), RequestRange, uint8_t(Request_e::MPFC_SLEEP)); SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); SetBitsInPlace(Response.Data(2), BufferPtrRange, mBufferPtr); SetBitsInPlace(Response.Data(2), DevStructRange, mDevStruct); SetBitsInPlace(Response.Data(3), ReqTypeRange, uint32_t(SleepRqType_e::WAKEUP_INPUT)); SetBitsInPlace(Response.Data(3), CurIndexRange, ReplyWrIdx); SendPacket(Response); mLogger << setloglevel(LogLevel_IoActivity) << "Ethernet SLEEP sent: WAKEUP_INPUT " << "Current index: " << DecPrinter(ReplyWrIdx) << " MDataP: " << HexPrinter(0) << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "Queues after" << std::endl; DumpQueues(); } } void SimIopEth_c::DumpQueues() { DumpMem(mLogger, "IN QUEUE", CpInQAddr, 3, mParent.GetMainframe()); DumpMem(mLogger, "OUT QUEUE", CpOutQAddr, 3, mParent.GetMainframe()); } SimIopEth_c::SimIopEth_c(const Configuration_c &aConfig, class SimIopCluster_c &aParent, const std::string &aName): mName(aName), mLogger(aConfig, mName.c_str()), mChannelId(aConfig.get("Channel")), mParent(aParent), mPacketsSent(0), mPacketsReceived(0), mBytesSent(0), mBytesReceived(0), mCrayPacketsSent(0), mCrayPacketsReceived(0), mSimMacAddr(aConfig.get("SimMacAddr")), mIopNumber(aConfig.get("IopNumber")), mThreadStarted(false) { #if defined(__CYGWIN__) || defined(_WIN32) TapAdapter_c *SelectedAdapter = nullptr; std::vector Adapters = EnumTaps(); boost::optional InterfaceName = aConfig.get_optional("InterfaceNameWindows"); boost::optional InterfaceGuid = aConfig.get_optional("InterfaceGuid"); for (auto &Adapter : Adapters) { if (InterfaceName.is_initialized() && Adapter.GetName() == InterfaceName.get()) { SelectedAdapter = &Adapter; break; } if (InterfaceGuid.is_initialized() && Adapter.GetDeviceGuid() == InterfaceGuid.get()) { SelectedAdapter = &Adapter; break; } } if (SelectedAdapter == nullptr) { if (Adapters.size() == 0) throw Generic_x() << "Can't find appropriate network interface. Please install TAP-windows network driver"; if (InterfaceName.is_initialized() || InterfaceGuid.is_initialized()) throw Generic_x() << "Can't find specified network interface"; SelectedAdapter = &Adapters[0]; } mAdapter = std::make_unique(std::move(*SelectedAdapter)); #else mAdapter = std::make_unique(); boost::optional InterfaceName = aConfig.get_optional("InterfaceNameLinux"); if (InterfaceName.is_initialized()) mAdapter->SetName(InterfaceName.get().c_str()); #endif // _WIN32 try { mLogger << setloglevel(LogLevel_IoActivity) << "Opening Ethernet device: " << mAdapter->GetName() << std::endl; mAdapter->Open(); mPacketCaptureThread = std::make_unique(*mAdapter); mPacketCaptureThread->SetFilterMac(mSimMacAddr); } catch (Generic_x &Ex) { mLogger << setloglevel(LogLevel_IoActivity) << "Error opening Ethernet device: " << mAdapter->GetName() << " with error: " << Ex.what() << std::endl; mAdapter = nullptr; mPacketCaptureThread = nullptr; } mLogger.SetParent(mParent.GetLogger()); } SimIopEth_c::~SimIopEth_c() { if (mThreadStarted) { //CRAY_ASSERT(mPacketCaptureThread != nullptr); mPacketCaptureThread->Terminate(); mPacketCaptureThread->CancelRead(); if (mPacketCaptureThread->joinable()) mPacketCaptureThread->join(); if (mAdapter != nullptr) mAdapter->Close(); } } void SimIopEth_c::GetStatus(StatusReport_c &aStatus, boost::timer::nanosecond_type aElapsedTime, bool aLongFormat) const { if (mAdapter != nullptr) { std::string AdapterName = mAdapter->GetName(); if (AdapterName.length() < 5 || aLongFormat) { aStatus.put(aLongFormat ? "Interface" : "If", AdapterName); } else { std::string DisplayName(AdapterName.begin(), AdapterName.begin() + 5); DisplayName += "..."; aStatus.put(aLongFormat ? "Interface" : "If", DisplayName); } aStatus.put(aLongFormat ? "Packets Sent" : "Sp", mPacketsSent); aStatus.put(aLongFormat ? "Packets Received" : "Rp", mPacketsReceived); aStatus.put(aLongFormat ? "Bytes Sent" : "Sb", mBytesSent); aStatus.put(aLongFormat ? "Bytes Received" : "Rb", mBytesReceived); aStatus.put(aLongFormat ? "Cray Packets Sent" : "CSp", mCrayPacketsSent); aStatus.put(aLongFormat ? "Cray Packets Received" : "CRp", mCrayPacketsReceived); aStatus.put(aLongFormat ? "Output Queue Read Idx" : "OQR", SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpOutQAddr + 0)))); aStatus.put(aLongFormat ? "Output Queue Write Idx" : "OQW", SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpOutQAddr + 1)))); aStatus.put(aLongFormat ? "Input Queue Read Idx" : "IQR", SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpInQAddr + 0)))); aStatus.put(aLongFormat ? "Input Queue Write Idx" : "IQW", SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpInQAddr + 1)))); } else { aStatus.put(aLongFormat ? "Interface" : "If", "--- N/A ---"); } } std::string SimIopEth_c::GetName() const { return mName; } void SimIopEth_c::RegisterCommands(CommandHooks_t &aHooks) { class CmdKick_c : public CmdFactoryBase_i { public: explicit CmdKick_c(SimIopEth_c &aParent) : mParent(aParent) {} virtual bool ParseAndExec(TokenStream_t::const_iterator aBegin, TokenStream_t::const_iterator aEnd) override { bool DoHelp = false; if (aBegin->mValue == "help") { DoHelp = true; ++aBegin; if (aBegin == aEnd) return false; } if (aBegin->mValue != "kick") return false; ++aBegin; if (aBegin == aEnd) return false; if (aBegin->mValue != mParent.GetName()) return false; if (DoHelp) { std::cout << "kick " << mParent.GetName() << std::endl; std::cout << " Kicks the ethernet driver to empty its TX queue" << std::endl; return true; } else { ++aBegin; if (aBegin != aEnd && aBegin->mTokenId != TokenTypes_e::EndOfLine) return false; try { mParent.HandleTxPackets(); std::cout << mParent.GetName() << " kicked" << std::endl; } catch (std::exception &Ex) { std::cout << "Kick failed" << std::endl; std::cout << Ex.what() << std::endl; } return true; } } virtual std::string GetCommandName() const override { return "kick"; } virtual std::string GetDeviceName() const override { return mParent.GetName(); } protected: SimIopEth_c &mParent; }; aHooks.emplace_back(std::make_unique(*this)); } void SimIopEth_c::MasterClear() { // mPacketSent = 0; mPacketsReceived = 0; } bool SimIopEth_c::HandleIosDPacket(std::vector &aIosDPacket) { IopEPacket_c Packet = GetIosEPacket(aIosDPacket); return HandleIosEPacket(Packet); } void SimIopEth_c::HandleTxPackets() { using namespace SimIopEth_n; CInt_t RdIdx = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpOutQAddr + 0))); CInt_t WrIdx = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpOutQAddr + 1))); CInt_t ContSize = SwapBytes(mParent.GetMainframe().MemReadNoWatchpoint(CAddr_t(CpOutQAddr + 2))); uint32_t Cont = uint32_t(GetBits(ContSize, 32, 63)); uint32_t Size = uint32_t(GetBits(ContSize, 0, 31)); bool SendSleep = false; for (CInt_t Idx = RdIdx; Idx != WrIdx; Idx = (Idx + 1) % Size) { HandleTxPacket(size_t(Idx)); SendSleep = true; } mParent.GetMainframe().MemWrite(CAddr_t(CpOutQAddr), SwapBytes(CInt_t(WrIdx))); if (SendSleep) { IopEPacket_c Response = mParent.GenerateResponse(); Response.SetSize(7); SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response if (mParent.GetIopRevision() == IopRevision_e::IOSE) { SetBitsInPlace(Response.Data(1), DestIdRange, 0x4331); // 'C1' SetBitsInPlace(Response.Data(1), SourceIdRange, 0x004d); // 'M' } else { // For IOSD, the reversal will happen during transmission SetBitsInPlace(Response.Data(1), DestIdRange, 0x004d); // 'M' SetBitsInPlace(Response.Data(1), SourceIdRange, 0x4331); // 'C1' } //SetBitsInPlace(Response.Data(1), PathOwnerRange, 0); SetBitsInPlace(Response.Data(1), IopNumberRange, 0xff); // All 1-s, but why??? SetBitsInPlace(Response.Data(1), ChannelNumberRange, mChannelId); SetBitsInPlace(Response.Data(1), RequestRange, uint8_t(Request_e::MPFC_SLEEP)); SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); SetBitsInPlace(Response.Data(2), BufferPtrRange, mBufferPtr); SetBitsInPlace(Response.Data(2), DevStructRange, mDevStruct); SetBitsInPlace(Response.Data(3), ReqTypeRange, uint32_t(SleepRqType_e::SLEEP_OUTPUT)); SetBitsInPlace(Response.Data(3), CurIndexRange, RdIdx); SendPacket(Response); mLogger << setloglevel(LogLevel_IoActivity) << "Ethernet SLEEP sent: SLEEP_OUTPUT " << "Current index: " << DecPrinter(RdIdx) << " MDataP: " << HexPrinter(0) << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "Queues after" << std::endl; DumpQueues(); } } bool SimIopEth_c::HandleIosEPacket(IopEPacket_c &aPacket) { using namespace SimIopEth_n; ++mCrayPacketsReceived; size_t ChannelNumber = size_t(GetBits(aPacket.Data(1), ChannelNumberRange)); uint8_t IopNumber = uint8_t(GetBits(aPacket.Data(1), IopNumberRange)); if (ChannelNumber != mChannelId) return false; // For some reason Iop No is allways filled in with all 1-s, so can't really filter on it... // if (IopNumber != mIopNumber) return false; std::stringstream EventStr; EventStr << "C->I PACKET M request - " << HexPrinter(aPacket.Data(0)) << " " << HexPrinter(aPacket.Data(1)) << " " << HexPrinter(aPacket.Data(2)); mLogger << setloglevel(LogLevel_EventFire) << EventStr.str() << std::endl; mParent.GetMainframe().GetEventDispatcher().Fire(EventStr.str()); Request_e Request = Request_e(GetBits(aPacket.Data(1), RequestRange)); mBufferPtr = uint32_t(GetBits(aPacket.Data(2), BufferPtrRange)); mDevStruct = uint32_t(GetBits(aPacket.Data(2), DevStructRange)); switch (Request) { case Request_e::MPFC_CLS: { mLogger << setloglevel(LogLevel_IoActivity) << "Ethernet CLOSE request" << std::endl; // DumpMem(mLogger, "Ethernet DEV STRUCT", DevStruct, 64, GetMainframe()); IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); SendPacket(Response); if (mPacketCaptureThread != nullptr) mPacketCaptureThread->Pause(); } break; case Request_e::MPFC_OPN: { RingOpAddr = uint32_t(GetBits(aPacket.Data(3), RingOpAddrRange)); CpInQAddr = uint32_t(GetBits(aPacket.Data(4), CpInQAddrRange)); CpOutQAddr = uint32_t(GetBits(aPacket.Data(4), CpOutQAddrRange)); CpQSize = uint32_t(GetBits(aPacket.Data(5), CpQSizeRange)); Mtu = uint32_t(GetBits(aPacket.Data(5), MtuRange)); uint64_t MacAddr = GetBits(aPacket.Data(6), MacAddrRange); auto Line = mLogger << setloglevel(LogLevel_IoActivity); Line << "Ethernet OPEN request: "; Line << "RingOpAddr: " << HexPrinter(RingOpAddr) << " "; Line << "CpInQAddr: " << HexPrinter(CpInQAddr) << " "; Line << "CpOutQAddr: " << HexPrinter(CpOutQAddr) << " "; Line << "CpQSize: " << HexPrinter(CpQSize) << " "; Line << "MTU: " << DecPrinter(Mtu) << " "; Line << std::endl; // DumpMem(mLogger, "Ethernet DEV STRUCT", DevStruct, 64, GetMainframe()); IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); if (mPacketCaptureThread != nullptr) { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); SetBitsInPlace(Response.Data(6), MacAddrRange, mSimMacAddr); SendPacket(Response); if (!mThreadStarted) { std::cout << "Starting receive thread" << std::endl; mPacketCaptureThread->Start(); } mThreadStarted = true; mPacketCaptureThread->Resume(); } else { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_HDW)); SetBitsInPlace(Response.Data(6), MacAddrRange, mSimMacAddr); } } break; case Request_e::MPFC_SLEEP: { SleepRqType_e ReqType = SleepRqType_e(GetBits(aPacket.Data(3), ReqTypeRange)); uint32_t CurIndex = uint32_t(GetBits(aPacket.Data(3), CurIndexRange)); uint32_t MDataP = uint32_t(GetBits(aPacket.Data(4), MDataPRange)); auto Line = mLogger << setloglevel(LogLevel_IoActivity); Line << "Ethernet SLEEP request: "; switch (ReqType) { case SleepRqType_e::SLEEP_INPUT: Line << "SLEEP_INPUT "; break; case SleepRqType_e::SLEEP_OUTPUT: Line << "SLEEP_OUTPUT "; break; case SleepRqType_e::WAKEUP_INPUT: Line << "WAKEUP_INPUT "; break; case SleepRqType_e::WAKEUP_OUTPUT: Line << "WAKEUP_OUTPUT "; break; case SleepRqType_e::SLEEP_CLOSED: Line << "SLEEP_CLOSED "; break; } Line << "Current index: " << DecPrinter(CurIndex) << " MDataP: " << HexPrinter(MDataP) << std::endl; mLogger << setloglevel(LogLevel_IoTrace) << "Queues before" << std::endl; DumpQueues(); bool SendResponse = false; IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } switch (ReqType) { case SleepRqType_e::SLEEP_INPUT: // mParent.GetMainframe().MemWrite(CAddr_t(CpInQAddr + 0), SwapBytes(CInt_t(CurIndex))); break; case SleepRqType_e::SLEEP_OUTPUT: break; case SleepRqType_e::WAKEUP_INPUT: // mParent.GetMainframe().MemWrite(CAddr_t(CpInQAddr + 0), SwapBytes(CInt_t(CurIndex))); // SetBitsInPlace(Response.Data(3), ReqTypeRange, uint8_t(SleepRqType_e::SLEEP_INPUT)); // SendResponse = true; // mPacketCaptureThread->Resume(); break; case SleepRqType_e::WAKEUP_OUTPUT: { HandleTxPackets(); //SetBitsInPlace(Response.Data(3), ReqTypeRange, uint8_t(SleepRqType_e::SLEEP_OUTPUT)); //SendResponse = true; } break; case SleepRqType_e::SLEEP_CLOSED: break; } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); if (mPacketCaptureThread != nullptr) { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); } else { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_HDW)); } if (SendResponse) SendPacket(Response); mLogger << setloglevel(LogLevel_IoTrace) << "Queues after" << std::endl; DumpQueues(); } break; case Request_e::MPFC_PROBE: { mLogger << setloglevel(LogLevel_IoActivity) << "Ethernet PROBE request" << std::endl; // DumpMem(mLogger, "Ethernet DEV STRUCT", DevStruct, 64, GetMainframe()); IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); if (mPacketCaptureThread != nullptr) { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); } else { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_HDW)); } SendPacket(Response); } break; case Request_e::MPFC_IOCTL: { uint32_t Cmd = uint32_t(GetBits(aPacket.Data(3), CmdRange)); bool IsVoid = (Cmd & 0x20000000) != 0; bool IsInput = (Cmd & 0x40000000) != 0; bool IsOutput = (Cmd & 0x80000000) != 0; size_t ParamLengthInBytes = (Cmd >> 16) & 0x1ff; char IoCtlX = (Cmd >> 8) & 0xff; uint8_t IoCtlCode = Cmd & 0xff; CAddr_t Buffer = CAddr_t(GetBits(aPacket.Data(3), BufferRange)); uint32_t Length = uint32_t(GetBits(aPacket.Data(4), LengthRange)); mLogger << setloglevel(LogLevel_IoActivity) << "Ethernet IOCTL request: " << DecPrinter(IoCtlCode) << " with " << DecPrinter(ParamLengthInBytes) << " bytes of parameter" << std::endl; // DumpMem(mLogger, "Parameter dump", Buffer, Length, mParent.GetMainframe()); // DumpMem(mLogger, "Ethernet DEV STRUCT", DevStruct, 64, GetMainframe()); IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); if (mPacketCaptureThread != nullptr) { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_OK)); } else { SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(Status_e::MPST_HDW)); } SendPacket(Response); } break; default: CRAY_ASSERT(false); break; } return true; } void SimIopEth_c::SendErrorResponse(std::vector &aIosDPacket, SimIopEth_n::Status_e aStatus) { IopEPacket_c Packet = GetIosEPacket(aIosDPacket); SendErrorResponse(Packet, aStatus); } void SimIopEth_c::SendErrorResponse(class IopEPacket_c &aPacket, SimIopEth_n::Status_e aStatus) { // Word 0 const BitRange_s TypeRange(56, 63); // Word 1 const BitRange_s DestIdRange(48, 63); const BitRange_s SourceIdRange(32, 47); const BitRange_s PathOwnerRange(25, 31); const BitRange_s IopNumberRange(22, 24); const BitRange_s ChannelNumberRange(16, 21); const BitRange_s RequestRange(8, 15); const BitRange_s StatusNumberRange(7, 7); const BitRange_s StatusRange(0, 6); IopEPacket_c Response = mParent.GenerateResponse(aPacket); Response.SetSize(aPacket.GetLength() - 1); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 1); ++Idx) { Response.Data(Idx) = aPacket.Data(Idx); } SetBitsInPlace(Response.Data(0), TypeRange, 'm'); // Mark packet as response SetBitsInPlace(Response.Data(1), StatusNumberRange, 0); SetBitsInPlace(Response.Data(1), StatusRange, uint8_t(aStatus)); SendPacket(Response); } IopEPacket_c SimIopEth_c::GetIosEPacket(std::vector &aIosDPacket) { IopEPacket_c RetVal; RetVal.SetSize(aIosDPacket.size() + 1); RetVal.SetLength(uint16_t(aIosDPacket.size() + 2)); for (size_t Idx = 0; Idx < aIosDPacket.size(); ++Idx) { RetVal.Data(Idx+1) = aIosDPacket[Idx]; } return RetVal; } void SimIopEth_c::SendPacket(IopEPacket_c &aPacket) { ++mCrayPacketsSent; if (mParent.GetIopRevision() == IopRevision_e::IOSE) { mParent.SendPacket(aPacket); } else { std::vector IosDPacket(6, 0); CRAY_ASSERT(aPacket.GetLength() == 8); for (size_t Idx = 0; Idx < size_t(aPacket.GetLength() - 2); ++Idx) IosDPacket[Idx] = aPacket.Data(Idx+1); ReversePacket(IosDPacket); mParent.SendPacket(IosDPacket); } } #if defined(PARTIAL_DEBUG) && defined(_MSC_VER) #pragma optimize ("", on) #endif