1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2015 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: Stefano Avallone <stavallo@unina.it>
19 */
20
21 #include "ns3/log.h"
22 #include "ns3/abort.h"
23 #include "ns3/queue-limits.h"
24 #include "ns3/net-device-queue-interface.h"
25 #include "ns3/uinteger.h"
26 #include "ns3/pointer.h"
27 #include "ns3/traffic-control-layer.h"
28 #include "traffic-control-helper.h"
29
30 namespace ns3 {
31
32 NS_LOG_COMPONENT_DEFINE ("TrafficControlHelper");
33
QueueDiscFactory(ObjectFactory factory)34 QueueDiscFactory::QueueDiscFactory (ObjectFactory factory)
35 : m_queueDiscFactory (factory)
36 {
37 }
38
39 void
AddInternalQueue(ObjectFactory factory)40 QueueDiscFactory::AddInternalQueue (ObjectFactory factory)
41 {
42 m_internalQueuesFactory.push_back (factory);
43 }
44
45 void
AddPacketFilter(ObjectFactory factory)46 QueueDiscFactory::AddPacketFilter (ObjectFactory factory)
47 {
48 m_packetFiltersFactory.push_back (factory);
49 }
50
51 uint16_t
AddQueueDiscClass(ObjectFactory factory)52 QueueDiscFactory::AddQueueDiscClass (ObjectFactory factory)
53 {
54 m_queueDiscClassesFactory.push_back (factory);
55 return static_cast<uint16_t>(m_queueDiscClassesFactory.size () - 1);
56 }
57
58 void
SetChildQueueDisc(uint16_t classId,uint16_t handle)59 QueueDiscFactory::SetChildQueueDisc (uint16_t classId, uint16_t handle)
60 {
61 NS_ABORT_MSG_IF (classId >= m_queueDiscClassesFactory.size (),
62 "Cannot attach a queue disc to a non existing class");
63 m_classIdChildHandleMap[classId] = handle;
64 }
65
66 Ptr<QueueDisc>
CreateQueueDisc(const std::vector<Ptr<QueueDisc>> & queueDiscs)67 QueueDiscFactory::CreateQueueDisc (const std::vector<Ptr<QueueDisc> > & queueDiscs)
68 {
69 // create the queue disc
70 Ptr<QueueDisc> qd = m_queueDiscFactory.Create<QueueDisc> ();
71
72 // create and add the internal queues
73 for (std::vector<ObjectFactory>::iterator i = m_internalQueuesFactory.begin ();
74 i != m_internalQueuesFactory.end (); i++ )
75 {
76 qd->AddInternalQueue (i->Create<QueueDisc::InternalQueue> ());
77 }
78
79 // create and add the packet filters
80 for (std::vector<ObjectFactory>::iterator i = m_packetFiltersFactory.begin ();
81 i != m_packetFiltersFactory.end (); i++ )
82 {
83 qd->AddPacketFilter (i->Create<PacketFilter> ());
84 }
85
86 // create and add the queue disc classes
87 for (uint16_t i = 0; i < m_queueDiscClassesFactory.size (); i++)
88 {
89 // the class ID is given by the index i of the vector
90 NS_ABORT_MSG_IF (m_classIdChildHandleMap.find (i) == m_classIdChildHandleMap.end (),
91 "Cannot create a queue disc class with no attached queue disc");
92
93 uint16_t handle = m_classIdChildHandleMap[i];
94 NS_ABORT_MSG_IF (handle >= queueDiscs.size () || queueDiscs[handle] == 0,
95 "A queue disc with handle " << handle << " has not been created yet");
96
97 m_queueDiscClassesFactory[i].Set ("QueueDisc", PointerValue (queueDiscs[handle]));
98 qd->AddQueueDiscClass (m_queueDiscClassesFactory[i].Create<QueueDiscClass> ());
99 }
100
101 return qd;
102 }
103
104
TrafficControlHelper()105 TrafficControlHelper::TrafficControlHelper ()
106 {
107 }
108
109 TrafficControlHelper
Default(std::size_t nTxQueues)110 TrafficControlHelper::Default (std::size_t nTxQueues)
111 {
112 NS_LOG_FUNCTION (nTxQueues);
113 NS_ABORT_MSG_IF (nTxQueues == 0, "The device must have at least one queue");
114 TrafficControlHelper helper;
115
116 if (nTxQueues == 1)
117 {
118 helper.SetRootQueueDisc ("ns3::FqCoDelQueueDisc");
119 }
120 else
121 {
122 uint16_t handle = helper.SetRootQueueDisc ("ns3::MqQueueDisc");
123 ClassIdList cls = helper.AddQueueDiscClasses (handle, nTxQueues, "ns3::QueueDiscClass");
124 helper.AddChildQueueDiscs (handle, cls, "ns3::FqCoDelQueueDisc");
125 }
126 return helper;
127 }
128
129 uint16_t
DoSetRootQueueDisc(ObjectFactory factory)130 TrafficControlHelper::DoSetRootQueueDisc (ObjectFactory factory)
131 {
132 NS_ABORT_MSG_UNLESS (m_queueDiscFactory.empty (), "A root queue disc has been already added to this factory");
133
134 m_queueDiscFactory.push_back (QueueDiscFactory (factory));
135 return 0;
136 }
137
138 void
DoAddInternalQueues(uint16_t handle,uint16_t count,ObjectFactory factory)139 TrafficControlHelper::DoAddInternalQueues (uint16_t handle, uint16_t count, ObjectFactory factory)
140 {
141 NS_ABORT_MSG_IF (handle >= m_queueDiscFactory.size (), "A queue disc with handle "
142 << handle << " does not exist");
143
144 for (int i = 0; i < count; i++)
145 {
146 m_queueDiscFactory[handle].AddInternalQueue (factory);
147 }
148 }
149
150 void
DoAddPacketFilter(uint16_t handle,ObjectFactory factory)151 TrafficControlHelper::DoAddPacketFilter (uint16_t handle, ObjectFactory factory)
152 {
153 NS_ABORT_MSG_IF (handle >= m_queueDiscFactory.size (), "A queue disc with handle "
154 << handle << " does not exist");
155
156 m_queueDiscFactory[handle].AddPacketFilter (factory);
157 }
158
159 TrafficControlHelper::ClassIdList
DoAddQueueDiscClasses(uint16_t handle,uint16_t count,ObjectFactory factory)160 TrafficControlHelper::DoAddQueueDiscClasses (uint16_t handle, uint16_t count, ObjectFactory factory)
161 {
162 NS_ABORT_MSG_IF (handle >= m_queueDiscFactory.size (), "A queue disc with handle "
163 << handle << " does not exist");
164
165 ClassIdList list;
166 uint16_t classId;
167
168 for (int i = 0; i < count; i++)
169 {
170 classId = m_queueDiscFactory[handle].AddQueueDiscClass (factory);
171 list.push_back (classId);
172 }
173 return list;
174 }
175
176 uint16_t
DoAddChildQueueDisc(uint16_t handle,uint16_t classId,ObjectFactory factory)177 TrafficControlHelper::DoAddChildQueueDisc (uint16_t handle, uint16_t classId, ObjectFactory factory)
178 {
179 NS_ABORT_MSG_IF (handle >= m_queueDiscFactory.size (), "A queue disc with handle "
180 << handle << " does not exist");
181
182 uint16_t childHandle = static_cast<uint16_t>(m_queueDiscFactory.size ());
183 m_queueDiscFactory.push_back (QueueDiscFactory (factory));
184 m_queueDiscFactory[handle].SetChildQueueDisc (classId, childHandle);
185
186 return childHandle;
187 }
188
189 TrafficControlHelper::HandleList
DoAddChildQueueDiscs(uint16_t handle,const TrafficControlHelper::ClassIdList & classes,ObjectFactory factory)190 TrafficControlHelper::DoAddChildQueueDiscs (uint16_t handle, const TrafficControlHelper::ClassIdList &classes,
191 ObjectFactory factory)
192 {
193 HandleList list;
194 for (ClassIdList::const_iterator c = classes.begin (); c != classes.end (); c++)
195 {
196 uint16_t childHandle = DoAddChildQueueDisc (handle, *c, factory);
197 list.push_back (childHandle);
198 }
199 return list;
200 }
201
202 QueueDiscContainer
Install(Ptr<NetDevice> d)203 TrafficControlHelper::Install (Ptr<NetDevice> d)
204 {
205 QueueDiscContainer container;
206
207 // A TrafficControlLayer object is aggregated by the InternetStackHelper, but check
208 // anyway because a queue disc has no effect without a TrafficControlLayer object
209 Ptr<TrafficControlLayer> tc = d->GetNode ()->GetObject<TrafficControlLayer> ();
210 NS_ASSERT (tc != 0);
211
212 // Start from an empty vector of queue discs
213 m_queueDiscs.clear ();
214 m_queueDiscs.resize (m_queueDiscFactory.size ());
215
216 // Create queue discs (from leaves to root)
217 for (auto i = m_queueDiscFactory.size (); i-- > 0; )
218 {
219 m_queueDiscs[i] = m_queueDiscFactory[i].CreateQueueDisc (m_queueDiscs);
220 }
221
222 // Set the root queue disc (if any has been created) on the device
223 if (!m_queueDiscs.empty () && m_queueDiscs[0])
224 {
225 tc->SetRootQueueDiscOnDevice (d, m_queueDiscs[0]);
226 container.Add (m_queueDiscs[0]);
227 }
228
229 // Queue limits objects can only be installed if a netdevice queue interface
230 // has been aggregated to the netdevice. This is normally the case if the
231 // netdevice has been created via helpers. Abort the simulation if not.
232 if (m_queueLimitsFactory.GetTypeId ().GetUid ())
233 {
234 Ptr<NetDeviceQueueInterface> ndqi = d->GetObject<NetDeviceQueueInterface> ();
235 NS_ABORT_MSG_IF (!ndqi, "A NetDeviceQueueInterface object has not been"
236 "aggregated to the NetDevice");
237 for (uint8_t i = 0; i < ndqi->GetNTxQueues (); i++)
238 {
239 Ptr<QueueLimits> ql = m_queueLimitsFactory.Create<QueueLimits> ();
240 ndqi->GetTxQueue (i)->SetQueueLimits (ql);
241 }
242 }
243
244 return container;
245 }
246
247 QueueDiscContainer
Install(NetDeviceContainer c)248 TrafficControlHelper::Install (NetDeviceContainer c)
249 {
250 QueueDiscContainer container;
251
252 for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i)
253 {
254 container.Add (Install (*i));
255 }
256
257 return container;
258 }
259
260 void
Uninstall(Ptr<NetDevice> d)261 TrafficControlHelper::Uninstall (Ptr<NetDevice> d)
262 {
263 Ptr<TrafficControlLayer> tc = d->GetNode ()->GetObject<TrafficControlLayer> ();
264 NS_ASSERT (tc != 0);
265
266 tc->DeleteRootQueueDiscOnDevice (d);
267 // remove the queue limits objects installed on the device transmission queues
268 Ptr<NetDeviceQueueInterface> ndqi = d->GetObject<NetDeviceQueueInterface> ();
269 // if a queue disc has been installed on the device, a netdevice queue interface
270 // must have been aggregated to the device
271 NS_ASSERT (ndqi);
272 for (uint8_t i = 0; i < ndqi->GetNTxQueues (); i++)
273 {
274 ndqi->GetTxQueue (i)->SetQueueLimits (0);
275 }
276 }
277
278 void
Uninstall(NetDeviceContainer c)279 TrafficControlHelper::Uninstall (NetDeviceContainer c)
280 {
281 for (NetDeviceContainer::Iterator i = c.Begin (); i != c.End (); ++i)
282 {
283 Uninstall (*i);
284 }
285 }
286
287
288 } // namespace ns3
289