LEFT | RIGHT |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 /* | 2 /* |
3 * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II | 3 * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II |
4 * | 4 * |
5 * This program is free software; you can redistribute it and/or modify | 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 | 6 * it under the terms of the GNU General Public License version 2 as |
7 * published by the Free Software Foundation; | 7 * published by the Free Software Foundation; |
8 * | 8 * |
9 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 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 | 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 | 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 * | 17 * |
18 * Author: Pasquale Imputato <p.imputato@gmail.com> | 18 * Author: Pasquale Imputato <p.imputato@gmail.com> |
19 * | 19 * |
20 */ | 20 */ |
21 | 21 |
22 #include "netmap-net-device.h" | 22 #include "netmap-net-device.h" |
23 #include "ns3/log.h" | 23 #include "ns3/log.h" |
24 #include "ns3/net-device-queue-interface.h" | 24 #include "ns3/net-device-queue-interface.h" |
25 #include "ns3/simulator.h" | 25 #include "ns3/simulator.h" |
26 #include "ns3/system-thread.h" | 26 #include "ns3/system-thread.h" |
27 #include "ns3/system-condition.h" | 27 #include "ns3/system-condition.h" |
| 28 #include "ns3/system-mutex.h" |
28 | 29 |
29 #include <sys/ioctl.h> | 30 #include <sys/ioctl.h> |
30 #include <sys/mman.h> | 31 #include <sys/mman.h> |
31 | 32 |
32 #include <poll.h> | 33 #include <poll.h> |
33 | 34 |
34 namespace ns3 { | 35 namespace ns3 { |
35 | 36 |
36 NS_LOG_COMPONENT_DEFINE ("NetmapNetDevice"); | 37 NS_LOG_COMPONENT_DEFINE ("NetmapNetDevice"); |
37 | 38 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 } | 138 } |
138 | 139 |
139 // getting the base struct of the interface in netmap mode | 140 // getting the base struct of the interface in netmap mode |
140 m_nifp = NETMAP_IF (memory, nmr.nr_offset); | 141 m_nifp = NETMAP_IF (memory, nmr.nr_offset); |
141 | 142 |
142 if (!m_nifp) | 143 if (!m_nifp) |
143 { | 144 { |
144 return false; | 145 return false; |
145 } | 146 } |
146 | 147 |
147 // this function read at initialization time the device infos, e.g. the number
of transmission ring slots. | |
148 // any change performed by the user host-side after the initialization | |
149 // time, e.g., by ethtool, has no effect ns-3-side | |
150 m_nTxRings = m_nifp->ni_tx_rings; | 148 m_nTxRings = m_nifp->ni_tx_rings; |
151 m_nRxRings = m_nifp->ni_rx_rings; | 149 m_nRxRings = m_nifp->ni_rx_rings; |
152 m_nTxRingsSlots = nmr.nr_tx_slots; | 150 m_nTxRingsSlots = nmr.nr_tx_slots; |
153 m_nRxRingsSlots = nmr.nr_rx_slots; | 151 m_nRxRingsSlots = nmr.nr_rx_slots; |
154 | 152 |
155 // we run a separated thread to perform flow control (between the netmap trans
mission ring) and | |
156 // to perform periodic netmap ring sync and notification about the transmitted
bytes to BQL. | |
157 m_waitingSlotThreadRun = true; | 153 m_waitingSlotThreadRun = true; |
158 m_waitingSlotThread = Create<SystemThread> (MakeCallback (&NetmapNetDevice::Wa
itingSlot, this)); | 154 m_waitingSlotThread = Create<SystemThread> (MakeCallback (&NetmapNetDevice::Wa
itingSlot, this)); |
159 m_waitingSlotThread->Start (); | 155 m_waitingSlotThread->Start (); |
160 | 156 |
161 return true; | 157 return true; |
162 | 158 |
163 } | 159 } |
164 | 160 |
165 uint32_t | 161 uint32_t |
166 NetmapNetDevice::GetBytesInNetmapTxRing () | 162 NetmapNetDevice::GetBytesInNetmapTxRing () |
(...skipping 13 matching lines...) Expand all Loading... |
180 for (int i = 1; i < inQueue; i++) | 176 for (int i = 1; i < inQueue; i++) |
181 { | 177 { |
182 bytesInQueue += txring->slot[tail].len; | 178 bytesInQueue += txring->slot[tail].len; |
183 tail ++; | 179 tail ++; |
184 tail = tail % m_nTxRingsSlots; | 180 tail = tail % m_nTxRingsSlots; |
185 } | 181 } |
186 | 182 |
187 return bytesInQueue; | 183 return bytesInQueue; |
188 } | 184 } |
189 | 185 |
| 186 int |
| 187 NetmapNetDevice::GetSpaceInNetmapTxRing () const |
| 188 { |
| 189 NS_LOG_FUNCTION (this); |
| 190 |
| 191 struct netmap_ring *txring; |
| 192 txring = NETMAP_TXRING (m_nifp, 0); |
| 193 |
| 194 return nm_ring_space (txring); |
| 195 } |
| 196 |
190 // runs in a separate thread | 197 // runs in a separate thread |
191 void | 198 void |
192 NetmapNetDevice::WaitingSlot () | 199 NetmapNetDevice::WaitingSlot () |
193 { | 200 { |
194 NS_LOG_FUNCTION (this); | 201 NS_LOG_FUNCTION (this); |
195 | 202 |
196 struct pollfd fds; | 203 struct pollfd fds; |
197 memset (&fds, 0, sizeof(fds)); | 204 memset (&fds, 0, sizeof(fds)); |
198 | 205 |
199 fds.fd = m_fd; | 206 fds.fd = m_fd; |
(...skipping 12 matching lines...) Expand all Loading... |
212 // we sync the netmap ring periodically. | 219 // we sync the netmap ring periodically. |
213 // traffic control can write packets during the period between two syn
cs. | 220 // traffic control can write packets during the period between two syn
cs. |
214 ioctl (m_fd, NIOCTXSYNC, NULL); | 221 ioctl (m_fd, NIOCTXSYNC, NULL); |
215 | 222 |
216 // we need of a nearly periodic notification to queue limits of the tr
ansmitted bytes. | 223 // we need of a nearly periodic notification to queue limits of the tr
ansmitted bytes. |
217 // we use this thread to notify about the transmitted bytes in the sle
ep period (alternatively, we can consider a | 224 // we use this thread to notify about the transmitted bytes in the sle
ep period (alternatively, we can consider a |
218 // periodic schedule of a function). | 225 // periodic schedule of a function). |
219 | 226 |
220 // we calculate the total transmitted bytes as differences between the
total queued and the current in queue | 227 // we calculate the total transmitted bytes as differences between the
total queued and the current in queue |
221 // also, we calculate the transmitted bytes in the sleep period as dif
ference between the current total transmitted | 228 // also, we calculate the transmitted bytes in the sleep period as dif
ference between the current total transmitted |
222 // and the previous total transmitted. | 229 // and the previous total transmitted |
223 | |
224 uint32_t totalTransmittedBytes = m_totalQueuedBytes - GetBytesInNetmap
TxRing (); | 230 uint32_t totalTransmittedBytes = m_totalQueuedBytes - GetBytesInNetmap
TxRing (); |
225 uint32_t deltaBytes = totalTransmittedBytes - prevTotalTransmittedByte
s; | 231 uint32_t deltaBytes = totalTransmittedBytes - prevTotalTransmittedByte
s; |
226 NS_LOG_DEBUG (deltaBytes << " delta transmitted bytes"); | 232 NS_LOG_DEBUG (deltaBytes << " delta transmitted bytes"); |
227 | |
228 prevTotalTransmittedBytes = totalTransmittedBytes; | 233 prevTotalTransmittedBytes = totalTransmittedBytes; |
229 | |
230 if (m_queue) | 234 if (m_queue) |
231 { | 235 { |
232 m_queue->NotifyTransmittedBytes (deltaBytes); | 236 m_queue->NotifyTransmittedBytes (deltaBytes); |
233 } | 237 } |
234 | 238 |
235 // we used a period to check and notify of 200 us; it is a value close
to the interrupt coalescence | 239 // we used a period to check and notify of 200 us; it is a value close
to the interrupt coalescence |
236 // period of a real device | 240 // period of a real device |
237 m_queueStopped.TimedWait (200000); // ns | 241 m_queueStopped.TimedWait (200000); // ns |
238 } | 242 } |
239 | |
240 m_queueStopped.SetCondition (false); | 243 m_queueStopped.SetCondition (false); |
241 | 244 |
242 // we are blocked for the next slot available in the netmap ring. | 245 // we are blocked for the next slot available in the netmap ring. |
243 // for netmap in emulated mode, if you disable the generic_txqdisc you are
unblocked for | 246 // for netmap in emulated mode, if you disable the generic_txqdisc you are
unblocked for the actual next slot available. |
244 // the actual next slot available. Conversely, without disabling the gener
ic_txqdisc you | 247 // conversely, without disabling the generic_txqdisc you are unblocked whe
n in the generic_txqdisc there are no packets. |
245 // are unblocked when in the generic_txqdisc there are no packets. | 248 ioctl (m_fd, NIOCTXSYNC, NULL); |
246 | |
247 // note: we can use a not blocking poll, e.g., with a max blocking time of
1 s. | |
248 | 249 |
249 poll (&fds, 1, -1); | 250 poll (&fds, 1, -1); |
250 | 251 |
251 NS_LOG_DEBUG ("Space in the netmap ring of " << nm_ring_space (txring) <<
" packets"); | 252 NS_LOG_DEBUG ("Space in the netmap ring of " << nm_ring_space (txring) <<
" packets"); |
252 | 253 |
253 // we can now wake the queue. | 254 // we can now wake the queue. |
254 if (m_queue) | 255 if (m_queue) |
255 { | 256 { |
256 m_queue->Wake (); | 257 m_queue->Wake (); |
257 } | 258 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 // if there is no room for other packets then stop the queue. | 297 // if there is no room for other packets then stop the queue. |
297 // then, we wake up the thread to wait for the next slot available. in mea
nwhile, the main process can | 298 // then, we wake up the thread to wait for the next slot available. in mea
nwhile, the main process can |
298 // run separately. | 299 // run separately. |
299 if (nm_ring_space(txring) == 0) | 300 if (nm_ring_space(txring) == 0) |
300 { | 301 { |
301 m_queue->Stop (); | 302 m_queue->Stop (); |
302 | 303 |
303 m_queueStopped.SetCondition (true); | 304 m_queueStopped.SetCondition (true); |
304 m_queueStopped.Signal (); | 305 m_queueStopped.Signal (); |
305 } | 306 } |
306 | |
307 } | 307 } |
308 | 308 |
309 return ret; | 309 return ret; |
310 } | 310 } |
311 | 311 |
312 // runs in a separate thread | 312 // runs in a separate thread |
313 ssize_t | 313 ssize_t |
314 NetmapNetDevice::Read (uint8_t* buffer) | 314 NetmapNetDevice::Read (uint8_t* buffer) |
315 { | 315 { |
316 NS_LOG_FUNCTION (this << buffer); | 316 NS_LOG_FUNCTION (this << buffer); |
317 | 317 |
318 struct netmap_ring *rxring; | 318 struct netmap_ring *rxring; |
319 | 319 |
320 uint16_t lenght = 0; | 320 uint16_t lenght = 0; |
321 | 321 |
322 int rxRingIndex = 0; | 322 int rxRingIndex = 0; |
323 | |
324 // we have a packet in one of the receiver rings. | 323 // we have a packet in one of the receiver rings. |
325 // we check for the first non empty receiver ring of a multiqueue device. | 324 // we check for the first non empty receiver ring of a multiqueue device. |
326 while (rxRingIndex < m_nRxRings) | 325 while (rxRingIndex < m_nRxRings) |
327 { | 326 { |
328 rxring = NETMAP_RXRING (m_nifp, rxRingIndex); | 327 rxring = NETMAP_RXRING (m_nifp, rxRingIndex); |
329 | 328 |
330 if (!nm_ring_empty (rxring)) | 329 if (!nm_ring_empty (rxring)) |
331 { | 330 { |
332 | 331 |
333 uint32_t i = rxring->cur; | 332 uint32_t i = rxring->cur; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 { | 366 { |
368 m_queueInterface = ndqi; | 367 m_queueInterface = ndqi; |
369 } | 368 } |
370 } | 369 } |
371 NetDevice::NotifyNewAggregate (); | 370 NetDevice::NotifyNewAggregate (); |
372 m_queueInterface->SetTxQueuesN (1); | 371 m_queueInterface->SetTxQueuesN (1); |
373 m_queueInterface->CreateTxQueues (); | 372 m_queueInterface->CreateTxQueues (); |
374 m_queue = m_queueInterface->GetTxQueue (0); | 373 m_queue = m_queueInterface->GetTxQueue (0); |
375 } | 374 } |
376 | 375 |
| 376 Ptr<NetDeviceQueue> |
| 377 NetmapNetDevice::GetTxQueue () const |
| 378 { |
| 379 NS_LOG_FUNCTION (this); |
| 380 return m_queue; |
| 381 } |
| 382 |
377 } // namespace ns3 | 383 } // namespace ns3 |
LEFT | RIGHT |