A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
netmap-net-device.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Pasquale Imputato <p.imputato@gmail.com>
7 */
8
9#include "netmap-net-device.h"
10
11#include "ns3/uinteger.h"
12
13#include <sys/ioctl.h>
14#include <thread>
15#include <unistd.h>
16
17namespace ns3
18{
19
20NS_LOG_COMPONENT_DEFINE("NetmapNetDevice");
21
22TypeId
24{
25 static TypeId tid = TypeId("ns3::NetDeviceQueueLock")
27 .SetGroupName("Network")
28 .AddConstructor<NetDeviceQueueLock>();
29 return tid;
30}
31
35
39
40bool
42{
43 m_mutex.lock();
44 bool stopped = NetDeviceQueue::IsStopped();
45 m_mutex.unlock();
46 return stopped;
47}
48
49void
51{
52 m_mutex.lock();
54 m_mutex.unlock();
55}
56
57void
59{
60 m_mutex.lock();
62 m_mutex.unlock();
63}
64
65void
67{
68 m_mutex.lock();
70 m_mutex.unlock();
71}
72
73void
80
81void
88
90 : m_bufferSize(65536),
91 // Defaults to maximum TCP window size
92 m_nifp(nullptr)
93{
94}
95
96void
98{
99 NS_LOG_FUNCTION(this << bufferSize);
100 m_bufferSize = bufferSize;
101}
102
103void
105{
106 NS_LOG_FUNCTION(this << nifp);
107 m_nifp = nifp;
108}
109
112{
113 NS_LOG_FUNCTION(this);
114
115 uint8_t* buf = (uint8_t*)malloc(m_bufferSize);
116 NS_ABORT_MSG_IF(buf == 0, "malloc() failed");
117
118 NS_LOG_LOGIC("Calling read on fd " << m_fd);
119
120 struct netmap_ring* rxring;
121 uint16_t len = 0;
122 uint32_t rxRingIndex = 0;
123
124 // we have a packet in one of the receiver rings
125 // we check for the first non empty receiver ring
126 while (rxRingIndex < m_nifp->ni_rx_rings)
127 {
128 rxring = NETMAP_RXRING(m_nifp, rxRingIndex);
129
130 if (!nm_ring_empty(rxring))
131 {
132 uint32_t i = rxring->cur;
133 uint8_t* buffer = (uint8_t*)NETMAP_BUF(rxring, rxring->slot[i].buf_idx);
134 len = rxring->slot[i].len;
135 NS_LOG_DEBUG("Received a packet of " << len << " bytes");
136
137 // copy buffer in the destination memory area
138 memcpy(buf, buffer, len);
139
140 // advance the netmap pointers and sync the fd
141 rxring->head = rxring->cur = nm_ring_next(rxring, i);
142
143 ioctl(m_fd, NIOCRXSYNC, nullptr);
144
145 break;
146 }
147
148 rxRingIndex++;
149 }
150
151 if (len <= 0)
152 {
153 free(buf);
154 buf = 0;
155 len = 0;
156 }
157 NS_LOG_LOGIC("Read " << len << " bytes on fd " << m_fd);
158 return FdReader::Data(buf, len);
159}
160
162
163TypeId
165{
166 static TypeId tid =
167 TypeId("ns3::NetmapNetDevice")
169 .SetGroupName("FdNetDevice")
170 .AddConstructor<NetmapNetDevice>()
171 .AddAttribute("SyncAndNotifyQueuePeriod",
172 "The period of time (in number of us) after which the device syncs the "
173 "netmap ring and notifies queue status.",
174 UintegerValue(50),
177 return tid;
178}
179
181{
182 NS_LOG_FUNCTION(this);
183 m_nifp = nullptr;
184 m_nTxRings = 0;
185 m_nTxRingsSlots = 0;
186 m_nRxRings = 0;
187 m_nRxRingsSlots = 0;
188 m_queue = nullptr;
191}
192
194{
195 NS_LOG_FUNCTION(this);
196 m_nifp = nullptr;
197 m_queue = nullptr;
198}
199
202{
203 NS_LOG_FUNCTION(this);
204
206 // 22 bytes covers 14 bytes Ethernet header with possible 8 bytes LLC/SNAP
207 fdReader->SetBufferSize(GetMtu() + 22);
208 fdReader->SetNetmapIfp(m_nifp);
209 return fdReader;
210}
211
212void
220
221void
223{
224 NS_LOG_FUNCTION(this);
225
226 m_queue->Stop();
227
229
230 if (m_syncAndNotifyQueueThread.joinable())
231 {
233 }
234}
235
238{
239 NS_LOG_FUNCTION(this);
240
241 struct netmap_ring* txring;
242 txring = NETMAP_TXRING(m_nifp, 0);
243
244 int tail = txring->tail;
245
246 // the netmap ring has one slot reserved
247 int inQueue = (m_nTxRingsSlots - 1) - nm_ring_space(txring);
248
249 uint32_t bytesInQueue = 0;
250
251 for (int i = 1; i < inQueue; i++)
252 {
253 bytesInQueue += txring->slot[tail].len;
254 tail++;
255 tail = tail % m_nTxRingsSlots;
256 }
257
258 return bytesInQueue;
259}
260
261void
268
269void
271{
272 NS_LOG_FUNCTION(this << nifp);
273
274 m_nifp = nifp;
275}
276
277void
279{
280 NS_LOG_FUNCTION(this << nTxRings << nTxRingsSlots);
281
282 m_nTxRings = nTxRings;
283 m_nTxRingsSlots = nTxRingsSlots;
284}
285
286void
288{
289 NS_LOG_FUNCTION(this << nRxRings << nRxRingsSlots);
290
291 m_nRxRings = nRxRings;
292 m_nRxRingsSlots = nRxRingsSlots;
293}
294
295int
297{
298 NS_LOG_FUNCTION(this);
299
300 struct netmap_ring* txring;
301 txring = NETMAP_TXRING(m_nifp, 0);
302
303 return nm_ring_space(txring);
304}
305
306// This function runs in a separate thread.
307void
309{
310 NS_LOG_FUNCTION(this);
311
312 struct netmap_ring* txring = NETMAP_TXRING(m_nifp, 0);
313
314 uint32_t prevTotalTransmittedBytes = 0;
315
316 while (m_syncAndNotifyQueueThreadRun == true)
317 {
318 // we sync the netmap ring periodically.
319 // the traffic control layer can write packets during the period between two syncs.
320 ioctl(GetFileDescriptor(), NIOCTXSYNC, nullptr);
321
322 // we need of a nearly periodic notification to queue limits of the transmitted bytes.
323 uint32_t totalTransmittedBytes = m_totalQueuedBytes - GetBytesInNetmapTxRing();
324 uint32_t deltaBytes = totalTransmittedBytes - prevTotalTransmittedBytes;
325 NS_LOG_DEBUG(deltaBytes << " delta transmitted bytes");
326 prevTotalTransmittedBytes = totalTransmittedBytes;
327 if (m_queue)
328 {
329 m_queue->NotifyTransmittedBytes(deltaBytes);
330
331 if (GetSpaceInNetmapTxRing() >= 32) // WAKE_THRESHOLD
332 {
333 if (m_queue->IsStopped())
334 {
335 m_queue->Wake();
336 }
337 }
338 }
339
341
342 NS_LOG_DEBUG("Space in the netmap ring of " << nm_ring_space(txring) << " packets");
343 }
344
345 ioctl(GetFileDescriptor(), NIOCTXSYNC, nullptr);
346}
347
348ssize_t
349NetmapNetDevice::Write(uint8_t* buffer, size_t length)
350{
351 NS_LOG_FUNCTION(this << buffer << length);
352
353 struct netmap_ring* txring;
354
355 // we use one ring also in case of multiqueue device to perform an accurate flow control on that
356 // ring
357 txring = NETMAP_TXRING(m_nifp, 0);
358
359 uint16_t ret = -1;
360
361 if (m_queue->IsStopped())
362 {
363 // the device queue is stopped and we cannot write other packets
364 return ret;
365 }
366
367 if (!nm_ring_empty(txring))
368 {
369 uint32_t i = txring->cur;
370 uint8_t* buf = (uint8_t*)NETMAP_BUF(txring, txring->slot[i].buf_idx);
371
372 memcpy(buf, buffer, length);
373 txring->slot[i].len = length;
374
375 txring->head = txring->cur = nm_ring_next(txring, i);
376
377 ret = length;
378
379 // we update the total transmitted bytes counter and notify queue limits of the queued bytes
380 m_totalQueuedBytes += length;
381 m_queue->NotifyQueuedBytes(length);
382
383 // if there is no room for other packets then stop the queue.
384 if (nm_ring_space(txring) == 0)
385 {
386 m_queue->Stop();
387 }
388 }
389
390 return ret;
391}
392
393} // namespace ns3
a NetDevice to read/write network traffic from/into a file descriptor.
int GetFileDescriptor() const
Get the associated file descriptor.
uint16_t GetMtu() const override
int m_fd
The file descriptor to read from.
Definition fd-reader.h:124
Network device transmission queue.
virtual void Stop()
Called by the device to stop this device transmission queue.
virtual void Wake()
Called by the device to wake the queue disc associated with this device transmission queue.
virtual bool IsStopped() const
Get the status of the device transmission queue.
virtual void Start()
Called by the device to start this device transmission queue.
virtual void NotifyTransmittedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes it is going to transmit.
virtual void NotifyQueuedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes queued to the device queue.
Network device transmission queue with lock.
virtual void NotifyTransmittedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes it is going to transmit.
virtual void NotifyQueuedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes queued to the device queue.
virtual bool IsStopped() const
Get the status of the device transmission queue.
virtual void Wake()
Called by the device to wake the queue disc associated with this device transmission queue.
std::mutex m_mutex
Mutex to serialize the operations performed on the queue.
static TypeId GetTypeId()
Get the type ID.
virtual void Stop()
Called by the device to stop this device transmission queue.
virtual void Start()
Called by the device to start this device transmission queue.
void SetBufferSize(uint32_t bufferSize)
Set size of the read buffer.
FdReader::Data DoRead()
The read implementation.
void SetNetmapIfp(struct netmap_if *nifp)
Set netmap interface representation.
struct netmap_if * m_nifp
Netmap interface representation.
uint32_t m_bufferSize
size of the read buffer
a NetDevice to read/write network traffic from/into a netmap file descriptor.
int GetSpaceInNetmapTxRing() const
Get the number of slots currently available in the netmap transmission ring.
uint32_t m_nRxRings
Number of receiver rings.
void SetRxRingsInfo(uint32_t nRxRings, uint32_t nRxRingsSlots)
Set the netmap receiver rings info.
void SetNetmapInterfaceRepresentation(struct netmap_if *nifp)
Set the netmap interface representation.
void DoFinishStoppingDevice()
Complete additional actions, if any, to tear down the device.
Ptr< NetDeviceQueue > m_queue
NetDevice queue.
uint8_t m_syncAndNotifyQueuePeriod
The period of time in us after which the device syncs the netmap ring and notifies queue status.
void DoFinishStartingDevice()
Complete additional actions, if any, to spin up down the device.
virtual ssize_t Write(uint8_t *buffer, size_t length)
The function Writes a packet into the netmap transmission ring.
uint32_t m_nTxRingsSlots
Number of slots in the transmission rings.
uint32_t GetBytesInNetmapTxRing()
Get the number of bytes currently in the netmap transmission ring.
std::thread m_syncAndNotifyQueueThread
Thread used to perform the flow control.
uint32_t m_nRxRingsSlots
Number of slots in the receiver rings.
struct netmap_if * m_nifp
Netmap interface representation.
uint32_t m_nTxRings
Number of transmission rings.
static TypeId GetTypeId()
Get the type ID.
void SetNetDeviceQueue(Ptr< NetDeviceQueue > queue)
Set the NetDeviceQueue.
uint32_t m_totalQueuedBytes
Total queued bytes.
std::atomic< bool > m_syncAndNotifyQueueThreadRun
Running flag of the flow control thread.
Ptr< FdReader > DoCreateFdReader()
Create the FdReader object.
virtual void SyncAndNotifyQueue()
This function syncs netmap ring and notifies netdevice queue.
void SetTxRingsInfo(uint32_t nTxRings, uint32_t nTxRingsSlots)
Set the netmap transmission rings info.
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
A structure representing data read.
Definition fd-reader.h:80