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/uinteger.h"
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25 #include <thread>
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;
195 }
196 
198 {
199  NS_LOG_FUNCTION (this);
200  m_nifp = nullptr;
201  m_queue = nullptr;
202 }
203 
206 {
207  NS_LOG_FUNCTION (this);
208 
209  Ptr<NetmapNetDeviceFdReader> fdReader = Create<NetmapNetDeviceFdReader> ();
210  // 22 bytes covers 14 bytes Ethernet header with possible 8 bytes LLC/SNAP
211  fdReader->SetBufferSize (GetMtu () + 22);
212  fdReader->SetNetmapIfp (m_nifp);
213  return fdReader;
214 }
215 
216 void
218 {
219  NS_LOG_FUNCTION (this);
220 
223 }
224 
225 
226 void
228 {
229  NS_LOG_FUNCTION (this);
230 
231  m_queue->Stop ();
232 
234 
235  if (m_syncAndNotifyQueueThread.joinable ())
236  {
238  }
239 }
240 
241 uint32_t
243 {
244  NS_LOG_FUNCTION (this);
245 
246  struct netmap_ring *txring;
247  txring = NETMAP_TXRING (m_nifp, 0);
248 
249  int tail = txring->tail;
250 
251  // the netmap ring has one slot reserved
252  int inQueue = (m_nTxRingsSlots - 1) - nm_ring_space (txring);
253 
254  uint32_t bytesInQueue = 0;
255 
256  for (int i = 1; i < inQueue; i++)
257  {
258  bytesInQueue += txring->slot[tail].len;
259  tail++;
260  tail = tail % m_nTxRingsSlots;
261  }
262 
263  return bytesInQueue;
264 }
265 
266 void
268 {
269  NS_LOG_FUNCTION (this);
270 
271  m_queue = queue;
272 }
273 
274 void
276 {
277  NS_LOG_FUNCTION (this << nifp);
278 
279  m_nifp = nifp;
280 }
281 
282 void
283 NetmapNetDevice::SetTxRingsInfo (uint32_t nTxRings, uint32_t nTxRingsSlots)
284 {
285  NS_LOG_FUNCTION (this << nTxRings << nTxRingsSlots);
286 
287  m_nTxRings = nTxRings;
288  m_nTxRingsSlots = nTxRingsSlots;
289 }
290 
291 void
292 NetmapNetDevice::SetRxRingsInfo (uint32_t nRxRings, uint32_t nRxRingsSlots)
293 {
294  NS_LOG_FUNCTION (this << nRxRings << nRxRingsSlots);
295 
296  m_nRxRings = nRxRings;
297  m_nRxRingsSlots = nRxRingsSlots;
298 }
299 
300 int
302 {
303  NS_LOG_FUNCTION (this);
304 
305  struct netmap_ring *txring;
306  txring = NETMAP_TXRING (m_nifp, 0);
307 
308  return nm_ring_space (txring);
309 }
310 
311 // This function runs in a separate thread.
312 void
314 {
315  NS_LOG_FUNCTION (this);
316 
317  struct netmap_ring *txring = NETMAP_TXRING (m_nifp, 0);
318 
319  uint32_t prevTotalTransmittedBytes = 0;
320 
321  while (m_syncAndNotifyQueueThreadRun == true)
322  {
323  // we sync the netmap ring periodically.
324  // the traffic control layer can write packets during the period between two syncs.
325  ioctl (GetFileDescriptor (), NIOCTXSYNC, NULL);
326 
327  // we need of a nearly periodic notification to queue limits of the transmitted bytes.
328  uint32_t totalTransmittedBytes = m_totalQueuedBytes - GetBytesInNetmapTxRing ();
329  uint32_t deltaBytes = totalTransmittedBytes - prevTotalTransmittedBytes;
330  NS_LOG_DEBUG (deltaBytes << " delta transmitted bytes");
331  prevTotalTransmittedBytes = totalTransmittedBytes;
332  if (m_queue)
333  {
334  m_queue->NotifyTransmittedBytes (deltaBytes);
335 
336  if (GetSpaceInNetmapTxRing () >= 32) // WAKE_THRESHOLD
337  {
338  if (m_queue->IsStopped ())
339  {
340  m_queue->Wake ();
341  }
342  }
343  }
344 
346 
347  NS_LOG_DEBUG ("Space in the netmap ring of " << nm_ring_space (txring) << " packets");
348  }
349 
350  ioctl (GetFileDescriptor (), NIOCTXSYNC, NULL);
351 
352 }
353 
354 ssize_t
355 NetmapNetDevice::Write (uint8_t *buffer, size_t length)
356 {
357  NS_LOG_FUNCTION (this << buffer << length);
358 
359  struct netmap_ring *txring;
360 
361  // we use one ring also in case of multiqueue device to perform an accurate flow control on that ring
362  txring = NETMAP_TXRING (m_nifp, 0);
363 
364  uint16_t ret = -1;
365 
366  if (m_queue->IsStopped ())
367  {
368  // the device queue is stopped and we cannot write other packets
369  return ret;
370  }
371 
372  if (!nm_ring_empty (txring))
373  {
374 
375  uint32_t i = txring->cur;
376  uint8_t *buf = (uint8_t *) NETMAP_BUF (txring, txring->slot[i].buf_idx);
377 
378  memcpy (buf, buffer, length);
379  txring->slot[i].len = length;
380 
381  txring->head = txring->cur = nm_ring_next (txring, i);
382 
383  ret = length;
384 
385  // we update the total transmitted bytes counter and notify queue limits of the queued bytes
386  m_totalQueuedBytes += length;
387  m_queue->NotifyQueuedBytes (length);
388 
389  // if there is no room for other packets then stop the queue.
390  if (nm_ring_space (txring) == 0)
391  {
392  m_queue->Stop ();
393  }
394  }
395 
396  return ret;
397 }
398 
399 } // namespace ns3
a NetDevice to read/write network traffic from/into a file descriptor.
Definition: fd-net-device.h:85
virtual uint16_t GetMtu(void) const
int GetFileDescriptor(void) const
Get the associated file descriptor.
int m_fd
The file descriptor to read from.
Network device transmission queue.
virtual bool IsStopped(void) const
Get the status of the device transmission queue.
virtual void Wake(void)
Called by the device to wake the queue disc associated with 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.
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.
Network device transmission queue with lock.
static TypeId GetTypeId(void)
Get the type ID.
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.
std::mutex m_mutex
Mutex to serialize the operations performed on the queue.
virtual void Start(void)
Called by the device to start this device transmission queue.
virtual void Stop(void)
Called by the device to stop this device transmission queue.
virtual bool IsStopped(void) const
Get the status of the device transmission queue.
virtual void Wake(void)
Called by the device to wake the queue disc associated with this device transmission queue.
FdReader::Data DoRead(void)
The read implementation.
void SetBufferSize(uint32_t bufferSize)
Set size of the read buffer.
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.
static TypeId GetTypeId(void)
Get the type ID.
void DoFinishStoppingDevice(void)
Complete additional actions, if any, to tear down the device.
void SetNetmapInterfaceRepresentation(struct netmap_if *nifp)
Set the netmap interface representation.
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.
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.
void DoFinishStartingDevice(void)
Complete additional actions, if any, to spin up down the device.
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.
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(void)
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.
Definition: ptr.h:74
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
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
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:273
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#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:45
Every class exported by the ns3 library is enclosed in the ns3 namespace.
A structure representing data read.