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
struct netmap_if * m_nifp
Netmap interface representation.
int GetSpaceInNetmapTxRing() const
Get the number of slots currently available in the netmap transmission ring.
A structure representing data read.
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
uint8_t m_syncAndNotifyQueuePeriod
The period of time in us after which the device syncs the netmap ring and notifies queue status...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
virtual void NotifyQueuedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes queued to the device queue. ...
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
uint32_t m_nTxRings
Number of transmission rings.
uint32_t m_nRxRings
Number of receiver rings.
uint32_t GetBytesInNetmapTxRing()
Get the number of bytes currently in the netmap transmission ring.
virtual void SyncAndNotifyQueue()
This function syncs netmap ring and notifies netdevice queue.
std::atomic< bool > m_syncAndNotifyQueueThreadRun
Running flag of the flow control thread.
virtual bool IsStopped(void) const
Get the status of the device transmission queue.
uint32_t m_totalQueuedBytes
Total queued bytes.
uint32_t m_bufferSize
size of the read buffer
Network device transmission queue with lock.
uint32_t m_nRxRingsSlots
Number of slots in the receiver rings.
virtual void Start(void)
Called by the device to start this device transmission queue.
void SetNetmapInterfaceRepresentation(struct netmap_if *nifp)
Set the netmap interface representation.
int m_fd
The file descriptor to read from.
Hold an unsigned integer type.
Definition: uinteger.h:44
struct netmap_if * m_nifp
Netmap interface representation.
virtual void Stop(void)
Called by the device to stop this device transmission queue.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
void SetNetmapIfp(struct netmap_if *nifp)
Set netmap interface representation.
void SetBufferSize(uint32_t bufferSize)
Set size of the read buffer.
virtual void NotifyQueuedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes queued to the device queue. ...
Every class exported by the ns3 library is enclosed in the ns3 namespace.
virtual void Stop(void)
Called by the device to stop this device transmission queue.
virtual void Start(void)
Called by the device to start this device transmission queue.
virtual uint16_t GetMtu(void) const
Ptr< NetDeviceQueue > m_queue
NetDevice queue.
int GetFileDescriptor(void) const
Get the associated file descriptor.
virtual void NotifyTransmittedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes it is going to transmit.
virtual void NotifyTransmittedBytes(uint32_t bytes)
Called by the netdevice to report the number of bytes it is going to transmit.
Ptr< SystemThread > m_syncAndNotifyQueueThread
Thread used to perform the flow control.
void DoFinishStartingDevice(void)
Complete additional actions, if any, to spin up down the device.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
virtual void Wake(void)
Called by the device to wake the queue disc associated with this device transmission queue...
Ptr< FdReader > DoCreateFdReader(void)
Create the FdReader object.
virtual ssize_t Write(uint8_t *buffer, size_t length)
The function Writes a packet into the netmap transmission ring.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
FdReader::Data DoRead(void)
The read implementation.
uint32_t m_nTxRingsSlots
Number of slots in the transmission rings.
void SetNetDeviceQueue(Ptr< NetDeviceQueue > queue)
Set the NetDeviceQueue.
virtual bool IsStopped(void) const
Get the status of the device transmission queue.
a NetDevice to read/write network traffic from/into a file descriptor.
Definition: fd-net-device.h:84
static TypeId GetTypeId(void)
Get the type ID.
static TypeId GetTypeId(void)
Get the type ID.
a NetDevice to read/write network traffic from/into a netmap file descriptor.
Network device transmission queue.
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
void SetTxRingsInfo(uint32_t nTxRings, uint32_t nTxRingsSlots)
Set the netmap transmission rings info.
a unique identifier for an interface.
Definition: type-id.h:58
void DoFinishStoppingDevice(void)
Complete additional actions, if any, to tear down the device.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
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
void SetRxRingsInfo(uint32_t nRxRings, uint32_t nRxRingsSlots)
Set the netmap receiver rings info.
std::mutex m_mutex
Mutex to serialize the operations performed on the queue.
virtual void Wake(void)
Called by the device to wake the queue disc associated with this device transmission queue...