26template <
typename Engine>
105 Statistics _statistics;
107 std::queue<DataBuffer*> _free_buffers;
108 std::atomic<bool> _running;
112 std::ofstream _latency_csv_file;
114 bool running() {
return _running.load(std::memory_order_acquire); }
118template <
typename Engine>
121 db<NIC>(
INF) <<
"[NIC] [constructor] initializing buffers and semaphores\n";
125 _free_buffers.push(&_buffer[
i]);
133 _address = Engine::mac_address();
136 _latency_csv_file.open(
"nic_latency.csv", std::ios::out | std::ios::app);
137 if (_latency_csv_file.is_open()) {
139 std::ifstream
test_file(
"nic_latency.csv");
142 _latency_csv_file <<
"latency_us\n";
145 db<NIC>(
INF) <<
"[NIC] [constructor] CSV latency log file opened\n";
147 db<NIC>(
WRN) <<
"[NIC] [constructor] Failed to open CSV latency log file\n";
152 db<NIC>(
INF) <<
"[NIC] [constructor] NIC fully initialized and Engine started with default radius " << _radius <<
"m\n";
155template <
typename Engine>
161 if (_latency_csv_file.is_open()) {
162 _latency_csv_file.close();
163 db<NIC>(
INF) <<
"[NIC] [destructor] CSV latency log file closed\n";
168 db<NIC>(
INF) <<
"[NIC] [destructor] semaphores destroyed\n";
172template <
typename Engine>
175 _running.store(
false, std::memory_order_release);
178 for (
unsigned int i = 0;
i < N_BUFFERS -
sem_value; ++
i) {
184template <
typename Engine>
186 db<NIC>(
TRC) <<
"NIC<Engine>::send() called!\n";
188 db<NIC>(
TRC) <<
"[NIC] send called when NIC is not running \n";
193 db<NIC>(
WRN) <<
"[NIC] send() called with a null buffer\n";
194 _statistics.tx_drops++;
205 _statistics.tx_drops++;
208 _statistics.packets_sent++;
209 _statistics.bytes_sent +=
result;
215template <
typename Engine>
217 db<NIC>(
TRC) <<
"NIC<Engine>::send() called!\n";
220 db<NIC>(
ERR) <<
"[NIC] send() called when NIC is inactive\n";
225 db<NIC>(
WRN) <<
"[NIC] send() called with a null buffer\n";
226 _statistics.tx_drops++;
234 _statistics.tx_drops++;
237 _statistics.packets_sent++;
238 _statistics.bytes_sent +=
result;
244template <
typename Engine>
246 db<NIC>(
TRC) <<
"NIC<Engine>::receive() called!\n";
249 db<NIC>(
ERR) <<
"[NIC] receive() called when NIC is inactive\n";
254 db<NIC>(
WRN) <<
"[NIC] receive() called with a null buffer\n";
255 _statistics.rx_drops++;
279template <
typename Engine>
285 db<NIC>(
WRN) <<
"[NIC] [handle()] called but NIC is not running - ignoring packet\n";
290 if (
frame->src == _address) {
302 db<NIC>(
INF) <<
"[NIC] [handle()] dropping empty frame\n";
303 _statistics.rx_drops++;
307 db<NIC>(
TRC) <<
"[NIC] [handle()] allocating buffer\n";
309 db<NIC>(
TRC) <<
"[NIC] [handle()] buffer allocated\n";
312 db<NIC>(
ERR) <<
"[NIC] [handle()] alloc called, but NIC is not running\n";
317 db<NIC>(
TRC) <<
"[NIC] [handle()] filling RX timestamp in the buffer\n";
320 std::int64_t timestamp =
rx_time.time_since_epoch().count();
321 buf->setRX(timestamp);
322 db<NIC>(
TRC) <<
"[NIC] [handle()] RX timestamp filled in the buffer: " << timestamp <<
"\n";
325 db<NIC>(
TRC) <<
"[NIC] [handle()] copying frame to buffer\n";
327 db<NIC>(
TRC) <<
"[NIC] [handle()] frame copied to buffer\n";
330 db<NIC>(
TRC) <<
"[NIC] [handle()] extracting TX timestamp for latency calculation\n";
331 const unsigned int header_size =
sizeof(std::uint16_t) * 2 +
sizeof(std::uint32_t);
332 const unsigned int tx_timestamp_offset =
header_size + 8;
341 db<NIC>(
INF) <<
"[NIC] [handle()] Latency calculated: TX=" <<
tx_time.time_since_epoch().count()
342 <<
"us, RX=" <<
rx_time.time_since_epoch().count() <<
"us, Latency=" <<
latency_us <<
"us\n";
347 db<NIC>(
WRN) <<
"[NIC] [handle()] Packet too small for TX timestamp extraction. Size: " <<
packet_size
348 <<
", required: " << (tx_timestamp_offset +
sizeof(
TimestampType)) <<
"\n";
352 db<NIC>(
ERR) <<
"[NIC] [handle()] trying to notify protocol when NIC is inactive\n";
358 db<NIC>(
INF) <<
"[NIC] [handle()] data received, but no one was notified (" <<
proto <<
")\n";
363template <
typename Engine>
368 db<NIC>(
ERR) <<
"[NIC] [alloc()] called when NIC is inactive\n";
373 db<NIC>(
TRC) <<
"[NIC] [alloc()] acquiring free buffers counter semaphore\n";
375 db<NIC>(
TRC) <<
"[NIC] [alloc()] free buffers counter semaphore acquired\n";
378 db<NIC>(
TRC) <<
"[NIC] [alloc()] acquiring binary semaphore\n";
380 db<NIC>(
TRC) <<
"[NIC] [alloc()] binary semaphore acquired\n";
383 db<NIC>(
TRC) <<
"[NIC] [alloc()] buffer removed from free buffers queue\n";
385 db<NIC>(
TRC) <<
"[NIC] [alloc()] binary semaphore released\n";
402template <
typename Engine>
404 db<NIC>(
TRC) <<
"NIC<Engine>::free() called!\n";
406 if (
buf ==
nullptr) {
407 db<NIC>(
WRN) <<
"[NIC] free() called with a null buffer\n";
412 db<NIC>(
ERR) <<
"[NIC] free() called when NIC is inactive\n";
419 db<NIC>(
INF) <<
"[NIC] [free()] freeing buffer, current semaphore value: " <<
sem_value <<
"\n";
426 _free_buffers.push(
buf);
438template <
typename Engine>
443template <
typename Engine>
449template <
typename Engine>
454template <
typename Engine>
456 db<NIC>(
TRC) <<
"NIC<Engine>::fillTxTimestamp() called!\n";
466 const unsigned int header_size =
sizeof(std::uint16_t) * 2 +
sizeof(std::uint32_t);
467 const unsigned int tx_timestamp_offset =
header_size + 8;
478 db<NIC>(
INF) <<
"[NIC] Filled TX timestamp at offset " << tx_timestamp_offset
479 <<
": " <<
tx_time.time_since_epoch().count() <<
"us\n";
482 <<
", required: " << (tx_timestamp_offset +
sizeof(
TimestampType)) <<
"\n";
486template <
typename Engine>
491template <
typename Engine>
501template <
typename Engine>
503 if (_latency_csv_file.is_open()) {
505 _latency_csv_file.flush();
508 db<NIC>(
WRN) <<
"[NIC] [logLatency] CSV file not open, cannot log latency\n";
static Clock & getInstance()
Get the singleton instance.
Definition clock.h:145
static std::string mac_to_string(Address addr)
Definition ethernet.h:36
std::uint16_t Protocol
Definition ethernet.h:24
static constexpr unsigned int HEADER_SIZE
Definition ethernet.h:26
This class initializes the API.
Definition initializer.h:20
const Address & address()
Definition nic.h:439
void setRadius(double radius)
Definition nic.h:492
static const unsigned int N_BUFFERS
Definition nic.h:32
Buffer< Ethernet::Frame > DataBuffer
Definition nic.h:37
int send(DataBuffer *buf, unsigned int packet_size)
Definition nic.h:185
double radius()
Definition nic.h:487
Conditionally_Data_Observed< DataBuffer, Protocol_Number > Observed
Definition nic.h:39
Conditional_Data_Observer< DataBuffer, Protocol_Number > Observer
Definition nic.h:38
~NIC()
Definition nic.h:156
void free(DataBuffer *buf)
Definition nic.h:403
DataBuffer * alloc(Address dst, Protocol_Number prot, unsigned int size)
Definition nic.h:364
Ethernet::Protocol Protocol_Number
Definition nic.h:36
const Statistics & statistics()
Definition nic.h:450
Ethernet::Address Address
Definition nic.h:35
int receive(DataBuffer *buf, Address *src, Address *dst, void *data, unsigned int size)
Definition nic.h:245
void setAddress(Address address)
Definition nic.h:444
static constexpr unsigned int MAX_FRAME_SIZE
Definition nic.h:33
void stop()
Definition nic.h:173
NIC()
Definition nic.h:119
std::chrono::time_point< std::chrono::steady_clock, std::chrono::microseconds > TimestampType
Definition clock.h:16
@ INF
Definition debug.h:208
Select_Debug<(Traits< T >::debugged &&Traits< Debug >::error)> db(Debug_Error l)
Definition debug.h:166
@ ERR
Definition debug.h:162
@ TRC
Definition debug.h:231
@ WRN
Definition debug.h:185
Protocol prot
Definition ethernet.h:2
Address src
Definition ethernet.h:1
Address dst
Definition ethernet.h:0
T * data()
Definition protocol.h:24
Address src
Definition ethernet.h:31
std::uint8_t payload[MTU]
Definition ethernet.h:33
std::atomic< unsigned int > bytes_sent
Definition nic.h:45
std::atomic< unsigned int > rx_drops
Definition nic.h:48
std::atomic< unsigned int > tx_drops
Definition nic.h:47
std::atomic< unsigned int > packets_received
Definition nic.h:44
Statistics()
Definition nic.h:50
std::atomic< unsigned int > bytes_received
Definition nic.h:46
std::atomic< unsigned int > packets_sent
Definition nic.h:43