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
27namespace ns3 {
28
29NS_LOG_COMPONENT_DEFINE ("NetmapNetDevice");
30
31TypeId
33{
34 static TypeId tid = TypeId ("ns3::NetDeviceQueueLock")
36 .SetGroupName ("Network")
37 .AddConstructor<NetDeviceQueueLock> ();
38 return tid;
39}
40
42{}
43
45{}
46
47bool
49{
50 m_mutex.lock ();
51 bool stopped = NetDeviceQueue::IsStopped ();
52 m_mutex.unlock ();
53 return stopped;
54}
55
56void
58{
59 m_mutex.lock ();
61 m_mutex.unlock ();
62}
63
64void
66{
67 m_mutex.lock ();
69 m_mutex.unlock ();
70}
71
72void
74{
75 m_mutex.lock ();
77 m_mutex.unlock ();
78}
79
80void
82{
83 m_mutex.lock ();
85 m_mutex.unlock ();
86}
87
88void
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
102void
104{
105 NS_LOG_FUNCTION (this << bufferSize);
106 m_bufferSize = bufferSize;
107}
108
109void
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
169TypeId
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;
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
217void
219{
220 NS_LOG_FUNCTION (this);
221
225}
226
227
228void
230{
231 NS_LOG_FUNCTION (this);
232
233 m_queue->Stop ();
234
238}
239
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
265void
267{
268 NS_LOG_FUNCTION (this);
269
270 m_queue = queue;
271}
272
273void
275{
276 NS_LOG_FUNCTION (this << nifp);
277
278 m_nifp = nifp;
279}
280
281void
283{
284 NS_LOG_FUNCTION (this << nTxRings << nTxRingsSlots);
285
286 m_nTxRings = nTxRings;
287 m_nTxRingsSlots = nTxRingsSlots;
288}
289
290void
292{
293 NS_LOG_FUNCTION (this << nRxRings << nRxRingsSlots);
294
295 m_nRxRings = nRxRings;
296 m_nRxRingsSlots = nRxRingsSlots;
297}
298
299int
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.
311void
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
353ssize_t
354NetmapNetDevice::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
a NetDevice to read/write network traffic from/into a file descriptor.
Definition: fd-net-device.h:86
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.
Ptr< SystemThread > m_syncAndNotifyQueueThread
Thread used to perform the flow control.
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.
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)
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.
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:1648
A structure representing data read.