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