Files
Jungfraujoch/receiver/host/MlxRawEthDevice.cpp

227 lines
7.1 KiB
C++

// Copyright (2019-2022) Paul Scherrer Institute
// SPDX-License-Identifier: GPL-3.0-or-later
#ifdef JFJOCH_USE_IBVERBS
#include "MlxRawEthDevice.h"
#include <netinet/in.h>
#ifdef JFJOCH_USE_NUMA
#include <numa.h>
#endif
MlxRawEthDevice::MlxRawEthDevice(uint16_t dev_id, uint16_t data_stream, size_t in_frame_buffer_size_modules,
int16_t in_numa_node)
: AcquisitionDevice(data_stream),
context("mlx5_" + std::to_string(dev_id)),
numa_node(in_numa_node)
{
max_modules = 16;
MapBuffersStandard(in_frame_buffer_size_modules, 1, numa_node);
mac_addr = (static_cast<uint64_t>(dev_id) << 8*5) | 0x00DDCCBBAA06;
}
void MlxRawEthDevice::InitializeCalibration(const DiffractionExperiment &experiment, const JFCalibration &calib) {
// Do nothing
}
int32_t MlxRawEthDevice::GetNUMANode() const {
return numa_node;
}
void MlxRawEthDevice::HW_WriteActionRegister(const ActionConfig *job) {
memcpy(&cfg, job, sizeof(ActionConfig));
}
void MlxRawEthDevice::HW_ReadActionRegister(ActionConfig *job) {
memcpy(job, &cfg, sizeof(ActionConfig));
}
void MlxRawEthDevice::MeasureThread() {
uint64_t packet_count = 0;
work_completion_queue.Put(Completion{
.type = Completion::Type::Start
});
try {
IBProtectionDomain pd(context);
IBCompletionQueue cq(context, BUFFER_COUNT+2);
IBQueuePair qp(pd, cq, 16, BUFFER_COUNT);
IBRegBuffer buffer(pd, BUFFER_COUNT, BUFFER_SIZE, numa_node);
ProcessJFPacket process(work_completion_queue, wr_queue, cfg.nmodules);
qp.Init();
qp.ReadyToReceive();
qp.ReadyToSend();
qp.FlowSteeringIPv4(ipv4_addr);
for (int i = 0; i < BUFFER_COUNT-1; i++)
qp.PostReceiveWR(*buffer.GetMemoryRegion(), i, buffer.GetLocation(i), BUFFER_SIZE);
auto cq_poll_future = std::async(std::launch::async, &MlxRawEthDevice::PollCQ,
this,
std::ref(buffer),
std::ref(qp),
std::ref(cq),
std::ref(process));
auto arp_future = std::async(std::launch::async, &MlxRawEthDevice::SendARP,
this,
std::ref(buffer),
std::ref(qp));
packet_count = cq_poll_future.get();
arp_future.get();
} catch (const JFJochException &e) {
cancel = true;
if (logger)
logger->ErrorException(e);
}
work_completion_queue.Put(Completion{
.type = Completion::Type::End,
.frame_number = packet_count
});
idle = true;
}
void MlxRawEthDevice::HW_StartAction() {
if (cfg.mode & MODE_CONV)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Conversion on CPU flag has to be enabled for Raw Ethernet device");
cancel = false;
idle = false;
measure = std::async(std::launch::async, &MlxRawEthDevice::MeasureThread, this);
}
bool MlxRawEthDevice::HW_IsIdle() const {
return idle;
}
void MlxRawEthDevice::HW_SetCancelDataCollectionBit() {
cancel = true;
}
bool MlxRawEthDevice::HW_SendWorkRequest(uint32_t handle) {
if (handle != UINT32_MAX)
wr_queue.Put(ProcessWorkRequest{
.ptr = buffer_device.at(handle),
.handle = handle
});
return true;
}
void MlxRawEthDevice::HW_GetStatus(ActionStatus *status) const {
memset(status, 0, sizeof(ActionStatus));
status->modules_internal_packet_generator = 1;
status->max_modules = max_modules;
}
void MlxRawEthDevice::HW_EndAction() {
if (measure.valid())
measure.get();
}
void MlxRawEthDevice::CopyInternalPacketGenFrameToDeviceBuffer() {
// Do nothing
}
void MlxRawEthDevice::SetMACAddress(uint64_t mac_addr_network_order) {
mac_addr = mac_addr_network_order;
}
void MlxRawEthDevice::SetIPv4Address(uint32_t ipv4_addr_network_order) {
ipv4_addr = ipv4_addr_network_order;
}
uint64_t MlxRawEthDevice::HW_GetMACAddress() const {
return mac_addr;
}
uint32_t MlxRawEthDevice::HW_GetIPv4Address() const {
return ipv4_addr;
}
uint64_t MlxRawEthDevice::PollCQ(IBRegBuffer &buffer, IBQueuePair &qp, IBCompletionQueue &cq, ProcessJFPacket &process) {
#ifdef JFJOCH_USE_NUMA
if (numa_available() != -1)
numa_run_on_node(numa_node);
#endif
uint64_t packet_counter = 0;
while (!cancel) {
int64_t i;
size_t size;
if (cq.Poll(i, size) > 0) {
if ((i < BUFFER_COUNT) && (size == sizeof(jf_raw_packet))) {
auto ptr = (jf_raw_packet *) buffer.GetLocation(i);
process.ProcessPacket(&ptr->jf);
qp.PostReceiveWR(*buffer.GetMemoryRegion(), i, buffer.GetLocation(i), BUFFER_SIZE);
packet_counter++;
}
} else
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
return packet_counter;
}
// ARP packet - from if_arp.h
#pragma pack(push)
#pragma pack(2)
struct RAW_ARP_Packet
{
unsigned char dest_mac[6];
unsigned char sour_mac[6];
uint16_t ether_type;
unsigned short int ar_hrd; /* Format of hardware address. */
unsigned short int ar_pro; /* Format of protocol address. */
unsigned char ar_hln; /* Length of hardware address. */
unsigned char ar_pln; /* Length of protocol address. */
unsigned short int ar_op; /* ARP opcode (command). */
unsigned char ar_sha[6]; /* Sender hardware address. */
unsigned ar_sip; /* Sender IP address. */
unsigned char ar_tha[6]; /* Target hardware address. */
unsigned ar_tip; /* Target IP address. */
};
#pragma pack(pop)
void MlxRawEthDevice::SendARP(IBRegBuffer &buffer, IBQueuePair &qp) {
uint8_t src_mac[6];
for (int i = 0; i < 6; i++)
src_mac[i] = (mac_addr & (0xFFlu << (i * 8))) >> (i * 8);
RAW_ARP_Packet arp_packet{
.dest_mac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
.sour_mac = {src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]},
.ether_type = htons(0x0806), // ether type for ARP
.ar_hrd = htons(1), // MAC addr
.ar_pro = htons(0x0800), // IPv4
.ar_hln = 0x6, // 6 bytes
.ar_pln = 0x4, // 4 bytes
.ar_op = htons(1), // ARP request
.ar_sha = {src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]},
.ar_sip = ipv4_addr,
.ar_tha = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
.ar_tip = ipv4_addr
};
memcpy(buffer.GetLocation(BUFFER_COUNT-1), &arp_packet, sizeof(RAW_ARP_Packet));
while (!cancel) {
qp.PostSendWR(*buffer.GetMemoryRegion(), buffer.GetLocation(BUFFER_COUNT-1), sizeof(RAW_ARP_Packet));
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
#endif //JFJOCH_USE_IBVERBS