1 @c ======================================================================== |
|
2 @c Other Network Topologies |
|
3 @c ======================================================================== |
|
4 |
|
5 @node Other-network-topologies |
|
6 @chapter Other Network Topologies |
|
7 @cindex topology |
|
8 @cindex Channel |
|
9 @cindex NetDevice |
|
10 @cindex topology!bus |
|
11 @cindex topology!point-to-point |
|
12 @cindex PointToPointChannel |
|
13 @cindex PointToPointNetDevice |
|
14 |
|
15 @emph{Network topology} is the study of the arrangement of of the elements |
|
16 (in @command{ns-3} represented by the classes @code{Channel} and @code{Node}) |
|
17 of a network. Two fundamental types of physical topologies are the |
|
18 @emph{point-to-point} and @emph{bus} topologies. We have already been exposed |
|
19 to the @command{ns-3} channel specialization named @code{CsmaChannel}. This is |
|
20 a simulation of a bus network. We also provide a simulation of a |
|
21 point-to-point channel with associated net devices. As described previously, |
|
22 the associated C++ classes specialize the @command{ns-3} base classes |
|
23 @code{NetDevice} and @code{Channel} and are called @code{PointToPointNetDevice} |
|
24 and @code{PointToPointChannel} respectively. |
|
25 |
|
26 We will use combinations of these bus and point-to-point topology elements |
|
27 to show how to create several commonly seen network topologies. |
|
28 |
|
29 @section A Point-to-Point Network |
|
30 We're going to take what might be seen as a step backward and look at a simple |
|
31 point-to-point network. We will be building the simplest network you can |
|
32 imagine. A serial link (point to point) between two computers. When you |
|
33 see this point-to-point network, you can think of an RS-422 (or RS-232 for |
|
34 you old-timers) cable. This topology is shown below. |
|
35 |
|
36 @sp 1 |
|
37 @center @image{figures/pp,,,,png} |
|
38 |
|
39 @cindex CreateObject |
|
40 @cindex InternetNode |
|
41 We have provided a file for you in the @code{tutorial} |
|
42 directory called @code{tutorial-point-to-point.cc}. You should now be |
|
43 familiar enough with the system to pick out fairly easily what has been |
|
44 changed. Let's focus on the following lines: |
|
45 |
|
46 @verbatim |
|
47 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
48 Ptr<Node> n1 = CreateObject<InternetNode> (); |
|
49 |
|
50 Ptr<PointToPointChannel> link = PointToPointTopology::AddPointToPointLink ( |
|
51 n0, n1, DataRate (38400), MilliSeconds (20)); |
|
52 |
|
53 PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", |
|
54 n1, "10.1.1.2"); |
|
55 @end verbatim |
|
56 |
|
57 You can see that we created two @code{InternetNode} objects in the usual way. |
|
58 Then, instead of creating a @code{CsmaChannel} we create a |
|
59 @code{PointToPointChannel}. This point-to-point channel, which we call |
|
60 @code{link}, connects node zero (@code{n0}) and node one (@code{n1}) over a |
|
61 simulated link that runs at 38400 bits per second and has a 20 millisecond |
|
62 simulated speed-of-light delay. This call also creates appropriate net devices |
|
63 and attaches them to nodes zero and one. |
|
64 |
|
65 We then add IP addresses to the net devices we just created using the topology |
|
66 helper @code{AddIpv4Addresses}. Node zero gets the IP address 10.1.1.1 and |
|
67 node one gets the IP address 10.1.1.2 assigned. |
|
68 |
|
69 The alert tutorial user may wonder what the network number or prefix is of |
|
70 those IP addresses. The point-to-point topology assumes that you want a |
|
71 @code{/30} subnet and assigns an appropriate net mask for you. It then then |
|
72 @emph{asserts} that the network numbers of the two net devices match. So there |
|
73 is an implicit network mask created down in the topology code that looks like, |
|
74 |
|
75 @verbatim |
|
76 Ipv4Mask netmask("255.255.255.252"); |
|
77 @end verbatim |
|
78 |
|
79 The rest of the code you should recognize and understand. We are just going |
|
80 to echo one packet across the point-to-point link. You should be now be able |
|
81 to build and run this example and to locate and interpret the ASCII trace |
|
82 file. This is left as an exercise for you. |
|
83 |
|
84 The file @code{tutorial-point-to-point.cc} is reproduced here for your |
|
85 convenience: |
|
86 |
|
87 @verbatim |
|
88 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
|
89 /* |
|
90 * This program is free software; you can redistribute it and/or modify |
|
91 * it under the terms of the GNU General Public License version 2 as |
|
92 * published by the Free Software Foundation; |
|
93 * |
|
94 * This program is distributed in the hope that it will be useful, |
|
95 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
96 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
97 * GNU General Public License for more details. |
|
98 * |
|
99 * You should have received a copy of the GNU General Public License |
|
100 * along with this program; if not, write to the Free Software |
|
101 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
102 */ |
|
103 |
|
104 #include "ns3/log.h" |
|
105 #include "ns3/ptr.h" |
|
106 #include "ns3/internet-stack.h" |
|
107 #include "ns3/point-to-point-channel.h" |
|
108 #include "ns3/mac48-address.h" |
|
109 #include "ns3/point-to-point-net-device.h" |
|
110 #include "ns3/point-to-point-topology.h" |
|
111 #include "ns3/udp-echo-client.h" |
|
112 #include "ns3/udp-echo-server.h" |
|
113 #include "ns3/simulator.h" |
|
114 #include "ns3/nstime.h" |
|
115 #include "ns3/ascii-trace.h" |
|
116 #include "ns3/pcap-trace.h" |
|
117 #include "ns3/global-route-manager.h" |
|
118 |
|
119 NS_LOG_COMPONENT_DEFINE ("PointToPointSimulation"); |
|
120 |
|
121 using namespace ns3; |
|
122 |
|
123 // Network topology |
|
124 // |
|
125 // point to point |
|
126 // +--------------+ |
|
127 // | | |
|
128 // n0 n1 |
|
129 // |
|
130 int |
|
131 main (int argc, char *argv[]) |
|
132 { |
|
133 LogComponentEnable ("PointToPointSimulation", LOG_LEVEL_INFO); |
|
134 |
|
135 NS_LOG_INFO ("Point to Point Topology Simulation"); |
|
136 |
|
137 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
138 Ptr<Node> n1 = CreateObject<InternetNode> (); |
|
139 |
|
140 Ptr<PointToPointChannel> link = PointToPointTopology::AddPointToPointLink ( |
|
141 n0, n1, DataRate (38400), MilliSeconds (20)); |
|
142 |
|
143 PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", |
|
144 n1, "10.1.1.2"); |
|
145 |
|
146 uint16_t port = 7; |
|
147 |
|
148 Ptr<UdpEchoClient> client = CreateObject<UdpEchoClient> (n0, "10.1.1.2", |
|
149 port, 1, Seconds(1.), 1024); |
|
150 |
|
151 Ptr<UdpEchoServer> server = CreateObject<UdpEchoServer> (n1, port); |
|
152 |
|
153 server->Start(Seconds(1.)); |
|
154 client->Start(Seconds(2.)); |
|
155 |
|
156 server->Stop (Seconds(10.)); |
|
157 client->Stop (Seconds(10.)); |
|
158 |
|
159 AsciiTrace asciitrace ("tutorial.tr"); |
|
160 asciitrace.TraceAllQueues (); |
|
161 asciitrace.TraceAllNetDeviceRx (); |
|
162 |
|
163 Simulator::Run (); |
|
164 Simulator::Destroy (); |
|
165 } |
|
166 @end verbatim |
|
167 |
|
168 @section A Star Network |
|
169 A point-to-point network is considered a special case of a star network. As |
|
170 you might expect, the process of constructing a star network is an extension |
|
171 of the very simple process used for a point-to-point link. We have provided |
|
172 a file for you in the @code{tutorial} directory called @code{tutorial-star.cc} |
|
173 that implements a simple star network as seen below. |
|
174 |
|
175 @sp 1 |
|
176 @center @image{figures/star,,,,png} |
|
177 |
|
178 In order to create a star network, we need to be able to instantiate some |
|
179 number (greater than one) of net devices on a node. In the name of simplicity |
|
180 of use, the @code{PointToPointTopology} topology helper does not allow one to |
|
181 do this. We provided a separate topology helper class, the |
|
182 @code{PointToPointIpv4Topology} helper class that provides the slightly finer |
|
183 granularity we need to accomplish a star network. In order to use this new |
|
184 helper we have to load the definitions by including the appropriate file. |
|
185 |
|
186 @verbatim |
|
187 #include "ns3/point-to-point-ipv4-topology.h" |
|
188 @end verbatim |
|
189 |
|
190 The star that we're going to create has a node in the center (@code{n0}) with |
|
191 six nodes surrounding (@code{n1} - @code{n6}). You should be able to easily |
|
192 find and understand the code that creates these nodes. |
|
193 |
|
194 @verbatim |
|
195 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
196 Ptr<Node> n1 = CreateObject<InternetNode> (); |
|
197 Ptr<Node> n2 = CreateObject<InternetNode> (); |
|
198 Ptr<Node> n3 = CreateObject<InternetNode> (); |
|
199 Ptr<Node> n4 = CreateObject<InternetNode> (); |
|
200 Ptr<Node> n5 = CreateObject<InternetNode> (); |
|
201 Ptr<Node> n6 = CreateObject<InternetNode> (); |
|
202 @end verbatim |
|
203 |
|
204 Next, we get into the differences between the @code{PointToPointTopology} |
|
205 helper and the @code{PointToPointIpv4Topology} helper. The |
|
206 @code{PointToPointIpv4Topology} helper looks and feels a little like the |
|
207 @code{CsmaIpv4Topology} helper. Just like you created a CSMA channel |
|
208 previously, you need to create a point-to-point channel. The following |
|
209 code creates a @code{PointToPointChannel} and calls it @code{link01}. You can |
|
210 interpret this name as being the channel (or @emph{link}) from node zero to |
|
211 node one. |
|
212 |
|
213 @verbatim |
|
214 Ptr<PointToPointChannel> link01 = |
|
215 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
216 MilliSeconds (20)); |
|
217 @end verbatim |
|
218 |
|
219 You need to provide a data rate for the channel which we set at 38400 bits |
|
220 per second. You must also provide a speed-of-light delay which we set at |
|
221 20 milliseconds. |
|
222 |
|
223 Just as you added a net device to the nodes in the CSMA tutorial section, you |
|
224 do the same here but with a point-to-point net device. The following code |
|
225 illustrates how we do that: |
|
226 |
|
227 @verbatim |
|
228 uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
229 link01); |
|
230 @end verbatim |
|
231 |
|
232 We call the @code{PointToPointIpv4Topology} helper and ask it to add a net |
|
233 device to node zero (@code{n0}) and connect it to the appropriate |
|
234 point-to-point link (@code{link01}) which you will recall is the serial link |
|
235 from node zero to node one. |
|
236 |
|
237 If you look at the following code, you will see the same calls are repeated |
|
238 to create the remaining five point-to-point channels and connect them |
|
239 to net devices on node zero. |
|
240 |
|
241 The next new code is found after the ``spokes'' of the star have been created. |
|
242 It looks like the following: |
|
243 |
|
244 @verbatim |
|
245 uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); |
|
246 uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); |
|
247 uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); |
|
248 uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); |
|
249 uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); |
|
250 uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); |
|
251 @end verbatim |
|
252 |
|
253 Here we are creating the net devices on the nodes surrounding the center node. |
|
254 In the first call, we are adding a net device on node one (@code{n1}) and |
|
255 connecting that net device to the channel named @code{link01}. Remember that |
|
256 we created the channel @code{link01} as the channel connecting node zero and |
|
257 node one. We previously created a net device on node zero and attached that |
|
258 device to @code{link01}. Here we are connecting the other side of that link |
|
259 to node one. The return value from this call is the net device index of the |
|
260 created net device. |
|
261 |
|
262 The next section of code adds addresses to the net devices we just created. |
|
263 The first call adds the IP address 10.1.1.1 to the net device going from |
|
264 node zero to node one. Recall that we first created a node named @code{n0} |
|
265 and a channel called @code{link01}. We added a net device to @code{n0} and |
|
266 remembered the net device index as the @code{uint32_t nd01}. This meant |
|
267 the net device @emph{nd} on node @emph{0} that we connected to node @emph{1}. |
|
268 We call @code{AddAddress} to add an IP address (10.1.1.1) to the net device |
|
269 on node zero identified by the net device index @code{nd01}. We provide a |
|
270 net mask suitable for a point to point network. This is typically a /30 |
|
271 address but we don't force that in this API. |
|
272 |
|
273 After setting up the address on node zero, we do the same for the node on |
|
274 the other end of the ``spoke'' --- in this case node one, with its single |
|
275 net device. Note that the network number is the same on both sides of this |
|
276 network. |
|
277 |
|
278 @verbatim |
|
279 PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", |
|
280 ``255.255.255.252''); |
|
281 |
|
282 PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", |
|
283 ``255.255.255.252''); |
|
284 @end verbatim |
|
285 |
|
286 The following code repeats this pattern assining similar IP addresses to the |
|
287 remaining net devices. Note that there are no @code{Mac48Address} address |
|
288 assignments --- they are not required. |
|
289 |
|
290 The rest of the code you should recognize and understand. We are just going |
|
291 to echo one packet across the point-to-point link. You should be now be able |
|
292 to build and run this example and to locate and interpret the ASCII trace |
|
293 file. This is left as an exercise for you. |
|
294 |
|
295 The file @code{tutorial-star.cc} is reproduced here for your convenience: |
|
296 |
|
297 @verbatim |
|
298 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
|
299 /* |
|
300 * This program is free software; you can redistribute it and/or modify |
|
301 * it under the terms of the GNU General Public License version 2 as |
|
302 * published by the Free Software Foundation; |
|
303 * |
|
304 * This program is distributed in the hope that it will be useful, |
|
305 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
306 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
307 * GNU General Public License for more details. |
|
308 * |
|
309 * You should have received a copy of the GNU General Public License |
|
310 * along with this program; if not, write to the Free Software |
|
311 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
312 */ |
|
313 |
|
314 #include "ns3/log.h" |
|
315 #include "ns3/ptr.h" |
|
316 #include "ns3/internet-stack.h" |
|
317 #include "ns3/point-to-point-channel.h" |
|
318 #include "ns3/mac48-address.h" |
|
319 #include "ns3/point-to-point-net-device.h" |
|
320 #include "ns3/point-to-point-ipv4-topology.h" |
|
321 #include "ns3/udp-echo-client.h" |
|
322 #include "ns3/udp-echo-server.h" |
|
323 #include "ns3/simulator.h" |
|
324 #include "ns3/nstime.h" |
|
325 #include "ns3/ascii-trace.h" |
|
326 #include "ns3/pcap-trace.h" |
|
327 #include "ns3/global-route-manager.h" |
|
328 |
|
329 NS_LOG_COMPONENT_DEFINE ("StarSimulation"); |
|
330 |
|
331 using namespace ns3; |
|
332 |
|
333 // Network topology |
|
334 // |
|
335 // n3 n2 |
|
336 // | / |
|
337 // | / |
|
338 // n4 --- n0 --- n1 |
|
339 // / | |
|
340 // / | |
|
341 // n5 n6 |
|
342 |
|
343 int |
|
344 main (int argc, char *argv[]) |
|
345 { |
|
346 LogComponentEnable ("StarSimulation", LOG_LEVEL_INFO); |
|
347 |
|
348 NS_LOG_INFO ("Star Topology Simulation"); |
|
349 |
|
350 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
351 Ptr<Node> n1 = CreateObject<InternetNode> (); |
|
352 Ptr<Node> n2 = CreateObject<InternetNode> (); |
|
353 Ptr<Node> n3 = CreateObject<InternetNode> (); |
|
354 Ptr<Node> n4 = CreateObject<InternetNode> (); |
|
355 Ptr<Node> n5 = CreateObject<InternetNode> (); |
|
356 Ptr<Node> n6 = CreateObject<InternetNode> (); |
|
357 |
|
358 Ptr<PointToPointChannel> link01 = |
|
359 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
360 MilliSeconds (20)); |
|
361 |
|
362 uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
363 link01); |
|
364 |
|
365 Ptr<PointToPointChannel> link02 = |
|
366 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
367 MilliSeconds (20)); |
|
368 |
|
369 uint32_t nd02 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
370 link02); |
|
371 |
|
372 Ptr<PointToPointChannel> link03 = |
|
373 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
374 MilliSeconds (20)); |
|
375 |
|
376 uint32_t nd03 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
377 link03); |
|
378 |
|
379 Ptr<PointToPointChannel> link04 = |
|
380 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
381 MilliSeconds (20)); |
|
382 |
|
383 uint32_t nd04 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
384 link04); |
|
385 |
|
386 Ptr<PointToPointChannel> link05 = |
|
387 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
388 MilliSeconds (20)); |
|
389 |
|
390 uint32_t nd05 = PointToPointIpv4Topology::AddNetDevice (n0, |
|
391 link05); |
|
392 |
|
393 Ptr<PointToPointChannel> link06 = |
|
394 PointToPointIpv4Topology::CreateChannel (DataRate (38400), |
|
395 MilliSeconds (20)); |
|
396 |
|
397 uint32_t nd06 = PointToPointIpv4Topology::AddNetDevice (n0, link06); |
|
398 |
|
399 uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); |
|
400 uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); |
|
401 uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); |
|
402 uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); |
|
403 uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); |
|
404 uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); |
|
405 |
|
406 PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", |
|
407 "255.255.255.252"); |
|
408 |
|
409 PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", |
|
410 "255.255.255.252"); |
|
411 |
|
412 PointToPointIpv4Topology::AddAddress (n0, nd02, "10.1.2.1", |
|
413 "255.255.255.252"); |
|
414 |
|
415 PointToPointIpv4Topology::AddAddress (n2, nd2, "10.1.2.2", |
|
416 "255.255.255.252"); |
|
417 |
|
418 PointToPointIpv4Topology::AddAddress (n0, nd03, "10.1.3.1", |
|
419 "255.255.255.252"); |
|
420 |
|
421 PointToPointIpv4Topology::AddAddress (n3, nd3, "10.1.2.2", |
|
422 "255.255.255.252"); |
|
423 |
|
424 PointToPointIpv4Topology::AddAddress (n0, nd04, "10.1.4.1", |
|
425 "255.255.255.252"); |
|
426 |
|
427 PointToPointIpv4Topology::AddAddress (n4, nd4, "10.1.4.2", |
|
428 "255.255.255.252"); |
|
429 |
|
430 PointToPointIpv4Topology::AddAddress (n0, nd05, "10.1.5.1", |
|
431 "255.255.255.252"); |
|
432 |
|
433 PointToPointIpv4Topology::AddAddress (n5, nd5, "10.1.5.2", |
|
434 "255.255.255.252"); |
|
435 |
|
436 PointToPointIpv4Topology::AddAddress (n0, nd06, "10.1.6.1", |
|
437 "255.255.255.252"); |
|
438 |
|
439 PointToPointIpv4Topology::AddAddress (n6, nd6, "10.1.6.2", |
|
440 "255.255.255.252"); |
|
441 |
|
442 uint16_t port = 7; |
|
443 |
|
444 Ptr<UdpEchoClient> client = CreateObject<UdpEchoClient> (n0, "10.1.1.2", |
|
445 port, 1, Seconds(1.), 1024); |
|
446 |
|
447 Ptr<UdpEchoServer> server = CreateObject<UdpEchoServer> (n1, port); |
|
448 |
|
449 server->Start(Seconds(1.)); |
|
450 client->Start(Seconds(2.)); |
|
451 |
|
452 server->Stop (Seconds(10.)); |
|
453 client->Stop (Seconds(10.)); |
|
454 |
|
455 AsciiTrace asciitrace ("tutorial.tr"); |
|
456 asciitrace.TraceAllQueues (); |
|
457 asciitrace.TraceAllNetDeviceRx (); |
|
458 |
|
459 Simulator::Run (); |
|
460 Simulator::Destroy (); |
|
461 } |
|
462 @end verbatim |
|
463 |
|
464 @subsection Routing |
|
465 If you are really excited about this simulator you may have already tried to |
|
466 modify the scripts outside the tutorial. I know that one of the first things |
|
467 that would have occurred to me when I saw the star network would have been to |
|
468 start trying to add applications to echo packets from nodes other than zero. |
|
469 If you tried, for example, to start the echo client on node one instead of |
|
470 node zero, you would have found an empty trace file. The reason for this |
|
471 is that you have now created an internetwork. This means you will need to |
|
472 enable internetwork routing. |
|
473 |
|
474 We have provided a file for you in the @code{tutorial} directory called |
|
475 @code{tutorial-star-routing.cc} to show you how this is done. This extremely |
|
476 tricky and difficult change is shown below: |
|
477 |
|
478 @verbatim |
|
479 GlobalRouteManager::PopulateRoutingTables (); |
|
480 @end verbatim |
|
481 |
|
482 This one-line addition, located just before the simulation runs, tells the |
|
483 @command{ns-3} @emph{global route manager} to walk the topology you created and |
|
484 build internetwork routing tables for all of the nodes in the simulation. |
|
485 We changed the client application so that it runs on node four: |
|
486 |
|
487 @verbatim |
|
488 Ptr<UdpEchoClient> client = CreateObject<UdpEchoClient> (n4, "10.1.1.2", |
|
489 port, 1, Seconds(1.), 1024); |
|
490 @end verbatim |
|
491 |
|
492 Now if you build and run @code{tutorial-star-routing.cc} you can examine the |
|
493 @code{tutorial.tr} file and see that your UDP echo packets are now correctly |
|
494 routed through the topology. |
|
495 |
|
496 @section A Dumbbell Network |
|
497 One of the most interesting simple topologies (from a phenomenological point of |
|
498 view) is commonly called a dumbbell network. The name derives from a |
|
499 superficial similarity in form to a piece of exercise equipment. |
|
500 |
|
501 The dumbbell model is typically composed of two bus or star network elements |
|
502 connected via a point-to-point link. The point-to-point link is usually |
|
503 configured with a lower bandwidth than the bus elements to provide a |
|
504 @emph{choke point}. |
|
505 |
|
506 The following is a representation of the topology. |
|
507 |
|
508 @sp 1 |
|
509 @center @image{figures/dumbbell,,,,png} |
|
510 |
|
511 We have provided a file that constructs this dumbbell network and creates |
|
512 enough data flowing across the choke point that some packets will be dropped. |
|
513 The file is called @code{tutorial-linear-dumbbell.cc} and is located in the |
|
514 @code{tutorial} directory. We have already covered all of the code used to |
|
515 create this network, so we will just quickly go over the main sections of the |
|
516 script. |
|
517 |
|
518 The first section creates a CSMA lan that will become the left side of the |
|
519 dumbbell network. This code should be very familiar since we used the same |
|
520 process to create our first example. |
|
521 |
|
522 @verbatim |
|
523 // |
|
524 // Create the lan on the left side of the dumbbell. |
|
525 // |
|
526 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
527 Ptr<Node> n1 = CreateObject<InternetNode> (); |
|
528 Ptr<Node> n2 = CreateObject<InternetNode> (); |
|
529 Ptr<Node> n3 = CreateObject<InternetNode> (); |
|
530 |
|
531 Ptr<CsmaChannel> lan1 = |
|
532 CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); |
|
533 |
|
534 uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan1, |
|
535 "08:00:2e:00:00:00"); |
|
536 |
|
537 uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan1, |
|
538 "08:00:2e:00:00:01"); |
|
539 |
|
540 uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, |
|
541 "08:00:2e:00:00:02"); |
|
542 |
|
543 uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, |
|
544 "08:00:2e:00:00:03"); |
|
545 |
|
546 CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0"); |
|
547 CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0"); |
|
548 CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0"); |
|
549 CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0"); |
|
550 @end verbatim |
|
551 |
|
552 The code to generate the CSMA lan on the right side is similar; only the names |
|
553 have been changed. |
|
554 |
|
555 @verbatim |
|
556 // |
|
557 // Create the lan on the right side of the dumbbell. |
|
558 // |
|
559 Ptr<Node> n4 = CreateObject<InternetNode> (); |
|
560 Ptr<Node> n5 = CreateObject<InternetNode> (); |
|
561 Ptr<Node> n6 = CreateObject<InternetNode> (); |
|
562 Ptr<Node> n7 = CreateObject<InternetNode> (); |
|
563 |
|
564 Ptr<CsmaChannel> lan2 = |
|
565 CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); |
|
566 |
|
567 uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan2, |
|
568 "08:00:2e:00:00:04"); |
|
569 |
|
570 uint32_t nd5 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, lan2, |
|
571 "08:00:2e:00:00:05"); |
|
572 |
|
573 uint32_t nd6 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n6, lan2, |
|
574 "08:00:2e:00:00:06"); |
|
575 |
|
576 uint32_t nd7 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n7, lan2, |
|
577 "08:00:2e:00:00:07"); |
|
578 |
|
579 CsmaIpv4Topology::AddIpv4Address (n4, nd4, "10.1.2.1", "255.255.255.0"); |
|
580 CsmaIpv4Topology::AddIpv4Address (n5, nd5, "10.1.2.2", "255.255.255.0"); |
|
581 CsmaIpv4Topology::AddIpv4Address (n6, nd6, "10.1.2.3", "255.255.255.0"); |
|
582 CsmaIpv4Topology::AddIpv4Address (n7, nd7, "10.1.2.4", "255.255.255.0"); |
|
583 @end verbatim |
|
584 |
|
585 Next, we create a point to point link to connect the two lans. We connect |
|
586 the point-to-point channel between nodes three (on the left lan) and four |
|
587 (on the right lan). You should recognize this as substantially similar to |
|
588 the link setup from the @code{point-to-point} example. |
|
589 |
|
590 @verbatim |
|
591 // |
|
592 // Create the point-to-point link to connect the two lans. |
|
593 // |
|
594 Ptr<PointToPointChannel> link = PointToPointTopology::AddPointToPointLink ( |
|
595 n3, n4, DataRate (38400), MilliSeconds (20)); |
|
596 |
|
597 PointToPointTopology::AddIpv4Addresses (link, n3, "10.1.3.1", |
|
598 n4, "10.1.3.2"); |
|
599 @end verbatim |
|
600 |
|
601 Then we configure data flows. We create four echo clients that send UDP |
|
602 packets from the left side lan to servers created on the right side lan. |
|
603 Notice that we send 100 packets with an inter-packet gap of ten milliseconds |
|
604 instead of the single packet we have previously used. This data rate is |
|
605 sufficient to saturate the point-to-point link and will cause packets to be |
|
606 dropped when the queue on the link net devices overflows (the default maximum |
|
607 queue depth is 100 packets). Note that we stagger the start of the echo |
|
608 clients to slowly bring up the data rates. |
|
609 |
|
610 @verbatim |
|
611 // |
|
612 // Create data flows across the link: |
|
613 // n0 ==> n4 ==> n0 |
|
614 // n1 ==> n5 ==> n1 |
|
615 // n2 ==> n6 ==> n2 |
|
616 // n3 ==> n7 ==> n3 |
|
617 // |
|
618 uint16_t port = 7; |
|
619 |
|
620 Ptr<UdpEchoClient> client0 = CreateObject<UdpEchoClient> (n0, "10.1.2.1", |
|
621 port, 100, Seconds(.01), 1024); |
|
622 Ptr<UdpEchoClient> client1 = CreateObject<UdpEchoClient> (n1, "10.1.2.2", |
|
623 port, 100, Seconds(.01), 1024); |
|
624 Ptr<UdpEchoClient> client2 = CreateObject<UdpEchoClient> (n2, "10.1.2.3", |
|
625 port, 100, Seconds(.01), 1024); |
|
626 Ptr<UdpEchoClient> client3 = CreateObject<UdpEchoClient> (n3, "10.1.2.4", |
|
627 port, 100, Seconds(.01), 1024); |
|
628 |
|
629 Ptr<UdpEchoServer> server4 = CreateObject<UdpEchoServer> (n4, port); |
|
630 Ptr<UdpEchoServer> server5 = CreateObject<UdpEchoServer> (n5, port); |
|
631 Ptr<UdpEchoServer> server6 = CreateObject<UdpEchoServer> (n6, port); |
|
632 Ptr<UdpEchoServer> server7 = CreateObject<UdpEchoServer> (n7, port); |
|
633 |
|
634 server4->Start(Seconds(1.)); |
|
635 server5->Start(Seconds(1.)); |
|
636 server6->Start(Seconds(1.)); |
|
637 server7->Start(Seconds(1.)); |
|
638 |
|
639 client0->Start(Seconds(2.)); |
|
640 client1->Start(Seconds(2.1)); |
|
641 client2->Start(Seconds(2.2)); |
|
642 client3->Start(Seconds(2.3)); |
|
643 |
|
644 server4->Stop (Seconds(10.)); |
|
645 server5->Stop (Seconds(10.)); |
|
646 server6->Stop (Seconds(10.)); |
|
647 server7->Stop (Seconds(10.)); |
|
648 |
|
649 client0->Stop (Seconds(10.)); |
|
650 client1->Stop (Seconds(10.)); |
|
651 client2->Stop (Seconds(10.)); |
|
652 client3->Stop (Seconds(10.)); |
|
653 @end verbatim |
|
654 |
|
655 The remainder of the file should be quite familiar to you. Go ahead and |
|
656 run @code{tutorial-linear-dumbbell}. Now take a look at the trace |
|
657 (@code{tutorial.tr}) file. You will now see trace lines that begin with |
|
658 @code{d}. Alternatively you can search for the string ``queue-drop'' which |
|
659 is the expansion of the drop code ('d'). |
|
660 |
|
661 Interpretation of a dropped packet is straightforward. We have expanded |
|
662 the first @code{queue-drop} trace for you below. See the section on ASCII |
|
663 tracing for details. |
|
664 |
|
665 @verbatim |
|
666 00 d |
|
667 01 2.40938 |
|
668 02 nodeid=3 |
|
669 03 device=1 |
|
670 04 queue-drop |
|
671 05 pkt-uid=124 |
|
672 06 LLCSNAP(type 0x800) |
|
673 07 IPV4( |
|
674 08 tos 0x0 |
|
675 09 ttl 63 |
|
676 10 id 20 |
|
677 11 offset 0 |
|
678 12 flags [none] |
|
679 13 length: 1052) 10.1.1.3 > 10.1.2.3 |
|
680 14 UDP(length: 1032) |
|
681 15 49153 > 7 |
|
682 16 DATA (length 1024) |
|
683 @end verbatim |
|
684 |
|
685 We leave it as an exercise to examine the trace files in more detail. |
|
686 |
|
687 @c ======================================================================== |
|
688 @c Nonlinear Thinking |
|
689 @c ======================================================================== |
|
690 |
|
691 @node Nonlinear-Thinking |
|
692 @chapter Nonlinear Thinking |
|
693 |
|
694 One thing that all of our examples so far have in common is that they are |
|
695 composed of a linear collection of calls into the @command{ns-3} system. The |
|
696 programmers among the readers may have wondered why there is not as much |
|
697 as a for-loop in all of the examples. The answer is that we wanted to |
|
698 introduce you to @command{ns-3} scripting with a minimum of conceptual |
|
699 overhead. We're going to remedy that situation shortly. |
|
700 |
|
701 We have written a number of @command{ns-3} scripts in C++. Although we have |
|
702 been perfectly linear in our script implementations, just like any other C++ |
|
703 program, an @command{ns-3} script can use any features of the language you |
|
704 desire. If you will look back at the @code{tutorial-linear-dumbbell.cc} |
|
705 example, you may notice that the code to create the left and right sides of |
|
706 the dumbbell is operationally identical --- only the names change. An obvious |
|
707 improvement of this program would be to use subroutines to create the sides. |
|
708 Since we are working with C++, we should probably do this in an |
|
709 object-oriented way. Since object-oriented design is somewhat of a black art |
|
710 to some people, we'll take some time here and outline a simple methodology |
|
711 you can follow. |
|
712 |
|
713 @section Object Design 101 --- Class Ipv4BusNetwork |
|
714 If you are a master of object oriented design, feel free to skip or skim this |
|
715 section, in which we derive a simplistic but fully operational bus network |
|
716 class. |
|
717 |
|
718 So you want to create a BusNetwork class. Often the biggest hurdle in a |
|
719 design is figuring out how to get started. One of the simplest and most |
|
720 straightforward ways to do an object decomposition of a problem is to simply |
|
721 write down a description of the problem and take a look at the words |
|
722 you used. Let's take some time and do that, first at a very high level. |
|
723 |
|
724 @example |
|
725 A bus network is an implementation of a particular network topology that |
|
726 contains some number of nodes. Each of these nodes is attached to a single |
|
727 multi-drop channel. The network itself has some attributes independent of |
|
728 the topology such as a network mask, network number (prefix) and base IP |
|
729 address. |
|
730 @end example |
|
731 |
|
732 The first thing to do is to focus on the nouns and adjectives. These will |
|
733 give you a starting point for required classes and member variables. |
|
734 |
|
735 Immediately we can notice that at the highest level we are talking about the |
|
736 noun @emph{network}. This probably won't surprise you. We also have an |
|
737 adjective that modifies the noun --- @emph{bus}. This should lead us to our |
|
738 first class definition. Usually class names are constructed in the same way |
|
739 as an English language sentence would be spoken. For example, one would speak |
|
740 of a @emph{bus network} in conversation, so we would normally create a |
|
741 @code{class BusNetwork} to represent it. |
|
742 |
|
743 One thing to note is that we have used two words in our description quite |
|
744 naturally: @emph{is} and @emph{has}. When you see these words should should |
|
745 immediately think of the object-oriented concepts of @emph{ISA} (inheritance) |
|
746 and @emph{HASA} (containment) respectively. We wrote that a bus network |
|
747 @emph{is} an implementation of a particular network topology. Perhaps you |
|
748 will agree that there is a natural base class called @code{Network} that |
|
749 @emph{has} the attributes discussed above. The fact that a @code{BusNetwork} |
|
750 @emph{ISA} kind of @code{Network} suggests inheritance. Let's capture that |
|
751 thought right away remembering that we're focused on IP version four here: |
|
752 |
|
753 @verbatim |
|
754 class Ipv4Network |
|
755 { |
|
756 public: |
|
757 Ipv4Address m_network; |
|
758 Ipv4Mask m_mask; |
|
759 Ipv4Address m_baseAddress; |
|
760 }; |
|
761 |
|
762 class Ipv4BusNetwork : public Ipv4Network |
|
763 { |
|
764 }; |
|
765 @end verbatim |
|
766 |
|
767 Let's take a look at the @emph{HASA} relationships of the bus network. Clearly |
|
768 it will @emph{have} a reference to the underlying channel that implements the |
|
769 actual communications medium. We use smart pointers for those references, so |
|
770 one member variable is obvious: |
|
771 |
|
772 @verbatim |
|
773 Ptr<CsmaChannel> m_channel; |
|
774 @end verbatim |
|
775 |
|
776 A bus network will also need to contain references to all of the nodes we |
|
777 eventually want to create. If you are working in C++ and see the words contain |
|
778 or container, you should immediately think of the Standard Template Library |
|
779 or STL. A quick search of the available containers there will probably lead |
|
780 you to consider the vector class. A vector is a container that looks like an |
|
781 array. This is just what we need here. Again, we want to use smart pointers |
|
782 to reference our nodes, so the declaration of the vector would look like, |
|
783 |
|
784 @verbatim |
|
785 std::vector<Ptr<Node> > m_nodes; |
|
786 @end verbatim |
|
787 |
|
788 It will save you headaches in the future if you notice that the space between |
|
789 the two right brackets is required to differentiate this situation from a |
|
790 right-shift operator. So we have a pretty good start already after just a |
|
791 little work. Now we need to turn our attention to actions. Let's write |
|
792 another little description of the things you consider doing to a Bus network. |
|
793 |
|
794 @example |
|
795 We need to be able to create a bus network. We need to be able to delete a |
|
796 bus network. We need to be able to get a handle to a node in order to add |
|
797 applications. We need to be able to set the network, mask and base address |
|
798 somehow, specify how many nodes to create and provide the underlying channel |
|
799 its required bandwidth and delay parameters. |
|
800 @end example |
|
801 |
|
802 We now look at the @emph{verbs} in that sentence. These will give a good |
|
803 starting point for the methods of the classes. For example, the verbs |
|
804 @emph{create} and @emph{delete} should suggest @emph{constructor} and |
|
805 @emph{destructor}. The verb @emph{get} leads us to providing a method called |
|
806 @code{GetNode}. We have to provide a number of parameters so we can either |
|
807 provide @emph{setters} or we can simply pass them in as parameters to our |
|
808 constructors. Since this is a simple example, we won't bother to implement |
|
809 getters and setters (methods to get and set member variables to enhance data |
|
810 hiding). Let's use this guidance to finish up our class declarations: |
|
811 |
|
812 @verbatim |
|
813 class Ipv4Network |
|
814 { |
|
815 public: |
|
816 Ipv4Network (Ipv4Address network, Ipv4Mask mask, Ipv4Address address); |
|
817 virtual ~Ipv4Network (); |
|
818 |
|
819 Ipv4Address m_network; |
|
820 Ipv4Mask m_mask; |
|
821 Ipv4Address m_baseAddress; |
|
822 }; |
|
823 |
|
824 class Ipv4BusNetwork : public Ipv4Network |
|
825 { |
|
826 public: |
|
827 Ipv4BusNetwork ( |
|
828 Ipv4Address network, |
|
829 Ipv4Mask mask, |
|
830 Ipv4Address startAddress, |
|
831 DataRate bps, |
|
832 Time delay, |
|
833 uint32_t n); |
|
834 |
|
835 virtual ~Ipv4BusNetwork (); |
|
836 |
|
837 Ptr<Node> GetNode (uint32_t n); |
|
838 |
|
839 private: |
|
840 std::vector<Ptr<Node> > m_nodes; |
|
841 Ptr<CsmaChannel> m_channel; |
|
842 }; |
|
843 @end verbatim |
|
844 |
|
845 That's it. We have actually already walked through almost all of the code |
|
846 required to construct a bus network in our @code{tutorial-csma-echo.cc} |
|
847 example, so let's just jump forward and take a look at an implementation |
|
848 of this thing. We provide an implementation for you in the files |
|
849 @code{ipv4-bus-network.h} and @code{ipv4-bus-network.cc} located in the |
|
850 @code{tutorial} directory. We also provide an example that uses the new |
|
851 class in the file @code{tutorial-bus-network.cc}. |
|
852 |
|
853 The interesting method from our current perspective is the Ipv4BusNetwork |
|
854 constructor, shown below: |
|
855 |
|
856 @verbatim |
|
857 Ipv4BusNetwork::Ipv4BusNetwork ( |
|
858 Ipv4Address network, |
|
859 Ipv4Mask mask, |
|
860 Ipv4Address baseAddress, |
|
861 DataRate bps, |
|
862 Time delay, |
|
863 uint32_t n) |
|
864 : |
|
865 Ipv4Network (network, mask, baseAddress) |
|
866 { |
|
867 Ipv4AddressGenerator::SeedNetwork (mask, network); |
|
868 Ipv4AddressGenerator::SeedAddress (mask, baseAddress); |
|
869 |
|
870 m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); |
|
871 |
|
872 for (uint32_t i = 0; i < n; ++i) |
|
873 { |
|
874 Ptr<Node> node = CreateObject<InternetNode> (); |
|
875 uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, |
|
876 Mac48Address::Allocate ()); |
|
877 Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, |
|
878 network); |
|
879 CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); |
|
880 m_nodes.push_back (node); |
|
881 } |
|
882 } |
|
883 @end verbatim |
|
884 |
|
885 Notice that we do the simple and straightforward thing and pass all of our |
|
886 parameters to the constructor. For those unfamiliar with C++, the line after |
|
887 the colon and before the opening brace (shown below), |
|
888 |
|
889 @verbatim |
|
890 : |
|
891 Ipv4Network (network, mask, baseAddress) |
|
892 { |
|
893 @end verbatim |
|
894 |
|
895 Passes the appropriate parameters to the constructor of the base class |
|
896 @code{Ipv4Network}. There are two new calls that we haven't seen immediately |
|
897 after this initialization. They are: |
|
898 |
|
899 @verbatim |
|
900 Ipv4AddressGenerator::SeedNetwork (mask, network); |
|
901 Ipv4AddressGenerator::SeedAddress (mask, baseAddress); |
|
902 @end verbatim |
|
903 |
|
904 We provide an IP address generator class to allow us to programmatically |
|
905 allocate IP addresses. The first call to @code{SeedNetwork} gives the |
|
906 address generator a starting network number to use when generating addresses. |
|
907 The second call to @code{SeedAddress} gives the address generator a starting |
|
908 IP address to use. There is a starting network and starting address for each |
|
909 of the 32 possible network masks. Later in the for loop, you will see a |
|
910 call to @code{AllocateAddress} in which the IP address for each node created |
|
911 in the loop is actually generated. |
|
912 |
|
913 The only unfamiliar call in the reset of the constructor will be: |
|
914 |
|
915 @verbatim |
|
916 m_nodes.push_back (node); |
|
917 @end verbatim |
|
918 |
|
919 This is the STL code to add the newly created node to the vector of nodes |
|
920 attached to the bus. |
|
921 |
|
922 For your convenience, we reproduce the entire bus network implementation below: |
|
923 |
|
924 @verbatim |
|
925 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
|
926 /* |
|
927 * Copyright (c) 2007 University of Washington |
|
928 * |
|
929 * This program is free software; you can redistribute it and/or modify |
|
930 * it under the terms of the GNU General Public License version 2 as |
|
931 * published by the Free Software Foundation; |
|
932 * |
|
933 * This program is distributed in the hope that it will be useful, |
|
934 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
935 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
936 * GNU General Public License for more details. |
|
937 * |
|
938 * You should have received a copy of the GNU General Public License |
|
939 * along with this program; if not, write to the Free Software |
|
940 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
941 */ |
|
942 |
|
943 #include "ns3/mac48-address.h" |
|
944 #include "ns3/csma-net-device.h" |
|
945 #include "ns3/csma-topology.h" |
|
946 #include "ns3/csma-ipv4-topology.h" |
|
947 |
|
948 #include "ipv4-bus-network.h" |
|
949 #include "ipv4-address-generator.h" |
|
950 |
|
951 namespace ns3 { |
|
952 |
|
953 Ipv4Network::Ipv4Network ( |
|
954 Ipv4Address network, |
|
955 Ipv4Mask mask, |
|
956 Ipv4Address address) |
|
957 : |
|
958 m_network (network), m_mask (mask), m_baseAddress (address) |
|
959 { |
|
960 } |
|
961 |
|
962 Ipv4Network::~Ipv4Network () |
|
963 { |
|
964 } |
|
965 |
|
966 Ipv4BusNetwork::Ipv4BusNetwork ( |
|
967 Ipv4Address network, |
|
968 Ipv4Mask mask, |
|
969 Ipv4Address baseAddress, |
|
970 DataRate bps, |
|
971 Time delay, |
|
972 uint32_t n) |
|
973 : |
|
974 Ipv4Network (network, mask, baseAddress) |
|
975 { |
|
976 Ipv4AddressGenerator::SeedNetwork (mask, network); |
|
977 Ipv4AddressGenerator::SeedAddress (mask, baseAddress); |
|
978 |
|
979 m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); |
|
980 |
|
981 for (uint32_t i = 0; i < n; ++i) |
|
982 { |
|
983 Ptr<Node> node = CreateObject<InternetNode> (); |
|
984 uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, |
|
985 Mac48Address::Allocate ()); |
|
986 Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, |
|
987 network); |
|
988 CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); |
|
989 m_nodes.push_back (node); |
|
990 } |
|
991 } |
|
992 |
|
993 Ipv4BusNetwork::~Ipv4BusNetwork () |
|
994 { |
|
995 } |
|
996 |
|
997 Ptr<Node> |
|
998 Ipv4BusNetwork::GetNode (uint32_t n) |
|
999 { |
|
1000 return m_nodes[n]; |
|
1001 } |
|
1002 |
|
1003 }; // namespace ns3 |
|
1004 @end verbatim |
|
1005 |
|
1006 @section Using Ipv4BusNetwork |
|
1007 If all you ever want to do with a bus network can be captured in a topology |
|
1008 with four nodes on the bus, the preceeding section may seem like a colossal |
|
1009 waste of time. This is probably not the case, though. Now that we have a |
|
1010 relatively abstract bus class, we can create bus networks with 4, 40 or 4000 |
|
1011 nodes with no additional effort. |
|
1012 |
|
1013 A use of the bus network class is shown in the file |
|
1014 @code{bus-network.cc} located in the @code{tutorial} directory. The |
|
1015 interesting code is, |
|
1016 |
|
1017 @verbatim |
|
1018 Ipv4BusNetwork bus ("10.1.0.0", "255.255.0.0", "0.0.0.3", |
|
1019 DataRate(10000000), MilliSeconds(20), 10); |
|
1020 @end verbatim |
|
1021 |
|
1022 Here we create a bus network with the network number ``10.1.0.0'' and the |
|
1023 network mask ``255.255.0.0'' that completes the IP network definition. You |
|
1024 can consider these together as ``10.1.0.0/16'' if you prefer. The next |
|
1025 parameter tells the bus to start numbering IP addresses of contained nodes at |
|
1026 ``10.1.0.3'' (remember the network number will be combined). We provided a |
|
1027 data rate of 10 megabits per second and a latency of 20 milliseconds. |
|
1028 Finally, we ask the @code{Ipv4BusNetwork} object to create ten nodes in the |
|
1029 network. |
|
1030 |
|
1031 If you are feeling brave, go ahead and change the number of nodes to be 100, |
|
1032 1000, 10,000 or more to generate larger and larger networks. Before you go |
|
1033 too far, remember that a trace file will be generated when you run your |
|
1034 resulting program and ee asked the trace facility to trace all net device |
|
1035 receive events. This will include the reception of the broadcast ARP request |
|
1036 by all of the nodes in the simulation, so this can add up quickly. |
|
1037 |
|
1038 @c ======================================================================== |
|
1039 @c Summary |
|
1040 @c ======================================================================== |
|
1041 |
|
1042 @node Summary |
|
1043 @chapter Summary |
|
1044 |
|
1045 This concludes the first part of the tutorial. We have focused on |
|
1046 using the @command{ns-3} system to construct various network topologies and to |
|
1047 simulate sendng data across the networks; and we've shown you how to use the |
|
1048 trace facility to get access to simulation results. |
|
1049 |
|
1050 We now encourage you to play with the system a little. Experiment with what |
|
1051 we have provided. Build a hierarchical network simulation. Perhaps exercise |
|
1052 your object design skills and create a new @code{Ipv4DumbbellNetwork} class |
|
1053 to create dumbbell networks using the Ipv4BusNetwork class we just created. |
|
1054 Hint: An Ipv4DumbbellNetwork @emph{has} two @code{Ipv4BusNetwork} objects; |
|
1055 a left side and a right side. |
|
1056 |
|
1057 In the next part of the tutorial we are going to drop down a level and begin |
|
1058 examining the lower levels of the system in more detail. We are going to |
|
1059 explain how to change the behavior of the system and eventually how to write |
|
1060 new models and applications. This is a good time to make sure that you |
|
1061 thoroughly understand what we've gone over so far. |
|
1062 |
|
1063 @c ======================================================================== |
|
1064 @c Object Model |
|
1065 @c ======================================================================== |
|
1066 |
|
1067 @node Object-Model |
|
1068 @chapter Object Model |
|
1069 |
|
1070 @cindex Object Model |
|
1071 There are two distinctly different meanings associated with the term Object |
|
1072 Model. The first speaks to the implementation of an object system --- a system |
|
1073 view; and the second speaks to the application programming interface (classes |
|
1074 or objects) one uses to access some service or system --- an application view. |
|
1075 |
|
1076 As an example of the system view sense of the term, the C++ language has an |
|
1077 associated object model that describes how objects are laid out in memory, |
|
1078 how virtual functions work, how inheritance is implemented, constructor and |
|
1079 destructor execution ordering, template instantiation, etc. |
|
1080 |
|
1081 @cindex API |
|
1082 @cindex DOM |
|
1083 @cindex Document Object Model |
|
1084 In the case of the application view, the Document Object Model is a good |
|
1085 example. In the words of W3C, the Document Object Model (DOM) is an |
|
1086 application programming interface (API) for HTML and XML documents. It defines |
|
1087 the logical structure of documents and the way a document is accessed and |
|
1088 manipulated. |
|
1089 |
|
1090 @cindex API |
|
1091 @cindex COM |
|
1092 @cindex Component Object Model |
|
1093 The Component Object Model (COM) from Microsoft actually spans both meanings |
|
1094 of the term and extends further into policy statements. From a system |
|
1095 perspective, COM specifies an interface definition language, the layout of |
|
1096 objects virtual function tables, the formats of Globally Unique Identifiers |
|
1097 and also specifies lifetime management mechanisms for objects via reference |
|
1098 counting. From the point of view of the API, COM specifies a number of |
|
1099 Interfaces as well as functions such as CoCreateInstance and various |
|
1100 threading models. The COM specification extends to policy by disallowing |
|
1101 implementation inheritance. |
|
1102 |
|
1103 @cindex Feynman |
|
1104 The @command{ns-3} object model takes the C++ language (system level) object |
|
1105 model as its basis, and extends that model by providing an API for software |
|
1106 componentry. You may find terms like Component, Interface and QueryInterface |
|
1107 in the following discussion, or used informally in other discussions about |
|
1108 @command{ns-3}. It is important to understand from the outset that this is |
|
1109 the @command{ns-3} object model, and not any other object model. |
|
1110 Richard Feynman (an American physicist) once described the behavior of matter |
|
1111 and light on a very small scale in the following way, |
|
1112 |
|
1113 @quotation |
|
1114 ``They do not behave like waves, they do not behave like particles, they do |
|
1115 not behave like clouds, or billiard balls, or weights on springs, or like |
|
1116 anything that you have ever seen.'' |
|
1117 @end quotation |
|
1118 |
|
1119 Just as students of quantum mechanics must rid themselves of preconceptions |
|
1120 regarding the behavior of matter at small scales, you should rid yourself of |
|
1121 any preconceptions you may have about components, interfaces and APIs for |
|
1122 software componentry before continuing. To paraphrase Feynman, @command{ns-3} |
|
1123 components do not behave like COM Components, or Java Beans, or CORBA |
|
1124 objects, or clouds or weights on springs, or like anything that you have |
|
1125 ever seen --- they are @command{ns-3} components. |
|
1126 |
|
1127 @section The C++ Object Model is the Root of all Things |
|
1128 @command{Ns-3} is primarily a C++ system. The system is written in C++ and |
|
1129 one can use standard C++ mechanisms for creating and using ns-3 objects. We |
|
1130 do not change this at all, nor do we make any pronouncements about the |
|
1131 superiority of one mechanism or another. What we will do is provide |
|
1132 convenience functions that we think will make creating and managing simulation |
|
1133 objects easier. |
|
1134 |
|
1135 @cindex CreateObject |
|
1136 Previously, you have seen objects created using the template function |
|
1137 @code{CreateObject} as in the following example: |
|
1138 |
|
1139 @verbatim |
|
1140 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
1141 @end verbatim |
|
1142 |
|
1143 This line of code, while it may be unfamiliar to some, is pure C++. If you |
|
1144 were to look in the header file ptr.h, you would find the following definition |
|
1145 of the @code{CreateObject} template. |
|
1146 |
|
1147 @verbatim |
|
1148 template <typename T> |
|
1149 Ptr<T> CreateObject (void) |
|
1150 { |
|
1151 Ptr<T> p = Ptr<T> (new T (), false); |
|
1152 p->SetTypeId (T::GetTypeId ()); |
|
1153 return p; |
|
1154 } |
|
1155 @end verbatim |
|
1156 |
|
1157 @cindex template |
|
1158 As you can see, this template creates objects of type @code{T} using the |
|
1159 operator @code{new}. Its a little harder to find the corresponding delete --- |
|
1160 it's in the file @code{object.cc} inside the method @code{Object::MaybeDelete}, |
|
1161 but when that @code{Ptr} which you see above goes out of scope it will call |
|
1162 @code{Unref} and ultimately the C++ @code{delete} operator will be called. |
|
1163 |
|
1164 @cindex new |
|
1165 @cindex delete |
|
1166 The ns-3 system uses the C++ @code{new} and @code{delete} operators, so there |
|
1167 is really no reason that you as a user of the ns-3 system are forbidden from |
|
1168 using these or any other C++ mechanism. If you so desire, you can take on |
|
1169 the responsibility for managing object lifetime (i.e., do not use the |
|
1170 @code{Ptr} smart pointer), work directly with the @code{new} and @code{delete} |
|
1171 operators and call methods like any C++ object as in the following example: |
|
1172 |
|
1173 @verbatim |
|
1174 MyClass *obj = new MyClass (); |
|
1175 obj->Method(); |
|
1176 delete obj; |
|
1177 @end verbatim |
|
1178 |
|
1179 @cindex model |
|
1180 You, as a competent model author, are encouraged to use whatever methods you |
|
1181 think are appropriate in your private code. Remember, however, that the |
|
1182 public ns-3 APIs do use smart pointers to pass objects around in an effort to |
|
1183 reduce the burden of object lifetime management. If you do intend to export |
|
1184 an API publicly, you should use the same object lifetime management approaches |
|
1185 as those found in the ns-3 public API if only for consistency. |
|
1186 |
|
1187 These APIs are there for convenience and consistency, but do not change the |
|
1188 fact that in ns-3 all of the objects are really just C++ objects, ultimately |
|
1189 created using the C++ new operator with C++ constructor semantics and are |
|
1190 ultimately deleted using the C++ delete operator, following C++ destructor |
|
1191 semantics. Although it may sometimes appear so, there is really no system- |
|
1192 level magic going on in ns-3. Ns-3 components and interfaces are C++ objects |
|
1193 just like any other object and our object model is simply a collection of APIs |
|
1194 built on the normal C++ object model. |
|
1195 |
|
1196 @cindex Interface |
|
1197 @cindex Abstract Data Type |
|
1198 @cindex ADT |
|
1199 @cindex Abstract Base Class |
|
1200 @cindex ABC |
|
1201 @section Interface |
|
1202 There are many different ideas floating around of what exactly the term |
|
1203 @emph{interface} means. Originally an interface just meant a communication |
|
1204 boundary between two entities. As the concepts of object oriented programming |
|
1205 (OOP) were surfacing in the 1980s, the term interface was applied to the |
|
1206 collection of access methods for the modular entities that were being defined. |
|
1207 |
|
1208 @cindex OOP |
|
1209 @cindex Object Oriented Programming |
|
1210 Two distinct approaches developed regarding specifying access mechanisms for |
|
1211 objects. The OOP purists were very concerned about object reuse and were led |
|
1212 to Abstract Data Types (ADT). These were eventually implemented in the case |
|
1213 of C++, as pure virtual methods in Abstract Base Classes (ABC). Another group |
|
1214 of folks was more interested in simply specifying object access methods in one |
|
1215 place and using inheritance as the primary reuse mechanism. |
|
1216 |
|
1217 Bjarne Stroustroup, the creator of C++, embraced both approaches. He makes |
|
1218 the following interesting observation: |
|
1219 |
|
1220 @quotation |
|
1221 ``Many classes [@dots{}] are useful both as themselves and also as bases for |
|
1222 derived classes. [@dots{}] Some classes, such as class @strong{Shape}, |
|
1223 represent abstract concepts for which objects cannot exist.'' |
|
1224 @end quotation |
|
1225 |
|
1226 @cindex PIMPL |
|
1227 @command{Ns-3} does not pick and enforce a particular approach. In |
|
1228 @command{ns-3} an interface is determined completely by a class declaration |
|
1229 just as any C++ object interface is declared. If you think of an object as |
|
1230 an abstract concept that should be implemented by derived classes, by all |
|
1231 means, use the Abstract Base Class approach to interface declaration. If you |
|
1232 think that an object should be completely concrete and you foresee no need |
|
1233 to ever modify its behavior, feel free to avoid declaring any methods virtual. |
|
1234 If you think that an object could be useful as a base class, feel free to |
|
1235 declare its methods virtual. If you like to use the PIMPL idiom, again, feel |
|
1236 free. If you want to use any combination of these techniques, feel free. |
|
1237 We make no restrictions. |
|
1238 |
|
1239 @cindex API |
|
1240 When we speak of an ns-3 interface, we do not worry about interface definition |
|
1241 languages, or pure virtual classes, or registries we just think about C++ |
|
1242 object declarations and their associated methods. We tend to think of |
|
1243 interfaces to objects as simply a private or public API. When we instantiate |
|
1244 an @command{ns-3} interface, it is the C++ object model that dictates how that |
|
1245 object is brought into existence. When a method is called on an @command{ns-3} |
|
1246 Interface, it is the C++ object model that dictates how that method is |
|
1247 dispatched. |
|
1248 |
|
1249 We do, however, provide a base class that endows vanilla C++ objects with |
|
1250 capabilities that can be seen as conceptually similar to those provided by |
|
1251 Microsoft Component Model @emph{Interfaces}. |
|
1252 |
|
1253 @section The Ns-3 Object and GetObject |
|
1254 @cindex Component Object Model |
|
1255 One thing that Microsoft arguably got right in the Component Object Model was |
|
1256 the idea of Interface aggregation and discovery via QueryInterface. We have |
|
1257 embraced these ideas in @command{ns-3}. This was done primarily to address a |
|
1258 common problem in large software systems. A good example of this problem |
|
1259 happens in the @command{ns-3} Node class. |
|
1260 |
|
1261 @cindex OOP |
|
1262 @cindex weak base class |
|
1263 @cindex base class bloat |
|
1264 @cindex Swiss Army Knife class |
|
1265 @cindex Node |
|
1266 If one were to take the standard OOP view of specializing a @code{Node} into |
|
1267 an internet host, for example, one would typically inherit from the @code{Node} |
|
1268 base class and include functionality to implement such things as internet |
|
1269 routing and a TCP/IP protocol stack. Other types of @code{Node}s might |
|
1270 inherit from the node class and specialize in different ways, or further |
|
1271 specialize the internet host class, treating it as a base class. This can |
|
1272 result in a complicated inheritance tree in which some specializations are |
|
1273 simply not available to other branches of the tree which can make reuse |
|
1274 difficult or impossible. This is known as the @emph{weak base class} problem |
|
1275 and creates pressure to drive functionality up the inheritance tree into the |
|
1276 base classes. This, in turn, results in @emph{base class bloat} and the |
|
1277 resulting @emph{swiss army knife} base classes which end up trying to do |
|
1278 everything in one place. |
|
1279 |
|
1280 Even if one successfully avoided these swiss army knife base classes, one |
|
1281 would also want to be able to treat new specializations of @code{Node} |
|
1282 generically in the system. This means one would pass references to the base |
|
1283 class (@code{Node}) across public APIs. This introduces @emph{upcasts} prior |
|
1284 to passing across public APIs and corresponding @emph{downcasts} on the other |
|
1285 side in order to gain access to required specialized functions. As the |
|
1286 inheritance tree becomes more complicated, this approach can cause another |
|
1287 related problem known as the @emph{fragile base class} problem. This happens |
|
1288 when changes to the base class cause unexpected problems in the various and |
|
1289 sundry subclasses. |
|
1290 |
|
1291 These effects seem always to result in a positive feedback loop driving |
|
1292 everything into the base class and destroying much of the encapsulation which |
|
1293 is a hallmark of the object oriented approach. |
|
1294 |
|
1295 @subsection Interface Composition |
|
1296 @cindex Node |
|
1297 There is a completely different way to address the Node specialization |
|
1298 problem. Instead of approaching the situation using inheritance, one can |
|
1299 look at the problem as one of composition. We can look at the @code{Node} |
|
1300 class as a container of sorts that holds other objects. In this case, the |
|
1301 objects would be instances of the classes implementing the internetwork |
|
1302 routing code, or the TCP/IP protocol stack described above. This approach |
|
1303 preserves the encapsulation and solves the weak base class, base class bloat |
|
1304 and fragile base class problems; but the question of method dispatch |
|
1305 immediately comes to mind. |
|
1306 |
|
1307 @cindex delegation |
|
1308 In many systems, @emph{delegation} is used. The base class, @code{Node}, |
|
1309 in this approach would provide methods that simply forward to the objects |
|
1310 implementing the desired functionality. This situation clearly does not |
|
1311 address the base class bloat problem since dispatch methods must be added |
|
1312 to the base class. The situation is mitigated somewhat by pushing the |
|
1313 implementation of the dispatch methods to contained objects, but the |
|
1314 fundamental problems are still present. What is really needed is a way |
|
1315 to compose objects but at the same time keep the interfaces to those |
|
1316 objects separated. |
|
1317 |
|
1318 @cindex aggregation |
|
1319 Composition, usually called @emph{aggregation}, along with runtime Interface |
|
1320 discovery is the solution that Microsoft originally championed and that |
|
1321 @command{ns-3} has adopted --- albeit with many simplifications and a few name |
|
1322 changes. |
|
1323 |
|
1324 @subsection Objects and Interfaces |
|
1325 @cindex COM |
|
1326 @cindex QueryInterface |
|
1327 Now that we have mentioned Microsoft COM and are almost obligated to mention |
|
1328 the terms Interface and QueryInterface. For those familiar with COM, loosely |
|
1329 speaking, QueryInterface is to COM as GetObject is to @command{ns-3}. |
|
1330 The analogy, while good conceptually, is superficial from an implementation |
|
1331 point of view. |
|
1332 |
|
1333 @cindex Node |
|
1334 Addressing our current example of a @code{Node}, generically speaking, each |
|
1335 node needs to aggregate an object that will implement internetwork routing |
|
1336 and TCP/IP. The system will need to provide a mechanism for locating the |
|
1337 aggregated objects and allow a client to discover them. |
|
1338 |
|
1339 @cindex aggregation |
|
1340 @cindex Object |
|
1341 These aggregated objects have interfaces in the C++ sense of collections of |
|
1342 method signatures. In @command{ns-3}, when objects are capable of |
|
1343 participating in this aggregation process, they are called @command{ns-3} |
|
1344 @code{Objects}. @code{Objects} receive the functionality required for this |
|
1345 participation by inheriting from the @command{ns-3} base class @code{Object}. |
|
1346 |
|
1347 Note well that when we write the word @code{Object} (note the uppercase 'O' in |
|
1348 the spelling and the change of font) we are referring to a kind of C++ object |
|
1349 that has inherited the capability of participating in an aggregation. The |
|
1350 @command{ns-3}-specific word @code{Object} can have a significantly different |
|
1351 meaning than that of a vanilla C++ object outside the aforementioned |
|
1352 inheritance tree, and the difference is only readily apparent via context. |
|
1353 In this tutorial we will always write the @command{ns-3}-specific kind of |
|
1354 @code{Object} in a fixed font; and will write the vanilla C++ term object in |
|
1355 normal font. In conversation, you will need to be careful to understand which |
|
1356 term is meant: object or @code{Object}. |
|
1357 |
|
1358 Once an object has inherited from class @code{Object} it has the ability to |
|
1359 @emph{host} an aggregation. This means that it has the ability to add other |
|
1360 @code{Objects} to its aggregation via the method @code{AggregateObject}. It |
|
1361 also means that it can provide a service to @emph{discover} other objects in |
|
1362 its aggregation via the method @code{GetObject}. |
|
1363 |
|
1364 @cindex base class |
|
1365 Technically, the class named @code{Object} is simply a base class that you |
|
1366 will inherit from if you want your @code{Objects} to support aggregation and |
|
1367 discovery. Many systems have a base class that implements common |
|
1368 functionality and these base classes are typically called something like |
|
1369 Object. The @command{ns-3} version of this base class relates primarily to |
|
1370 @code{Object} aggregation and discovery, although it does also provide methods |
|
1371 to help with intrusive reference counting and tracing as well. |
|
1372 |
|
1373 When a C++ object inherits from the ns-3 Object base class, it is conceptually |
|
1374 promoted to an ns-3 @code{Object} irrespective of how the object was declared |
|
1375 (e.g., as an abstract base class, concrete class, with virtual methods, etc.). |
|
1376 In ns-3, you should associate inheritance from the class named @code{Object} |
|
1377 with promotion of an object to the status of some locatable @code{Object} |
|
1378 rather than with the form of the class declaration. |
|
1379 |
|
1380 @cindex COM |
|
1381 @cindex CORBA |
|
1382 @cindex ORBit |
|
1383 For those of you unfamiliar with Microsoft COM, CORBA or ORBit, this might |
|
1384 sound obvious. For those of with such a background, the point we are making |
|
1385 is that there is no such thing in @command{ns-3} as a separate Interface |
|
1386 declaration, no such thing as an Interface Definition Language, no such thing |
|
1387 as a UUID or GUID, etc. In @command{ns-3} we just work with C++ objects that |
|
1388 may be given some very useful abilities by inheriting from the @command{ns-3} |
|
1389 base class @code{Object}. @command{Ns-3} @code{Objects} are not required to |
|
1390 inherit from classes composed of pure virtual methods in order to define an |
|
1391 Interface. It's all really just ``plain old C++.'' |
|
1392 |
|
1393 To summarize, when you instantiate an object that inherits from the |
|
1394 @code{Object} class, you will have a C++ object that has four important |
|
1395 properties: |
|
1396 |
|
1397 @cindex AggregateObject |
|
1398 @cindex GetObject |
|
1399 @itemize @bullet |
|
1400 @item The @code{Object} has a C++ interface defined by the collection of method signatures in its inheritance tree; |
|
1401 @item The @code{Object} has some way to identify its underlying class uniquely; |
|
1402 @item The @code{Object} is a kind of container that has the ability to aggregate other @code{Objects} using the method @code{AggregateObject}; |
|
1403 @item The @code{Object} exports a method called @code{GetObject} that allows for discovery of other aggregated @code{Objects}. |
|
1404 @end itemize |
|
1405 |
|
1406 @cindex base class |
|
1407 @cindex Object |
|
1408 It is crucially important to understand what we have described here |
|
1409 (especially for those coming from other systems that provide similar |
|
1410 functionality). A given C++ class has an object access interface that is |
|
1411 essentially the collection of method signatures specified in its inheritance |
|
1412 tree. This is a C++ object model thing. Ns-3 provides a base class from |
|
1413 which the class in question can inherit and be promoted to the status of |
|
1414 @code{Object}. Once a class becomes an @code{Object} it has inherited the |
|
1415 ability to aggregate and search for other @code{Objects} that are added to |
|
1416 its aggregation. |
|
1417 |
|
1418 That last detail is important. In @command{ns-3} @code{Objects} are both |
|
1419 containers and specifications for a object method access. We have previously |
|
1420 mentioned that the @code{Node} class acts as a container. In fact, the |
|
1421 @code{Node} class inherits from @code{Object} and is itself an @command{ns-3} |
|
1422 @code{Object}. So, when the @code{Node} object is created it is really an |
|
1423 aggregation of one @code{Object} and you can call @code{AggregateObject} or |
|
1424 @code{GetObject} on the resulting @code{Node} object. Along with being an |
|
1425 aggregation, the @code{Node} class also describes a public interface. This |
|
1426 public interface (API) is declared just as any C++ object is declared, via its |
|
1427 class methods as specified in the inheritance tree. For those steeped in |
|
1428 COM or CORBA, this is where the concept of Interface works in @command{ns-3}. |
|
1429 Remember that it is generally true that @code{Objects} are both aggregations |
|
1430 and APIs. |
|
1431 |
|
1432 @subsection Aggregations |
|
1433 @cindex aggregate |
|
1434 The figure below shows how an @code{Object} could be illustrated in detail. |
|
1435 The line with the circle at the top of the diagram represents the appearance |
|
1436 of the @code{Object} API to the external world. This circle and line are |
|
1437 together called a lollipop because of its superficial similarity to a kind of |
|
1438 childs candy. |
|
1439 |
|
1440 @sp 1 |
|
1441 @center @image{oneobj,,,,png} |
|
1442 |
|
1443 @cindex API |
|
1444 You could declare this API and associated @code{Object} quite simply using a |
|
1445 non-virtual class as follows, |
|
1446 |
|
1447 @verbatim |
|
1448 class A : public Object { |
|
1449 public: |
|
1450 static ns3::TypeId GetTypeId (void) |
|
1451 { |
|
1452 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1453 .SetParent (Object::GetTypeId ()) |
|
1454 .AddConstructor<A> (); |
|
1455 return tid; |
|
1456 } |
|
1457 |
|
1458 A () |
|
1459 { |
|
1460 } |
|
1461 |
|
1462 void MethodA (void); |
|
1463 }; |
|
1464 @end verbatim |
|
1465 |
|
1466 The methods that are then available via the API labeled @code{A} in the |
|
1467 figure above are the methods inherited from the @code{Object} base class |
|
1468 (@code{GetObject}, @code{Ref}, and @code{Unref}) and those from class |
|
1469 @code{A} (@code{MethodA}). |
|
1470 |
|
1471 Note that you must declare a @code{TypeId} in your @code{Object} class, and |
|
1472 it must be declared static to make it class-wide in scope. This @code{TypeId} |
|
1473 is a unifying element in the @command{ns-3} object model and uniquely |
|
1474 identifies @code{Objects} at run-time as being instantiated from a particular |
|
1475 class. We'll have much more to say about @code{TypiId} shortly. |
|
1476 |
|
1477 You can think of the arc and arrow device coming off each side of the |
|
1478 illustrated @code{Objects} as part of a connector. These connectors allow |
|
1479 @code{GetObject} to search aggregations for an instance of a class type. |
|
1480 The figure below shows an aggregation of three @code{Objects}: A, B and C. |
|
1481 The class declarations for classes @code{B} and @code{C} are substantially |
|
1482 similar to that of class @code{A}. |
|
1483 |
|
1484 @sp 1 |
|
1485 @center @image{threeobj,,,,png} |
|
1486 |
|
1487 You can visualize these @code{Objects} as being snapped together like Lego |
|
1488 building blocks if you like. When @code{Objects} are aggregated, a |
|
1489 @code{GetObject} search path is formed through the connectors. In order |
|
1490 to create this aggregation you will first need to create the @code{Objects}. |
|
1491 These are just normal, everyday C++ objects that we can create using the |
|
1492 @code{CreateObject} template function and manage using smart pointers. The |
|
1493 following code should be obvious to you by now: |
|
1494 |
|
1495 @verbatim |
|
1496 Ptr<A> a = CreateObject<A> (); |
|
1497 Ptr<B> b = CreateObject<B> (); |
|
1498 Ptr<C> c = CreateObject<C> (); |
|
1499 @end verbatim |
|
1500 |
|
1501 @cindex aggregation |
|
1502 When you create an aggregation, you pick one of the @code{Objects} of the |
|
1503 aggregation to think of as the container. In this case well pick @code{Object} |
|
1504 A. In order to aggregate an @code{Object}, you simply call the method |
|
1505 @code{AggregateObject} that your class has inherited from class @code{Object}. |
|
1506 The following code will aggregate @code{Object B} and @code{Object C} onto |
|
1507 the @code{Object} (and container/aggregation) @code{A}. |
|
1508 |
|
1509 @cindex AggregateObject |
|
1510 @cindex GetObject |
|
1511 @cindex Object |
|
1512 @verbatim |
|
1513 a->AggregateObject (b); |
|
1514 a->AggregateObject (c); |
|
1515 @end verbatim |
|
1516 |
|
1517 Thats all there is to it. Now that you have those connectors snapped |
|
1518 together, you can ask each of the @code{Objects} in the aggregation for any of |
|
1519 the other @code{Objects} in the aggregation. Lets look at a simple example: |
|
1520 |
|
1521 @verbatim |
|
1522 Ptr<B> newB = a->GetObject<B> (); |
|
1523 @end verbatim |
|
1524 |
|
1525 Now, the explanation of what this snippet does is not as simple as writing it. |
|
1526 The left hand side of this assignment declares a smart pointer to the class |
|
1527 @code{B} to help with memory management of the returned @code{Object} pointer. |
|
1528 You should be very familiar with smart pointers at this stage of the tutorial. |
|
1529 |
|
1530 The right hand side illustrates how @code{GetObject} is acutally used. |
|
1531 The method @code{GetObject} is templated. The assocated template parameter |
|
1532 (between the brackets) specifies the @emph{class} that is being requested. |
|
1533 This is important. Since it is the class type that specifies the search |
|
1534 criterion, there can be only one instance of a particular class present in an |
|
1535 aggregation. Looking back a little, although the parameter to |
|
1536 @code{AggregateObject} appears to be a vanilla C++ object (@code{b} or @code{c} |
|
1537 above), it actually represents (is an instance of) a class that has an |
|
1538 associated @code{TypeId} and inherits from @code{Object}. When you call |
|
1539 @code{GetObject} you specify the search criterion (using the template |
|
1540 parameter) as a class name. This referenced class must also have an |
|
1541 associated @code{TypeId} and must also have inherited from @code{Object}. |
|
1542 |
|
1543 This may be summarized by saying that @code{AggregateObject} takes an |
|
1544 @emph{instance} of an object of a particular class that inherits from |
|
1545 @code{Object}. GetObject looks for a @emph{class} of a particular type |
|
1546 (that again inherits from @code{Object}) and possibly returns an aggregated |
|
1547 object instance of that type. |
|
1548 |
|
1549 Now that you have those conceptual connectors snapped together, you can ask |
|
1550 each of the @code{Objects} in the aggregation for any of the @code{Objects} |
|
1551 in the aggregation. For example we could walk the @code{Objects} asking each |
|
1552 for the next in the aggregation. First we would ask the @code{Object} pointed |
|
1553 to by the smart pointer @code{a} to look for the @code{Object} @code{class B}: |
|
1554 |
|
1555 @verbatim |
|
1556 Ptr<B> newB = a->GetObject<B> (); |
|
1557 @end verbatim |
|
1558 |
|
1559 Next, we can ask the @code{Object} pointed to by the smart pointer @code{newB} |
|
1560 to look for the @code{Object} representing @code{class C}: |
|
1561 |
|
1562 @verbatim |
|
1563 Ptr<C> newC = newB->GetObject<C> (); |
|
1564 @end verbatim |
|
1565 |
|
1566 @cindex Object |
|
1567 Then, we can ask the @code{Object} pointed to by the smart pointer @code{newC} |
|
1568 to look for the @code{Object} representing @code{class A} and complete our |
|
1569 circuit of the aggregation: |
|
1570 |
|
1571 @verbatim |
|
1572 Ptr<A> newA = newC->GetObject<A> (); |
|
1573 @end verbatim |
|
1574 |
|
1575 @cindex GetObject |
|
1576 @code{GetObject} has some important properties that we need to go over. |
|
1577 Technically, @code{GetObject} is a @emph{symmetric}, @emph{reflexive} and |
|
1578 @emph{transitive} operation with respect to the set of aggregated |
|
1579 @code{Objects}. |
|
1580 |
|
1581 @subsubsection Symmetry |
|
1582 @cindex symmetry |
|
1583 The symmetric nature of @code{GetObject} guarantees that if one performs a |
|
1584 @code{GetObject} on a given @code{Object} for the class of that same |
|
1585 @code{Object}, that @code{GetObject} must succeed. In other words, the |
|
1586 fact that you accessed the aggregation via an instance of an @code{Object A} |
|
1587 in the aggregation implies the reachability of that @code{Object} in the |
|
1588 aggregation. This is usually written (by Microsoft) as, |
|
1589 |
|
1590 @center must succeed (A >> A) |
|
1591 |
|
1592 We can illustrate this property with the code snippet, |
|
1593 |
|
1594 @verbatim |
|
1595 Ptr<A> symmetricA = a->GetObject<A> (); |
|
1596 NS_ASSERT (symmetricA); |
|
1597 @end verbatim |
|
1598 |
|
1599 Here we take as given an interface (smart) pointer --- named @code{a} --- on |
|
1600 which we perform a @code{GetObject} looking for the class that represents that |
|
1601 same @code{Object}. This call must always succeed and a smart pointer to the |
|
1602 aggregated instance of that class is returned. |
|
1603 |
|
1604 @subsubsection Reflexivity |
|
1605 @cindex reflexivity |
|
1606 Calls to @code{GetObject} must also be reflexive. This means that if you |
|
1607 successfully @code{GetObject} for @code{Object B} from @code{Object A}, then |
|
1608 you must always be able to @code{GetObject} for @code{A} from @code{B}. This |
|
1609 is usually written as, |
|
1610 |
|
1611 @center must succeed (A >> B, then B >> A) |
|
1612 |
|
1613 This property can be illustrated with the code snippet, |
|
1614 |
|
1615 @verbatim |
|
1616 Ptr<B> b = a->GetObject<B> (); |
|
1617 Ptr<A> reflexiveA = b->GetObject<A> (); |
|
1618 NS_ASSERT (reflexiveA); |
|
1619 @end verbatim |
|
1620 |
|
1621 If the first @code{GetObject} on @code{Object A} looking for @code{Object B} |
|
1622 succeeds, then a @code{GetObject} on @code{Object B} looking @code{Object A} |
|
1623 must succeed. |
|
1624 |
|
1625 @subsubsection Transitivity |
|
1626 @cindex transitivity |
|
1627 @code{GetObject} must also be transitive. This means that if one can |
|
1628 find @code{Object B} from @code{Object A}, and @code{Object C} from |
|
1629 @code{Object B}, then one must also be able to find @code{Object C} from |
|
1630 @code{Object A}. This is usually written as, |
|
1631 |
|
1632 @center must succeed (A >> B, and B >> C, then A >> C) |
|
1633 |
|
1634 This property can be illustrated with the code snippet, |
|
1635 |
|
1636 @verbatim |
|
1637 Ptr<B> b = a->GetObject<B> (); |
|
1638 Ptr<C> c = b->GetObject<C> (); |
|
1639 Ptr<C> transitiveC = a->GetObject<C> (); |
|
1640 NS_ASSERT (transitiveC); |
|
1641 @end verbatim |
|
1642 |
|
1643 If you can get to @code{Object B} from @code{Object A}, and you can get to |
|
1644 @code{Object C} from @code{Object B}, then a @code{GetObject} on |
|
1645 @code{Object A} looking for @code{Object C} must also succeed. |
|
1646 |
|
1647 @subsection Creating the TypeId |
|
1648 @cindex TypeId |
|
1649 @cindex GetTypeId |
|
1650 The final piece of this puzzle is the @code{TypeId}. Recall that the |
|
1651 declaration our example object above included the following code |
|
1652 |
|
1653 @verbatim |
|
1654 static ns3::TypeId GetTypeId (void) |
|
1655 { |
|
1656 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1657 .SetParent (Object::GetTypeId ()) |
|
1658 .AddConstructor<A> (); |
|
1659 return tid; |
|
1660 } |
|
1661 @end verbatim |
|
1662 |
|
1663 This is the bit of code that ties this all together. For those unfamiliar |
|
1664 with the idioms involved, this declaration can be rather dense. First, let's |
|
1665 examine the function declaration itself. The following code, |
|
1666 |
|
1667 @verbatim |
|
1668 static ns3::TypeId GetTypeId (void) ... |
|
1669 @end verbatim |
|
1670 |
|
1671 declares a function that will be associated with all of the instances of the |
|
1672 given class. This is a function, not a method, in that it can be accessed |
|
1673 without a @emph{this} pointer; but it is associated with the class in a |
|
1674 namespace sense. The use of this kind of declaration allows one to write, |
|
1675 |
|
1676 @verbatim |
|
1677 return A::GetTypeId (void); |
|
1678 @end verbatim |
|
1679 |
|
1680 if the @code{TypeId} is needed for our @code{class A}. More generically the |
|
1681 class name can be substituted in a template, as is done deep in the |
|
1682 @command{ns-3} object system. |
|
1683 |
|
1684 From this perspective, if you leave out the middle of the function definition, |
|
1685 the boundaries should make sense to you. |
|
1686 |
|
1687 @verbatim |
|
1688 static ns3::TypeId GetTypeId (void) |
|
1689 { |
|
1690 return tid; |
|
1691 } |
|
1692 @end verbatim |
|
1693 |
|
1694 @cindex function-local variable |
|
1695 You are obviously looking at a global function associated with your class |
|
1696 that simply returns a @code{TypeId}. Now, what about the rest. The code |
|
1697 |
|
1698 @verbatim |
|
1699 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1700 .SetParent (Object::GetTypeId ()) |
|
1701 .AddConstructor<A> (); |
|
1702 @end verbatim |
|
1703 |
|
1704 when found inside the function declaration is called a function-local variable |
|
1705 with associated initialization. It'll be easier to pick this statement apart |
|
1706 piece by piece as well. The first line, |
|
1707 |
|
1708 @verbatim |
|
1709 static ns3::TypeId tid = ... |
|
1710 @end verbatim |
|
1711 |
|
1712 is the declaration of the function-local variable tid. This is essentially |
|
1713 an initialized global variable, the scope of which has been reduced to within |
|
1714 the enclosing method. You can think of this as a kind of global variable |
|
1715 that can only be accessed right there where it is created. If the variable |
|
1716 is initialized, this amounts to the same behavior as if a global static |
|
1717 initializer was declared in a namespace of the same name as your class. |
|
1718 Global static initializers are guaranteed by the C++ language definition to |
|
1719 be executed before your main procedure is entered. So are function-local |
|
1720 variables. |
|
1721 |
|
1722 The variable that is being initialized is of type @code{ns3::TypeId}, is |
|
1723 named @code{A::tid} since it is inside the class declaration for |
|
1724 @code{class A}, and is initialized by a call to the constructor for the class |
|
1725 @code{TypeId}. The constructor for @code{TypeId} takes a @code{std::string} |
|
1726 that can be used to locate the type information for your class. We usually |
|
1727 privide the class name as the string. |
|
1728 |
|
1729 Hopefully, this much of the declaration is now clear: |
|
1730 |
|
1731 @verbatim |
|
1732 static ns3::TypeId GetTypeId (void) |
|
1733 { |
|
1734 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1735 ... |
|
1736 return tid; |
|
1737 } |
|
1738 @end verbatim |
|
1739 |
|
1740 All that is left now are the lines including @code{SetParent} and |
|
1741 @code{AddConstructor}. |
|
1742 |
|
1743 @verbatim |
|
1744 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1745 .SetParent (Object::GetTypeId ()) |
|
1746 .AddConstructor<A> (); |
|
1747 @end verbatim |
|
1748 |
|
1749 The last bit may seem quite odd at first glance, but don't let the way the |
|
1750 code is broken up over several lines throw you. If you saw something like, |
|
1751 |
|
1752 @verbatim |
|
1753 pointer->TypeId()->SetParent()->AddConstructor(); |
|
1754 @end verbatim |
|
1755 |
|
1756 you probably wouldn't hesitate at all. Clearly, you would think, a method |
|
1757 called @code{TypeId} is called using the pointer called @code{pointer} as |
|
1758 shown below. |
|
1759 |
|
1760 @verbatim |
|
1761 pointer->TypeId() |
|
1762 @end verbatim |
|
1763 |
|
1764 The method @code{TypeId} must further return a pointer to an object that has |
|
1765 a method called @code{SetParent}. Just as clearly, @code{SetParent} must |
|
1766 return a pointer to an object that has a method called @code{AddConstructor}. |
|
1767 The same sort of thing is happening in our code snipped, except we are using |
|
1768 references instead of pointers. Perhaps if we rearrange this code to live on |
|
1769 one line it will be clearer. |
|
1770 |
|
1771 @verbatim |
|
1772 ns3::TypeId ("A").SetParent (Object::GetTypeId ()).AddConstructor<A> (); |
|
1773 @end verbatim |
|
1774 |
|
1775 It's just a string of method calls. The remaining question is then, what do |
|
1776 those three methods do. |
|
1777 |
|
1778 The first, @code{ns3::TypeId ("A")}, simply allocates a new type in the system |
|
1779 and allows you to refer to it in the future by a string. We have mentioned |
|
1780 inheritance trees often in the previous discussion. The second method, |
|
1781 @code{SetParent} associates the class being defined with its parents in the |
|
1782 tree. Finally, the @code{AddConstructor} method allows you to specify a |
|
1783 constructor to be used when an instance of your class is created using |
|
1784 @code{CreateObject}. |
|
1785 |
|
1786 @verbatim |
|
1787 AddConstructor<A> (); |
|
1788 @end verbatim |
|
1789 |
|
1790 You can interpret this as explaining to the @command{ns-3} object system that |
|
1791 you have a constructor named @code{A::A} which takes no parameters. You are |
|
1792 saying that this constructor should be used when @code{CreateObject} is called |
|
1793 with no parameters. |
|
1794 |
|
1795 By including the structure of the inheritance tree, in @command{ns-3} we can |
|
1796 use implementation inheritance to easily create new @code{Objects}. You are |
|
1797 prevented from doing so in Microsoft COM, but this was almost universally |
|
1798 identified as a problem. |
|
1799 |
|
1800 So, looking at the entire @code{GetTypeId} declaration again, |
|
1801 |
|
1802 @verbatim |
|
1803 static ns3::TypeId GetTypeId (void) |
|
1804 { |
|
1805 static ns3::TypeId tid = ns3::TypeId ("A") |
|
1806 .SetParent (Object::GetTypeId ()) |
|
1807 .AddConstructor<A> (); |
|
1808 return tid; |
|
1809 } |
|
1810 @end verbatim |
|
1811 |
|
1812 it should be clear what is happening. |
|
1813 |
|
1814 @subsection A Very Real Example |
|
1815 @cindex Node |
|
1816 @cindex AggregateObject |
|
1817 @cindex GetObject |
|
1818 @cindex Object |
|
1819 At this point you may be asking yourself what the point of all of this is, |
|
1820 since you already had those pointers laying around when you created the |
|
1821 objects. The typical case is that one will create and aggregate some number |
|
1822 of @code{Objects} in a constructor and return only a pointer to a single |
|
1823 @code{Object} as in our canonical example with @code{class Node}. In this |
|
1824 case, the @code{Node} would be created and the @code{Node} constructor might |
|
1825 create and call @code{AggregateObject} to aggregate the @code{Objects} for |
|
1826 internetwork routing and TCP/IP. From an external point of view, these |
|
1827 aggregated objects may be discovered at run-time using @code{GetObject}. |
|
1828 |
|
1829 Generally one tends to think of one of the @code{Objects} in the aggregation |
|
1830 as being the container and other @code{Objects} being aggregated to that |
|
1831 container. In the case of a Node, for example, it is quite natural to think |
|
1832 of the Node as being the container which contains protocol stacks, internet |
|
1833 routing, etc. So, lets start thinking about a real example by calling the |
|
1834 container @code{Object Node} instead of @code{A} as we have been. The |
|
1835 creation of this @code{Object} is found all over our example programs. For |
|
1836 example, you will find code like the following in |
|
1837 @code{samples/simple-point-to-point.cc}: |
|
1838 |
|
1839 @verbatim |
|
1840 Ptr<Node> n = CreateObject<InternetNode> (); |
|
1841 @end verbatim |
|
1842 |
|
1843 It may appear obvious to you now that the @code{InternetNode} class name |
|
1844 provided to the template function @code{CreateObject} means that |
|
1845 @code{InternetNode} is an @command{ns-3} @code{Object} and you will be able to |
|
1846 call @code{GetObject} on the resulting smart pointer. Well, I'm afraid that's |
|
1847 not entirely true. It's slightly more complicated. |
|
1848 |
|
1849 Take a look at @code{src/internet-stack/internet-stack.h} and find the class |
|
1850 declaration for @code{InternetNode}. |
|
1851 |
|
1852 @verbatim |
|
1853 class InternetNode : public Node |
|
1854 { |
|
1855 public: |
|
1856 InternetNode(); |
|
1857 ... |
|
1858 }; |
|
1859 @end verbatim |
|
1860 |
|
1861 @cindex GetTypeId |
|
1862 @cindex TypeId |
|
1863 @cindex Object |
|
1864 There is no declaration of a @code{static TypeId GetTypeId (void)} in this |
|
1865 class. This means that the @code{InternetNode} is really not an @code{Object} |
|
1866 for which you can @code{GetObject}. It turns out that the @code{InternetNode} |
|
1867 is an @emph{implementation class} of the @code{Node Object}. |
|
1868 |
|
1869 You may recall that there can be an implicit cast in a smart pointer |
|
1870 assignment if the cast is to a visible, unambiguous base class. That is, in |
|
1871 fact, what is happening here. Now, take a look at @code{src/node/node.h} and |
|
1872 find the class declaration for @code{class Node}. There you will find, |
|
1873 |
|
1874 @verbatim |
|
1875 class Node : public Object |
|
1876 { |
|
1877 public: |
|
1878 static TypeId GetTypeId (void); |
|
1879 ... |
|
1880 }; |
|
1881 @end verbatim |
|
1882 |
|
1883 Class @code{InternetNode} inherits from class @code{Node} that, in turn, |
|
1884 inherits from class @code{Object}. It is @code{Node} that provides a |
|
1885 @code{GetTypeId} method. Therefore it is @code{Node} that is an |
|
1886 @command{ns-3} @code{Object}. Note well that @code{InternetNode} is not an |
|
1887 @code{Object} in the sense that one should call @code{GetObject} on an |
|
1888 aggregation looking for an @code{InternetNode} class. That is, you should not |
|
1889 do, |
|
1890 |
|
1891 @verbatim |
|
1892 Ptr<InternetNode> i = node->GetObject<InternetNode> (); |
|
1893 @end verbatim |
|
1894 |
|
1895 since there really is not InternetNode::GetTypeId. It is @code{Node} that is |
|
1896 the @emph{proper} @code{Object} in this case and you should view |
|
1897 @code{InternetNode} as an implementation of the @code{Node Object}. This may |
|
1898 become clearer as we look a little deeper. |
|
1899 |
|
1900 We spoke of a protocol stack that is aggregated to a @code{Node} in our |
|
1901 discussions above, what we see in the real @command{ns-3} code is that this |
|
1902 is represented by the @code{Ipv4 Object}. If you look in |
|
1903 @code{src/node/ipv4.h} you will find, |
|
1904 |
|
1905 @verbatim |
|
1906 class Ipv4 : public Object |
|
1907 { |
|
1908 public: |
|
1909 static TypeId GetTypeId (void); |
|
1910 ... |
|
1911 }; |
|
1912 @end verbatim |
|
1913 |
|
1914 Since class @code{Ipv4} inherits from class @code{Object} and has a |
|
1915 @code{GetTypeId}, it is an @command{ns-3} @code{Object}. If you look in |
|
1916 @code{src/node/ipv4.cc} you will find, |
|
1917 |
|
1918 @verbatim |
|
1919 TypeId |
|
1920 Ipv4::GetTypeId (void) |
|
1921 { |
|
1922 static TypeId tid = TypeId ("Ipv4") |
|
1923 .SetParent<Object> (); |
|
1924 return tid; |
|
1925 } |
|
1926 @end verbatim |
|
1927 |
|
1928 After all of this reading you know that this code snippet is asking the |
|
1929 system to create a unique @code{TypeId} for the @code{Ipv4} class and |
|
1930 declares that @code{Ipv4} inherits from class @code{Object}. This is what |
|
1931 makes an @code{Ipv4} an @code{Object}. |
|
1932 |
|
1933 @cindex Ipv4 |
|
1934 It turns out that the Ipv4 class is an abstract base class (ABC). There are |
|
1935 a number of pure virtual methods declared in that class. This means that |
|
1936 an @code{Ipv4} object may not be instantiated. This is reflected by the fact |
|
1937 that there are no constructors registered in the @code{GetTypeId} method above. |
|
1938 What is instantiated in the real system is an implementation class, called |
|
1939 @code{Ipv4Impl}. This class inherits from @code{Ipv4} and provides the |
|
1940 required virtual methods. This is where understanding what is an |
|
1941 @code{Object} and what is not can get tricky. The @code{Object} is the |
|
1942 @code{Ipv4} class since that is where the @code{GetTypeId} is found. The fact |
|
1943 that you see @code{GetTypeId} there tells you that the @code{Ipv4} class is |
|
1944 the class for which you can @code{GetObject}. |
|
1945 |
|
1946 @cindex implementation class |
|
1947 The class @code{Ipv4Impl} provides an implementation for the pure virtual |
|
1948 methods in @code{Ipv4}. Since class @code{Ipv4} cannot be instantiated, one |
|
1949 instantiates the @code{Ipv4Impl} class to create an @code{Ipv4} @code{Object}. |
|
1950 You will use the @code{CreateObject} template function to create an object that |
|
1951 implements the methods of an @code{Object}. You can probably see how this |
|
1952 gets even more tricky in conversation. |
|
1953 |
|
1954 Once the @code{Ipv4Impl} object is instantiated, the resulting pointer is |
|
1955 immediately cast to an @code{Ipv4} pointer. Clients will then use the |
|
1956 methods specified in the @code{Ipv4} class to access the @code{Ipv4 Object} |
|
1957 methods which are, in turn, implemented in the @code{Ipv4Impl} object. |
|
1958 |
|
1959 If you now look in the file, @code{src/internet-stack/internet-stack.cc} you |
|
1960 will see the following code in @code{InternetNode::Construct} that creates the |
|
1961 @code{Ipv4} Interface and aggregates it. |
|
1962 |
|
1963 @verbatim |
|
1964 Ptr<Ipv4Impl> ipv4Impl = CreateObject<Ipv4Impl> (ipv4); |
|
1965 ... |
|
1966 Object::AggregateObject (ipv4Impl); |
|
1967 @end verbatim |
|
1968 |
|
1969 Note that the parameter @code{ipv4} passed to the @code{CreateObject} template |
|
1970 function is actually a pointer to an @code{Ipv4L3Protocol} which you can |
|
1971 ignore at this point --- it doesn't really have anything to do with the |
|
1972 @code{Ipv4} Interface. |
|
1973 |
|
1974 This is exactly the same thing that is happening in the case of the |
|
1975 @code{InternetNode}. |
|
1976 |
|
1977 @verbatim |
|
1978 Ptr<Node> n = CreateObject<InternetNode> (); |
|
1979 @end verbatim |
|
1980 |
|
1981 @cindex implementation object |
|
1982 @code{CreateObject} is being called to create an implementation object, |
|
1983 in this case @code{InternetNode}, which implements the methods of the |
|
1984 @code{Node Object}. It is the resulting @code{Node Object} which you would |
|
1985 use as the container and it is the @code{Node} class that you would use as |
|
1986 the template parameter when calling @code{GetObject}. In the same way, you |
|
1987 would @emph{not} want to do, |
|
1988 |
|
1989 @verbatim |
|
1990 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4Impl> (); |
|
1991 @end verbatim |
|
1992 |
|
1993 Rather you should understand that the @emph{proper} @code{Object} is the |
|
1994 @code{Ipv4} not the @code{Ipv4Impl} and do the following, |
|
1995 |
|
1996 @verbatim |
|
1997 Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> (); |
|
1998 @end verbatim |
|
1999 |
|
2000 @cindex CreateObject |
|
2001 This does illustrate that the fact that whether an object created by |
|
2002 @code{CreateObject} is or is not an @code{Object} in the usual sense can be |
|
2003 quite well hidden if you are casually looking at the object creation code. |
|
2004 The designers of the system had long and involved discussions on this issue |
|
2005 and in the end decided that mnemonic aids such as Hungarian notation were a |
|
2006 stylistic thing and you should just refer to the system documentation to |
|
2007 determine what objects are @command{ns-3} @code{Objects} and what the APIs |
|
2008 of those @code{Objects} actually are (RTFM --- as in Read the Fine Manual, |
|
2009 of course). |
|
2010 |
|
2011 @cindex AggregateObject |
|
2012 @cindex Object |
|
2013 In the case of @code{Ipv4Impl}, you know that the class inherits somehow |
|
2014 from @code{Object} since there is a call to @code{AggregateObject} that |
|
2015 refers to an instance of an @code{Ipv4Impl}. You will have to go to |
|
2016 the header file @code{src/internet-stack/ipv4-impl.h} and find that |
|
2017 @code{Ipv4Impl} inherits from class @code{Ipv4}. You will then have go to |
|
2018 the file @code{src/node/ipv4.h} and see that it inherits from @code{Object} and |
|
2019 defines a @code{GetTypeId}. Thus the @code{Object} for which you can |
|
2020 @code{GetObject} is really the @code{Ipv4 Object}. |
|
2021 |
|
2022 Returning to some real @command{ns-3} example code, lets take a look at |
|
2023 @code{examples/simple-point-to-point.cc}. You will find the following |
|
2024 code in this file: |
|
2025 |
|
2026 @verbatim |
|
2027 Ptr<Node> n0 = CreateObject<InternetNode> (); |
|
2028 ... |
|
2029 Ptr<Ipv4> ipv4; |
|
2030 ipv4 = n0->GetObject<Ipv4> (); |
|
2031 ipv4->SetDefaultRoute (Ipv4Address (``10.1.1.2''), 1); |
|
2032 @end verbatim |
|
2033 |
|
2034 @cindex InternetNode |
|
2035 @cindex Node |
|
2036 @cindex Object |
|
2037 @cindex GetObject |
|
2038 The first line creates an @code{InternetNode} implementation object and casts |
|
2039 the resulting smart pointer to a @code{Node} as we have discussed extensively. |
|
2040 The next line shown declares a smart pointer to an @code{Ipv4 Object}. We |
|
2041 then do a @code{GetObject} on the @code{Node} looking for the |
|
2042 @code{Ipv4 Object}. You know since you've read every line of this tutorial |
|
2043 in detail exactly how that @code{Ipv4 Object} got into every @code{Node}. You |
|
2044 know that the @code{GetObject} will return a smart pointer to its aggregated |
|
2045 @code{Ipv4} Interface. Once we have the @code{Ipv4} smart pointer, we simply |
|
2046 use it as if it were any other C++ object. The last line shows this by |
|
2047 setting the default route for the node. |
|
2048 |
|
2049 @section Caveats |
|
2050 There are a few things that you should remember but which may not be |
|
2051 immediately obvious. |
|
2052 |
|
2053 @subsection Ns-3 Objects are Associated with Classes not C++ objects |
|
2054 @cindex Object |
|
2055 @cindex GetObject |
|
2056 @cindex iterate |
|
2057 @cindex aggregation |
|
2058 @cindex GetNDevices |
|
2059 Okay, you can see some of the problems with the terminology popping up again. |
|
2060 We are reminding you that when you do a GetObject you are providing the key |
|
2061 to the lookup by giving a class name and not anything that is unique to a |
|
2062 C++ object. |
|
2063 |
|
2064 You cannot add more than one @code{Object} of a given type (class name) to an |
|
2065 aggregation. If you need to contain a number of @code{Objects} of the same |
|
2066 type in the same aggregation, you will need to provide a separate container |
|
2067 over which you can iterate. For example, the @code{Node} class provides |
|
2068 methods, |
|
2069 |
|
2070 @verbatim |
|
2071 uint32_t GetNDevices (void) const; |
|
2072 Ptr<NetDevice> GetDevice (uint32_t index) const; |
|
2073 @end verbatim |
|
2074 |
|
2075 that are used iterate over the multiple @code{NetDevice} @code{Objects} |
|
2076 associated with it. |
|
2077 |
|
2078 @emph{Remember: Object types do not identify objects.} |
|
2079 |
|
2080 @subsection Dont use GetObject to Check Your Own Type. |
|
2081 @cindex GetObject |
|
2082 It is tempting to use @code{GetObject} as a form of runtime type |
|
2083 information. Dont do it. You have no control over what @emph{other} |
|
2084 object may be added to your aggregation. Someone else may have |
|
2085 appropriated (reimplemented) your type and aggregated themselves onto the |
|
2086 aggregation. |
|
2087 |
|
2088 Consider a socket factory implementation. Sockets can be either UDP sockets |
|
2089 or TCP sockets. A socket factory will have a generic @code{SocketFactory} |
|
2090 Object and either a UDP specific interface for setting UDP parameters or a |
|
2091 similar TCP-specific interface. |
|
2092 |
|
2093 Consider what might happen if you declared your socket factory as a partially |
|
2094 abstract base class, and then provided separate implementations for UDP and |
|
2095 TCP specific methods of this factory in separate concrete classes. Now |
|
2096 consider what might happen if you used @code{GetObject} in your base class |
|
2097 to determine if you were a UDP or a TCP factory. |
|
2098 |
|
2099 If a factory, say the UDP version, were not aggregated to any other |
|
2100 @code{Object}, the base class could @code{GetObject} on itself for the |
|
2101 UDP-specific class name. If the @code{GetObject} succeeded, it could then |
|
2102 infer that it was a UDP implementation and would then do any UDP-specific |
|
2103 tasks it could. [Experienced C++ folks are cringing about how |
|
2104 horrible this design is, but bear with me --- its a simple illustration of |
|
2105 a specific and perhaps not-too-obvious problem.] |
|
2106 |
|
2107 If another factory, say the TCP version, were not aggregated to any other |
|
2108 Interface, the base class could @code{GetObject} on itself for the UDP-specific |
|
2109 interface. If this failed, it could then infer that it had a TCP |
|
2110 implementation and would then do any TCP-specific tasks it could. |
|
2111 |
|
2112 Now, what happens when these two working objects are aggregated together by |
|
2113 some innocent end-user. Since the @code{Objects} are conceptually snapped |
|
2114 together, the TCP implementation would suddenly begin finding the UDP |
|
2115 Interface from the other class factory and think it was the UPD implementation. |
|
2116 |
|
2117 @emph{Objects should not be used as run-time type information.} |
|
2118 |
|
2119 @section Connecting the Dots |
|
2120 @cindex Object |
|
2121 @cindex GetObject |
|
2122 @cindex AggregateObject |
|
2123 @cindex GetTypeId |
|
2124 @cindex API |
|
2125 This may all sound very complicated to you if this is your first exposure to |
|
2126 these concepts. It may be annoying if I tell you that its really not as hard |
|
2127 as it sounds. Rest assured that if you take some time, look at and understand |
|
2128 the examples and write a little test code it will all come together for you. |
|
2129 Grep around the system for @code{AggregateObject} and @code{GetObject} and |
|
2130 take a look at how we have used them. This will also give you a good idea of |
|
2131 what our core @code{Objects} and associated APIs are. If you grep for |
|
2132 @code{GetTypeId} you will find most, if not all of the @code{Object} API |
|
2133 interface declarations in the system. The more you see this idiom in |
|
2134 use, the more comfortable you will be with the idea and the more you will see |
|
2135 how this addresses the weak base class, swiss army knife base class, and |
|
2136 fragile base class problems I explained at the beginning. |
|
2137 |
|
2138 As I alluded to earlier, the developers had long discussions regarding how to |
|
2139 make navigating the @code{Object} environment easier. The primary issue was |
|
2140 how we could make it easier to convey to you, the model writer, that an object |
|
2141 was an @code{Object}. We originally used similar terminology as Microsoft |
|
2142 COM and used QueryInterface instead of @code{GetObject}. One suggestion was |
|
2143 to adopt the convention that classes that implemented Interfaces must begin |
|
2144 with the letter I. Microsoft does this, as exemplified by the class IUnknown. |
|
2145 We also toyed with the idea of beginning our header files with ``i-'' as in |
|
2146 ``i-ipv4.h.'' We considered forcing some structure on Interfaces with a pure |
|
2147 virtual class specification, the names of which begin with an I; and |
|
2148 corresponding implementations, the names of which begin with a C. This all |
|
2149 got out of hand fairly quickly. |
|
2150 |
|
2151 In the end we decided that we were really discussing issues of programming |
|
2152 style, and we really could not come up with a strong reason to impose any |
|
2153 particular solution. No matter what direction we took, we ended up with some |
|
2154 form of extra confusion or extra complexity somewhere in the system. The |
|
2155 resulting system is extremely flexible and easy to use. It is, unfortunately, |
|
2156 sometimes hard to document and talk about. |
|
2157 |
|
2158 @cindex Feynman |
|
2159 If it helps you to think in terms of Microsoft COM and Interfaces, by all means |
|
2160 do so, just be aware that even though @command{ns-3} @code{Objects} descend |
|
2161 from COM in some sense, there are subtle differences that may get you lost or |
|
2162 into trouble. So to paraphrase Feynman one more time, |
|
2163 |
|
2164 @quotation |
|
2165 ``@command{Ns-3} @code{Objects} do not behave like COM Components, or Java |
|
2166 Beans, or CORBA objects, or clouds or weights on springs, or like anything |
|
2167 that you have ever seen --- they are @command{ns-3} components.'' |
|
2168 @end quotation |
|
2169 |
|
2170 Just get very familiar with the @command{ns-3} object model. It is the heart |
|
2171 of the system and if you do not understand it you will not understand how to |
|
2172 write an @command{ns-3} model properly. |
|
2173 |
|
2174 @c ======================================================================== |
|
2175 @c Doxygen |
|
2176 @c ======================================================================== |
|
2177 |
|
2178 @node The-Doxygen-Documentation-System |
|
2179 @chapter The Doxygen Documentation System |
|
2180 |
|
2181 @node How-To-Change-Things |
|
2182 @chapter How to Change Things |
|
2183 |
|
2184 @node How-To-Set-Default-Values |
|
2185 @chapter How to Set Default Values |
|
2186 |
|
2187 @node How-To-Write-A-New-Application |
|
2188 @chapter How to Write a New Application |
|
2189 |
|