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