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
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;
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
216void
218{
219 NS_LOG_FUNCTION (this);
220
223}
224
225
226void
228{
229 NS_LOG_FUNCTION (this);
230
231 m_queue->Stop ();
232
234
235 if (m_syncAndNotifyQueueThread.joinable ())
236 {
238 }
239}
240
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
266void
268{
269 NS_LOG_FUNCTION (this);
270
271 m_queue = queue;
272}
273
274void
276{
277 NS_LOG_FUNCTION (this << nifp);
278
279 m_nifp = nifp;
280}
281
282void
284{
285 NS_LOG_FUNCTION (this << nTxRings << nTxRingsSlots);
286
287 m_nTxRings = nTxRings;
288 m_nTxRingsSlots = nTxRingsSlots;
289}
290
291void
293{
294 NS_LOG_FUNCTION (this << nRxRings << nRxRingsSlots);
295
296 m_nRxRings = nRxRings;
297 m_nRxRingsSlots = nRxRingsSlots;
298}
299
300int
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.
312void
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
354ssize_t
355NetmapNetDevice::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)
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.