Compare commits
2397 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8869dc9630 | |||
| 62c2e46c37 | |||
| 89e20b56c9 | |||
| 2b1bc24321 | |||
| cb19bb1404 | |||
| 92c9208ea6 | |||
| 8c7759dc6b | |||
| b9aeaf3650 | |||
| 87c68d5a58 | |||
| 77d2f50c2f | |||
| ddef596d2f | |||
| fcf9b4cf5b | |||
| bdf0896c2a | |||
| 3aa9ce9efd | |||
| 73f7efb2f2 | |||
| e10db3d576 | |||
| daaed2d5e6 | |||
| f1019e4026 | |||
| 398ffd3d58 | |||
| ae661f53e0 | |||
| 4b3b79be2f | |||
| 2fb03d7aa3 | |||
| 14c3cac1d1 | |||
| c4ea047cb9 | |||
| 6746cc48eb | |||
| 1fe76d94f1 | |||
| 6d739bf2b5 | |||
| c3fb9059ac | |||
| 0c35c2b60f | |||
| 9008e089ae | |||
| ad46f21982 | |||
| 8a78bf66ae | |||
| da514b5edb | |||
| 4743c2ff7c | |||
| 7c05c10381 | |||
| 544f9d1a81 | |||
| c7e37d1a18 | |||
| b357866655 | |||
| aefd3e3371 | |||
| 4587183489 | |||
| 6f2e42050f | |||
| a86ec45ec9 | |||
| d99df782e9 | |||
| e1d52991b6 | |||
| 2d2675e6f8 | |||
| d4a0ae2a74 | |||
| b5cfed2178 | |||
| a6aed94fe8 | |||
| 9da2bfa832 | |||
| 098186e7e6 | |||
| 452bb57c9f | |||
| 1b8812d558 | |||
| 4a73b2abd0 | |||
| c11554b553 | |||
| da05aa1327 | |||
| 2edda56a6f | |||
| 9ed0f04944 | |||
| 1aef4543cc | |||
| 9ccd6dadcb | |||
| 8ae203ce50 | |||
| 1e4c17bc9f | |||
| cbc938e2bf | |||
| cdb5cc083f | |||
| de189d447c | |||
| aebdb9fbfd | |||
| 82e92545aa | |||
| 8559d575f5 | |||
| 5a3fbf3637 | |||
| 9ca1253956 | |||
| de69fcb842 | |||
| 88d12f80eb | |||
| a37b419abd | |||
| 6c4692ea55 | |||
| 97d98fa1ce | |||
| 6bcd10f205 | |||
| 36ac76b49c | |||
| d003d6a34f | |||
| 3b217b603e | |||
| 43263bc0e7 | |||
| 525969ca64 | |||
| fb9ca8f381 | |||
| 1f9b7723b8 | |||
| 60c2ddafa8 | |||
| 64e2c2bb8f | |||
| b469955b1e | |||
| c3557faf08 | |||
| 4d144c5ec8 | |||
| 2b7b6628f3 | |||
| de2475ddc3 | |||
| 4d2bbed418 | |||
| 7ef64dd6ce | |||
| 90bbabf52f | |||
| c43918d4c2 | |||
| 14562c914d | |||
| 017b3b191d | |||
| 49a48f01e8 | |||
| 12ae07ddab | |||
| d86a521ff1 | |||
| 3e3f102d62 | |||
| 45f9ff0ddc | |||
| 44478e378d | |||
| 1eb07aeaef | |||
| 10a7924d63 | |||
| d3b35a295c | |||
| 1a5577bc3d | |||
| 92f2ed110a | |||
| 8b7d6955e6 | |||
| 1ae7ba74b9 | |||
| 94b7fd9434 | |||
| 1ca824b340 | |||
| 94587dd4f3 | |||
| 6495130641 | |||
| d1cc848f30 | |||
| 39b7522f4c | |||
| 1840dfe6b1 | |||
| 5307dcfd48 | |||
| 9dfc592a26 | |||
| be9d919a58 | |||
| 937f78e7bc | |||
| d9a606c58d | |||
| d3942cd4d0 | |||
| 6badc137d9 | |||
| 2eafd4b9b1 | |||
| add091ea23 | |||
| 92ebbd036d | |||
| f08ea71825 | |||
| a5c312cb1c | |||
| e20525cad9 | |||
| 00d36e836c | |||
| 312b8da3a3 | |||
| 05a27250c1 | |||
| a7a0a3de70 | |||
| 26d46a960d | |||
| 2a323473e4 | |||
| 4904c44f15 | |||
| e4ec46dd52 | |||
| a947ff3967 | |||
| bbf1d7cce3 | |||
| dfb9b7360a | |||
| 554fcfda0d | |||
| 16d1d635a0 | |||
| 62d8743f1c | |||
| 5872949e0a | |||
| f173b434dd | |||
| 48fa3d344c | |||
| b9d448c83b | |||
| 6152ba1a89 | |||
| 08f2b87daa | |||
| 39c1412e3e | |||
| 41b7eadd33 | |||
| b851cc5b0b | |||
| 08961f4883 | |||
| c9ccce91ed | |||
| 76dd4d1db4 | |||
| 27e5640201 | |||
| fdc3e27c11 | |||
| 709f6a6d5b | |||
| 45793c3a02 | |||
| 137ff47a46 | |||
| ab01dd65a4 | |||
| 31870b3bc0 | |||
| 0c34dea05b | |||
| b135ced7aa | |||
| 16018e8d7e | |||
| 0ef25b59c4 | |||
| 20b1d65d07 | |||
| eaf4fb4a6d | |||
| f86b2de0af | |||
| 4182edbc93 | |||
| 6af434b9f9 | |||
| f79ac9e373 | |||
| c352b35d3f | |||
| b91e3b0e4c | |||
| 0d86d03be0 | |||
| 9a94ef7a2d | |||
| 791e9ae464 | |||
| c2a543f568 | |||
| b3390aaa3e | |||
| 3d0264e3a3 | |||
| 42fbffdbdb | |||
| f83b6c7ab1 | |||
| 2f1e4574c0 | |||
| de351e9388 | |||
| 20f5f62292 | |||
| 0008eeebce | |||
| ca7b76ef27 | |||
| a41edb2fa1 | |||
| ffd1766adc | |||
| f9e025ad81 | |||
| b62c394703 | |||
| 4ba092f3aa | |||
| 93126f3a55 | |||
| 62ff82d0ca | |||
| e62a059f05 | |||
| 5f94a4cf59 | |||
| 888a3bdad6 | |||
| 72dba0d456 | |||
| 3bd417f4e5 | |||
| 72d054a867 | |||
| e9e87c3232 | |||
| ef99300eff | |||
| 49d5404bfc | |||
| c21d79a87b | |||
| 8dc2460416 | |||
| e6bd2a7a6a | |||
| 3a34c3fff1 | |||
| ad374c8d87 | |||
| 935532822b | |||
| 45d6dcd5f4 | |||
| e4c1b22090 | |||
| 2a14b1c408 | |||
| 5b119aa40d | |||
| 25de2ff3c4 | |||
| 4c4ef85a93 | |||
| 67d54a7f8a | |||
| 0a476b4f04 | |||
| 2c57f536e3 | |||
| a1882f8e10 | |||
| 7c509777e5 | |||
| d5a75f0cec | |||
| 91c4ef481f | |||
| d034ec3e08 | |||
| dd4979ef89 | |||
| 84c9dd96db | |||
| 18011ba4eb | |||
| aa7b91f890 | |||
| 0e05b107fd | |||
| 05c3383610 | |||
| 43c64f656b | |||
| 2b4b265b60 | |||
| 0efe19fe76 | |||
| 1a990a1877 | |||
| 6547b9222c | |||
| a4a8086580 | |||
| 8d3dfb1df9 | |||
| 3226ce7f09 | |||
| 1b12b95ee9 | |||
| ffdff79112 | |||
| 4b7bfc9b77 | |||
| ccb704ffc7 | |||
| ce87f97994 | |||
| 8a7187fba3 | |||
| 3a8df9f3d6 | |||
| 31a31ffc07 | |||
| 63dccc1973 | |||
| 36e6b69aaf | |||
| dc624d46b3 | |||
| 1cecfe5548 | |||
| a54122b4e8 | |||
| 693099a950 | |||
| ae1fed72b1 | |||
| b5e22fdc37 | |||
| 47e58be578 | |||
| 833506428b | |||
| ca3c48f8e8 | |||
| b00892cae7 | |||
| 2e116e5f74 | |||
| 9eb007fd26 | |||
| 6be343530f | |||
| 9ee8930726 | |||
| 0add09088e | |||
| 006ac07f97 | |||
| 5d5fd895f1 | |||
| a042d0bbef | |||
| 3ebec1046c | |||
| 4340da4ca6 | |||
| 6ec88588f1 | |||
| 32bc3d3664 | |||
| ee62b6d04e | |||
| fc73accacd | |||
| 9da8e1bb03 | |||
| 515183caae | |||
| 0f55fefaba | |||
| ddda864b77 | |||
| 5a16ff1df4 | |||
| 53841f6170 | |||
| 3c8bfe6ae6 | |||
| 2e699a4704 | |||
| 7089f682d6 | |||
| 371ed54dc9 | |||
| 0b6e955a24 | |||
| f5bb823415 | |||
| 83cd996471 | |||
| 418a3fae42 | |||
| 66229167d2 | |||
| 164e8c83bc | |||
| 2865203612 | |||
| f2a37c6ca4 | |||
| 6236cbf9a3 | |||
| 58ab30c53c | |||
| beaf8569c0 | |||
| 9679a25783 | |||
| aaccadb46a | |||
| 4c424da911 | |||
| 623d9898b7 | |||
| 1c05220bba | |||
| ccd72825dd | |||
| 29169d42b6 | |||
| 43ecf40b5a | |||
| 119cf2035b | |||
| 73aec9c9b1 | |||
| 04c8831510 | |||
| fbabf8129a | |||
| 08511f30c5 | |||
| daddd90d07 | |||
| bfe0533aa3 | |||
| f8a2add627 | |||
| af58cc3026 | |||
| c6f7bb2d3e | |||
| 075851985f | |||
| e4eeeb18f5 | |||
| b61d0ff5f2 | |||
| 288d193daa | |||
| 0996a38b84 | |||
| 18ee064a79 | |||
| 96c43a7e26 | |||
| 5c7b34db46 | |||
| d3623e2142 | |||
| 062a2dcc42 | |||
| 2d581766fd | |||
| d7a038431f | |||
| e17282f995 | |||
| 78829ba702 | |||
| 4a78ce68d1 | |||
| ad54b2ce62 | |||
| f79e7581b6 | |||
| aeffbb31d7 | |||
| b998a05cce | |||
| 3752943c22 | |||
| 9fd7fbb86c | |||
| 829a6dd8bb | |||
| 1f0dd55d8d | |||
| 28bf2500e9 | |||
| 63d6b14d45 | |||
| 815f3721b7 | |||
| 0dab5235c9 | |||
| eb9fa68703 | |||
| 7be1b92968 | |||
| d1ddd3c89b | |||
| 9b153c313b | |||
| ea6e067812 | |||
| 6a93edb24e | |||
| a6321aac60 | |||
| 450b10b597 | |||
| f91e2ff5a4 | |||
| 35170aed54 | |||
| 2c1b7db441 | |||
| a557f1c064 | |||
| f2b7b1795b | |||
| 3b711f9852 | |||
| a890500150 | |||
| 7468230ede | |||
| 6a3326e529 | |||
| 4ff40c4a07 | |||
| 254057bd80 | |||
| f5f32e0ea3 | |||
| 39ef17d6a4 | |||
| 505de0c685 | |||
| bb10734d66 | |||
| edb480ad29 | |||
| f4cff0e194 | |||
| 78a2df8963 | |||
| f8ec434cdb | |||
| 1649c1dc65 | |||
| 5c5ab1f1f0 | |||
| 53be11fe6f | |||
| 6fd8b6c572 | |||
| 61375f8ef5 | |||
| 8a32b1e369 | |||
| 22d1a6046d | |||
| db81db32a8 | |||
| c9d422bbb6 | |||
| bd1ef984cc | |||
| 6d53b47cae | |||
| 09f00c5b34 | |||
| fbe5e3949f | |||
| 43dbc0b4d1 | |||
| 5e9344d2d4 | |||
| 2b0056553c | |||
| 6cf0d2e645 | |||
| 822e13a7df | |||
| a62f9d7771 | |||
| 112b278854 | |||
| 14c60f7ad3 | |||
| e855838ed1 | |||
| 8a4b416428 | |||
| ca687b56f6 | |||
| 556d973168 | |||
| 42282f5512 | |||
| 0e65d73baa | |||
| f7691237f5 | |||
| ed0dcc982b | |||
| a390b13f86 | |||
| 5d91e8c2d2 | |||
| 0789c9b435 | |||
| 03b4114b20 | |||
| fda39900e3 | |||
| 9167a8b308 | |||
| 60c81de8b5 | |||
| 3211fbb0bf | |||
| 3327b9da92 | |||
| 72b496b9ef | |||
| 8bfd88b80b | |||
| c456128c6d | |||
| dd283f6ead | |||
| 271ea4bc75 | |||
| e7c2292d7b | |||
| c883517a1d | |||
| 696859e936 | |||
| 267a3ca69d | |||
| 27c1fab7fc | |||
| be27a1c03d | |||
| ba319c457d | |||
| 4a556dbf91 | |||
| 923b1180f9 | |||
| f6ba778fc9 | |||
| cff773b8d2 | |||
| 776a594c3c | |||
| a75e91cc03 | |||
| dc271270a8 | |||
| cc927f907f | |||
| 53fb65aea7 | |||
| 560a34ba97 | |||
| e0570ec0b0 | |||
| e110fea8ff | |||
| d4cd3c92fd | |||
| b807dfa090 | |||
| 5a16b2cad8 | |||
| 9ea56ac66a | |||
| 478e810ad5 | |||
| bf90dded3c | |||
| c22d5c5733 | |||
| bb5f9f1a50 | |||
| 3f1c2d2653 | |||
| f6dcb76287 | |||
| 6740fc4627 | |||
| edc7af8a02 | |||
| 80c8937a01 | |||
| 4400054ebe | |||
| 3a43bd4987 | |||
| c140066890 | |||
| c3f0505ddc | |||
| 8501ca807c | |||
| 75643a53ef | |||
| b6471a7749 | |||
| 0c393e38c4 | |||
| 05019b6214 | |||
| 737bc7cd00 | |||
| 31d26c1e84 | |||
| ec7c5d2dd6 | |||
| b34fbc477b | |||
| a8acd5c5f0 | |||
| 621f07f0d2 | |||
| 11468a4235 | |||
| 441b674f96 | |||
| 2c273b86cd | |||
| d4347bc1b5 | |||
| 5a8c75187d | |||
| 36049254af | |||
| 18dd6edda3 | |||
| c802635595 | |||
| 56b59c5905 | |||
| 6490c81cf8 | |||
| ec3d666f3b | |||
| 8dc44fbfaf | |||
| 5a8d264371 | |||
| 3faceb9149 | |||
| aad4e224e5 | |||
| 5bd019aba0 | |||
| 9fe0c49344 | |||
| bcc362cd11 | |||
| 34c057c351 | |||
| 9c1922aebe | |||
| 058f508927 | |||
| 24863d5368 | |||
| e103bc0ded | |||
| 766efc6d0e | |||
| e4fa093d5f | |||
| cb1e1d0023 | |||
| dc96b531b1 | |||
| a4a18943f7 | |||
| a87eed74c2 | |||
| 5a614715ea | |||
| 27d2380327 | |||
| d1d683ee21 | |||
| 812fc3be75 | |||
| ae4529b819 | |||
| 2c1c5afe91 | |||
| b41554c18f | |||
| 40349f92d8 | |||
| 6935a997e6 | |||
| 41f6573c8d | |||
| 2b44913a70 | |||
| 64f72686aa | |||
| d06c2b4fae | |||
| 889e333a35 | |||
| 379c3d5390 | |||
| 02273c7da7 | |||
| 2bb663d011 | |||
| 0dfe8fa5df | |||
| e173bb868d | |||
| c5ffe4c9dc | |||
| a053ff6896 | |||
| 537e375fe1 | |||
| 879b2cb91d | |||
| c0d60678d9 | |||
| 521c43eb23 | |||
| 627813fe6c | |||
| 16f7931992 | |||
| 76847a02ca | |||
| 935a7896e1 | |||
| 7f6f6ba6a7 | |||
| 8977a827b2 | |||
| 11608c6b16 | |||
| 6ac2042e55 | |||
| 4ff7264001 | |||
| 9bcf1cdac5 | |||
| f2769ba5a5 | |||
| db02706e4c | |||
| 78bfd610d9 | |||
| 20726f8201 | |||
| 4fc3138b1e | |||
| b6932288ae | |||
| 6397957980 | |||
| 8810ebfe02 | |||
| 7771ab6562 | |||
| 27615d70d1 | |||
| 1a443df051 | |||
| ff4dfc3009 | |||
| a349c602db | |||
| 62308cf1ce | |||
| 511e11e9be | |||
| 6de12cc9d2 | |||
| 9ad6948605 | |||
| 7e17f8d7e1 | |||
| 67c8f12b67 | |||
| e0346ac124 | |||
| 46cc3fab6d | |||
| 02dc54f597 | |||
| a7677d77de | |||
| e963c05aeb | |||
| cb475c1750 | |||
| 4202275d10 | |||
| e9c67a3ada | |||
| ba70c90271 | |||
| 8d084573dc | |||
| 9644e5ee88 | |||
| 74541b0d23 | |||
| fa2983e8a4 | |||
| a280c30a20 | |||
| a85420cd34 | |||
| 982fe8454b | |||
| b5cfd48e9a | |||
| b7f945f750 | |||
| 942f3404a3 | |||
| fd49891782 | |||
| 6191bda098 | |||
| ac7ef5158d | |||
| c61932afc5 | |||
| 473ea28f10 | |||
| 2158f87125 | |||
| b4aaac11c6 | |||
| 1d78ea62e8 | |||
| 37f1478f00 | |||
| 2fe2751c9e | |||
| 80e0d082b4 | |||
| 011e2bbb70 | |||
| 26fba17dc2 | |||
| 4e2a41ae85 | |||
| cb3bcff3a6 | |||
| 72f7ffdb6d | |||
| 050af31b95 | |||
| 89d089c506 | |||
| 3d0e59cd05 | |||
| 83dea96517 | |||
| e1d6ca18e1 | |||
| 7020d1611e | |||
| 0a3da46adc | |||
| ed271f5954 | |||
| a3628b44c1 | |||
| 23edc105e2 | |||
| 44afb107ba | |||
| 5fe039c6a6 | |||
| cabb264eef | |||
| ab8a395c49 | |||
| da1d232338 | |||
| 08eb0aef35 | |||
| d869416a92 | |||
| 77bf878ea8 | |||
| 4966231237 | |||
| 1724e3ceec | |||
| 58dd143df7 | |||
| a6979a7bb9 | |||
| 7b8b8e8de3 | |||
| 7f56378951 | |||
| b21f71e568 | |||
| 8872354a55 | |||
| 69dfbe8707 | |||
| 5117b61f63 | |||
| bb59c6a9fb | |||
| c6868e0961 | |||
| ff02feb0b7 | |||
| 991e83fe2c | |||
| 0a9ad0c47c | |||
| dafc9f88ae | |||
| 9b4661c799 | |||
| 69ddf50d98 | |||
| 386b5fe6eb | |||
| 25374b7325 | |||
| da3541e88d | |||
| 3bf71817cf | |||
| 8acd8baa33 | |||
| 7c1cda0ccb | |||
| a12b08bd3a | |||
| 341ef1908c | |||
| 18bfce3a97 | |||
| 35729f1717 | |||
| f44690e9af | |||
| 14690d8553 | |||
| 44d0c56680 | |||
| 3a19364b1b | |||
| 9ad409452b | |||
| 47775d87da | |||
| 41bbee50af | |||
| 80fec1898e | |||
| 0ccf783437 | |||
| 35d9ec1c8e | |||
| 4e5eab77e2 | |||
| 29f19e164e | |||
| e1c0003987 | |||
| 4404c371af | |||
| 83ac55585c | |||
| e9a8648ae9 | |||
| f17df2c2dc | |||
| 18c92e855d | |||
| 048ffbe7d3 | |||
| e5818f9865 | |||
| 09b0afe3d5 | |||
| 4f3921d1bf | |||
| 48a799a6ac | |||
| 08ce187c6b | |||
| d3fb648979 | |||
| 2759411565 | |||
| fa8f4bf528 | |||
| eeaea6f03b | |||
| 8125fab8c3 | |||
| 7fe3f102ff | |||
| 53b38a05ea | |||
| 8aada40095 | |||
| 621b84064a | |||
| 91cf6bfccd | |||
| c9785a0ef0 | |||
| 73ea5d6192 | |||
| 752658119f | |||
| 53b3d2bb1f | |||
| e22584cd79 | |||
| 05b6cf11a8 | |||
| 960bc0d1ba | |||
| 745520c03d | |||
| de80ab4910 | |||
| c995c98e85 | |||
| fc3824059b | |||
| ef44869539 | |||
| 4ef540a4e6 | |||
| 56299308b6 | |||
| f7aa0eb745 | |||
| 881590b6d7 | |||
| c78d5b071a | |||
| 6974ce4f24 | |||
| 627a2048f1 | |||
| 5cd592fe06 | |||
| 295c1cd3d5 | |||
| 931e5140e2 | |||
| 574ed67011 | |||
| 5b42ef5b02 | |||
| c6aa4c8fb4 | |||
| 6534020b54 | |||
| a3ed490b7f | |||
| 10bbdc4176 | |||
| 26f046edd5 | |||
| cabfd83031 | |||
| 1518a1dbd1 | |||
| e5b7c28375 | |||
| 2f666d9622 | |||
| 30525bef9a | |||
| e14aaceabe | |||
| c8f4d234ea | |||
| 8dc5510518 | |||
| 6b9fc231e1 | |||
| a0a7c6d88c | |||
| f6438556ef | |||
| 5d4ecfc62c | |||
| de502593ef | |||
| b5bfc150e3 | |||
| bcf92901ac | |||
| c7be59d0c1 | |||
| 218c66592a | |||
| 96e4874bdb | |||
| 0ef1e6b866 | |||
| 0bfc594407 | |||
| fd014845f7 | |||
| 660e414f36 | |||
| 1806cbede9 | |||
| 3aa9706150 | |||
| 939cee7ac3 | |||
| 0f79c7d754 | |||
| 6a96f3f3ea | |||
| ef0a14d093 | |||
| b66b302a6a | |||
| b685071f5a | |||
| 2ea43c9729 | |||
| eb89e875f7 | |||
| 7ecce753a6 | |||
| 8ab25173a1 | |||
| ac16151d22 | |||
| b68fa9919b | |||
| 516eb971a3 | |||
| 22a66ef917 | |||
| 9cf6137916 | |||
| 36995793fb | |||
| 0ddbe50a61 | |||
| 0d839a85c0 | |||
| be10286ae5 | |||
| 4163debdfb | |||
| c4b1bff412 | |||
| 848cb7cfb5 | |||
| 6df47b4d19 | |||
| c09319cab9 | |||
| 175518d248 | |||
| 14ccd72505 | |||
| fb452286e6 | |||
| aa3db11715 | |||
| 250eed3667 | |||
| 5a7be54e31 | |||
| 4227fc706d | |||
| 3e4aa96665 | |||
| b97dfc9450 | |||
| 3c32879211 | |||
| 5d2044ae93 | |||
| b5a8d46096 | |||
| 7a1c14372c | |||
| 9cac5c71ee | |||
| ef8ee7e7ef | |||
| ae62a57f4e | |||
| e3fe5ec788 | |||
| bd1c208097 | |||
| 56c82ac742 | |||
| 321b953877 | |||
| 603615d2d0 | |||
| a4c5f55812 | |||
| 517c5e5bfd | |||
| 514685e9a6 | |||
| 9b1a38aa42 | |||
| 9af9500a0c | |||
| eb4fb0cb5d | |||
| 415eb2496a | |||
| bb5e793580 | |||
| fcc2066d01 | |||
| ad625de65a | |||
| 6f26975964 | |||
| 9a8cbe189f | |||
| 782dd6d45b | |||
| 5ed6f37ad9 | |||
| fceeaca439 | |||
| f46a1041b8 | |||
| 90a26d4d51 | |||
| 90a367e2e1 | |||
| 5273535527 | |||
| c777a6802f | |||
| 267b3e487b | |||
| 4ca05b7aad | |||
| b1d7592e34 | |||
| b6d8a11148 | |||
| 8ca8824655 | |||
| 59df24f63f | |||
| 81b8f0f159 | |||
| e4a7b6e868 | |||
| 773b4d80a5 | |||
| b14aab2fe4 | |||
| a02c29d25b | |||
| ec5c7742d9 | |||
| 6916fd5c3b | |||
| 06e1a61fab | |||
| 93f5de21b1 | |||
| 8350d5d0af | |||
| 0fa7cbe6a3 | |||
| 45d5f42ca3 | |||
| f15c11d440 | |||
| 20d6fdf375 | |||
| c3d5b77c96 | |||
| 9b37416720 | |||
| 163c32fc28 | |||
| a786828ddf | |||
| 23bfe3fe09 | |||
| 732c7f1d0b | |||
| ce83863f87 | |||
| 713c893939 | |||
| 7951713874 | |||
| 42c7a8c6ab | |||
| 99f4928d7c | |||
| 356b89e672 | |||
| 7b79b4cdef | |||
| db4e999d61 | |||
| 346b857c6c | |||
| 936b124ff7 | |||
| ed22af820c | |||
| a5e8bdf451 | |||
| 8b2caa1a2a | |||
| c43e0ecb14 | |||
| 4c40782b30 | |||
| 5c83be026b | |||
| 0a3b46fdf5 | |||
| af58f11739 | |||
| 58d05259cb | |||
| 662bf63f87 | |||
| 947e86f4fa | |||
| a0f5714f8a | |||
| b7ab54776d | |||
| 4a1cb62fce | |||
| bf1aad6a7d | |||
| 93ee85a925 | |||
| 69a95852ba | |||
| 8e4605294a | |||
| 289cf2170e | |||
| 8f6d84e669 | |||
| 21466b9afe | |||
| de39c3b77a | |||
| 374362b25c | |||
| 7965ccd65c | |||
| 893a2d0859 | |||
| fea84ff0f2 | |||
| e06e3096cb | |||
| 0c586271e5 | |||
| 1d4187bd0f | |||
| fe07d43e5d | |||
| 9e40bb3bfd | |||
| 4704c9d427 | |||
| 49087105ad | |||
| dd0ae959fe | |||
| 8f8639aa7a | |||
| e5e35f6545 | |||
| 1ae525bf0e | |||
| fb2f498e54 | |||
| cf2466f185 | |||
| 5ea4a79c06 | |||
| ed32045dc6 | |||
| 1fe93d4e86 | |||
| e933b3091d | |||
| 0a8fd09acf | |||
| 200a9c69ff | |||
| bfc21a4e47 | |||
| 276147ac65 | |||
| 9094ef8b1b | |||
| b4ca4f9cf3 | |||
| a5c397f21b | |||
| d5221dcfe4 | |||
| 847f7587ff | |||
| 061f5a8426 | |||
| 6a2d2601fc | |||
| 0d49574056 | |||
| 10d2a5b770 | |||
| 9b0290012f | |||
| 9db1cd07e3 | |||
| 5b36ba86ad | |||
| f38dfb4e28 | |||
| 38d882d889 | |||
| 4e598bde94 | |||
| 702a31b06e | |||
| b5664b575d | |||
| 0ffaf38602 | |||
| 2eae2f926c | |||
| 96b47442ea | |||
| 93ae3cea51 | |||
| 6895e23eca | |||
| b744916fb8 | |||
| 0febad916b | |||
| 7b44a35460 | |||
| 5e08c5cb5b | |||
| c4238a2fb7 | |||
| 2aa6ff8d7d | |||
| 6d05a9e061 | |||
| f8ca997175 | |||
| 377f70de36 | |||
| 0dbeed4691 | |||
| ca3a3794bf | |||
| 1bcb523456 | |||
| 68a81eed0b | |||
| f9538ea708 | |||
| 03cc15ebdd | |||
| 37b0481304 | |||
| c1d4c1d4c5 | |||
| a7f4957c02 | |||
| e039942a02 | |||
| 1706273d74 | |||
| 23d972d9dd | |||
| 3b50a66d0b | |||
| 969a41048d | |||
| 5fc7981de6 | |||
| d041abd435 | |||
| 9a0f0f438f | |||
| baca67f7a3 | |||
| cb069a418f | |||
| ae4e6226cf | |||
| fda20b8236 | |||
| c5dc486e2c | |||
| 144e84154b | |||
| 5de083e234 | |||
| e4529f9217 | |||
| b511f31d39 | |||
| 4d6e41a185 | |||
| 73740bdbc6 | |||
| b30c9ee4b3 | |||
| 386b63ceb9 | |||
| ebbea8ae40 | |||
| ad7d70ae34 | |||
| c182f4d479 | |||
| 6353d911c0 | |||
| 8c4ce99b89 | |||
| 6c34a2f48e | |||
| f95a872d12 | |||
| 95c59da336 | |||
| 78a151d337 | |||
| cccdb1f6d6 | |||
| 4dce1b28b8 | |||
| 8bac0c2ba3 | |||
| c194579f5e | |||
| 2a3e635cd1 | |||
| 82c3fa3aaa | |||
| 2830225b2c | |||
| cf9ed2855f | |||
| b4edd36ec5 | |||
| 49d1a39d16 | |||
| 23a8d8bf1b | |||
| 1e70c7ac38 | |||
| bf0d4e7154 | |||
| e8fc6ec946 | |||
| be2b52ac8f | |||
| 7bb06e0661 | |||
| b56cad3cbc | |||
| 5bec43f720 | |||
| 25bb76ce20 | |||
| e94efb4a11 | |||
| de438d035b | |||
| 88c9b123ee | |||
| 2c234e63e7 | |||
| bd94258500 | |||
| ee5f2a5475 | |||
| 2806d0edbe | |||
| c51821715f | |||
| 85cbeccd3e | |||
| 147510bb00 | |||
| 450ca7325d | |||
| 3f5fa2d889 | |||
| 2e4860e39e | |||
| 392c7581eb | |||
| 81f0d2464c | |||
| 58a93485de | |||
| 23c4395731 | |||
| 0a20822e64 | |||
| cdc9002e41 | |||
| f8ae534480 | |||
| c6f3793178 | |||
| 96451fdb37 | |||
| feb47b3bb1 | |||
| 4f02439cb1 | |||
| b0e8f9ff56 | |||
| 74a7f5d065 | |||
| 8cc988f172 | |||
| a14e1de6cc | |||
| a30e3a7e94 | |||
| 450f9db5c6 | |||
| eca7dc5b27 | |||
| e51df22a48 | |||
| fa3b613148 | |||
| d4a6b3ab85 | |||
| c295b15d7e | |||
| cf48df0f49 | |||
| 16a94230d2 | |||
| d226ebb036 | |||
| 2c658704eb | |||
| ea1eacc952 | |||
| 161ff1c6b0 | |||
| eec4df655d | |||
| bd0ca7917a | |||
| 5af34cc0da | |||
| 69f491c008 | |||
| 1f848288d8 | |||
| 9cd8e34252 | |||
| 5137b37f86 | |||
| 16086b3349 | |||
| 153e0f6d48 | |||
| f44a019aed | |||
| f826fbc2d9 | |||
| f03f1c237b | |||
| b4c23f8ebf | |||
| dd8985b92d | |||
| bf9d59fe21 | |||
| 9fcd20505c | |||
| a142d30a9d | |||
| c3658bd810 | |||
| 6e7d9062cb | |||
| a6438d91b4 | |||
| d2d16360c1 | |||
| 3b277785c0 | |||
| c94bc0c5c8 | |||
| b1495e485e | |||
| 6d6ba0c668 | |||
| 0bc09d7d86 | |||
| 563f2e3594 | |||
| 6ba83d0891 | |||
| f21962defc | |||
| c3719a2eca | |||
| 3b58cf8c0e | |||
| b390f1ef73 | |||
| 02fd903228 | |||
| 52ca0dd3f6 | |||
| 6a874b283c | |||
| fd238f3e40 | |||
| 438036550f | |||
| a0e14bd523 | |||
| c8a76b7dd5 | |||
| c86c3ce16d | |||
| dd48772c9e | |||
| 53833582b7 | |||
| f262b76a41 | |||
| 441e17174d | |||
| defd58bc77 | |||
| 38f2897c29 | |||
| d9d019c5d4 | |||
| f23152d7a7 | |||
| d625837eb9 | |||
| cecd35e20b | |||
| 5ade799440 | |||
| 2786b195ee | |||
| ad6f51646d | |||
| 328190ca63 | |||
| 5b5649de74 | |||
| 78003d863a | |||
| 71c635dedc | |||
| 5f5518e05b | |||
| bd33305e5b | |||
| aa8bd8a8ba | |||
| 84cdad7f7d | |||
| 3c38ca5a1b | |||
| ffaf3e7d91 | |||
| a81a6fc0ec | |||
| 6c3559792c | |||
| 6292ead1f7 | |||
| 9a15ceadf6 | |||
| f61e9a9941 | |||
| 21a113f38f | |||
| 4f3bd6f9dd | |||
| d2c80f4d1a | |||
| 2949d86908 | |||
| 0fcbdbf0fe | |||
| 1dc22a9e8f | |||
| 5c769d2d24 | |||
| a2e63b7f0b | |||
| 44c33f1618 | |||
| 4730d7087f | |||
| 3b31a0234e | |||
| cac5b2ca97 | |||
| 3b08f13bf3 | |||
| e51bb180d4 | |||
| 4e97b6b47c | |||
| ed6ee71ded | |||
| 6c69295696 | |||
| fb72939392 | |||
| b61692f121 | |||
| 9ff2549315 | |||
| 3a4eb97315 | |||
| 4f58be6548 | |||
| 33bd62d32f | |||
| c547c88e89 | |||
| 2a4dcce444 | |||
| b41d008223 | |||
| a144ad9a1e | |||
| 93be0562cc | |||
| 64bb988613 | |||
| 3fcff1b1b3 | |||
| 6150ba4860 | |||
| 676307027c | |||
| 976f16c4d9 | |||
| b88e90fec3 | |||
| 2103459845 | |||
| 348eb1e187 | |||
| 1fb6ad5488 | |||
| 328aa2cc45 | |||
| 2deb2ea0f0 | |||
| bc1ab2d79b | |||
| f3e77eea3d | |||
| 6b0e717a19 | |||
| 906a9748b5 | |||
| 414c33ffc9 | |||
| 77f8c5cbf2 | |||
| 3f5d7030cb | |||
| c53c3afd46 | |||
| 33fd7f0c67 | |||
| 853f0a13e9 | |||
| 9569ad645b | |||
| 3a98117aa5 | |||
| 42092bc91e | |||
| 2d6f46dfa8 | |||
| f1f400bcee | |||
| a6e289c8ef | |||
| a83ec513a1 | |||
| f043a8789c | |||
| 30bbef4b14 | |||
| 26fb62c748 | |||
| 77c0e85775 | |||
| ac45276835 | |||
| cfa242a6a5 | |||
| 26599981a0 | |||
| 8fe2191d04 | |||
| 35b4c6c6b8 | |||
| e42ccef4a7 | |||
| 8449139061 | |||
| 16e7e60cab | |||
| c53988d01e | |||
| 1fea8b38fc | |||
| 7d6cd9ae7c | |||
| bd70c33606 | |||
| f2a0ca2b0e | |||
| 282543b759 | |||
| 15748575d8 | |||
| cc9655af45 | |||
| 465bf1c10a | |||
| eb1200a2cd | |||
| c1a71e53f9 | |||
| f5fe661c13 | |||
| f42e5c4814 | |||
| 135a4ab58c | |||
| b192207132 | |||
| 3464e84e90 | |||
| a0ee98cb4b | |||
| 01d7a64670 | |||
| cbafcb5aa6 | |||
| b604bf2d7a | |||
| 05efca8430 | |||
| 007f125e46 | |||
| 83dd618e5b | |||
| ffc992893f | |||
| b04e3d6cd6 | |||
| 5e19f9707b | |||
| 457d07a50f | |||
| 3262a4e103 | |||
| df27c80c72 | |||
| bc54e34375 | |||
| 49deb08b81 | |||
| b8fbe8341f | |||
| 07e46fb8aa | |||
| 0ee86b72fb | |||
| b54c43b966 | |||
| 1b82e5cba7 | |||
| 8a825ee775 | |||
| c91b667c13 | |||
| 32611749b2 | |||
| dd9e29c425 | |||
| 8debe6ef1d | |||
| bab56b0d88 | |||
| 0b43b4fdc2 | |||
| 210fb3539c | |||
| 026f3f2aef | |||
| 9b5d0a50f7 | |||
| d3df13225d | |||
| fb2ebab793 | |||
| 2f71efe6a7 | |||
| 7813d6fdd7 | |||
| 8ce92e1bc2 | |||
| 9316a5c23f | |||
| 64684b6b71 | |||
| f133bfaf9f | |||
| 3f174e0bd0 | |||
| 39a0e3b29c | |||
| ac8e86643e | |||
| 6a51ea96c0 | |||
| 94e2d9059a | |||
| 85c67ca048 | |||
| 99a5a8370f | |||
| 284ebcc23f | |||
| c156f29c86 | |||
| e075fcd4f3 | |||
| 49a8c459a8 | |||
| 1e45a4c9f5 | |||
| dd825831c7 | |||
| 1b17161758 | |||
| 908971e48b | |||
| ca76e83370 | |||
| 4774f44062 | |||
| f198acda79 | |||
| 86a564094c | |||
| f2c5dd8d71 | |||
| ed8ef96a61 | |||
| 87a1ae56d7 | |||
| 63331e705a | |||
| 6f447c2b6a | |||
| f415e99a36 | |||
| b699ad9ae1 | |||
| 632a762654 | |||
| a4a3bc72fc | |||
| b809739d8c | |||
| 7ad2a4c3f2 | |||
| 4c4332c88b | |||
| 6c0ef59a30 | |||
| 83714d4d03 | |||
| 7498ef647c | |||
| 321dfcf741 | |||
| bdc6fcf5dd | |||
| 50cd61e7c3 | |||
| 125796fec7 | |||
| d1d0e1c732 | |||
| 820fd1c13a | |||
| 577373aed9 | |||
| d1865a2c1e | |||
| 60efef0caf | |||
| 71c53d9f3d | |||
| 11a58a55c3 | |||
| fc099a35ab | |||
| f992fe0b8d | |||
| ac99f9e46c | |||
| 225df7593f | |||
| 5ecad32251 | |||
| cfd44fc50c | |||
| 20f47863bf | |||
| c6cfbd4e8c | |||
| 8422056873 | |||
| 80ba651375 | |||
| 18e5bf9c07 | |||
| 0394180213 | |||
| b52be989ed | |||
| b15597dbe7 | |||
| 6aa4ae880a | |||
| 01d2d77a76 | |||
| 640a49e1ce | |||
| c8cf6df4cd | |||
| 7f0a1a1caf | |||
| d9942c0c32 | |||
| 587d573a04 | |||
| 391adea516 | |||
| aad088e588 | |||
| ed31e39491 | |||
| 34345b47d0 | |||
| 873a2c8dda | |||
| 838bef63b3 | |||
| 6d97118181 | |||
| c1544ba7c4 | |||
| 008e02b03c | |||
| 2e68155c6d | |||
| a53e880346 | |||
| 79f4bb679e | |||
| 21baa41ccf | |||
| d20ccf186e | |||
| 3128aadfe0 | |||
| 03da97b0b8 | |||
| 2d39b3c2d0 | |||
| dada8dc1db | |||
| 5b47785ae4 | |||
| c18e92df67 | |||
| 8828ac5d30 | |||
| 83d717bcae | |||
| 21f9524b3e | |||
| c7078a3e10 | |||
| 1bbd9675b6 | |||
| 87db306da0 | |||
| c41da878f9 | |||
| 0a17e5ab7f | |||
| 2f356fd916 | |||
| 1bf52bda9e | |||
| 89117a326c | |||
| 51bc877b4e | |||
| f5772f0423 | |||
| 95596a53b0 | |||
| c114ad9aa7 | |||
| bb9c35ffea | |||
| 6b426b5f83 | |||
| 9e215a3493 | |||
| 3321873fc6 | |||
| fc57cac746 | |||
| dbdd00fef8 | |||
| 0986cb46d9 | |||
| e55384067b | |||
| c905f0658d | |||
| 99fca41f02 | |||
| eb666a62ac | |||
| 6e660e4c27 | |||
| 00bf89e1d2 | |||
| 48a98d8b1f | |||
| 1a8421bbfe | |||
| ecc4bab8f2 | |||
| b5a64f2fae | |||
| 7e11cfb891 | |||
| cdcfbd8ab2 | |||
| 9964005525 | |||
| 3dd8898aaf | |||
| d3acfdfa07 | |||
| cb0eeaeb32 | |||
| b114ba4ec6 | |||
| 688683fdaf | |||
| f0740d8235 | |||
| bf33ac89eb | |||
| baeee68d27 | |||
| 25d1f542d7 | |||
| 1b919575f2 | |||
| f7e49cfb04 | |||
| c3cbbcacd7 | |||
| d030b978ab | |||
| 1acb811437 | |||
| 1bf7be4d2a | |||
| 44096d2f95 | |||
| 136cb036b4 | |||
| a1bfcd1216 | |||
| 277173ae0f | |||
| 28e6e63c5d | |||
| a49623136a | |||
| 9041f3ed1f | |||
| bc759b5bb3 | |||
| 0d70b12c75 | |||
| b471e74ef8 | |||
| 745412ffb8 | |||
| 680c125dde | |||
| d072cdd527 | |||
| 570126f8ff | |||
| 5de828fa15 | |||
| 32f3411eca | |||
| 7509e66617 | |||
| 92d65a529f | |||
| 51590ad30f | |||
| 7af70745f3 | |||
| 936c25c98b | |||
| fcbfa307ef | |||
| 534b655291 | |||
| 5a0fa236cb | |||
| d17845d767 | |||
| ecd20983e8 | |||
| 66b200178f | |||
| 7dca6e0b04 | |||
| 60b6fb3d39 | |||
| 9d1a3eff16 | |||
| e560f2329d | |||
| d58602289d | |||
| 8845f347d3 | |||
| d6611f02ba | |||
| 3ed9dc6a94 | |||
| dbfc58c5ed | |||
| aedad2ccb0 | |||
| 1aa79965c7 | |||
| a7ec5d9b71 | |||
| 4afb2919fa | |||
| 52d6092ffd | |||
| 4bef99703a | |||
| 1afa21922f | |||
| d3cb3eccff | |||
| 937d727011 | |||
| ca7f175fb7 | |||
| 81f5e4c039 | |||
| 2f4ed00c93 | |||
| cb1b1daacd | |||
| 6862cc0ce9 | |||
| 6ff8bda568 | |||
| 8e78937160 | |||
| d7bfb88be9 | |||
| 46654ba28a | |||
| 34889dfb6a | |||
| e2a3b89175 | |||
| 6a51a05171 | |||
| 09bfa883ac | |||
| 6f0268171d | |||
| e0da616e37 | |||
| 224f0a0684 | |||
| f928f6c161 | |||
| 4e5203a3dd | |||
| 58363c9dab | |||
| 0e7024488d | |||
| 6310a6040b | |||
| ec31e714d6 | |||
| a80d3bcf38 | |||
| ad9b41e45e | |||
| 9d643387fb | |||
| c570beefbd | |||
| 6f97972582 | |||
| 736368f441 | |||
| 8975be38ae | |||
| 7aede726ca | |||
| 228150cd72 | |||
| 9f4f9e7b2f | |||
| 629de5c931 | |||
| 30af256bb6 | |||
| 7340c86c61 | |||
| 187c6692d8 | |||
| 0c5de08870 | |||
| 36a6d0c93c | |||
| 2d66b73e34 | |||
| 18517c1fe5 | |||
| 69dfc4fe32 | |||
| d7fe272673 | |||
| 40add040f9 | |||
| 766d7138ac | |||
| dc3fb38cbb | |||
| eb1e734628 | |||
| ba95d49a67 | |||
| a90aee32a0 | |||
| 8a9502ce01 | |||
| 8d46c4debc | |||
| fe2ab99c52 | |||
| a5467f201c | |||
| 976c3bbe98 | |||
| 551de62f42 | |||
| 860df74295 | |||
| eca4117497 | |||
| 434226dd01 | |||
| e770997d09 | |||
| 52d42bca30 | |||
| 3b5eba1c85 | |||
| 76af0aa6ed | |||
| 4a6e000a07 | |||
| cf2fbcb6e3 | |||
| 11c2f8c991 | |||
| 0d3182c278 | |||
| 1d2a21fa1f | |||
| c6763e76ee | |||
| 818c1ea9e9 | |||
| 0b4d0fcf67 | |||
| 384c4b998e | |||
| 449bd78db7 | |||
| 5d2227d3a6 | |||
| 0058449576 | |||
| 2059a57d96 | |||
| 8bb9ab629f | |||
| 73c536fa04 | |||
| 2d07bbdf2c | |||
| 83e7cf54f4 | |||
| 54725d30b1 | |||
| e688cc520b | |||
| ec5e79f86b | |||
| 87d56eb866 | |||
| 2922488eb9 | |||
| b8230bf5e6 | |||
| e66a3625b4 | |||
| 61ed256846 | |||
| 31bafccb6c | |||
| db709dc4dc | |||
| 9461d8ec13 | |||
| 834eb4c1b6 | |||
| 21ab738c72 | |||
| 620a465f84 | |||
| 0c760dc107 | |||
| ad7ea01ee8 | |||
| 1026821e33 | |||
| 302bdd366c | |||
| e5241d93e5 | |||
| 6804f40bc4 | |||
| a18fc4fd93 | |||
| 315dfd2041 | |||
| f5513abfc8 | |||
| 0296999ec8 | |||
| b2a44942a8 | |||
| 268e4d5ec9 | |||
| 4f562dbbfb | |||
| e9127c0427 | |||
| b2545f4d89 | |||
| 9c922e0c73 | |||
| d6721ea8ef | |||
| c8503d149e | |||
| cd045df1c3 | |||
| 20b226769f | |||
| 8460428f2e | |||
| d7f63afae7 | |||
| 6ad1a5b57f | |||
| a2388cc4b4 | |||
| f79ee4b582 | |||
| 03fd848f18 | |||
| 258a44de1a | |||
| 20a04408a6 | |||
| 662356311a | |||
| 806cba6352 | |||
| b42e00961b | |||
| fc0089c0f4 | |||
| 2c9b70a674 | |||
| 0bb0cb7b93 | |||
| 0e9a8e6c3d | |||
| c7d39c7975 | |||
| 86abaf4009 | |||
| 382c3d1787 | |||
| 2ac8e7e496 | |||
| 2425ad39ef | |||
| 6b5b86f343 | |||
| 230645ffa5 | |||
| 3861eada88 | |||
| a1691fda9b | |||
| ec7d64d30d | |||
| 8cda08d41c | |||
| 05fe040f88 | |||
| 756cc86a23 | |||
| 9e470dffc3 | |||
| 6e2080f092 | |||
| 24a0b73ce3 | |||
| 473c0eecb1 | |||
| 10baa77dbc | |||
| dec333d063 | |||
| 61d85c75d3 | |||
| 8dab22328c | |||
| ac0991a7cc | |||
| bc276b2bc1 | |||
| 1e6415ce45 | |||
| e4f6408939 | |||
| 497bb74d5a | |||
| dee939e78c | |||
| 79aa1535f3 | |||
| 9f2902e9d2 | |||
| ace6574179 | |||
| 8ac82843af | |||
| 3e4acb6921 | |||
| 3a41b51160 | |||
| c0ed9be287 | |||
| bb9a9fb06d | |||
| 1a0edab86e | |||
| 673ac3faa9 | |||
| 3833b9b585 | |||
| 6ba9224f32 | |||
| d138a49895 | |||
| 0e434f0212 | |||
| f807067337 | |||
| 5e5800363e | |||
| d643cf8c1d | |||
| 7a37ee7c30 | |||
| d42e7a6d0a | |||
| 115506476b | |||
| fab9df7825 | |||
| 0873562023 | |||
| ca890b509a | |||
| 59fc14c57c | |||
| 907ad64f96 | |||
| c96ad24a35 | |||
| 9a7694f32a | |||
| 73e9110b64 | |||
| 90439fc8c4 | |||
| 1a480445c9 | |||
| adf066acdd | |||
| a2d11d8100 | |||
| f77b8a9137 | |||
| ad0241047d | |||
| 6218b00486 | |||
| 4585f14b5f | |||
| c0af9c2bf1 | |||
| bf2adc6861 | |||
| 743a4eaf02 | |||
| 4df07ae61f | |||
| 6c1d1db4b4 | |||
| 11ac94d449 | |||
| a84a41bc75 | |||
| 5f61c348c2 | |||
| ffdc440926 | |||
| 3457fcb48b | |||
| f70700c330 | |||
| b28727ef8c | |||
| 3af33c8b75 | |||
| 9059dd7e3e | |||
| 2d0f686964 | |||
| cf896e8064 | |||
| 2422ec276d | |||
| c00aa2d807 | |||
| ab400de069 | |||
| 829a28c986 | |||
| 666850a6bc | |||
| 89ff51cc09 | |||
| c0ea316f44 | |||
| 7fae03e300 | |||
| 728d858f15 | |||
| 2029981f00 | |||
| 3e2e67d88d | |||
| 4fd5e3dc74 | |||
| 17a02b8fbb | |||
| 75a174bc7b | |||
| 086e01fcb8 | |||
| a219428887 | |||
| ca86b0acf9 | |||
| f20df8a492 | |||
| d742b306d7 | |||
| 119c647097 | |||
| 64c6fa6525 | |||
| 5a7965468d | |||
| 855ccbf300 | |||
| 855d52908b | |||
| 1440302ab3 | |||
| 9e055bd52f | |||
| d4a36c2e0f | |||
| ef9c8a4716 | |||
| cd21a5ed8a | |||
| 1d0c9511a5 | |||
| cd73b37673 | |||
| f970ede20b | |||
| 9308382295 | |||
| caf0a2c143 | |||
| 06cb649b55 | |||
| e216675ca1 | |||
| fec546e939 | |||
| e7fb2a2c7c | |||
| 1bc6f6eeda | |||
| afc46ac1d3 | |||
| 636e47d219 | |||
| 9c219d647d | |||
| 99da16b834 | |||
| d8e5697bfe | |||
| b504a88459 | |||
| 3745686f38 | |||
| fda2e2d34d | |||
| 2f4da0f0b0 | |||
| 327e60b275 | |||
| 2450bac944 | |||
| 46fe0fbc29 | |||
| 8f30f628a0 | |||
| 27ba7608db | |||
| d2cd341615 | |||
| 978e3e6e81 | |||
| 5099bebba5 | |||
| 6951f13ce4 | |||
| ea76a9f88e | |||
| 35ed9727d3 | |||
| b7ddc30244 | |||
| e525cd4465 | |||
| 3898752f67 | |||
| c0b11f6eab | |||
| b6d9bf7319 | |||
| 16e4a3c10e | |||
| 4b00999550 | |||
| c5797b916f | |||
| 7a6385b614 | |||
| 5391aa0fa2 | |||
| 06659f1dfc | |||
| eec001cad4 | |||
| d953614fe4 | |||
| 82070b999c | |||
| cbf46c9ec4 | |||
| 13347878df | |||
| 343d9fd63f | |||
| 4d1ab8f4ba | |||
| f7ff4d6cc7 | |||
| c1717498f4 | |||
| 74a57d9e12 | |||
| df3bfb2771 | |||
| 76dc77106f | |||
| 265df9d0f2 | |||
| e4352e3c5a | |||
| da44de59b9 | |||
| 8180ca7a9d | |||
| 71125e4833 | |||
| 5408c387ba | |||
| 8df3425a2e | |||
| eb4e4b6b05 | |||
| 166563d343 | |||
| f6dcef3b49 | |||
| 299015ae5d | |||
| dbc4beb71a | |||
| 7d23d0c5b0 | |||
| ac9d618188 | |||
| 87cd21f1f8 | |||
| a54dc98fad | |||
| 392b535cf0 | |||
| eecce3f414 | |||
| bea31d6487 | |||
| bd51ec2c87 | |||
| 75c461c8f9 | |||
| c8d4f578af | |||
| 4b242b57c8 | |||
| 6a5e3bf70d | |||
| 43bb81fd82 | |||
| 1f6d0347cc | |||
| 0826d6de53 | |||
| df5905ace6 | |||
| acadb46e6c | |||
| ccee2254e0 | |||
| e26b497ccc | |||
| 5e49ae47a9 | |||
| 1d79c8dc53 | |||
| 7bf7f4bbe5 | |||
| bba1cb3859 | |||
| 36b77224c5 | |||
| b310b6745d | |||
| 9ef345f02d | |||
| 8649c899db | |||
| ed9f98bda1 | |||
| 2e1dcf1479 | |||
| 90b02a4f6c | |||
| 16b634a7fc | |||
| 873176a3e6 | |||
| 6c30d76401 | |||
| 9bc6fe4e7a | |||
| 013a31afdb | |||
| 57b0050ae7 | |||
| 61a105af21 | |||
| 51a6c25e16 | |||
| 0e3ff45eb9 | |||
| 77e7c6f60f | |||
| d09deab2f1 | |||
| 3e77a6301d | |||
| 3e89ecfdf6 | |||
| 644fffd69f | |||
| a84dd0068c | |||
| eb05af8e74 | |||
| 7c6c5fe445 | |||
| 191c80211b | |||
| b13164b2c0 | |||
| 28456d5486 | |||
| eb99e12003 | |||
| 058529526c | |||
| 49cf104a12 | |||
| b639466adb | |||
| 1cf86b9641 | |||
| f894771e7d | |||
| 451a4762df | |||
| 92313a2d64 | |||
| 94743678a9 | |||
| 4a6e5ee331 | |||
| b284eab745 | |||
| 6969cf239a | |||
| 2b3b68605e | |||
| 738735b808 | |||
| c1034b9344 | |||
| 42e6c413b6 | |||
| 4e75362d4b | |||
| 9bbfa99b4c | |||
| 1f49f40faa | |||
| 69735ce1a5 | |||
| 8d1ac59134 | |||
| 3407a01845 | |||
| 485a114a2d | |||
| 4ae082bfc7 | |||
| cbd6277844 | |||
| 96f04b41cb | |||
| ba9338c522 | |||
| b39cf878a0 | |||
| 20bf1d71bb | |||
| 313a167729 | |||
| ca342d8de2 | |||
| 0c2dd78f3b | |||
| 3c81d0423e | |||
| 3fcc420e08 | |||
| 65c099c02a | |||
| c197a4a62c | |||
| 60fbe881c1 | |||
| e96365a4bc | |||
| 1e865deaaf | |||
| df98467eaf | |||
| 7265a5f3c0 | |||
| 0ac1983b66 | |||
| a0e8906575 | |||
| f13dc2777d | |||
| 0f588a8d97 | |||
| 6ce3443a34 | |||
| 1e448915d1 | |||
| a9124f0a4a | |||
| bd1adba17e | |||
| 39cb30a4be | |||
| 6ced31f8b5 | |||
| 74ceb06336 | |||
| ee35d8ada2 | |||
| 4e92674be7 | |||
| a39d25f6c1 | |||
| 0147e59899 | |||
| a08faa038f | |||
| 42189e5c52 | |||
| 6c05ba06ff | |||
| 1a75a82523 | |||
| 8b5b6d3636 | |||
| fd8b0ba57d | |||
| 187ae2fe0e | |||
| 4a6a601b5a | |||
| 5631c4d214 | |||
| 6be5ea55ce | |||
| b43e2f9190 | |||
| eb81a302b0 | |||
| 6b8f9a0d07 | |||
| 7d8b071049 | |||
| e143b5d142 | |||
| 929e23b74e | |||
| 07fb4b1e5b | |||
| f652969936 | |||
| 65c0b60e5f | |||
| 5b76e3e70f | |||
| 99d7c597b6 | |||
| 5e7e0d7b2a | |||
| e377cbad38 | |||
| 0824ceacd9 | |||
| 4ddb327597 | |||
| e068eb8bd1 | |||
| 0a9cb8d248 | |||
| bb1711de60 | |||
| 8c85cc598d | |||
| 5883e3db52 | |||
| 2894f50005 | |||
| 87a9c29cf7 | |||
| 471e30d85e | |||
| 3330ba77b1 | |||
| 62df1e933b | |||
| d23b3123ba | |||
| 2d73bd9927 | |||
| ca379f0814 | |||
| c5b3ed12a0 | |||
| 0e177e766a | |||
| 15234069fe | |||
| 45c531c463 | |||
| 01d0b1767c | |||
| 45f247393e | |||
| c8967b4b5e | |||
| cd40e70901 | |||
| ec3c5c7774 | |||
| 69c4f021c9 | |||
| a2fb5d5cbe | |||
| 0261a0b795 | |||
| 3b2ffd1a07 | |||
| e20b40ee61 | |||
| a882435757 | |||
| afbb95d987 | |||
| 74f9163b24 | |||
| cda26929bd | |||
| f9a6120685 | |||
| 979da57982 | |||
| 33e923540a | |||
| c384b746f7 | |||
| 4d9cf433ff | |||
| 380cdf687a | |||
| 722fb64245 | |||
| 67b0c98578 | |||
| 9f6f56f3ff | |||
| 91a6beb749 | |||
| a5cf22af80 | |||
| cc6d4c0c06 | |||
| 0b0a187967 | |||
| 966643a542 | |||
| 04569d27b7 | |||
| f55a3c0b3d | |||
| 579a173fbf | |||
| fa4bcd0cd4 | |||
| 8acd0300cd | |||
| 65f12f1df5 | |||
| 551fe6ebc5 | |||
| 95c06276cf | |||
| 403ece5588 | |||
| fce27dc4de | |||
| b41cef3631 | |||
| 3eeae90472 | |||
| e366a6eed4 | |||
| 90c8be1fa3 | |||
| 669ce539dd | |||
| ccef3f6d9f | |||
| c1b38a9203 | |||
| 3f159872c0 | |||
| 9a836af0d0 | |||
| 4e486b1f59 | |||
| 217edad33c | |||
| 89a326ebc5 | |||
| bce75ae3a8 | |||
| 9bf17256fb | |||
| 027cd21aa1 | |||
| 391b3eef11 | |||
| 4bf8491d01 | |||
| a62ac4df3a | |||
| 9a7206b971 | |||
| e23f26a8f3 | |||
| 490d38c9f1 | |||
| 02418f7498 | |||
| ca21c26638 | |||
| 00a9973ca8 | |||
| 2ee1d5fca6 | |||
| d8b046a69f | |||
| 08bcb4249d | |||
| 35f5503e26 | |||
| c0b90df335 | |||
| bea15392ec | |||
| 52de20c3b6 | |||
| 365e662472 | |||
| 89758558cf | |||
| 8d5ddc0ddf | |||
| 9d2617d9a0 | |||
| 6b17652197 | |||
| 6c2a73ebda | |||
| ad45701790 | |||
| ad3b6a04cc | |||
| caab4a3f41 | |||
| aecc283cb5 | |||
| 87c9e523c7 | |||
| 90451d9635 | |||
| e567af9b24 | |||
| dfae0be7d0 | |||
| d62a38e533 | |||
| bc8ee80491 | |||
| 915e34b32b | |||
| 5099a91a21 | |||
| 6f9ab0dea5 | |||
| f90c3d0350 | |||
| 66d375b3b3 | |||
| 233d71fec7 | |||
| 14f3f82555 | |||
| 22fec82616 | |||
| fcfdb18914 | |||
| 23d17d56e9 | |||
| 4d50d21f78 | |||
| 722285bd8f | |||
| 2bd8f97709 | |||
| b4aae47556 | |||
| 1d546dbd83 | |||
| 9fbb2607a1 | |||
| 442d4c9e35 | |||
| de7999c932 | |||
| 03cf88211e | |||
| ec4d9bbcb9 | |||
| 2df1260c87 | |||
| 6e762c1ae3 | |||
| 2db3a828d6 | |||
| c62cf3c82d | |||
| 5da9cd2205 | |||
| 883d92940f | |||
| f53e19589d | |||
| 8e6b694d6e | |||
| c298892833 | |||
| 971997fbc1 | |||
| 8b87d39c72 | |||
| 1124cf3a03 | |||
| 3691c3cc98 | |||
| 072734f7e8 | |||
| 0b34c336f7 | |||
| 6b64959309 | |||
| 704cab010d | |||
| 3153bfd916 | |||
| 493c34dfb9 | |||
| 346cdbfb18 | |||
| cb9fdc66e3 | |||
| 07aedd4bb2 | |||
| 8881f8bd91 | |||
| ee2b9fc885 | |||
| 250109b215 | |||
| aaa8a45658 | |||
| e683e1ab1c | |||
| 23a116b96e | |||
| 29014acd87 | |||
| c4ccb4a8ca | |||
| b392b2a867 | |||
| a7de7bcf31 | |||
| 371b1b01cb | |||
| 08062bc3c5 | |||
| bac11af00e | |||
| 69ccebd108 | |||
| 7f3f471f12 | |||
| 9f7eb9eecb | |||
| 86f50b36d6 | |||
| 0eca73234a | |||
| f346815b18 | |||
| 5e9325fad1 | |||
| d668f7749f | |||
| a34d15da01 | |||
| 7bc4564029 | |||
| f302d055e9 | |||
| 9cb258d920 | |||
| 4b8e9cf7d1 | |||
| 9b33c46995 | |||
| 6ae06014c5 | |||
| 32cd28829a | |||
| aceebd88bb | |||
| 7ad0b27460 | |||
| 635374075f | |||
| d3672ded33 | |||
| b5f68770a3 | |||
| 1bd35c2b55 | |||
| 1242430e2f | |||
| 771bf92f78 | |||
| 042f455113 | |||
| 57464209b8 | |||
| d6f35d7c5c | |||
| 1f73d0d258 | |||
| 7f9545754c | |||
| 1e22e6d203 | |||
| 496f1d91d0 | |||
| 5a38178db2 | |||
| 55b4291df0 | |||
| 5c419ea37f | |||
| 02ccad8fbc | |||
| 9a8e9dc34b | |||
| e6aae4aa5f | |||
| b8458246b8 | |||
| 287416006a | |||
| 1a1dda1796 | |||
| 3fd0b3ba42 | |||
| 77712a63ad | |||
| caf9c39afa | |||
| 0db07e14d6 | |||
| 988d512b77 | |||
| 06c632fa50 | |||
| f750bcefab | |||
| 4946bbcf97 | |||
| dcdca3338d | |||
| fbbd5dc9a6 | |||
| 913319d9e3 | |||
| 3919d03f97 | |||
| 5c19b67791 | |||
| a55fa0d833 | |||
| 8e1489d85b | |||
| 797d537cb8 | |||
| b6618577c7 | |||
| 0cb76eb275 | |||
| 93cea27ad8 | |||
| 263326ecbe | |||
| 61c85465b9 | |||
| 25c33df302 | |||
| 7d5a47afe9 | |||
| fc7802ea0f | |||
| b2ddd93191 | |||
| d9a9624c6c | |||
| aff09e3e34 | |||
| 6db993b589 | |||
| a454a51939 | |||
| 6a1e38d831 | |||
| cb6943010a | |||
| 6929464500 | |||
| 6e956f6cc3 | |||
| b080a339a6 | |||
| 5de2add9c3 | |||
| de77db64fc | |||
| 555885a3b0 | |||
| f6ec749e96 | |||
| a5b8f5af68 | |||
| fce7c3cc39 | |||
| 4050d495ed | |||
| 3378f0de19 | |||
| c05e7134ed | |||
| f8a6287322 | |||
| 6c6a9a073f | |||
| 9c309707a7 | |||
| 9c1e4a0e70 | |||
| 7298cd1110 | |||
| e672f9711f | |||
| 740ad8c1b2 | |||
| 62310f6b21 | |||
| 9c2de843b5 | |||
| a905bf35a7 | |||
| bd1932f12c | |||
| d272bd4e05 | |||
| 67e42e8600 | |||
| 078d8b607c | |||
| 7c001bf468 | |||
| 2eef3ac5fb | |||
| 63cc2150a0 | |||
| 2476dd4474 | |||
| b954d65b8f | |||
| 1b62aa5a79 | |||
| 48d1219f5c | |||
| 210e88b511 | |||
| 21960157ae | |||
| 73322272fe | |||
| 4d12a0bfdf | |||
| b632880fde | |||
| 707b722c36 | |||
| dd3ca3aa63 | |||
| a4c3028881 | |||
| b4b0d52ffb | |||
| 492afc0f9d | |||
| 38b3f73a85 | |||
| 2319629592 | |||
| 802ac99d0d | |||
| e91a1198a0 | |||
| b835a6b564 | |||
| 2687579986 | |||
| e05f635db5 | |||
| d3f1f2a341 | |||
| 4886a7c0fe | |||
| 93ad9161ec | |||
| 39633a0f09 | |||
| f8baaaf617 | |||
| 354e017a33 | |||
| 3d9d4ce7be | |||
| 530b65e51d | |||
| af6bed4995 | |||
| f7f981d549 | |||
| 1454050eef | |||
| 8c80e6c2f8 | |||
| b4237e51dc | |||
| 7af432c313 | |||
| 833462a84e | |||
| 222eea66fa | |||
| 072626d390 | |||
| e4dedb226f | |||
| acde0b6311 | |||
| 8cb57d43d6 | |||
| f597f96152 | |||
| 0f5b5f1f6c | |||
| ea0a9ae7ab | |||
| 98abf1d812 | |||
| f1b9327123 | |||
| 497b9deadc | |||
| 2e723a700d | |||
| 5b558714de | |||
| 2641f7fe88 | |||
| 80bf1491e1 | |||
| 22cf3afdfa | |||
| f2084098e2 | |||
| 00e998e5f9 | |||
| df7f115415 | |||
| 0467d48201 | |||
| 41074331ed | |||
| 034469197c | |||
| c80acdf88f | |||
| 7b9fbc36e1 | |||
| ecd4f30e41 | |||
| 8682d0293a | |||
| 28ddc5db69 | |||
| 9e23045867 | |||
| 08758e9129 | |||
| 14404dff66 | |||
| 7b0e63b123 | |||
| 3b52247058 | |||
| 4c5fe41f2b | |||
| b4ebd87229 | |||
| d5086e07a0 | |||
| b4698b7cca | |||
| 510083f0ea | |||
| e7f300bc7c | |||
| 45773a987d | |||
| 9f8910c258 | |||
| ef462dbb5e | |||
| d38da7ae3d | |||
| a9fe0f2d23 | |||
| 5e4dbc66dc | |||
| e85f337b2f | |||
| a7d36f9f9f | |||
| e6ef4109c8 | |||
| fc7b62e329 | |||
| 3cfda55a69 | |||
| 64a8418674 | |||
| c3e1f137e1 | |||
| 0b1819cdc8 | |||
| dcf642ffb0 | |||
| 21be3e3912 | |||
| d6cb167a0c | |||
| 1177dc94b8 | |||
| daa9c3c13c | |||
| 9d5184bae4 | |||
| c7906b2d61 | |||
| 0b1ddb45a2 | |||
| 3cec6af4a8 | |||
| 8474486b74 | |||
| 695119b3a5 | |||
| 863de62880 | |||
| c716994cab | |||
| db6a90d956 | |||
| 4d847a04a7 | |||
| a60ac679a0 | |||
| 8a5f927d8d | |||
| 073e685b0d | |||
| a7089873e9 | |||
| c2c7f7d71c | |||
| c2c923ba11 | |||
| e45d934cb6 | |||
| f35ff8f583 | |||
| 6b29b3c817 | |||
| 317f336c76 | |||
| ddd0dc6dff | |||
| 1da64ebbd6 | |||
| 48cf146a6f | |||
| ccd6240e23 | |||
| 41c4b6453a | |||
| fda49d72c1 | |||
| 230b3840ad | |||
| 31530c7311 | |||
| ad5f36f2ac | |||
| 718ec64593 | |||
| b078d91894 | |||
| 0e21d85be1 | |||
| 54af49fe40 | |||
| 2d950869f8 | |||
| d3ec8f8791 | |||
| 9033830375 | |||
| 35e5c48814 | |||
| b16efc8c0b | |||
| bdf28a79fc | |||
| bc634975d4 | |||
| 2f682ca9f8 | |||
| bb8c8e5fa8 | |||
| 014bc9ed79 | |||
| a89dbfad01 | |||
| b53716bd7f | |||
| 6e9b3d811b | |||
| 3fa85ade3a | |||
| 1bd05e4561 | |||
| a38a0d5b81 | |||
| efcf28b96b | |||
| 6b827886a0 | |||
| f6712c7cbd | |||
| 3e11da04df | |||
| 56d6ee9a1c | |||
| 897a518750 | |||
| c9b7590dd9 | |||
| 4d3d250d5e | |||
| 43d93b87bc | |||
| f0a90a46ed | |||
| d379c41d72 | |||
| 57688559b1 | |||
| fa26073882 | |||
| b37ca7868a | |||
| 767621d2cb | |||
| ab93e1f56d | |||
| f3523e8381 | |||
| 0eeaf31270 | |||
| 5703b95d0e | |||
| 7acaffa841 | |||
| ea7652677d | |||
| b239441ff9 | |||
| 8bea90280f | |||
| 4fef0935fb | |||
| 421e19ca4b | |||
| 3e00c2d842 | |||
| 3fe8f75d1b | |||
| 8e0837b6a1 | |||
| 347b7238dc | |||
| fdb89d13ef | |||
| f3060d8a33 | |||
| be743da973 | |||
| de8d7725be | |||
| 7033df8c0c | |||
| 2e6e200962 | |||
| b7a44adca0 | |||
| e831a050cd | |||
| 4e2af32bcf | |||
| 198b031d03 | |||
| 5ec60a6a2c | |||
| eadaabbe62 | |||
| b2d7640a1d | |||
| 39ba117abf | |||
| 7a3849ffdb | |||
| 9a367b2be7 | |||
| f671c11773 | |||
| bb7208b754 | |||
| 3ae6f849ac | |||
| e682be574b | |||
| ab084a9399 | |||
| 3f4edebda6 | |||
| a59e3bb3cd | |||
| e62ea4cdb4 | |||
| e3283739ce | |||
| 600aa2ec16 | |||
| 0921355a74 | |||
| 1ac757bd60 | |||
| 9c46074145 | |||
| 2ad239b6c9 | |||
| 9bc8eb952b | |||
| 83cbc1f450 | |||
| 5ef0970789 | |||
| 41920cc74f | |||
| bda63626d2 | |||
| d0d364d729 | |||
| e896c2576b | |||
| 8b417ebd25 | |||
| 6d93d700bb | |||
| 88b0af83b5 | |||
| 5e3d0126e3 | |||
| aef4192d6a | |||
| 30b8b3c61f | |||
| 7a1c6388c2 | |||
| a694ccb39e | |||
| a85bcfc0d7 | |||
| 5cc787f648 | |||
| a011792fb6 | |||
| 2bd88ed300 | |||
| bd234eafe3 | |||
| 0405be5bb0 | |||
| f8616ba0b5 | |||
| c40b0f6f63 | |||
| b10c76a3a6 | |||
| 683b301fb7 | |||
| 76223227ba | |||
| 04e59f26b9 | |||
| ba0f81e65c | |||
| 204352ca8b | |||
| 8b07f89d13 | |||
| 2f01154847 | |||
| 24458b4bf1 | |||
| 52049833fd | |||
| 3ec27d06ec | |||
| 510d234611 | |||
| 3006bcb3f7 | |||
| b9c2580f22 | |||
| 2684031ff2 | |||
| de2866fe38 | |||
| 2f2b10d22b | |||
| 2065013a04 | |||
| 57b3448019 | |||
| 65faee4e7b | |||
| e1c4bbed1d | |||
| 420fb5f6cc | |||
| c4ee764dd8 | |||
| 3e0167a9e9 | |||
| be74b3dca8 | |||
| ba94df76e1 | |||
| 6361dd3f6e | |||
| 9f44a9d6a4 | |||
| 534ab7a030 | |||
| e0399adca9 | |||
| 33a0cc3759 | |||
| 9ff955496e | |||
| 9424ed9669 | |||
| 248122670f | |||
| 9dc9be484f | |||
| 3fc88faa51 | |||
| 8168ddcb40 | |||
| d57291777f | |||
| e47dd4f054 | |||
| 4e86f62a64 | |||
| 711276e62b | |||
| a2acacebe0 | |||
| 40e70fc6e9 | |||
| f4d5687704 | |||
| 3adfd850c7 | |||
| 42019fca7c | |||
| 0fc2f3d86d | |||
| b10355c846 | |||
| 05d649ef54 | |||
| 71d55ebf18 | |||
| dc80efa426 | |||
| 0068da44d4 | |||
| 3640d302e1 | |||
| d07e17d85c | |||
| a87c498af8 | |||
| 75070e1bfa | |||
| 5487c20beb | |||
| bcedf25ebf | |||
| 7ce874f5d0 | |||
| bd0cbfb5b8 | |||
| dfb744bdf1 | |||
| 849c347d2e | |||
| 9c3fa17ce2 | |||
| 37783c3446 | |||
| 2447ea37ca | |||
| 4d0e208a2e | |||
| 3aa83b20ff | |||
| 1194823a73 | |||
| 60685f35d8 | |||
| 4d9b0f6157 | |||
| e2428486b1 | |||
| 5a7dd75687 | |||
| 42bc462559 | |||
| d0ff4c3306 | |||
| 2f5acd74d9 | |||
| 7979a01371 | |||
| 59633b8ba6 | |||
| 1eecfd24f6 | |||
| fdda9161fe | |||
| 4156e28d78 | |||
| 418275589c | |||
| be946aab50 | |||
| 2aca908685 | |||
| 99ec33418a | |||
| c416887542 | |||
| dd0ff29f66 | |||
| 3e22f47624 | |||
| bda20507bd | |||
| 9111697a0b | |||
| 97ac1394fa | |||
| 6966d2633a | |||
| 58d341cea3 | |||
| f27587f391 | |||
| ce6536c1d8 | |||
| c0420dfa2a | |||
| 0c77aa5a69 | |||
| 96698c5783 | |||
| 038bc809cb | |||
| 71d559e1f2 | |||
| 184d929521 | |||
| 5e975db36e | |||
| 9a89cf1978 | |||
| 94c1f03300 | |||
| 872df4e54e | |||
| 5fdde955b3 | |||
| 826d8e0303 | |||
| 3f87b85886 | |||
| af6777397c | |||
| 2f29b73496 | |||
| c14499b211 | |||
| 57b5993f8d | |||
| 2f8fdae0db | |||
| e57869a38e | |||
| e4d291802b | |||
| 77eb4ec65a | |||
| d27798e797 | |||
| fca6b52fba | |||
| 04ebac2279 | |||
| fb968dccdf | |||
| 1271ada6e1 | |||
| 7a86a8a8e7 | |||
| e9ee638ae9 | |||
| 965e14c3f9 | |||
| a2ca638f47 | |||
| 0197e59eb1 | |||
| 418adb52a4 | |||
| 8894524474 | |||
| 6ec6318d5f | |||
| a5e90a8dea | |||
| b22e98aa01 | |||
| 89ea0a9911 | |||
| 7fec46aecf |
@@ -1,9 +1,28 @@
|
||||
.*.orig$
|
||||
.*\.o$
|
||||
.*~$
|
||||
build-dir
|
||||
build
|
||||
.*\.sconsign
|
||||
doc/html.*
|
||||
doc/latex.*
|
||||
.lock-wscript
|
||||
\.rej$
|
||||
\.orig$
|
||||
\.o$
|
||||
~$
|
||||
^build-dir
|
||||
^build
|
||||
^doc/html
|
||||
^doc/latex
|
||||
^\.lock-wscript
|
||||
^\.waf
|
||||
^doc/introspected-doxygen\.h$
|
||||
.*\.py[co]$
|
||||
\.pcap$
|
||||
^doc/manual/manual/
|
||||
doc/manual/manual.aux
|
||||
doc/manual/manual.cp
|
||||
doc/manual/manual.fn
|
||||
doc/manual/manual.html
|
||||
doc/manual/manual.ky
|
||||
doc/manual/manual.log
|
||||
doc/manual/manual.pdf
|
||||
doc/manual/manual.pg
|
||||
doc/manual/manual.toc
|
||||
doc/manual/manual.tp
|
||||
doc/manual/manual.vr
|
||||
^doc/manual/figures/.*eps
|
||||
^doc/manual/figures/.*pdf
|
||||
^doc/manual/figures/.*png
|
||||
|
||||
@@ -2,3 +2,16 @@
|
||||
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
|
||||
0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
|
||||
38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
|
||||
5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
|
||||
08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
|
||||
267e2ebc28e4e4ae2f579e1cfc29902acade0c34 buffer-working-before-breaking
|
||||
606df29888e7573b825fc891a002f0757166b616 release ns-3.0.6
|
||||
36472385a1cc7c44d34fb7a5951b930010f4e8d2 release ns-3.0.7
|
||||
560a5091e0e6ded47d269e2f2dee780f13950a63 release ns-3.0.8
|
||||
4db981a0d9eb135e3e1c07765cff8d66f7a55cca release ns-3.0.9
|
||||
b5bf2588cde2f1273b1095cc5c83a0c272e55370 release ns-3.0.10
|
||||
ee5e1da76ecc52337f097cd90ebb50a3d49ec541 release-3.0.11
|
||||
b17f2928291eec5bf5b1c59a4a5fd583f704ac40 release ns-3.0.12
|
||||
79dba133b5f8a2d6f6f678a22e8519bc155e6a4e release ns-3.0.13
|
||||
8869a79a391f49d0c787f0558cc9329b4e7ee40e release candidate ns-3.1-RC1
|
||||
951296e9a277e14113a0d3ba86a9688b222569ae release ns-3.1-RC2
|
||||
|
||||
@@ -2,5 +2,9 @@ Raj Bhattarcharjea (raj.b@gatech.edu)
|
||||
Gustavo Carneiro (gjc@inescporto.pt, gjcarneiro@gmail.com)
|
||||
Craig Dowell (craigdo@ee.washington.edu)
|
||||
Tom Henderson (tomhend@u.washington.edu)
|
||||
Joe Kopena (tjkopena@cs.drexel.edu)
|
||||
Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
|
||||
Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
|
||||
Federico Maguolo (maguolof@dei.unipd.it)
|
||||
George F. Riley (riley@ece.gatech.edu)
|
||||
Guillaume Vu-Brugier (gvubrugier@gmail.com)
|
||||
|
||||
@@ -36,25 +36,26 @@ project. These steps are described in doc/contributing.txt
|
||||
|
||||
This package contains the latest version of ns-3 which aims
|
||||
at being a replacement for ns-2. Currently, ns-3 provides a
|
||||
number of very simple network simulation models:
|
||||
- an ipv4 and udp stack
|
||||
number of simple network simulation models:
|
||||
- an ipv4 and tcp and udp stack
|
||||
- arp support at the bottom of the stack
|
||||
- point-to-point physical-layer links
|
||||
- static global and OLSR unicast routing
|
||||
- point-to-point, CSMA, and Wifi links
|
||||
- mobility
|
||||
- OnOff traffic generator
|
||||
|
||||
Our focus to date has been on getting an overall software
|
||||
framework in place. The framework is there to make adding
|
||||
new models as simple as possible:
|
||||
- an extensive tracing system can be used to connect
|
||||
any number of arbitrary trace sources to any number
|
||||
of trace sinks. This tracing system is decoupled
|
||||
from the act of serializing the trace events to a
|
||||
file: users can and should provide their own
|
||||
trace handling routines.
|
||||
|
||||
- an extensive callback-based tracing system
|
||||
|
||||
- simple file trace serialization support is included
|
||||
to both text and pcap files.
|
||||
|
||||
- an attribute system for configuring parameters in the
|
||||
models
|
||||
|
||||
- adding new MAC-level models simply requires subclassing
|
||||
the pair of classes NetDevice and Channel.
|
||||
|
||||
@@ -71,29 +72,26 @@ use of these ns-3 libraries.
|
||||
|
||||
To build the set of default libraries and the example
|
||||
programs included in this package, you need to use the
|
||||
tool 'scons'. Detailed information on how to install
|
||||
and use scons is included in the file doc/build.txt
|
||||
tool 'waf'. Detailed information on how to install
|
||||
and use waf is included in the file doc/build.txt
|
||||
|
||||
However, the real quick and dirty way to get started is to
|
||||
type the command "scons" the the directory which contains
|
||||
type the command "./waf" the the directory which contains
|
||||
this README file. The files built will be copied in the
|
||||
build-dir/dbg-shared/bin and build-dir/dbg-shared/lib
|
||||
directories. build-dir/dbg-shared/bin will contain
|
||||
one binary for each of the sample code in the 'samples'
|
||||
directory and one binary for each of the detailed examples
|
||||
found in the 'examples' directory.
|
||||
build/debug or build/optimized.
|
||||
|
||||
The current codebase is expected to build and run on the
|
||||
following set of platforms:
|
||||
- linux x86 gcc 4.2, 4.1, and, 3.4.
|
||||
- linux x86_64 gcc 4.0
|
||||
- linux x86 gcc 4.2, 4.1, and, 3.4.6.
|
||||
- linux x86_64 gcc 4.1.3, 4.2.1, 3.4.6
|
||||
- MacOS X ppc and x86
|
||||
- cygwin gcc 3.4.4 (debug only)
|
||||
|
||||
The current codebase is expected to fail to build on
|
||||
the following platforms:
|
||||
- gcc 3.3 and earlier
|
||||
- optimized builds on gcc 3.4.4 and 3.4.5
|
||||
- optimized builds on linux x86 gcc 4.0
|
||||
- cygwin
|
||||
|
||||
Other platforms may or may not work: we welcome
|
||||
patches to improve the portability of the code to these
|
||||
@@ -106,22 +104,17 @@ On recent Linux systems, once you have built ns-3, it
|
||||
should be easy to run the sample programs with the
|
||||
following command:
|
||||
|
||||
./build-dir/dbg-shared/bin/simple-p2p
|
||||
./waf --run simple-global-routing
|
||||
|
||||
or:
|
||||
|
||||
cd build-dir/dbg-shared/bin
|
||||
./simple-p2p
|
||||
|
||||
That program should generate a simple-p2p.tr text
|
||||
trace file and a set of simple-p2p-xx-xx.pcap binary
|
||||
pcap trace files, which can be read by tcpdump.
|
||||
That program should generate a simple-global-routing.tr text
|
||||
trace file and a set of simple-global-routing-xx-xx.pcap binary
|
||||
pcap trace files, which can be read by tcpdump -tt -r filename.pcap
|
||||
|
||||
5) Getting access to the ns-3 documentation
|
||||
-------------------------------------------
|
||||
|
||||
Once you have verified that your build of ns-3 works by running
|
||||
the simple-p2p example as outlined in 4) above, it is
|
||||
the simple-point-to-point example as outlined in 4) above, it is
|
||||
quite likely that you will want to get started on reading
|
||||
some ns-3 documentation.
|
||||
|
||||
@@ -131,12 +124,7 @@ include some of it in this release for ease of use.
|
||||
|
||||
This documentation includes:
|
||||
|
||||
- an architecture document which describes a very
|
||||
high-level view of ns-3: it tries to explain the
|
||||
use-cases the ns-3 developers really focused on when
|
||||
doing the initial design and then goes on to explain
|
||||
the structure of the resulting framework.
|
||||
See the file doc/architecture.pdf
|
||||
- a tutorial
|
||||
|
||||
- a wiki for user-contributed tips: http://www.nsnam.org/wiki/
|
||||
|
||||
@@ -145,17 +133,6 @@ This documentation includes:
|
||||
as introductory text:
|
||||
http://www.nsnam.org/doxygen/index.html
|
||||
|
||||
If you want to re-generate this documentation, you can
|
||||
easily do so:
|
||||
|
||||
- doc/architecture.pdf is generated from the architecture.tex
|
||||
file in http://code.nsnam.org/docs
|
||||
|
||||
- the doxygen documentation is generated from the doc/doxygen.conf
|
||||
configuration file. The command "scons doc" will generate it
|
||||
as doc/html/index.html if you have installed the doxygen tools
|
||||
(see http://www.doxygen.org)
|
||||
|
||||
6) Working with the development version of ns-3
|
||||
-----------------------------------------------
|
||||
|
||||
|
||||
+108
@@ -3,6 +3,114 @@
|
||||
|
||||
This file contains ns-3 release notes (most recent releases first).
|
||||
|
||||
Release 3.1 (2008/06/30 tentatively)
|
||||
========================
|
||||
First supported ns-3 release.
|
||||
|
||||
- TCP bugfixes and support for packet tags
|
||||
- CSMA NetDevice cleanup and documentation
|
||||
- internet-node renamed to internet-stack
|
||||
- Socket::RecvFrom added; "flags" argument added to Send calls
|
||||
- updated doxygen
|
||||
- several bugs and open issues closed out
|
||||
- revised tutorial
|
||||
|
||||
Note: Some API in class ns3::Ipv4 and ns3::Ipv4RoutingProtocol is
|
||||
deprecated and may be removed and replaced in future releases.
|
||||
|
||||
Release 3.0.13 (2008/06/02)
|
||||
========================
|
||||
- point to point links generate ppp pcap traces
|
||||
- point to point links support asymmetrical data rates.
|
||||
- generate doxygen documentation for all attributes and trace sources
|
||||
- add ConfigStore and GtkConfigStore to contrib module
|
||||
- socket API now support tx and rx buffers: implemented for UDP and TCP
|
||||
- ARP cache now supports per-entry pending queues
|
||||
- lots of bugfixes and implementation and API cleanups
|
||||
|
||||
Warning: among API changes in this release, Application::Start and
|
||||
Application::Stop now interprets the time argument as a relative
|
||||
instead of absolute simulation time, to align with how Simulator::Schedule
|
||||
behaves. Any code that calls these APIs in the middle of the simulation
|
||||
will need to be adapted.
|
||||
|
||||
The API of Simulator::StopAt (time) has also changed. Now it is
|
||||
called Simulator::Stop (time), and takes a relative time, instead of
|
||||
absolute.
|
||||
|
||||
Release 3.0.12 (2008/04/07)
|
||||
========================
|
||||
- Add Attribute support to the TypeId metadata system and add
|
||||
attribute support to all in-tree models
|
||||
- Add a mid-level helper API to build simulation topologies
|
||||
and perform simple ascii and pcap link-level tracing.
|
||||
- Large amount of structural changes to accomodate the needs
|
||||
of the upcoming python bindings
|
||||
- new rate control algorithm (RRAA) and a jakes propagation model
|
||||
in the 802.11 model (Federico Maguolo).
|
||||
- regression test framework added
|
||||
- TCP delayed acknowledgements and multitasking server
|
||||
|
||||
Release 3.0.11 (2008/02/15)
|
||||
========================
|
||||
- Initial port of GTNetS TCP implementation (initial version
|
||||
that does not support multitasking or delayed acknowledgments yet,
|
||||
but supports a reliable stream service)
|
||||
- Changes to the ns-3 object model to create a TypeId-based
|
||||
metadata system
|
||||
- lots of bug fixes throughout the system
|
||||
- tutorial updates
|
||||
|
||||
Release 3.0.10 (2008/01/15)
|
||||
========================
|
||||
- Add tutorial document content;
|
||||
- Valgrind option for "waf" tool;
|
||||
- Doxygen organization changes.
|
||||
|
||||
Release 3.0.9 (2007/12/15)
|
||||
========================
|
||||
- A 802.11 model ported from Yans. This model supports:
|
||||
* a rather extensive PHY model
|
||||
* log-distance and friis propagation model
|
||||
* a simple set of rate control algorithms (ARF, Ideal,
|
||||
AARF, constant-rate)
|
||||
* adhoc and infrastructure mode (beacon+assoc)
|
||||
- Use smart pointer for Packet in the APIs
|
||||
- A new contrib directory with helper classes:
|
||||
EventGarbageCollector, Gnuplot
|
||||
- Tracing support for Applications
|
||||
- many bugs fixed
|
||||
|
||||
Release 3.0.8 (2007/11/15)
|
||||
========================
|
||||
- A simple error model
|
||||
- Source files for ns-3 tutorial
|
||||
|
||||
Release 3.0.7 (2007/10/15)
|
||||
========================
|
||||
- OLSR routing protocol
|
||||
- A timer class
|
||||
- Additional mobility models (random waypoint, random 2D walk)
|
||||
- A mobility visualization tool
|
||||
|
||||
Release 3.0.6 (2007/09/15)
|
||||
========================
|
||||
- Static multicast IPv4 routing
|
||||
- Logging overhaul (NS_LOG macros)
|
||||
- Refactoring of tracing subsystem
|
||||
- Tutorial document started
|
||||
|
||||
Release 3.0.5 (2007/08/15)
|
||||
========================
|
||||
|
||||
- Refactoring to support win32-based unix environments (Cygwin, mingw)
|
||||
- "Packet socket" for allowing applications to access NetDevices directly
|
||||
- Generalized, polymorphic Address class
|
||||
- Add CSMA NetDevice model (from Emmanuelle Laprise)
|
||||
- Modularize IPv4 routing support (from Gustavo Carneiro)
|
||||
- Add mobility framework and basic mobility models
|
||||
- Global unicast centralized routing
|
||||
|
||||
Release 3.0.4 (2007/07/15)
|
||||
========================
|
||||
|
||||
|
||||
-484
@@ -1,484 +0,0 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import os.path
|
||||
import build
|
||||
|
||||
version_file = open ('VERSION', 'r')
|
||||
version = version_file.readline ()
|
||||
version_file.close ()
|
||||
version = version.strip ()
|
||||
|
||||
ns3 = build.Ns3()
|
||||
ns3.build_dir = 'build-dir'
|
||||
ns3.version = version
|
||||
ns3.name = 'ns3'
|
||||
ns3.distname = 'ns'
|
||||
ns3.doxygen_config = os.path.join('doc', 'doxygen.conf')
|
||||
ns3.add_extra_dist(os.path.join('doc', 'main.txt'))
|
||||
ns3.add_extra_dist ('doc/architecture.pdf')
|
||||
ns3.add_extra_dist ('doc/contributing.txt')
|
||||
ns3.add_extra_dist ('doc/build.txt')
|
||||
ns3.add_extra_dist ('doc/codingstd.txt')
|
||||
ns3.add_extra_dist ('doc/mercurial.txt')
|
||||
ns3.add_extra_dist ('README')
|
||||
ns3.add_extra_dist ('RELEASE_NOTES')
|
||||
ns3.add_extra_dist ('AUTHORS')
|
||||
ns3.add_extra_dist ('VERSION')
|
||||
|
||||
ns3.add_extra_dist('ns3/_placeholder_')
|
||||
for wscript in [
|
||||
"src/core/wscript",
|
||||
"src/node/wscript",
|
||||
"src/devices/p2p/wscript",
|
||||
"src/common/wscript",
|
||||
"src/applications/wscript",
|
||||
"src/simulator/wscript",
|
||||
"src/internet-node/wscript",
|
||||
"src/wscript",
|
||||
"utils/wscript",
|
||||
"samples/wscript",
|
||||
"examples/wscript",
|
||||
"wscript",
|
||||
]:
|
||||
ns3.add_extra_dist(wscript)
|
||||
ns3.add_extra_dist('waf.bat')
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The Core module
|
||||
#
|
||||
core = build.Ns3Module('core', 'src/core')
|
||||
ns3.add(core)
|
||||
core.add_sources([
|
||||
'callback-test.cc',
|
||||
'debug.cc',
|
||||
'assert.cc',
|
||||
'ptr.cc',
|
||||
'object.cc',
|
||||
'test.cc',
|
||||
'random-variable.cc',
|
||||
'rng-stream.cc',
|
||||
'uid-manager.cc',
|
||||
'default-value.cc',
|
||||
'command-line.cc',
|
||||
'type-name.cc',
|
||||
'component-manager.cc',
|
||||
])
|
||||
env = Environment()
|
||||
if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin':
|
||||
core.add_external_dep('pthread')
|
||||
core.add_sources([
|
||||
'unix-system-wall-clock-ms.cc',
|
||||
])
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
core.add_sources([
|
||||
'win32-system-wall-clock-ms.cc',
|
||||
])
|
||||
core.add_headers ([
|
||||
'uid-manager.h',
|
||||
'singleton.h',
|
||||
])
|
||||
core.add_inst_headers([
|
||||
'system-wall-clock-ms.h',
|
||||
'empty.h',
|
||||
'callback.h',
|
||||
'ptr.h',
|
||||
'object.h',
|
||||
'debug.h',
|
||||
'assert.h',
|
||||
'fatal-error.h',
|
||||
'test.h',
|
||||
'random-variable.h',
|
||||
'rng-stream.h',
|
||||
'default-value.h',
|
||||
'command-line.h',
|
||||
'type-name.h',
|
||||
'component-manager.h',
|
||||
])
|
||||
|
||||
def config_core (env, config):
|
||||
retval = []
|
||||
# XXX This check is primitive but it should be
|
||||
# good enough for now.
|
||||
if config.CheckCHeader ('stdlib.h') == 1:
|
||||
retval.append ('#define HAVE_STDLIB_H 1')
|
||||
retval.append ('#define HAVE_GETENV 1')
|
||||
else:
|
||||
retval.append ('#undef HAVE_STDLIB_H')
|
||||
retval.append ('#undef HAVE_GETENV')
|
||||
return retval
|
||||
core.add_config (config_core)
|
||||
|
||||
#
|
||||
# The Simu module
|
||||
#
|
||||
simu = build.Ns3Module('simulator', 'src/simulator')
|
||||
ns3.add(simu)
|
||||
simu.add_dep('core')
|
||||
simu.add_external_dep('m')
|
||||
simu.add_sources([
|
||||
'high-precision.cc',
|
||||
'time.cc',
|
||||
'event-id.cc',
|
||||
'scheduler.cc',
|
||||
'scheduler-factory.cc',
|
||||
'scheduler-list.cc',
|
||||
'scheduler-heap.cc',
|
||||
'scheduler-map.cc',
|
||||
'event-impl.cc',
|
||||
'simulator.cc',
|
||||
])
|
||||
simu.add_headers([
|
||||
'scheduler-heap.h',
|
||||
'scheduler-map.h',
|
||||
'scheduler-list.h'
|
||||
])
|
||||
simu.add_inst_headers([
|
||||
'high-precision.h',
|
||||
'nstime.h',
|
||||
'event-id.h',
|
||||
'event-impl.h',
|
||||
'simulator.h',
|
||||
'scheduler.h',
|
||||
'scheduler-factory.h',
|
||||
'simulation-singleton.h',
|
||||
])
|
||||
high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
|
||||
if high_precision_as_double == 'y':
|
||||
simu.add_inst_header ('high-precision-double.h')
|
||||
simu.add_source ('high-precision-double.cc')
|
||||
else:
|
||||
simu.add_inst_headers ([
|
||||
'high-precision-128.h',
|
||||
'cairo-wideint-private.h'
|
||||
])
|
||||
simu.add_sources ([
|
||||
'high-precision-128.cc',
|
||||
'cairo-wideint.c',
|
||||
])
|
||||
|
||||
def config_simulator (env, config):
|
||||
retval = []
|
||||
high_precision_as_double = ARGUMENTS.get('high-precision-as-double', 'n')
|
||||
if high_precision_as_double == 'y':
|
||||
retval.append ('#define USE_HIGH_PRECISION_DOUBLE 1')
|
||||
else:
|
||||
retval.append ('#undef USE_HIGH_PRECISION_DOUBLE')
|
||||
if config.CheckCHeader ('stdint.h') == 1:
|
||||
retval.append ('#define HAVE_STDINT_H 1')
|
||||
elif config.CheckCHeader ('inttypes.h') == 1:
|
||||
retval.append ('#define HAVE_INTTYPES_H 1')
|
||||
elif config.CheckCHeader ('sys/inttypes.h') == 1:
|
||||
retval.append ('#define HAVE_SYS_INT_TYPES_H 1')
|
||||
return retval
|
||||
simu.add_config (config_simulator)
|
||||
|
||||
|
||||
#
|
||||
# The Common module
|
||||
#
|
||||
common = build.Ns3Module('common', 'src/common')
|
||||
common.add_deps(['core', 'simulator'])
|
||||
ns3.add(common)
|
||||
common.add_sources([
|
||||
'buffer.cc',
|
||||
'chunk.cc',
|
||||
'header.cc',
|
||||
'trailer.cc',
|
||||
'packet-printer.cc',
|
||||
'packet-metadata.cc',
|
||||
'packet.cc',
|
||||
'tags.cc',
|
||||
'pcap-writer.cc',
|
||||
'variable-tracer-test.cc',
|
||||
'trace-context.cc',
|
||||
'trace-resolver.cc',
|
||||
'callback-trace-source.cc',
|
||||
'empty-trace-resolver.cc',
|
||||
'composite-trace-resolver.cc',
|
||||
'trace-root.cc',
|
||||
'data-rate.cc',
|
||||
])
|
||||
common.add_headers ([
|
||||
])
|
||||
common.add_inst_headers([
|
||||
'buffer.h',
|
||||
'chunk.h',
|
||||
'header.h',
|
||||
'trailer.h',
|
||||
'tags.h',
|
||||
'packet.h',
|
||||
'packet-printer.h',
|
||||
'packet-metadata.h',
|
||||
'uv-trace-source.h',
|
||||
'sv-trace-source.h',
|
||||
'fv-trace-source.h',
|
||||
'pcap-writer.h',
|
||||
'callback-trace-source.h',
|
||||
'trace-context.h',
|
||||
'trace-resolver.h',
|
||||
'empty-trace-resolver.h',
|
||||
'composite-trace-resolver.h',
|
||||
'array-trace-resolver.h',
|
||||
'trace-root.h',
|
||||
'terminal-trace-resolver.h',
|
||||
'data-rate.h',
|
||||
])
|
||||
|
||||
node = build.Ns3Module ('node', 'src/node')
|
||||
ns3.add (node)
|
||||
node.add_deps (['core', 'common', 'simulator'])
|
||||
node.add_sources ([
|
||||
'node.cc',
|
||||
'ipv4-address.cc',
|
||||
'net-device.cc',
|
||||
'mac-address.cc',
|
||||
'llc-snap-header.cc',
|
||||
'ipv4-route.cc',
|
||||
'queue.cc',
|
||||
'drop-tail-queue.cc',
|
||||
'channel.cc',
|
||||
'node-list.cc',
|
||||
'socket.cc',
|
||||
'socket-factory.cc',
|
||||
'udp.cc',
|
||||
'ipv4.cc',
|
||||
'application.cc',
|
||||
])
|
||||
node.add_inst_headers ([
|
||||
'node.h',
|
||||
'ipv4-address.h',
|
||||
'net-device.h',
|
||||
'mac-address.h',
|
||||
'ipv4-route.h',
|
||||
'queue.h',
|
||||
'drop-tail-queue.h',
|
||||
'llc-snap-header.h',
|
||||
'channel.h',
|
||||
'node-list.h',
|
||||
'socket.h',
|
||||
'socket-factory.h',
|
||||
'udp.h',
|
||||
'ipv4.h',
|
||||
'application.h',
|
||||
])
|
||||
|
||||
applications = build.Ns3Module ('applications', 'src/applications')
|
||||
ns3.add (applications)
|
||||
applications.add_deps (['node'])
|
||||
applications.add_sources ([
|
||||
'onoff-application.cc',
|
||||
])
|
||||
applications.add_inst_headers ([
|
||||
'onoff-application.h',
|
||||
])
|
||||
|
||||
inode = build.Ns3Module ('internet-node', 'src/internet-node')
|
||||
ns3.add (inode)
|
||||
inode.add_deps (['node'])
|
||||
inode.add_sources ([
|
||||
'internet-node.cc',
|
||||
'l3-demux.cc',
|
||||
'l3-protocol.cc',
|
||||
'ipv4-l4-demux.cc',
|
||||
'ipv4-l4-protocol.cc',
|
||||
'ipv4-header.cc',
|
||||
'udp-header.cc',
|
||||
'ipv4-checksum.cc',
|
||||
'ipv4-interface.cc',
|
||||
'ipv4-l3-protocol.cc',
|
||||
'ipv4-end-point.cc',
|
||||
'udp-l4-protocol.cc',
|
||||
'arp-header.cc',
|
||||
'arp-cache.cc',
|
||||
'arp-ipv4-interface.cc',
|
||||
'arp-l3-protocol.cc',
|
||||
'ipv4-loopback-interface.cc',
|
||||
'header-utils.cc',
|
||||
'udp-socket.cc',
|
||||
'ipv4-end-point-demux.cc',
|
||||
'arp-private.cc',
|
||||
'ipv4-impl.cc',
|
||||
'ipv4-private.cc',
|
||||
'ascii-trace.cc',
|
||||
'pcap-trace.cc',
|
||||
'udp-impl.cc',
|
||||
])
|
||||
inode.add_headers ([
|
||||
'ipv4-checksum.h',
|
||||
'arp-header.h',
|
||||
'arp-cache.h',
|
||||
'arp-l3-protocol.h',
|
||||
'ipv4-loopback-interface.h',
|
||||
'l3-demux.h',
|
||||
'header-utils.h',
|
||||
'arp-ipv4-interface.h',
|
||||
'udp-socket.h',
|
||||
'udp-l4-protocol.h',
|
||||
'arp-private.h',
|
||||
'ipv4-impl.h',
|
||||
'ipv4-private.h',
|
||||
'ipv4-l3-protocol.h',
|
||||
'l3-protocol.h',
|
||||
'ipv4-l4-protocol.h',
|
||||
'ipv4-l4-demux.h',
|
||||
'ipv4-end-point-demux.h',
|
||||
'ipv4-end-point.h',
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
'ipv4-interface.h',
|
||||
'sgi-hashmap.h',
|
||||
'udp-impl.h',
|
||||
])
|
||||
inode.add_inst_headers ([
|
||||
'internet-node.h',
|
||||
'ascii-trace.h',
|
||||
'pcap-trace.h',
|
||||
'ipv4-header.h',
|
||||
'udp-header.h',
|
||||
])
|
||||
|
||||
|
||||
|
||||
p2p = build.Ns3Module ('p2p', 'src/devices/p2p')
|
||||
ns3.add (p2p)
|
||||
p2p.add_deps (['node'])
|
||||
p2p.add_sources ([
|
||||
'p2p-net-device.cc',
|
||||
'p2p-channel.cc',
|
||||
'p2p-topology.cc',
|
||||
])
|
||||
p2p.add_inst_headers ([
|
||||
'p2p-net-device.h',
|
||||
'p2p-channel.h',
|
||||
'p2p-topology.h',
|
||||
])
|
||||
|
||||
|
||||
# utils
|
||||
run_tests = build.Ns3Module('run-tests', 'utils')
|
||||
ns3.add(run_tests)
|
||||
run_tests.set_executable()
|
||||
run_tests.add_deps(['core', 'simulator', 'common'])
|
||||
run_tests.add_source('run-tests.cc')
|
||||
|
||||
bench_object = build.Ns3Module('bench-object', 'utils')
|
||||
ns3.add(bench_object)
|
||||
bench_object.set_executable()
|
||||
bench_object.add_deps(['core'])
|
||||
bench_object.add_source('bench-object.cc')
|
||||
|
||||
bench_packets = build.Ns3Module('bench-packets', 'utils')
|
||||
ns3.add(bench_packets)
|
||||
bench_packets.set_executable()
|
||||
bench_packets.add_deps (['core', 'common'])
|
||||
bench_packets.add_source('bench-packets.cc')
|
||||
|
||||
bench_simu = build.Ns3Module('bench-simulator', 'utils')
|
||||
ns3.add(bench_simu)
|
||||
bench_simu.set_executable()
|
||||
bench_simu.add_dep('simulator')
|
||||
bench_simu.add_source('bench-simulator.cc')
|
||||
|
||||
replay_simu = build.Ns3Module('replay-simulation', 'utils')
|
||||
ns3.add(replay_simu)
|
||||
replay_simu.set_executable()
|
||||
replay_simu.add_dep('simulator')
|
||||
replay_simu.add_source('replay-simulation.cc')
|
||||
|
||||
|
||||
# samples
|
||||
sample_debug = build.Ns3Module('sample-debug', 'samples')
|
||||
sample_debug.set_executable()
|
||||
ns3.add(sample_debug)
|
||||
sample_debug.add_dep('core')
|
||||
sample_debug.add_source('main-debug.cc')
|
||||
sample_debug.add_source('main-debug-other.cc')
|
||||
|
||||
sample_packet_printer = build.Ns3Module('sample-packet-printer', 'samples')
|
||||
sample_packet_printer.set_executable()
|
||||
ns3.add(sample_packet_printer)
|
||||
sample_packet_printer.add_deps (['common', 'internet-node'])
|
||||
sample_packet_printer.add_source('main-packet-printer.cc')
|
||||
|
||||
|
||||
sample_callback = build.Ns3Module('sample-callback', 'samples')
|
||||
sample_callback.set_executable()
|
||||
ns3.add(sample_callback)
|
||||
sample_callback.add_dep('core')
|
||||
sample_callback.add_source('main-callback.cc')
|
||||
|
||||
sample_ptr = build.Ns3Module('sample-ptr', 'samples')
|
||||
sample_ptr.set_executable()
|
||||
ns3.add(sample_ptr)
|
||||
sample_ptr.add_dep('core')
|
||||
sample_ptr.add_source('main-ptr.cc')
|
||||
|
||||
sample_trace = build.Ns3Module('sample-trace', 'samples')
|
||||
#ns3.add(sample_trace)
|
||||
sample_trace.add_dep('common')
|
||||
sample_trace.set_executable()
|
||||
sample_trace.add_source('main-trace.cc')
|
||||
|
||||
sample_query_interface = build.Ns3Module('sample-query-interface', 'samples')
|
||||
ns3.add(sample_query_interface)
|
||||
sample_query_interface.add_dep('common')
|
||||
sample_query_interface.set_executable()
|
||||
sample_query_interface.add_source('main-query-interface.cc')
|
||||
|
||||
sample_simu = build.Ns3Module('sample-simulator', 'samples')
|
||||
ns3.add(sample_simu)
|
||||
sample_simu.set_executable()
|
||||
sample_simu.add_dep('simulator')
|
||||
sample_simu.add_source('main-simulator.cc')
|
||||
|
||||
sample_packet = build.Ns3Module('sample-packet', 'samples')
|
||||
ns3.add(sample_packet)
|
||||
sample_packet.set_executable()
|
||||
sample_packet.add_dep('common')
|
||||
sample_packet.add_source('main-packet.cc')
|
||||
|
||||
sample_test = build.Ns3Module('sample-test', 'samples')
|
||||
sample_test.set_executable()
|
||||
ns3.add(sample_test)
|
||||
sample_test.add_dep('core')
|
||||
sample_test.add_source('main-test.cc')
|
||||
|
||||
sample_simple = build.Ns3Module('sample-simple', 'samples')
|
||||
sample_simple.set_executable()
|
||||
ns3.add(sample_simple)
|
||||
sample_simple.add_deps(['core', 'simulator', 'node', 'internet-node'])
|
||||
sample_simple.add_source('main-simple.cc')
|
||||
|
||||
sample_sp2p = build.Ns3Module('sample-simple-p2p', 'samples')
|
||||
sample_sp2p.set_executable()
|
||||
#n3.add(sample_sp2p)
|
||||
sample_sp2p.add_deps(['core', 'simulator', 'node', 'internet-node', 'p2p'])
|
||||
sample_sp2p.add_source('main-simple-p2p.cc')
|
||||
|
||||
sample_default_value = build.Ns3Module('sample-default-value', 'samples')
|
||||
sample_default_value.set_executable()
|
||||
ns3.add(sample_default_value)
|
||||
sample_default_value.add_deps(['core', 'simulator', 'node', 'p2p'])
|
||||
sample_default_value.add_source('main-default-value.cc')
|
||||
|
||||
sample_object = build.Ns3Module('sample-object', 'samples')
|
||||
sample_object.set_executable()
|
||||
ns3.add(sample_object)
|
||||
sample_object.add_deps(['core'])
|
||||
sample_object.add_source('main-object.cc')
|
||||
|
||||
sample_component_manager = build.Ns3Module('sample-component-manager', 'samples')
|
||||
sample_component_manager.set_executable()
|
||||
ns3.add(sample_component_manager)
|
||||
sample_component_manager.add_deps(['core'])
|
||||
sample_component_manager.add_source('main-component-manager.cc')
|
||||
|
||||
# examples
|
||||
example_simple_p2p = build.Ns3Module('simple-p2p', 'examples')
|
||||
example_simple_p2p.set_executable()
|
||||
ns3.add(example_simple_p2p)
|
||||
example_simple_p2p.add_deps(['core', 'simulator', 'node', 'p2p', 'internet-node', 'applications'])
|
||||
example_simple_p2p.add_source('simple-p2p.cc')
|
||||
|
||||
ns3.generate_dependencies()
|
||||
@@ -1,561 +0,0 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
# Copyright (c) 2006 INRIA
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation;
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
from SCons.Environment import Environment
|
||||
from SCons.Builder import Builder
|
||||
from SCons.Action import Action
|
||||
import SCons
|
||||
|
||||
# hack stolen from wengo
|
||||
# to get an ARGUMENTS defined correctly
|
||||
try:
|
||||
ARGUMENTS = SCons.Script.ARGUMENTS
|
||||
COMMAND_LINE_TARGETS = SCons.Script.COMMAND_LINE_TARGETS
|
||||
except AttributeError:
|
||||
from SCons.Script.SConscript import Arguments
|
||||
from SCons.Script.SConscript import CommandLineTargets
|
||||
ARGUMENTS = Arguments
|
||||
COMMAND_LINE_TARGETS = CommandLineTargets
|
||||
|
||||
class Ns3Module:
|
||||
def __init__(self, name, dir):
|
||||
self.sources = []
|
||||
self.inst_headers = []
|
||||
self.headers = []
|
||||
self.extra_dist = []
|
||||
self.deps = []
|
||||
self.external_deps = []
|
||||
self.config = []
|
||||
self.name = name
|
||||
self.dir = dir
|
||||
self.executable = False
|
||||
self.library = True
|
||||
self.ldflags = []
|
||||
self.header_inst_dir = ''
|
||||
def set_library(self):
|
||||
self.library = True
|
||||
self.executable = False
|
||||
def set_executable(self):
|
||||
self.library = False
|
||||
self.executable = True
|
||||
def add_config(self, config_fn):
|
||||
self.config.append(config_fn)
|
||||
def add_extra_dist(self, dist):
|
||||
self.extra_dist.append(dist)
|
||||
def add_external_dep(self, dep):
|
||||
self.external_deps.append(dep)
|
||||
def add_dep(self, dep):
|
||||
self.deps.append(dep)
|
||||
def add_deps(self, deps):
|
||||
self.deps.extend(deps)
|
||||
def add_source(self, source):
|
||||
self.sources.append(source)
|
||||
def add_sources(self, sources):
|
||||
self.sources.extend(sources)
|
||||
def add_header(self, header):
|
||||
self.headers.append(header)
|
||||
def add_headers(self, headers):
|
||||
self.headers.extend(headers)
|
||||
def add_inst_header(self, header):
|
||||
self.inst_headers.append(header)
|
||||
def add_inst_headers(self, headers):
|
||||
self.inst_headers.extend(headers)
|
||||
def add_ldflags (self, ldflags):
|
||||
self.ldflags.extend (ldflags)
|
||||
def add_ldflag (self, ldflag):
|
||||
self.add_ldflags ([ldflag])
|
||||
def set_header_inst_dir (self, inst_dir):
|
||||
self.header_inst_dir = inst_dir
|
||||
|
||||
|
||||
def MyCopyAction(target, source, env):
|
||||
try:
|
||||
if len(target) == len(source):
|
||||
for i in range(len(target)):
|
||||
shutil.copy(source[i].path, target[i].path)
|
||||
return 0
|
||||
else:
|
||||
return 'invalid target/source match'
|
||||
except:
|
||||
print
|
||||
return 'exception'
|
||||
def MyCopyActionPrint(target, source, env):
|
||||
if len(target) == len(source):
|
||||
output = ''
|
||||
for i in range(len(target)):
|
||||
output = output + 'copy \'' + source[i].path + '\' to \'' + target[i].path + '\''
|
||||
if i < len(target) - 1:
|
||||
output = output + '\n'
|
||||
return output
|
||||
else:
|
||||
return 'error in copy'
|
||||
def GcxxEmitter(target, source, env):
|
||||
if os.path.exists(source[0].path):
|
||||
return [target, source]
|
||||
else:
|
||||
return [[], []]
|
||||
def MyRmTree(target, source, env):
|
||||
shutil.rmtree(env['RM_DIR'])
|
||||
return 0
|
||||
def MyRmTreePrint(target, source, env):
|
||||
return ''
|
||||
def print_cmd_line(s, target, src, env):
|
||||
print 'Building ' + (' and '.join([str(x) for x in target])) + '...'
|
||||
|
||||
class Ns3BuildVariant:
|
||||
def __init__(self):
|
||||
self.static = False
|
||||
self.gcxx_deps = False
|
||||
self.gcxx_root = ''
|
||||
self.build_root = ''
|
||||
self.env = None
|
||||
|
||||
class Ns3:
|
||||
def __init__(self):
|
||||
self.__modules = []
|
||||
self.extra_dist = []
|
||||
self.build_dir = 'build'
|
||||
self.version = '0.0.1'
|
||||
self.name = 'noname'
|
||||
self.distname = 'noname'
|
||||
self.doxygen_config = ''
|
||||
def add(self, module):
|
||||
self.__modules.append(module)
|
||||
def add_extra_dist(self, dist):
|
||||
self.extra_dist.append(dist)
|
||||
def __get_module(self, name):
|
||||
for module in self.__modules:
|
||||
if module.name == name:
|
||||
return module
|
||||
return None
|
||||
def get_mod_output(self, module, variant):
|
||||
if module.executable:
|
||||
suffix = variant.env.subst(variant.env['PROGSUFFIX'])
|
||||
filename = os.path.join(variant.build_root, 'bin',
|
||||
module.name + suffix)
|
||||
else:
|
||||
if variant.static:
|
||||
prefix = variant.env['LIBPREFIX']
|
||||
suffix = variant.env['LIBSUFFIX']
|
||||
else:
|
||||
prefix = variant.env['SHLIBPREFIX']
|
||||
suffix = variant.env['SHLIBSUFFIX']
|
||||
prefix = variant.env.subst(prefix)
|
||||
suffix = variant.env.subst(suffix)
|
||||
filename = os.path.join(variant.build_root, 'lib',
|
||||
prefix + module.name + suffix)
|
||||
return filename
|
||||
def get_obj_builders(self, variant, module):
|
||||
env = variant.env.Copy ()
|
||||
objects = []
|
||||
hash = {}
|
||||
self.get_internal_deps (module, hash)
|
||||
for dep in hash.values ():
|
||||
if dep.header_inst_dir != '':
|
||||
inc_dir = os.path.join(variant.build_root, 'include',
|
||||
self.name, dep.header_inst_dir)
|
||||
env.Append (CPPPATH = [inc_dir])
|
||||
|
||||
if len(module.config) > 0:
|
||||
src_config_file = os.path.join(self.build_dir, 'config', module.name + '-config.h')
|
||||
tgt_config_file = os.path.join(variant.build_root, 'include',
|
||||
self.name, module.name + '-config.h')
|
||||
|
||||
for source in module.sources:
|
||||
obj_file = os.path.splitext(source)[0] + '.o'
|
||||
tgt = os.path.join(variant.build_root, module.dir, obj_file)
|
||||
src = os.path.join(module.dir, source)
|
||||
if variant.static:
|
||||
obj_builder = env.StaticObject(target = tgt, source = src)
|
||||
else:
|
||||
obj_builder = env.SharedObject(target = tgt, source = src)
|
||||
if len(module.config) > 0:
|
||||
config_file = env.MyCopyBuilder(target = [tgt_config_file],
|
||||
source = [src_config_file])
|
||||
env.Depends(obj_builder, config_file)
|
||||
if variant.gcxx_deps:
|
||||
gcno_tgt = os.path.join(variant.build_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcno')
|
||||
gcda_tgt = os.path.join(variant.build_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcda')
|
||||
gcda_src = os.path.join(variant.gcxx_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcda')
|
||||
gcno_src = os.path.join(variant.gcxx_root, module.dir,
|
||||
os.path.splitext(source)[0] + '.gcno')
|
||||
gcno_builder = env.CopyGcxxBuilder(target = gcno_tgt, source = gcno_src)
|
||||
gcda_builder = env.CopyGcxxBuilder(target = gcda_tgt, source = gcda_src)
|
||||
env.Depends(obj_builder, gcda_builder)
|
||||
env.Depends(obj_builder, gcno_builder)
|
||||
objects.append(obj_builder)
|
||||
return objects
|
||||
def get_internal_deps(self, module, hash):
|
||||
for dep_name in module.deps:
|
||||
dep = self.__get_module(dep_name)
|
||||
hash[dep_name] = dep
|
||||
self.get_internal_deps(dep, hash)
|
||||
def get_external_deps(self, module):
|
||||
hash = {}
|
||||
self.get_internal_deps(module, hash)
|
||||
ext_hash = {}
|
||||
for mod in hash.values():
|
||||
for ext_dep in mod.external_deps:
|
||||
ext_hash[ext_dep] = 1
|
||||
return ext_hash.keys()
|
||||
def get_sorted_deps(self, module):
|
||||
h = {}
|
||||
self.get_internal_deps(module, h)
|
||||
modules = []
|
||||
for dep in h.keys():
|
||||
deps_copy = []
|
||||
mod = h[dep]
|
||||
deps_copy.extend(mod.deps)
|
||||
modules.append([mod, deps_copy])
|
||||
sorted = []
|
||||
while len(modules) > 0:
|
||||
to_remove = []
|
||||
for item in modules:
|
||||
if len(item[1]) == 0:
|
||||
to_remove.append(item[0].name)
|
||||
for item in to_remove:
|
||||
for i in modules:
|
||||
if item in i[1]:
|
||||
i[1].remove(item)
|
||||
new_modules = []
|
||||
for mod in modules:
|
||||
found = False
|
||||
for i in to_remove:
|
||||
if i == mod[0].name:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
new_modules.append(mod)
|
||||
modules = new_modules
|
||||
sorted.extend(to_remove)
|
||||
sorted.reverse()
|
||||
# append external deps
|
||||
ext_deps = self.get_external_deps(module)
|
||||
for dep in ext_deps:
|
||||
sorted.append(dep)
|
||||
return sorted
|
||||
|
||||
def gen_mod_dep(self, variant):
|
||||
build_root = variant.build_root
|
||||
cpp_path = os.path.join(variant.build_root, 'include')
|
||||
env = variant.env
|
||||
env.Append(CPPPATH = [cpp_path])
|
||||
header_dir = os.path.join(build_root, 'include', self.name)
|
||||
lib_path = os.path.join(build_root, 'lib')
|
||||
env.Append (LIBPATH = [lib_path])
|
||||
module_builders = []
|
||||
for module in self.__modules:
|
||||
my_env = env.Copy ();
|
||||
objects = self.get_obj_builders(variant, module)
|
||||
libs = self.get_sorted_deps(module)
|
||||
my_env.Append (LIBS = libs)
|
||||
my_env.Append (LINKFLAGS = module.ldflags)
|
||||
|
||||
filename = self.get_mod_output(module, variant)
|
||||
if module.executable:
|
||||
module_builder = my_env.Program(target=filename, source=objects)
|
||||
else:
|
||||
if variant.static:
|
||||
module_builder = my_env.StaticLibrary(target=filename, source=objects)
|
||||
else:
|
||||
module_builder = my_env.SharedLibrary(target=filename, source=objects)
|
||||
|
||||
for dep_name in module.deps:
|
||||
dep = self.__get_module(dep_name)
|
||||
my_env.Depends(module_builder, self.get_mod_output(dep, variant))
|
||||
|
||||
for header in module.inst_headers:
|
||||
if module.header_inst_dir != '':
|
||||
tgt = os.path.join(header_dir, module.header_inst_dir, header)
|
||||
else:
|
||||
tgt = os.path.join(header_dir, header)
|
||||
src = os.path.join(module.dir, header)
|
||||
#builder = env.Install(target = tgt, source = src)
|
||||
header_builder = my_env.MyCopyBuilder(target=tgt, source=src)
|
||||
my_env.Depends(module_builder, header_builder)
|
||||
|
||||
module_builders.append(module_builder)
|
||||
return module_builders
|
||||
def gen_mod_config(self, env):
|
||||
config_dir = os.path.join(self.build_dir, 'config')
|
||||
for module in self.__modules:
|
||||
if len(module.config) > 0:
|
||||
config_file = os.path.join(config_dir, module.name + '-config.h')
|
||||
config_file_guard = module.name + '_CONFIG_H'
|
||||
config_file_guard.upper()
|
||||
if not os.path.isfile(config_file):
|
||||
if not os.path.isdir(config_dir):
|
||||
os.makedirs(config_dir)
|
||||
outfile = open(config_file, 'w')
|
||||
outfile.write('#ifndef ' + config_file_guard + '\n')
|
||||
outfile.write('#define ' + config_file_guard + '\n')
|
||||
config = env.Configure()
|
||||
for fn in module.config:
|
||||
output = fn(env, config)
|
||||
for o in output:
|
||||
outfile.write(o)
|
||||
outfile.write('\n')
|
||||
outfile.write('#endif /*' + config_file_guard + '*/\n')
|
||||
config.Finish()
|
||||
def generate_dependencies(self):
|
||||
inheritenv = (ARGUMENTS.get('inheritenv', 'n') in 'yY1')
|
||||
if inheritenv:
|
||||
env = Environment(ENV=os.environ)
|
||||
else:
|
||||
env = Environment()
|
||||
self.gen_mod_config(env)
|
||||
cc = env['CC']
|
||||
cxx = env.subst(env['CXX'])
|
||||
if cc == '':
|
||||
print "Missing C compiler."
|
||||
env.Exit (1);
|
||||
if cxx == '':
|
||||
print "Missing C++ compiler."
|
||||
env.Exit (1);
|
||||
common_flags = ARGUMENTS.get('cflags', '').split(' ')
|
||||
cxxflags = ARGUMENTS.get('cxxflags', '').split(' ')
|
||||
ldflags = ARGUMENTS.get('ldflags', '').split(' ')
|
||||
if cc == 'cl' and cxx == 'cl':
|
||||
env = Environment(tools=['mingw'])
|
||||
cc = env['CC']
|
||||
cxx = env.subst(env['CXX'])
|
||||
if cc == 'gcc' and cxx == 'g++':
|
||||
common_flags.extend(['-g3', '-Wall', '-Werror'])
|
||||
debug_flags = []
|
||||
opti_flags = ['-O3']
|
||||
elif cc == 'cl' and cxx == 'cl':
|
||||
env = Environment(ENV=os.environ)
|
||||
debug_flags = ['-W1', '-GX', '-EHsc', '-D_DEBUG', '/MDd']
|
||||
opti_flags = ['-O2', '-EHsc', '-DNDEBUG', '/MD']
|
||||
cc = ARGUMENTS.get ('cc', '')
|
||||
cxx = ARGUMENTS.get ('cxx', '')
|
||||
if cc != '':
|
||||
env.Replace (CC = cc)
|
||||
if cxx != '':
|
||||
env.Replace (CXX = cxx)
|
||||
env.Append(CCFLAGS = common_flags,
|
||||
CPPDEFINES = ['RUN_SELF_TESTS'],
|
||||
TARFLAGS = '-c -z',
|
||||
CPPFLAGS = cxxflags,
|
||||
LINKFLAGS = ldflags)
|
||||
if env['PLATFORM'] == 'posix':
|
||||
env.Append(LINKFLAGS = ' -z origin')
|
||||
env.Append(RPATH=env.Literal(os.path.join('\\$$ORIGIN', os.pardir, 'lib')))
|
||||
verbose = ARGUMENTS.get('verbose', 'n')
|
||||
if verbose == 'n':
|
||||
env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
|
||||
header_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint))
|
||||
env.Append(BUILDERS = {'MyCopyBuilder':header_builder})
|
||||
gcxx_builder = Builder(action = Action(MyCopyAction, strfunction=MyCopyActionPrint),
|
||||
emitter = GcxxEmitter)
|
||||
env.Append(BUILDERS = {'CopyGcxxBuilder':gcxx_builder})
|
||||
variant = Ns3BuildVariant()
|
||||
builders = []
|
||||
|
||||
|
||||
gcov_env = env.Copy()
|
||||
gcov_env.Append(CFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
|
||||
CXXFLAGS = ['-fprofile-arcs', '-ftest-coverage'],
|
||||
LINKFLAGS = ['-fprofile-arcs'])
|
||||
# code coverage analysis
|
||||
variant.static = False
|
||||
variant.env = gcov_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'gcov')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
gcov_env.Alias('gcov', builder)
|
||||
gcov_env.Alias('lcov-report')
|
||||
if 'lcov-report' in COMMAND_LINE_TARGETS:
|
||||
lcov_report_dir = os.path.join(self.build_dir, 'lcov-report')
|
||||
create_dir_command = "rm -rf " + lcov_report_dir
|
||||
create_dir_command += " && mkdir " + lcov_report_dir + ";"
|
||||
gcov_env.Execute(create_dir_command)
|
||||
info_file = os.path.join(lcov_report_dir, self.name + '.info')
|
||||
lcov_command = "utils/lcov/lcov -c -d . -o " + info_file
|
||||
lcov_command += " --source-dirs=" + os.getcwd()
|
||||
lcov_command += ":" + os.path.join(os.getcwd(),
|
||||
variant.build_root,
|
||||
'include')
|
||||
gcov_env.Execute(lcov_command)
|
||||
genhtml_command = "utils/lcov/genhtml -o " + lcov_report_dir
|
||||
genhtml_command += " " + info_file
|
||||
gcov_env.Execute(genhtml_command)
|
||||
|
||||
|
||||
|
||||
opt_env = env.Copy()
|
||||
opt_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
# optimized static support
|
||||
variant.static = True
|
||||
variant.env = opt_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-static')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
opt_env.Alias('opt-static', builder)
|
||||
|
||||
|
||||
opt_env = env.Copy()
|
||||
opt_env.Append(CFLAGS = opti_flags,
|
||||
CXXFLAGS = opti_flags,
|
||||
CPPDEFINES = ['NDEBUG'])
|
||||
# optimized shared support
|
||||
variant.static = False
|
||||
variant.env = opt_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-shared')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
opt_env.Alias('opt-shared', builder)
|
||||
|
||||
|
||||
arc_env = env.Copy()
|
||||
arc_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
arc_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-generate'],
|
||||
CXXFLAGS=['-frandom-seed=0', '-fprofile-generate'],
|
||||
LINKFLAGS=['-frandom-seed=0', '-fprofile-generate'])
|
||||
# arc profiling
|
||||
variant.static = False
|
||||
variant.env = arc_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-arc')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
arc_env.Alias('opt-arc', builder)
|
||||
|
||||
|
||||
arcrebuild_env = env.Copy()
|
||||
arcrebuild_env.Append(CFLAGS=opti_flags,
|
||||
CXXFLAGS=opti_flags,
|
||||
CPPDEFINES=['NDEBUG'])
|
||||
arcrebuild_env.Append(CFLAGS=['-frandom-seed=0', '-fprofile-use'],
|
||||
CXXFLAGS=['-frandom-seed=0', '-fprofile-use'],
|
||||
LINKFLAGS=['-frandom-seed=0', '-fprofile-use'])
|
||||
# arc rebuild
|
||||
variant.static = False
|
||||
variant.env = arcrebuild_env
|
||||
variant.gcxx_deps = True
|
||||
variant.gcxx_root = os.path.join(self.build_dir, 'opt-arc')
|
||||
variant.build_root = os.path.join(self.build_dir, 'opt-arc-rebuild')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
arcrebuild_env.Alias('opt-arc-rebuild', builder)
|
||||
variant.gcxx_deps = False
|
||||
|
||||
|
||||
|
||||
|
||||
dbg_env = env.Copy()
|
||||
dbg_env.Append(CFLAGS = debug_flags,
|
||||
CXXFLAGS = debug_flags,
|
||||
CPPDEFINES = ['NS3_DEBUG_ENABLE',
|
||||
'NS3_ASSERT_ENABLE'])
|
||||
# debug static support
|
||||
variant.static = True
|
||||
variant.env = dbg_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'dbg-static')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
dbg_env.Alias('dbg-static', builder)
|
||||
|
||||
dbg_env = env.Copy()
|
||||
dbg_env.Append(CFLAGS=debug_flags,
|
||||
CXXFLAGS=debug_flags,
|
||||
CPPDEFINES = ['NS3_DEBUG_ENABLE',
|
||||
'NS3_ASSERT_ENABLE'])
|
||||
# debug shared support
|
||||
variant.static = False
|
||||
variant.env = dbg_env
|
||||
variant.build_root = os.path.join(self.build_dir, 'dbg-shared')
|
||||
builders = self.gen_mod_dep(variant)
|
||||
for builder in builders:
|
||||
dbg_env.Alias('dbg-shared', builder)
|
||||
|
||||
env.Alias('dbg', 'dbg-shared')
|
||||
env.Alias('opt', 'opt-shared')
|
||||
env.Default('dbg')
|
||||
env.Alias('all', ['dbg-shared', 'dbg-static', 'opt-shared', 'opt-static'])
|
||||
|
||||
|
||||
# dist support
|
||||
dist_env = env.Copy()
|
||||
if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin':
|
||||
dist_list = []
|
||||
for module in self.__modules:
|
||||
for f in module.sources:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.headers:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.inst_headers:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in module.extra_dist:
|
||||
dist_list.append(os.path.join(module.dir, f))
|
||||
for f in self.extra_dist:
|
||||
dist_list.append(f)
|
||||
dist_list.append (self.doxygen_config)
|
||||
dist_list.append('SConstruct')
|
||||
dist_list.append('build.py')
|
||||
|
||||
targets = []
|
||||
basename = self.distname + '-' + self.version
|
||||
for src in dist_list:
|
||||
tgt = os.path.join(basename, src)
|
||||
targets.append(dist_env.MyCopyBuilder(target=tgt, source=src))
|
||||
tar = basename + '.tar.gz'
|
||||
zip = basename + '.zip'
|
||||
tmp_tar = os.path.join(self.build_dir, tar)
|
||||
tmp_zip = os.path.join(self.build_dir, zip)
|
||||
dist_tgt = [tar, zip]
|
||||
dist_src = [tmp_tar, tmp_zip]
|
||||
dist_env.Tar(tmp_tar, targets)
|
||||
dist_env.Zip(tmp_zip, targets)
|
||||
dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
|
||||
dist_env.Alias('dist', dist_builder)
|
||||
dist_env.Append(RM_DIR=basename)
|
||||
dist_env.AddPostAction(dist_builder, dist_env.Action(MyRmTree,
|
||||
strfunction=MyRmTreePrint))
|
||||
dist_builder = dist_env.MyCopyBuilder(target=dist_tgt, source=dist_src)
|
||||
dist_env.Alias('fastdist', dist_tgt)
|
||||
|
||||
# distcheck
|
||||
distcheck_list = []
|
||||
for src in dist_list:
|
||||
tgt = os.path.join(self.build_dir, basename, src)
|
||||
distcheck_list.append(tgt)
|
||||
untar = env.Command(distcheck_list, tar,
|
||||
['cd ' + self.build_dir + ' && tar -zxf ../' + tar])
|
||||
scons_dir = os.path.join(self.build_dir, basename)
|
||||
distcheck_builder = env.Command('x', distcheck_list,
|
||||
['cd ' + scons_dir + ' && scons'])
|
||||
env.AlwaysBuild(distcheck_builder)
|
||||
env.Alias('distcheck', distcheck_builder)
|
||||
if self.doxygen_config != '':
|
||||
doxy = env.Command('doc/html/*', self.doxygen_config,
|
||||
['doxygen ' + self.doxygen_config])
|
||||
env.AlwaysBuild(doxy)
|
||||
env.Alias('doc', doxy)
|
||||
+25
-33
@@ -3,70 +3,62 @@ build system (http://www.freehackers.org/~tnagy/waf.html)
|
||||
|
||||
=== Installing Waf ===
|
||||
|
||||
If this file is part of a development release tarball, the top-level
|
||||
ns-3 directory should contain a current waf script.
|
||||
|
||||
However, the ns-3 Mercurial code repository does not contain the waf
|
||||
script. Instead, developers should check it out from a subversion
|
||||
repository:
|
||||
|
||||
svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
|
||||
|
||||
[ note: 'tags/ns3' is a tag that represents the last svn version
|
||||
tested to work correctly with ns3, although 'trunk' will likely work
|
||||
as well ]
|
||||
|
||||
Then it can be installed system-wide with 'sudo waf-light install'.
|
||||
When preparing a distribution, the resulting 'waf' script, which is
|
||||
self contained (no external files needed), can be easily included in
|
||||
the tarball so that users downloading ns-3 can easily build it without
|
||||
having Waf installed (although Python >= 2.3 is still needed).
|
||||
The top-level ns-3 directory should contain a current waf script.
|
||||
|
||||
=== Building with Waf ===
|
||||
|
||||
To build ns-3 with waf type the commands:
|
||||
1. waf configure [options]
|
||||
2. waf
|
||||
To build ns-3 with waf type the commands from the top-level directory:
|
||||
1. ./waf configure [options]
|
||||
2. ./waf
|
||||
|
||||
To see valid configure options, type waf --help. The most important
|
||||
To see valid configure options, type ./waf --help. The most important
|
||||
option is -d <debug level>. Valid debug levels (which are listed in
|
||||
waf --help) are: ultradebug, debug, release, and optimized. It is
|
||||
waf --help) are: "debug" or "optimized". It is
|
||||
also possible to change the flags used for compilation with (e.g.):
|
||||
CXXFLAGS="-O3" waf configure.
|
||||
CXXFLAGS="-O3" ./waf configure.
|
||||
|
||||
[ Note: Unlike some other build tools, to change the build target,
|
||||
the option must be supplied during the configure stage rather than
|
||||
the build stage (i.e., "waf -d optimized" will not work; instead, do
|
||||
"waf -d optimized configure; waf" ]
|
||||
the build stage (i.e., "./waf -d optimized" will not work; instead, do
|
||||
"./waf -d optimized configure; ./waf" ]
|
||||
|
||||
The resulting binaries are placed in build/<debuglevel>/srcpath.
|
||||
|
||||
Other waf usages include:
|
||||
|
||||
1. waf check
|
||||
1. ./waf check
|
||||
Runs the unit tests
|
||||
|
||||
2. waf --doxygen
|
||||
2. ./waf --doxygen
|
||||
Run doxygen to generate documentation
|
||||
|
||||
3. waf --lcov-report
|
||||
3. ./waf --lcov-report
|
||||
Run code coverage analysis (assuming the project was configured
|
||||
with --enable-gcov)
|
||||
|
||||
4. waf --run "program [args]"
|
||||
4. ./waf --run "program [args]"
|
||||
Run a ns3 program, given its target name, with the given
|
||||
arguments. This takes care of automatically modifying the the
|
||||
path for finding the ns3 dynamic libraries in the environment
|
||||
before running the program. Note: the "program [args]" string is
|
||||
parsed using POSIX shell rules.
|
||||
|
||||
5. waf --shell
|
||||
4.1 ./waf --run programname --command-template "... %s ..."
|
||||
|
||||
Same as --run, but uses a command template with %s replaced by the
|
||||
actual program (whose name is given by --run). This can be use to
|
||||
run ns-3 programs with helper tools. For example, to run unit
|
||||
tests with valgrind, use the command:
|
||||
|
||||
./waf --run run-tests --command-template "valgrind %s"
|
||||
|
||||
5. ./waf --shell
|
||||
Starts a nested system shell with modified environment to run ns3 programs.
|
||||
|
||||
6. waf distclean
|
||||
6. ./waf distclean
|
||||
Cleans out the entire build/ directory
|
||||
|
||||
7. waf dist
|
||||
7. ./waf dist
|
||||
The command 'waf dist' can be used to create a distribution tarball.
|
||||
It includes all files in the source directory, except some particular
|
||||
extensions that are blacklisted, such as back files (ending in ~).
|
||||
|
||||
+158
-65
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.4.4
|
||||
# Doxyfile 1.5.4
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
@@ -14,10 +14,18 @@
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# This tag specifies the encoding used for all characters in the config file that
|
||||
# follow. The default is UTF-8 which is also the encoding used for all text before
|
||||
# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
|
||||
# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
|
||||
# possible encodings.
|
||||
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
|
||||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
|
||||
PROJECT_NAME = "NS-3"
|
||||
PROJECT_NAME = "NS-3 "
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
@@ -45,24 +53,14 @@ CREATE_SUBDIRS = NO
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# The default language is English, other supported languages are:
|
||||
# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
|
||||
# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
|
||||
# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
|
||||
# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
|
||||
# Swedish, and Ukrainian.
|
||||
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
|
||||
# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
|
||||
# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
|
||||
# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
|
||||
# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# This tag can be used to specify the encoding used in the generated output.
|
||||
# The encoding is not always determined by the language that is chosen,
|
||||
# but also whether or not the output is meant for Windows or non-Windows users.
|
||||
# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
|
||||
# forces the Windows encoding (this is the default for the Windows binary),
|
||||
# whereas setting the tag to NO uses a Unix-style encoding (the default for
|
||||
# all platforms other than Windows).
|
||||
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
# the file and class documentation (similar to JavaDoc).
|
||||
@@ -135,11 +133,19 @@ SHORT_NAMES = NO
|
||||
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||
# comment as the brief description. If set to NO, the JavaDoc
|
||||
# comments will behave just like the Qt-style comments (thus requiring an
|
||||
# explicit @brief command for a brief description.
|
||||
# comments will behave just like regular Qt-style comments
|
||||
# (thus requiring an explicit @brief command for a brief description.)
|
||||
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
|
||||
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
|
||||
# interpret the first line (until the first dot) of a Qt-style
|
||||
# comment as the brief description. If set to NO, the comments
|
||||
# will behave just like regular Qt-style comments (thus requiring
|
||||
# an explicit \brief command for a brief description.)
|
||||
|
||||
QT_AUTOBRIEF = NO
|
||||
|
||||
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
|
||||
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
|
||||
# comments) as a brief description. This used to be the default behaviour.
|
||||
@@ -161,13 +167,6 @@ DETAILS_AT_TOP = NO
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
|
||||
# a new page for each member. If set to NO, the documentation of a member will
|
||||
# be part of the file/class/namespace that contains it.
|
||||
@@ -195,13 +194,40 @@ ALIASES =
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
|
||||
# only. Doxygen will then generate output that is more tailored for Java.
|
||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
|
||||
# sources only. Doxygen will then generate output that is more tailored for Java.
|
||||
# For instance, namespaces will be presented as packages, qualified scopes
|
||||
# will look different, etc.
|
||||
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
|
||||
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
|
||||
# include (a tag file for) the STL sources as input, then you should
|
||||
# set this tag to YES in order to let doxygen match functions declarations and
|
||||
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
|
||||
# func(std::string) {}). This also make the inheritance and collaboration
|
||||
# diagrams that involve STL classes more complete and accurate.
|
||||
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
|
||||
# If you use Microsoft's C++/CLI language, you should set this option to YES to
|
||||
# enable parsing support.
|
||||
|
||||
CPP_CLI_SUPPORT = NO
|
||||
|
||||
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
|
||||
# Doxygen will parse them like normal C++ but will assume all classes use public
|
||||
# instead of private inheritance when no explicit protection keyword is present.
|
||||
|
||||
SIP_SUPPORT = NO
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
|
||||
# the same type (for instance a group of public functions) to be put as a
|
||||
# subgroup of that type (e.g. under the Public Functions section). Set it to
|
||||
@@ -210,6 +236,16 @@ OPTIMIZE_OUTPUT_JAVA = NO
|
||||
|
||||
SUBGROUPING = YES
|
||||
|
||||
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is
|
||||
# documented as struct with the name of the typedef. So
|
||||
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
|
||||
# with name TypeT. When disabled the typedef will appear as a member of a file,
|
||||
# namespace, or class. And the struct will be named TypeS. This can typically
|
||||
# be useful for C code where the coding convention is that all structs are
|
||||
# typedef'ed and only the typedef is referenced never the struct's name.
|
||||
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -244,6 +280,13 @@ EXTRACT_LOCAL_CLASSES = NO
|
||||
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
|
||||
# If this flag is set to YES, the members of anonymous namespaces will be extracted
|
||||
# and appear in the documentation as a namespace called 'anonymous_namespace{file}',
|
||||
# where file will be replaced with the base name of the file that contains the anonymous
|
||||
# namespace. By default anonymous namespace are hidden.
|
||||
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||
# undocumented members of documented classes, files or namespaces.
|
||||
# If set to NO (the default) these members will be included in the
|
||||
@@ -376,7 +419,7 @@ SHOW_USED_FILES = YES
|
||||
|
||||
# If the sources in your project are distributed over multiple directories
|
||||
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
|
||||
# in the documentation. The default is YES.
|
||||
# in the documentation. The default is NO.
|
||||
|
||||
SHOW_DIRECTORIES = NO
|
||||
|
||||
@@ -385,7 +428,7 @@ SHOW_DIRECTORIES = NO
|
||||
# version control system). Doxygen will invoke the program by executing (via
|
||||
# popen()) the command <command> <input-file>, where <command> is the value of
|
||||
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
|
||||
# provided by doxygen. Whatever the progam writes to standard output
|
||||
# provided by doxygen. Whatever the program writes to standard output
|
||||
# is used as the file version. See the manual for examples.
|
||||
|
||||
FILE_VERSION_FILTER =
|
||||
@@ -397,7 +440,7 @@ FILE_VERSION_FILTER =
|
||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
QUIET = NO
|
||||
QUIET = YES
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||
@@ -433,7 +476,7 @@ WARN_NO_PARAMDOC = NO
|
||||
# $version, which will be replaced by the version of the file (if it could
|
||||
# be obtained via FILE_VERSION_FILTER)
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_FORMAT = "$file:$line: $text "
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
||||
# and error messages should be written. If left blank the output is written
|
||||
@@ -450,16 +493,28 @@ WARN_LOGFILE =
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = src doc/main.txt
|
||||
INPUT = doc/modules \
|
||||
doc/main.h \
|
||||
doc/introspected-doxygen.h \
|
||||
doc/howtos/ \
|
||||
src
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files that
|
||||
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
|
||||
# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
|
||||
# See http://www.gnu.org/software/libiconv for the list of possible encodings.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank the following patterns are tested:
|
||||
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
|
||||
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
|
||||
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
|
||||
|
||||
FILE_PATTERNS = *.h *.tcc
|
||||
FILE_PATTERNS = *.h \
|
||||
*.tcc
|
||||
|
||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||
# should be searched for input files as well. Possible values are YES and NO.
|
||||
@@ -471,10 +526,12 @@ RECURSIVE = YES
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
|
||||
EXCLUDE = \
|
||||
src/simulator/high-precision.h \
|
||||
src/simulator/high-precision-128.h \
|
||||
src/simulator/high-precision-double.h
|
||||
EXCLUDE = src/routing/olsr/olsr-state.h \
|
||||
src/routing/olsr/repositories.h \
|
||||
src/routing/olsr/routing-table.h \
|
||||
src/simulator/high-precision.h \
|
||||
src/simulator/high-precision-128.h \
|
||||
src/simulator/high-precision-double.h
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
|
||||
# directories that are symbolic links (a Unix filesystem feature) are excluded
|
||||
@@ -490,6 +547,13 @@ EXCLUDE_SYMLINKS = NO
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the output.
|
||||
# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
|
||||
# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
|
||||
|
||||
EXCLUDE_SYMBOLS =
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
@@ -514,7 +578,7 @@ EXAMPLE_RECURSIVE = NO
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH =
|
||||
IMAGE_PATH = doc
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
@@ -548,7 +612,9 @@ FILTER_SOURCE_FILES = NO
|
||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||
# be generated. Documented entities will be cross-referenced with these sources.
|
||||
# Note: To get rid of all source code in the generated output, make sure also
|
||||
# VERBATIM_HEADERS is set to NO.
|
||||
# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH
|
||||
# then you must also enable this option. If you don't then doxygen will produce
|
||||
# a warning and turn it on anyway
|
||||
|
||||
SOURCE_BROWSER = NO
|
||||
|
||||
@@ -575,6 +641,13 @@ REFERENCED_BY_RELATION = YES
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
|
||||
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
|
||||
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
|
||||
# link to the source code. Otherwise they will link to the documentstion.
|
||||
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
|
||||
# If the USE_HTAGS tag is set to YES then the references to source code
|
||||
# will point to the HTML generated by the htags(1) tool instead of doxygen
|
||||
# built-in source browser. The htags tool is part of GNU's global source
|
||||
@@ -667,6 +740,14 @@ HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
||||
# page has loaded. For this to work a browser that supports
|
||||
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
|
||||
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
|
||||
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
|
||||
# be used to specify the file name of the resulting .chm file. You
|
||||
# can add a path in front of the file if the result should not be
|
||||
@@ -965,13 +1046,13 @@ ENABLE_PREPROCESSING = YES
|
||||
# compilation will be performed. Macro expansion can be done in a controlled
|
||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
MACRO_EXPANSION = YES
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||
# then the macro expansion is limited to the macros specified with the
|
||||
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||
# PREDEFINED and EXPAND_AS_DEFINED tags.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||
@@ -999,14 +1080,18 @@ INCLUDE_FILE_PATTERNS =
|
||||
# undefined via #undef or recursively expanded use the := operator
|
||||
# instead of the = operator.
|
||||
|
||||
PREDEFINED = RUN_SELF_TESTS NS3_DEBUG_ENABLE
|
||||
PREDEFINED = RUN_SELF_TESTS \
|
||||
NS3_ASSERT_ENABLE \
|
||||
NS3_LOG_ENABLE
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
EXPAND_AS_DEFINED = ATTRIBUTE_VALUE_DEFINE \
|
||||
ATTRIBUTE_VALUE_DEFINE_WITH_NAME \
|
||||
ATTRIBUTE_HELPER_HEADER_2
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
||||
# doxygen's preprocessor will remove all function-like macros that are alone
|
||||
@@ -1072,6 +1157,14 @@ PERL_PATH = /usr/bin/perl
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# You can define message sequence charts within doxygen comments using the \msc
|
||||
# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
|
||||
# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
|
||||
# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
|
||||
# be found in the default search path.
|
||||
|
||||
MSCGEN_PATH =
|
||||
|
||||
# If set to YES, the inheritance and collaboration graphs will hide
|
||||
# inheritance and usage relations if the target is undocumented
|
||||
# or is not a class.
|
||||
@@ -1129,7 +1222,7 @@ INCLUDE_GRAPH = YES
|
||||
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
|
||||
# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
|
||||
# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
|
||||
# generate a call dependency graph for every global function or class method.
|
||||
# Note that enabling this option will significantly increase the time of a run.
|
||||
# So in most cases it will be better to enable call graphs for selected
|
||||
@@ -1137,6 +1230,14 @@ INCLUDED_BY_GRAPH = YES
|
||||
|
||||
CALL_GRAPH = NO
|
||||
|
||||
# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
|
||||
# generate a caller dependency graph for every global function or class method.
|
||||
# Note that enabling this option will significantly increase the time of a run.
|
||||
# So in most cases it will be better to enable caller graphs for selected
|
||||
# functions only using the \callergraph command.
|
||||
|
||||
CALLER_GRAPH = NO
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
|
||||
@@ -1166,31 +1267,23 @@ DOT_PATH =
|
||||
|
||||
DOTFILE_DIRS =
|
||||
|
||||
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
|
||||
# nodes that will be shown in the graph. If the number of nodes in a graph
|
||||
# becomes larger than this value, doxygen will truncate the graph, which is
|
||||
# visualized by representing a node as a red box. Note that doxygen if the number
|
||||
# of direct children of the root node in a graph is already larger than
|
||||
# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note
|
||||
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
|
||||
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
|
||||
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
|
||||
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
|
||||
# graphs generated by dot. A depth value of 3 means that only nodes reachable
|
||||
# from the root by following a path via at most 3 edges will be shown. Nodes
|
||||
# that lay further from the root node will be omitted. Note that setting this
|
||||
# option to 1 or 2 may greatly reduce the computation time needed for large
|
||||
# code bases. Also note that a graph may be further truncated if the graph's
|
||||
# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
|
||||
# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
|
||||
# the graph is not depth-constrained.
|
||||
# code bases. Also note that the size of a graph can be further restricted by
|
||||
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
|
||||
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/*!
|
||||
\page application How to create a traffic generator ?
|
||||
\anchor howtos-application
|
||||
|
||||
<b>Question:</b> How do I create a new traffic generator ?
|
||||
|
||||
<b>Answer:</b> It is possible to instanciate \ref ns3::Packet "Packet"
|
||||
objects, schedule events, and call functions from any piece of code
|
||||
in ns-3 so, technically, there is no single answer to the question of
|
||||
how we can write a new traffic generator. However, the
|
||||
\ref ns3::Socket "Socket" API was really designed to be the single
|
||||
point of entry for traffic generators or traffic analysers and the
|
||||
\ref ns3::Application "Application" class was designed to hold
|
||||
together any number of sockets.
|
||||
|
||||
Implementing a new traffic generator thus boils down to:
|
||||
- implementing a new subclass of the \ref ns3::Application "Application"
|
||||
base class
|
||||
- instanciate one or many sockets within that application
|
||||
- start scheduling events when \ref ns3::Application::StartApplication "StartApplication"
|
||||
is called
|
||||
- stop scheduling events when \ref ns3::Application::StopApplication "StopApplication"
|
||||
is called
|
||||
- create packets and send them over one or many sockets in each event
|
||||
|
||||
The following "random" generator generates packets separated by a random
|
||||
delay and with a random size.
|
||||
|
||||
\code
|
||||
class RandomGenerator : public Application
|
||||
{
|
||||
public:
|
||||
RandomGenerator ();
|
||||
void SetDelay (RandomVariable delay);
|
||||
void SetSize (RandomVariable size);
|
||||
void SetRemote (std::string socketType,
|
||||
Address remote);
|
||||
private:
|
||||
virtual void StartApplication (void);
|
||||
virtual void StopApplication (void);
|
||||
void DoGenerate (void);
|
||||
|
||||
RandomVariable m_delay;
|
||||
RandomVariable m_size;
|
||||
Ptr<Socket> m_socket;
|
||||
};
|
||||
\endcode
|
||||
|
||||
The socket is created in the SetRemote method:
|
||||
\code
|
||||
void
|
||||
RandomGenerator::SetRemote (std::string socketType,
|
||||
Address remote)
|
||||
{
|
||||
TypeId tid = TypeId::LookupByName (socketType);
|
||||
m_socket = Socket::CreateSocket (GetNode (), tid);
|
||||
m_socket->Bind ();
|
||||
m_socket->ShutdownRecv ();
|
||||
m_socket->Connect (remote);
|
||||
}
|
||||
\endcode
|
||||
While the the crux of the logic is located in the DoGenerate method
|
||||
which is called from within StartApplication:
|
||||
\code
|
||||
void
|
||||
RandomGenerator::DoGenerate (void)
|
||||
{
|
||||
m_next = Simulator::Schedule (Seconds (m_delay.GetValue ()),
|
||||
&RandomGenerator::DoGenerate, this);
|
||||
Ptr<Packet> p = Create<Packet> (m_size.GetIntValue ());
|
||||
m_socket->Send (p);
|
||||
}
|
||||
\endcode
|
||||
|
||||
To make that application more integrated in ns-3, it needs an associated
|
||||
helper class:
|
||||
\code
|
||||
class RandomAppHelper
|
||||
{
|
||||
public:
|
||||
RandomAppHelper (std::string protocol, Address remote);
|
||||
void SetPacketSize (RandomVariable packetSize);
|
||||
void SetDelay (RandomVariable delay);
|
||||
ApplicationContainer Install (NodeContainer nodes);
|
||||
private:
|
||||
std::string m_protocol;
|
||||
Address m_remote;
|
||||
RandomVariable m_packetSize;
|
||||
RandomVariable m_delay;
|
||||
};
|
||||
\endcode
|
||||
|
||||
which could be trivially implemented as:
|
||||
\code
|
||||
ApplicationContainer
|
||||
RandomAppHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
ApplicationContainer applications;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<RandomAppHelper> app = CreateObject<RandomAppHelper> ();
|
||||
app->SetSize (m_packetSize);
|
||||
app->SetDelay (m_delay);
|
||||
app->SetRemote (m_protocol, m_remote);
|
||||
(*i)->AddApplication (app);
|
||||
applications.Add (app);
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Despite being functional, this API is not very consistant with the style of
|
||||
the other helper classes, all of which allow you to control the parameters
|
||||
of the underlying class through attributes and not explicit setters. The
|
||||
following API thus replaces the pair SetPacketSize/SetDelay with a single
|
||||
method SetAttribute:
|
||||
\code
|
||||
class RandomAppHelper
|
||||
{
|
||||
public:
|
||||
RandomAppHelper (std::string protocol, Address remote);
|
||||
void SetAttribute (std::string name, const AttributeValue &value);
|
||||
ApplicationContainer Install (NodeContainer c);
|
||||
private:
|
||||
std::string m_protocol;
|
||||
Address m_remote;
|
||||
ObjectFactory m_factory;
|
||||
};
|
||||
\endcode
|
||||
|
||||
And which can be used as follows:
|
||||
\code
|
||||
RandomAppHelper app = RandomAppHelper ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address ("192.168.1.10"), 10));
|
||||
app.SetAttribute ("Delay", StringValue ("Constant:2.5"));
|
||||
app.SetAttribute ("Size", StringValue ("Constant:2100"));
|
||||
app.Install (nodes);
|
||||
\endcode
|
||||
|
||||
The implementation, in this case, is not necessarily longer but its
|
||||
simplicity hides a lot of behind-the-scenes complexity:
|
||||
|
||||
\code
|
||||
void
|
||||
RandomAppHelper::SetAttribute (std::string name, const AttributeValue &value)
|
||||
{
|
||||
m_factory.Set (name, value);
|
||||
}
|
||||
ApplicationContainer
|
||||
RandomAppHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
ApplicationContainer applications;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<RandomAppHelper> app = m_factory.Create<RandomAppHelper> ();
|
||||
app->SetRemote (m_socketType, m_remote);
|
||||
(*i)->AddApplication (app);
|
||||
applications.Add (app);
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
\endcode
|
||||
|
||||
The key difference between this implementation and the previous one
|
||||
is that this helper does not handle explicitely the attributes
|
||||
delay and packet size. Instead, it stores them in an
|
||||
\ref ns3::ObjectFactory "ObjectFactory" object. This, of course,
|
||||
does not work magically, and requires extra support from the
|
||||
underlying RandomGenerator class. Specifically, it requires
|
||||
that the underlying RandomGenerator defines its attributes
|
||||
in its \ref ns3::TypeId "TypeId" in a new public static method:
|
||||
|
||||
\code
|
||||
class RandomGenerator
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
};
|
||||
\endcode
|
||||
|
||||
The corresponding implementation is shown below:
|
||||
|
||||
\code
|
||||
TypeId
|
||||
RandomGenerator::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("RandomGenerator")
|
||||
.SetParent<Application> ()
|
||||
.AddConstructor<RandomGenerator> ()
|
||||
.AddAttribute ("Delay", "The delay between two packets (s)",
|
||||
RandomVariableValue (ConstantVariable (1.0)),
|
||||
MakeRandomVariableAccessor (&RandomGenerator::m_delay),
|
||||
MakeRandomVariableChecker ())
|
||||
.AddAttribute ("PacketSize", "The size of each packet (bytes)",
|
||||
RandomVariableValue (ConstantVariable (2000)),
|
||||
MakeRandomVariableAccessor (&RandomGenerator::m_size),
|
||||
MakeRandomVariableChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
\endcode
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
\page callbacks Using ns-3 callbacks
|
||||
\anchor howtos-callbacks
|
||||
|
||||
\section null_callbacks Null Callbacks
|
||||
|
||||
<b>Question:</b> The API I am using calls for using a callback (in the
|
||||
function signature), but I do not
|
||||
want to provide one. Is there a way to provide a null callback?
|
||||
|
||||
<b>Answer:</b> Use the ns3::MakeNullCallback construct:
|
||||
\code
|
||||
template<typename R>
|
||||
Callback< R, T1, T2, T3, T4, T5, T6 > ns3::MakeNullCallback (void)
|
||||
\endcode
|
||||
|
||||
Example usage: The ns3::Socket class uses callbacks to indicate completion
|
||||
of events such as a successful TCP connect(). These callbacks are set
|
||||
in the following function:
|
||||
\code
|
||||
void Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
|
||||
Callback<void, Ptr<Socket> > connectionFailed,
|
||||
Callback<void, Ptr<Socket> > halfClose);
|
||||
|
||||
\endcode
|
||||
But suppose you do not care about registering a callback for the
|
||||
halfClose event (but you want to register one for the
|
||||
connectionSucceeded and connectionFailed cases). In that case, you
|
||||
can pass a null callback as the third argument. You just need to
|
||||
pass a callback with the matching signature, as follows:
|
||||
\code
|
||||
localSocket->SetConnectCallback (
|
||||
MakeCallback (&ConnectionSucceededCallback),
|
||||
MakeCallback (&ConnectionFailedCallback),
|
||||
MakeNullCallback<void, Ptr<Socket> > () );
|
||||
\endcode
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,162 @@
|
||||
/*!
|
||||
\page net-device How to create a new OSI layer 1 + 2 implementation ?
|
||||
\anchor howtos-net-device
|
||||
|
||||
<b>Question:</b> How do I integrate a new OSI layer 1 + 2 implementation ?
|
||||
|
||||
<b>Answer:</b> The OSI layers 1 and 2 are represented by the ns3::NetDevice
|
||||
and ns3::Channel classes. To plug transparently in ns-3, a new layer 1+2 model
|
||||
thus simply needs to provide two new subclasses of these two base classes.
|
||||
|
||||
To make that subclassing process easy, two skeleton classes are provided in
|
||||
the src/node directory: simple-net-device.h (ns3::SimpleNetDevice) and
|
||||
simple-channel.h (ns3::SimpleChannel) implement a broadcast passthru medium
|
||||
using 48bit MAC addresses without any kind of MAC access algorithm or PHY
|
||||
layer modeling.
|
||||
|
||||
The ns3::SimpleChannel class is really very simple: it provides
|
||||
an implementation for the ns3::Channel::GetNDevices and ns3::Channel::GetDevice
|
||||
methods defined in the Channel base class and, then defines the channel-specific
|
||||
send and add methods:
|
||||
- The Add method is used by SimpleNetDevice::SetChannel to register a new
|
||||
SimpleNetDevice with its associated channel.
|
||||
- The Send method is used by SimpleNetDevice::Send to send a packet over the
|
||||
broadcast medium and ensure that it gets delivered to all associated devices
|
||||
(except the sender).
|
||||
|
||||
\code
|
||||
class SimpleChannel : public Channel
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
SimpleChannel ();
|
||||
|
||||
void Send (Ptr<Packet> p, uint16_t protocol, Mac48Address to, Mac48Address from,
|
||||
Ptr<SimpleNetDevice> sender);
|
||||
|
||||
void Add (Ptr<SimpleNetDevice> device);
|
||||
|
||||
// inherited from ns3::Channel
|
||||
virtual uint32_t GetNDevices (void) const;
|
||||
virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
|
||||
|
||||
private:
|
||||
std::vector<Ptr<SimpleNetDevice> > m_devices;
|
||||
};
|
||||
\endcode
|
||||
|
||||
The SimpleNetDevice class is also trivial since it implements no special
|
||||
MAC-layer processing:
|
||||
\code
|
||||
class SimpleNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
SimpleNetDevice ();
|
||||
|
||||
void Receive (Ptr<Packet> packet, uint16_t protocol, Mac48Address to, Mac48Address from);
|
||||
void SetChannel (Ptr<SimpleChannel> channel);
|
||||
void SetAddress (Mac48Address address);
|
||||
|
||||
// inherited from NetDevice base class.
|
||||
virtual void SetName(const std::string name);
|
||||
...
|
||||
};
|
||||
\endcode
|
||||
|
||||
The code below illustrates how the three model-specific methods defined above are
|
||||
implemented:
|
||||
|
||||
\code
|
||||
void
|
||||
SimpleNetDevice::Receive (Ptr<Packet> packet, uint16_t protocol,
|
||||
Mac48Address to, Mac48Address from)
|
||||
{
|
||||
if (to == m_address || to == Mac48Address::GetBroadcast ())
|
||||
{
|
||||
m_rxCallback (this, packet, protocol, from);
|
||||
}
|
||||
}
|
||||
void
|
||||
SimpleNetDevice::SetChannel (Ptr<SimpleChannel> channel)
|
||||
{
|
||||
m_channel = channel;
|
||||
m_channel->Add (this);
|
||||
}
|
||||
void
|
||||
SimpleNetDevice::SetAddress (Mac48Address address)
|
||||
{
|
||||
m_address = address;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Building a topology with such a device is then a matter of
|
||||
instanciating a set of SimpleNetDevice objects connected on a shared
|
||||
SimpleChannel:
|
||||
\code
|
||||
NodeContainer nodes;
|
||||
nodes.Create (10);
|
||||
Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
|
||||
for (uint32_t i = 0; i < nodes.GetN (); ++i)
|
||||
{
|
||||
CreateSimpleDevice (nodes.Get (i), channel);
|
||||
}
|
||||
\endcode
|
||||
|
||||
With the following CreateSimpleDevice function:
|
||||
\code
|
||||
static Ptr<SimpleNetDevice>
|
||||
CreateSimpleDevice (Ptr<Node> node, Ptr<SimpleChannel> channel)
|
||||
{
|
||||
Ptr<SimpleNetDevice> device = CreateObject<SimpleNetDevice> ();
|
||||
device->SetAddress (Mac48Address:Allocate ());
|
||||
device->SetChannel (channel);
|
||||
node->AddDevice (device);
|
||||
return device;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Of course, ultimately, you need to provide a helper class for this new device and channel
|
||||
to save each user from having to re-implement their own CreateSimpleDevice helper
|
||||
function:
|
||||
|
||||
\code
|
||||
class SimpleHelper
|
||||
{
|
||||
public:
|
||||
NetDeviceContainer Install (NodeContainer nodes, Ptr<SimpleChannel> channel);
|
||||
NetDeviceContainer Install (NodeContainer nodes);
|
||||
};
|
||||
\endcode
|
||||
|
||||
with the following straightforward implementation, inspired by the CreateSimpleDevice
|
||||
function defined above:
|
||||
|
||||
\code
|
||||
NetDeviceContainer
|
||||
SimpleHelper::Install (NodeContainer nodes, Ptr<SimpleChannel> channel)
|
||||
{
|
||||
NetDeviceContainer devices;
|
||||
for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i)
|
||||
{
|
||||
Ptr<SimpleNetDevice> dev = CreateObject<SimpleNetDevice> ();
|
||||
dev->SetAddress (Mac48Address::Allocate ());
|
||||
dev->SetChannel (channel);
|
||||
(*i)->AddDevice (dev);
|
||||
devices.Add (dev);
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
NetDeviceContainer
|
||||
SimpleHelper::Install (NodeContainer nodes)
|
||||
{
|
||||
return Install (nodes, CreateObject<SimpleChannel> ());
|
||||
}
|
||||
\endcode
|
||||
|
||||
Of course, at some point, this device helper class should also contain a couple of
|
||||
ascii and pcap tracing helper functions but, since the default SimpleNetDevice
|
||||
class we used as an example here does not report any trace event, it would
|
||||
be of little use.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,119 @@
|
||||
/*!
|
||||
\page packet-header-trailer How to create a new type of protocol header or trailer
|
||||
\anchor howtos-packet-header-trailer
|
||||
|
||||
<b>Question:</b> I want to implement a new protocol X which uses a new
|
||||
type of header Y. How do I implement and use this new header Y in ns-3 ?
|
||||
|
||||
<b>Answer:</b> The key is to implement a new subclass of the ns3::Header
|
||||
base class to represent your protocol header:
|
||||
\code
|
||||
class YHeader : public Header
|
||||
{
|
||||
public:
|
||||
// must be implemented to become a valid new header.
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
virtual void Print (std::ostream &os) const;
|
||||
|
||||
// allow protocol-specific access to the header data.
|
||||
void SetData (uint32_t data);
|
||||
uint32_t GetData (void) const;
|
||||
private:
|
||||
uint32_t m_data;
|
||||
};
|
||||
\endcode
|
||||
|
||||
Once this class is implemented, you can easily store your protocol
|
||||
header into a packet:
|
||||
\code
|
||||
Ptr<Packet> p = ...;
|
||||
YHeader yHeader;
|
||||
yHeader.SetData (0xdeadbeaf);
|
||||
// copy the header into the packet
|
||||
p->AddHeader (yHeader);
|
||||
\endcode
|
||||
and get it out of a packet:
|
||||
\code
|
||||
Ptr<Packet> p = ...;
|
||||
YHeader yHeader;
|
||||
// copy the header from the packet
|
||||
p->RemoveHeader (yHeader);
|
||||
uint32_t data = yHeader.GetData ();
|
||||
\endcode
|
||||
|
||||
The implementation of the new header is very simple. First, you need
|
||||
to give a TypeId to your YHeader class:
|
||||
\code
|
||||
TypeId
|
||||
YHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("YHeader")
|
||||
.SetParent<Header> ()
|
||||
.AddConstructor<YHeader> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
YHeader::GetInstanceTypeId (void)
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
\endcode
|
||||
|
||||
Then, you need to allow your header to serialize and deserialize itself
|
||||
to a byte buffer in its network representation. Here, our new protocol
|
||||
header contains first a 2-byte constant, and, then, the data field so,
|
||||
the total size of the header is 2+4=6 bytes.
|
||||
\code
|
||||
uint32_t
|
||||
YHeader::GetSerializedSize (void) const
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
void
|
||||
YHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
// The 2 byte-constant
|
||||
start.WriteU8 (0xfe);
|
||||
start.WriteU8 (0xef);
|
||||
// The data.
|
||||
start.WriteHtonU32 (m_data);
|
||||
}
|
||||
uint32_t
|
||||
YHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
uint8_t tmp;
|
||||
tmp = start.ReadU8 ();
|
||||
NS_ASSERT (tmp == 0xfe);
|
||||
tmp = start.ReadU8 ();
|
||||
NS_ASSERT (tmp == 0xef);
|
||||
m_data = start.ReadNtohU32 ();
|
||||
return 6; // the number of bytes consumed.
|
||||
}
|
||||
\endcode
|
||||
|
||||
Finally, to make sure that Packet::Print also prints the content
|
||||
of your header, just as it prints the content of the other
|
||||
headers of the system, you need to provide a Print method:
|
||||
\code
|
||||
void
|
||||
YHeader::Print (std::ostream &os) const
|
||||
{
|
||||
os << "data=" << m_data;
|
||||
}
|
||||
\endcode
|
||||
|
||||
The code will look the same if you want to implement a trailer,
|
||||
that is, a protocol data structure which will be appended to the
|
||||
end of the packet, not its start: you need to make sure that
|
||||
you derive from the ns3::Trailer base class and that you call
|
||||
Packet::AddTrailer and Packet::RemoveTrailer. Another important
|
||||
detail is that you must make sure to rewind the iterator in your
|
||||
Serialize and Deserialize methods writing to or reading from
|
||||
the underlying buffer.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
\page howtos ns-3 HOWTOs
|
||||
\anchor howtos-anchor
|
||||
|
||||
This is an organized set of frequently asked questions (FAQ) and HOWTOs
|
||||
for ns-3. This complements the following wiki pages:
|
||||
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/User_FAQ">User FAQ</a>
|
||||
- <a href="http://www.nsnam.org/wiki/index.php/Developer_FAQ">Developer FAQ</a>
|
||||
|
||||
Please consider contributing tips to either the wiki (yourself) or
|
||||
by submitting a patch to this maintained documentation.
|
||||
|
||||
- \subpage callbacks
|
||||
- \subpage packet-header-trailer
|
||||
- \subpage net-device
|
||||
- \subpage application
|
||||
|
||||
*/
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* \mainpage ns-3 Documentation
|
||||
*
|
||||
* \section intro-sec Introduction
|
||||
* <a href="http://www.nsnam.org/">ns-3</a> documentation is maintained using
|
||||
* <a href="http://www.doxygen.org">Doxygen</a>.
|
||||
* Doxygen is typically used for
|
||||
* API documentation, and organizes such documentation across different
|
||||
* modules. This project uses Doxygen both for building the manual around
|
||||
* the API documentation, and a separate GNU texinfo document is used for
|
||||
* the manual.
|
||||
*
|
||||
* The ns-3 project documentation is organized as follows:
|
||||
* - <b><a href="modules.html">modules</a></b>: The "Modules" tab (above)
|
||||
* organizes all of the public API and supporting manual text
|
||||
* along the source code directory structure. This forms the
|
||||
* "ns-3 manual", and it is available in HTML and PDF forms.
|
||||
* - \ref howtos-anchor "HOWTOs": A set of HOWTOs and FAQs is
|
||||
* maintained on another Doxygen "Related Page"
|
||||
* - <a href="http://www.nsnam.org/docs/tutorial/tutorial.html">tutorial</a>: The ns-3 tutorial is a separate document maintained in <a href="http://www.gnu.org/software/texinfo/"> GNU Texinfo</a>.
|
||||
* - The <b><a href="http://www.nsnam.org/wiki/index.php/Main_Page">ns-3 wiki</a></b>
|
||||
* contains additional user-contributed material. Some wiki-contributed
|
||||
* material may migrate to and overlap with the Doxygen information.
|
||||
*
|
||||
* \section install-sec Building the Documentation
|
||||
*
|
||||
* ns-3 requires Doxygen version 1.5.4 or greater to fully build all items,
|
||||
* although earlier versions of Doxygen will mostly work.
|
||||
*
|
||||
* Type "./waf check" followed by "./waf --doxygen" to build the documentation.
|
||||
* There is a program that runs during "./waf check" that builds pieces of
|
||||
* the documentation through introspection. The doc/ directory contains
|
||||
* configuration for Doxygen (doxygen.conf and main.txt). The Doxygen
|
||||
* build process puts html files into the doc/html/ directory, and latex
|
||||
* filex into the doc/latex/ directory.
|
||||
*
|
||||
* \section module-sec Module overview
|
||||
*
|
||||
* The ns-3 library is split across multiple modules:
|
||||
* - core: located in src/core and contains a number of facilities which
|
||||
* do not depend on any other module. Some of these facilities are
|
||||
* OS-dependent.
|
||||
* - simulator: located in src/simulator and contains event scheduling
|
||||
* facilities.
|
||||
* - common: located in src/common and contains facilities specific
|
||||
* to network simulations but shared by pretty much every model
|
||||
* of a network component.
|
||||
* - node: located in src/node. Defines the abstract interfaces which
|
||||
* must be implemented by every node and more specifically, by ipv4 nodes.
|
||||
* - devices: located in src/devices. Contains a set of MAC-level models
|
||||
*
|
||||
* More detail can be found in the <b><a href="modules.html">Modules</a></b>
|
||||
* tab.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* \namespace ns3
|
||||
* \brief Every class exported by the ns3 library is enclosed in the
|
||||
* ns3 namespace.
|
||||
*/
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* \mainpage An Introduction to ns-3
|
||||
*
|
||||
* The ns-3 library is split across multiple modules:
|
||||
* - core: located in src/core and contains a number of facilities which
|
||||
* do not depend on any other module. Some of these facilities are
|
||||
* OS-dependent.
|
||||
* - simulator: located in src/simulator and contains event scheduling
|
||||
* facilities.
|
||||
* - common: located in src/common and contains facilities specific
|
||||
* to network simulations but shared by pretty much every model
|
||||
* of a network component.
|
||||
* - node: located in src/node. Defines the abstract interfaces which
|
||||
* must be implemented by every node and more specifically, by ipv4 nodes.
|
||||
* - devices: located in src/devices. Contains a set of MAC-level models
|
||||
*
|
||||
* The "core" module contains:
|
||||
* - a Functor class: ns3::Callback
|
||||
* - an os-independent interface to get access to the elapsed wall clock time: ns3::SystemWallClockMs
|
||||
* - a class to register regression tests with the test manager: ns3::Test and ns3::TestManager
|
||||
* - debugging facilities: \ref debugging, \ref assert, \ref error
|
||||
* - \ref randomvariable
|
||||
* - \ref config
|
||||
* - a base class for objects which need to support reference counting
|
||||
* and QueryInterface: ns3::Object and ns3::InterfaceId
|
||||
* - a ns3::ComponentManager which can be used to manage the creation
|
||||
* of any object which derives from ns3::Object through an ns3::ClassId
|
||||
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
|
||||
*
|
||||
* The "simulator" module contains:
|
||||
* - a time management class to hold a time and convert between various time units: ns3::Time
|
||||
* - a scheduler base class used to implement new simulation event schedulers:
|
||||
* ns3::Scheduler and ns3::SchedulerFactory
|
||||
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
|
||||
*
|
||||
* The "common" module contains:
|
||||
* - a packet class to create and manipulate simulation packets: ns3::Packet, ns3::Header,
|
||||
* and ns3::Trailer. This packet class also supports per-packet ns3::Tag which are
|
||||
* globs of data which can be attached to any packet.
|
||||
* - a set of low-level trace facilities: \ref lowleveltracing
|
||||
*
|
||||
* The "node" module contains:
|
||||
* - a ns3::Node base class which should be subclassed by any new type of
|
||||
* network Node.
|
||||
* - models which abstract the MAC-layer from the IP layer protocols:
|
||||
* ns3::NetDevice and ns3::Channel.
|
||||
* - models which abstract the application-layer API: ns3::Application,
|
||||
* ns3::Socket, ns3::SocketFactory, and, ns3::Udp
|
||||
*
|
||||
* The "internet-node" module contains a set of classes which implement the
|
||||
* APIs defined in the "node" module:
|
||||
* - an Ipv4/Udp stack with socket support
|
||||
* - an ARP module
|
||||
* - an InternetNode class which is a Node subclass.
|
||||
*
|
||||
* The "devices" module contains:
|
||||
* - a PointToPoint MAC device: ns3::PointToPointNetDevice, ns3::PointToPointChannel,
|
||||
* and ns3::PointToPointTopology.
|
||||
*/
|
||||
/**
|
||||
* \namespace ns3
|
||||
* \brief Every class exported by the ns3 library is enclosed in the
|
||||
* ns3 namespace.
|
||||
*/
|
||||
/**
|
||||
* \defgroup constants Constants
|
||||
* \brief Constants you can change
|
||||
*/
|
||||
@@ -0,0 +1,49 @@
|
||||
TEXI2HTML = texi2html
|
||||
TEXI2PDF = texi2dvi --pdf
|
||||
EPSTOPDF = epstopdf
|
||||
TGIF = tgif
|
||||
DIA = dia
|
||||
CONVERT = convert
|
||||
CSS = --css-include=manual.css
|
||||
SPLIT = --split section
|
||||
|
||||
DIA_SOURCES = buffer.dia sockets-overview.dia
|
||||
TGIF_SOURCES = packet.obj
|
||||
|
||||
DIA_EPS = ${DIA_SOURCES:.dia=.eps}
|
||||
DIA_PNG = ${DIA_SOURCES:.dia=.png}
|
||||
DIA_PDF = ${DIA_SOURCES:.dia=.pdf}
|
||||
|
||||
TGIF_EPS = ${TGIF_SOURCES:.obj=.eps}
|
||||
TGIF_PNG = ${TGIF_SOURCES:.obj=.png}
|
||||
TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf}
|
||||
|
||||
all: images html split-html pdf
|
||||
|
||||
# Note: tgif requires a valid x display to convert from .obj to .png.
|
||||
# If running this makefile on a remote console, the X virtual frame
|
||||
# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake"
|
||||
# display
|
||||
images:
|
||||
cd figures/; $(DIA) -t png $(DIA_SOURCES)
|
||||
cd figures/; $(DIA) -t eps $(DIA_SOURCES)
|
||||
cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);)
|
||||
cd figures/; $(TGIF) -print -png $(TGIF_SOURCES)
|
||||
cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES)
|
||||
cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);)
|
||||
|
||||
html: images
|
||||
$(TEXI2HTML) ${CSS} manual.texi
|
||||
|
||||
split-html: images
|
||||
$(TEXI2HTML) ${CSS} ${SPLIT} manual.texi
|
||||
|
||||
pdf: images
|
||||
$(TEXI2PDF) manual.texi
|
||||
|
||||
figures-clean:
|
||||
cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF)
|
||||
cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF)
|
||||
|
||||
clean: figures-clean
|
||||
rm -rf manual.aux manual.cp manual.cps manual.fn manual.ky manual.pg manual.tp manual.vr manual.toc manual.log manual.pdf manual.html manual/
|
||||
@@ -0,0 +1,559 @@
|
||||
@node Attributes
|
||||
@chapter Attributes
|
||||
@anchor{chap:Attributes}
|
||||
|
||||
In ns-3 simulations, there are two main aspects to configuration:
|
||||
@itemize @bullet
|
||||
@item the simulation topology and how objects are connected
|
||||
@item the values used by the models instantiated in the topology
|
||||
@end itemize
|
||||
|
||||
This chapter focuses on the second item above: how the many values
|
||||
in use in ns-3 are organized, documented, and modifiable by ns-3 users.
|
||||
The ns-3 attribute system is also the underpinning of how traces
|
||||
and statistics are gathered in the simulator.
|
||||
|
||||
Before delving into details of the attribute value system,
|
||||
it will help to review some basic properties of @code{class ns3::Object}.
|
||||
|
||||
@node Object Overview
|
||||
@section Object Overview
|
||||
|
||||
ns-3 is fundamentally a C++ object-based system. By this we mean that
|
||||
new C++ classes (types) can be declared, defined, and subclassed
|
||||
as usual.
|
||||
|
||||
Many ns-3 objects inherit from the @code{ns3::Object} base class. These
|
||||
objects have some additional properties that we exploit for
|
||||
organizing the system and improving the memory management
|
||||
of our objects:
|
||||
|
||||
@itemize @bullet
|
||||
@item a "metadata" system that links the class name to a lot of
|
||||
meta-information about the object, including the base class of the subclass,
|
||||
the set of accessible constructors in the subclass, and the set of
|
||||
"attributes" of the subclass
|
||||
@item a reference counting smart pointer implementation, for memory
|
||||
management.
|
||||
@end itemize
|
||||
|
||||
ns-3 objects that use the attribute system derive from either
|
||||
@code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects
|
||||
we will discuss derive from @code{ns3::Object}, but a few that
|
||||
are outside the smart pointer memory management framework derive
|
||||
from @code{ns3::ObjectBase}.
|
||||
|
||||
Let's review a couple of properties of these objects.
|
||||
|
||||
@node Smart pointers
|
||||
@subsection Smart pointers
|
||||
|
||||
As introduced above in @ref{Smart Pointers 101}, ns-3 objects
|
||||
are memory managed by a
|
||||
@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}.
|
||||
|
||||
Smart pointers are used extensively in the ns-3 APIs, to avoid passing
|
||||
references to heap-allocated objects that may cause memory leaks.
|
||||
For most basic usage (syntax), treat a smart pointer like a regular pointer:
|
||||
@verbatim
|
||||
Ptr<WifiNetDevice> nd = ...;
|
||||
nd->CallSomeFunction ();
|
||||
// etc.
|
||||
@end verbatim
|
||||
|
||||
@node CreateObject
|
||||
@subsection CreateObject
|
||||
|
||||
As we discussed above in @ref{Object Creation},
|
||||
at the lowest-level API, objects of type @code{ns3::Object} are
|
||||
not instantiated using @code{operator new} as usual but instead by
|
||||
a templated function called @code{CreateObject()}.
|
||||
|
||||
A typical way to create such an object is as follows:
|
||||
@verbatim
|
||||
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
|
||||
@end verbatim
|
||||
|
||||
You can think of this as being functionally equivalent to:
|
||||
@verbatim
|
||||
WifiNetDevice* nd = new WifiNetDevice ();
|
||||
@end verbatim
|
||||
|
||||
Objects that derive from @code{ns3::Object} must be allocated
|
||||
on the heap using CreateObject(). Those deriving from
|
||||
@code{ns3::ObjectBase}, such as ns-3 helper functions and packet
|
||||
headers and trailers, can be allocated on the stack.
|
||||
|
||||
In some scripts, you may not see a lot of CreateObject() calls
|
||||
in the code;
|
||||
this is because there are some helper objects in effect that
|
||||
are doing the CreateObject()s for you.
|
||||
|
||||
@node TypeId
|
||||
@subsection TypeId
|
||||
|
||||
ns-3 classes that derive from class ns3::Object can include
|
||||
a metadata class called @code{TypeId} that records meta-information
|
||||
about the class, for use in the object aggregation and component
|
||||
manager systems:
|
||||
@itemize @bullet
|
||||
@item a unique string identifying the class
|
||||
@item the base class of the subclass, within the metadata system
|
||||
@item the set of accessible constructors in the subclass
|
||||
@end itemize
|
||||
|
||||
@node Object Summary
|
||||
@subsection Object Summary
|
||||
|
||||
Putting all of these concepts together, let's look at a specific
|
||||
example: @code{class ns3::Node}.
|
||||
|
||||
The public header file node.h has a declaration that includes
|
||||
a static GetTypeId function call:
|
||||
@verbatim
|
||||
class Node : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
This is defined in the node.cc file as follows:
|
||||
@verbatim
|
||||
TypeId
|
||||
Node::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::Node")
|
||||
.SetParent<Object> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
Finally, when users want to create Nodes, they call:
|
||||
@verbatim
|
||||
Ptr<Node> n = CreateObject<Node> ();
|
||||
@end verbatim
|
||||
|
||||
We next discuss how attributes (values associated with member variables
|
||||
or functions of the class) are plumbed into the above TypeId.
|
||||
|
||||
@node Attribute Overview
|
||||
@section Attribute Overview
|
||||
|
||||
The goal of the attribute system is to organize the access of
|
||||
internal member objects of a simulation. This goal arises because,
|
||||
typically in simulation, users will cut and paste/modify existing
|
||||
simulation scripts, or will use higher-level simulation constructs,
|
||||
but often will be interested in studying or tracing particular
|
||||
internal variables. For instance, use cases such as:
|
||||
@itemize @bullet
|
||||
@item "I want to trace the packets on the wireless interface only on
|
||||
the first access point"
|
||||
@item "I want to trace the value of the TCP congestion window (every
|
||||
time it changes) on a particular TCP socket"
|
||||
@item "I want a dump of all values that were used in my simulation."
|
||||
@end itemize
|
||||
|
||||
Similarly, users may want fine-grained access to internal
|
||||
variables in the simulation, or may want to broadly change the
|
||||
initial value used for a particular parameter in all subsequently
|
||||
created objects. Finally, users may wish to know what variables
|
||||
are settable and retrievable in a simulation configuration. This
|
||||
is not just for direct simulation interaction on the command line;
|
||||
consider also a (future) graphical user interface
|
||||
that would like to be able to provide a feature whereby a user
|
||||
might right-click on an node on the canvas and see a hierarchical,
|
||||
organized list of parameters that are settable on the node and its
|
||||
constituent member objects, and help text and default values for
|
||||
each parameter.
|
||||
|
||||
@node Functional overview
|
||||
@subsection Functional overview
|
||||
|
||||
We provide a way for users to access values deep in the system, without
|
||||
having to plumb accessors (pointers) through the system and walk
|
||||
pointer chains to get to them. Consider a class DropTailQueue that
|
||||
has a member variable that is an unsigned integer @code{m_maxPackets};
|
||||
this member variable controls the depth of the queue.
|
||||
|
||||
If we look at the declaration of DropTailQueue, we see the following:
|
||||
@verbatim
|
||||
class DropTailQueue : public Queue {
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
...
|
||||
|
||||
private:
|
||||
std::queue<Ptr<Packet> > m_packets;
|
||||
uint32_t m_maxPackets;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
Let's consider things that a user may want to do with the value of
|
||||
m_maxPackets:
|
||||
|
||||
@itemize @bullet
|
||||
@item Set a default value for the system, such that whenever a new
|
||||
DropTailQueue is created, this member is initialized to that default.
|
||||
@item Set or get the value on an already instantiated queue.
|
||||
@end itemize
|
||||
|
||||
The above things typically require providing Set() and Get() functions,
|
||||
and some type of global default value.
|
||||
|
||||
In the ns-3 attribute system, these value definitions and accessor
|
||||
functions are moved into the TypeId class; e.g.:
|
||||
@verbatim
|
||||
TypeId DropTailQueue::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::DropTailQueue")
|
||||
.SetParent<Queue> ()
|
||||
.AddConstructor<DropTailQueue> ()
|
||||
.AddAttribute ("MaxPackets",
|
||||
"The maximum number of packets accepted by this DropTailQueue.",
|
||||
UintegerValue (100),
|
||||
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
;
|
||||
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The AddAttribute() method is performing a number of things with this
|
||||
value:
|
||||
@itemize @bullet
|
||||
@item Binding the variable m_maxPackets to a string "MaxPackets"
|
||||
@item Providing a default value (100 packets)
|
||||
@item Providing some help text defining the value
|
||||
@item Providing a "checker" (not used in this example) that can be used to set
|
||||
bounds on the allowable range of values
|
||||
@end itemize
|
||||
|
||||
The key point is that now the value of this variable and its default
|
||||
value are accessible in the attribute namespace, which is based on
|
||||
strings such as "MaxPackets" and TypeId strings. In the next
|
||||
section, we will provide an example script that shows how users
|
||||
may manipulate these values.
|
||||
|
||||
@node Basic usage
|
||||
@subsection Basic usage
|
||||
|
||||
Let's look at how a user script might access these values.
|
||||
This is based on the script found at @code{samples/main-attribute-value.cc},
|
||||
with some details stripped out.
|
||||
@verbatim
|
||||
//
|
||||
// This is a basic example of how to use the attribute system to
|
||||
// set and get a value in the underlying system; namely, an unsigned
|
||||
// integer of the maximum number of packets in a queue
|
||||
//
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// By default, the MaxPackets attribute has a value of 100 packets
|
||||
// (this default can be observed in the function DropTailQueue::GetTypeId)
|
||||
//
|
||||
// Here, we set it to 80 packets. We could use one of two value types:
|
||||
// a string-based value or a Uinteger value
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
|
||||
// The below function call is redundant
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// SetDefaults() at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
@end verbatim
|
||||
|
||||
The main thing to notice in the above are the two calls to
|
||||
@code{Config::SetDefault}. This is how we set the default value
|
||||
for all subsequently instantiated DropTailQueues. We illustrate
|
||||
that two types of Value classes, a StringValue and a UintegerValue class,
|
||||
can be used to assign the value to the attribute named by
|
||||
"ns3::DropTailQueue::MaxPackets".
|
||||
|
||||
Now, we will create a few objects using the low-level API; here,
|
||||
our newly created queues will not have a m_maxPackets initialized to
|
||||
100 packets but to 80 packets, because of what we did above with
|
||||
default values.
|
||||
@verbatim
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
|
||||
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
|
||||
n0->AddDevice (net0);
|
||||
|
||||
Ptr<Queue> q = CreateObject<DropTailQueue> ();
|
||||
net0->AddQueue(q);
|
||||
@end verbatim
|
||||
|
||||
At this point, we have created a single node (Node 0) and a
|
||||
single PointToPointNetDevice (NetDevice 0) and added a
|
||||
DropTailQueue to it.
|
||||
|
||||
Now, we can manipulate the MaxPackets value of the already
|
||||
instantiated DropTailQueue. Here are various ways to do that.
|
||||
|
||||
@subsubsection Pointer-based access
|
||||
|
||||
We assume that a smart pointer (Ptr) to a relevant network device is
|
||||
in hand; here, it is the net0 pointer.
|
||||
|
||||
One way to change the value is to access a pointer to the
|
||||
underlying queue and modify its attribute.
|
||||
|
||||
First, we observe that we can get a pointer to the (base class)
|
||||
queue via the PointToPointNetDevice attributes, where it is called
|
||||
TxQueue
|
||||
@verbatim
|
||||
PointerValue tmp;
|
||||
net0->GetAttribute ("TxQueue", tmp);
|
||||
Ptr<Object> txQueue = tmp.GetObject ();
|
||||
@end verbatim
|
||||
|
||||
Using the GetObject function, we can perform a safe downcast
|
||||
to a DropTailQueue, where MaxPackets is a member
|
||||
@verbatim
|
||||
Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
|
||||
NS_ASSERT (dtq != 0);
|
||||
@end verbatim
|
||||
|
||||
Next, we can get the value of an attribute on this queue.
|
||||
We have introduced wrapper "Value" classes for the underlying
|
||||
data types, similar to Java wrappers around these types, since
|
||||
the attribute system stores values and not disparate types.
|
||||
Here, the attribute value is assigned to a UintegerValue, and
|
||||
the Get() method on this value produces the (unwrapped) uint32_t.
|
||||
@verbatim
|
||||
UintegerValue limit;
|
||||
dtq->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
Note that the above downcast is not really needed; we could have
|
||||
done the same using the Ptr<Queue> even though the attribute
|
||||
is a member of the subclass
|
||||
@verbatim
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
Now, let's set it to another value (60 packets)
|
||||
@verbatim
|
||||
txQueue->SetAttribute("MaxPackets", UintegerValue (60));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
@subsubsection Namespace-based access
|
||||
|
||||
An alternative way to get at the attribute is to use the configuration
|
||||
namespace. Here, this attribute resides on a known path in this
|
||||
namespace; this approach is useful if one doesn't have access to
|
||||
the underlying pointers and would like to configure a specific
|
||||
attribute with a single statement.
|
||||
@verbatim
|
||||
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
We could have also used wildcards to set this value for all nodes
|
||||
and all net devices (which in this simple example has the same
|
||||
effect as the previous Set())
|
||||
@verbatim
|
||||
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
@node Setting through constructors and helper classes
|
||||
@subsection Setting through constructors helper classes
|
||||
|
||||
Arbitrary combinations of attributes can be set and fetched from
|
||||
the helper and low-level APIs; either from the constructors themselves:
|
||||
@verbatim
|
||||
Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
|
||||
@end verbatim
|
||||
or from the higher-level helper APIs, such as:
|
||||
@verbatim
|
||||
mobility.SetPositionAllocator ("GridPositionAllocator",
|
||||
"MinX", DoubleValue (-100.0),
|
||||
"MinY", DoubleValue (-100.0),
|
||||
"DeltaX", DoubleValue (5.0),
|
||||
"DeltaY", DoubleValue (20.0),
|
||||
"GridWidth", UintegerValue (20),
|
||||
"LayoutType", StringValue ("RowFirst"));
|
||||
@end verbatim
|
||||
|
||||
@node Value classes
|
||||
@subsection Value classes
|
||||
Readers will note the new FooValue classes which are subclasses of the
|
||||
AttributeValue base class. These can be thought of as
|
||||
an intermediate class that can be used to convert from raw types to the
|
||||
Values that are used by the attribute system. Recall that this database is holding
|
||||
objects of many types with a single generic type. Conversions to this
|
||||
type can either be done using an intermediate class (IntegerValue, DoubleValue for
|
||||
"floating point") or via strings. Direct implicit conversion of types
|
||||
to Value is not really practical. So in the above, users have a choice
|
||||
of using strings or values:
|
||||
@verbatim
|
||||
p->Set ("cwnd", StringValue ("100")); // string-based setter
|
||||
p->Set ("cwnd", IntegerValue (100)); // integer-based setter
|
||||
@end verbatim
|
||||
|
||||
The system provides some macros that help users declare and define
|
||||
new AttributeValue subclasses for new types that they want to introduce into
|
||||
the attribute system:
|
||||
@itemize @bullet
|
||||
@item ATTRIBUTE_HELPER_HEADER
|
||||
@item ATTRIBUTE_HELPER_CPP
|
||||
@end itemize
|
||||
|
||||
@node Extending attributes
|
||||
@section Extending attributes
|
||||
|
||||
The ns-3 system will place a number of internal values under the
|
||||
attribute system, but undoubtedly users will want to extend this
|
||||
to pick up ones we have missed, or to add their own classes to this.
|
||||
|
||||
@subsection Adding an existing internal variable to the metadata system
|
||||
|
||||
Consider this variable in class TcpSocket:
|
||||
@verbatim
|
||||
uint32_t m_cWnd; // Congestion window
|
||||
@end verbatim
|
||||
|
||||
Suppose that someone working with Tcp wanted to get or set the
|
||||
value of that variable using the metadata system. If it were not
|
||||
already provided by ns-3, the user could declare the following addition
|
||||
in the metadata system (to the TypeId declaration for TcpSocket):
|
||||
@verbatim
|
||||
.AddParameter ("Congestion window",
|
||||
"Tcp congestion window (bytes)",
|
||||
Uinteger (1),
|
||||
MakeUintegerAccessor (&TcpSocket::m_cWnd),
|
||||
MakeUintegerChecker<uint16_t> ());
|
||||
|
||||
@end verbatim
|
||||
|
||||
Now, the user with a pointer to the TcpSocket can perform operations
|
||||
such as setting and getting the value, without having to add these
|
||||
functions explicitly. Furthermore, access controls can be applied, such
|
||||
as allowing the parameter to be read and not written, or bounds
|
||||
checking on the permissible values can be applied.
|
||||
|
||||
@subsection Adding a new TypeId
|
||||
|
||||
Here, we discuss the impact on a user who wants to add a new class to
|
||||
ns-3; what additional things must be done to hook it into this system.
|
||||
|
||||
We've already introduced what a TypeId definition looks like:
|
||||
@verbatim
|
||||
TypeId
|
||||
RandomWalk2dMobilityModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::RandomWalk2dMobilityModel")
|
||||
.SetParent<MobilityModel> ()
|
||||
.SetGroupName ("Mobility")
|
||||
.AddConstructor<RandomWalk2dMobilityModel> ()
|
||||
.AddAttribute ("Bounds",
|
||||
"Bounds of the area to cruise.",
|
||||
RectangleValue (Rectangle (0.0, 0.0, 100.0, 100.0)),
|
||||
MakeRectangleAccessor (&RandomWalk2dMobilityModel::m_bounds),
|
||||
MakeRectangleChecker ())
|
||||
.AddAttribute ("Time",
|
||||
"Change current direction and speed after moving for this delay.",
|
||||
TimeValue (Seconds (1.0)),
|
||||
MakeTimeAccessor (&RandomWalk2dMobilityModel::m_modeTime),
|
||||
MakeTimeChecker ())
|
||||
// etc (more parameters).
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The declaration for this in the class declaration is one-line public
|
||||
member method:
|
||||
@verbatim
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
@end verbatim
|
||||
|
||||
Typical mistakes here involve:
|
||||
@itemize @bullet
|
||||
@item Not calling the SetParent method or calling it with the wrong type
|
||||
@item Not calling the AddConstructor method of calling it with the wrong type
|
||||
@item Introducing a typographical error in the name of the TypeId in its constructor
|
||||
@item Not using the fully-qualified c++ typename of the enclosing c++ class as the
|
||||
name of the TypeId
|
||||
@end itemize
|
||||
None of these mistakes can be detected by the ns-3 codebase so, users
|
||||
are advised to check carefully multiple times that they got these right.
|
||||
|
||||
|
||||
@section Adding new class type to the attribute system
|
||||
|
||||
From the perspective of the user who writes a new class in the system and
|
||||
wants to hook it in to the attribute system, there is mainly the matter
|
||||
of writing
|
||||
the conversions to/from strings and attribute values. Most of this can be
|
||||
copy/pasted with macro-ized code. For instance, consider class
|
||||
Rectangle in the @code{src/mobility/} directory:
|
||||
|
||||
One line is added to the class declaration:
|
||||
@verbatim
|
||||
/**
|
||||
* \brief a 2d rectangle
|
||||
*/
|
||||
class Rectangle
|
||||
{
|
||||
...
|
||||
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
One macro call and two operators, are added below the class declaration:
|
||||
|
||||
@verbatim
|
||||
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
|
||||
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
|
||||
|
||||
ATTRIBUTE_HELPER_HEADER (Rectangle);
|
||||
@end verbatim
|
||||
|
||||
In the class definition, the code looks like this:
|
||||
|
||||
@verbatim
|
||||
ATTRIBUTE_HELPER_CPP (Rectangle);
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const Rectangle &rectangle)
|
||||
{
|
||||
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
|
||||
return os;
|
||||
}
|
||||
std::istream &
|
||||
operator >> (std::istream &is, Rectangle &rectangle)
|
||||
{
|
||||
char c1, c2, c3;
|
||||
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
|
||||
if (c1 != '|' ||
|
||||
c2 != '|' ||
|
||||
c3 != '|')
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
These stream operators simply convert from a string representation of the
|
||||
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
|
||||
modeler must specify these operators and the string syntactical representation
|
||||
of an instance of the new class.
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
@node Callbacks
|
||||
@chapter Callbacks
|
||||
|
||||
Some new users to @command{ns-3} are unfamiliar with an extensively used
|
||||
programming idiom used throughout the code: the ``ns-3 callback''. This
|
||||
chapter provides some motivation on the callback, guidance on how to use
|
||||
it, and details on its implementation.
|
||||
|
||||
@menu
|
||||
* Motivation::
|
||||
* Using the Callback API::
|
||||
* Callback locations in ns-3::
|
||||
* Implementation details::
|
||||
@end menu
|
||||
|
||||
@node Motivation
|
||||
@section Motivation
|
||||
|
||||
Consider that you have two simulation models A and B, and you wish
|
||||
to have them pass information between them during the simulation. One
|
||||
way that you can do that is that you can make A and B each explicitly
|
||||
knowledgable about the other, so that they can invoke methods on each
|
||||
other.
|
||||
|
||||
@verbatim
|
||||
class A {
|
||||
public:
|
||||
void ReceiveInput ( // parameters );
|
||||
...
|
||||
}
|
||||
|
||||
(in another source file:)
|
||||
|
||||
class B {
|
||||
public:
|
||||
void ReceiveInput ( // parameters);
|
||||
void DoSomething (void);
|
||||
...
|
||||
|
||||
private:
|
||||
A* a_instance; // pointer to an A
|
||||
}
|
||||
|
||||
void
|
||||
B::DoSomething()
|
||||
{
|
||||
// Tell a_instance that something happened
|
||||
a_instance->ReceiveInput ( // parameters);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This certainly works, but it has the drawback that it introduces a
|
||||
dependency on A and B to know about the other at compile time (this
|
||||
makes it harder to have independent compilation units in the simulator)
|
||||
and is not generalized; if in a later usage scenario, B needs to talk
|
||||
to a completely different C object, the source code for B needs to be
|
||||
changed to add a ``c_instance'' and so forth. It is easy to see that
|
||||
this is a brute force mechanism of communication that can lead to
|
||||
programming cruft in the models.
|
||||
|
||||
This is not to say that objects should not know about one another
|
||||
if there is a hard dependency between them, but that often the model
|
||||
can be made more flexible if its interactions are less constrained at
|
||||
compile time.
|
||||
|
||||
This is not an abstract problem for network simulation research,
|
||||
but rather it has been a source of problems in previous simulators,
|
||||
when researchers want to extend or modify the system to do different
|
||||
things (as they are apt to do in research). Consider, for example,
|
||||
a user who wants to add an IPsec security protocol sublayer
|
||||
between TCP and IP:
|
||||
@verbatim
|
||||
------------ -----------
|
||||
| TCP | | TCP |
|
||||
------------ -----------
|
||||
| becomes -> |
|
||||
----------- -----------
|
||||
| IP | | IPsec |
|
||||
----------- -----------
|
||||
|
|
||||
-----------
|
||||
| IP |
|
||||
-----------
|
||||
@end verbatim
|
||||
If the simulator has
|
||||
made assumptions, and hard coded into the code, that IP always talks
|
||||
to a transport protocol above, the user may be forced to hack the
|
||||
system to get the desired interconnections.
|
||||
|
||||
An alternative that provides this flexibility is to use a level of
|
||||
indirection that is commonly known in programming as a callback.
|
||||
A callback function is not invoked explicitly by the caller but is
|
||||
rather delegated to another function that receives the callback
|
||||
function's address and can call it.
|
||||
|
||||
You may be familiar with function pointers in C or C++; these can
|
||||
be used to implement callbacks. For more information on introductory
|
||||
callbacks, an online reference is:
|
||||
@uref{http://www.inquiry.com/techtips/cpp_pro/10min/10min0300.asp,,Declaring Function Pointers and Implementing Callbacks} and
|
||||
@uref{http://en.wikipedia.org/wiki/Callback_(computer_science),,Callback (computer science)-- Wikipedia}.
|
||||
|
||||
The callback API in @command{ns-3} is designed to minimize the overall
|
||||
coupling between various pieces of of the simulator
|
||||
by making each module depend on the callback API
|
||||
itself rather than depend on other modules. It acts as a sort of
|
||||
third-party to which work is delegated and which forwards this
|
||||
work to the proper target module. This callback API, being based
|
||||
on C++ templates,
|
||||
is type-safe; that is, it performs static type checks to enforce
|
||||
proper signature compatibility between callers and callees. It
|
||||
is therefore more type-safe to use than traditional function
|
||||
pointers, but the syntax may look imposing at first. This section
|
||||
is designed to walk you through the callback system so that you
|
||||
can be comfortable using it in @command{ns-3}.
|
||||
|
||||
@node Using the Callback API
|
||||
@section Using the Callback API
|
||||
|
||||
The Callback API is fairly minimal, providing only two services:
|
||||
@itemize @bullet
|
||||
@item callback type declaration: a way to declare a type of callback
|
||||
with a given signature, and,
|
||||
@item callback instantiation: a way to instantiate a
|
||||
template-generated forwarding callback which can forward any calls
|
||||
to another C++ class member method or C++ function.
|
||||
@end itemize
|
||||
|
||||
This is best observed via walking through an example, based on
|
||||
@code{samples/main-callback.cc}.
|
||||
|
||||
@node Using the Callback API with static functions
|
||||
@subsection Using the Callback API with static functions
|
||||
|
||||
Consider a function:
|
||||
@verbatim
|
||||
static double
|
||||
CbOne (double a, double b)
|
||||
{
|
||||
std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
|
||||
return a;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Consider also the following main program snippett:
|
||||
@verbatim
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// return type: double
|
||||
// first arg type: double
|
||||
// second arg type: double
|
||||
Callback<double, double, double> one;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This class template Callback implements what is known as the Functor
|
||||
Design Pattern. It is used to declare the type of a callback. It contains
|
||||
one mandatory argument (the return type of the function to be assigned
|
||||
to this callback) and up to five optional arguments, which each specify
|
||||
the type of the arguments (if your function has more than five arguments,
|
||||
then this can be handled by extending the callback implementation).
|
||||
|
||||
So in the above, we have a declared a callback named "one" that will
|
||||
eventually hold a function pointer. The function that it will hold
|
||||
must return double and must support two double arguments. If one
|
||||
tries to pass a function whose signature does not match the declared
|
||||
callback, the compilation will fail.
|
||||
|
||||
Now, we need to tie together this callback instance and the actual
|
||||
target function (CbOne). Notice above that CbOne has the same function
|
||||
signature types as the callback-- this is important. We can
|
||||
pass in any such properly-typed function to this callback. Let's
|
||||
look at this more closely:
|
||||
@verbatim
|
||||
static double CbOne (double a, double b) {}
|
||||
^ ^ ^
|
||||
| ---| ------|
|
||||
| | |
|
||||
Callback<double, double, double> one;
|
||||
@end verbatim
|
||||
You can only bind a function to a callback if they have the matching
|
||||
signature. The first template argument is the return type, and the
|
||||
additional template arguments are the types of the arguments of
|
||||
the function signature.
|
||||
|
||||
Now, let's bind our callback "one" to the function that matches its
|
||||
signature:
|
||||
@verbatim
|
||||
// build callback instance which points to cbOne function
|
||||
one = MakeCallback (&CbOne);
|
||||
@end verbatim
|
||||
|
||||
Then, later in the program, if the callback is to be used, it can be
|
||||
used as follows:
|
||||
@verbatim
|
||||
// this is not a null callback
|
||||
NS_ASSERT (!one.IsNull ());
|
||||
// invoke cbOne function through callback instance
|
||||
double retOne;
|
||||
retOne = one (10.0, 20.0);
|
||||
@end verbatim
|
||||
|
||||
The check @code{IsNull()} ensures that the callback is not null; that there
|
||||
is a function to call behind this callback. Then, @code{one()} returns the
|
||||
same result as if @code{CbOne()} had been called directly.
|
||||
|
||||
|
||||
@node Using the Callback API with member functions
|
||||
@subsection Using the Callback API with member functions
|
||||
|
||||
Generally, you will not be calling static functions but instead
|
||||
public member functions of an object. In this case, an extra
|
||||
argument is needed to the MakeCallback function, to tell the system
|
||||
on which object the function should be invoked. Consider this example,
|
||||
also from main-callback.cc:
|
||||
|
||||
@verbatim
|
||||
class MyCb {
|
||||
public:
|
||||
int CbTwo (double a) {
|
||||
std::cout << "invoke cbTwo a=" << a << std::endl;
|
||||
return -5;
|
||||
}
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
// return type: int
|
||||
// first arg type: double
|
||||
Callback<int, double> two;
|
||||
MyCb cb;
|
||||
// build callback instance which points to MyCb::cbTwo
|
||||
two = MakeCallback (&MyCb::CbTwo, &cb);
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
Here, we pass a (raw) pointer to the @code{MakeCallback<>} function,
|
||||
that says, when @code{two ()} is invoked, to call the @code{CbTwo} function
|
||||
on the object pointed to by @code{&cb}.
|
||||
|
||||
A variation of this is used when objects are referred to by ns-3 smart
|
||||
pointers. The MakeCallback API takes a raw pointer, so we need to
|
||||
call @code{PeekPointer ()} to obtain this raw pointer. So the example
|
||||
above would look like:
|
||||
|
||||
@verbatim
|
||||
class MyCb : public Object {
|
||||
public:
|
||||
int CbTwo (double a) {
|
||||
std::cout << "invoke cbTwo a=" << a << std::endl;
|
||||
return -5;
|
||||
}
|
||||
};
|
||||
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
// return type: int
|
||||
// first arg type: double
|
||||
Callback<int, double> two;
|
||||
Ptr<MyCb> cb = CreateObject<MyCb> ();
|
||||
// build callback instance which points to MyCb::cbTwo
|
||||
two = MakeCallback (&MyCb::CbTwo, PeekPointer (cb));
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@node Building Null Callbacks
|
||||
@subsection Building Null Callbacks
|
||||
|
||||
It is possible for callbacks to be null; hence it may be wise to
|
||||
check before using them. There is a special construct for a null
|
||||
callback, which is preferable to simply passing "0" as an argument;
|
||||
it is the @code{MakeNullCallback<>} construct:
|
||||
@verbatim
|
||||
two = MakeNullCallback<int, double> ();
|
||||
// invoking a null callback is just like
|
||||
// invoking a null function pointer:
|
||||
// it will crash at runtime.
|
||||
//int retTwoNull = two (20.0);
|
||||
NS_ASSERT (two.IsNull ());
|
||||
@end verbatim
|
||||
|
||||
@node Callback locations in ns-3
|
||||
@section Callback locations in @command{ns-3}
|
||||
|
||||
Where are callbacks frequently used in @command{ns-3}? Here are some of the
|
||||
more visible ones to typical users:
|
||||
|
||||
@subsection Socket API
|
||||
@subsection Layer-2/Layer-3 API
|
||||
@subsection Tracing subsystem
|
||||
@subsection Routing
|
||||
Route Reply
|
||||
|
||||
@node Implementation details
|
||||
@section Implementation details
|
||||
|
||||
This section is advanced explanation for C++ experts interested in
|
||||
the implementation, and may be skipped by most users.
|
||||
|
||||
This code was originally written based on the techniques described
|
||||
@uref{http://www.codeproject.com/cpp/TTLFunction.asp,,here}.
|
||||
It was subsequently rewritten to follow the architecture
|
||||
outlined in
|
||||
@uref{http://www.amazon.com/Modern-C\%2B\%2B-Design-Programming-Patterns/dp/0201704315/ref=pd_bbs_sr_1/102-0157303-1900156?ie=UTF8\&s=books\&qid=1187982662\&sr=1-1,,Modern C++ Design: Generic Programming and Design Patterns Applied-- Alexandrescu}, chapter 5, "Generalized Functors".
|
||||
|
||||
This code uses:
|
||||
@itemize @bullet
|
||||
@item default template parameters to saves users from having to
|
||||
specify empty parameters when the number of parameters
|
||||
is smaller than the maximum supported number
|
||||
@item the pimpl idiom: the Callback class is passed around by
|
||||
value and delegates the crux of the work to its pimpl pointer.
|
||||
@item two pimpl implementations which derive from CallbackImpl
|
||||
FunctorCallbackImpl can be used with any functor-type
|
||||
while MemPtrCallbackImpl can be used with pointers to
|
||||
member functions.
|
||||
@item a reference list implementation to implement the Callback's
|
||||
value semantics.
|
||||
@end itemize
|
||||
|
||||
This code most notably departs from the Alexandrescu
|
||||
implementation in that it does not use type lists to specify
|
||||
and pass around the types of the callback arguments.
|
||||
Of course, it also does not use copy-destruction semantics
|
||||
and relies on a reference list rather than autoPtr to hold
|
||||
the pointer.
|
||||
@@ -0,0 +1,18 @@
|
||||
Please write image files in a vector graphics format, when possible, and
|
||||
generate the .png and .pdf versions on the fly (see ../Makefile).
|
||||
|
||||
Currently supported tools are dia and tgif. xfig could be added similarly
|
||||
if someone wants to add it. The main requirement for adding another format
|
||||
is that the tool to edit it is freely available and that a cron script can
|
||||
autogenerate the pdf and png from the figure source.
|
||||
|
||||
Store the .dia, or .obj versions in mercurial, but not the .png or .pdfs.
|
||||
If the figure is not available in a vector graphics format, store both
|
||||
a .png and a .pdf version in this directory.
|
||||
|
||||
If you add a source (.dia, .obj) file here, remember to add it to
|
||||
the list of figure sources in the Makefile in the directory above
|
||||
|
||||
Note: tgif can convert from .obj to .pdf, but the pdf that results takes
|
||||
up a whole page. Instead, we convert to an intermediate .eps step, and
|
||||
then run epstopdf.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,227 @@
|
||||
%TGIF 4.1.43-QPL
|
||||
state(0,37,100.000,0,64,0,32,0,9,1,1,1,0,0,0,1,0,'Courier-Bold',1,103680,0,3,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0).
|
||||
%
|
||||
% @(#)$Header$
|
||||
% %W%
|
||||
%
|
||||
unit("1 pixel/pixel").
|
||||
color_info(11,65535,0,[
|
||||
"magenta", 65535, 0, 65535, 65535, 0, 65535, 1,
|
||||
"red", 65535, 0, 0, 65535, 0, 0, 1,
|
||||
"green", 0, 65535, 0, 0, 65535, 0, 1,
|
||||
"blue", 0, 0, 65535, 0, 0, 65535, 1,
|
||||
"yellow", 65535, 65535, 0, 65535, 65535, 0, 1,
|
||||
"pink", 65535, 49344, 52171, 65535, 49344, 52171, 1,
|
||||
"cyan", 0, 65535, 65535, 0, 65535, 65535, 1,
|
||||
"CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1,
|
||||
"white", 65535, 65535, 65535, 65535, 65535, 65535, 1,
|
||||
"black", 0, 0, 0, 0, 0, 0, 1,
|
||||
"DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1
|
||||
]).
|
||||
script_frac("0.6").
|
||||
fg_bg_colors('black','white').
|
||||
dont_reencode("FFDingbests:ZapfDingbats").
|
||||
page(1,"",1,'').
|
||||
box('black','',32,48,240,256,0,3,1,0,0,0,0,0,0,'3',0,[
|
||||
]).
|
||||
text('black',64,10,1,0,1,121,28,3,22,6,0,0,0,0,2,121,28,0,0,"",0,0,0,0,32,'',[
|
||||
minilines(121,28,0,0,0,0,0,[
|
||||
mini_line(121,22,6,0,0,0,[
|
||||
str_block(0,121,22,6,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,138240,121,22,6,0,0,0,0,0,0,0,
|
||||
"class Packet")])
|
||||
])
|
||||
])]).
|
||||
text('black',416,100,1,0,1,116,28,15,22,6,0,0,0,0,2,116,28,0,0,"",0,0,0,0,122,'',[
|
||||
minilines(116,28,0,0,0,0,0,[
|
||||
mini_line(116,22,6,0,0,0,[
|
||||
str_block(0,116,22,6,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,138240,116,22,6,0,0,0,0,0,0,0,
|
||||
"class Buffer")])
|
||||
])
|
||||
])]).
|
||||
text('black',48,178,4,0,1,83,69,32,14,4,0,0,0,0,2,83,69,0,0,"",0,0,0,0,192,'',[
|
||||
minilines(83,69,0,0,0,0,0,[
|
||||
mini_line(80,14,4,0,0,0,[
|
||||
str_block(0,80,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
|
||||
"private data:")])
|
||||
]),
|
||||
mini_line(59,14,3,0,0,0,[
|
||||
str_block(0,59,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,59,14,3,0,0,0,0,0,0,0,
|
||||
"- unique id")])
|
||||
]),
|
||||
mini_line(83,14,3,0,0,0,[
|
||||
str_block(0,83,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,83,14,3,0,0,0,0,0,0,0,
|
||||
"- Buffer object")])
|
||||
]),
|
||||
mini_line(76,14,3,0,0,0,[
|
||||
str_block(0,76,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,76,14,3,0,0,0,0,0,0,0,
|
||||
"- Tags object")])
|
||||
])
|
||||
])]).
|
||||
text('black',112,288,1,0,1,103,28,82,22,6,0,0,0,0,2,103,28,0,0,"",0,0,0,0,310,'',[
|
||||
minilines(103,28,0,0,0,0,0,[
|
||||
mini_line(103,22,6,0,0,0,[
|
||||
str_block(0,103,22,6,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,138240,103,22,6,0,-1,0,0,0,0,0,
|
||||
"class Tags")])
|
||||
])
|
||||
])]).
|
||||
text('black',48,50,5,0,1,175,86,176,14,4,0,0,0,0,2,175,86,0,0,"",0,0,0,0,64,'',[
|
||||
minilines(175,86,0,0,0,0,0,[
|
||||
mini_line(105,14,4,0,0,0,[
|
||||
str_block(0,105,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
|
||||
"public functions:")])
|
||||
]),
|
||||
mini_line(80,14,3,0,0,0,[
|
||||
str_block(0,80,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0,
|
||||
"- constructors")])
|
||||
]),
|
||||
mini_line(175,14,3,0,0,0,[
|
||||
str_block(0,175,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,175,14,3,0,-1,0,0,0,0,0,
|
||||
"- add/remove/peek at Headers")])
|
||||
]),
|
||||
mini_line(155,14,3,0,0,0,[
|
||||
str_block(0,155,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0,
|
||||
"- add/remove/peek at Tags")])
|
||||
]),
|
||||
mini_line(88,14,3,0,0,0,[
|
||||
str_block(0,88,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,88,14,3,0,0,0,0,0,0,0,
|
||||
"- fragmentation")])
|
||||
])
|
||||
])]).
|
||||
box('black','',384,144,614,352,0,3,1,245,0,0,0,0,0,'3',0,[
|
||||
]).
|
||||
text('black',400,274,4,0,1,204,69,246,14,4,0,0,0,0,2,204,69,0,0,"",0,0,0,0,288,'',[
|
||||
minilines(204,69,0,0,0,0,0,[
|
||||
mini_line(80,14,4,0,0,0,[
|
||||
str_block(0,80,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
|
||||
"private data:")])
|
||||
]),
|
||||
mini_line(193,14,3,0,0,0,[
|
||||
str_block(0,193,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,193,14,3,0,0,0,0,0,0,0,
|
||||
"- struct BufferData, a dynamically")])
|
||||
]),
|
||||
mini_line(160,14,3,0,0,0,[
|
||||
str_block(0,160,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,160,14,3,0,0,0,0,0,0,0,
|
||||
"varying byte buffer to which")])
|
||||
]),
|
||||
mini_line(204,14,3,0,0,0,[
|
||||
str_block(0,204,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,204,14,3,0,0,0,0,0,0,0,
|
||||
"data can be prepended or appended")])
|
||||
])
|
||||
])]).
|
||||
text('black',400,146,5,0,1,188,86,247,14,4,0,0,0,0,2,188,86,0,0,"",0,0,0,0,160,'',[
|
||||
minilines(188,86,0,0,0,0,0,[
|
||||
mini_line(105,14,4,0,0,0,[
|
||||
str_block(0,105,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
|
||||
"public functions:")])
|
||||
]),
|
||||
mini_line(172,14,3,0,0,0,[
|
||||
str_block(0,172,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,172,14,3,0,0,0,0,0,0,0,
|
||||
"- Iterators to move byte buffer")])
|
||||
]),
|
||||
mini_line(171,14,3,0,0,0,[
|
||||
str_block(0,171,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,171,14,3,0,0,0,0,0,0,0,
|
||||
"pointers forward or backward")])
|
||||
]),
|
||||
mini_line(188,14,3,0,0,0,[
|
||||
str_block(0,188,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,188,14,3,0,0,0,0,0,0,0,
|
||||
"- functions to read and write data")])
|
||||
]),
|
||||
mini_line(132,14,3,0,0,0,[
|
||||
str_block(0,132,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,132,14,3,0,-1,0,0,0,0,0,
|
||||
"of various sized chunks")])
|
||||
])
|
||||
])]).
|
||||
box('black','',96,324,304,532,0,3,1,264,0,0,0,0,0,'3',0,[
|
||||
]).
|
||||
text('black',112,454,4,0,1,167,69,265,14,4,0,0,0,0,2,167,69,0,0,"",0,0,0,0,468,'',[
|
||||
minilines(167,69,0,0,0,0,0,[
|
||||
mini_line(80,14,4,0,0,0,[
|
||||
str_block(0,80,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,80,14,4,0,-1,0,0,0,0,0,
|
||||
"private data:")])
|
||||
]),
|
||||
mini_line(167,14,3,0,0,0,[
|
||||
str_block(0,167,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,167,14,3,0,0,0,0,0,0,0,
|
||||
"- singly linked-list of TagData")])
|
||||
]),
|
||||
mini_line(158,14,3,0,0,0,[
|
||||
str_block(0,158,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,158,14,3,0,0,0,0,0,0,0,
|
||||
"structures, with a reference")])
|
||||
]),
|
||||
mini_line(32,14,3,0,0,0,[
|
||||
str_block(0,32,14,3,0,0,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,32,14,3,0,0,0,0,0,0,0,
|
||||
"count")])
|
||||
])
|
||||
])]).
|
||||
text('black',112,326,5,0,1,155,86,266,14,4,0,0,0,0,2,155,86,0,0,"",0,0,0,0,340,'',[
|
||||
minilines(155,86,0,0,0,0,0,[
|
||||
mini_line(105,14,4,0,0,0,[
|
||||
str_block(0,105,14,4,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Bold',1,80640,105,14,4,0,-1,0,0,0,0,0,
|
||||
"public functions:")])
|
||||
]),
|
||||
mini_line(80,14,3,0,0,0,[
|
||||
str_block(0,80,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,80,14,3,0,-1,0,0,0,0,0,
|
||||
"- constructors")])
|
||||
]),
|
||||
mini_line(155,14,3,0,0,0,[
|
||||
str_block(0,155,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,155,14,3,0,-1,0,0,0,0,0,
|
||||
"- templates to add, remove,")])
|
||||
]),
|
||||
mini_line(148,14,3,0,0,0,[
|
||||
str_block(0,148,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,148,14,3,0,-1,0,0,0,0,0,
|
||||
"or peek at Tags of various")])
|
||||
]),
|
||||
mini_line(31,14,3,0,0,0,[
|
||||
str_block(0,31,14,3,0,-1,0,0,0,[
|
||||
str_seg('black','Times-Roman',0,80640,31,14,3,0,-1,0,0,0,0,0,
|
||||
"types")])
|
||||
])
|
||||
])]).
|
||||
poly('black','',2,[
|
||||
59,245,96,320],0,2,1,272,0,0,3,0,0,0,0,'2',0,0,
|
||||
"0","",[
|
||||
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
|
||||
]).
|
||||
poly('black','',2,[
|
||||
123,246,288,320],0,2,1,280,0,0,3,0,0,0,0,'2',0,0,
|
||||
"0","",[
|
||||
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
|
||||
]).
|
||||
poly('black','',2,[
|
||||
141,219,379,147],0,2,1,286,0,0,3,0,0,0,0,'2',0,0,
|
||||
"0","",[
|
||||
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
|
||||
]).
|
||||
poly('black','',2,[
|
||||
132,226,375,335],0,2,1,287,0,0,3,0,0,0,0,'2',0,0,
|
||||
"0","",[
|
||||
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
|
||||
]).
|
||||
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
@node Logging
|
||||
@chapter Logging
|
||||
@anchor{chap:Logging}
|
||||
|
||||
This chapter is the first in a series of chapters discussing things that
|
||||
one can do to modify the input or output of existing ns-3 scripts.
|
||||
|
||||
Examples:
|
||||
@itemize @bullet
|
||||
@item Enable or disable the generation of log messages, with fine granularity
|
||||
@item Set default values for configuration values in the system
|
||||
@item Generate a report of all configuration values used during a simulation
|
||||
run (not yet implemented)
|
||||
@item Set or get values of member variables on objects already instantiated
|
||||
@item Customizing the tracing output of the script
|
||||
@item Generate statistics on (not yet implemented)
|
||||
@item Perform a large number of independent runs of the same simulation
|
||||
@end itemize
|
||||
|
||||
@node Logging Basics
|
||||
@section Logging Basics
|
||||
|
||||
@node Enabling Log Output
|
||||
@section Enabling Log Output
|
||||
@@ -0,0 +1,156 @@
|
||||
body {
|
||||
font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif;
|
||||
background: white;
|
||||
color: black;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
# color: #990000;
|
||||
color: #009999;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 10pt;
|
||||
background: #e0e0e0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
#main th {
|
||||
font-size: 12pt;
|
||||
background: #b0b0b0;
|
||||
}
|
||||
|
||||
.odd {
|
||||
font-size: 12pt;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.even {
|
||||
font-size: 12pt;
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
.answer {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.answer p {
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.answer ul {
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
#feedback {
|
||||
color: #b0b0b0;
|
||||
font-size: 9pt;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#header {
|
||||
position: absolute;
|
||||
margin: 0px;
|
||||
top: 10px;
|
||||
height:96px;
|
||||
left: 175px;
|
||||
right: 10em;
|
||||
bottom: auto;
|
||||
background: white;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#middle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#main {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 175px;
|
||||
right: 100px;
|
||||
background: white;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
position: absolute;
|
||||
top: 75px;
|
||||
left: 0em;
|
||||
width: 146px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#navbar a:link, #navbar a:visited {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
#navbar a:hover {
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
#navbar dl {
|
||||
width: 146px;
|
||||
padding: 0;
|
||||
margin: 0 0 10px 0px;
|
||||
background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left;
|
||||
}
|
||||
|
||||
#navbar dt {
|
||||
padding: 6px 10px;
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
background: #009999;
|
||||
margin: 0px;
|
||||
border-bottom: 1px solid #fff;
|
||||
color: white;
|
||||
background: #009999 url(images/box_top2.gif) no-repeat top left;
|
||||
}
|
||||
|
||||
#navbar dd {
|
||||
font-size: 100%;
|
||||
margin: 0 0 0 0px;
|
||||
padding: 6px 10px;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
dd#selected {
|
||||
background: #99ffff url(images/arrow.gif) no-repeat;
|
||||
background-position: 4px 10px;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename ns-3.info
|
||||
@settitle ns-3 manual
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@ifinfo
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
four forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator
|
||||
@item @uref{http://www.nsnam.org/tutorial/index.html,,ns-3 Tutorial}
|
||||
@item Reference Manual (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML versions
|
||||
should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
@end ifinfo
|
||||
|
||||
@copying
|
||||
|
||||
This is an @command{ns-3} reference manual.
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
four forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/tutorial/index.html,,ns-3 Tutorial}
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen}: Documentation of the public APIs of the simulator
|
||||
@item Reference Manual (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML
|
||||
versions should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
|
||||
This software is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This software is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see @uref{http://www.gnu.org/licenses/}.
|
||||
@end copying
|
||||
|
||||
@titlepage
|
||||
@title ns-3 Reference Manual
|
||||
@author ns-3 project
|
||||
@author feedback: ns-developers@@isi.edu
|
||||
@today{}
|
||||
|
||||
@c @page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
|
||||
@c So the toc is printed at the start.
|
||||
@anchor{Full Table of Contents}
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top, Overview, Full Table of Contents
|
||||
@top ns-3 Manual (html version)
|
||||
|
||||
For a pdf version of this manual,
|
||||
see @uref{http://www.nsnam.org/docs/manual.pdf}.
|
||||
|
||||
@insertcopying
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* Random variables::
|
||||
* Callbacks::
|
||||
* Attributes::
|
||||
* Packets::
|
||||
* Sockets APIs::
|
||||
* Routing overview::
|
||||
* Troubleshooting
|
||||
@end menu
|
||||
|
||||
@include random.texi
|
||||
@include callbacks.texi
|
||||
@include attributes.texi
|
||||
@include packets.texi
|
||||
@include sockets.texi
|
||||
@c @include output.texi
|
||||
@include routing.texi
|
||||
@c @include other.texi
|
||||
@include troubleshoot.texi
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
|
||||
@c ========================================================================
|
||||
@c Simulation Output
|
||||
@c ========================================================================
|
||||
|
||||
@node Simulation Output
|
||||
@chapter Simulation Output
|
||||
|
||||
At this point, you should be able to execute any of the built-in
|
||||
programs distributed with @command{ns-3}. Next, we will look at
|
||||
how to generate and tailor the simulation output, before turning
|
||||
to how to modify simulation scripts to do different things.
|
||||
|
||||
@node Tracing Basics
|
||||
@section Tracing Basics
|
||||
|
||||
The whole point of simulation is to generate output for further
|
||||
study, and the @command{ns-3} tracing system is a primary
|
||||
mechanism for this.
|
||||
Since @command{ns-3} is a C++ program, standard facilities for
|
||||
generating output from C++ programs apply:
|
||||
|
||||
@verbatim
|
||||
#include <iostream>
|
||||
...
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
std::cout << "The value of x is " << x << std::endl;
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The goal of the @command{ns-3} tracing system is to
|
||||
provide a structured way to configure the simulator to output results
|
||||
in standard or modifiable formats.
|
||||
@itemize @bullet
|
||||
@item For basic tasks, the tracing system should allow the user to
|
||||
generate standard tracing for popular tracing sources, and to customize
|
||||
which objects generate the tracing.
|
||||
@item Intermediate users will be able to extend the tracing system to
|
||||
modify the output format generated, or to insert new tracing sources,
|
||||
without modifying the core of the simulator.
|
||||
@item Advanced users can modify the simulator core to add new
|
||||
tracing sources and sinks.
|
||||
@end itemize
|
||||
|
||||
The @command{ns-3} tracing system is fundamentally built on the
|
||||
concept of separating tracing sources from sinks.
|
||||
@enumerate
|
||||
@item Trace sources (e.g., provide access to every packet received)
|
||||
@item Trace sinks (e.g., print out the packet)
|
||||
@item A mechanism to tie together sources and sinks
|
||||
@end enumerate
|
||||
The rationale for this division is to allow users to attach new
|
||||
types of sinks to existing tracing sources, without requiring
|
||||
users to edit and recompile the core of the simulator.
|
||||
Thus, in the example above, a user could write a new tracing sink
|
||||
and attach it to an existing tracing source. What remains to
|
||||
be defined is a way for users to find these hooks (tracing sources)
|
||||
and attach sinks to them. A new tracing namespace is defined for
|
||||
this purpose.
|
||||
|
||||
We will first walk through how some pre-defined sources and sinks
|
||||
are provided and may be customized with little user effort. We
|
||||
return later in this chapter to advanced tracing configuration including
|
||||
extending the tracing namespace and creating new tracing sources.
|
||||
|
||||
@subsection ASCII tracing
|
||||
@cindex ASCII
|
||||
For Internet nodes, the ASCII trace wrapper is a wrapper around
|
||||
the @command{ns-3} low-level
|
||||
tracing system that lets you get access to underlying trace events easily.
|
||||
The output of a trace of a simulation run is an ASCII file --- thus the name.
|
||||
In the spririt of keeping things simple, you won't be able to control or
|
||||
configure the output at this stage.
|
||||
|
||||
For those familiar with @command{ns-2} output, this type of trace is
|
||||
analogous to the @command{out.tr} generated by many scripts.
|
||||
|
||||
@cindex tracing packets
|
||||
Let's just jump right in. As usual, we need to include the definitions
|
||||
related to using ASCII tracing (don't edit any files quite yet):
|
||||
|
||||
@verbatim
|
||||
#include "ns3/ascii-trace.h"
|
||||
@end verbatim
|
||||
|
||||
We then need to add the code to the script to actually enable the ASCII tracing
|
||||
code. The following code must be inserted before the call to
|
||||
@code{Simulator::Run ();}:
|
||||
|
||||
@verbatim
|
||||
AsciiTrace asciitrace ("tutorial.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
@end verbatim
|
||||
|
||||
The first line declares an object of type @code{AsciiTrace} named
|
||||
@code{asciitrace} and passes a string parameter to its constructor. This
|
||||
parameter is a file name to which all of the trace information will be written.
|
||||
The second line, @code{asciitrace.TraceAllQueues ();} asks the trace object to
|
||||
arrange that all queue operations (enqueue, dequeue, drop) on the queues
|
||||
in all of the nodes of the system be traced. On the receive side,
|
||||
@code{asciitrace.TraceAlllNetDeviceRx ()} traces packets received by
|
||||
a NetDevice. For those familiar with @command{ns-2}, these are equivalent
|
||||
to the popular trace points that log "+", "-", "d", and "r" events.
|
||||
|
||||
Try running the following program from the command line:
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-ascii-trace
|
||||
@end verbatim
|
||||
|
||||
@cindex tutorial.tr
|
||||
Just as you have seen previously, you will see some messages from @emph{Waf}
|
||||
and then the ``Compilation finished successfully'' message. The
|
||||
next message, @code{UDP Echo Simulation} is from the running program. When
|
||||
it ran, the program will have created a file named @code{tutorial.tr}.
|
||||
Because of the way that Waf works, the file is not created in the local
|
||||
directory, it is created at the top-level directory of the repository. So,
|
||||
change into the top level directory and take a look at the file
|
||||
@code{tutorial.tr} in your favorite editor.
|
||||
|
||||
@subsubsection Parsing Ascii Traces
|
||||
@cindex parsing ascii traces
|
||||
|
||||
This section parses in detail the structure of the ascii tracing
|
||||
output. If you find this output format self explanatory (it
|
||||
resembles tcpdump output), you may skip to the next
|
||||
section on pcap tracing.
|
||||
|
||||
@cindex trace event
|
||||
There's a lot of information there in a pretty dense form, but the first thing
|
||||
to notice is that there are a number of distinct lines in this file. It may
|
||||
be difficult to see this clearly unless you widen your windows considerably.
|
||||
Each line in the file corresponds to a @emph{trace event}. A trace event
|
||||
happens whenever specific conditions happen in the simulation. In this case
|
||||
we are tracing events on the @emph{device queue} present in every net device
|
||||
on every node in the simulation. The device queue is a queue through which
|
||||
every packet destined for a channel must pass --- it is the device
|
||||
@emph{transmit} queue. Note that each line in the trace file begins with a
|
||||
lone character (has a space after it). This character will have the following
|
||||
meaning:
|
||||
|
||||
@cindex enqueue
|
||||
@cindex dequeue
|
||||
@cindex drop
|
||||
@itemize @bullet
|
||||
@item @code{+}: An enqueue operation occurred on the device queue;
|
||||
@item @code{-}: A dequeue operation occurred on the device queue;
|
||||
@item @code{d}: A packet was dropped, typically because the queue was full.
|
||||
@end itemize
|
||||
|
||||
Let's take a more detailed view of the first line. I'll break it down into
|
||||
sections (indented for clarity) with a two digit reference number on the
|
||||
left side:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=9
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=ff:ff:ff:ff:ff:ff
|
||||
10 ARP(request
|
||||
11 source mac: 08:00:2e:00:00:00
|
||||
12 source ipv4: 10.1.1.1
|
||||
13 dest ipv4: 10.1.1.2)
|
||||
14 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex trace event
|
||||
@cindex simulation time
|
||||
The first line of this expanded trace event (reference number 00) is the
|
||||
queue operation. We have a @code{+} character, so this corresponds to an
|
||||
@emph{enqueue} operation. The second line (reference 01) is the simulation
|
||||
time expressed in seconds. You may recall that we asked the
|
||||
@code{UdpEchoClient} to start sending packets at two seconds. Here we see
|
||||
confirmation that this is, indeed, happening.
|
||||
|
||||
@cindex node number
|
||||
@cindex net device number
|
||||
@cindex smart pointer
|
||||
The next lines of the example listing (references 02 and 03) tell us that
|
||||
this trace event originated in a given node and net device. Each time a node
|
||||
is created it is given an identifying number that monotonically increases from
|
||||
zero. Therefore, @code{nodeid=0} means that the node in which the given trace
|
||||
event originated is the first node we created. In the case of our script,
|
||||
this first node is is the node pointed to by the smart pointer @code{n0}. Not
|
||||
too surpsisingly, this is also the node to which we attached the
|
||||
@code{UdpEchoClient}. The device number is local to each node, and so the
|
||||
device given by @code{device=0} is the first net device that we added to the
|
||||
node in question. In our simulation, this corresponds to the
|
||||
@code{CsmaNetDevice} we added to node zero (@code{n0}).
|
||||
|
||||
@cindex uid
|
||||
@cindex unique ID
|
||||
@cindex packet
|
||||
The next line (reference 04) is a more readable form of the operation code
|
||||
seen in the first line --- i.e., the character @code{+} means
|
||||
@code{queue-enqueue}. Reference number 05 indicates that the @emph{unique id}
|
||||
of the packet being enqueued is @code{9}. The fact that the first packet we
|
||||
see has a unique ID of 9 should indicates to you that other things have
|
||||
happened in the protocol stack before we got to this point. This will become
|
||||
clear momentarily.
|
||||
|
||||
@cindex Ethernet
|
||||
@cindex MAC address
|
||||
Reference items 06 and 14 indicate that this is an Ethernet packet with
|
||||
a zero (not computed) checksum (note the indentation to make parsing this
|
||||
trace event a little easier). Reference 08 and 09 are the source and
|
||||
destination addresses of this packet. The packet is from the MAC address we
|
||||
assigned to the node zero net device in the script, and is destined for the
|
||||
broadcast address --- this is a broadcast packet.
|
||||
|
||||
@cindex Address Resolution Protocol
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
Reference items 10 through 13 make clear what is happening. This is an ARP
|
||||
(Address Resolution Protocol) request for the MAC address of the node on
|
||||
which the @code{UdpEchoServer} resides. The protocol stack can't send a UDP
|
||||
packet to be echoed until it knows (resolves) the MAC address; and this trace
|
||||
event corresponds to an ARP request being queued for transmission to the local
|
||||
network. The next line in the trace file (partially expanded),
|
||||
|
||||
@verbatim
|
||||
00 -
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-dequeue
|
||||
05 pkt-uid=9
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
shows the (same) ARP request packet being dequeued from the device queue by
|
||||
the net device and (implicitly) being sent down the channel to the broadcast
|
||||
MAC address. We are not tracing net device reception events so we don't
|
||||
actually see all of the net devices receiving the broadcast packet. We do,
|
||||
however see the following in the third line of the trace file:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00207
|
||||
02 nodeid=1
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=10
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:01,
|
||||
09 destination=08:00:2e:00:00:00,
|
||||
10 ARP(reply
|
||||
11 source mac: 08:00:2e:00:00:01
|
||||
12 source ipv4: 10.1.1.2
|
||||
13 dest mac: 08:00:2e:00:00:00
|
||||
14 dest ipv4: 10.1.1.1)
|
||||
15 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex ARP|response
|
||||
Notice that this is a queue-enqueue operation (references 00 and 04) happening
|
||||
on node one (reference 02) at simulation time 2.00207 seconds (reference 01).
|
||||
Looking at the packet payload (references 10-14) we see that this is an ARP
|
||||
reply to the request sent by node one. Note that the simulation time
|
||||
(reference 01) is now 2.00207 seconds. This is direct result of the data rate
|
||||
(5 mb/s) and latency (2 ms) parameters that we passed to the
|
||||
@code{CsmaChannel} when we created it. Clearly the ARP request packet was
|
||||
sent over the channel and received approximately 2 ms later by node one. A
|
||||
corresponding ARP response packet was created and enqueued on node one's net
|
||||
device. It is this enqueue trace event that has being logged.
|
||||
|
||||
@cindex queue
|
||||
@cindex queue|transmit
|
||||
@cindex echo
|
||||
Given the current state of affairs, the next thing you may expect to see is
|
||||
this ARP request being received by node zero, but remember we are only looking
|
||||
at trace events on the device @emph{transmit} queue. The reception of the ARP
|
||||
response by node zero will not directly trigger any trace event in this case,
|
||||
but it will enable the protocol stack to continue what it was originally doing
|
||||
(trying to send an echo packet). Thus, the next line we see in the trace file
|
||||
(@code{tutorial.tr}) is the first UDP echo packet being sent to the net device.
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00415
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=7
|
||||
06 ETHERNET
|
||||
07 length/type=0x800,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=08:00:2e:00:00:01
|
||||
10 IPV4(
|
||||
11 tos 0x0
|
||||
12 ttl 64
|
||||
13 id 0
|
||||
14 offset 0
|
||||
15 flags [none]
|
||||
16 length: 1052) 10.1.1.1 > 10.1.1.2
|
||||
17 UDP(length: 1032)
|
||||
18 49153 > 7
|
||||
19 DATA (length 1024)
|
||||
20 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex echo
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
@cindex ARP|response
|
||||
@cindex IP
|
||||
@cindex Ipv4
|
||||
I won't go into too much detail about this packet, but I will point out a
|
||||
few key items in the trace. First, the packet was enqueued at simulation time
|
||||
of 2.00415 seconds. This time reflects the fact that the echo client
|
||||
application started at 2. seconds and there were two ARP packets transmitted
|
||||
across the network (two milliseconds + data transmission time each way). The
|
||||
packet unique identifier (reference 05) is 7. Notice that this is a lower
|
||||
number than the ARP request packet, which had a unique ID of 9. This tells
|
||||
us that the UDP packet was actually created before the ARP request packet ---
|
||||
which makes perfect sense since it was the attempt to send packet 7 that
|
||||
triggered sending the ARP request packet 9. Note that this an Ethernet
|
||||
packet (reference 06) like all other packets in this simulation, however this
|
||||
particular packet carries an IPV4 payload and therefore has an IP version 4
|
||||
header (indicated by references 10-16). This Ipv4 in turn contains a UDP
|
||||
header (references 17, 18) and finally 1024 bytes of data (reference 20).
|
||||
Clearly, this is the UDP echo packet emitted by the
|
||||
@code{UdpEchoClient Application}.
|
||||
|
||||
The next trace event is an ARP request from node one. We can infer that node
|
||||
one has received the UDP echo packet and the @code{UdpEchoServer Application}
|
||||
on that node has turned the packet around. Just as node zero needed to ARP
|
||||
for the MAC address of node one, now node one must ARP for the MAC address of
|
||||
node zero. We see the ARP request enqueued on the transmit queue of node one;
|
||||
then we see the ARP request dequeued from the tranmit queue of node one (and
|
||||
implicitly transmitted to node zero). Then we see an ARP response enqueued
|
||||
on the transmit queue of node zero; and finally the ARP response dequeued (and
|
||||
implicitly transmitted back to node one).
|
||||
|
||||
This exchange is summarized in the following trace event excerpts,
|
||||
|
||||
@verbatim
|
||||
+ 2.00786 nodeid=1 ... ARP(request ...
|
||||
- 2.00786 nodeid=1 ... ARP(request ...
|
||||
+ 2.00994 nodeid=0 ... ARP(reply ...
|
||||
- 2.00994 nodeid=0 ... ARP(reply ...
|
||||
@end verbatim
|
||||
|
||||
The final two trace events in the @code{tutorial.tr} file correspond to the
|
||||
echoed packet being enqueued for transmission on the net device for node one,
|
||||
and that packet being dequeued (and implicitly transmitted back to node zero).
|
||||
|
||||
@cindex AsciiTrace!TraceAllNetDeviceRx
|
||||
@cindex ARP!request
|
||||
If you look at the trace file (@code{tutorial.tr}) you will also see some
|
||||
entries with an @code{r} event, indicating a
|
||||
@emph{receive} trace event. Recall that the first packet sent on the network
|
||||
was a broadcast ARP request. We should then see all four nodes receive a
|
||||
copy of this request. This is the case, as the first four receive trace
|
||||
events are,
|
||||
|
||||
@verbatim
|
||||
r 2.00207 nodeid=0 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=1 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=2 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=3 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
@end verbatim
|
||||
|
||||
@cindex unique ID
|
||||
You can see that a copy of the broadcast packet with unique ID 9 was received
|
||||
by the net devices on nodes 0, 1, 2 and 3. We leave it up to you to parse the
|
||||
rest of the trace file and understand the remaining reception events.
|
||||
|
||||
@subsection PCAP Trace Wrapper
|
||||
@cindex pcap
|
||||
@cindex Wireshark
|
||||
The @command{ns-3} @emph{pcap trace wrapper} is used to create trace files in
|
||||
@code{.pcap} format. The acronym pcap (usually written in lower case) stands
|
||||
for @emph{p}acket @emph{cap}ture, and is actually an API that includes the
|
||||
definition of a @code{.pcap} file format. The most popular program that can
|
||||
read and display this format is Wireshark (formerly called Ethereal).
|
||||
However, there are many traffic trace analyzers that use this packet
|
||||
format, including X, Y, and Z. We encourage users to exploit the
|
||||
many tools available for analyzing pcap traces; below, we show how
|
||||
tcpdump and Wireshark can be used..
|
||||
|
||||
@cindex tutorial-csma-echo-ascii-trace.cc
|
||||
@cindex tutorial-csma-echo-pcap-trace.cc
|
||||
The code used to enable pcap tracing is similar to that for ASCII tracing.
|
||||
We have provided another file, @code{tutorial-csma-echo-pcap-trace.cc} that
|
||||
uses the pcap trace wrapper. We have added the code to include the pcap
|
||||
trace wrapper defintions:
|
||||
|
||||
@verbatim
|
||||
#include "ns3/pcap-trace.h"
|
||||
@end verbatim
|
||||
|
||||
And then added the following code below the AsciiTrace methods:
|
||||
|
||||
@cindex PcapTrace
|
||||
@cindex PcapTrace!TraceAllIp
|
||||
@verbatim
|
||||
PcapTrace pcaptrace ("tutorial.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
@end verbatim
|
||||
|
||||
The first line of the code immediately above declares an object of type
|
||||
@code{PcapTrace} named @code{pcaptrace} and passes a string parameter to its
|
||||
constructor. This object is used to hide the details of the actual tracing
|
||||
subsystem. The parameter is a base file name from which the actual trace file
|
||||
names will be built. The second line of code tells the @code{PcamTrace}
|
||||
object to trace all IP activity in all of the nodes present in the simulation.
|
||||
|
||||
@cindex interface index
|
||||
Trace files are not created until trace activity is detected. Each file name
|
||||
is composed of the base file name, followed by a @code{'-'}, a node id followed
|
||||
by a @code{'-}', and an IP interface index. You will soon see a file named
|
||||
@code{tutorial.pcap-0-1}, for example. This will be the trace file generated
|
||||
as events are detected on node zero, interface index one. N.B. Interface
|
||||
indices are different that net device indices --- interface index zero
|
||||
corresponds to the loopback interface and interface index one corresponds to
|
||||
the first net device you added to a node.
|
||||
|
||||
You may run the new program just like all of the others so far:
|
||||
|
||||
@cindex Waf
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-pcap-trace
|
||||
@end verbatim
|
||||
|
||||
If you look at the top level directory of your distribution, you should now
|
||||
see three log files: @code{tutorial.tr} is the ASCII trace file we have
|
||||
previously examined. @code{tutorial.pcap-0-1} and @code{tutorial.pcap-1-1}
|
||||
are the new pcap files we just generated. There will not be files
|
||||
corresponding to nodes two and three since we have not sent any IP packets to
|
||||
those nodes.
|
||||
|
||||
@subsubsection Reading output with tcpdump
|
||||
@cindex tcpdump
|
||||
|
||||
@subsubsection Reading output with Wireshark
|
||||
@cindex Wireshark
|
||||
If you are unfamilar with Wireshark, there is a web site available from which
|
||||
you can download programs and documentation: @uref{http://www.wireshark.org/}.
|
||||
|
||||
If you have Wireshark available, you can open each of the trace files and
|
||||
display the contents as if you had captured the packets using a
|
||||
@emph{packet sniffer}. Note that only IP packets are traced using this
|
||||
wrapper, so you will not see the ARP exchanges that were logged when using
|
||||
the ASCII trace wrapper. You are encouraged to take a look at the contents
|
||||
of these pcap files using your favorite pcap software (or Wireshark).
|
||||
|
||||
@node Advanced Tracing
|
||||
@section Advanced Tracing
|
||||
|
||||
@@ -0,0 +1,620 @@
|
||||
@node Packets
|
||||
@chapter Packets
|
||||
|
||||
The design of the Packet framework of @emph{ns} was heavily guided by a few
|
||||
important use-cases:
|
||||
@itemize @bullet
|
||||
@item avoid changing the core of the simulator to introduce
|
||||
new types of packet headers or trailers
|
||||
@item maximize the ease of integration with real-world code
|
||||
and systems
|
||||
@item make it easy to support fragmentation, defragmentation,
|
||||
and, concatenation which are important, especially in wireless systems.
|
||||
@item make memory management of this object efficient
|
||||
@item allow actual application data or dummy application bytes for
|
||||
emulated applications
|
||||
@end itemize
|
||||
|
||||
@emph{ns} Packet objects contain a buffer of bytes: protocol headers and
|
||||
trailers are serialized in this buffer of bytes using user-provided
|
||||
serialization and deserialization routines. The content of this byte
|
||||
buffer is expected to match bit-for-bit the content of a real packet on
|
||||
a real network implementing the protocol of interest.
|
||||
|
||||
Fragmentation and defragmentation are quite natural to implement within
|
||||
this context: since we have a buffer of real bytes, we can split it in
|
||||
multiple fragments and re-assemble these fragments. We expect that this
|
||||
choice will make it really easy to wrap our Packet data structure within
|
||||
Linux-style skb or BSD-style mbuf to integrate real-world kernel code in
|
||||
the simulator. We also expect that performing a real-time plug of the
|
||||
simulator to a real-world network will be easy.
|
||||
|
||||
Because we understand that simulation developers often wish to store in
|
||||
packet objects data which is not found in the real packets (such as
|
||||
timestamps or any kind of similar in-band data), the @emph{ns} Packet class
|
||||
can also store extra per-packet "Tags" which are 16 bytes blobs of data.
|
||||
Any Packet can store any number of unique Tags, each of which is
|
||||
uniquely identified by its C++ type. These tags make it easy to attach
|
||||
per-model data to a packet without having to patch the main Packet
|
||||
class or Packet facilities.
|
||||
|
||||
Memory management of Packet objects is entirely automatic and extremely
|
||||
efficient: memory for the application-level payload can be modelized by
|
||||
a virtual buffer of zero-filled bytes for which memory is never allocated
|
||||
unless explicitely requested by the user or unless the packet is fragmented.
|
||||
Furthermore, copying, adding, and, removing headers or trailers to a packet
|
||||
has been optimized to be virtually free through a technique known as
|
||||
Copy On Write.
|
||||
|
||||
Packets (messages) are fundamental objects in the simulator and
|
||||
their design is important from a performance and resource management
|
||||
perspective. There
|
||||
are various ways to design the simulation packet, and tradeoffs
|
||||
among the different approaches. In particular, there is a
|
||||
tension between ease-of-use, performance, and safe interface
|
||||
design.
|
||||
|
||||
There are a few requirements on this object design:
|
||||
@itemize @bullet
|
||||
@item Creation, management, and deletion of this object
|
||||
should be as simple as possible, while avoiding the
|
||||
chance for memory leaks and/or heap corruption;
|
||||
@item Packets should support serialization and deserialization
|
||||
so that network emulation is supported;
|
||||
@item Packets should support fragmentation and concatenation
|
||||
(multiple packets in a data link frame), especially for wireless
|
||||
support;
|
||||
@item It should be natural for packets to carry actual application
|
||||
data, or if there is only an emulated application and there is
|
||||
no need to carry dummy bytes, smaller packets could be used with
|
||||
just the headers and a record of the payload size, but not actual
|
||||
application bytes, conveyed in the simulated packet.
|
||||
@item Packets should facilitate BSD-like operations on mbufs, for
|
||||
support of ported operating system stacks.
|
||||
@item Additional side-information should be supported, such as
|
||||
a tag for cross-layer information.
|
||||
@end itemize
|
||||
|
||||
@section Packet design overview
|
||||
|
||||
Unlike @emph{ns-2}, in which Packet objects contain a buffer of C++
|
||||
structures corresponding to protocol headers, each network packet in
|
||||
@emph{ns-3} contains a byte Buffer and a list of Tags:
|
||||
@itemize @bullet
|
||||
@item The byte buffer stores the serialized content of the chunks
|
||||
added to a packet. The serialized representation of these chunks is
|
||||
expected to match that of real network packets bit for bit
|
||||
(although nothing forces you to do this) which means that the content
|
||||
of a packet buffer is expected to be that of a real packet.
|
||||
Packets can also be created with an arbitrary zero-filled payload
|
||||
for which no real memory is allocated.
|
||||
@item The list of tags stores an arbitrarily large set of arbitrary
|
||||
user-provided data structures in the packet. Each Tag is uniquely
|
||||
identified by its type; only one instance of each
|
||||
type of data structure is allowed in a list of tags. These tags typically
|
||||
contain per-packet cross-layer information or flow identifiers (i.e.,
|
||||
things that you wouldn't find in the bits on the wire). Each tag
|
||||
stored in the tag list can be at most 16 bytes.
|
||||
Trying to attach bigger data structures will trigger
|
||||
crashes at runtime. The 16 byte limit is a modifiable compilation
|
||||
constant.
|
||||
@end itemize
|
||||
|
||||
@float Figure,fig:packets
|
||||
@caption{Implementation overview of Packet class.}
|
||||
@image{figures/packet}
|
||||
@end float
|
||||
|
||||
Figure @ref{fig:packets} is a high-level overview of the Packet
|
||||
implementation; more detail on the byte Buffer implementation
|
||||
is provided later in Figure @ref{fig:buffer}.
|
||||
In \nsthree, the Packet byte buffer is analogous to a Linux skbuff
|
||||
or BSD mbuf; it is a serialized representation of the actual
|
||||
data in the packet. The tag list is a container for extra
|
||||
items useful for simulation convenience; if a Packet is converted
|
||||
to an emulated packet and put over an actual network, the tags
|
||||
are stripped off and the byte buffer is copied directly
|
||||
into a real packet.
|
||||
|
||||
The Packet class has value semantics: it can be freely copied around,
|
||||
allocated on the stack, and passed to functions as arguments. Whenever
|
||||
an instance is copied, the full underlying data is not copied; it
|
||||
has ``copy-on-write'' (COW) semantics. Packet instances can be passed
|
||||
by value to function arguments without any performance hit.
|
||||
|
||||
The fundamental classes for adding to and removing from the byte
|
||||
buffer are @code{class Header} and @code{class Trailer}.
|
||||
Headers are more common but the below discussion also largely applies to
|
||||
protocols using trailers. Every protocol header that needs to
|
||||
be inserted and removed from a Packet instance should derive from
|
||||
the abstract Header base class and implement the private pure
|
||||
virtual methods listed below:
|
||||
@itemize @bullet
|
||||
@item @code{ns3::Header::SerializeTo()}
|
||||
@item @code{ns3::Header::DeserializeFrom()}
|
||||
@item @code{ns3::Header::GetSerializedSize()}
|
||||
@item @code{ns3::Header::PrintTo()}
|
||||
@end itemize
|
||||
Basically, the first three functions are used to serialize and deserialize
|
||||
protocol control information to/from a Buffer. For example,
|
||||
one may define @code{class TCPHeader : public Header}. The
|
||||
TCPHeader object will typically consist of some private data
|
||||
(like a sequence number) and public interface access functions
|
||||
(such as checking the bounds of an input). But the underlying
|
||||
representation of the TCPHeader in a Packet Buffer is 20 serialized
|
||||
bytes (plus TCP options). The TCPHeader::SerializeTo() function would
|
||||
therefore be designed to write these 20 bytes properly into
|
||||
the packet, in network byte order. The last function is used
|
||||
to define how the Header object prints itself onto an output stream.
|
||||
|
||||
Similarly, user-defined Tags can be appended to the packet.
|
||||
Unlike Headers, Tags are not serialized into a contiguous buffer
|
||||
but are stored in an array. By default, Tags are limited to 16 bytes in
|
||||
size. Tags can be flexibly defined to be any type, but there
|
||||
can only be one instance of any particular object type in
|
||||
the Tags buffer at any time. The implementation makes use
|
||||
of templates to generate the proper set of Add(), Remove(),
|
||||
and Peek() functions for each Tag type.
|
||||
|
||||
@section Packet interface
|
||||
|
||||
The public member functions of a Packet object are as follows:
|
||||
|
||||
@subsection Constructors
|
||||
@verbatim
|
||||
/**
|
||||
* Create an empty packet with a new uid (as returned
|
||||
* by getUid).
|
||||
*/
|
||||
Packet ();
|
||||
/**
|
||||
* Create a packet with a zero-filled payload.
|
||||
* The memory necessary for the payload is not allocated:
|
||||
* it will be allocated at any later point if you attempt
|
||||
* to fragment this packet or to access the zero-filled
|
||||
* bytes. The packet is allocated with a new uid (as
|
||||
* returned by getUid).
|
||||
*
|
||||
* \param size the size of the zero-filled payload
|
||||
*/
|
||||
Packet (uint32_t size);
|
||||
@end verbatim
|
||||
|
||||
@subsection Adding and removing Buffer data
|
||||
The below code is reproduced for Header class only; similar functions
|
||||
exist for Trailers.
|
||||
@verbatim
|
||||
/**
|
||||
* Add header to this packet. This method invokes the
|
||||
* ns3::Header::serializeTo method to request the header to serialize
|
||||
* itself in the packet buffer.
|
||||
*
|
||||
* \param header a reference to the header to add to this packet.
|
||||
*/
|
||||
void Add (Header const &header);
|
||||
/**
|
||||
* Deserialize header from this packet. This method invokes the
|
||||
* ns3::Header::deserializeFrom method to request the header to deserialize
|
||||
* itself from the packet buffer. This method does not remove
|
||||
* the data from the buffer. It merely reads it.
|
||||
*
|
||||
* \param header a reference to the header to deserialize from the buffer
|
||||
*/
|
||||
void Peek (Header &header);
|
||||
/**
|
||||
* Remove a deserialized header from the internal buffer.
|
||||
* This method removes the bytes read by Packet::peek from
|
||||
* the packet buffer.
|
||||
*
|
||||
* \param header a reference to the header to remove from the internal buffer.
|
||||
*/
|
||||
void Remove (Header const &header);
|
||||
/**
|
||||
* Add trailer to this packet. This method invokes the
|
||||
* ns3::Trailer::serializeTo method to request the trailer to serialize
|
||||
* itself in the packet buffer.
|
||||
*
|
||||
* \param trailer a reference to the trailer to add to this packet.
|
||||
*/
|
||||
@end verbatim
|
||||
|
||||
@subsection Adding and removing Tags
|
||||
@verbatim
|
||||
/**
|
||||
* Attach a tag to this packet. The tag is fully copied
|
||||
* in a packet-specific internal buffer. This operation
|
||||
* is expected to be really fast.
|
||||
*
|
||||
* \param tag a pointer to the tag to attach to this packet.
|
||||
*/
|
||||
template <typename T>
|
||||
void AddTag (T const &tag);
|
||||
/**
|
||||
* Remove a tag from this packet. The data stored internally
|
||||
* for this tag is copied in the input tag if an instance
|
||||
* of this tag type is present in the internal buffer. If this
|
||||
* tag type is not present, the input tag is not modified.
|
||||
*
|
||||
* This operation can be potentially slow and might trigger
|
||||
* unexpectedly large memory allocations. It is thus
|
||||
* usually a better idea to create a copy of this packet,
|
||||
* and invoke removeAllTags on the copy to remove all
|
||||
* tags rather than remove the tags one by one from a packet.
|
||||
*
|
||||
* \param tag a pointer to the tag to remove from this packet
|
||||
* \returns true if an instance of this tag type is stored
|
||||
* in this packet, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool RemoveTag (T &tag);
|
||||
/**
|
||||
* Copy a tag stored internally to the input tag. If no instance
|
||||
* of this tag is present internally, the input tag is not modified.
|
||||
*
|
||||
* \param tag a pointer to the tag to read from this packet
|
||||
* \returns true if an instance of this tag type is stored
|
||||
* in this packet, false otherwise.
|
||||
*/
|
||||
template <typename T>
|
||||
bool PeekTag (T &tag) const;
|
||||
/**
|
||||
* Remove all the tags stored in this packet. This operation is
|
||||
* much much faster than invoking removeTag n times.
|
||||
*/
|
||||
void RemoveAllTags (void);
|
||||
@end verbatim
|
||||
|
||||
@subsection Fragmentation
|
||||
@verbatim
|
||||
/**
|
||||
* Create a new packet which contains a fragment of the original
|
||||
* packet. The returned packet shares the same uid as this packet.
|
||||
*
|
||||
* \param start offset from start of packet to start of fragment to create
|
||||
* \param length length of fragment to create
|
||||
* \returns a fragment of the original packet
|
||||
*/
|
||||
Packet CreateFragment (uint32_t start, uint32_t length) const;
|
||||
|
||||
/**
|
||||
* Concatenate the input packet at the end of the current
|
||||
* packet. This does not alter the uid of either packet.
|
||||
*
|
||||
* \param packet packet to concatenate
|
||||
*/
|
||||
void addAtEnd (Packet packet);
|
||||
|
||||
/oncatenate the input packet at the end of the current
|
||||
* packet. This does not alter the uid of either packet.
|
||||
*
|
||||
* \param packet packet to concatenate
|
||||
*/
|
||||
void AddAtEnd (Packet packet);
|
||||
/**
|
||||
* Concatenate the fragment of the input packet identified
|
||||
* by the offset and size parameters at the end of the current
|
||||
* packet. This does not alter the uid of either packet.
|
||||
*
|
||||
* \param packet to concatenate
|
||||
* \param offset offset of fragment to copy from the start of the input packet
|
||||
* \param size size of fragment of input packet to copy.
|
||||
*/
|
||||
void AddAtEnd (Packet packet, uint32_t offset, uint32_t size);
|
||||
/**
|
||||
* Remove size bytes from the end of the current packet
|
||||
* It is safe to remove more bytes that what is present in
|
||||
* the packet.
|
||||
*
|
||||
* \param size number of bytes from remove
|
||||
*/
|
||||
void RemoveAtEnd (uint32_t size);
|
||||
/**
|
||||
* Remove size bytes from the start of the current packet.
|
||||
* It is safe to remove more bytes that what is present in
|
||||
* the packet.
|
||||
*
|
||||
* \param size number of bytes from remove
|
||||
*/
|
||||
void RemoveAtStart (uint32_t size);
|
||||
@end verbatim
|
||||
|
||||
@subsection Miscellaneous
|
||||
@verbatim
|
||||
/**
|
||||
* \returns the size in bytes of the packet (including the zero-filled
|
||||
* initial payload)
|
||||
*/
|
||||
uint32_t GetSize (void) const;
|
||||
/**
|
||||
* If you try to change the content of the buffer
|
||||
* returned by this method, you will die.
|
||||
*
|
||||
* \returns a pointer to the internal buffer of the packet.
|
||||
*/
|
||||
uint8_t const *PeekData (void) const;
|
||||
/**
|
||||
* A packet is allocated a new uid when it is created
|
||||
* empty or with zero-filled payload.
|
||||
*
|
||||
* \returns an integer identifier which uniquely
|
||||
* identifies this packet.
|
||||
*/
|
||||
uint32_t GetUid (void) const;
|
||||
@end verbatim
|
||||
|
||||
@section Using Headers
|
||||
@emph{walk through an example of adding a UDP header}
|
||||
|
||||
@section Using Tags
|
||||
@emph{walk through an example of adding a flow ID}
|
||||
|
||||
@section Using Fragmentation
|
||||
@emph{walk through an example of link-layer fragmentation/reassembly}
|
||||
|
||||
@section Sample program
|
||||
The below sample program (from @code{ns3/samples/main-packet.cc}) illustrates
|
||||
some use of the Packet, Header, and Tag classes.
|
||||
|
||||
@verbatim
|
||||
/* -*- Mode:C++; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/* A sample Header implementation
|
||||
*/
|
||||
class MyHeader : public Header {
|
||||
public:
|
||||
MyHeader ();
|
||||
virtual ~MyHeader ();
|
||||
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
private:
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
virtual void DeserializeFrom (Buffer::Iterator start);
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
|
||||
uint16_t m_data;
|
||||
};
|
||||
|
||||
MyHeader::MyHeader ()
|
||||
{}
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
void
|
||||
MyHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "MyHeader data=" << m_data << std::endl;
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::GetSerializedSize (void) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
void
|
||||
MyHeader::SerializeTo (Buffer::Iterator start) const
|
||||
{
|
||||
// serialize in head of buffer
|
||||
start.WriteHtonU16 (m_data);
|
||||
}
|
||||
void
|
||||
MyHeader::DeserializeFrom (Buffer::Iterator start)
|
||||
{
|
||||
// deserialize from head of buffer
|
||||
m_data = start.ReadNtohU16 ();
|
||||
}
|
||||
|
||||
void
|
||||
MyHeader::SetData (uint16_t data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
uint16_t
|
||||
MyHeader::GetData (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
/* A sample Tag implementation
|
||||
*/
|
||||
struct MyTag {
|
||||
uint16_t m_streamId;
|
||||
};
|
||||
|
||||
static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
|
||||
|
||||
|
||||
static void
|
||||
Receive (Packet p)
|
||||
{
|
||||
MyHeader my;
|
||||
p.Peek (my);
|
||||
p.Remove (my);
|
||||
std::cout << "received data=" << my.GetData () << std::endl;
|
||||
struct MyTag myTag;
|
||||
p.PeekTag (myTag);
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet p;
|
||||
MyHeader my;
|
||||
my.SetData (2);
|
||||
std::cout << "send data=2" << std::endl;
|
||||
p.Add (my);
|
||||
struct MyTag myTag;
|
||||
myTag.m_streamId = 5;
|
||||
p.AddTag (myTag);
|
||||
Receive (p);
|
||||
return 0;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
@section Implementation details
|
||||
|
||||
@subsection Private member variables
|
||||
|
||||
A Packet object's interface provides access to some private
|
||||
data:
|
||||
@verbatim
|
||||
Buffer m_buffer;
|
||||
Tags m_tags;
|
||||
uint32_t m_uid;
|
||||
static uint32_t m_global_uid;
|
||||
@end verbatim
|
||||
Each Packet has a Buffer and a Tags object, and a 32-bit unique ID (m\_uid).
|
||||
A static member variable keeps track of the UIDs allocated. Note
|
||||
that real network packets do not have a UID; the UID is therefore an
|
||||
instance of data that normally would be stored as a Tag in the packet.
|
||||
However, it was felt that a UID is a special case that is so often
|
||||
used in simulations that it would be more convenient to store it
|
||||
in a member variable.
|
||||
|
||||
@subsection Buffer implementation
|
||||
|
||||
Class Buffer represents a buffer of bytes. Its size is
|
||||
automatically adjusted to hold any data prepended
|
||||
or appended by the user. Its implementation is optimized
|
||||
to ensure that the number of buffer resizes is minimized,
|
||||
by creating new Buffers of the maximum size ever used.
|
||||
The correct maximum size is learned at runtime during use by
|
||||
recording the maximum size of each packet.
|
||||
|
||||
Authors of new Header or Trailer classes need to know the public
|
||||
API of the Buffer class. (add summary here)
|
||||
|
||||
The byte buffer is implemented as follows:
|
||||
@verbatim
|
||||
struct BufferData {
|
||||
uint32_t m_count;
|
||||
uint32_t m_size;
|
||||
uint32_t m_initialStart;
|
||||
uint32_t m_dirtyStart;
|
||||
uint32_t m_dirtySize;
|
||||
uint8_t m_data[1];
|
||||
};
|
||||
struct BufferData *m_data;
|
||||
uint32_t m_zeroAreaSize;
|
||||
uint32_t m_start;
|
||||
uint32_t m_size;
|
||||
@end verbatim
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{BufferData::m_count}: reference count for BufferData structure
|
||||
@item @code{BufferData::m_size}: size of data buffer stored in BufferData structure
|
||||
@item @code{BufferData::m_initialStart}: offset from start of data buffer where data was first inserted
|
||||
@item @code{BufferData::m_dirtyStart}: offset from start of buffer where every Buffer which holds a reference to this BufferData instance have written data so far
|
||||
@item @code{BufferData::m_dirtySize}: size of area where data has been written so far
|
||||
@item @code{BufferData::m_data}: pointer to data buffer
|
||||
@item @code{Buffer::m_zeroAreaSize}: size of zero area which extends before @code{m_initialStart}
|
||||
@item @code{Buffer::m_start}: offset from start of buffer to area used by this buffer
|
||||
@item @code{Buffer::m_size}: size of area used by this Buffer in its BufferData structure
|
||||
@end itemize
|
||||
|
||||
@float Figure,fig:buffer
|
||||
@caption{Implementation overview of a packet's byte Buffer.}
|
||||
@image{figures/buffer,15cm}
|
||||
@end float
|
||||
|
||||
This data structure is summarized in Figure @ref{fig:buffer}.
|
||||
Each Buffer holds a pointer to an instance of a BufferData. Most
|
||||
Buffers should be able to share the same underlying BufferData and
|
||||
thus simply increase the BufferData's reference count. If they have to
|
||||
change the content of a BufferData inside the Dirty Area, and if the
|
||||
reference count is not one, they first create a copy of the BufferData and
|
||||
then complete their state-changing operation.
|
||||
|
||||
@subsection Tags implementation
|
||||
Tags are implemented by a single pointer which points to the start of a
|
||||
linked list ofTagData data structures. Each TagData structure points
|
||||
to the next TagData in the list (its next pointer contains zero to
|
||||
indicate the end of the linked list). Each TagData contains an integer
|
||||
unique id which identifies the type of the tag stored in the TagData.
|
||||
@verbatim
|
||||
struct TagData {
|
||||
struct TagData *m_next;
|
||||
uint32_t m_id;
|
||||
uint32_t m_count;
|
||||
uint8_t m_data[Tags::SIZE];
|
||||
};
|
||||
class Tags {
|
||||
struct TagData *m_next;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
Adding a tag is a matter of inserting a new TagData at the head of
|
||||
the linked list. Looking at a tag requires you to find the relevant
|
||||
TagData in the linked list and copy its data into the user data
|
||||
structure. Removing a tag and updating the content of a tag
|
||||
requires a deep copy of the linked list before performing this operation.
|
||||
On the other hand, copying a Packet and its tags is a matter of
|
||||
copying the TagData head pointer and incrementing its reference count.
|
||||
|
||||
Tags are found by the unique mapping betweent the Tag type and
|
||||
its underlying id. This is why at most one instance of any Tag
|
||||
can be stored in a packet. The mapping between Tag type and
|
||||
underlying id is performed by a registration as follows:
|
||||
@verbatim
|
||||
/* A sample Tag implementation
|
||||
*/
|
||||
struct MyTag {
|
||||
uint16_t m_streamId;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
@emph{add description of TagRegistration for printing}
|
||||
|
||||
@subsection Memory management
|
||||
|
||||
@emph{Describe free list.}
|
||||
|
||||
@emph{Describe dataless vs. data-full packets.}
|
||||
|
||||
@subsection Copy-on-write semantics
|
||||
The current implementation of the byte buffers and tag list is based
|
||||
on COW (Copy On Write). An introduction to COW can be found in Scott
|
||||
Meyer's "More Effective C++", items 17 and 29). This design feature
|
||||
and aspects of the public interface borrows from the packet design
|
||||
of the Georgia Tech Network Simulator.
|
||||
This implementation of COW uses a customized reference counting
|
||||
smart pointer class.
|
||||
|
||||
What COW means is that
|
||||
copying packets without modifying them is very cheap (in terms of CPU
|
||||
and memory usage) and modifying them can be also very cheap. What is
|
||||
key for proper COW implementations is being
|
||||
able to detect when a given modification of the state of a packet triggers
|
||||
a full copy of the data prior to the modification: COW systems need
|
||||
to detect when an operation is ``dirty'' and must therefore invoke
|
||||
a true copy.
|
||||
|
||||
Dirty operations:
|
||||
@itemize @bullet
|
||||
@item Packet::RemoveTag()
|
||||
@item Packet::Add()
|
||||
@item both versions of ns3::Packet::AddAtEnd()
|
||||
@end itemize
|
||||
|
||||
Non-dirty operations:
|
||||
@itemize @bullet
|
||||
@item Packet::AddTag()
|
||||
@item Packet::RemoveAllTags()
|
||||
@item Packet::PeekTag()
|
||||
@item Packet::Peek()
|
||||
@item Packet::Remove()
|
||||
@item Packet::CreateFragment()
|
||||
@item Packet::RemoveAtStart()
|
||||
@item Packet::RemoveAtEnd()
|
||||
@end itemize
|
||||
|
||||
Dirty operations will always be slower than non-dirty operations,
|
||||
sometimes by several orders of magnitude. However, even the
|
||||
dirty operations have been optimized for common use-cases which
|
||||
means that most of the time, these operations will not trigger
|
||||
data copies and will thus be still very fast.
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
@anchor{chap:rv}
|
||||
@node Random variables
|
||||
@chapter Random variables
|
||||
|
||||
ns-3 contains a built-in pseudo-random number generator (PRNG).
|
||||
It is important for serious users of the simulator to understand
|
||||
the functionality, configuration, and usage of this PRNG, and
|
||||
to decide whether it is sufficient for his or her research use.
|
||||
|
||||
@node Quick Overview
|
||||
@section Quick Overview
|
||||
|
||||
ns-3 random numbers are provided via instances of @code{class RandomVariable}.
|
||||
@itemize @bullet
|
||||
@item @strong{by default, ns-3 simulations use a random seed}; if there is any
|
||||
randomness in the simulation, each run of the program will yield different results. To use a fixed seed, users must call
|
||||
@code{RandomVariable::UseGlobalSeed ()} at the beginning of the program;
|
||||
see section @xref{Seeding and independent replications}
|
||||
@item each RandomVariable used in ns-3 has a virtual random number
|
||||
generator associated with it; all random variables use either a fixed
|
||||
or random seed based on the use of the global seed (previous bullet);
|
||||
@item if you intend to perform multiple runs of the same scenario, with
|
||||
different random numbers, please be sure to read the section on how to
|
||||
perform independent replications: @xref{Seeding and independent replications}.
|
||||
@end itemize
|
||||
|
||||
Read further for more explanation about the random number facility for
|
||||
ns-3.
|
||||
|
||||
@node Background
|
||||
@section Background
|
||||
|
||||
Simulations use a lot of random numbers; the study in [cite]
|
||||
found that most network simulations spend as much as 50%
|
||||
of the CPU generating random numbers. Simulation users need
|
||||
to be concerned with the quality of the (pseudo) random numbers and
|
||||
the independence between different streams of random numbers.
|
||||
|
||||
Users need to be concerned with a few issues, such as:
|
||||
@itemize @bullet
|
||||
@item the seeding of the random number generator and whether a
|
||||
simulation run is deterministic or not,
|
||||
@item how to acquire different streams of random numbers that are
|
||||
independent from one another, and
|
||||
@item how long it takes for streams to cycle
|
||||
@end itemize
|
||||
|
||||
We will introduce a few terms here: a RNG provides a long sequence
|
||||
of (pseudo) random numbers.
|
||||
The length of this sequence is called the @emph{cycle length}
|
||||
or @emph{period}, after which the RNG will repeat itself.
|
||||
This sequence can
|
||||
be partitioned into disjoint @emph{streams}. A stream of a
|
||||
RNG is a contiguous subset or block of the RNG sequence.
|
||||
For instance, if the
|
||||
RNG period is of length N, and two streams are provided from this
|
||||
RNG, then
|
||||
the first stream might use the first N/2 values and the second
|
||||
stream might produce the second N/2 values. An important property
|
||||
here is that the two streams are uncorrelated. Likewise, each
|
||||
stream can be partitioned disjointly to a number of
|
||||
uncorrelated @emph{substreams}. The underlying RNG hopefully
|
||||
produces a pseudo-random sequence of numbers with a very long
|
||||
cycle length, and partitions this into streams and substreams in an
|
||||
efficient manner.
|
||||
|
||||
ns-3 uses the same underlying random number generator as does
|
||||
ns-2: the MRG32k3a generator from Pierre L'Ecuyer. A
|
||||
detailed description can be found in
|
||||
@uref{http://www.iro.umontreal.ca/~lecuyer/myftp/papers/streams00.pdf,,}.
|
||||
The MRG32k3a generator provides 1.8x10^19 independent
|
||||
streams of random numbers, each of which consists of
|
||||
2.3x10^15 substreams. Each substream has a period
|
||||
(@emph{i.e.}, the number of random numbers before overlap) of
|
||||
7.6x10^22. The period of the entire generator is
|
||||
3.1x10^57. Figure ref-streams provides a graphical idea of
|
||||
how the streams and substreams fit together.
|
||||
|
||||
Class @code{ns3::RandomVariable} is the public interface to this
|
||||
underlying random number generator. When users create new
|
||||
RandomVariables (such as UniformVariable, ExponentialVariable,
|
||||
etc.), they create an object that uses one of the distinct, independent
|
||||
streams of the random number generator. Therefore, each
|
||||
object of type RandomVariable has, conceptually, its own "virtual" RNG.
|
||||
Furthermore, each RandomVariable can be configured to use
|
||||
one of the set of substreams drawn from the main stream.
|
||||
|
||||
An alternate implementation would be to allow each RandomVariable
|
||||
to have its own (differently seeded) RNG. However, we cannot
|
||||
guarantee as strongly that the different sequences would be
|
||||
uncorrelated in such a case; hence, we prefer to use a single RNG
|
||||
and streams and substreams from it.
|
||||
|
||||
@anchor{chap:rv:indeprep}
|
||||
@node Seeding and independent replications
|
||||
@section Seeding and independent replications
|
||||
|
||||
ns-3 simulations can be configured to produce deterministic or
|
||||
random results. If the ns-3 simulation is configured to use
|
||||
a fixed, deterministic seed with the same run number, it should give
|
||||
the same output each time it is run.
|
||||
|
||||
By default, ns-3 simulations use random seeds where the seeding
|
||||
is drawn from @code{/dev/random} (if it is available) or else from
|
||||
the time of day. A user who wants to fix the initial seeding
|
||||
of the PRNG must call the following static method during simulation
|
||||
configuration:
|
||||
@verbatim
|
||||
RandomVariable::UseGlobalSeed (uint32_t s0, s1, s2, s3, s4, s5);
|
||||
@end verbatim
|
||||
where the six parameters are each of type uint32_t.
|
||||
|
||||
A typical use case is to run a simulation as a sequence of independent
|
||||
trials, so as to compute statistics on a large number of independent
|
||||
runs. The user can either change the global seed and rerun the
|
||||
simulation, or can advance the substream state of the RNG.
|
||||
This seeding and substream state setting must be called before any
|
||||
random variables are created; e.g.
|
||||
|
||||
@verbatim
|
||||
RandomVariable::UseGlobalSeed(1,2,3,4,5,6);
|
||||
int N = atol(argv[1]); //read in run number from command line
|
||||
RandomVariable::SetRunNumber(N);
|
||||
// Now, create random variables
|
||||
UniformVariable x(0,10);
|
||||
ExponentialVariable y(2902);
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
Which is better, setting a new seed or advancing the substream state?
|
||||
There is no guarantee that the streams
|
||||
produced by two random seeds will not overlap. The only way to
|
||||
guarantee that two streams do not overlap is to use the substream
|
||||
capability provided by the RNG implementation.
|
||||
@strong{Therefore, use the substream capability to produce
|
||||
multiple independent runs of the same simulation.}
|
||||
In other words, the more statistically rigorous way to configure
|
||||
multiple independent replications is not to simply ignore the
|
||||
seeding (and use /dev/random to seed the generator each time) but
|
||||
instead to use a fixed seed and to iterate the run number.
|
||||
This implementation allows for a maximum of
|
||||
2.3x10^15 independent replications using the substreams.
|
||||
|
||||
@node class RandomVariable
|
||||
@section class RandomVariable
|
||||
|
||||
All random variables should derive from @code{class RandomVariable}.
|
||||
This base class provides a few static methods for globally configuring
|
||||
the behavior of the random number generator. Derived classes
|
||||
provide API for drawing random variates from the particular
|
||||
distribution being supported.
|
||||
|
||||
Each RandomVariable created in the simulation is given a generator
|
||||
that is a new RNGStream from the underlying PRNG.
|
||||
Used in this manner, the L'Ecuyer implementation allows for a maximum of
|
||||
1.8x10^19 random variables. Each random variable in
|
||||
a single replication can produce up to 7.6x10^22 random
|
||||
numbers before overlapping.
|
||||
|
||||
@node Base class public API
|
||||
@section Base class public API
|
||||
|
||||
Below are excerpted a few public methods of @code{class RandomVariable}
|
||||
that deal with the global configuration and state of the RNG.
|
||||
@verbatim
|
||||
/**
|
||||
* \brief Set seeding behavior
|
||||
*
|
||||
* Specify whether the POSIX device /dev/random is to
|
||||
* be used for seeding. When this is used, the underlying
|
||||
* generator is seeded with data from /dev/random instead of
|
||||
* being seeded based upon the time of day. Defaults to true.
|
||||
*/
|
||||
static void UseDevRandom(bool udr = true);
|
||||
|
||||
/**
|
||||
* \brief Use the global seed to force precisely reproducible results.
|
||||
*/
|
||||
static void UseGlobalSeed(uint32_t s0, uint32_t s1, uint32_t s2,
|
||||
uint32_t s3, uint32_t s4, uint32_t s5);
|
||||
|
||||
/**
|
||||
* \brief Set the run number of this simulation
|
||||
*/
|
||||
static void SetRunNumber(uint32_t n);
|
||||
|
||||
/**
|
||||
* \brief Get the internal state of the RNG
|
||||
*
|
||||
* This function is for power users who understand the inner workings
|
||||
* of the underlying RngStream method used. It returns the internal
|
||||
* state of the RNG via the input parameter.
|
||||
* \param seed Output parameter; gets overwritten with the internal state
|
||||
* of the RNG.
|
||||
*/
|
||||
void GetSeed(uint32_t seed[6]) const;
|
||||
@end verbatim
|
||||
|
||||
We have already described the seeding configuration above.
|
||||
|
||||
@node Types of RandomVariables
|
||||
@section Types of RandomVariables
|
||||
|
||||
The following types of random variables are provided, and are documented
|
||||
in the ns-3 Doxygen or by reading @code{src/core/random-variable.h}. Users
|
||||
can also create their own custom random variables by deriving from
|
||||
class RandomVariable.
|
||||
@itemize @bullet
|
||||
@item @code{class UniformVariable }
|
||||
@item @code{class ConstantVariable }
|
||||
@item @code{class SequentialVariable }
|
||||
@item @code{class ExponentialVariable }
|
||||
@item @code{class ParetoVariable }
|
||||
@item @code{class WeibullVariable }
|
||||
@item @code{class NormalVariable }
|
||||
@item @code{class EmpiricalVariable }
|
||||
@item @code{class IntEmpiricalVariable }
|
||||
@item @code{class DeterministicVariable }
|
||||
@item @code{class LogNormalVariable }
|
||||
@item @code{class TriangularVariable }
|
||||
@end itemize
|
||||
|
||||
@node Semantics of RandomVariable objects
|
||||
@section Semantics of RandomVariable objects
|
||||
|
||||
RandomVariable objects have value semantics. This means that they
|
||||
can be passed by value to functions. The can also be passed by
|
||||
reference to const. RandomVariables do not derive from
|
||||
@code{ns3::Object} and we do not use smart pointers to manage them;
|
||||
they are either allocated on the stack or else users explicitly manage
|
||||
any heap-allocated RandomVariables.
|
||||
|
||||
RandomVariable objects can also be used in ns-3 attributes, which means
|
||||
that values can be set for them through the ns-3 attribute system.
|
||||
An example is in the propagation models for WifiNetDevice:
|
||||
@verbatim
|
||||
TypeId
|
||||
RandomPropagationDelayModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel")
|
||||
.SetParent<PropagationDelayModel> ()
|
||||
.AddConstructor<RandomPropagationDelayModel> ()
|
||||
.AddAttribute ("Variable",
|
||||
"The random variable which generates random delays (s).",
|
||||
RandomVariableValue (UniformVariable (0.0, 1.0)),
|
||||
MakeRandomVariableAccessor (&RandomPropagationDelayModel::m_variable),
|
||||
MakeRandomVariableChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
Here, the ns-3 user can change the default random variable for this
|
||||
delay model (which is a UniformVariable ranging from 0 to 1) through
|
||||
the attribute system.
|
||||
|
||||
@node Using other PRNG
|
||||
@section Using other PRNG
|
||||
|
||||
There is presently no support for substituting a different underlying
|
||||
random number generator (e.g., the GNU Scientific Library or the Akaroa
|
||||
package). Patches are welcome.
|
||||
|
||||
@node More advanced usage
|
||||
@section More advanced usage
|
||||
|
||||
@emph{To be completed}
|
||||
|
||||
@node Publishing your results
|
||||
@section Publishing your results
|
||||
|
||||
When you publish simulation results, a key piece of configuration
|
||||
information that you should always state is how you used the
|
||||
the random number generator.
|
||||
@itemize @bullet
|
||||
@item what seeds you used,
|
||||
@item what RNG you used if not the default,
|
||||
@item how were independent runs performed,
|
||||
@item for large simulations, how did you check that you did not cycle.
|
||||
@end itemize
|
||||
|
||||
It is incumbent on the researcher publishing results to include enough
|
||||
information to allow others to reproduce his or her results. It is
|
||||
also incumbent on the researcher to convince oneself that the random
|
||||
numbers used were statistically valid, and to state in the paper why
|
||||
such confidence is assumed.
|
||||
|
||||
@node Summary
|
||||
@section Summary
|
||||
|
||||
Let's review what things you should do when creating a simulation.
|
||||
|
||||
@itemize @bullet
|
||||
@item Decide whether you are running with a fixed seed or random seed;
|
||||
a random seed is the default,
|
||||
@item Decide how you are going to manage independent replications, if
|
||||
applicable,
|
||||
@item Convince yourself that you are not drawing more random values
|
||||
than the cycle length, if you are running a long simulation, and
|
||||
@item When you publish, follow the guidelines above about documenting your
|
||||
use of the random number generator.
|
||||
@end itemize
|
||||
|
||||
The program @emph{samples/main-random.cc} has some examples of usage.
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
@node Routing overview
|
||||
@chapter Routing overview
|
||||
|
||||
This chapter describes the overall design of routing in the
|
||||
@code{src/internet-stack}
|
||||
module, and some details about the routing approachs currently
|
||||
implemented.
|
||||
|
||||
@node Routing-Overview
|
||||
@section Overview
|
||||
|
||||
We intend to support traditional routing approaches and protocols,
|
||||
ports of open source routing implementations, and facilitate research
|
||||
into unorthodox routing techniques.
|
||||
For simulations that are not primarily focused on routing and that
|
||||
simply want correct routing tables to occur somehow, we have an
|
||||
global centralized routing capability. A singleton object
|
||||
(GlobalRouteManager) be instantiated, builds a network map, and
|
||||
populates a forwarding table on each node at time t=0 in the
|
||||
simulation. Simulation script writers can use the same node
|
||||
API to manually enter routes as well.
|
||||
|
||||
@node Support for multiple routing protocols
|
||||
@section Support for multiple routing protocols
|
||||
|
||||
Typically, multiple routing protocols are supported in user space and
|
||||
coordinate to write a single forwarding table in the kernel. Presently
|
||||
in @command{ns-3}, the implementation instead allows for multiple routing
|
||||
protocols to build/keep their own routing state, and the IPv4 implementation
|
||||
will query each one of these routing protocols (in some order determined
|
||||
by the simulation author) until a route is found.
|
||||
|
||||
We chose this approach because it may better
|
||||
faciliate the integration of disparate routing approaches that may
|
||||
be difficult to coordinate the writing to a single table, approaches
|
||||
where more information than destination IP address (e.g., source
|
||||
routing) is used to determine the next hop, and on-demand
|
||||
routing approaches where packets must be cached.
|
||||
|
||||
There are presently two routing protocols defined:
|
||||
@itemize @bullet
|
||||
@item class Ipv4StaticRouting (covering both unicast and multicast)
|
||||
@item Optimized Link State Routing (a MANET protocol defined in
|
||||
@uref{http://www.ietf.org/rfc/rfc3626.txt,,RFC 3626})
|
||||
@end itemize
|
||||
but first we describe how multiple routing protocols are supported.
|
||||
|
||||
@subsection class Ipv4RoutingProtocol
|
||||
|
||||
@code{class Ipv4RoutingProtocol} derives from ns-3 Object which means
|
||||
that it supports interface aggregation and reference counting. Routing
|
||||
protocols should inherit from this class, defined in src/node/ipv4.cc.
|
||||
|
||||
The main function that must be supported by these protocols is called
|
||||
@code{RequestRoute}.
|
||||
@verbatim
|
||||
* This method is called whenever a node's IPv4 forwarding engine
|
||||
* needs to lookup a route for a given packet and IP header.
|
||||
*
|
||||
* The routing protocol implementation may determine immediately it
|
||||
* should not be handling this particular the route request. For
|
||||
* instance, a routing protocol may decline to search for routes for
|
||||
* certain classes of addresses, like link-local. In this case,
|
||||
* RequestRoute() should return false and the routeReply callback
|
||||
* must not be invoked.
|
||||
*
|
||||
* If the routing protocol implementations assumes it can provide
|
||||
* the requested route, then it should return true, and the
|
||||
* routeReply callback must be invoked, either immediately before
|
||||
* returning true (synchronously), or in the future (asynchronous).
|
||||
* The routing protocol may use any information available in the IP
|
||||
* header and packet as routing key, although most routing protocols
|
||||
* use only the destination address (as given by
|
||||
* ipHeader.GetDestination ()). The routing protocol is also
|
||||
* allowed to add a new header to the packet, which will appear
|
||||
* immediately after the IP header, although most routing do not
|
||||
* insert any extra header.
|
||||
*/
|
||||
virtual bool RequestRoute (uint32_t ifIndex,
|
||||
const Ipv4Header &ipHeader,
|
||||
Ptr<Packet> packet,
|
||||
RouteReplyCallback routeReply) = 0;
|
||||
@end verbatim
|
||||
|
||||
This class also provides a typedef (used above) for a special Callback
|
||||
that will pass to the callback function the Ipv4Route that is found (see the
|
||||
Doxygen documentation):
|
||||
@verbatim
|
||||
typedef Callback<void, bool, const Ipv4Route&, Ptr<Packet>, const Ipv4Header&> RouteReplyCallback;
|
||||
@end verbatim
|
||||
|
||||
@subsection Ipv4::AddRoutingProtocol
|
||||
|
||||
Class Ipv4 provides a pure virtual function declaration for the
|
||||
method that allows one to add a routing protocol:
|
||||
@verbatim
|
||||
void AddRoutingProtocol (Ptr<Ipv4RoutingProtocol> routingProtocol,
|
||||
int16_t priority);
|
||||
@end verbatim
|
||||
This method is implemented by class Ipv4L3Protocol in the internet-stack
|
||||
module.
|
||||
|
||||
The priority variable above governs the priority in which the routing
|
||||
protocols are inserted. Notice that it is a signed int.
|
||||
When the class Ipv4L3Protocol is instantiated, a single routing
|
||||
protocol (Ipv4StaticRouting, introduced below) is added at priority
|
||||
zero. Internally, a list of Ipv4RoutingProtocols is stored, and
|
||||
and the routing protocols are each consulted in decreasing order
|
||||
of priority to see whether a match is found. Therefore, if you
|
||||
want your Ipv4RoutingProtocol to have priority lower than the static
|
||||
routing, insert it with priority less than 0; e.g.:
|
||||
@verbatim
|
||||
m_ipv4->AddRoutingProtocol (m_routingTable, -10);
|
||||
@end verbatim
|
||||
|
||||
@subsection Ipv4L3Protocol::Lookup
|
||||
|
||||
The main function for obtaining a route is shown below:
|
||||
@verbatim
|
||||
Ipv4L3Protocol::Lookup (
|
||||
uint32_t ifIndex,
|
||||
Ipv4Header const &ipHeader,
|
||||
Ptr<Packet> packet,
|
||||
Ipv4RoutingProtocol::RouteReplyCallback routeReply)
|
||||
@end verbatim
|
||||
|
||||
This function will search the list of routing protocols, in priority order,
|
||||
until a route is found. It will then invoke the RouteReplyCallback
|
||||
and no further routing protocols will be searched. If the caller does
|
||||
not want to constrain the possible interface, it can be wildcarded
|
||||
as such:
|
||||
@verbatim
|
||||
Lookup (Ipv4RoutingProtocol::IF_INDEX_ANY, ipHeader, packet, routeReply);
|
||||
@end verbatim
|
||||
|
||||
@node Roadmap and Future work
|
||||
@section Roadmap and Future work
|
||||
|
||||
Some goals for future support are:
|
||||
|
||||
Users should be able to trace (either debug print, or redirect to a trace
|
||||
file) the routing table in a format such as used in an
|
||||
Unix implementation:
|
||||
@verbatim
|
||||
# netstat -nr (or # route -n)
|
||||
Kernel IP routing table
|
||||
Destination Gateway Genmask Flags MSS Window irtt Iface
|
||||
127.0.0.1 * 255.255.255.255 UH 0 0 0 lo
|
||||
172.16.1.0 * 255.255.255.0 U 0 0 0 eth0
|
||||
172.16.2.0 172.16.1.1 255.255.255.0 UG 0 0 0 eth0
|
||||
|
||||
# ip route show
|
||||
192.168.99.0/24 dev eth0 scope link
|
||||
127.0.0.0/8 dev lo scope link
|
||||
default via 192.168.99.254 dev eth0
|
||||
@end verbatim
|
||||
|
||||
Global computation of multicast routing should be implemented as well.
|
||||
This would ignore group membership and ensure that a copy of every
|
||||
sourced multicast datagram would be delivered to each node.
|
||||
This might be implemented as an RPF mechanism that functioned on-demand
|
||||
by querying the forwarding table,
|
||||
and perhaps optimized by a small multicast forwarding cache. It is
|
||||
a bit trickier to implement over wireless links where the input
|
||||
interface is the same as the output interface; other aspects of the
|
||||
packet must be considered and the forwarding logic slightly changed
|
||||
to allow for forwarding out the same interface.
|
||||
|
||||
In the future, work on bringing XORP or quagga routing to ns, but it will
|
||||
take several months to port and enable.
|
||||
|
||||
There are presently no roadmap plans for IPv6.
|
||||
|
||||
@node Static routing
|
||||
@section Static routing
|
||||
|
||||
The internet-stack module provides one routing protocol (Ipv4StaticRouting)
|
||||
by default. This routing protocol allows one to add unicast or multicast
|
||||
static routes to a node.
|
||||
|
||||
@node Unicast routing
|
||||
@section Unicast routing
|
||||
|
||||
The unicast static routing API may be accessed via the functions
|
||||
@verbatim
|
||||
void Ipv4::AddHostRouteTo ()
|
||||
void Ipv4::AddNetworkRouteTo ()
|
||||
void Ipv4::SetDefaultRoute ()
|
||||
uint32_t Ipv4::GetNRoutes ()
|
||||
Ipv4Route Ipv4::GetRoute ()
|
||||
@end verbatim
|
||||
|
||||
@uref{http://www.nsnam.org/doxygen/index.html,,Doxygen} documentation
|
||||
provides full documentation of these methods. These methods are forwarding
|
||||
functions to the actual implementation in Ipv4StaticRouting, when using
|
||||
the internet-stack module.
|
||||
|
||||
@node Multicast routing
|
||||
@section Multicast routing
|
||||
|
||||
The following function is used to add a static multicast route
|
||||
to a node:
|
||||
@verbatim
|
||||
void
|
||||
Ipv4StaticRouting::AddMulticastRoute (Ipv4Address origin,
|
||||
Ipv4Address group,
|
||||
uint32_t inputInterface,
|
||||
std::vector<uint32_t> outputInterfaces);
|
||||
@end verbatim
|
||||
|
||||
A multicast route must specify an origin IP address, a multicast group and
|
||||
an input network interface index as conditions and provide a vector of
|
||||
output network interface indices over which packets matching the conditions
|
||||
are sent.
|
||||
|
||||
Typically there are two main types of multicast routes: routes of the
|
||||
first kind are used during forwarding. All of the conditions must be
|
||||
exlicitly provided. The second kind of routes are used to get packets off
|
||||
of a local node. The difference is in the input interface. Routes for
|
||||
forwarding will always have an explicit input interface specified. Routes
|
||||
off of a node will always set the input interface to a wildcard specified
|
||||
by the index Ipv4RoutingProtocol::IF\_INDEX\_ANY.
|
||||
|
||||
For routes off of a local node wildcards may be used in the origin and
|
||||
multicast group addresses. The wildcard used for Ipv4Adresses is that
|
||||
address returned by Ipv4Address::GetAny () -- typically "0.0.0.0". Usage
|
||||
of a wildcard allows one to specify default behavior to varying degrees.
|
||||
|
||||
For example, making the origin address a wildcard, but leaving the
|
||||
multicast group specific allows one (in the case of a node with multiple
|
||||
interfaces) to create different routes using different output interfaces
|
||||
for each multicast group.
|
||||
|
||||
If the origin and multicast addresses are made wildcards, you have created
|
||||
essentially a default multicast address that can forward to multiple
|
||||
interfaces. Compare this to the actual default multicast address that is
|
||||
limited to specifying a single output interface for compatibility with
|
||||
existing functionality in other systems.
|
||||
|
||||
Another command sets the default multicast route:
|
||||
@verbatim
|
||||
void
|
||||
Ipv4StaticRouting::SetDefaultMulticastRoute (uint32_t outputInterface);
|
||||
@end verbatim
|
||||
|
||||
This is the multicast equivalent of the unicast version SetDefaultRoute.
|
||||
We tell the routing system what to do in the case where a specific route
|
||||
to a destination multicast group is not found. The system forwards
|
||||
packets out the specified interface in the hope that "something out there"
|
||||
knows better how to route the packet. This method is only used in
|
||||
initially sending packets off of a host. The default multicast route is
|
||||
not consulted during forwarding -- exact routes must be specified using
|
||||
AddMulticastRoute for that case.
|
||||
|
||||
Since we're basically sending packets to some entity we think may know
|
||||
better what to do, we don't pay attention to "subtleties" like origin
|
||||
address, nor do we worry about forwarding out multiple interfaces. If the
|
||||
default multicast route is set, it is returned as the selected route from
|
||||
LookupStatic irrespective of origin or multicast group if another specific
|
||||
route is not found.
|
||||
|
||||
Finally, a number of additional functions are provided to fetch and
|
||||
remove multicast routes:
|
||||
@verbatim
|
||||
uint32_t GetNMulticastRoutes (void) const;
|
||||
|
||||
Ipv4MulticastRoute *GetMulticastRoute (uint32_t i) const;
|
||||
|
||||
Ipv4MulticastRoute *GetDefaultMulticastRoute (void) const;
|
||||
|
||||
bool RemoveMulticastRoute (Ipv4Address origin,
|
||||
Ipv4Address group,
|
||||
uint32_t inputInterface);
|
||||
|
||||
void RemoveMulticastRoute (uint32_t index);
|
||||
@end verbatim
|
||||
|
||||
@node Global centralized routing
|
||||
@section Global centralized routing
|
||||
|
||||
Presently, global centralized IPv4 @emph{unicast} routing over both
|
||||
point-to-point and shared (CSMA) links is supported.
|
||||
The global centralized routing will be modified in the future to
|
||||
reduce computations once profiling finds the performance bottlenecks.
|
||||
|
||||
@node Global Unicast Routing API
|
||||
@section Global Unicast Routing API
|
||||
|
||||
The public API is very minimal. User scripts include the following:
|
||||
@verbatim
|
||||
#include "ns3/global-route-manager.h"
|
||||
@end verbatim
|
||||
|
||||
After IP addresses are configured, the following function call will
|
||||
cause all of the nodes that have an Ipv4 interface to receive
|
||||
forwarding tables entered automatically by the GlobalRouteManager:
|
||||
@verbatim
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
@end verbatim
|
||||
|
||||
@emph{Note:} A reminder that the wifi NetDevice is not yet supported
|
||||
(only CSMA and PointToPoint).
|
||||
|
||||
@node Global Routing Implementation
|
||||
@section Global Routing Implementation
|
||||
|
||||
A singleton object (GlobalRouteManager) is responsible for populating
|
||||
the static routes on each node, using the public Ipv4 API of that node.
|
||||
It queries each node in the topology for a "globalRouter" interface.
|
||||
If found, it uses the API of that interface to obtain a "link state
|
||||
advertisement (LSA)" for the router. Link State Advertisements
|
||||
are used in OSPF routing, and we follow their formatting.
|
||||
|
||||
The GlobalRouteManager populates a link state database with LSAs
|
||||
gathered from the entire topology. Then, for each router in the topology,
|
||||
the GlobalRouteManager executes the OSPF shortest path first (SPF)
|
||||
computation on the database, and populates the routing tables on each
|
||||
node.
|
||||
|
||||
The quagga (http://www.quagga.net) OSPF implementation was used as the
|
||||
basis for the routing computation logic.
|
||||
One benefit of following an existing OSPF SPF implementation is that
|
||||
OSPF already has defined link state advertisements for all common
|
||||
types of network links:
|
||||
@itemize @bullet
|
||||
@item point-to-point (serial links)
|
||||
@item point-to-multipoint (Frame Relay, ad hoc wireless)
|
||||
@item non-broadcast multiple access (ATM)
|
||||
@item broadcast (Ethernet)
|
||||
@end itemize
|
||||
Therefore, we think that enabling these other link types will be more
|
||||
straightforward now that the underlying OSPF SPF framework is in place.
|
||||
|
||||
Presently, we can handle IPv4 point-to-point, numbered links, as well
|
||||
as shared broadcast (CSMA) links, and we do not do equal-cost multipath.
|
||||
|
||||
The GlobalRouteManager first walks the list of nodes and aggregates
|
||||
a GlobalRouter interface to each one as follows:
|
||||
@verbatim
|
||||
typedef std::vector < Ptr<Node> >::iterator Iterator;
|
||||
for (Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
|
||||
{
|
||||
Ptr<Node> node = *i;
|
||||
Ptr<GlobalRouter> globalRouter = CreateObject<GlobalRouter> (node);
|
||||
node->AggregateObject (globalRouter);
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
This interface is later queried and used to generate a Link State
|
||||
Advertisement for each router, and this link state database is
|
||||
fed into the OSPF shortest path computation logic. The Ipv4 API
|
||||
is finally used to populate the routes themselves.
|
||||
|
||||
@node Optimized Link State Routing (OLSR)
|
||||
@section Optimized Link State Routing (OLSR)
|
||||
|
||||
This is the first dynamic routing protocol for @command{ns-3}. The implementation
|
||||
is found in the src/routing/olsr directory, and an example script is in
|
||||
examples/simple-point-to-point-olsr.cc.
|
||||
|
||||
The following commands will enable OLSR in a simulation.
|
||||
|
||||
@verbatim
|
||||
olsr::EnableAllNodes (); // Start OLSR on all nodes
|
||||
olsr::EnableNodes(InputIterator begin, InputIterator end); // Start on
|
||||
// a list of nodes
|
||||
olsr::EnableNode (Ptr<Node> node); // Start OLSR on "node" only
|
||||
@end verbatim
|
||||
|
||||
Once instantiated, the agent can be started with the Start() command,
|
||||
and the OLSR "main interface" can be set with the SetMainInterface()
|
||||
command. A number of protocol constants are defined in olsr-agent-impl.cc.
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
@node Sockets APIs
|
||||
@chapter Sockets APIs
|
||||
|
||||
The @uref{http://en.wikipedia.org/wiki/Berkeley_sockets,,sockets API}
|
||||
is a long-standing API used by user-space applications to access
|
||||
network services in the kernel. A ``socket'' is an abstraction, like
|
||||
a Unix file handle, that allows applications to connect to other
|
||||
Internet hosts and exchange reliable byte streams and unreliable
|
||||
datagrams, among other services.
|
||||
|
||||
ns-3 provides two types of sockets APIs, and it is important to
|
||||
understand the differences between them. The first is a @emph{native}
|
||||
ns-3 API, while the second uses the services of the native API to
|
||||
provide a @uref{http://en.wikipedia.org/wiki/POSIX,,POSIX-like}
|
||||
API as part of an overall application process. Both APIs strive
|
||||
to be close to the typical sockets API that application writers
|
||||
on Unix systems are accustomed to, but the POSIX variant is much
|
||||
closer to a real system's sockets API.
|
||||
|
||||
@section ns-3 sockets API
|
||||
|
||||
The native sockets API for ns-3 provides an interface to various
|
||||
types of transport protocols (TCP, UDP) as well as to packet sockets
|
||||
and, in the future, Netlink-like sockets. However, users are cautioned
|
||||
to understand that the semantics are @strong{not} the exact same as
|
||||
one finds in a real system (for an API which is very much aligned
|
||||
to real systems, see the next section).
|
||||
|
||||
@code{class ns3::Socket} is defined in @code{src/node/socket.cc,h}.
|
||||
Readers will note that many public member functions are aligned
|
||||
with real sockets function calls, and all other things being equal,
|
||||
we have tried to align with a Posix sockets API. However, note that:
|
||||
|
||||
@itemize @bullet
|
||||
@item ns-3 applications handle a smart pointer to a Socket object, not
|
||||
a file descriptor;
|
||||
@item there is no notion of synchronous API or a ``blocking'' API;
|
||||
in fact, the model for interaction between application and socket is
|
||||
one of asynchronous I/O, which is not typically found in real systems
|
||||
(more on this below);
|
||||
@item the C-style socket address structures are not used;
|
||||
@item the API is not a complete sockets API, such as supporting
|
||||
all socket options or all function variants;
|
||||
@item many calls use @code{ns3::Packet} class to transfer data
|
||||
between application and socket. This may seem a little funny to
|
||||
people to pass ``Packets'' across a stream socket API, but think
|
||||
of these packets as just fancy byte buffers at this level (more
|
||||
on this also below).
|
||||
@end itemize
|
||||
|
||||
@subsection Basic operation and calls
|
||||
|
||||
@float Figure,fig:sockets-overview
|
||||
@caption{Implementation overview of native sockets API}
|
||||
@image{figures/sockets-overview, 10cm}
|
||||
@end float
|
||||
|
||||
@subsubsection Creating sockets
|
||||
|
||||
An application that wants to use sockets must first create one.
|
||||
On real systems, this is accomplished by calling socket():
|
||||
@verbatim
|
||||
int
|
||||
socket(int domain, int type, int protocol);
|
||||
@end verbatim
|
||||
which creates a socket in the system and returns an integer descriptor.
|
||||
|
||||
In ns-3, we have no equivalent of a system call at the lower layers,
|
||||
so we adopt the following model. There are certain @emph{factory}
|
||||
objects that can create sockets. Each factory is capable of creating
|
||||
one type of socket, and if sockets of a particular type are able to
|
||||
be created on a given node, then a factory that can create such sockets
|
||||
must be aggregated to the Node.
|
||||
@verbatim
|
||||
static Ptr<Socket> CreateSocket (Ptr<Node> node, TypeId tid);
|
||||
@end verbatim
|
||||
Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
|
||||
@code{PacketSocketFactory}, and @code{UdpSocketFactory}.
|
||||
|
||||
This method returns a smart pointer to a Socket object. Here is an
|
||||
example:
|
||||
@verbatim
|
||||
Ptr<Node> n0;
|
||||
// Do some stuff to build up the Node's internet stack
|
||||
Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
|
||||
@end verbatim
|
||||
|
||||
In some ns-3 code, sockets will not be explicitly created by user's
|
||||
main programs, if an ns-3 application does it. For instance, for
|
||||
@code{class ns3::OnOffApplication}, the function @code{StartApplication()}
|
||||
performs the socket creation, and the application holds the socket
|
||||
pointer.
|
||||
|
||||
@subsubsection Using sockets
|
||||
|
||||
Below is a typical sequence of socket calls for a TCP client in a
|
||||
real implementation:
|
||||
@itemize @bullet
|
||||
@item @code{sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);}
|
||||
@item @code{bind(sock, ...);}
|
||||
@item @code{connect(sock, ...);}
|
||||
@item @code{send(sock, ...);}
|
||||
@item @code{recv(sock, ...);}
|
||||
@item @code{close(sock);}
|
||||
@end itemize
|
||||
|
||||
There are analogs to all of these calls in ns-3, but we will focus on
|
||||
two aspects here. First, most usage of sockets in real systems
|
||||
requires a way to manage I/O between the application and kernel.
|
||||
These models include @emph{blocking sockets}, @emph{signal-based I/O},
|
||||
and @emph{non-blocking sockets} with polling. In ns-3, we make use
|
||||
of the callback mechanisms to support a fourth mode, which is
|
||||
analogous to POSIX @emph{asynchronous I/O}.
|
||||
|
||||
In this model, on the sending side, if the @code{send()} call were to
|
||||
fail because of insufficient buffers, the application suspends the
|
||||
sending of more data until a function registered at the
|
||||
@code{SetSendCallback()} callback is invoked. An application can
|
||||
also ask the socket how much space is available by calling
|
||||
@code{GetTxAvailable ()}. A typical sequence of events for
|
||||
sending data (ignoring connection setup) might be:
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{SetSendCallback (MakeCallback(&HandleSendCallback));}
|
||||
@item @code{Send ();}
|
||||
@item @code{Send ();}
|
||||
@item ...
|
||||
@item @code{// Send fails because buffer is full}
|
||||
@item (wait until HandleSendCallback() is called)
|
||||
@item (HandleSendCallback() is called by socket, since space now available)
|
||||
@item @code{Send (); // Start sending again}
|
||||
@end itemize
|
||||
|
||||
Similarly, on the receive side, the socket user does not block on
|
||||
a call to @code{recv()}. Instead, the application sets a callback
|
||||
with @code{SetRecvCallback ()} in which the socket will notify the
|
||||
application when (and how much) there is data to be read, and
|
||||
the application then calls @code{Recv()} to read the data until
|
||||
no more can be read.
|
||||
|
||||
@subsection Packet vs. buffer variants
|
||||
|
||||
There are two basic variants of @code{Send()} and @code{Recv()} supported:
|
||||
@verbatim
|
||||
virtual int Send (Ptr<Packet> p) = 0;
|
||||
int Send (const uint8_t* buf, uint32_t size);
|
||||
|
||||
Ptr<Packet> Recv (void);
|
||||
int Recv (uint8_t* buf, uint32_t size);
|
||||
@end verbatim
|
||||
|
||||
The non-Packet variants are left for legacy API reasons. When calling
|
||||
the raw buffer variant of @code{Send()}, the buffer is immediately
|
||||
written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
|
||||
|
||||
Users may find it semantically odd to pass a Packet to a stream socket
|
||||
such as TCP. However, do not let the name bother you; think of
|
||||
@code{ns3::Packet} to be a fancy byte buffer. There are a few reasons why
|
||||
the Packet variants are more likely to be preferred in ns-3:
|
||||
|
||||
@itemize @bullet
|
||||
@item Users can use the Tags facility of packets to, for example, encode
|
||||
a flow ID or other helper data.
|
||||
@item Users can exploit the copy-on-write implementation to avoid
|
||||
memory copies (on the receive side, the conversion back to a
|
||||
@code{uint8_t* buf} may sometimes incur an additional copy).
|
||||
@item Use of Packet is more aligned with the rest of the ns-3 API
|
||||
@end itemize
|
||||
|
||||
@subsection Sending dummy data
|
||||
|
||||
Sometimes, users want the simulator to just pretend that there is an
|
||||
actual data payload in the packet (e.g. to calculate transmission delay)
|
||||
but do not want to actually produce or consume the data. This is
|
||||
straightforward to support in ns-3; have applications call
|
||||
@code{Create<Packet> (size);} instead of @code{Create<Packet> (buffer, size);}.
|
||||
Similarly, passing in a zero to the pointer argument in the raw buffer
|
||||
variants has the same effect. Note that, if some subsequent code tries
|
||||
to read the Packet data buffer, the fake buffer will be converted to
|
||||
a real (zero'ed) buffer on the spot, and the efficiency will be lost there.
|
||||
|
||||
@subsection Socket options
|
||||
|
||||
@emph{to be completed}
|
||||
|
||||
@subsection Socket errno
|
||||
|
||||
@emph{to be completed}
|
||||
|
||||
@subsection Example programs
|
||||
|
||||
@emph{to be completed}
|
||||
|
||||
@section POSIX-like sockets API
|
||||
|
||||
@emph{this capability is under development and is scheduled for
|
||||
inclusion in August 2008 timeframe; see the repository
|
||||
http://code.nsnam.org/mathieu/ns-3-simu for details}
|
||||
|
||||
The below is excerpted from Mathieu's post to ns-developers list
|
||||
on April 4, 2008.
|
||||
|
||||
"To summarize, the goal is that the full posix/socket API is defined in
|
||||
src/process/simu.h: each posix type and function is re-defined there
|
||||
with a simu_ or SIMU_ prefix to avoid ugly name clashes and collisions
|
||||
(feel free to come up with a better prefix).
|
||||
|
||||
Each process is created with a call to ProcessManager::Create and is
|
||||
attached to that ProcessManager instance. So, if the ProcessManager
|
||||
(which is aggregated to a Node in src/helper/process-helper.cc) is
|
||||
killed when the simulation ends, the system will automatically reclaim
|
||||
all the resources of each process associated to each manager. The same
|
||||
happens when an application "exits" from its main function.
|
||||
|
||||
The example application defines two posix "processes": the function
|
||||
ClientProgram creates a udp socket on the localhost port 2000 and the
|
||||
function ServerProgram creates a udp socket on the localhost port 2000.
|
||||
The code does not work right now because I did not get the details of
|
||||
simu_read right yet but, I do plan to make this work at some point.
|
||||
|
||||
I really think that this approach is worthwhile for many reasons, a few
|
||||
of which are outlined below:
|
||||
@itemize @bullet
|
||||
@item makes porting real world application code _much_ easier
|
||||
|
||||
@item makes write applications for new users much easier because they can
|
||||
read the bsd socket api reference and documentation and write code
|
||||
directly.
|
||||
|
||||
@item can be used to write applications which work in both simulation and
|
||||
in the real world at the same time. To do this, all you have to do is
|
||||
write your application to use the simu_ API, and, then, you can chose at
|
||||
compile-time which implementation of that API you want to use: you can
|
||||
pick one implementation which forwards all calls to the system BSD
|
||||
socket API or another one which forwards all calls to the attached
|
||||
ProcessManager. Arguably, I did not implement the version which forwards
|
||||
to system BSD sockets but, that should be pretty trivial.
|
||||
@end itemize
|
||||
|
||||
So, anyway, comments about the overall API would be welcome. Students
|
||||
interested in the gsoc project for real-world code integration should
|
||||
consider looking at this also."
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@node Statistics
|
||||
@chapter Statistics
|
||||
@anchor{chap:Statistics}
|
||||
|
||||
ns-3 does not presently have support for statistics (automatically generated
|
||||
statistical output). This is planned
|
||||
for development later in 2008. If you are interested in contributing,
|
||||
please see @uref{http://www.nsnam.org/wiki/index.php/Suggested_Projects,,our suggested projects page} or contact the ns-developers
|
||||
list.
|
||||
@@ -0,0 +1,82 @@
|
||||
@node Troubleshooting
|
||||
@chapter Troubleshooting
|
||||
|
||||
This chapter posts some information about possibly common errors in building
|
||||
or running ns-3 programs.
|
||||
|
||||
Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items.
|
||||
|
||||
@node Build errors
|
||||
@section Build errors
|
||||
|
||||
@node Run-time errors
|
||||
@section Run-time errors
|
||||
|
||||
Sometimes, errors can occur with a program after a successful build. These
|
||||
are run-time errors, and can commonly occur when memory is corrupted or
|
||||
pointer values are unexpectedly null.
|
||||
|
||||
Here is an example of what might occur:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11
|
||||
@end verbatim
|
||||
|
||||
The error message says that the program terminated unsuccessfully, but it is
|
||||
not clear from this information what might be wrong. To examine more
|
||||
closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s"
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh)
|
||||
Copyright 2004 Free Software Foundation, Inc.
|
||||
GDB is free software, covered by the GNU General Public License, and you are
|
||||
welcome to change it and/or distribute copies of it under certain conditions.
|
||||
Type "show copying" to see the conditions.
|
||||
There is absolutely no warranty for GDB. Type "show warranty" for details.
|
||||
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
|
||||
Reading symbols from shared object read from target memory...done.
|
||||
Loaded system supplied DSO at 0xf5c000
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0x0804aa12 in main (argc=1, argv=0xbfdfefa4)
|
||||
at ../examples/tcp-point-to-point.cc:136
|
||||
136 Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
(gdb) p localSocket
|
||||
$1 = {m_ptr = 0x3c5d65}
|
||||
(gdb) p socketFactory
|
||||
$2 = {m_ptr = 0x0}
|
||||
(gdb) quit
|
||||
The program is running. Exit anyway? (y or n) y
|
||||
@end verbatim
|
||||
|
||||
Note first the way the program was invoked-- pass the command to run as
|
||||
an argument to the command template "gdb %s".
|
||||
|
||||
This tells us that there was an attempt to dereference a null pointer
|
||||
socketFactory.
|
||||
|
||||
Let's look around line 136 of tcp-point-to-point, as gdb suggests:
|
||||
@verbatim
|
||||
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
@end verbatim
|
||||
|
||||
The culprit here is that the return value of GetObject is not being
|
||||
checked and may be null.
|
||||
|
||||
Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory
|
||||
checker} for more subtle errors. Again, you invoke the use of valgrind
|
||||
similarly:
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s"
|
||||
@end verbatim
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @anchor modules_anchor
|
||||
*
|
||||
* @defgroup simulator Simulator
|
||||
* The "simulator" module contains:
|
||||
* - a time management class to hold a time and convert between various time units: ns3::Time
|
||||
* - a scheduler base class used to implement new simulation event schedulers:
|
||||
* ns3::Scheduler and ns3::SchedulerFactory
|
||||
* - a simulator class used to create, schedule and cancel events: ns3::Simulator
|
||||
*
|
||||
* @defgroup core Core
|
||||
* \brief The "core" module contains:
|
||||
* - a Functor class: ns3::Callback
|
||||
* - an os-independent interface to get access to the elapsed wall clock time: ns3::SystemWallClockMs
|
||||
* - a class to register regression tests with the test manager: ns3::Test and ns3::TestManager
|
||||
* - debugging facilities: \ref logging, \ref assert
|
||||
* - \ref randomvariable
|
||||
* - a base class for objects which need to support per-instance "attributes" and
|
||||
* trace sources: ns3::ObjectBase
|
||||
* - a base class for objects which need to support reference counting
|
||||
* and dynamic object aggregation: ns3::Object
|
||||
* - a smart-pointer class ns3::Ptr designed to work together with ns3::Object
|
||||
* - a configuration class used to set and control all attributes and trace sources
|
||||
* in a simulation: ns3::Config.
|
||||
*
|
||||
* @defgroup common Common
|
||||
* The "common" module contains:
|
||||
* - a packet class to create and manipulate simulation packets:
|
||||
* ns3::Packet, ns3::Header, and ns3::Trailer. This packet class
|
||||
* also supports per-packet ns3::Tag which are globs of data
|
||||
* which can be attached to any packet.
|
||||
*
|
||||
* @defgroup node Node
|
||||
* The "node" module contains:
|
||||
* - a ns3::Node base class which should be subclassed by any new type of
|
||||
* network Node.
|
||||
* - models which abstract the MAC-layer from the IP layer protocols:
|
||||
* ns3::NetDevice and ns3::Channel.
|
||||
* - models which abstract the application-layer API: ns3::Application,
|
||||
* ns3::Socket, ns3::SocketFactory, and, ns3::Udp
|
||||
*
|
||||
*
|
||||
* @defgroup devices Devices
|
||||
*
|
||||
* @defgroup internetStack InternetStack
|
||||
*
|
||||
* The "internet-stack" module contains:
|
||||
* - an Ipv4 stack
|
||||
* - an ARP module
|
||||
* - a UDP and a TCP implementation
|
||||
*
|
||||
* @defgroup helper Helpers
|
||||
*
|
||||
* @defgroup applications Applications
|
||||
*
|
||||
* @defgroup mobility Mobility
|
||||
*
|
||||
* @defgroup routing Routing
|
||||
*
|
||||
* @defgroup constants Constants
|
||||
* @brief Constants you can change
|
||||
*
|
||||
* @defgroup contrib Contrib
|
||||
*/
|
||||
+1658
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
+71
-13
@@ -1,19 +1,77 @@
|
||||
Steps in doing an ns-3 release
|
||||
|
||||
1. prepare the source files
|
||||
1. check out a clean ns-3-dev somewhere
|
||||
2. prepare the source files
|
||||
- revise and check in AUTHORS, if needed
|
||||
- revise and check in RELEASE_NOTES
|
||||
- update and check in VERSION to the latest release number
|
||||
2. make a new "architecture.pdf" document and place it in the doc/ directory
|
||||
3. scons dist
|
||||
4. test tarball on release platforms (run-tests and simple-p2p)
|
||||
5. tag ns-3-dev with "release ns-3.0.X"
|
||||
6. clone the ns-3-dev and place it on the repository
|
||||
7. upload "ns-3.0.x.tar.gz" to the releases/ directory on the server
|
||||
8. update web page
|
||||
- DO NOT change VERSION at this time
|
||||
- confirm that Doxygen builds cleanly and without warnings
|
||||
(./waf check; ./waf --doxygen), and check in any necessary changes
|
||||
- ensure no regressions (./waf --regression)
|
||||
3. ./waf configure; ./waf dist
|
||||
- this will create an ns-3-dev.tar.bz2 tarball
|
||||
- this will also create a ns-3-dev-ref-traces.tar.bz2 tarball
|
||||
4. test dev tarball on release platforms (waf check and maybe some other
|
||||
scripts)
|
||||
5. once you are happy with the tarball, tag ns-3-dev and ns-3-dev-ref-traces
|
||||
- hg tag "release ns-3.1x"
|
||||
- hg push
|
||||
- cd into regression/ns-3-dev-ref-traces
|
||||
- hg tag "release ns-3.1x"
|
||||
- hg push
|
||||
6. clone the tagged ns-3-dev and place it on the repository
|
||||
- ssh code.nsnam.org; sudo tcsh; su code;
|
||||
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.1x
|
||||
- cd /home/code/repos/ns-3.1x/.hg and edit the hgrc appropriately:
|
||||
"description = ns-3.1x release
|
||||
name = ns-3.1x"
|
||||
- clone the ns-3-dev-ref-traces and place it on the repository as above
|
||||
but use the name ns-3.1x-ref-traces and edit the hgrc appropriately
|
||||
7. check out a clean version of the new release (ns-3.1x) somewhere
|
||||
8. Update the VERSION for this new release
|
||||
- change the string 3-dev in the VERSION file to the real version
|
||||
(e.g. 3.1) This must agree with the version name you chose in the clone
|
||||
for the regression tests to work.
|
||||
- hg commit
|
||||
- hg push
|
||||
9. Run the regression tests on the new release (debug and optimized)
|
||||
- ./waf -d debug configure
|
||||
- ./waf
|
||||
- ./waf --regression
|
||||
- ./waf --valgrind --regression (for valgrind version)
|
||||
- ./waf -d optimized configure
|
||||
- ./waf
|
||||
- ./waf --regression
|
||||
- ./waf --valgrind --regression (for valgrind version)
|
||||
- There should be no regression errors at this time
|
||||
10. Create final tarballs
|
||||
- ./waf configure; ./waf dist
|
||||
- this will create an ns-3.1x.tar.bz2 tarball
|
||||
- this will also create a ns-3.1x-ref-traces.tar.bz2 tarball
|
||||
11. upload "ns-3.1x.tar.bz2" to the /var/www/html/releases/ directory on
|
||||
the www.nsnam.org server
|
||||
- give it 644 file permissions, and user/group = apache
|
||||
12. upload "ns-3.1x-ref-traces.tar.bz2" to the /var/www/html/releases/
|
||||
directory on the www.nsnam.org server
|
||||
- give it 644 file permissions, and user/group = apache
|
||||
13. update web pages on www.nsnam.org (source is in the www/ module)
|
||||
- clone the source repo (hg clone http://code.nsnam.org/www)
|
||||
- add link to news.html
|
||||
- update download.html
|
||||
- update roadmap.html
|
||||
- update getting_started.html
|
||||
- update documents.html
|
||||
- update roadmap on wiki
|
||||
- commit and push changes
|
||||
- build and update HTML directory on the server
|
||||
-- ssh www.nsnam.org; sudo tcsh; su nsnam;
|
||||
-- run ~/bin/update-html
|
||||
- build and update Doxygen directory on the server
|
||||
- update and upload software architecture document (PDF, HTML)
|
||||
9. announce to ns-developers, with summary of release notes
|
||||
-- edit ~/bin/update-doxygen-release file and change RELEASE variable
|
||||
to the right version number
|
||||
-- run ~/bin/update-doxygen-release
|
||||
14. Final checks
|
||||
- download tarball from web, build and run regression tests for as many
|
||||
targets as you can
|
||||
- download release from mercurial, build and run regression tests for as
|
||||
many targets as you can
|
||||
- test and verify until you're confident the release is solid.
|
||||
15. announce to ns-developers, with summary of release notes
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
TEXI2HTML = texi2html
|
||||
TEXI2PDF = texi2dvi --pdf
|
||||
EPSTOPDF = epstopdf
|
||||
TGIF = tgif
|
||||
DIA = dia
|
||||
CONVERT = convert
|
||||
CSS = --css-include=tutorial.css
|
||||
SPLIT = --split section
|
||||
|
||||
DIA_SOURCES = pp.dia dumbbell.dia star.dia
|
||||
TGIF_SOURCES = helpers.obj
|
||||
|
||||
DIA_EPS = ${DIA_SOURCES:.dia=.eps}
|
||||
DIA_PNG = ${DIA_SOURCES:.dia=.png}
|
||||
DIA_PDF = ${DIA_SOURCES:.dia=.pdf}
|
||||
|
||||
TGIF_EPS = ${TGIF_SOURCES:.obj=.eps}
|
||||
TGIF_PNG = ${TGIF_SOURCES:.obj=.png}
|
||||
TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf}
|
||||
|
||||
all: images html split-html pdf
|
||||
|
||||
# Note: tgif requires a valid x display to convert from .obj to .png.
|
||||
# If running this makefile on a remote console, the X virtual frame
|
||||
# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake"
|
||||
# display
|
||||
images:
|
||||
cd figures/; $(DIA) -t png $(DIA_SOURCES)
|
||||
cd figures/; $(DIA) -t eps $(DIA_SOURCES)
|
||||
cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);)
|
||||
cd figures/; $(TGIF) -print -png $(TGIF_SOURCES)
|
||||
cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES)
|
||||
cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);)
|
||||
|
||||
html: images
|
||||
$(TEXI2HTML) ${CSS} tutorial.texi
|
||||
|
||||
split-html: images
|
||||
$(TEXI2HTML) ${CSS} ${SPLIT} tutorial.texi
|
||||
|
||||
pdf: images
|
||||
$(TEXI2PDF) tutorial.texi
|
||||
|
||||
figures-clean:
|
||||
cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF)
|
||||
cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF)
|
||||
|
||||
clean: figures-clean
|
||||
rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/
|
||||
@@ -0,0 +1,535 @@
|
||||
@node ns-3 Attributes
|
||||
@chapter ns-3 Attributes
|
||||
@anchor{chap:Attributes}
|
||||
|
||||
In ns-3 simulations, there are two main aspects to configuration:
|
||||
@itemize @bullet
|
||||
@item the simulation topology and how objects are connected
|
||||
@item the values used by the models instantiated in the topology
|
||||
@end itemize
|
||||
|
||||
This chapter focuses on the second item above: how the many values
|
||||
in use in ns-3 are organized, documented, and modifiable by ns-3 users.
|
||||
The ns-3 attribute system is also the underpinning of how traces
|
||||
and statistics are gathered in the simulator.
|
||||
|
||||
Before delving into details of the attribute value system,
|
||||
it will help to review some basic properties of @code{class ns3::Object}.
|
||||
|
||||
@node Object Overview
|
||||
@section Object Overview
|
||||
|
||||
ns-3 is fundamentally a C++ object-based system. By this we mean that
|
||||
new C++ classes (types) can be declared, defined, and subclassed
|
||||
as usual.
|
||||
|
||||
Many ns-3 objects inherit from the @code{ns3::Object} base class. These
|
||||
objects have some additional properties that we exploit for
|
||||
organizing the system and improving the memory management
|
||||
of our objects:
|
||||
|
||||
@itemize @bullet
|
||||
@item a "metadata" system that links the class name to a lot of
|
||||
meta-information about the object, including the base class of the subclass,
|
||||
the set of accessible constructors in the subclass, and the set of
|
||||
"attributes" of the subclass
|
||||
@item a reference counting smart pointer implementation, for memory
|
||||
management.
|
||||
@end itemize
|
||||
|
||||
ns-3 objects that use the attribute system derive from either
|
||||
@code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects
|
||||
we will discuss derive from @code{ns3::Object}, but a few that
|
||||
are outside the smart pointer memory management framework derive
|
||||
from @code{ns3::ObjectBase}.
|
||||
|
||||
Let's review a couple of properties of these objects.
|
||||
|
||||
@node Smart pointers
|
||||
@subsection Smart pointers
|
||||
|
||||
As introduced above in @ref{Smart Pointers 101}, ns-3 objects
|
||||
are memory managed by a
|
||||
@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}.
|
||||
|
||||
Smart pointers are used extensively in the ns-3 APIs, to avoid passing
|
||||
references to heap-allocated objects that may cause memory leaks.
|
||||
For most basic usage (syntax), treat a smart pointer like a regular pointer:
|
||||
@verbatim
|
||||
Ptr<WifiNetDevice> nd = ...;
|
||||
nd->CallSomeFunction ();
|
||||
// etc.
|
||||
@end verbatim
|
||||
|
||||
@node CreateObject
|
||||
@subsection CreateObject
|
||||
|
||||
As we discussed above in @ref{Object Creation},
|
||||
at the lowest-level API, objects of type @code{ns3::Object} are
|
||||
not instantiated using @code{operator new} as usual but instead by
|
||||
a templated function called @code{CreateObject()}.
|
||||
|
||||
A typical way to create such an object is as follows:
|
||||
@verbatim
|
||||
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
|
||||
@end verbatim
|
||||
|
||||
You can think of this as being functionally equivalent to:
|
||||
@verbatim
|
||||
WifiNetDevice* nd = new WifiNetDevice ();
|
||||
@end verbatim
|
||||
|
||||
Objects that derive from @code{ns3::Object} must be allocated
|
||||
on the heap using CreateObject(). Those deriving from
|
||||
@code{ns3::ObjectBase}, such as ns-3 helper functions and packet
|
||||
headers and trailers, can be allocated on the stack.
|
||||
|
||||
In some scripts, you may not see a lot of CreateObject() calls
|
||||
in the code;
|
||||
this is because there are some helper objects in effect that
|
||||
are doing the CreateObject()s for you.
|
||||
|
||||
@node TypeId
|
||||
@subsection TypeId
|
||||
|
||||
ns-3 classes that derive from class ns3::Object can include
|
||||
a metadata class called @code{TypeId} that records meta-information
|
||||
about the class, for use in the object aggregation and component
|
||||
manager systems:
|
||||
@itemize @bullet
|
||||
@item a unique string identifying the class
|
||||
@item the base class of the subclass, within the metadata system
|
||||
@item the set of accessible constructors in the subclass
|
||||
@end itemize
|
||||
|
||||
@node Object Summary
|
||||
@subsection Object Summary
|
||||
|
||||
Putting all of these concepts together, let's look at a specific
|
||||
example: @code{class ns3::Node}.
|
||||
|
||||
The public header file node.h has a declaration that includes
|
||||
a static GetTypeId function call:
|
||||
@verbatim
|
||||
class Node : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
This is defined in the node.cc file as follows:
|
||||
@verbatim
|
||||
TypeId
|
||||
Node::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::Node")
|
||||
.SetParent<Object> ()
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
Finally, when users want to create Nodes, they call:
|
||||
@verbatim
|
||||
Ptr<Node> n = CreateObject<Node> n;
|
||||
@end verbatim
|
||||
|
||||
We next discuss how attributes (values associated with member variables
|
||||
or functions of the class) are plumbed into the above TypeId.
|
||||
|
||||
@node Attribute Overview
|
||||
@section Attribute Overview
|
||||
|
||||
The goal of the attribute system is to organize the access of
|
||||
internal member objects of a simulation. This goal arises because,
|
||||
typically in simulation, users will cut and paste/modify existing
|
||||
simulation scripts, or will use higher-level simulation constructs,
|
||||
but often will be interested in studying or tracing particular
|
||||
internal variables. For instance, use cases such as:
|
||||
@itemize @bullet
|
||||
@item "I want to trace the packets on the wireless interface only on
|
||||
the first access point"
|
||||
@item "I want to trace the value of the TCP congestion window (every
|
||||
time it changes) on a particular TCP socket"
|
||||
@item "I want a dump of all values that were used in my simulation."
|
||||
@end itemize
|
||||
|
||||
Similarly, users may want fine-grained access to internal
|
||||
variables in the simulation, or may want to broadly change the
|
||||
initial value used for a particular parameter in all subsequently
|
||||
created objects. Finally, users may wish to know what variables
|
||||
are settable and retrievable in a simulation configuration. This
|
||||
is not just for direct simulation interaction on the command line;
|
||||
consider also a (future) graphical user interface
|
||||
that would like to be able to provide a feature whereby a user
|
||||
might right-click on an node on the canvas and see a hierarchical,
|
||||
organized list of parameters that are settable on the node and its
|
||||
constituent member objects, and help text and default values for
|
||||
each parameter.
|
||||
|
||||
@node Functional overview
|
||||
@subsection Functional overview
|
||||
|
||||
We provide a way for users to access values deep in the system, without
|
||||
having to plumb accessors (pointers) through the system and walk
|
||||
pointer chains to get to them. Consider a class DropTailQueue that
|
||||
has a member variable that is an unsigned integer @code{m_maxPackets};
|
||||
this member variable controls the depth of the queue.
|
||||
|
||||
If we look at the declaration of DropTailQueue, we see the following:
|
||||
@verbatim
|
||||
class DropTailQueue : public Queue {
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
...
|
||||
|
||||
private:
|
||||
std::queue<Ptr<Packet> > m_packets;
|
||||
uint32_t m_maxPackets;
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
Let's consider things that a user may want to do with the value of
|
||||
m_maxPackets:
|
||||
|
||||
@itemize @bullet
|
||||
@item Set a default value for the system, such that whenever a new
|
||||
DropTailQueue is created, this member is initialized to that default.
|
||||
@item Set or get the value on an already instantiated queue.
|
||||
@end itemize
|
||||
|
||||
The above things typically require providing Set() and Get() functions,
|
||||
and some type of global default value.
|
||||
|
||||
In the ns-3 attribute system, these value definitions and accessor
|
||||
functions are moved into the TypeId class; e.g.:
|
||||
@verbatim
|
||||
TypeId DropTailQueue::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::DropTailQueue")
|
||||
.SetParent<Queue> ()
|
||||
.AddConstructor<DropTailQueue> ()
|
||||
.AddAttribute ("MaxPackets", "The maximum number of packets accepted by this DropTailQueue.",
|
||||
Uinteger (100),
|
||||
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
;
|
||||
|
||||
return tid;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The AddAttribute() method is performing a number of things with this
|
||||
value:
|
||||
@itemize @bullet
|
||||
@item Binding the variable m_maxPackets to a string "MaxPackets"
|
||||
@item Providing a default value (100 packets)
|
||||
@item Providing some help text defining the value
|
||||
@item Providing a "checker" (not used in this example) that can be used to set
|
||||
bounds on the allowable range of values
|
||||
@end itemize
|
||||
|
||||
The key point is that now the value of this variable and its default
|
||||
value are accessible in the attribute namespace, which is based on
|
||||
strings such as "MaxPackets" and TypeId strings. In the next
|
||||
section, we will provide an example script that shows how users
|
||||
may manipulate these values.
|
||||
|
||||
@node Basic usage
|
||||
@subsection Basic usage
|
||||
|
||||
Let's look at how a user script might access these values.
|
||||
This is based on the script found at @code{samples/main-attribute-value.cc},
|
||||
with some details stripped out.
|
||||
@verbatim
|
||||
//
|
||||
// This is a basic example of how to use the attribute system to
|
||||
// set and get a value in the underlying system; namely, an unsigned
|
||||
// integer of the maximum number of packets in a queue
|
||||
//
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// By default, the MaxPackets attribute has a value of 100 packets
|
||||
// (this default can be observed in the function DropTailQueue::GetTypeId)
|
||||
//
|
||||
// Here, we set it to 80 packets. We could use one of two value types:
|
||||
// a string-based value or a Uinteger value
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", String ("80"));
|
||||
// The below function call is redundant
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", Uinteger(80));
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// SetDefaults() at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
@end verbatim
|
||||
|
||||
The main thing to notice in the above are the two calls to
|
||||
@code{Config::SetDefault}. This is how we set the default value
|
||||
for all subsequently instantiated DropTailQueues. We illustrate
|
||||
that two types of Value classes, a String and a Uinteger class,
|
||||
can be used to assign the value to the attribute named by
|
||||
"ns3::DropTailQueue::MaxPackets".
|
||||
|
||||
Now, we will create a few objects using the low-level API; here,
|
||||
our newly created queues will not have a m_maxPackets initialized to
|
||||
100 packets but to 80 packets, because of what we did above with
|
||||
default values.
|
||||
@verbatim
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
|
||||
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
|
||||
n0->AddDevice (net0);
|
||||
|
||||
Ptr<Queue> q = CreateObject<DropTailQueue> ();
|
||||
net0->AddQueue(q);
|
||||
@end verbatim
|
||||
|
||||
At this point, we have created a single node (Node 0) and a
|
||||
single PointToPointNetDevice (NetDevice 0) and added a
|
||||
DropTailQueue to it.
|
||||
|
||||
Now, we can manipulate the MaxPackets value of the already
|
||||
instantiated DropTailQueue. Here are various ways to do that.
|
||||
|
||||
@subsubsection Pointer-based access
|
||||
|
||||
We assume that a smart pointer (Ptr) to a relevant network device is
|
||||
in hand; here, it is the net0 pointer.
|
||||
|
||||
One way to change the value is to access a pointer to the
|
||||
underlying queue and modify its attribute.
|
||||
|
||||
First, we observe that we can get a pointer to the (base class)
|
||||
queue via the PointToPointNetDevice attributes, where it is called
|
||||
TxQueue
|
||||
@verbatim
|
||||
Ptr<Queue> txQueue = net0->GetAttribute ("TxQueue");
|
||||
@end verbatim
|
||||
|
||||
Using the GetObject function, we can perform a safe downcast
|
||||
to a DropTailQueue, where MaxPackets is a member
|
||||
@verbatim
|
||||
Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
|
||||
NS_ASSERT (dtq);
|
||||
@end verbatim
|
||||
|
||||
Next, we can get the value of an attribute on this queue
|
||||
We have introduced wrapper "Value" classes for the underlying
|
||||
data types, similar to Java wrappers around these types, since
|
||||
the attribute system stores values and not disparate types.
|
||||
Here, the attribute value is assigned to a Uinteger, and
|
||||
the Get() method on this value produces the (unwrapped) uint32_t.
|
||||
@verbatim
|
||||
Uinteger limit = dtq->GetAttribute ("MaxPackets");
|
||||
NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
Note that the above downcast is not really needed; we could have
|
||||
done the same using the Ptr<Queue> even though the attribute
|
||||
is a member of the subclass
|
||||
@verbatim
|
||||
limit = txQueue->GetAttribute ("MaxPackets");
|
||||
NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
Now, let's set it to another value (60 packets)
|
||||
@verbatim
|
||||
txQueue->SetAttribute("MaxPackets", Uinteger (60));
|
||||
limit = txQueue->GetAttribute ("MaxPackets");
|
||||
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
@subsubsection Namespace-based access
|
||||
|
||||
An alternative way to get at the attribute is to use the configuration
|
||||
namespace. Here, this attribute resides on a known path in this
|
||||
namespace; this approach is useful if one doesn't have access to
|
||||
the underlying pointers and would like to configure a specific
|
||||
attribute with a single statement.
|
||||
@verbatim
|
||||
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", Uinteger (25));
|
||||
limit = txQueue->GetAttribute ("MaxPackets");
|
||||
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
We could have also used wildcards to set this value for all nodes
|
||||
and all net devices (which in this simple example has the same
|
||||
effect as the previous Set())
|
||||
@verbatim
|
||||
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", Uinteger (15));
|
||||
limit = txQueue->GetAttribute ("MaxPackets");
|
||||
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
@end verbatim
|
||||
|
||||
@node Setting through constructors and helper classes
|
||||
@subsection Setting through constructors helper classes
|
||||
|
||||
Arbitrary combinations of attributes can be set and fetched from
|
||||
the helper and low-level APIs; either from the constructors themselves:
|
||||
@verbatim
|
||||
Ptr<Object> p = CreateObject<MyNewObject> ("n1", v1, "n2", v2, ...);
|
||||
@end verbatim
|
||||
or from the higher-level helper APIs, such as:
|
||||
@verbatim
|
||||
mobility.SetPositionAllocator ("GridPositionAllocator",
|
||||
"MinX", FpValue (-100.0),
|
||||
"MinY", FpValue (-100.0),
|
||||
"DeltaX", FpValue (5.0),
|
||||
"DeltaY", FpValue (20.0),
|
||||
"GridWidth", UintValue (20),
|
||||
"LayoutType", "RowFirst");
|
||||
@end verbatim
|
||||
|
||||
@node Value classes
|
||||
@subsection Value classes
|
||||
Readers will note the new Value classes. These can be thought of as
|
||||
an intermediate class that can be used to convert from raw types to the
|
||||
Values that are used by the system. Recall that this database is holding
|
||||
objects of many types with a single generic type. Conversions to this
|
||||
type can either be done using an intermediate class (IntValue, FpValue for
|
||||
"floating point") or via strings. Direct implicit conversion of types
|
||||
to Value is not really practical. So in the above, users have a choice
|
||||
of using strings or values:
|
||||
@verbatim
|
||||
p->Set ("cwnd", "100"); // string-based setter
|
||||
p->Set ("cwnd", IntValue(100)); // value-based setter
|
||||
@end verbatim
|
||||
|
||||
The system provides some macros that help users declare and define
|
||||
new Value subclasses for new types that they want to introduce into
|
||||
the attribute system.
|
||||
|
||||
@node Extending attributes
|
||||
@section Extending attributes
|
||||
|
||||
The ns-3 system will place a number of internal values under the
|
||||
attribute system, but undoubtedly users will want to extend this
|
||||
to pick up ones we have missed, or to add their own classes to this.
|
||||
|
||||
@subsection Adding an existing internal variable to the metadata system
|
||||
|
||||
// XXX revise me
|
||||
|
||||
Consider this variable in class TcpSocket:
|
||||
@verbatim
|
||||
uint32_t m_cWnd; // Congestion window
|
||||
@end verbatim
|
||||
|
||||
Suppose that someone working with Tcp wanted to get or set the
|
||||
value of that variable using the metadata system. If it were not
|
||||
already provided by ns-3, the user could declare the following addition
|
||||
in the metadata system (to the TypeId declaration for TcpSocket):
|
||||
@verbatim
|
||||
.AddParameter ("Congestion window",
|
||||
"Tcp congestion window (bytes)",
|
||||
MakeUIntParamSpec (&TcpSocket::m_cWnd, 1));
|
||||
|
||||
@end verbatim
|
||||
|
||||
Now, the user with a pointer to the TcpSocket can perform operations
|
||||
such as setting and getting the value, without having to add these
|
||||
functions explicitly. Furthermore, access controls can be applied, such
|
||||
as allowing the parameter to be read and not written, or bounds
|
||||
checking on the permissible values can be applied.
|
||||
|
||||
@subsection Adding a new TypeId
|
||||
|
||||
Here, we discuss the impact on a user who wants to add a new class to
|
||||
ns-3; what additional things must be done to hook it into this system.
|
||||
|
||||
We've already introduced what a TypeId definition looks like:
|
||||
@verbatim
|
||||
TypeId
|
||||
RandomWalk2dMobilityModel::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("RandomWalkMobilityModel")
|
||||
.SetParent<MobilityModel> ()
|
||||
.SetGroupName ("Mobility")
|
||||
.AddConstructor<RandomWalk2dMobilityModel> ()
|
||||
// followed by a number of Parameters
|
||||
.AddParameter ("bounds",
|
||||
"Bounds of the area to cruise.",
|
||||
MakeRectangleParamSpec (&RandomWalk2dMobilityModel::m_bounds, Rectangle (0.0, 0.0, 100.0, 100.0)))
|
||||
.AddParameter ("time",
|
||||
"Change current direction and speed after moving for this delay.",
|
||||
MakeTimeParamSpec (&RandomWalk2dMobilityModel::m_modeTime,
|
||||
Seconds (1.0)))
|
||||
|
||||
// etc (more parameters).
|
||||
@end verbatim
|
||||
|
||||
The declaration for this in the class declaration is one-line public
|
||||
member method:
|
||||
@verbatim
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
@end verbatim
|
||||
|
||||
@section Adding new class type to the Value system
|
||||
|
||||
From the perspective of the user who writes a new class in the system and
|
||||
wants to hook it in to the attribute system, there is mainly the matter
|
||||
of writing
|
||||
the conversions to/from strings and Values. Most of this can be
|
||||
copy/pasted with macro-ized code. For instance, consider class
|
||||
Rectangle in the @code{src/mobility/} directory:
|
||||
|
||||
One line is added to the class declaration:
|
||||
@verbatim
|
||||
/**
|
||||
* \brief a 2d rectangle
|
||||
*/
|
||||
class Rectangle
|
||||
{
|
||||
...
|
||||
|
||||
VALUE_HELPER_HEADER_1 (Rectangle);
|
||||
};
|
||||
@end verbatim
|
||||
|
||||
One templatized declaration, and two operators, are added below the
|
||||
class declaration:
|
||||
|
||||
@verbatim
|
||||
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
|
||||
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
|
||||
|
||||
VALUE_HELPER_HEADER_2 (Rectangle);
|
||||
@end verbatim
|
||||
|
||||
In the class definition, the code looks like this:
|
||||
|
||||
@verbatim
|
||||
VALUE_HELPER_CPP (Rectangle);
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream &os, const Rectangle &rectangle)
|
||||
{
|
||||
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax;
|
||||
return os;
|
||||
}
|
||||
std::istream &
|
||||
operator >> (std::istream &is, Rectangle &rectangle)
|
||||
{
|
||||
char c1, c2, c3;
|
||||
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax;
|
||||
if (c1 != '|' ||
|
||||
c2 != '|' ||
|
||||
c3 != '|')
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
These stream operators simply convert from a string representation of the
|
||||
Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the
|
||||
modeler must specify these operators and the string syntactical representation
|
||||
of an instance of the new class.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Please write image files in a vector graphics format, when possible, and
|
||||
generate the .png and .pdf versions on the fly (see ../Makefile).
|
||||
|
||||
Currently supported tools are dia and tgif. xfig could be added similarly
|
||||
if someone wants to add it. The main requirement for adding another format
|
||||
is that the tool to edit it is freely available and that a cron script can
|
||||
autogenerate the pdf and png from the figure source.
|
||||
|
||||
Store the .dia, or .obj versions in mercurial, but not the .png or .pdfs.
|
||||
If the figure is not available in a vector graphics format, store both
|
||||
a .png and a .pdf version in this directory.
|
||||
|
||||
If you add a source (.dia, .obj) file here, remember to add it to
|
||||
the list of figure sources in the Makefile in the directory above
|
||||
|
||||
Note: tgif can convert from .obj to .pdf, but the pdf that results takes
|
||||
up a whole page. Instead, we convert to an intermediate .eps step, and
|
||||
then run epstopdf.
|
||||
Binary file not shown.
@@ -0,0 +1,115 @@
|
||||
%TGIF 4.1.43-QPL
|
||||
state(0,37,100.000,0,0,0,32,1,9,1,1,0,0,1,2,1,0,'Courier',0,80640,0,2,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,2880,0).
|
||||
%
|
||||
% @(#)$Header$
|
||||
% %W%
|
||||
%
|
||||
unit("1 pixel/pixel").
|
||||
color_info(11,65535,0,[
|
||||
"magenta", 65535, 0, 65535, 65535, 0, 65535, 1,
|
||||
"red", 65535, 0, 0, 65535, 0, 0, 1,
|
||||
"green", 0, 65535, 0, 0, 65535, 0, 1,
|
||||
"blue", 0, 0, 65535, 0, 0, 65535, 1,
|
||||
"yellow", 65535, 65535, 0, 65535, 65535, 0, 1,
|
||||
"pink", 65535, 49344, 52171, 65535, 49344, 52171, 1,
|
||||
"cyan", 0, 65535, 65535, 0, 65535, 65535, 1,
|
||||
"CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1,
|
||||
"white", 65535, 65535, 65535, 65535, 65535, 65535, 1,
|
||||
"black", 0, 0, 0, 0, 0, 0, 1,
|
||||
"DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1
|
||||
]).
|
||||
script_frac("0.6").
|
||||
fg_bg_colors('black','white').
|
||||
dont_reencode("FFDingbests:ZapfDingbats").
|
||||
page(1,"",1,'').
|
||||
text('black',272,195,2,0,1,248,36,0,13,5,0,0,0,0,2,248,36,0,0,"",0,0,0,0,208,'',[
|
||||
minilines(248,36,0,0,0,0,0,[
|
||||
mini_line(200,13,5,0,0,0,[
|
||||
str_block(0,200,13,5,0,-8,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,200,13,5,0,-8,0,0,0,0,0,
|
||||
"low-level APIs (all src/ ")])
|
||||
]),
|
||||
mini_line(248,13,5,0,0,0,[
|
||||
str_block(0,248,13,5,0,-2,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,248,13,5,0,-2,0,0,0,0,0,
|
||||
"directories except src/helper/)")])
|
||||
])
|
||||
])]).
|
||||
rcbox('black','',96,240,384,288,5,1,1,0,16,2,0,0,0,0,'1',0,[
|
||||
]).
|
||||
text('black',192,259,1,0,1,112,18,3,13,5,2,0,0,0,2,112,18,0,0,"",0,0,0,0,272,'',[
|
||||
minilines(112,18,0,0,0,0,0,[
|
||||
mini_line(112,13,5,0,0,0,[
|
||||
str_block(0,112,13,5,0,0,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,112,13,5,0,0,0,0,0,0,0,
|
||||
"ns-3 simulator")])
|
||||
])
|
||||
])]).
|
||||
poly('black','',2,[
|
||||
272,208,240,240],0,1,1,17,0,0,2,0,0,0,0,'1',0,0,
|
||||
"0","",[
|
||||
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
|
||||
]).
|
||||
poly('black','',2,[
|
||||
240,176,240,240],1,1,1,18,0,0,0,0,0,0,0,'1',0,0,
|
||||
"0","",[
|
||||
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
|
||||
]).
|
||||
rcbox('black','',176,128,384,176,5,1,1,0,16,25,0,0,0,0,'1',0,[
|
||||
]).
|
||||
text('black',192,131,2,0,1,120,36,26,13,5,2,0,0,0,2,120,36,0,0,"",0,0,0,0,144,'',[
|
||||
minilines(120,36,0,0,0,0,0,[
|
||||
mini_line(120,13,5,0,0,0,[
|
||||
str_block(0,120,13,5,0,-1,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,120,13,5,0,-1,0,0,0,0,0,
|
||||
"ns-3 helper API")])
|
||||
]),
|
||||
mini_line(96,13,5,0,0,0,[
|
||||
str_block(0,96,13,5,0,-2,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,96,13,5,0,-2,0,0,0,0,0,
|
||||
"(src/helper)")])
|
||||
])
|
||||
])]).
|
||||
rcbox('black','',96,16,384,64,0,1,1,0,16,32,0,0,0,0,'1',0,[
|
||||
]).
|
||||
poly('black','',2,[
|
||||
240,64,240,128],1,1,1,36,0,0,0,0,0,0,0,'1',0,0,
|
||||
"0","",[
|
||||
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
|
||||
]).
|
||||
text('black',272,83,2,0,1,200,36,40,13,5,0,0,0,0,2,200,36,0,0,"",0,0,0,0,96,'',[
|
||||
minilines(200,36,0,0,0,0,0,[
|
||||
mini_line(200,13,5,0,0,0,[
|
||||
str_block(0,200,13,5,0,-2,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,200,13,5,0,-2,0,0,0,0,0,
|
||||
"helper APIs (src/helper/)")])
|
||||
]),
|
||||
mini_line(192,13,5,0,0,0,[
|
||||
str_block(0,192,13,5,0,-1,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,192,13,5,0,-1,0,0,0,0,0,
|
||||
"call into low-level APIs")])
|
||||
])
|
||||
])]).
|
||||
poly('black','',2,[
|
||||
272,96,240,128],0,1,1,41,0,0,2,0,0,0,0,'1',0,0,
|
||||
"0","",[
|
||||
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
|
||||
]).
|
||||
text('black',128,19,2,0,1,232,36,47,13,5,0,0,0,0,2,232,36,0,0,"",0,0,0,0,32,'',[
|
||||
minilines(232,36,0,0,0,0,0,[
|
||||
mini_line(224,13,5,0,0,0,[
|
||||
str_block(0,224,13,5,0,-2,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,224,13,5,0,-2,0,0,0,0,0,
|
||||
"ns-3 scripts (main programs)")])
|
||||
]),
|
||||
mini_line(232,13,5,0,0,0,[
|
||||
str_block(0,232,13,5,0,-1,0,0,0,[
|
||||
str_seg('black','Courier',0,80640,232,13,5,0,-1,0,0,0,0,0,
|
||||
"- may use either or both APIs")])
|
||||
])
|
||||
])]).
|
||||
poly('black','',2,[
|
||||
144,64,144,240],1,1,1,50,0,0,0,0,0,0,0,'1',0,0,
|
||||
"0","",[
|
||||
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
|
||||
]).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,20 @@
|
||||
@node Helper Functions
|
||||
@chapter Helper Functions
|
||||
@anchor{chap:Helpers}
|
||||
This chapter describes an intermediate API for the simulator; what we
|
||||
call the "helper API". The helper API is implemented in
|
||||
@code{src/helper/} directory; it depends on (and wraps) the low-level
|
||||
API which is implemented everywhere else in @code{src/}. The following
|
||||
figure shows this relationship.
|
||||
@center @image{figures/helpers,,,,png}
|
||||
|
||||
The use of the helper API is optional. It has two main goals:
|
||||
@itemize @bullet
|
||||
@item Provide "syntactic sugar" to wrap a number of related low-level
|
||||
API calls together, that would normally be grouped together often, into
|
||||
something that is more user-friendly.
|
||||
@item Handle configuration of larger topological units (e.g., a set
|
||||
of nodes or a set of nodes on a particular link) .
|
||||
@end itemize
|
||||
|
||||
(more to follow)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
@node Logging
|
||||
@chapter Logging
|
||||
@anchor{chap:Logging}
|
||||
|
||||
This chapter is the first in a series of chapters discussing things that
|
||||
one can do to modify the input or output of existing ns-3 scripts.
|
||||
|
||||
Examples:
|
||||
@itemize @bullet
|
||||
@item Enable or disable the generation of log messages, with fine granularity
|
||||
@item Set default values for configuration values in the system
|
||||
@item Generate a report of all configuration values used during a simulation
|
||||
run (not yet implemented)
|
||||
@item Set or get values of member variables on objects already instantiated
|
||||
@item Customizing the tracing output of the script
|
||||
@item Generate statistics on (not yet implemented)
|
||||
@item Perform a large number of independent runs of the same simulation
|
||||
@end itemize
|
||||
|
||||
@node Logging Basics
|
||||
@section Logging Basics
|
||||
|
||||
@node Enabling Log Output
|
||||
@section Enabling Log Output
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,462 @@
|
||||
|
||||
@c ========================================================================
|
||||
@c Simulation Output
|
||||
@c ========================================================================
|
||||
|
||||
@node Simulation Output
|
||||
@chapter Simulation Output
|
||||
|
||||
At this point, you should be able to execute any of the built-in
|
||||
programs distributed with @command{ns-3}. Next, we will look at
|
||||
how to generate and tailor the simulation output, before turning
|
||||
to how to modify simulation scripts to do different things.
|
||||
|
||||
@node Tracing Basics
|
||||
@section Tracing Basics
|
||||
|
||||
The whole point of simulation is to generate output for further
|
||||
study, and the @command{ns-3} tracing system is a primary
|
||||
mechanism for this.
|
||||
Since @command{ns-3} is a C++ program, standard facilities for
|
||||
generating output from C++ programs apply:
|
||||
|
||||
@verbatim
|
||||
#include <iostream>
|
||||
...
|
||||
int main ()
|
||||
{
|
||||
...
|
||||
std::cout << "The value of x is " << x << std::endl;
|
||||
...
|
||||
}
|
||||
@end verbatim
|
||||
|
||||
The goal of the @command{ns-3} tracing system is to
|
||||
provide a structured way to configure the simulator to output results
|
||||
in standard or modifiable formats.
|
||||
@itemize @bullet
|
||||
@item For basic tasks, the tracing system should allow the user to
|
||||
generate standard tracing for popular tracing sources, and to customize
|
||||
which objects generate the tracing.
|
||||
@item Intermediate users will be able to extend the tracing system to
|
||||
modify the output format generated, or to insert new tracing sources,
|
||||
without modifying the core of the simulator.
|
||||
@item Advanced users can modify the simulator core to add new
|
||||
tracing sources and sinks.
|
||||
@end itemize
|
||||
|
||||
The @command{ns-3} tracing system is fundamentally built on the
|
||||
concept of separating tracing sources from sinks.
|
||||
@enumerate
|
||||
@item Trace sources (e.g., provide access to every packet received)
|
||||
@item Trace sinks (e.g., print out the packet)
|
||||
@item A mechanism to tie together sources and sinks
|
||||
@end enumerate
|
||||
The rationale for this division is to allow users to attach new
|
||||
types of sinks to existing tracing sources, without requiring
|
||||
users to edit and recompile the core of the simulator.
|
||||
Thus, in the example above, a user could write a new tracing sink
|
||||
and attach it to an existing tracing source. What remains to
|
||||
be defined is a way for users to find these hooks (tracing sources)
|
||||
and attach sinks to them. A new tracing namespace is defined for
|
||||
this purpose.
|
||||
|
||||
We will first walk through how some pre-defined sources and sinks
|
||||
are provided and may be customized with little user effort. We
|
||||
return later in this chapter to advanced tracing configuration including
|
||||
extending the tracing namespace and creating new tracing sources.
|
||||
|
||||
@subsection ASCII tracing
|
||||
@cindex ASCII
|
||||
For Internet nodes, the ASCII trace wrapper is a wrapper around
|
||||
the @command{ns-3} low-level
|
||||
tracing system that lets you get access to underlying trace events easily.
|
||||
The output of a trace of a simulation run is an ASCII file --- thus the name.
|
||||
In the spririt of keeping things simple, you won't be able to control or
|
||||
configure the output at this stage.
|
||||
|
||||
For those familiar with @command{ns-2} output, this type of trace is
|
||||
analogous to the @command{out.tr} generated by many scripts.
|
||||
|
||||
@cindex tracing packets
|
||||
Let's just jump right in. As usual, we need to include the definitions
|
||||
related to using ASCII tracing (don't edit any files quite yet):
|
||||
|
||||
@verbatim
|
||||
#include "ns3/ascii-trace.h"
|
||||
@end verbatim
|
||||
|
||||
We then need to add the code to the script to actually enable the ASCII tracing
|
||||
code. The following code must be inserted before the call to
|
||||
@code{Simulator::Run ();}:
|
||||
|
||||
@verbatim
|
||||
AsciiTrace asciitrace ("tutorial.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
@end verbatim
|
||||
|
||||
The first line declares an object of type @code{AsciiTrace} named
|
||||
@code{asciitrace} and passes a string parameter to its constructor. This
|
||||
parameter is a file name to which all of the trace information will be written.
|
||||
The second line, @code{asciitrace.TraceAllQueues ();} asks the trace object to
|
||||
arrange that all queue operations (enqueue, dequeue, drop) on the queues
|
||||
in all of the nodes of the system be traced. On the receive side,
|
||||
@code{asciitrace.TraceAlllNetDeviceRx ()} traces packets received by
|
||||
a NetDevice. For those familiar with @command{ns-2}, these are equivalent
|
||||
to the popular trace points that log "+", "-", "d", and "r" events.
|
||||
|
||||
Try running the following program from the command line:
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-ascii-trace
|
||||
@end verbatim
|
||||
|
||||
@cindex tutorial.tr
|
||||
Just as you have seen previously, you will see some messages from @emph{Waf}
|
||||
and then the ``Compilation finished successfully'' message. The
|
||||
next message, @code{UDP Echo Simulation} is from the running program. When
|
||||
it ran, the program will have created a file named @code{tutorial.tr}.
|
||||
Because of the way that Waf works, the file is not created in the local
|
||||
directory, it is created at the top-level directory of the repository. So,
|
||||
change into the top level directory and take a look at the file
|
||||
@code{tutorial.tr} in your favorite editor.
|
||||
|
||||
@subsubsection Parsing Ascii Traces
|
||||
@cindex parsing ascii traces
|
||||
|
||||
This section parses in detail the structure of the ascii tracing
|
||||
output. If you find this output format self explanatory (it
|
||||
resembles tcpdump output), you may skip to the next
|
||||
section on pcap tracing.
|
||||
|
||||
@cindex trace event
|
||||
There's a lot of information there in a pretty dense form, but the first thing
|
||||
to notice is that there are a number of distinct lines in this file. It may
|
||||
be difficult to see this clearly unless you widen your windows considerably.
|
||||
Each line in the file corresponds to a @emph{trace event}. A trace event
|
||||
happens whenever specific conditions happen in the simulation. In this case
|
||||
we are tracing events on the @emph{device queue} present in every net device
|
||||
on every node in the simulation. The device queue is a queue through which
|
||||
every packet destined for a channel must pass --- it is the device
|
||||
@emph{transmit} queue. Note that each line in the trace file begins with a
|
||||
lone character (has a space after it). This character will have the following
|
||||
meaning:
|
||||
|
||||
@cindex enqueue
|
||||
@cindex dequeue
|
||||
@cindex drop
|
||||
@itemize @bullet
|
||||
@item @code{+}: An enqueue operation occurred on the device queue;
|
||||
@item @code{-}: A dequeue operation occurred on the device queue;
|
||||
@item @code{d}: A packet was dropped, typically because the queue was full.
|
||||
@end itemize
|
||||
|
||||
Let's take a more detailed view of the first line. I'll break it down into
|
||||
sections (indented for clarity) with a two digit reference number on the
|
||||
left side:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=9
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=ff:ff:ff:ff:ff:ff
|
||||
10 ARP(request
|
||||
11 source mac: 08:00:2e:00:00:00
|
||||
12 source ipv4: 10.1.1.1
|
||||
13 dest ipv4: 10.1.1.2)
|
||||
14 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex trace event
|
||||
@cindex simulation time
|
||||
The first line of this expanded trace event (reference number 00) is the
|
||||
queue operation. We have a @code{+} character, so this corresponds to an
|
||||
@emph{enqueue} operation. The second line (reference 01) is the simulation
|
||||
time expressed in seconds. You may recall that we asked the
|
||||
@code{UdpEchoClient} to start sending packets at two seconds. Here we see
|
||||
confirmation that this is, indeed, happening.
|
||||
|
||||
@cindex node number
|
||||
@cindex net device number
|
||||
@cindex smart pointer
|
||||
The next lines of the example listing (references 02 and 03) tell us that
|
||||
this trace event originated in a given node and net device. Each time a node
|
||||
is created it is given an identifying number that monotonically increases from
|
||||
zero. Therefore, @code{nodeid=0} means that the node in which the given trace
|
||||
event originated is the first node we created. In the case of our script,
|
||||
this first node is is the node pointed to by the smart pointer @code{n0}. Not
|
||||
too surpsisingly, this is also the node to which we attached the
|
||||
@code{UdpEchoClient}. The device number is local to each node, and so the
|
||||
device given by @code{device=0} is the first net device that we added to the
|
||||
node in question. In our simulation, this corresponds to the
|
||||
@code{CsmaNetDevice} we added to node zero (@code{n0}).
|
||||
|
||||
@cindex uid
|
||||
@cindex unique ID
|
||||
@cindex packet
|
||||
The next line (reference 04) is a more readable form of the operation code
|
||||
seen in the first line --- i.e., the character @code{+} means
|
||||
@code{queue-enqueue}. Reference number 05 indicates that the @emph{unique id}
|
||||
of the packet being enqueued is @code{9}. The fact that the first packet we
|
||||
see has a unique ID of 9 should indicates to you that other things have
|
||||
happened in the protocol stack before we got to this point. This will become
|
||||
clear momentarily.
|
||||
|
||||
@cindex Ethernet
|
||||
@cindex MAC address
|
||||
Reference items 06 and 14 indicate that this is an Ethernet packet with
|
||||
a zero (not computed) checksum (note the indentation to make parsing this
|
||||
trace event a little easier). Reference 08 and 09 are the source and
|
||||
destination addresses of this packet. The packet is from the MAC address we
|
||||
assigned to the node zero net device in the script, and is destined for the
|
||||
broadcast address --- this is a broadcast packet.
|
||||
|
||||
@cindex Address Resolution Protocol
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
Reference items 10 through 13 make clear what is happening. This is an ARP
|
||||
(Address Resolution Protocol) request for the MAC address of the node on
|
||||
which the @code{UdpEchoServer} resides. The protocol stack can't send a UDP
|
||||
packet to be echoed until it knows (resolves) the MAC address; and this trace
|
||||
event corresponds to an ARP request being queued for transmission to the local
|
||||
network. The next line in the trace file (partially expanded),
|
||||
|
||||
@verbatim
|
||||
00 -
|
||||
01 2
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-dequeue
|
||||
05 pkt-uid=9
|
||||
...
|
||||
@end verbatim
|
||||
|
||||
shows the (same) ARP request packet being dequeued from the device queue by
|
||||
the net device and (implicitly) being sent down the channel to the broadcast
|
||||
MAC address. We are not tracing net device reception events so we don't
|
||||
actually see all of the net devices receiving the broadcast packet. We do,
|
||||
however see the following in the third line of the trace file:
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00207
|
||||
02 nodeid=1
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=10
|
||||
06 ETHERNET
|
||||
07 length/type=0x806,
|
||||
08 source=08:00:2e:00:00:01,
|
||||
09 destination=08:00:2e:00:00:00,
|
||||
10 ARP(reply
|
||||
11 source mac: 08:00:2e:00:00:01
|
||||
12 source ipv4: 10.1.1.2
|
||||
13 dest mac: 08:00:2e:00:00:00
|
||||
14 dest ipv4: 10.1.1.1)
|
||||
15 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex ARP|response
|
||||
Notice that this is a queue-enqueue operation (references 00 and 04) happening
|
||||
on node one (reference 02) at simulation time 2.00207 seconds (reference 01).
|
||||
Looking at the packet payload (references 10-14) we see that this is an ARP
|
||||
reply to the request sent by node one. Note that the simulation time
|
||||
(reference 01) is now 2.00207 seconds. This is direct result of the data rate
|
||||
(5 mb/s) and latency (2 ms) parameters that we passed to the
|
||||
@code{CsmaChannel} when we created it. Clearly the ARP request packet was
|
||||
sent over the channel and received approximately 2 ms later by node one. A
|
||||
corresponding ARP response packet was created and enqueued on node one's net
|
||||
device. It is this enqueue trace event that has being logged.
|
||||
|
||||
@cindex queue
|
||||
@cindex queue|transmit
|
||||
@cindex echo
|
||||
Given the current state of affairs, the next thing you may expect to see is
|
||||
this ARP request being received by node zero, but remember we are only looking
|
||||
at trace events on the device @emph{transmit} queue. The reception of the ARP
|
||||
response by node zero will not directly trigger any trace event in this case,
|
||||
but it will enable the protocol stack to continue what it was originally doing
|
||||
(trying to send an echo packet). Thus, the next line we see in the trace file
|
||||
(@code{tutorial.tr}) is the first UDP echo packet being sent to the net device.
|
||||
|
||||
@verbatim
|
||||
00 +
|
||||
01 2.00415
|
||||
02 nodeid=0
|
||||
03 device=0
|
||||
04 queue-enqueue
|
||||
05 pkt-uid=7
|
||||
06 ETHERNET
|
||||
07 length/type=0x800,
|
||||
08 source=08:00:2e:00:00:00,
|
||||
09 destination=08:00:2e:00:00:01
|
||||
10 IPV4(
|
||||
11 tos 0x0
|
||||
12 ttl 64
|
||||
13 id 0
|
||||
14 offset 0
|
||||
15 flags [none]
|
||||
16 length: 1052) 10.1.1.1 > 10.1.1.2
|
||||
17 UDP(length: 1032)
|
||||
18 49153 > 7
|
||||
19 DATA (length 1024)
|
||||
20 ETHERNET fcs=0
|
||||
@end verbatim
|
||||
|
||||
@cindex simulation time
|
||||
@cindex echo
|
||||
@cindex ARP
|
||||
@cindex ARP|request
|
||||
@cindex ARP|response
|
||||
@cindex IP
|
||||
@cindex Ipv4
|
||||
I won't go into too much detail about this packet, but I will point out a
|
||||
few key items in the trace. First, the packet was enqueued at simulation time
|
||||
of 2.00415 seconds. This time reflects the fact that the echo client
|
||||
application started at 2. seconds and there were two ARP packets transmitted
|
||||
across the network (two milliseconds + data transmission time each way). The
|
||||
packet unique identifier (reference 05) is 7. Notice that this is a lower
|
||||
number than the ARP request packet, which had a unique ID of 9. This tells
|
||||
us that the UDP packet was actually created before the ARP request packet ---
|
||||
which makes perfect sense since it was the attempt to send packet 7 that
|
||||
triggered sending the ARP request packet 9. Note that this an Ethernet
|
||||
packet (reference 06) like all other packets in this simulation, however this
|
||||
particular packet carries an IPV4 payload and therefore has an IP version 4
|
||||
header (indicated by references 10-16). This Ipv4 in turn contains a UDP
|
||||
header (references 17, 18) and finally 1024 bytes of data (reference 20).
|
||||
Clearly, this is the UDP echo packet emitted by the
|
||||
@code{UdpEchoClient Application}.
|
||||
|
||||
The next trace event is an ARP request from node one. We can infer that node
|
||||
one has received the UDP echo packet and the @code{UdpEchoServer Application}
|
||||
on that node has turned the packet around. Just as node zero needed to ARP
|
||||
for the MAC address of node one, now node one must ARP for the MAC address of
|
||||
node zero. We see the ARP request enqueued on the transmit queue of node one;
|
||||
then we see the ARP request dequeued from the tranmit queue of node one (and
|
||||
implicitly transmitted to node zero). Then we see an ARP response enqueued
|
||||
on the transmit queue of node zero; and finally the ARP response dequeued (and
|
||||
implicitly transmitted back to node one).
|
||||
|
||||
This exchange is summarized in the following trace event excerpts,
|
||||
|
||||
@verbatim
|
||||
+ 2.00786 nodeid=1 ... ARP(request ...
|
||||
- 2.00786 nodeid=1 ... ARP(request ...
|
||||
+ 2.00994 nodeid=0 ... ARP(reply ...
|
||||
- 2.00994 nodeid=0 ... ARP(reply ...
|
||||
@end verbatim
|
||||
|
||||
The final two trace events in the @code{tutorial.tr} file correspond to the
|
||||
echoed packet being enqueued for transmission on the net device for node one,
|
||||
and that packet being dequeued (and implicitly transmitted back to node zero).
|
||||
|
||||
@cindex AsciiTrace!TraceAllNetDeviceRx
|
||||
@cindex ARP!request
|
||||
If you look at the trace file (@code{tutorial.tr}) you will also see some
|
||||
entries with an @code{r} event, indicating a
|
||||
@emph{receive} trace event. Recall that the first packet sent on the network
|
||||
was a broadcast ARP request. We should then see all four nodes receive a
|
||||
copy of this request. This is the case, as the first four receive trace
|
||||
events are,
|
||||
|
||||
@verbatim
|
||||
r 2.00207 nodeid=0 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=1 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=2 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
r 2.00207 nodeid=3 device=0 dev-rx pkt-uid=9 ARP(request ...
|
||||
@end verbatim
|
||||
|
||||
@cindex unique ID
|
||||
You can see that a copy of the broadcast packet with unique ID 9 was received
|
||||
by the net devices on nodes 0, 1, 2 and 3. We leave it up to you to parse the
|
||||
rest of the trace file and understand the remaining reception events.
|
||||
|
||||
@subsection PCAP Trace Wrapper
|
||||
@cindex pcap
|
||||
@cindex Wireshark
|
||||
The @command{ns-3} @emph{pcap trace wrapper} is used to create trace files in
|
||||
@code{.pcap} format. The acronym pcap (usually written in lower case) stands
|
||||
for @emph{p}acket @emph{cap}ture, and is actually an API that includes the
|
||||
definition of a @code{.pcap} file format. The most popular program that can
|
||||
read and display this format is Wireshark (formerly called Ethereal).
|
||||
However, there are many traffic trace analyzers that use this packet
|
||||
format, including X, Y, and Z. We encourage users to exploit the
|
||||
many tools available for analyzing pcap traces; below, we show how
|
||||
tcpdump and Wireshark can be used..
|
||||
|
||||
@cindex tutorial-csma-echo-ascii-trace.cc
|
||||
@cindex tutorial-csma-echo-pcap-trace.cc
|
||||
The code used to enable pcap tracing is similar to that for ASCII tracing.
|
||||
We have provided another file, @code{tutorial-csma-echo-pcap-trace.cc} that
|
||||
uses the pcap trace wrapper. We have added the code to include the pcap
|
||||
trace wrapper defintions:
|
||||
|
||||
@verbatim
|
||||
#include "ns3/pcap-trace.h"
|
||||
@end verbatim
|
||||
|
||||
And then added the following code below the AsciiTrace methods:
|
||||
|
||||
@cindex PcapTrace
|
||||
@cindex PcapTrace!TraceAllIp
|
||||
@verbatim
|
||||
PcapTrace pcaptrace ("tutorial.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
@end verbatim
|
||||
|
||||
The first line of the code immediately above declares an object of type
|
||||
@code{PcapTrace} named @code{pcaptrace} and passes a string parameter to its
|
||||
constructor. This object is used to hide the details of the actual tracing
|
||||
subsystem. The parameter is a base file name from which the actual trace file
|
||||
names will be built. The second line of code tells the @code{PcamTrace}
|
||||
object to trace all IP activity in all of the nodes present in the simulation.
|
||||
|
||||
@cindex interface index
|
||||
Trace files are not created until trace activity is detected. Each file name
|
||||
is composed of the base file name, followed by a @code{'-'}, a node id followed
|
||||
by a @code{'-}', and an IP interface index. You will soon see a file named
|
||||
@code{tutorial.pcap-0-1}, for example. This will be the trace file generated
|
||||
as events are detected on node zero, interface index one. N.B. Interface
|
||||
indices are different that net device indices --- interface index zero
|
||||
corresponds to the loopback interface and interface index one corresponds to
|
||||
the first net device you added to a node.
|
||||
|
||||
You may run the new program just like all of the others so far:
|
||||
|
||||
@cindex Waf
|
||||
@verbatim
|
||||
./waf --run tutorial-csma-echo-pcap-trace
|
||||
@end verbatim
|
||||
|
||||
If you look at the top level directory of your distribution, you should now
|
||||
see three log files: @code{tutorial.tr} is the ASCII trace file we have
|
||||
previously examined. @code{tutorial.pcap-0-1} and @code{tutorial.pcap-1-1}
|
||||
are the new pcap files we just generated. There will not be files
|
||||
corresponding to nodes two and three since we have not sent any IP packets to
|
||||
those nodes.
|
||||
|
||||
@subsubsection Reading output with tcpdump
|
||||
@cindex tcpdump
|
||||
|
||||
@subsubsection Reading output with Wireshark
|
||||
@cindex Wireshark
|
||||
If you are unfamilar with Wireshark, there is a web site available from which
|
||||
you can download programs and documentation: @uref{http://www.wireshark.org/}.
|
||||
|
||||
If you have Wireshark available, you can open each of the trace files and
|
||||
display the contents as if you had captured the packets using a
|
||||
@emph{packet sniffer}. Note that only IP packets are traced using this
|
||||
wrapper, so you will not see the ARP exchanges that were logged when using
|
||||
the ASCII trace wrapper. You are encouraged to take a look at the contents
|
||||
of these pcap files using your favorite pcap software (or Wireshark).
|
||||
|
||||
@node Advanced Tracing
|
||||
@section Advanced Tracing
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@node Statistics
|
||||
@chapter Statistics
|
||||
@anchor{chap:Statistics}
|
||||
|
||||
ns-3 does not presently have support for statistics (automatically generated
|
||||
statistical output). This is planned
|
||||
for development later in 2008. If you are interested in contributing,
|
||||
please see @uref{http://www.nsnam.org/wiki/index.php/Suggested_Projects,,our suggested projects page} or contact the ns-developers
|
||||
list.
|
||||
@@ -0,0 +1,82 @@
|
||||
@node Troubleshooting
|
||||
@chapter Troubleshooting
|
||||
|
||||
This chapter posts some information about possibly common errors in building
|
||||
or running ns-3 programs.
|
||||
|
||||
Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items.
|
||||
|
||||
@node Build errors
|
||||
@section Build errors
|
||||
|
||||
@node Run-time errors
|
||||
@section Run-time errors
|
||||
|
||||
Sometimes, errors can occur with a program after a successful build. These
|
||||
are run-time errors, and can commonly occur when memory is corrupted or
|
||||
pointer values are unexpectedly null.
|
||||
|
||||
Here is an example of what might occur:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11
|
||||
@end verbatim
|
||||
|
||||
The error message says that the program terminated unsuccessfully, but it is
|
||||
not clear from this information what might be wrong. To examine more
|
||||
closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}:
|
||||
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s"
|
||||
Entering directory `/home/tomh/ns-3-nsc/build'
|
||||
Compilation finished successfully
|
||||
GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh)
|
||||
Copyright 2004 Free Software Foundation, Inc.
|
||||
GDB is free software, covered by the GNU General Public License, and you are
|
||||
welcome to change it and/or distribute copies of it under certain conditions.
|
||||
Type "show copying" to see the conditions.
|
||||
There is absolutely no warranty for GDB. Type "show warranty" for details.
|
||||
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
|
||||
Reading symbols from shared object read from target memory...done.
|
||||
Loaded system supplied DSO at 0xf5c000
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0x0804aa12 in main (argc=1, argv=0xbfdfefa4)
|
||||
at ../examples/tcp-point-to-point.cc:136
|
||||
136 Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
(gdb) p localSocket
|
||||
$1 = {m_ptr = 0x3c5d65}
|
||||
(gdb) p socketFactory
|
||||
$2 = {m_ptr = 0x0}
|
||||
(gdb) quit
|
||||
The program is running. Exit anyway? (y or n) y
|
||||
@end verbatim
|
||||
|
||||
Note first the way the program was invoked-- pass the command to run as
|
||||
an argument to the command template "gdb %s".
|
||||
|
||||
This tells us that there was an attempt to dereference a null pointer
|
||||
socketFactory.
|
||||
|
||||
Let's look around line 136 of tcp-point-to-point, as gdb suggests:
|
||||
@verbatim
|
||||
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
|
||||
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
|
||||
localSocket->Bind ();
|
||||
@end verbatim
|
||||
|
||||
The culprit here is that the return value of GetObject is not being
|
||||
checked and may be null.
|
||||
|
||||
Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory
|
||||
checker} for more subtle errors. Again, you invoke the use of valgrind
|
||||
similarly:
|
||||
@verbatim
|
||||
ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s"
|
||||
@end verbatim
|
||||
@@ -0,0 +1,156 @@
|
||||
body {
|
||||
font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif;
|
||||
background: white;
|
||||
color: black;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
# color: #990000;
|
||||
color: #009999;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 10pt;
|
||||
background: #e0e0e0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
#main th {
|
||||
font-size: 12pt;
|
||||
background: #b0b0b0;
|
||||
}
|
||||
|
||||
.odd {
|
||||
font-size: 12pt;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.even {
|
||||
font-size: 12pt;
|
||||
background: #e0e0e0;
|
||||
}
|
||||
|
||||
.answer {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.answer p {
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.answer ul {
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
#feedback {
|
||||
color: #b0b0b0;
|
||||
font-size: 9pt;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#header {
|
||||
position: absolute;
|
||||
margin: 0px;
|
||||
top: 10px;
|
||||
height:96px;
|
||||
left: 175px;
|
||||
right: 10em;
|
||||
bottom: auto;
|
||||
background: white;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#middle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#main {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 175px;
|
||||
right: 100px;
|
||||
background: white;
|
||||
padding: 0em 0em 0em 0em;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
position: absolute;
|
||||
top: 75px;
|
||||
left: 0em;
|
||||
width: 146px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#navbar a:link, #navbar a:visited {
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
#navbar a:hover {
|
||||
font-weight: normal;
|
||||
text-decoration: underline;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
#navbar dl {
|
||||
width: 146px;
|
||||
padding: 0;
|
||||
margin: 0 0 10px 0px;
|
||||
background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left;
|
||||
}
|
||||
|
||||
#navbar dt {
|
||||
padding: 6px 10px;
|
||||
font-size: 100%;
|
||||
font-weight: bold;
|
||||
background: #009999;
|
||||
margin: 0px;
|
||||
border-bottom: 1px solid #fff;
|
||||
color: white;
|
||||
background: #009999 url(images/box_top2.gif) no-repeat top left;
|
||||
}
|
||||
|
||||
#navbar dd {
|
||||
font-size: 100%;
|
||||
margin: 0 0 0 0px;
|
||||
padding: 6px 10px;
|
||||
color: #0047b9;
|
||||
}
|
||||
|
||||
dd#selected {
|
||||
background: #99ffff url(images/arrow.gif) no-repeat;
|
||||
background-position: 4px 10px;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename ns-3.info
|
||||
@settitle ns-3 tutorial
|
||||
@c @setchapternewpage odd
|
||||
@c %**end of header
|
||||
|
||||
@ifinfo
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
three forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator
|
||||
@item Tutorial (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML versions
|
||||
should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
@end ifinfo
|
||||
|
||||
@copying
|
||||
|
||||
This is an @command{ns-3} tutorial.
|
||||
Primary documentation for the @command{ns-3} project is available in
|
||||
three forms:
|
||||
@itemize @bullet
|
||||
@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator
|
||||
@item Tutorial (this document)
|
||||
@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki}
|
||||
@end itemize
|
||||
|
||||
This document is written in GNU Texinfo and is to be maintained in
|
||||
revision control on the @command{ns-3} code server. Both PDF and HTML
|
||||
versions should be available on the server. Changes to
|
||||
the document should be discussed on the ns-developers@@isi.edu mailing list.
|
||||
|
||||
This software is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This software is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see @uref{http://www.gnu.org/licenses/}.
|
||||
@end copying
|
||||
|
||||
@titlepage
|
||||
@title ns-3 Tutorial
|
||||
@author ns-3 project
|
||||
@author feedback: ns-developers@@isi.edu
|
||||
@today{}
|
||||
|
||||
@c @page
|
||||
@vskip 0pt plus 1filll
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
|
||||
@c So the toc is printed at the start.
|
||||
@anchor{Full Table of Contents}
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top, Overview, Full Table of Contents
|
||||
@top ns-3 Tutorial (html version)
|
||||
|
||||
For a pdf version of this tutorial,
|
||||
see @uref{http://www.nsnam.org/docs/tutorial.pdf}.
|
||||
|
||||
@insertcopying
|
||||
@end ifnottex
|
||||
|
||||
@menu
|
||||
* Tutorial Goals::
|
||||
Part 1: Getting Started with ns-3
|
||||
* Overview::
|
||||
* Browsing::
|
||||
* Resources::
|
||||
* Downloading and Compiling::
|
||||
* Some-Prerequisites::
|
||||
Part 2: Reading ns-3 Programs
|
||||
* A-First-ns-3-Script::
|
||||
Part 3: Reconfiguring Existing ns-3 Scripts
|
||||
* Logging::
|
||||
* ns-3 Attributes::
|
||||
* Tracing::
|
||||
* Statistics::
|
||||
Part 4: Creating New or Revised Topologies
|
||||
* Helper Functions::
|
||||
@end menu
|
||||
|
||||
@include introduction.texi
|
||||
@include log.texi
|
||||
@include attributes.texi
|
||||
@include statistics.texi
|
||||
@include helpers.texi
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
||||
@@ -0,0 +1,126 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//
|
||||
// Example of the sending of a datagram to a broadcast address
|
||||
//
|
||||
// Network topology
|
||||
// ==============
|
||||
// | |
|
||||
// n0 n1 n2
|
||||
// | |
|
||||
// ==========
|
||||
//
|
||||
// n0 originates UDP broadcast to 255.255.255.255/discard port, which
|
||||
// is replicated and received on both n1 and n2
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CsmaBroadcastExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaBroadcastExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
LogComponentEnable ("CsmaBroadcastExample", LOG_PREFIX_TIME);
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (3);
|
||||
NodeContainer c0 = NodeContainer (c.Get (0), c.Get (1));
|
||||
NodeContainer c1 = NodeContainer (c.Get (0), c.Get (2));
|
||||
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", DataRateValue (DataRate(5000000)));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds(2)));
|
||||
|
||||
NetDeviceContainer n0 = csma.Install (c0);
|
||||
NetDeviceContainer n1 = csma.Install (c1);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.0.0", "255.255.255.0");
|
||||
ipv4.Assign (n0);
|
||||
ipv4.SetBase ("192.168.1.0", "255.255.255.0");
|
||||
ipv4.Assign (n1);
|
||||
|
||||
|
||||
// RFC 863 discard port ("9") indicates packet should be thrown away
|
||||
// by the system. We allow this silent discard to be overridden
|
||||
// by the PacketSink application.
|
||||
uint16_t port = 9;
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 512 bytes (default) at a rate of 500 Kb/s (default) from n0
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address ("255.255.255.255"), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer app = onoff.Install (c0.Get (0));
|
||||
// Start the application
|
||||
app.Start (Seconds (1.0));
|
||||
app.Stop (Seconds (10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
sink.Install (c0.Get (1));
|
||||
sink.Install (c1.Get (1));
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// csma-broadcast.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -tt -r" command
|
||||
CsmaHelper::EnablePcapAll ("csma-broadcast");
|
||||
std::ofstream ascii;
|
||||
ascii.open ("csma-broadcast.tr");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// Lan1
|
||||
// ===========
|
||||
// | | |
|
||||
// n0 n1 n2 n3 n4
|
||||
// | | |
|
||||
// ===========
|
||||
// Lan0
|
||||
//
|
||||
// - Multicast source is at node n0;
|
||||
// - Multicast forwarded by node n2 onto LAN1;
|
||||
// - Nodes n0, n1, n2, n3, and n4 receive the multicast frame.
|
||||
// - Node n4 listens for the data
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CsmaMulticastExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
//
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
//
|
||||
// LogComponentEnable ("CsmaMulticastExample", LOG_LEVEL_INFO);
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
//
|
||||
// Set up default values for the simulation.
|
||||
//
|
||||
// Select Ethernet II-style encapsulation (no LLC/Snap header)
|
||||
Config::SetDefault ("ns3::CsmaNetDevice::EncapsulationMode", StringValue ("IpArp"));
|
||||
|
||||
// Allow the user to override any of the defaults at
|
||||
// run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (5);
|
||||
// We will later want two subcontainers of these nodes, for the two LANs
|
||||
NodeContainer c0 = NodeContainer (c.Get (0), c.Get (1), c.Get (2));
|
||||
NodeContainer c1 = NodeContainer (c.Get (2), c.Get (3), c.Get (4));
|
||||
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", DataRateValue (DataRate (5000000)));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
|
||||
// We will use these NetDevice containers later, for IP addressing
|
||||
NetDeviceContainer nd0 = csma.Install (c0); // First LAN
|
||||
NetDeviceContainer nd1 = csma.Install (c1); // Second LAN
|
||||
|
||||
NS_LOG_INFO ("Add IP Stack.");
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4Addr;
|
||||
ipv4Addr.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4Addr.Assign (nd0);
|
||||
ipv4Addr.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
ipv4Addr.Assign (nd1);
|
||||
|
||||
NS_LOG_INFO ("Configure multicasting.");
|
||||
//
|
||||
// Now we can configure multicasting. As described above, the multicast
|
||||
// source is at node zero, which we assigned the IP address of 10.1.1.1
|
||||
// earlier. We need to define a multicast group to send packets to. This
|
||||
// can be any multicast address from 224.0.0.0 through 239.255.255.255
|
||||
// (avoiding the reserved routing protocol addresses).
|
||||
//
|
||||
|
||||
Ipv4Address multicastSource ("10.1.1.1");
|
||||
Ipv4Address multicastGroup ("225.1.2.4");
|
||||
|
||||
// Now, we will set up multicast routing. We need to do three things:
|
||||
// 1) Configure a (static) multicast route on node n2
|
||||
// 2) Set up a default multicast route on the sender n0
|
||||
// 3) Have node n4 join the multicast group
|
||||
// We have a helper that can help us with static multicast
|
||||
StaticMulticastRouteHelper multicast;
|
||||
|
||||
// 1) Configure a (static) multicast route on node n2 (multicastRouter)
|
||||
Ptr<Node> multicastRouter = c.Get (2); // The node in question
|
||||
Ptr<NetDevice> inputIf = nd0.Get (2); // The input NetDevice
|
||||
NetDeviceContainer outputDevices; // A container of output NetDevices
|
||||
outputDevices.Add (nd1.Get (0)); // (we only need one NetDevice here)
|
||||
|
||||
multicast.AddMulticastRoute (multicastRouter, multicastSource,
|
||||
multicastGroup, inputIf, outputDevices);
|
||||
|
||||
// 2) Set up a default multicast route on the sender n0
|
||||
Ptr<Node> sender = c.Get (0);
|
||||
Ptr<NetDevice> senderIf = nd0.Get(0);
|
||||
multicast.SetDefaultMulticastRoute (sender, senderIf);
|
||||
|
||||
// 3) Have node n4 join the multicast group
|
||||
Ptr<Node> receiver = c.Get (4);
|
||||
multicast.JoinMulticastGroup (receiver, multicastSource, multicastGroup);
|
||||
|
||||
//
|
||||
// Create an OnOff application to send UDP datagrams from node zero to the
|
||||
// multicast group (node four will be listening).
|
||||
//
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
|
||||
uint16_t multicastPort = 9; // Discard port (RFC 863)
|
||||
|
||||
// Configure a multicast packet generator that generates a packet
|
||||
// every few seconds
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (multicastGroup, multicastPort)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
onoff.SetAttribute ("DataRate", DataRateValue (DataRate ("255b/s")));
|
||||
onoff.SetAttribute ("PacketSize", UintegerValue (128));
|
||||
|
||||
ApplicationContainer srcC = onoff.Install (c0.Get (0));
|
||||
|
||||
//
|
||||
// Tell the application when to start and stop.
|
||||
//
|
||||
srcC.Start(Seconds(1.));
|
||||
srcC.Stop (Seconds(10.));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny(), multicastPort));
|
||||
|
||||
ApplicationContainer sinkC = sink.Install (c1.Get (2)); // Node n4
|
||||
// Start the sink
|
||||
sinkC.Start (Seconds (1.0));
|
||||
sinkC.Stop (Seconds (10.0));
|
||||
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
//
|
||||
// Ascii trace output will be sent to the file "csma-multicast.tr"
|
||||
//
|
||||
std::ofstream ascii;
|
||||
ascii.open ("csma-multicast.tr");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced.
|
||||
// The output files will be named:
|
||||
// csma-multicast.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
CsmaHelper::EnablePcapAll ("csma-multicast");
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// n0 n1 n2 n3
|
||||
// | | | |
|
||||
// =================
|
||||
// LAN
|
||||
//
|
||||
// - CBR/UDP flows from n0 to n1 and from n3 to n0
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CsmaOneSubnetExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
//
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
//
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaOneSubnetExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
//
|
||||
// Allow the user to override any of the defaults and the above Bind() at
|
||||
// run-time, via command-line arguments
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
|
||||
NS_LOG_INFO ("Build Topology");
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", DataRateValue (5000000));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
//
|
||||
// Now fill out the topology by creating the net devices required to connect
|
||||
// the nodes to the channels and hooking them up. AddIpv4CsmaNetDevice will
|
||||
// create a net device, add a MAC address (in memory of the pink flamingo) and
|
||||
// connect the net device to a nodes and also to a channel. the
|
||||
// AddIpv4CsmaNetDevice method returns a net device index for the net device
|
||||
// created on the node. Interpret nd0 as the net device we created for node
|
||||
// zero.
|
||||
//
|
||||
NetDeviceContainer nd0 = csma.Install (c);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (nd0);
|
||||
|
||||
//
|
||||
// Create an OnOff application to send UDP datagrams from node zero to node 1.
|
||||
//
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address ("10.1.1.2"), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer app = onoff.Install (c.Get (0));
|
||||
// Start the application
|
||||
app.Start (Seconds (1.0));
|
||||
app.Stop (Seconds (10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
sink.Install (c.Get (1));
|
||||
|
||||
//
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
//
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port)));
|
||||
ApplicationContainer app2 = onoff.Install (c.Get (3));
|
||||
|
||||
sink.Install (c.Get (0));
|
||||
|
||||
app2.Start(Seconds (1.1));
|
||||
app2.Stop (Seconds (10.0));
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
// Trace output will be sent to the file "csma-one-subnet.tr"
|
||||
//
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
std::ofstream ascii;
|
||||
ascii.open ("csma-one-subnet.tr");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
//
|
||||
// Also configure some tcpdump traces; each interface will be traced.
|
||||
// The output files will be named:
|
||||
// csma-one-subnet.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
//
|
||||
CsmaHelper::EnablePcapAll ("csma-one-subnet");
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0 n1 n2 n3
|
||||
// | | | |
|
||||
// =====================
|
||||
//
|
||||
// - CBR/UDP flows from n0 to n1, and from n3 to n0
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CsmaPacketSocketExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaPacketSocketExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
|
||||
PacketSocketHelper packetSocket;
|
||||
packetSocket.Install (c);
|
||||
|
||||
// create the shared medium used by all csma devices.
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
Ptr<CsmaChannel> channel = CreateObject<CsmaChannel> (
|
||||
"DataRate", DataRateValue (DataRate(5000000)),
|
||||
"Delay", TimeValue (MilliSeconds(2)));
|
||||
|
||||
// use a helper function to connect our nodes to the shared channel.
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
CsmaHelper csma;
|
||||
csma.SetDeviceParameter ("EncapsulationMode", StringValue ("Llc"));
|
||||
NetDeviceContainer devs = csma.Install (c, channel);
|
||||
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
// Create the OnOff application to send raw datagrams
|
||||
PacketSocketAddress socket;
|
||||
socket.SetSingleDevice(devs.Get (0)->GetIfIndex ());
|
||||
socket.SetPhysicalAddress (devs.Get (1)->GetAddress ());
|
||||
socket.SetProtocol (2);
|
||||
OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1.0)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0.0)));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
socket.SetSingleDevice (devs.Get (3)->GetIfIndex ());
|
||||
socket.SetPhysicalAddress (devs.Get (0)->GetAddress ());
|
||||
socket.SetProtocol (3);
|
||||
onoff.SetAttribute ("Remote", AddressValue (socket));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0.0)));
|
||||
apps = onoff.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the csma-packet-socket.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
std::ofstream os;
|
||||
os.open ("csma-packet-socket.tr");
|
||||
csma.EnableAsciiAll (os);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
// This script exercises global routing code in a mixed point-to-point
|
||||
// and csma/cd environment
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ p-p
|
||||
// \ (shared csma/cd)
|
||||
// n2 -------------------------n3
|
||||
// / | |
|
||||
// / p-p n4 n5 ---------- n6
|
||||
// n1 p-p
|
||||
//
|
||||
// - CBR/UDP flows from n0 to n6
|
||||
// - Tracing of queues and packet receptions to file "mixed-global-routing.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("MixedGlobalRoutingExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("448kb/s"));
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind ()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (7);
|
||||
NodeContainer n0n2 = NodeContainer (c.Get (0), c.Get (2));
|
||||
NodeContainer n1n2 = NodeContainer (c.Get (1), c.Get (2));
|
||||
NodeContainer n5n6 = NodeContainer (c.Get (5), c.Get (6));
|
||||
NodeContainer n2345 = NodeContainer (c.Get (2), c.Get (3), c.Get (4), c.Get (5));
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
|
||||
NetDeviceContainer d5d6 = p2p.Install (n5n6);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", StringValue ("5Mbps"));
|
||||
csma.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d2345 = csma.Install (n2345);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
ipv4.Assign (d1d2);
|
||||
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i5i6 = ipv4.Assign (d5d6);
|
||||
|
||||
ipv4.SetBase ("10.250.1.0", "255.255.255.0");
|
||||
ipv4.Assign (d2345);
|
||||
|
||||
// Create router nodes, initialize routing database and set up the routing
|
||||
// tables in the nodes.
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (i5i6.GetAddress (1), port));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
onoff.SetAttribute ("DataRate", StringValue ("300bps"));
|
||||
onoff.SetAttribute ("PacketSize", UintegerValue (50));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("mixed-global-routing.tr");
|
||||
PointToPointHelper::EnablePcapAll ("mixed-global-routing");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
CsmaHelper::EnablePcapAll ("mixed-global-routing");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// This ns-3 example demonstrates the use of helper functions to ease
|
||||
// the construction of simulation scenarios.
|
||||
//
|
||||
// The simulation topology consists of a mixed wired and wireless
|
||||
// scenario in which a hierarchical mobility model is used.
|
||||
//
|
||||
// The simulation layout consists of N backbone routers interconnected
|
||||
// by an ad hoc wifi network.
|
||||
// Each backbone router also has a local 802.11 network and is connected
|
||||
// to a local LAN. An additional set of (K-1) nodes are connected to
|
||||
// this backbone. Finally, a local LAN is connected to each router
|
||||
// on the backbone, with L-1 additional hosts.
|
||||
//
|
||||
// The nodes are populated with TCP/IP stacks, and OLSR unicast routing
|
||||
// on the backbone. An example UDP transfer is shown. The simulator
|
||||
// be configured to output tcpdumps or traces from different nodes.
|
||||
//
|
||||
//
|
||||
// +--------------------------------------------------------+
|
||||
// | |
|
||||
// | 802.11 ad hoc, ns-2 mobility |
|
||||
// | |
|
||||
// +--------------------------------------------------------+
|
||||
// | o o o (N backbone routers) |
|
||||
// +--------+ +--------+
|
||||
// wired LAN | mobile | wired LAN | mobile |
|
||||
// -----------| router | -----------| router |
|
||||
// --------- ---------
|
||||
// | |
|
||||
// +----------------+ +----------------+
|
||||
// | 802.11 | | 802.11 |
|
||||
// | net | | net |
|
||||
// | K-1 hosts | | K-1 hosts |
|
||||
// +----------------+ +----------------+
|
||||
//
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/contrib-module.h"
|
||||
#include "ns3/wifi-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
//
|
||||
// Define logging keyword for this file
|
||||
//
|
||||
NS_LOG_COMPONENT_DEFINE ("MixedWireless");
|
||||
|
||||
//
|
||||
// This function will be used below as a trace sink
|
||||
//
|
||||
#ifdef ENABLE_FOR_TRACING_EXAMPLE
|
||||
static void
|
||||
CourseChangeCallback (std::string path, Ptr<const MobilityModel> model)
|
||||
{
|
||||
Vector position = model->GetPosition ();
|
||||
std::cout << "CourseChange " << path << " x=" << position.x << ", y=" << position.y << ", z=" << position.z << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
//
|
||||
// First, we declare and initialize a few local variables that control some
|
||||
// simulation parameters.
|
||||
//
|
||||
uint32_t backboneNodes = 10;
|
||||
uint32_t infraNodes = 5;
|
||||
uint32_t lanNodes = 5;
|
||||
uint32_t stopTime = 10;
|
||||
|
||||
//
|
||||
// Simulation defaults are typically set next, before command line
|
||||
// arguments are parsed.
|
||||
//
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", StringValue ("210"));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("448kb/s"));
|
||||
|
||||
//
|
||||
// For convenience, we add the local variables to the command line argument
|
||||
// system so that they can be overridden with flags such as
|
||||
// "--backboneNodes=20"
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.AddValue("backboneNodes", "number of backbone nodes", backboneNodes);
|
||||
cmd.AddValue ("infraNodes", "number of leaf nodes", infraNodes);
|
||||
cmd.AddValue("lanNodes", "number of LAN nodes", lanNodes);
|
||||
cmd.AddValue("stopTime", "simulation stop time (seconds)", stopTime);
|
||||
|
||||
//
|
||||
// The system global variables and the local values added to the argument
|
||||
// system can be overridden by command line arguments by using this call.
|
||||
//
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// The metadata system (off by default) is used by ascii tracing below
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Construct the backbone //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Create a container to manage the nodes of the adhoc (backbone) network.
|
||||
// Later we'll create the rest of the nodes we'll need.
|
||||
//
|
||||
NodeContainer backbone;
|
||||
backbone.Create (backboneNodes);
|
||||
//
|
||||
// Create the backbone wifi net devices and install them into the nodes in
|
||||
// our container
|
||||
//
|
||||
WifiHelper wifi;
|
||||
wifi.SetMac ("ns3::AdhocWifiMac");
|
||||
wifi.SetPhy ("ns3::WifiPhy");
|
||||
NetDeviceContainer backboneDevices = wifi.Install (backbone);
|
||||
//
|
||||
// Add the IPv4 protocol stack to the nodes in our container
|
||||
//
|
||||
InternetStackHelper internet;
|
||||
internet.Install (backbone);
|
||||
//
|
||||
// Assign IPv4 addresses to the device drivers (actually to the associated
|
||||
// IPv4 interfaces) we just created.
|
||||
//
|
||||
Ipv4AddressHelper ipAddrs;
|
||||
ipAddrs.SetBase ("192.168.0.0", "255.255.255.0");
|
||||
ipAddrs.Assign (backboneDevices);
|
||||
|
||||
//
|
||||
// The ad-hoc network nodes need a mobility model so we aggregate one to
|
||||
// each of the nodes we just finished building.
|
||||
//
|
||||
MobilityHelper mobility;
|
||||
Ptr<ListPositionAllocator> positionAlloc =
|
||||
CreateObject<ListPositionAllocator> ();
|
||||
double x = 0.0;
|
||||
for (uint32_t i = 0; i < backboneNodes; ++i)
|
||||
{
|
||||
positionAlloc->Add (Vector (x, 0.0, 0.0));
|
||||
x += 5.0;
|
||||
}
|
||||
mobility.SetPositionAllocator (positionAlloc);
|
||||
mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
|
||||
"Bounds", RectangleValue (Rectangle (0, 1000, 0, 1000)),
|
||||
"Speed", RandomVariableValue (ConstantVariable (2000)),
|
||||
"Pause", RandomVariableValue (ConstantVariable (0.2)));
|
||||
mobility.Install (backbone);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Construct the LANs //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Reset the address base-- all of the CSMA networks will be in
|
||||
// the "172.16 address space
|
||||
ipAddrs.SetBase ("172.16.0.0", "255.255.255.0");
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < backboneNodes; ++i)
|
||||
{
|
||||
NS_LOG_INFO ("Configuring local area network for backbone node " << i);
|
||||
//
|
||||
// Create a container to manage the nodes of the LAN. We need
|
||||
// two containers here; one with all of the new nodes, and one
|
||||
// with all of the nodes including new and existing nodes
|
||||
//
|
||||
NodeContainer newLanNodes;
|
||||
newLanNodes.Create (lanNodes - 1);
|
||||
// Now, create the container with all nodes on this link
|
||||
NodeContainer lan (backbone.Get (i), newLanNodes);
|
||||
//
|
||||
// Create the CSMA net devices and install them into the nodes in our
|
||||
// collection.
|
||||
//
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate",
|
||||
DataRateValue (DataRate (5000000)));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
NetDeviceContainer lanDevices = csma.Install (lan);
|
||||
//
|
||||
// Add the IPv4 protocol stack to the new LAN nodes
|
||||
//
|
||||
internet.Install (newLanNodes);
|
||||
//
|
||||
// Assign IPv4 addresses to the device drivers (actually to the
|
||||
// associated IPv4 interfaces) we just created.
|
||||
//
|
||||
ipAddrs.Assign (lanDevices);
|
||||
//
|
||||
// Assign a new network prefix for the next LAN, according to the
|
||||
// network mask initialized above
|
||||
//
|
||||
ipAddrs.NewNetwork ();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Construct the mobile networks //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Reset the address base-- all of the 802.11 networks will be in
|
||||
// the "10.0" address space
|
||||
ipAddrs.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
|
||||
for (uint32_t i = 0; i < backboneNodes; ++i)
|
||||
{
|
||||
NS_LOG_INFO ("Configuring wireless network for backbone node " << i);
|
||||
//
|
||||
// Create a container to manage the nodes of the LAN. We need
|
||||
// two containers here; one with all of the new nodes, and one
|
||||
// with all of the nodes including new and existing nodes
|
||||
//
|
||||
NodeContainer newInfraNodes;
|
||||
newInfraNodes.Create (infraNodes - 1);
|
||||
// Now, create the container with all nodes on this link
|
||||
NodeContainer infra (backbone.Get (i), newInfraNodes);
|
||||
//
|
||||
// Create another ad hoc network and devices
|
||||
//
|
||||
WifiHelper wifiInfra;
|
||||
wifiInfra.SetMac ("ns3::AdhocWifiMac");
|
||||
wifiInfra.SetPhy ("ns3::WifiPhy");
|
||||
NetDeviceContainer infraDevices = wifiInfra.Install (infra);
|
||||
|
||||
// Add the IPv4 protocol stack to the nodes in our container
|
||||
//
|
||||
internet.Install (newInfraNodes);
|
||||
//
|
||||
// Assign IPv4 addresses to the device drivers (actually to the associated
|
||||
// IPv4 interfaces) we just created.
|
||||
//
|
||||
ipAddrs.Assign (infraDevices);
|
||||
//
|
||||
// Assign a new network prefix for each mobile network, according to
|
||||
// the network mask initialized above
|
||||
//
|
||||
ipAddrs.NewNetwork ();
|
||||
//
|
||||
// The new wireless nodes need a mobility model so we aggregate one
|
||||
// to each of the nodes we just finished building.
|
||||
//
|
||||
Ptr<ListPositionAllocator> subnetAlloc =
|
||||
CreateObject<ListPositionAllocator> ();
|
||||
for (uint32_t j = 0; j < infra.GetN (); ++j)
|
||||
{
|
||||
subnetAlloc->Add (Vector (0.0, j, 0.0));
|
||||
}
|
||||
mobility.PushReferenceMobilityModel (backbone.Get (i));
|
||||
mobility.SetPositionAllocator (subnetAlloc);
|
||||
mobility.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
|
||||
"Bounds", RectangleValue (Rectangle (-25, 25, -25, 25)),
|
||||
"Speed", RandomVariableValue (ConstantVariable (30)),
|
||||
"Pause", RandomVariableValue (ConstantVariable (0.4)));
|
||||
mobility.Install (infra);
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Routing configuration //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_LOG_INFO ("Enabling OLSR routing on all backbone nodes");
|
||||
OlsrHelper olsr;
|
||||
olsr.Install (backbone);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Application configuration //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s, between two nodes
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
// Let's make sure that the user does not define too few LAN nodes
|
||||
// to make this example work. We need lanNodes >= 5
|
||||
NS_ASSERT (lanNodes >= 5);
|
||||
Ptr<Node> appSource = NodeList::GetNode (11);
|
||||
Ptr<Node> appSink = NodeList::GetNode (13);
|
||||
Ipv4Address remoteAddr = Ipv4Address ("172.16.0.5");
|
||||
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (remoteAddr, port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
ApplicationContainer apps = onoff.Install (appSource);
|
||||
apps.Start (Seconds (3.0));
|
||||
apps.Stop (Seconds (20.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port));
|
||||
apps = sink.Install (appSink);
|
||||
apps.Start (Seconds (3.0));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Tracing configuration //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
//
|
||||
// Let's set up some ns-2-like ascii traces, using another helper class
|
||||
//
|
||||
std::ofstream ascii;
|
||||
ascii.open ("mixed-wireless.tr");
|
||||
WifiHelper::EnableAsciiAll (ascii);
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
// Look at nodes 11, 13 only
|
||||
//WifiHelper::EnableAscii (ascii, 11, 0);
|
||||
//WifiHelper::EnableAscii (ascii, 13, 0);
|
||||
|
||||
// Let's do a pcap trace on the backbone devices
|
||||
WifiHelper::EnablePcap ("mixed-wireless", backboneDevices);
|
||||
// Let's additionally trace the application Sink, ifIndex 0
|
||||
CsmaHelper::EnablePcap ("mixed-wireless", appSink->GetId (), 0);
|
||||
|
||||
#ifdef ENABLE_FOR_TRACING_EXAMPLE
|
||||
Config::Connect ("/NodeList/*/$MobilityModel/CourseChange",
|
||||
MakeCallback (&CourseChangeCallback));
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Run simulation //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Stop (Seconds (stopTime));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 ------------------------n3
|
||||
// / /
|
||||
// / 5 Mb/s, 2ms /
|
||||
// n1--------------------------
|
||||
// 1.5 Mb/s, 100ms
|
||||
//
|
||||
// this is a modification of simple-global-routing to allow for
|
||||
// a single hop but higher-cost path between n1 and n3
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file "simple-rerouting.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SimpleAlternateRoutingExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable("GlobalRouteManager", LOG_LOGIC);
|
||||
LogComponentEnable("GlobalRouter", LOG_LOGIC);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("300b/s"));
|
||||
|
||||
// The below metric, if set to 3 or higher, will cause packets between
|
||||
// n1 and n3 to take the 2-hop route through n2
|
||||
|
||||
CommandLine cmd;
|
||||
//
|
||||
// Additionally, we plumb this metric into the default value / command
|
||||
// line argument system as well, for exemplary purposes. This means
|
||||
// that it can be resettable at the command-line to the program,
|
||||
// rather than recompiling
|
||||
// e.g. waf --run "simple-alternate-routing --AlternateCost=5"
|
||||
uint16_t sampleMetric = 1;
|
||||
cmd.AddValue ("AlternateCost",
|
||||
"This metric is used in the example script between n3 and n1 ",
|
||||
sampleMetric);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// DefaultValue::Bind ()s at run-time, via command-line arguments
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
NodeContainer n0n2 = NodeContainer (c.Get (0), c.Get (2));
|
||||
NodeContainer n1n2 = NodeContainer (c.Get (1), c.Get (2));
|
||||
NodeContainer n3n2 = NodeContainer (c.Get (3), c.Get (2));
|
||||
NodeContainer n1n3 = NodeContainer (c.Get (1), c.Get (3));
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
|
||||
NetDeviceContainer d3d2 = p2p.Install (n3n2);
|
||||
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("100ms"));
|
||||
NetDeviceContainer d1d3 = p2p.Install (n1n3);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// Later, we add IP addresses. The middle two octets correspond to
|
||||
// the channel number.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
ipv4.SetBase ("10.2.2.0", "255.255.255.0");
|
||||
ipv4.Assign (d3d2);
|
||||
|
||||
ipv4.SetBase ("10.3.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i3 = ipv4.Assign (d1d3);
|
||||
|
||||
i1i3.SetMetric (0, sampleMetric);
|
||||
i1i3.SetMetric (1, sampleMetric);
|
||||
|
||||
// Create router nodes, initialize routing database and set up the routing
|
||||
// tables in the nodes.
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
// Create the OnOff application to send UDP datagrams
|
||||
NS_LOG_INFO ("Create Application.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
// Create a flow from n3 to n1, starting at time 1.1 seconds
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (i1i2.GetAddress (0), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Start (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
apps = sink.Install (c.Get (1));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-alternate-routing.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-alternate-routing");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ns-2 simple.tcl script (ported from ns-2)
|
||||
* Originally authored by Steve McCanne, 12/19/1996
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
//
|
||||
// - all links are point-to-point links with indicated one-way BW/delay
|
||||
// - CBR/UDP flows from n0 to n3, and from n3 to n1
|
||||
// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "simple-error-model.tr"
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SimpleErrorModelExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Set a few parameters
|
||||
Config::SetDefault ("ns3::RateErrorModel::ErrorRate", DoubleValue (0.01));
|
||||
Config::SetDefault ("ns3::RateErrorModel::ErrorUnit", StringValue ("EU_PKT"));
|
||||
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", DataRateValue (DataRate ("448kb/s")));
|
||||
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
NodeContainer n0n2 = NodeContainer (c.Get (0), c.Get (2));
|
||||
NodeContainer n1n2 = NodeContainer (c.Get (1), c.Get (2));
|
||||
NodeContainer n3n2 = NodeContainer (c.Get (3), c.Get (2));
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (5000000)));
|
||||
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (1500000)));
|
||||
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (10)));
|
||||
NetDeviceContainer d3d2 = p2p.Install (n3n2);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i3i2 = ipv4.Assign (d3d2);
|
||||
|
||||
NS_LOG_INFO ("Use global routing.");
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (i3i2.GetAddress (1), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable(1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable(0)));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start(Seconds(1.0));
|
||||
apps.Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
apps = sink.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (i1i2.GetAddress (0), port)));
|
||||
apps = onoff.Install (c.Get (3));
|
||||
apps.Start(Seconds(1.1));
|
||||
apps.Stop (Seconds(10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink.SetAttribute ("Local",
|
||||
AddressValue (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
apps = sink.Install (c.Get (1));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
//
|
||||
// Error model
|
||||
//
|
||||
// Create an ErrorModel based on the implementation (constructor)
|
||||
// specified by the default classId
|
||||
Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ("RanVar", RandomVariableValue (UniformVariable (0.0, 1.0)),
|
||||
"ErrorRate", DoubleValue (0.001));
|
||||
d3d2.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
|
||||
|
||||
// Now, let's use the ListErrorModel and explicitly force a loss
|
||||
// of the packets with pkt-uids = 11 and 17 on node 2, device 0
|
||||
std::list<uint32_t> sampleList;
|
||||
sampleList.push_back (11);
|
||||
sampleList.push_back (17);
|
||||
// This time, we'll explicitly create the error model we want
|
||||
Ptr<ListErrorModel> pem = CreateObject<ListErrorModel> ();
|
||||
pem->SetList (sampleList);
|
||||
d0d2.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (pem));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-error-model.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-error-model");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ns-2 simple.tcl script (ported from ns-2)
|
||||
* Originally authored by Steve McCanne, 12/19/1996
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
//
|
||||
// - all links are point-to-point links with indicated one-way BW/delay
|
||||
// - CBR/UDP flows from n0 to n3, and from n3 to n1
|
||||
// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "simple-global-routing.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SimpleGlobalRoutingExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("SimpleGlobalRoutingExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Set up some default values for the simulation. Use the
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("448kb/s"));
|
||||
|
||||
//DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// DefaultValue::Bind ()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
NodeContainer n0n2 = NodeContainer (c.Get(0), c.Get (2));
|
||||
NodeContainer n1n2 = NodeContainer (c.Get(1), c.Get (2));
|
||||
NodeContainer n3n2 = NodeContainer (c.Get(3), c.Get (2));
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
|
||||
NetDeviceContainer d3d2 = p2p.Install (n3n2);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i0i2 = ipv4.Assign (d0d2);
|
||||
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i3i2 = ipv4.Assign (d3d2);
|
||||
|
||||
// Create router nodes, initialize routing database and set up the routing
|
||||
// tables in the nodes.
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (i3i2.GetAddress (0), port)));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
|
||||
apps = sink.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (i1i2.GetAddress (0), port)));
|
||||
apps = onoff.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
apps = sink.Install (c.Get (1));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-global-routing.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-global-routing");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ns-2 simple.tcl script (ported from ns-2)
|
||||
* Originally authored by Steve McCanne, 12/19/1996
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
//
|
||||
// - all links are p2p links with indicated one-way BW/delay
|
||||
// - CBR/UDP flows from n0 to n3, and from n3 to n1
|
||||
// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "simple-p2p.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
|
||||
#include "ns3/ascii-trace.h"
|
||||
#include "ns3/pcap-trace.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/p2p-channel.h"
|
||||
#include "ns3/p2p-net-device.h"
|
||||
#include "ns3/mac-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/p2p-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
DebugComponentEnable("Object");
|
||||
DebugComponentEnable("Queue");
|
||||
DebugComponentEnable("DropTailQueue");
|
||||
DebugComponentEnable("Channel");
|
||||
DebugComponentEnable("PointToPointChannel");
|
||||
DebugComponentEnable("PointToPointNetDevice");
|
||||
#endif
|
||||
|
||||
// Set up some default values for the simulation. Use the Bind()
|
||||
// technique to tell the system what subclass of Queue to use,
|
||||
// and what the queue limit is
|
||||
|
||||
// The below Bind command tells the queue factory which class to
|
||||
// instantiate, when the queue factory is invoked in the topology code
|
||||
Bind ("Queue", "DropTailQueue");
|
||||
|
||||
Bind ("OnOffApplicationPacketSize", "210");
|
||||
Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
|
||||
//Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate(1500000), MilliSeconds(10));
|
||||
|
||||
// Later, we add IP addresses.
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.1.1"),
|
||||
n2, Ipv4Address("10.1.1.2"));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address("10.1.2.1"),
|
||||
n2, Ipv4Address("10.1.2.2"));
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel2, n2, Ipv4Address("10.1.3.1"),
|
||||
n3, Ipv4Address("10.1.3.2"));
|
||||
|
||||
// Finally, we add static routes. These three steps (Channel and
|
||||
// NetDevice creation, IP Address assignment, and routing) are
|
||||
// separated because there may be a need to postpone IP Address
|
||||
// assignment (emulation) or modify to use dynamic routing
|
||||
PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
|
||||
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
Ipv4Address("10.1.3.2"),
|
||||
80,
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
Ipv4Address("10.1.2.1"),
|
||||
80,
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1);
|
||||
ipv4 = n3->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1);
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-p2p.tr file
|
||||
AsciiTrace asciitrace ("simple-p2p.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("simple-p2p.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* ns-2 simple.tcl script (ported from ns-2)
|
||||
* Originally authored by Steve McCanne, 12/19/1996
|
||||
*/
|
||||
|
||||
// Port of ns-2/tcl/ex/simple.tcl to ns-3
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3---------n4
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
//
|
||||
// - all links are point-to-point links with indicated one-way BW/delay
|
||||
// - CBR/UDP flows from n0 to n3, and from n3 to n1
|
||||
// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
|
||||
// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
|
||||
// (i.e., DataRate of 448,000 bps)
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "simple-point-to-point-olsr.tr"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SimpleGlobalRoutingExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("SimpleGlobalRoutingExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Set up some default values for the simulation. Use the
|
||||
|
||||
Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (210));
|
||||
Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("448kb/s"));
|
||||
|
||||
//DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// DefaultValue::Bind ()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer c;
|
||||
c.Create (5);
|
||||
NodeContainer n02 = NodeContainer (c.Get(0), c.Get (2));
|
||||
NodeContainer n12 = NodeContainer (c.Get(1), c.Get (2));
|
||||
NodeContainer n32 = NodeContainer (c.Get(3), c.Get (2));
|
||||
NodeContainer n34 = NodeContainer (c.Get (3), c.Get (4));
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer nd02 = p2p.Install (n02);
|
||||
NetDeviceContainer nd12 = p2p.Install (n12);
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("1500kbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("10ms"));
|
||||
NetDeviceContainer nd32 = p2p.Install (n32);
|
||||
NetDeviceContainer nd34 = p2p.Install (n34);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i02 = ipv4.Assign (nd02);
|
||||
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i12 = ipv4.Assign (nd12);
|
||||
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i32 = ipv4.Assign (nd32);
|
||||
|
||||
ipv4.SetBase ("10.1.4.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i34 = ipv4.Assign (nd34);
|
||||
|
||||
// Enable OLSR
|
||||
NS_LOG_INFO ("Enabling OLSR Routing.");
|
||||
OlsrHelper olsr;
|
||||
olsr.InstallAll ();
|
||||
|
||||
// Create the OnOff application to send UDP datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (i34.GetAddress (1), port));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port));
|
||||
|
||||
apps = sink.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (i12.GetAddress (0), port)));
|
||||
apps = onoff.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
apps = sink.Install (c.Get (1));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-point-to-point-olsr.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-point-to-point-olsr");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
Simulator::Stop (Seconds (30));
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// 10Mb/s, 10ms 10Mb/s, 10ms
|
||||
// n0-----------------n1-----------------n2
|
||||
//
|
||||
//
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "tcp-large-transfer.tr"
|
||||
// - pcap traces also generated in the following files
|
||||
// "tcp-large-transfer-$n-$i.pcap" where n and i represent node and interface
|
||||
// numbers respectively
|
||||
// Usage (e.g.): ./waf --run tcp-large-transfer
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/global-route-manager.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpLargeTransfer");
|
||||
|
||||
// The number of bytes to send in this simulation.
|
||||
static uint32_t txBytes = 2000000;
|
||||
|
||||
// These are for starting the writing process, and handling the sending
|
||||
// socket's notification upcalls (events). These two together more or less
|
||||
// implement a sending "Application", although not a proper ns3::Application
|
||||
// subclass.
|
||||
|
||||
void StartFlow(Ptr<Socket>, Ipv4Address, uint16_t);
|
||||
void WriteUntilBufferFull (Ptr<Socket>, uint32_t);
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
// LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpSocketImpl", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("PacketSink", LOG_LEVEL_ALL);
|
||||
// LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL);
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create three nodes. The first container contains
|
||||
// nodes 0 and 1 from the diagram above, and the second one contains nodes
|
||||
// 1 and 2. This reflects the channel connectivity, and will be used to
|
||||
// install the network interfaces and connect them with a channel.
|
||||
NodeContainer n0n1;
|
||||
n0n1.Create (2);
|
||||
|
||||
NodeContainer n1n2;
|
||||
n1n2.Add (n0n1.Get (1));
|
||||
n1n2.Create (1);
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
// First make and configure the helper, so that it will put the appropriate
|
||||
// parameters on the network interfaces and channels we are about to install.
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate(10000000)));
|
||||
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds(10)));
|
||||
|
||||
// And then install devices and channels connecting our topology.
|
||||
NetDeviceContainer dev0 = p2p.Install (n0n1);
|
||||
NetDeviceContainer dev1 = p2p.Install (n1n2);
|
||||
|
||||
// Now add ip/tcp stack to all nodes.
|
||||
NodeContainer allNodes = NodeContainer (n0n1, n1n2.Get (1));
|
||||
InternetStackHelper internet;
|
||||
internet.Install (allNodes);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
|
||||
ipv4.Assign (dev0);
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev1);
|
||||
|
||||
// and setup ip routing tables to get total ip-level connectivity.
|
||||
GlobalRouteManager::PopulateRoutingTables ();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simulation 1
|
||||
//
|
||||
// Send 2000000 bytes over a connection to server port 50000 at time 0
|
||||
// Should observe SYN exchange, a lot of data segments and ACKS, and FIN
|
||||
// exchange. FIN exchange isn't quite compliant with TCP spec (see release
|
||||
// notes for more info)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint16_t servPort = 50000;
|
||||
|
||||
// Create a packet sink to receive these packets on n2...
|
||||
PacketSinkHelper sink ("ns3::TcpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), servPort));
|
||||
|
||||
ApplicationContainer apps = sink.Install (n1n2.Get (1));
|
||||
apps.Start (Seconds (0.0));
|
||||
|
||||
// Create a source to send packets from n0. Instead of a full Application
|
||||
// and the helper APIs you might see in other example files, this example
|
||||
// will use sockets directly and register some socket callbacks as a sending
|
||||
// "Application".
|
||||
|
||||
// Create and bind the socket...
|
||||
Ptr<Socket> localSocket =
|
||||
Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ());
|
||||
localSocket->Bind ();
|
||||
|
||||
// ...and schedule the sending "Application"; This is similar to what an
|
||||
// ns3::Application subclass would do internally.
|
||||
Simulator::ScheduleNow (&StartFlow, localSocket,
|
||||
ipInterfs.GetAddress (1), servPort);
|
||||
|
||||
// One can toggle the comment for the following line on or off to see the
|
||||
// effects of finite send buffer modelling. One can also change the size of
|
||||
// said buffer.
|
||||
|
||||
//localSocket->SetAttribute("SndBufSize", UintegerValue(4096));
|
||||
|
||||
//Ask for ASCII and pcap traces of network traffic
|
||||
std::ofstream ascii;
|
||||
ascii.open ("tcp-large-transfer.tr");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
PointToPointHelper::EnablePcapAll ("tcp-large-transfer");
|
||||
|
||||
// Finally, set up the simulator to run. The 1000 second hard limit is a
|
||||
// failsafe in case some change above causes the simulation to never end
|
||||
Simulator::Stop (Seconds(1000));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//begin implementation of sending "Application"
|
||||
void StartFlow(Ptr<Socket> localSocket,
|
||||
Ipv4Address servAddress,
|
||||
uint16_t servPort)
|
||||
{
|
||||
NS_LOG_LOGIC("Starting flow at time " << Simulator::Now ().GetSeconds ());
|
||||
localSocket->Connect (InetSocketAddress (servAddress, servPort));//connect
|
||||
|
||||
// tell the tcp implementation to call WriteUntilBufferFull again
|
||||
// if we blocked and new tx buffer space becomes available
|
||||
localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull));
|
||||
WriteUntilBufferFull (localSocket, txBytes);
|
||||
}
|
||||
|
||||
void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace)
|
||||
{
|
||||
// Perform series of 1040 byte writes (this is a multiple of 26 since
|
||||
// we want to detect data splicing in the output stream)
|
||||
uint32_t writeSize = 1040;
|
||||
uint8_t data[writeSize];
|
||||
|
||||
while (txBytes > 0) {
|
||||
uint32_t curSize= txBytes > writeSize ? writeSize : txBytes;
|
||||
if (curSize > txSpace)
|
||||
curSize = txSpace;
|
||||
for(uint32_t i = 0; i < curSize; ++i)
|
||||
{
|
||||
char m = toascii (97 + i % 26);
|
||||
data[i] = m;
|
||||
}
|
||||
int amountSent = localSocket->Send (data, curSize, 0);
|
||||
if(amountSent < 0)
|
||||
{
|
||||
// we will be called again when new tx space becomes available.
|
||||
std::cout << "Socket blocking, " << txBytes << " left to write, returning" << std::endl;
|
||||
return;
|
||||
}
|
||||
txBytes -= curSize;
|
||||
if (amountSent != (int)curSize)
|
||||
{
|
||||
std::cout << "Short Write, returning" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
localSocket->Close ();
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// n0 n1 n2 n3
|
||||
// | | | |
|
||||
// =================
|
||||
// LAN
|
||||
//
|
||||
// - UDP flows from n0 to n1 and back
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "udp-echo.tr"
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("UdpEchoExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
//
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
//
|
||||
#if 0
|
||||
LogComponentEnable ("UdpEchoExample", LOG_LEVEL_INFO);
|
||||
|
||||
LogComponentEnable("Object", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Queue", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("DropTailQueue", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Channel", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("CsmaChannel", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("NetDevice", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("CsmaNetDevice", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("PacketSocket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Socket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpSocket", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpL4Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4L3Protocol", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4StaticRouting", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4Interface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("ArpIpv4Interface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("Ipv4LoopbackInterface", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("OnOffApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
|
||||
#endif
|
||||
|
||||
// Allow the user to override any of the defaults and the above Bind() at
|
||||
// run-time, via command-line arguments
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer n;
|
||||
n.Create (4);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (n);
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
// Explicitly create the channels required by the topology (shown above).
|
||||
//
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", DataRateValue (DataRate(5000000)));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
NetDeviceContainer d = csma.Install (n);
|
||||
|
||||
Ipv4AddressHelper ipv4;
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (d);
|
||||
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
//
|
||||
// Create a UdpEchoServer application on node one.
|
||||
//
|
||||
uint16_t port = 9; // well-known echo port number
|
||||
UdpEchoServerHelper server;
|
||||
server.SetPort (port);
|
||||
ApplicationContainer apps = server.Install (n.Get(1));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
//
|
||||
// Create a UdpEchoClient application to send UDP datagrams from node zero to
|
||||
// node one.
|
||||
//
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 1;
|
||||
Time interPacketInterval = Seconds (1.);
|
||||
UdpEchoClientHelper client;
|
||||
client.SetRemote (i.GetAddress (1), port);
|
||||
client.SetAppAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAppAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAppAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
apps = client.Install (n.Get (0));
|
||||
apps.Start (Seconds (2.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("udp-echo.tr");
|
||||
CsmaHelper::EnablePcapAll ("udp-echo");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../waf "$@"
|
||||
@@ -0,0 +1,261 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006,2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/contrib-module.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("Main");
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class Experiment
|
||||
{
|
||||
public:
|
||||
Experiment ();
|
||||
Experiment (std::string name);
|
||||
GnuplotDataset Run (const WifiHelper &wifi);
|
||||
private:
|
||||
void ReceivePacket (Ptr<Socket> socket);
|
||||
void SetPosition (Ptr<Node> node, Vector position);
|
||||
Vector GetPosition (Ptr<Node> node);
|
||||
void AdvancePosition (Ptr<Node> node);
|
||||
Ptr<Socket> SetupPacketReceive (Ptr<Node> node);
|
||||
|
||||
uint32_t m_bytesTotal;
|
||||
GnuplotDataset m_output;
|
||||
};
|
||||
|
||||
Experiment::Experiment ()
|
||||
: m_output ()
|
||||
{}
|
||||
|
||||
Experiment::Experiment (std::string name)
|
||||
: m_output (name)
|
||||
{
|
||||
m_output.SetStyle (GnuplotDataset::LINES);
|
||||
}
|
||||
|
||||
void
|
||||
Experiment::SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
Vector
|
||||
Experiment::GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
return mobility->GetPosition ();
|
||||
}
|
||||
|
||||
void
|
||||
Experiment::AdvancePosition (Ptr<Node> node)
|
||||
{
|
||||
Vector pos = GetPosition (node);
|
||||
double mbs = ((m_bytesTotal * 8.0) / 1000000);
|
||||
m_bytesTotal = 0;
|
||||
m_output.Add (pos.x, mbs);
|
||||
pos.x += 1.0;
|
||||
if (pos.x >= 210.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetPosition (node, pos);
|
||||
//std::cout << "x="<<pos.x << std::endl;
|
||||
Simulator::Schedule (Seconds (1.0), &Experiment::AdvancePosition, this, node);
|
||||
}
|
||||
|
||||
void
|
||||
Experiment::ReceivePacket (Ptr<Socket> socket)
|
||||
{
|
||||
Ptr<Packet> packet;
|
||||
while (packet = socket->Recv ())
|
||||
{
|
||||
m_bytesTotal += packet->GetSize ();
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Socket>
|
||||
Experiment::SetupPacketReceive (Ptr<Node> node)
|
||||
{
|
||||
TypeId tid = TypeId::LookupByName ("ns3::PacketSocketFactory");
|
||||
Ptr<Socket> sink = Socket::CreateSocket (node, tid);
|
||||
sink->Bind ();
|
||||
sink->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this));
|
||||
return sink;
|
||||
}
|
||||
|
||||
GnuplotDataset
|
||||
Experiment::Run (const WifiHelper &wifi)
|
||||
{
|
||||
m_bytesTotal = 0;
|
||||
|
||||
NodeContainer c;
|
||||
c.Create (2);
|
||||
|
||||
PacketSocketHelper packetSocket;
|
||||
packetSocket.Install (c);
|
||||
|
||||
NetDeviceContainer devices = wifi.Install (c);
|
||||
|
||||
MobilityHelper mobility;
|
||||
Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
|
||||
positionAlloc->Add (Vector (0.0, 0.0, 0.0));
|
||||
positionAlloc->Add (Vector (5.0, 0.0, 0.0));
|
||||
mobility.SetPositionAllocator (positionAlloc);
|
||||
mobility.SetMobilityModel ("ns3::StaticMobilityModel");
|
||||
|
||||
mobility.Install (c);
|
||||
|
||||
PacketSocketAddress socket;
|
||||
socket.SetSingleDevice(devices.Get (0)->GetIfIndex ());
|
||||
socket.SetPhysicalAddress (devices.Get (1)->GetAddress ());
|
||||
socket.SetProtocol (1);
|
||||
|
||||
OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (250)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
onoff.SetAttribute ("DataRate", DataRateValue (DataRate (60000000)));
|
||||
onoff.SetAttribute ("PacketSize", UintegerValue (2000));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (c.Get (0));
|
||||
apps.Start (Seconds (0.5));
|
||||
apps.Stop (Seconds (250.0));
|
||||
|
||||
Simulator::Schedule (Seconds (1.5), &Experiment::AdvancePosition, this, c.Get (1));
|
||||
Ptr<Socket> recvSink = SetupPacketReceive (c.Get (1));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
|
||||
return m_output;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// disable fragmentation
|
||||
Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200"));
|
||||
Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("2200"));
|
||||
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
Gnuplot gnuplot = Gnuplot ("reference-rates.png");
|
||||
|
||||
Experiment experiment;
|
||||
WifiHelper wifi;
|
||||
GnuplotDataset dataset;
|
||||
|
||||
wifi.SetMac ("ns3::AdhocWifiMac");
|
||||
wifi.SetPhy ("ns3::WifiPhy");
|
||||
|
||||
NS_LOG_DEBUG ("54");
|
||||
experiment = Experiment ("54mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-54mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("48");
|
||||
experiment = Experiment ("48mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-48mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("36");
|
||||
experiment = Experiment ("36mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-36mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("24");
|
||||
experiment = Experiment ("24mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-24mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("18");
|
||||
experiment = Experiment ("18mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-18mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("12");
|
||||
experiment = Experiment ("12mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-12mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("9");
|
||||
experiment = Experiment ("9mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-9mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("6");
|
||||
experiment = Experiment ("6mb");
|
||||
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager",
|
||||
"DataMode", StringValue ("wifia-6mbs"));
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
|
||||
gnuplot = Gnuplot ("rate-control.png");
|
||||
Config::SetDefault ("ns3::WifiPhy::Standard", StringValue ("holland"));
|
||||
|
||||
|
||||
NS_LOG_DEBUG ("arf");
|
||||
experiment = Experiment ("arf");
|
||||
wifi.SetRemoteStationManager ("ns3::ArfWifiManager");
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("aarf");
|
||||
experiment = Experiment ("aarf");
|
||||
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
NS_LOG_DEBUG ("ideal");
|
||||
experiment = Experiment ("ideal");
|
||||
wifi.SetRemoteStationManager ("ns3::IdealWifiManager");
|
||||
dataset = experiment.Run (wifi);
|
||||
gnuplot.AddDataset (dataset);
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006,2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/common-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/contrib-module.h"
|
||||
#include "ns3/wifi-module.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
void
|
||||
DevTxTrace (std::string context, Ptr<const Packet> p, Mac48Address address)
|
||||
{
|
||||
std::cout << " TX to=" << address << " p: " << *p << std::endl;
|
||||
}
|
||||
void
|
||||
DevRxTrace (std::string context, Ptr<const Packet> p, Mac48Address address)
|
||||
{
|
||||
std::cout << " RX from=" << address << " p: " << *p << std::endl;
|
||||
}
|
||||
void
|
||||
PhyRxOkTrace (std::string context, Ptr<const Packet> packet, double snr, WifiMode mode, enum WifiPreamble preamble)
|
||||
{
|
||||
std::cout << "PHYRXOK mode=" << mode << " snr=" << snr << " " << *packet << std::endl;
|
||||
}
|
||||
void
|
||||
PhyRxErrorTrace (std::string context, Ptr<const Packet> packet, double snr)
|
||||
{
|
||||
std::cout << "PHYRXERROR snr=" << snr << " " << *packet << std::endl;
|
||||
}
|
||||
void
|
||||
PhyTxTrace (std::string context, Ptr<const Packet> packet, WifiMode mode, WifiPreamble preamble, uint8_t txPower)
|
||||
{
|
||||
std::cout << "PHYTX mode=" << mode << " " << *packet << std::endl;
|
||||
}
|
||||
void
|
||||
PhyStateTrace (std::string context, Time start, Time duration, enum WifiPhy::State state)
|
||||
{
|
||||
std::cout << " state=";
|
||||
switch (state) {
|
||||
case WifiPhy::TX:
|
||||
std::cout << "tx ";
|
||||
break;
|
||||
case WifiPhy::SYNC:
|
||||
std::cout << "sync ";
|
||||
break;
|
||||
case WifiPhy::CCA_BUSY:
|
||||
std::cout << "cca-busy";
|
||||
break;
|
||||
case WifiPhy::IDLE:
|
||||
std::cout << "idle ";
|
||||
break;
|
||||
}
|
||||
std::cout << " start="<<start<<" duration="<<duration<<std::endl;
|
||||
}
|
||||
|
||||
static void
|
||||
SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
static Vector
|
||||
GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
|
||||
return mobility->GetPosition ();
|
||||
}
|
||||
|
||||
static void
|
||||
AdvancePosition (Ptr<Node> node)
|
||||
{
|
||||
Vector pos = GetPosition (node);
|
||||
pos.x += 5.0;
|
||||
if (pos.x >= 210.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetPosition (node, pos);
|
||||
//std::cout << "x="<<pos.x << std::endl;
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
// enable rts cts all the time.
|
||||
Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("0"));
|
||||
// disable fragmentation
|
||||
Config::SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", StringValue ("2200"));
|
||||
|
||||
WifiHelper wifi;
|
||||
MobilityHelper mobility;
|
||||
NodeContainer stas;
|
||||
NodeContainer ap;
|
||||
NetDeviceContainer staDevs;
|
||||
PacketSocketHelper packetSocket;
|
||||
|
||||
stas.Create (2);
|
||||
ap.Create (1);
|
||||
|
||||
// give packet socket powers to nodes.
|
||||
packetSocket.Install (stas);
|
||||
packetSocket.Install (ap);
|
||||
|
||||
Ptr<WifiChannel> channel = CreateObject<WifiChannel> ();
|
||||
channel->SetPropagationDelayModel (CreateObject<ConstantSpeedPropagationDelayModel> ());
|
||||
Ptr<LogDistancePropagationLossModel> log = CreateObject<LogDistancePropagationLossModel> ();
|
||||
log->SetReferenceModel (CreateObject<FriisPropagationLossModel> ());
|
||||
channel->SetPropagationLossModel (log);
|
||||
|
||||
Ssid ssid = Ssid ("wifi-default");
|
||||
wifi.SetPhy ("ns3::WifiPhy");
|
||||
wifi.SetRemoteStationManager ("ns3::ArfWifiManager");
|
||||
// setup stas.
|
||||
wifi.SetMac ("ns3::NqstaWifiMac",
|
||||
"Ssid", SsidValue (ssid),
|
||||
"ActiveProbing", BooleanValue (false));
|
||||
staDevs = wifi.Install (stas, channel);
|
||||
// setup ap.
|
||||
wifi.SetMac ("ns3::NqapWifiMac", "Ssid", SsidValue (ssid),
|
||||
"BeaconGeneration", BooleanValue (true),
|
||||
"BeaconInterval", TimeValue (Seconds (2.5)));
|
||||
wifi.Install (ap, channel);
|
||||
|
||||
// mobility.
|
||||
mobility.Install (stas);
|
||||
mobility.Install (ap);
|
||||
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, ap.Get (0));
|
||||
|
||||
PacketSocketAddress socket;
|
||||
socket.SetSingleDevice(staDevs.Get (0)->GetIfIndex ());
|
||||
socket.SetPhysicalAddress (staDevs.Get (1)->GetAddress ());
|
||||
socket.SetProtocol (1);
|
||||
|
||||
OnOffHelper onoff ("ns3::PacketSocketFactory", Address (socket));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (42)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
ApplicationContainer apps = onoff.Install (stas.Get (0));
|
||||
apps.Start (Seconds (0.5));
|
||||
apps.Stop (Seconds (43.0));
|
||||
|
||||
Simulator::Stop (Seconds (44.0));
|
||||
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Tx", MakeCallback (&DevTxTrace));
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Rx", MakeCallback (&DevRxTrace));
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Phy/RxOk", MakeCallback (&PhyRxOkTrace));
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Phy/RxError", MakeCallback (&PhyRxErrorTrace));
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Phy/Tx", MakeCallback (&PhyTxTrace));
|
||||
Config::Connect ("/NodeList/*/DeviceList/*/Phy/State", MakeCallback (&PhyStateTrace));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+56
-8
@@ -1,13 +1,61 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import Params
|
||||
|
||||
def build(bld):
|
||||
def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
|
||||
obj = bld.create_obj('cpp', 'program')
|
||||
obj.target = name
|
||||
obj.uselib_local = ["ns3-%s" % dep for dep in deps]
|
||||
obj.source = source
|
||||
return obj
|
||||
|
||||
obj = create_ns_prog('simple-p2p', 'simple-p2p.cc', deps=['p2p', 'internet-node'])
|
||||
obj = bld.create_ns3_program('mixed-wireless',
|
||||
['core', 'simulator', 'mobility', 'wifi', 'point-to-point', 'internet-stack'])
|
||||
obj.source = 'mixed-wireless.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-global-routing',
|
||||
['point-to-point', 'internet-stack', 'global-routing'])
|
||||
obj.source = 'simple-global-routing.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-alternate-routing',
|
||||
['point-to-point', 'internet-stack', 'global-routing'])
|
||||
obj.source = 'simple-alternate-routing.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-error-model',
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'simple-error-model.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-one-subnet',
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-one-subnet.cc'
|
||||
|
||||
obj = bld.create_ns3_program('udp-echo',
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'udp-echo.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-broadcast',
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-broadcast.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-packet-socket',
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-packet-socket.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-multicast',
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-multicast.cc'
|
||||
|
||||
obj = bld.create_ns3_program( 'mixed-global-routing',
|
||||
['point-to-point', 'internet-stack', 'global-routing' , 'csma-cd'])
|
||||
obj.source = 'mixed-global-routing.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-point-to-point-olsr',
|
||||
['point-to-point', 'internet-stack', 'olsr'])
|
||||
obj.source = 'simple-point-to-point-olsr.cc'
|
||||
|
||||
obj = bld.create_ns3_program('tcp-large-transfer',
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'tcp-large-transfer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('wifi-adhoc',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'wifi-adhoc.cc'
|
||||
|
||||
obj = bld.create_ns3_program('wifi-ap',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'wifi-ap.cc'
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName, "csma-broadcast")
|
||||
@@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName, "csma-multicast")
|
||||
@@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName, "csma-one-subnet")
|
||||
@@ -0,0 +1,13 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
"csma-packet-socket")
|
||||
@@ -0,0 +1,13 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
"simple-error-model")
|
||||
@@ -0,0 +1,13 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
"simple-global-routing")
|
||||
@@ -0,0 +1,13 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
"simple-point-to-point-olsr")
|
||||
@@ -0,0 +1,13 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName,
|
||||
"tcp-large-transfer")
|
||||
@@ -0,0 +1,12 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Generic trace-comparison-type regression test."""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tracediff
|
||||
|
||||
def run(verbose, generate, refDirName):
|
||||
"""Execute a test."""
|
||||
|
||||
return tracediff.run_test(verbose, generate, refDirName, "udp-echo")
|
||||
+1
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../waf "$@"
|
||||
@@ -0,0 +1,142 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2008 University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Tom Henderson <tomh@tomh.org>
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("AttributeValueSample");
|
||||
|
||||
//
|
||||
// This is a basic example of how to use the attribute system to
|
||||
// set and get a value in the underlying system; namely, an unsigned
|
||||
// integer of the maximum number of packets in a queue
|
||||
//
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
LogComponentEnable ("AttributeValueSample", LOG_LEVEL_INFO);
|
||||
|
||||
// By default, the MaxPackets attribute has a value of 100 packets
|
||||
// (this default can be observed in the function DropTailQueue::GetTypeId)
|
||||
//
|
||||
// Here, we set it to 80 packets. We could use one of two value types:
|
||||
// a string-based value or a UintegerValue value
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
|
||||
// The below function call is redundant
|
||||
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));
|
||||
|
||||
// Allow the user to override any of the defaults and the above
|
||||
// SetDefaults() at run-time, via command-line arguments
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Now, we will create a few objects using the low-level API
|
||||
Ptr<Node> n0 = CreateObject<Node> ();
|
||||
|
||||
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
|
||||
n0->AddDevice (net0);
|
||||
|
||||
Ptr<Queue> q = CreateObject<DropTailQueue> ();
|
||||
net0->SetQueue(q);
|
||||
|
||||
// At this point, we have created a single node (Node 0) and a
|
||||
// single PointToPointNetDevice (NetDevice 0) and added a
|
||||
// DropTailQueue to it.
|
||||
|
||||
// Now, we can manipulate the MaxPackets value of the already
|
||||
// instantiated DropTailQueue. Here are various ways to do that.
|
||||
|
||||
// We assume that a smart pointer (Ptr) to a relevant network device
|
||||
// is in hand; here, it is the net0 pointer.
|
||||
|
||||
// 1. Pointer-based access
|
||||
//
|
||||
// One way to change the value is to access a pointer to the
|
||||
// underlying queue and modify its attribute.
|
||||
//
|
||||
// First, we observe that we can get a pointer to the (base class)
|
||||
// queue via the PointToPointNetDevice attributes, where it is called
|
||||
// TxQueue
|
||||
PointerValue ptr;
|
||||
net0->GetAttribute ("TxQueue", ptr);
|
||||
Ptr<Queue> txQueue = ptr.Get<Queue> ();
|
||||
|
||||
// Using the GetObject function, we can perform a safe downcast
|
||||
// to a DropTailQueue, where MaxPackets is a member
|
||||
Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> ();
|
||||
NS_ASSERT (dtq);
|
||||
|
||||
// Next, we can get the value of an attribute on this queue
|
||||
// We have introduced wrapper "Value" classes for the underlying
|
||||
// data types, similar to Java wrappers around these types, since
|
||||
// the attribute system stores values and not disparate types.
|
||||
// Here, the attribute value is assigned to a Uinteger, and
|
||||
// the Get() method on this value produces the (unwrapped) uint32_t.
|
||||
UintegerValue limit;
|
||||
dtq->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets");
|
||||
|
||||
// Note that the above downcast is not really needed; we could have
|
||||
// done the same using the Ptr<Queue> even though the attribute
|
||||
// is a member of the subclass
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets");
|
||||
|
||||
// Now, let's set it to another value (60 packets)
|
||||
txQueue->SetAttribute("MaxPackets", UintegerValue (60));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets");
|
||||
|
||||
// 2. Namespace-based access
|
||||
//
|
||||
// An alternative way to get at the attribute is to use the configuration
|
||||
// namespace. Here, this attribute resides on a known path in this
|
||||
// namespace; this approach is useful if one doesn't have access to
|
||||
// the underlying pointers and would like to configure a specific
|
||||
// attribute with a single statement.
|
||||
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("4. txQueue limit changed through namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
|
||||
// we could have also used wildcards to set this value for all nodes
|
||||
// and all net devices (which in this simple example has the same
|
||||
// effect as the previous Set())
|
||||
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15));
|
||||
txQueue->GetAttribute ("MaxPackets", limit);
|
||||
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " <<
|
||||
limit.Get () << " packets");
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 University of Washington
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include "ns3/debug.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/drop-tail.h"
|
||||
#include "ns3/layer-connector.h"
|
||||
#include "ns3/channel.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Internet Node
|
||||
// ===========================================================================
|
||||
class FakeInternetNode : public LayerConnectorUpper
|
||||
{
|
||||
public:
|
||||
FakeInternetNode ();
|
||||
~FakeInternetNode ();
|
||||
|
||||
void Doit (void);
|
||||
|
||||
protected:
|
||||
bool UpperDoSendUp (Packet &p);
|
||||
bool UpperDoPull (Packet &p);
|
||||
|
||||
DropTailQueue m_dtqOutbound;
|
||||
DropTailQueue m_dtqInbound;
|
||||
};
|
||||
|
||||
FakeInternetNode::FakeInternetNode ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::FakeInternetNode ()");
|
||||
}
|
||||
|
||||
FakeInternetNode::~FakeInternetNode ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::~FakeInternetNode ()");
|
||||
}
|
||||
|
||||
void
|
||||
FakeInternetNode::Doit (void)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::Doit ()");
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::Doit (): **** Send outbound packet");
|
||||
Packet p;
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
UpperNotify();
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (" << &p << ")");
|
||||
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::UpperDoSendUp (): **** Receive inbound packet");
|
||||
m_dtqInbound.Enqueue(p);
|
||||
return m_dtqInbound.Dequeue(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakeInternetNode::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeInternetNode::DoPull (" << &p << ")");
|
||||
|
||||
return m_dtqOutbound.Dequeue(p);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Physical Layer
|
||||
// ===========================================================================
|
||||
class FakePhysicalLayer :
|
||||
public LayerConnectorLower,
|
||||
public LayerConnectorUpper
|
||||
{
|
||||
public:
|
||||
FakePhysicalLayer ();
|
||||
~FakePhysicalLayer ();
|
||||
|
||||
protected:
|
||||
bool LowerDoNotify (LayerConnectorUpper *upper);
|
||||
bool UpperDoSendUp (Packet &p);
|
||||
bool UpperDoPull (Packet &p);
|
||||
|
||||
DropTailQueue m_dtqInbound;
|
||||
DropTailQueue m_dtqOutbound;
|
||||
};
|
||||
|
||||
FakePhysicalLayer::FakePhysicalLayer ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::FakePhysicalLayer ()");
|
||||
}
|
||||
|
||||
FakePhysicalLayer::~FakePhysicalLayer ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::~FakePhysicalLayer ()");
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::LowerDoNotify (LayerConnectorUpper *upper)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify ()");
|
||||
|
||||
Packet p;
|
||||
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Starting pull");
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
m_upperPartner->UpperPull(p);
|
||||
|
||||
m_dtqOutbound.Enqueue(p);
|
||||
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::LowerDoNotify (): Got bits, Notify lower");
|
||||
|
||||
NS_ASSERT(m_lowerPartner);
|
||||
return m_lowerPartner->LowerNotify(this);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoSendUp (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::UpperDoSendUp (" << &p << ")");
|
||||
|
||||
NS_ASSERT(m_upperPartner);
|
||||
return m_upperPartner->UpperSendUp(p);
|
||||
}
|
||||
|
||||
bool
|
||||
FakePhysicalLayer::UpperDoPull (Packet &p)
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakePhysicalLayer::DoPull (" << &p << ")");
|
||||
|
||||
return m_dtqOutbound.Dequeue(p);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Cook up a simplistic Channel, just to add any moby hack we feel like
|
||||
// ===========================================================================
|
||||
class FakeChannel : public Channel
|
||||
{
|
||||
public:
|
||||
FakeChannel ();
|
||||
~FakeChannel ();
|
||||
};
|
||||
|
||||
FakeChannel::FakeChannel ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeChannel::FakeChannel ()");
|
||||
}
|
||||
|
||||
FakeChannel::~FakeChannel ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("FakeChannel::~FakeChannel ()");
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
NS_DEBUG_UNCOND("Channel Hackorama");
|
||||
|
||||
#if 0
|
||||
DebugComponentEnable("Queue");
|
||||
DebugComponentEnable("DropTailQueue");
|
||||
DebugComponentEnable("LayerConnector");
|
||||
DebugComponentEnable("Channel");
|
||||
#endif
|
||||
|
||||
FakeInternetNode node1, node2, node3, node4;
|
||||
FakePhysicalLayer phys1, phys2, phys3, phys4;
|
||||
FakeChannel channel;
|
||||
Packet pkt;
|
||||
|
||||
// all the hassle above lets us do something very simple here
|
||||
|
||||
node1.ConnectToLower(phys1);
|
||||
phys1.ConnectToUpper(node1);
|
||||
phys1.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys1);
|
||||
|
||||
node2.ConnectToLower(phys2);
|
||||
phys2.ConnectToUpper(node2);
|
||||
phys2.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys2);
|
||||
|
||||
node3.ConnectToLower(phys3);
|
||||
phys3.ConnectToUpper(node3);
|
||||
phys3.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys3);
|
||||
|
||||
node4.ConnectToLower(phys4);
|
||||
phys4.ConnectToUpper(node4);
|
||||
phys4.ConnectToLower(channel);
|
||||
channel.ConnectToUpper(phys4);
|
||||
|
||||
node1.Doit();
|
||||
node2.Doit();
|
||||
node3.Doit();
|
||||
node4.Doit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/component-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class AnObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
AnObject (int a, double b);
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnObject::iid = MakeInterfaceId ("AnObject", Object::iid);
|
||||
const ClassId AnObject::cid = MakeClassId<AnObject, int, double> ("AnObject", AnObject::iid);
|
||||
|
||||
AnObject::AnObject (int a, double b)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnObject::iid);
|
||||
}
|
||||
void
|
||||
AnObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<AnObject> anObject = ComponentManager::Create<AnObject,int,double> (AnObject::cid, AnObject::iid, 10, 20.0);
|
||||
NS_ASSERT (anObject != 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/debug.h"
|
||||
|
||||
NS_DEBUG_COMPONENT_DEFINE ("MyComponentB");
|
||||
|
||||
namespace foo {
|
||||
|
||||
void OneFunction (void)
|
||||
{
|
||||
NS_DEBUG ("OneFunction debug");
|
||||
}
|
||||
|
||||
}; // namespace foo
|
||||
@@ -1,27 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/debug.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
NS_DEBUG_COMPONENT_DEFINE ("MyComponentA");
|
||||
|
||||
// declare other function
|
||||
namespace foo {
|
||||
void OneFunction (void);
|
||||
}
|
||||
|
||||
int main (int argc, int argv)
|
||||
{
|
||||
NS_DEBUG ("nargc="<<argc);
|
||||
|
||||
foo::OneFunction ();
|
||||
|
||||
NS_DEBUG ("other debug output");
|
||||
|
||||
int a;
|
||||
a = 0;
|
||||
|
||||
NS_ASSERT (a == 0);
|
||||
NS_ASSERT_MSG (a == 0, "my msg");
|
||||
NS_ASSERT (a != 0);
|
||||
NS_ASSERT_MSG (a != 0, "my 2 msg");
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include <string>
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/debug.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
//
|
||||
// This sample file demonstrates how to take some simple member
|
||||
// variables and hook them into the default variable system
|
||||
// Typically, you will establish a static variable to maintain the current
|
||||
// value of the default parameter. Then as other code require the values of
|
||||
// the defaults, they query them with GetValue() to get the present value.
|
||||
static BooleanDefaultValue defaultTestBool1 ("testBool1", "helpBool", true);
|
||||
static IntegerDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
|
||||
static IntegerDefaultValue<uint32_t> defaultTestInt2 ("testInt2", "helpInt2", 47);
|
||||
|
||||
//
|
||||
// This test class demonstrates the declaration of variables that
|
||||
// may be overridden by the default-value system
|
||||
//
|
||||
// You will see in the core ns-3 modules that many member variables
|
||||
// can be overridden in this manner
|
||||
//
|
||||
class TestClass {
|
||||
public:
|
||||
TestClass();
|
||||
virtual ~TestClass () {}
|
||||
|
||||
bool m_testBool1;
|
||||
int m_testInt1;
|
||||
uint32_t m_testInt2;
|
||||
};
|
||||
|
||||
//
|
||||
// In the constructor, you can assign default values in the initializer
|
||||
// list such as below; note that the instance of the created TestClass
|
||||
// will have the values as dictated by the current value of the default.
|
||||
// This means that the behavior of this class can be changed on the fly with
|
||||
// calls to bind.
|
||||
//
|
||||
TestClass::TestClass () :
|
||||
m_testBool1(defaultTestBool1.GetValue()),
|
||||
m_testInt1(defaultTestInt1.GetValue()),
|
||||
m_testInt2(defaultTestInt2.GetValue())
|
||||
{
|
||||
}
|
||||
using std::cout;
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
//The following allows the default values established so far to be hooked
|
||||
//into the command line argument processing unit. Essentially, the command
|
||||
//line processor is aware of the DefaultValues that have been registered, and
|
||||
//will accept command line overrides of these. The call automatically
|
||||
//provides a --help option in addition to allowing overrides of defaults.
|
||||
uint32_t loops = 0;
|
||||
CommandLine::AddArgValue("loops","a test of the command line",loops);
|
||||
CommandLine::Parse(argc,argv);
|
||||
|
||||
//utilize the loops variable to show that it can be read from the command line
|
||||
if(loops>0)
|
||||
{
|
||||
cout<<"You requested "<<loops<<" iterations of a loop";
|
||||
for(uint32_t i=0;i<loops;++i)
|
||||
cout<<"iteration "<<i;
|
||||
}
|
||||
|
||||
// Before objects are instantiated in your simulation script, you have
|
||||
// the opportunity to overwrite any default value in the system.
|
||||
// The Bind () method allows you to specify the name (string) of the
|
||||
// global variable and value (string) to overwrite the default.
|
||||
// Here, the default value of 33 for testInt1 is overwritten with 57
|
||||
//
|
||||
Bind("testInt1", "57");
|
||||
|
||||
TestClass* testclass = new TestClass ();
|
||||
NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
|
||||
NS_DEBUG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
|
||||
NS_DEBUG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
|
||||
delete testclass;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NodeContainer nodes;
|
||||
|
||||
// create an array of empty nodes for testing purposes
|
||||
nodes.Create (120);
|
||||
|
||||
MobilityHelper mobility;
|
||||
// setup the grid itself: objects are layed out
|
||||
// started from (-100,-100) with 20 objects per row,
|
||||
// the x interval between each object is 5 meters
|
||||
// and the y interval between each object is 20 meters
|
||||
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
|
||||
"MinX", DoubleValue (-100.0),
|
||||
"MinY", DoubleValue (-100.0),
|
||||
"DeltaX", DoubleValue (5.0),
|
||||
"DeltaY", DoubleValue (20.0),
|
||||
"GridWidth", UintegerValue (20),
|
||||
"LayoutType", StringValue ("RowFirst"));
|
||||
// each object will be attached a static position.
|
||||
// i.e., once set by the "position allocator", the
|
||||
// position will never change.
|
||||
mobility.SetMobilityModel ("ns3::StaticMobilityModel");
|
||||
|
||||
// finalize the setup by attaching to each object
|
||||
// in the input array a position and initializing
|
||||
// this position with the calculated coordinates.
|
||||
mobility.Install (nodes);
|
||||
|
||||
// iterate our nodes and print their position.
|
||||
for (NodeContainer::Iterator j = nodes.Begin ();
|
||||
j != nodes.End (); ++j)
|
||||
{
|
||||
Ptr<Node> object = *j;
|
||||
Ptr<MobilityModel> position = object->GetObject<MobilityModel> ();
|
||||
NS_ASSERT (position != 0);
|
||||
Vector pos = position->GetPosition ();
|
||||
std::cout << "x=" << pos.x << ", y=" << pos.y << ", z=" << pos.z << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
#include "ns3/object.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
class AnObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
AnObject ();
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnObject::iid = MakeInterfaceId ("AnObject", Object::iid);
|
||||
|
||||
AnObject::AnObject ()
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnObject::iid);
|
||||
}
|
||||
void
|
||||
AnObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
class AnotherObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
AnotherObject (int a);
|
||||
private:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId AnotherObject::iid = MakeInterfaceId ("AnotherObject", Object::iid);
|
||||
|
||||
AnotherObject::AnotherObject (int a)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnotherObject::iid);
|
||||
}
|
||||
void
|
||||
AnotherObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
class YetAnotherObject : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
YetAnotherObject (int a);
|
||||
private:
|
||||
virtual void DoDispose (void);
|
||||
};
|
||||
|
||||
const InterfaceId YetAnotherObject::iid = MakeInterfaceId ("YetAnotherObject", Object::iid);
|
||||
|
||||
YetAnotherObject::YetAnotherObject (int a)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (YetAnotherObject::iid);
|
||||
// aggregated directly to another object.
|
||||
AddInterface (Create<AnObject> ());
|
||||
}
|
||||
void
|
||||
YetAnotherObject::DoDispose (void)
|
||||
{
|
||||
// Do your work here.
|
||||
// chain up
|
||||
Object::DoDispose ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Ptr<Object> p;
|
||||
Ptr<AnObject> anObject;
|
||||
Ptr<AnotherObject> anotherObject;
|
||||
Ptr<YetAnotherObject> yetAnotherObject;
|
||||
|
||||
p = Create<AnObject> ();
|
||||
// p gives you access to AnObject's interface
|
||||
anObject = p->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
// p does not give you access to AnotherObject's interface
|
||||
anotherObject = p->QueryInterface<AnotherObject> (AnotherObject::iid);
|
||||
NS_ASSERT (anotherObject == 0);
|
||||
|
||||
anotherObject = Create<AnotherObject> (1);
|
||||
// AnotherObject does not give you access to AnObject's interface
|
||||
anObject = anotherObject->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject == 0);
|
||||
|
||||
// aggregate the two objects
|
||||
p->AddInterface (anotherObject);
|
||||
// p gives you access to AnObject's interface
|
||||
anObject = p->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
// p gives you access to AnotherObject's interface
|
||||
anotherObject = p->QueryInterface<AnotherObject> (AnotherObject::iid);
|
||||
NS_ASSERT (anotherObject != 0);
|
||||
|
||||
|
||||
yetAnotherObject = Create<YetAnotherObject> (2);
|
||||
// gives you acess to AnObject interface too.
|
||||
anObject = yetAnotherObject->QueryInterface<AnObject> (AnObject::iid);
|
||||
NS_ASSERT (anObject != 0);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/* A sample Header implementation
|
||||
*/
|
||||
class MyHeader : public Header
|
||||
{
|
||||
public:
|
||||
|
||||
MyHeader ();
|
||||
virtual ~MyHeader ();
|
||||
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual void Print (std::ostream &os) const;
|
||||
virtual void Serialize (Buffer::Iterator start) const;
|
||||
virtual uint32_t Deserialize (Buffer::Iterator start);
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
private:
|
||||
uint16_t m_data;
|
||||
};
|
||||
|
||||
MyHeader::MyHeader ()
|
||||
{
|
||||
// we must provide a public default constructor,
|
||||
// implicit or explicit, but never private.
|
||||
}
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
|
||||
TypeId
|
||||
MyHeader::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MyHeader")
|
||||
.SetParent<Header> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
MyHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
void
|
||||
MyHeader::Print (std::ostream &os) const
|
||||
{
|
||||
// This method is invoked by the packet printing
|
||||
// routines to print the content of my header.
|
||||
os << "data=" << m_data << std::endl;
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::GetSerializedSize (void) const
|
||||
{
|
||||
// we reserve 2 bytes for our header.
|
||||
return 2;
|
||||
}
|
||||
void
|
||||
MyHeader::Serialize (Buffer::Iterator start) const
|
||||
{
|
||||
// we can serialize two bytes at the start of the buffer.
|
||||
// we write them in network byte order.
|
||||
start.WriteHtonU16 (m_data);
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::Deserialize (Buffer::Iterator start)
|
||||
{
|
||||
// we can deserialize two bytes from the start of the buffer.
|
||||
// we read them in network byte order and store them
|
||||
// in host byte order.
|
||||
m_data = start.ReadNtohU16 ();
|
||||
|
||||
// we return the number of bytes effectively read.
|
||||
return 2;
|
||||
}
|
||||
|
||||
void
|
||||
MyHeader::SetData (uint16_t data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
uint16_t
|
||||
MyHeader::GetData (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// instantiate a header.
|
||||
MyHeader sourceHeader;
|
||||
sourceHeader.SetData (2);
|
||||
|
||||
// instantiate a packet
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
|
||||
// and store my header into the packet.
|
||||
p->AddHeader (sourceHeader);
|
||||
|
||||
// print the content of my packet on the standard output.
|
||||
p->Print (std::cout);
|
||||
|
||||
// you can now remove the header from the packet:
|
||||
MyHeader destinationHeader;
|
||||
p->RemoveHeader (destinationHeader);
|
||||
|
||||
// and check that the destination and source
|
||||
// headers contain the same values.
|
||||
NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006,2007 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -49,7 +48,7 @@ void DefaultPrint (void)
|
||||
{
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
// and add 3 headers to this packet.
|
||||
Packet p (1000);
|
||||
Ptr<Packet> p = Create<Packet> (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
@@ -57,48 +56,39 @@ void DefaultPrint (void)
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
std::cout << "full packet size=" << p->GetSize () << std::endl;
|
||||
// Here, invoke the default Print routine, directed to std out
|
||||
p.Print (std::cout);
|
||||
p->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// Now, we fragment our packet in 3 consecutive pieces.
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
Ptr<Packet> p1 = p->CreateFragment (0, 2);
|
||||
Ptr<Packet> p2 = p->CreateFragment (2, 1000);
|
||||
Ptr<Packet> p3 = p->CreateFragment (1002, 26);
|
||||
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout);
|
||||
p1->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout);
|
||||
p2->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout);
|
||||
p3->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
// And, finally, we re-aggregate the 3 consecutive pieces.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
Ptr<Packet> aggregate = p1->Copy ();
|
||||
aggregate->AddAtEnd (p2);
|
||||
aggregate->AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout);
|
||||
aggregate->Print (std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// The below functions are used in place of default versions, in the
|
||||
// non-default case below. For instance, DoPrintIpv4Header will print
|
||||
// out less IPv4 header information than the default print function
|
||||
void
|
||||
DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size,
|
||||
std::string &name, struct PacketPrinter::FragmentInformation info)
|
||||
{
|
||||
os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
|
||||
}
|
||||
void
|
||||
DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
|
||||
struct PacketPrinter::FragmentInformation info)
|
||||
@@ -129,19 +119,15 @@ void NonDefaultPrint (void)
|
||||
// set a string separator automatically inserted
|
||||
// between each call to a printing function.
|
||||
printer.SetSeparator (" - ");
|
||||
// set the default print function: invoked if no
|
||||
// specialized function has been provided for a header
|
||||
// or trailer
|
||||
printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
|
||||
// set the payload print function
|
||||
printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
|
||||
printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload));
|
||||
// set the print function for the header type Ipv4Header.
|
||||
printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
|
||||
printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
|
||||
MakeCallback (&DoPrintIpv4HeaderFragment));
|
||||
|
||||
|
||||
// We create a packet with 1000 bytes of zero payload
|
||||
Packet p (1000);
|
||||
Ptr<Packet> p = Create<Packet> (1000);
|
||||
Ipv4Header ipv4;
|
||||
UdpHeader udp;
|
||||
ipv4.SetSource (Ipv4Address ("192.168.0.1"));
|
||||
@@ -149,35 +135,35 @@ void NonDefaultPrint (void)
|
||||
udp.SetSource (1025);
|
||||
udp.SetDestination (80);
|
||||
udp.SetPayloadSize (1000);
|
||||
p.AddHeader (udp);
|
||||
p.AddHeader (ipv4);
|
||||
p->AddHeader (udp);
|
||||
p->AddHeader (ipv4);
|
||||
|
||||
std::cout << "full packet size=" << p.GetSize () << std::endl;
|
||||
p.Print (std::cout, printer);
|
||||
std::cout << "full packet size=" << p->GetSize () << std::endl;
|
||||
p->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
// fragment our packet in 3 pieces
|
||||
Packet p1 = p.CreateFragment (0, 2);
|
||||
Packet p2 = p.CreateFragment (2, 1000);
|
||||
Packet p3 = p.CreateFragment (1002, 26);
|
||||
Ptr<Packet> p1 = p->CreateFragment (0, 2);
|
||||
Ptr<Packet> p2 = p->CreateFragment (2, 1000);
|
||||
Ptr<Packet> p3 = p->CreateFragment (1002, 26);
|
||||
std::cout << "fragment1" << std::endl;
|
||||
p1.Print (std::cout, printer);
|
||||
p1->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment2" << std::endl;
|
||||
p2.Print (std::cout, printer);
|
||||
p2->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
std::cout << "fragment3" << std::endl;
|
||||
p3.Print (std::cout, printer);
|
||||
p3->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
|
||||
// aggregate all 3 fragments of the original packet
|
||||
// to reconstruct a copy of the original packet.
|
||||
Packet aggregate = p1;
|
||||
aggregate.AddAtEnd (p2);
|
||||
aggregate.AddAtEnd (p3);
|
||||
Ptr<Packet> aggregate = p1->Copy ();
|
||||
aggregate->AddAtEnd (p2);
|
||||
aggregate->AddAtEnd (p3);
|
||||
std::cout << "aggregated" << std::endl;
|
||||
aggregate.Print (std::cout, printer);
|
||||
aggregate->Print (std::cout, printer);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006,2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ns3/tag.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
// define this class in a public header
|
||||
class MyTag : public Tag
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
virtual TypeId GetInstanceTypeId (void) const;
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
virtual void Serialize (TagBuffer i) const;
|
||||
virtual void Deserialize (TagBuffer i);
|
||||
virtual void Print (std::ostream &os) const;
|
||||
|
||||
// these are our accessors to our tag structure
|
||||
void SetSimpleValue (uint8_t value);
|
||||
uint8_t GetSimpleValue (void) const;
|
||||
private:
|
||||
uint8_t m_simpleValue;
|
||||
};
|
||||
|
||||
TypeId
|
||||
MyTag::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MyTag")
|
||||
.SetParent<Tag> ()
|
||||
.AddConstructor<MyTag> ()
|
||||
.AddAttribute ("SimpleValue",
|
||||
"A simple value",
|
||||
EmptyAttributeValue (),
|
||||
MakeUintegerAccessor (&MyTag::GetSimpleValue),
|
||||
MakeUintegerChecker<uint8_t> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
MyTag::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
uint32_t
|
||||
MyTag::GetSerializedSize (void) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
void
|
||||
MyTag::Serialize (TagBuffer i) const
|
||||
{
|
||||
i.WriteU8 (m_simpleValue);
|
||||
}
|
||||
void
|
||||
MyTag::Deserialize (TagBuffer i)
|
||||
{
|
||||
m_simpleValue = i.ReadU8 ();
|
||||
}
|
||||
void
|
||||
MyTag::Print (std::ostream &os) const
|
||||
{
|
||||
os << "v=" << (uint32_t)m_simpleValue;
|
||||
}
|
||||
void
|
||||
MyTag::SetSimpleValue (uint8_t value)
|
||||
{
|
||||
m_simpleValue = value;
|
||||
}
|
||||
uint8_t
|
||||
MyTag::GetSimpleValue (void) const
|
||||
{
|
||||
return m_simpleValue;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
// create a tag.
|
||||
MyTag tag;
|
||||
tag.SetSimpleValue (0x56);
|
||||
|
||||
// store the tag in a packet.
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
p->AddTag (tag);
|
||||
|
||||
// create a copy of the packet
|
||||
Ptr<Packet> aCopy = p->Copy ();
|
||||
|
||||
// read the tag from the packet copy
|
||||
MyTag tagCopy;
|
||||
p->FindFirstMatchingTag (tagCopy);
|
||||
|
||||
// the copy and the original are the same !
|
||||
NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
|
||||
|
||||
aCopy->PrintTags (std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/header.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
/* A sample Header implementation
|
||||
*/
|
||||
class MyHeader : public Header {
|
||||
public:
|
||||
MyHeader ();
|
||||
virtual ~MyHeader ();
|
||||
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
private:
|
||||
virtual std::string DoGetName (void) const;
|
||||
virtual void PrintTo (std::ostream &os) const;
|
||||
virtual void SerializeTo (Buffer::Iterator start) const;
|
||||
virtual uint32_t DeserializeFrom (Buffer::Iterator start);
|
||||
virtual uint32_t GetSerializedSize (void) const;
|
||||
|
||||
uint16_t m_data;
|
||||
};
|
||||
|
||||
MyHeader::MyHeader ()
|
||||
{}
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
std::string
|
||||
MyHeader::DoGetName (void) const
|
||||
{
|
||||
return "MyHeader";
|
||||
}
|
||||
void
|
||||
MyHeader::PrintTo (std::ostream &os) const
|
||||
{
|
||||
os << "MyHeader data=" << m_data << std::endl;
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::GetSerializedSize (void) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
void
|
||||
MyHeader::SerializeTo (Buffer::Iterator start) const
|
||||
{
|
||||
// serialize in head of buffer
|
||||
start.WriteHtonU16 (m_data);
|
||||
}
|
||||
uint32_t
|
||||
MyHeader::DeserializeFrom (Buffer::Iterator start)
|
||||
{
|
||||
// deserialize from head of buffer
|
||||
m_data = start.ReadNtohU16 ();
|
||||
return GetSerializedSize ();
|
||||
}
|
||||
|
||||
void
|
||||
MyHeader::SetData (uint16_t data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
uint16_t
|
||||
MyHeader::GetData (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
/* A sample Tag implementation
|
||||
*/
|
||||
struct MyTag {
|
||||
uint16_t m_streamId;
|
||||
};
|
||||
|
||||
static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
|
||||
|
||||
|
||||
static void
|
||||
Receive (Packet p)
|
||||
{
|
||||
MyHeader my;
|
||||
p.RemoveHeader (my);
|
||||
std::cout << "received data=" << my.GetData () << std::endl;
|
||||
struct MyTag myTag;
|
||||
p.PeekTag (myTag);
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Packet p;
|
||||
MyHeader my;
|
||||
my.SetData (2);
|
||||
std::cout << "send data=2" << std::endl;
|
||||
p.AddHeader (my);
|
||||
struct MyTag myTag;
|
||||
myTag.m_streamId = 5;
|
||||
p.AddTag (myTag);
|
||||
Receive (p);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/string.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static void
|
||||
PrintOne (double minTxpower, double maxTxpower, double stepTxpower, double min, double max, double step)
|
||||
{
|
||||
Ptr<StaticMobilityModel> a = CreateObject<StaticMobilityModel> ();
|
||||
Ptr<StaticMobilityModel> b = CreateObject<StaticMobilityModel> ();
|
||||
Ptr<LogDistancePropagationLossModel> log = CreateObject<LogDistancePropagationLossModel> ();
|
||||
log->SetReferenceModel (CreateObject<FriisPropagationLossModel> ());
|
||||
|
||||
Ptr<PropagationLossModel> model = log;
|
||||
|
||||
a->SetPosition (Vector (0.0, 0.0, 0.0));
|
||||
for (double x = min; x < max; x+= step)
|
||||
{
|
||||
b->SetPosition (Vector (x, 0.0, 0.0));
|
||||
std::cout << x << " ";
|
||||
for (double txpower = minTxpower; txpower < maxTxpower; txpower += stepTxpower)
|
||||
{
|
||||
double rxPowerDbm = txpower + model->GetLoss (a, b);
|
||||
std::cout << rxPowerDbm << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
Config::SetGlobal ("LogDistancePropagationLossModel::ReferenceDistance", StringValue ("1.0"));
|
||||
Config::SetGlobal ("LogDistancePropagationLossModel::Exponent", StringValue ("4"));
|
||||
|
||||
PrintOne (-10, 20, 5, 0, 10000, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+2
-2
@@ -49,7 +49,7 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
// Create a new object of type A, store it in global
|
||||
// variable g_a
|
||||
Ptr<A> a = Create<A> ();
|
||||
Ptr<A> a = CreateObject<A> ();
|
||||
a->Method ();
|
||||
Ptr<A> prev = StoreA (a);
|
||||
NS_ASSERT (prev == 0);
|
||||
@@ -58,7 +58,7 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
// Create a new object of type A, store it in global
|
||||
// variable g_a, get a hold on the previous A object.
|
||||
Ptr<A> a = Create<A> ();
|
||||
Ptr<A> a = CreateObject<A> ();
|
||||
Ptr<A> prev = StoreA (a);
|
||||
// call method on object
|
||||
prev->Method ();
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 University of Washington
|
||||
* Authors: Tom Henderson, Craig Dowell
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ns3/debug.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/component-manager.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
//
|
||||
// This sample file shows examples of how to use QueryInterface.
|
||||
//
|
||||
// QueryInterface is a templated method of class Object, defined in
|
||||
// src/core/object.h. ns-3 objects that derive from class Object
|
||||
// can have QueryInterface invoked on them.
|
||||
//
|
||||
// QueryInterface is a type-safe way to ask an object, at run-time,
|
||||
// "Do you support the interface identified by the given InterfaceId?"
|
||||
// It avoids deprecated techniques of having to downcast pointers to
|
||||
// an object to ask questions about its type. One or more interfaces
|
||||
// may be associated with a given object.
|
||||
//
|
||||
// QueryInterface is of most use when working with base class
|
||||
// pointers of objects that may be subclassed. For instance,
|
||||
// one may have a pointer to a Node, but not know whether it has
|
||||
// an IPv4 stack. Another example might be to determine whether
|
||||
// a Node has an EnergyModel, to which calls to decrement energy
|
||||
// from the node's battery might be made.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Object is the base class for ns-3 node-related objects used at
|
||||
// the public API. Object provides reference counting implementations
|
||||
// and the QueryInterface.
|
||||
//
|
||||
// A common design paradigm for an ns-3 node object, such as a Queue,
|
||||
// is that we provide an abstract base class that inherits from
|
||||
// Object. This class is assigned an interface ID (iid) and
|
||||
// contains the basic API for objects in this class and subclasses.
|
||||
// This base class is specialized to provide implementations of
|
||||
// the object in question (such as a DropTailQueue).
|
||||
//
|
||||
// The design pattern commonly used is known as the "non-virtual
|
||||
// public interface" pattern, whereby the public API for this
|
||||
// object is a set of public non-virtual functions that forward
|
||||
// to private virtual functions. The forwarding functions can
|
||||
// impose pre- and post-conditions on the forwarding call at
|
||||
// the base class level.
|
||||
//
|
||||
// We'll call this base class "AnInterface" in the example below.
|
||||
//
|
||||
//
|
||||
class AnInterface : public Object
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
void methodA (void);
|
||||
private:
|
||||
virtual void domethodA (void) = 0;
|
||||
};
|
||||
|
||||
void
|
||||
AnInterface::methodA (void)
|
||||
{
|
||||
// pre-dispatch asserts
|
||||
NS_DEBUG_UNCOND("AnInterface pre-condition::methodA");
|
||||
domethodA ();
|
||||
NS_DEBUG_UNCOND("AnInterface post-condition::methodA\n");
|
||||
// post-dispatch asserts
|
||||
}
|
||||
|
||||
//
|
||||
// The below assignment assigns the InterfaceId of the class AnInterface,
|
||||
// and declares that the parent iid is that of class Object.
|
||||
//
|
||||
const InterfaceId AnInterface::iid = MakeInterfaceId ("AnInterface", Object::iid);
|
||||
|
||||
//
|
||||
// AnImplementation is an implementation of the abstract base class
|
||||
// defined above. It provides implementation for the virtual functions
|
||||
// in the base class. It defines one ClassId for each constructor,
|
||||
// and can also provide an interface itself (in this example,
|
||||
// a methodImpl is available)
|
||||
//
|
||||
class AnImplementation : public AnInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
AnImplementation ();
|
||||
void methodImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void);
|
||||
};
|
||||
|
||||
void
|
||||
AnImplementation::methodImpl (void)
|
||||
{
|
||||
NS_DEBUG_UNCOND("AnImplementation::methodImpl\n");
|
||||
}
|
||||
|
||||
|
||||
AnImplementation::AnImplementation (void)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (AnImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnImplementation::domethodA ()
|
||||
{
|
||||
NS_DEBUG_UNCOND("AnImplementation::domethodA");
|
||||
}
|
||||
|
||||
//
|
||||
// The below assignment assigns the InterfaceId of the class AnImplementation,
|
||||
// and declares that the parent iid is that of class Object.
|
||||
//
|
||||
const InterfaceId AnImplementation::iid =
|
||||
MakeInterfaceId ("AnImplementation", AnInterface::iid);
|
||||
|
||||
//
|
||||
// The next few lines are used by the component manager. They
|
||||
// state that the component manager can create a new object
|
||||
// AnImplementation and return an interface corresponding to
|
||||
// the AnImplementation iid.
|
||||
//
|
||||
const ClassId AnImplementation::cid =
|
||||
MakeClassId<AnImplementation>
|
||||
("AnImplementation", AnImplementation::iid);
|
||||
|
||||
|
||||
//
|
||||
// Extending interfaces
|
||||
// ==================
|
||||
// What if AnInterface doesn't provide enough API for your
|
||||
// object type?
|
||||
// - if you aren't concerned about backward compatibility and
|
||||
// don't mind recompiling, you just add new methods to AnInterface
|
||||
// and recompile.
|
||||
// - if you want to address backward compatibiliy, or allow part
|
||||
// of the system to use the old interface, you have to do more.
|
||||
// You have to declare a new interface with the new functionality.
|
||||
//
|
||||
|
||||
class AnExtendedInterface : public AnInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
void methodB (void);
|
||||
private:
|
||||
virtual void domethodB (void) = 0;
|
||||
};
|
||||
|
||||
const InterfaceId AnExtendedInterface::iid =
|
||||
MakeInterfaceId ("AnExtendedInterface", AnInterface::iid);
|
||||
|
||||
//
|
||||
// Then you need provide an implementation for the virtual
|
||||
// methods. If you are providing a new implementation for
|
||||
// everything, the answer is straightforward
|
||||
//
|
||||
|
||||
class ANewImplementation : public AnExtendedInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
ANewImplementation ();
|
||||
void methodImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void) { /* new-implementation-behavior (); */}
|
||||
virtual void domethodB (void) { /* new-implementation-behavior (); */}
|
||||
};
|
||||
|
||||
ANewImplementation::ANewImplementation (void)
|
||||
{
|
||||
// enable our interface
|
||||
SetInterfaceId (ANewImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
ANewImplementation::methodImpl (void)
|
||||
{
|
||||
NS_DEBUG_UNCOND("ANewImplementation::methodImpl\n");
|
||||
}
|
||||
|
||||
const InterfaceId ANewImplementation::iid =
|
||||
MakeInterfaceId ("ANewImplementation", AnExtendedInterface::iid);
|
||||
|
||||
//
|
||||
// If you want to extend an existing implementation, you can use
|
||||
// the existing class to instantiate an implementation of its
|
||||
// methods (hasa) and do the following if you can use stuff from
|
||||
// the existing class.
|
||||
//
|
||||
|
||||
class AnExtendedImplementation : public AnExtendedInterface
|
||||
{
|
||||
public:
|
||||
static const InterfaceId iid;
|
||||
static const ClassId cid;
|
||||
|
||||
AnExtendedImplementation ();
|
||||
void methodImpl (void) { /* pImpl->methodImpl (); */ }
|
||||
void methodExtendedImpl (void);
|
||||
private:
|
||||
virtual void domethodA (void) { /* new-implementation-behavior (); */}
|
||||
virtual void domethodB (void) { /* new-implementation-behavior (); */}
|
||||
Ptr<AnImplementation> pImpl;
|
||||
};
|
||||
|
||||
AnExtendedImplementation::AnExtendedImplementation (void)
|
||||
{
|
||||
pImpl = Create<AnImplementation> ();
|
||||
SetInterfaceId (AnExtendedImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnExtendedImplementation::methodExtendedImpl (void)
|
||||
{
|
||||
NS_DEBUG_UNCOND("AnExtendedImplementation::methodExtendedImpl\n");
|
||||
}
|
||||
|
||||
const InterfaceId AnExtendedImplementation::iid =
|
||||
MakeInterfaceId ("AnExtendedImplementation", AnExtendedInterface::iid);
|
||||
|
||||
//
|
||||
// Inheriting from an existing implementation (isa) and an extended
|
||||
// interface is tricky, because of the diamond multiple inheritance
|
||||
// problem. If the pImpl method above is not desirable, it may
|
||||
// be that the implementation extension could be aggregated.
|
||||
//
|
||||
// The extension will not have access to the base implementation,
|
||||
// so this design pattern may be more appropriate if the extension
|
||||
// is very modular (e.g., add an EnergyModel to a wireless interface)
|
||||
//
|
||||
// EXAMPLE NOT YET PROVIDED
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
Ptr<AnInterface> aBase = ComponentManager::Create<AnImplementation>
|
||||
(AnImplementation::cid, AnInterface::iid);
|
||||
NS_ASSERT (aBase != 0);
|
||||
|
||||
aBase->methodA ();
|
||||
//aBase->methodImpl (); // XXX won't compile, aBase not right ptr type
|
||||
|
||||
Ptr<AnImplementation> aBaseImplPtr =
|
||||
aBase-> QueryInterface<AnImplementation> (AnImplementation::iid);
|
||||
aBaseImplPtr->methodImpl ();
|
||||
aBaseImplPtr->methodA();
|
||||
|
||||
// Test symmetric property of QueryInterface
|
||||
Ptr<AnInterface> aBase2 =
|
||||
aBaseImplPtr-> QueryInterface<AnInterface> (AnInterface::iid);
|
||||
aBase2->methodA ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static void
|
||||
CourseChange (std::string context, Ptr<const MobilityModel> position)
|
||||
{
|
||||
Vector pos = position->GetPosition ();
|
||||
std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
|
||||
<< ", z=" << pos.z << std::endl;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
|
||||
NodeContainer c;
|
||||
c.Create (10000);
|
||||
|
||||
MobilityHelper mobility;
|
||||
mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
|
||||
"X", StringValue ("100.0"),
|
||||
"Y", StringValue ("100.0"),
|
||||
"Rho", StringValue ("Uniform:0:30"));
|
||||
mobility.SetMobilityModel ("ns3::StaticMobilityModel");
|
||||
mobility.Install (c);
|
||||
|
||||
Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
|
||||
MakeCallback (&CourseChange));
|
||||
|
||||
Simulator::Stop (Seconds (100.0));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user