Compare commits
1103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 2949d86908 | |||
| 0fcbdbf0fe | |||
| 1dc22a9e8f | |||
| 5c769d2d24 | |||
| a2e63b7f0b | |||
| 44c33f1618 | |||
| 4730d7087f | |||
| 4f58be6548 | |||
| 33bd62d32f | |||
| c547c88e89 | |||
| 2a4dcce444 | |||
| b41d008223 | |||
| a144ad9a1e | |||
| 93be0562cc | |||
| 64bb988613 | |||
| 3fcff1b1b3 | |||
| 6150ba4860 | |||
| 676307027c | |||
| 976f16c4d9 | |||
| b88e90fec3 | |||
| 2103459845 | |||
| 1fb6ad5488 | |||
| 328aa2cc45 | |||
| 2deb2ea0f0 | |||
| bc1ab2d79b | |||
| f3e77eea3d | |||
| 6b0e717a19 | |||
| 2d6f46dfa8 | |||
| f1f400bcee | |||
| a6e289c8ef | |||
| f043a8789c | |||
| 30bbef4b14 | |||
| 26fb62c748 | |||
| 77c0e85775 | |||
| e42ccef4a7 | |||
| 8449139061 | |||
| c53988d01e | |||
| 7d6cd9ae7c | |||
| bd70c33606 | |||
| 15748575d8 | |||
| cc9655af45 | |||
| 465bf1c10a | |||
| eb1200a2cd | |||
| c1a71e53f9 | |||
| f5fe661c13 | |||
| f42e5c4814 | |||
| 135a4ab58c | |||
| b192207132 | |||
| a0ee98cb4b | |||
| cbafcb5aa6 | |||
| b604bf2d7a | |||
| 05efca8430 | |||
| 83dd618e5b | |||
| ffc992893f | |||
| b04e3d6cd6 | |||
| 5e19f9707b | |||
| 49deb08b81 |
@@ -9,3 +9,20 @@
|
||||
^\.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
|
||||
|
||||
@@ -9,3 +9,8 @@
|
||||
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
|
||||
|
||||
@@ -2,6 +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.
|
||||
|
||||
@@ -81,14 +82,15 @@ 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
|
||||
- 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
|
||||
|
||||
Other platforms may or may not work: we welcome
|
||||
@@ -102,11 +104,11 @@ On recent Linux systems, once you have built ns-3, it
|
||||
should be easy to run the sample programs with the
|
||||
following command:
|
||||
|
||||
./waf --run simple-point-to-point
|
||||
./waf --run simple-global-routing
|
||||
|
||||
That program should generate a simple-point-to-point.tr text
|
||||
trace file and a set of simple-point-to-point-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
|
||||
-------------------------------------------
|
||||
@@ -122,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/
|
||||
|
||||
@@ -136,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 "./waf --doxygen" 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
|
||||
-----------------------------------------------
|
||||
|
||||
|
||||
@@ -3,6 +3,64 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -185,7 +185,7 @@ TAB_SIZE = 4
|
||||
# will result in a user-defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES = valueref{1}="\ref DefaultValue\1 \"\1\""
|
||||
ALIASES =
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
|
||||
# sources only. Doxygen will then generate output that is more tailored for C.
|
||||
@@ -496,7 +496,6 @@ WARN_LOGFILE =
|
||||
INPUT = doc/modules \
|
||||
doc/main.h \
|
||||
doc/introspected-doxygen.h \
|
||||
doc/tracing.h \
|
||||
doc/howtos/ \
|
||||
src
|
||||
|
||||
@@ -1047,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_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.
|
||||
@@ -1090,7 +1089,9 @@ PREDEFINED = RUN_SELF_TESTS \
|
||||
# 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
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
*/
|
||||
@@ -12,6 +12,9 @@ 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
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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'],[
|
||||
]).
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -13,18 +13,18 @@
|
||||
* - 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 error
|
||||
* - debugging facilities: \ref logging, \ref assert
|
||||
* - \ref randomvariable
|
||||
* - \ref config
|
||||
* - 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 QueryInterface: ns3::Object and ns3::InterfaceId
|
||||
* - a set of low-level trace facilities integrated in the ns3::Object system: \ref tracing
|
||||
* - a ns3::ComponentManager which can be used to manage the creation
|
||||
* of any object which derives from ns3::Object through an ns3::ClassId
|
||||
* 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 "core" module contains:
|
||||
* 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
|
||||
@@ -41,18 +41,16 @@
|
||||
*
|
||||
*
|
||||
* @defgroup devices Devices
|
||||
* The "devices" module contains:
|
||||
* - a PointToPoint MAC device: ns3::PointToPointNetDevice, ns3::PointToPointChannel,
|
||||
* and ns3::PointToPointTopology.
|
||||
*
|
||||
* @defgroup internetNode InternetNode
|
||||
* @defgroup internetStack InternetStack
|
||||
*
|
||||
* 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
|
||||
* The "internet-stack" module contains:
|
||||
* - an Ipv4 stack
|
||||
* - an ARP module
|
||||
* - an InternetNode class which is a Node subclass.
|
||||
* - a UDP and a TCP implementation
|
||||
*
|
||||
* @defgroup helper Helpers
|
||||
*
|
||||
* @defgroup applications Applications
|
||||
*
|
||||
* @defgroup mobility Mobility
|
||||
@@ -64,4 +62,3 @@
|
||||
*
|
||||
* @defgroup contrib Contrib
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,35 +1,77 @@
|
||||
Steps in doing an ns-3 release
|
||||
|
||||
0. check out a clean ns-3-dev somewhere
|
||||
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
|
||||
- DO NOT change VERSION at this time
|
||||
- confirm that Doxygen builds cleanly and without warnings
|
||||
(./waf --doxygen), and check in any necessary changes
|
||||
2. ./waf configure; ./waf dist
|
||||
- this will create a ns-3.0.x.tar.bz2 tarball
|
||||
3. test tarball on release platforms (waf check and maybe some other scripts)
|
||||
4. once you are happy with the tarball, tag ns-3-dev with "release ns-3.0.X"
|
||||
- hg tag "release ns-3.0.x"
|
||||
(./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
|
||||
5. clone the tagged ns-3-dev and place it on the repository
|
||||
- ssh code.nsnam.org; sudo; su code;
|
||||
- cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
|
||||
- cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately:
|
||||
"description = ns-3.0.x release
|
||||
name = ns-3.0.x"
|
||||
6. upload "ns-3.0.x.tar.bz2" to the /var/www/html/releases/ directory on
|
||||
- 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 600 permissions, and user/group = apache
|
||||
8. update web pages on www.nsnam.org (source is in the www/ module)
|
||||
- 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 getting_started.html
|
||||
- update documents.html
|
||||
- update roadmap on wiki
|
||||
- build and update Doxygen directory on the server
|
||||
- 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
|
||||
-- edit ~/bin/update-doxygen-release file and change RELEASE variable
|
||||
to the right version number
|
||||
-- run ~/bin/update-doxygen-release
|
||||
9. announce to ns-developers, with summary of release notes
|
||||
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
|
||||
|
||||
@@ -1,584 +0,0 @@
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup TraceSourceList List of trace sources
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \defgroup tracing Tracing
|
||||
*
|
||||
* The flexibility of the ns-3 tracing system comes at the cost of quite
|
||||
* a bit of complexity so, before trying to use the low-level aspects
|
||||
* of the tracing API, it is important to focus on some basic definitions:
|
||||
*
|
||||
* - A trace source is an object instance which can report trace events
|
||||
* to a set of listening trace sinks.
|
||||
*
|
||||
* - A trace sink is a user-provided callback (a function) which can
|
||||
* be connected to a set of trace sources to receive the events generated
|
||||
* by each trace source.
|
||||
*
|
||||
* - A trace resolver is an object which allows users to establish
|
||||
* connections between a set of trace sources and a set of trace sinks.
|
||||
*
|
||||
* \section TraceSource Generating Trace Events
|
||||
*
|
||||
* So, what does it look like in practice ? First, let's look at trace
|
||||
* sources. We have two types of trace sources: numeric, and, normal
|
||||
* trace sources. Numeric trace sources behave as normal c++ integers
|
||||
* or c++ floating point numbers except that they report as trace events
|
||||
* each change of their value. For example:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (void)
|
||||
* {
|
||||
* // use the "int" trace source just
|
||||
* // like any other "int" variable.
|
||||
* m_cwnd *= 2;
|
||||
* m_cwnd += 4;
|
||||
* if (m_cwnd > 100)
|
||||
* {
|
||||
* // do something.
|
||||
* }
|
||||
* }
|
||||
* private:
|
||||
* // declare an instance of a "int" trace source
|
||||
* SVTraceSource<int> m_cwnd;
|
||||
* };
|
||||
* \endcode
|
||||
* Normal trace sources, on the other hand, allow you to trace the
|
||||
* call of arbitrary functions and methods, as shown below. They are
|
||||
* typically used to track "rx", "tx", or "drop" events but could
|
||||
* also be used to track route change events, or position change
|
||||
* events:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet
|
||||
* m_doSomething (packet);
|
||||
* // do something
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Ptr<Packet> > m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
* Every type of trace source derives from the ns3::TraceSource base class.
|
||||
* As of today, the set of concrete subclasses is relatively short:
|
||||
* ns3::CallbackTraceSource, ns3::SvTraceSource, ns3::UvTraceSource, and,
|
||||
* ns3::FvTraceSource.
|
||||
*
|
||||
* \section TraceSink Receiving Trace Events
|
||||
*
|
||||
* To receive these trace events, a user should specify a set of trace sinks.
|
||||
* For example, to receive the "int" and the "something" events shown in the
|
||||
* examples above, a user would declare the following functions:
|
||||
* \code
|
||||
* // oldValue and newValue contain the previous and new values of
|
||||
* // the connected SVTraceSource<int> trace source.
|
||||
* void
|
||||
* CwndTraceSink (const TraceContext &context, int64_t oldValue, int64_t newValue)
|
||||
* {
|
||||
* // for example, print the new value:
|
||||
* std::cout << "cwnd=" << newValue << std::endl;
|
||||
* }
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the packet
|
||||
* std::cout << "packet " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* Each of these sink function takes, as a first argument, a reference to a
|
||||
* const TraceContext object. This context object contains information which
|
||||
* describes the instance of the connected trace source: that information is
|
||||
* setup during the connection process and does not change afterwards
|
||||
* The type and the number of the other arguments to each trace sink depends
|
||||
* on the type of the connected trace source: it conveys per-event information
|
||||
* from the trace source to the trace sink. For example, UVTraceSource and
|
||||
* SVTraceSource trace sources require two extra arguments. The former requires
|
||||
* two unsigned 64 bit integers while the latter requires two signed 64 bit
|
||||
* integers. More generally, users can consult the \ref TraceSourceList
|
||||
* to figure out the arguments which a trace sink is required to receive
|
||||
* for each trace source: a signature of the user trace sink must match
|
||||
* _exactly_ the signature documented in the \ref TraceSourceList.
|
||||
*
|
||||
*
|
||||
* \section TraceSourceSimpleExport A simple way to connect Trace Sources with Trace Sinks
|
||||
*
|
||||
* The crux of the complexity of the ns-3 tracing system comes from its
|
||||
* flexible system used to connect trace sources to trace sinks but what is really
|
||||
* nice about it is that it is not necessary to use it to setup simple traces.
|
||||
*
|
||||
* The simplest way to export a set of trace sources to a user, for example,
|
||||
* during the early prototyping phases of a system, is to add a set of public methods
|
||||
* to give to your users access to the trace source object instances you use to generate
|
||||
* trace events:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet
|
||||
* m_doSomething (packet);
|
||||
* // do something
|
||||
* }
|
||||
* CallbackTraceSource<Ptr<Packet>> *PeekSomethingTraceSource (void) const
|
||||
* {
|
||||
* return &m_doSomething
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Ptr<Packet>> m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
* If your users hold a pointer to an instance of MyModel, and if they want to connect
|
||||
* a MySomethingSink, they can simply do the following which invokes the
|
||||
* TraceSource::AddCallback method and creates a Callback object from the user's
|
||||
* sink with the MakeCallback function.
|
||||
* \code
|
||||
* void
|
||||
* MySomethingSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // do whatever you want.
|
||||
* }
|
||||
* MyModel *model = ...;
|
||||
* CallbackTraceSource<Ptr<Packet>> *source = model->PeekSomethingTraceSource ();
|
||||
* source->AddCallback (MakeCallback (&MySomethingSink));
|
||||
* \endcode
|
||||
*
|
||||
* The full power of the tracing system comes however from its ns3::NodeList::Connect
|
||||
* method which is described in the following sections.
|
||||
*
|
||||
* \section TraceConnection Connecting Trace Sources to Trace Sinks
|
||||
*
|
||||
* If a trace source is integrated in the ns-3 trace connection facility, a user
|
||||
* should call the ns3::NodeList::Connect method to establish a connection between
|
||||
* a trace sink and a set of matching trace sources. The second argument to that
|
||||
* method is a callback to the user's trace sink.
|
||||
* That callback is easy to construct: call ns3::MakeCallback and you are done. The
|
||||
* first argument is a string whose format is similar to a unix path and which is
|
||||
* used to uniquely identify the set of trace sources you want to connect to.
|
||||
* The set of acceptable path strings is also documented in the \ref TraceSourceList.
|
||||
*
|
||||
* So, what does this look like from the perspective of a user ? If we wanted to
|
||||
* connect to a trace source defined somewhere deep into the a set of NetDevice objects
|
||||
* located in some nodes of the system, we could write the following:
|
||||
* \code
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the packet
|
||||
* std::cout << "packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* // connect the above sink to a matching trace source
|
||||
* NodeList::Connect ("/nodes/* /devices/* /rx", MakeCallback (&DoSomethingTraceSink));
|
||||
* \endcode
|
||||
*
|
||||
* The connection path string "/nodes/* /devices/* /rx" matches the "rx" trace source
|
||||
* located in every netdevice located in every node. The syntax of that path string
|
||||
* is loosely based on regular expressions so, a user could conceivably connect
|
||||
* to the trace sources present in only one node identified by node index:
|
||||
* "/nodex/3/devices/* /rx".
|
||||
*
|
||||
* The matching algorithm used here is very useful since it allows you to connect
|
||||
* at once a large set of trace sources to a single sink but it introduces another
|
||||
* problem: it becomes impossible when you receive an event in your trace sink to
|
||||
* know from _which_ trace source the event is coming from. In our example, the
|
||||
* trace source might be coming from the NetDevice number 2 of Node 10 or Netdevice
|
||||
* number 0 of Node 5. In both cases, you might need to know which of these NetDevice
|
||||
* is generating this event, if only to generate some ascii trace dump. Another
|
||||
* similar use-case is that you might have connected the same trace sink to
|
||||
* multiple types of events which have the same signature: it is quite common
|
||||
* to receive all tx, rx, and drop events in the same trace sink and that would be
|
||||
* quite trivial to achieve with a string such as: "/nodes/* /devices/* /*"
|
||||
*
|
||||
* The source of a trace event can be retrieved from a trace sink using
|
||||
* different means: the simplest
|
||||
* way to get this information is to use the builtin printing facility of
|
||||
* the TraceContext object:
|
||||
* \code
|
||||
* void
|
||||
* DoSomethingTraceSink (const TraceContext &context, Ptr<Packet> packet)
|
||||
* {
|
||||
* // for example, print the packet
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* The above code is going to generate output which looks like the following:
|
||||
* \code
|
||||
* context="nodeid=2 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
|
||||
* context="nodeid=1 device=0 dev-rx" packet: IPV4(tos 0x0 ttl 64 id 0 offset ...
|
||||
* ...
|
||||
* \endcode
|
||||
*
|
||||
* Another more advanced way to get information out of a TraceContext is to call its
|
||||
* ns3::TraceContext::GetElement method. This method takes as its first and only
|
||||
* argument an instance of the object we want to read and the list of available
|
||||
* object instances we can read from a TraceContext is documented, once again,
|
||||
* in the \ref TraceSourceList. For example, we could write the following to
|
||||
* generate adhoc trace output:
|
||||
* \code
|
||||
* void DeviceRxSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* NodeListIndex nodeIndex;
|
||||
* NodeNetDeviceIndex deviceIndex;
|
||||
* context.GetElement (nodeIndex);
|
||||
* context.GetElement (deviceIndex);
|
||||
* std::cout << "node-index=" << nodeIndex.Get ();
|
||||
* std::cout << ", device-index=" << deviceIndex.Get ();
|
||||
* std::cout << ", packet: " << packet->Print ();
|
||||
* std::cout << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \section ExportingTraceSources Exporting new Trace Sources
|
||||
*
|
||||
* Using existing trace sources to connect them to a set of adhoc trace sinks
|
||||
* is not really complicated but, setting up new trace sources which can hook
|
||||
* in this automatic connection system is a bit more complicated.
|
||||
*
|
||||
* So far, we know that a model author can generate trace events really easily:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* void DoSomething (Ptr<Packet> packet)
|
||||
* {
|
||||
* // report this event on packet with value
|
||||
* m_doSomething (packet);
|
||||
* // do something
|
||||
* }
|
||||
* private:
|
||||
* // report every "something" function call.
|
||||
* CallbackTraceSource<Ptr<Packet>> m_doSomething;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* To make these new trace sources available to the rest of the connection system,
|
||||
* the first step is to make sure that your model object derives from the ns3::Object
|
||||
* base class either directly (as shown below) or indirectly through another base class:
|
||||
* \code
|
||||
* class MyModel : public Object {...};
|
||||
* // or:
|
||||
* class SomeOtherObject : public Object {...};
|
||||
* class MyModel : public SomeOtherObject {...};
|
||||
* \endcode
|
||||
*
|
||||
* This is pretty trivial and lays the ground for the second step: overriding the
|
||||
* ns3::Object::GetTraceResolver method:
|
||||
* \code
|
||||
* class MyModel : public MyParent
|
||||
* {
|
||||
* public:
|
||||
* // declare overriden method
|
||||
* virtual Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
* private:
|
||||
* // the new trace source to export.
|
||||
* CallbackTraceSource<Ptr<Packet>> m_rxSource;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* To implement this method, you could attempt to implement a new subclass of
|
||||
* the ns3::TraceResolver base class and return an instance from this method but
|
||||
* this would be very hard. Instead, you should use the helper class
|
||||
* ns3::CompositeTraceResolver to register your trace sources and chain up to
|
||||
* your parent:
|
||||
* \code
|
||||
* Ptr<TraceResolver>
|
||||
* MyModel::GetTraceResolver (void) const
|
||||
* {
|
||||
* // create an empty trace resolver
|
||||
* Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
|
||||
* // register m_rxSource
|
||||
* resolver->AddSource ("rx", // the name of the trace source in the path string
|
||||
* TraceDoc ("some help text to explain the purpose of this trace source",
|
||||
* "Packet", // the type of the first argument to the trace source
|
||||
* "the purpose of the first argument",
|
||||
* "type-of-second-argument", "purpose-of-second-argument"),
|
||||
* m_rxSource // the trace source itself is registered
|
||||
* );
|
||||
* // make sure we include the trace sources implemented in the parent.
|
||||
* resolver->SetParentResolver (MyParent::GetTraceResolver ());
|
||||
* return resolver;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Once you have written that code, you must make sure that this new method GetTraceResolver
|
||||
* is going to be called at some point by the tracing system. If your model is located somewhere
|
||||
* deep in MAC or PHY layer, that is, it is part of a NetDevice implementation, all you
|
||||
* have to do is to make sure that your model is registered as a "composite" of your NetDevice
|
||||
* subclass:
|
||||
* \code
|
||||
* class MyNetDevice : public NetDevice
|
||||
* {
|
||||
* public:
|
||||
* Ptr<TraceResolver> GetTraceResolver (void) const;
|
||||
* private:
|
||||
* Ptr<MyModel> m_model;
|
||||
* };
|
||||
*
|
||||
* Ptr<TraceResolver>
|
||||
* MyNetDevice::GetTraceResolver (void) const
|
||||
* {
|
||||
* Ptr<CompositeTraceResolver> resolver = ...;
|
||||
* // register other trace source
|
||||
* ...
|
||||
* // register now your model as a "composite"
|
||||
* resolver->AddComposite ("my-model", m_model);
|
||||
* // chain up to parent.
|
||||
* resolver->SetParentResolver (NetDevice::GetTraceResolver ());
|
||||
* return resolver;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* The code above will make your "rx" trace source appear under the
|
||||
* /nodes/xx/devices/xx/my-model/rx namespace path.
|
||||
*
|
||||
* If you have implemented a new layer 3 or 4 protocol object, the process to
|
||||
* export your trace sources is quite similar. You need to subclass from
|
||||
* ns3::Object, override the ns3::Object::GetTraceResolver method, make
|
||||
* sure you chain up to your parent's GetTraceResolver method, and, finally,
|
||||
* make sure that someone calls your new GetTraceResolver method. How to accomplish
|
||||
* the latter should be documented in the node's API documentation which describes
|
||||
* how to implement a new layer 3 or 4 protocol object.
|
||||
*
|
||||
* \section AdvancedTraceContext Creating new Trace Context Elements
|
||||
*
|
||||
* The last important feature which model developers need to understand
|
||||
* is how to provide extra context information to trace sinks. For example,
|
||||
* if your model exports both rx and tx trace sources which share the same
|
||||
* signature, it is quite natural for a user to connect to a single trace sink
|
||||
* to both of them with a trace path string such as "/nodes/* /devices/* /(rx|tx)".
|
||||
* In this case, it becomes necessary to be able, from the trace sink function,
|
||||
* to tell which event triggered the call to the trace sink: a rx or a tx event.
|
||||
*
|
||||
* That example is detailed below with a TX, a RX, and a DROP source:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* private:
|
||||
* CallbackTraceSource<Ptr<Packet>> m_rxSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_txSource;
|
||||
* CallbackTraceSource<Ptr<Packet>> m_dropSource;
|
||||
* };
|
||||
* \endcode
|
||||
* When a single sink is connected to all 3 sources here, one might want
|
||||
* to write code like the following:
|
||||
* \code
|
||||
* void DeviceRxSink (const TraceContext &context, Ptr<const Packet> &packet)
|
||||
* {
|
||||
* switch (type) {
|
||||
* case RX:
|
||||
* std::cout << "rx" << std::endl;
|
||||
* break;
|
||||
* case TX:
|
||||
* std::cout << "tx" << std::endl;
|
||||
* break;
|
||||
* case DROP:
|
||||
* std::cout << "drop" << std::endl;
|
||||
* break;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \subsection AdvancedTraceContextSimpleSolution The simple solution
|
||||
*
|
||||
* The simplest way to do achieve the result shown above is to include
|
||||
* in the trace source an extra explicit argument which describes the source event:
|
||||
* - define a small enum with 3 values
|
||||
* - change the signature of m_rxSource, m_txSource, and m_dropSource to include
|
||||
* the enum
|
||||
* - pass the enum value in each event
|
||||
*
|
||||
* The resulting code is shown below:
|
||||
* \code
|
||||
* class MyModel
|
||||
* {
|
||||
* public:
|
||||
* // define the trace type enum.
|
||||
* enum TraceType {
|
||||
* RX,
|
||||
* TX,
|
||||
* DROP
|
||||
* };
|
||||
* private:
|
||||
* // generate events
|
||||
* void NotifyRxPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::RX);
|
||||
* }
|
||||
* void NotifyTxPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::TX);
|
||||
* }
|
||||
* void NotifyDropPacket (Ptr<Packet> p) {
|
||||
* m_rxSource (p, MyModel::DROP);
|
||||
* }
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_rxSource;
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_txSource;
|
||||
* CallbackTraceSource<Ptr<Packet>,enum TraceType> m_dropSource;
|
||||
* };
|
||||
* \endcode
|
||||
* These 3 new sources can be connected easily to a new trace sink:
|
||||
* \code
|
||||
* void ASimpleTraceSink (const TraceContext &context, Ptr<const Packet> packet, enum MyModel::TraceType type)
|
||||
* {
|
||||
* // here, read the "type" argument
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* This solution works but it makes it impossible to connect a single trace sink to a set
|
||||
* of trace sources which represent "rx" events in different NetDevice objects since
|
||||
* each of them will define a different enum type with different values: since the
|
||||
* trace sink signature must match exactly the trace source signature, it is impossible
|
||||
* to connect at the same time to all "rx" events of different NetDevice.
|
||||
*
|
||||
* \subsection AdvancedTraceContextFancySolution The more complex and generic solution
|
||||
*
|
||||
* There is, hopefully, a way to get the best of both worlds, that is, to allow a
|
||||
* user to connect to a lot of trace source events of the same kind but coming from different
|
||||
* implementations and to allow the user to differentiate between these different
|
||||
* implementations.
|
||||
*
|
||||
* Rather than define an adhoc enum type with a list of trace sources, you can also
|
||||
* define a new ns3::TraceContextElement for your source sources. For example, if you
|
||||
* define a new MyModelTraceType class which contains the type of trace, your users can
|
||||
* then write trace sink code which looks like this:
|
||||
* \code
|
||||
* void AFancyTraceSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* MyModelTraceType type;
|
||||
* if (context.GetElement (type))
|
||||
* {
|
||||
* switch (type.Get ())
|
||||
* {
|
||||
* case MyModelTraceType::RX:
|
||||
* std::cout << "rx" << std::endl;
|
||||
* break;
|
||||
* case MyModelTraceType::TX:
|
||||
* std::cout << "tx" << std::endl;
|
||||
* break;
|
||||
* case MyModelTraceType::DROP:
|
||||
* std::cout << "drop" << std::endl;
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Of course, since the type of trace is stored in the TraceContext, your users can
|
||||
* also take the shortcut which uses the printing functionality of the TraceContext:
|
||||
* \code
|
||||
* void ALessFancyTraceSink (const TraceContext &context, Ptr<const Packet> packet)
|
||||
* {
|
||||
* std::cout << "context=\"" << context << "\" packet: " << packet->Print () << std::endl;
|
||||
* }
|
||||
* \endcode
|
||||
* which will generate something like the following when the trace source comes
|
||||
* from MyModel:
|
||||
* \code
|
||||
* context="my-model-rx" packet: ...
|
||||
* \endcode
|
||||
*
|
||||
* The first step to achieve this is to define and implement a new
|
||||
* subclass of the ns3::TraceContextElement base class. The exact list of
|
||||
* public methods which must be implemented is described in the API
|
||||
* documentation of the ns3::TraceContextElement class.
|
||||
* \code
|
||||
* class MyModelTraceType : public TraceContextElement
|
||||
* {
|
||||
* public:
|
||||
* enum Type {
|
||||
* RX,
|
||||
* TX,
|
||||
* DROP
|
||||
* };
|
||||
* // called from MyModel::GetTraceResolver
|
||||
* MyModelTraceType (enum Type type);
|
||||
* // needed for by the tracing subsystem.
|
||||
* MyModelTraceType ();
|
||||
* // called from trace sink
|
||||
* enum Type Get (void) const;
|
||||
* // needed by the tracing subsystem
|
||||
* static uint16_t GetUid (void);
|
||||
* // needed by the tracing subsystem to
|
||||
* // print the content of a TraceContext
|
||||
* void Print (std::ostream &os) const;
|
||||
* // needed by the tracing subsystem to
|
||||
* // generate the doxygen documentation.
|
||||
* std::string GetTypeName (void) const;
|
||||
* private:
|
||||
* enum Type m_type;
|
||||
* };
|
||||
* \endcode
|
||||
* The implementation does not require much thinking:
|
||||
* \code
|
||||
* MyModelTraceType::MyModelTraceType ()
|
||||
* : m_type (RX)
|
||||
* {// an arbitrary default value.
|
||||
* }
|
||||
* MyModelTraceType::MyModelTraceType (enum Type type)
|
||||
* : m_type (type)
|
||||
* {}
|
||||
* enum MyModelTraceType::Type
|
||||
* MyModelTraceType::Get (void) const
|
||||
* {
|
||||
* return m_type;
|
||||
* }
|
||||
* uint16_t
|
||||
* MyModelTraceType::GetUid (void)
|
||||
* {
|
||||
* // use protected TraceContextElement::AllocateUid method
|
||||
* // the input string is used to uniquely identify this new subclass
|
||||
* static uint16_t uid = AllocateUid<MyModelTraceType> ("ns3::MyModelTraceType");
|
||||
* return uid;
|
||||
* }
|
||||
* void
|
||||
* MyModelTraceType::Print (std::ostream &os) const
|
||||
* {
|
||||
* // this method is invoked by the print function of a TraceContext
|
||||
* // if it contains an instance of this TraceContextElement.
|
||||
* switch (m_type) {
|
||||
* case RX: os << "rx"; break;
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* std::string
|
||||
* MyModelTraceType::GetTypeName (void) const
|
||||
* {
|
||||
* // This method should return a fully-qualified c++ typename
|
||||
* // This method is used only for documentation purposes to
|
||||
* // generate the content of the Trace Source List.
|
||||
* return "ns3::MyModelTraceType";
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Once this subclass is implemented, the work is almost completed: you
|
||||
* just need to pass an instance of that class as the last argument of
|
||||
* the ns3::CompositeTraceResolver::AddSource method as shown below:
|
||||
* \code
|
||||
* Ptr<TraceResolver>
|
||||
* MyModel::GetTraceResolver (void) const
|
||||
* {
|
||||
* // create an empty trace resolver
|
||||
* Ptr<CompositeTraceResolver> resolver = Create<CompositeTraceResolver> ();
|
||||
* // register m_rxSource
|
||||
* resolver->AddSource ("rx", // the name of the trace source in the path string
|
||||
* TraceDoc ("some help text to explain the purpose of this trace source",
|
||||
* "Packet", // the type of the first argument to the trace source
|
||||
* "the purpose of the first argument",
|
||||
* "type-of-second-argument", "purpose-of-second-argument"),
|
||||
* m_rxSource, // the trace source itself is registered
|
||||
* // the TraceContextElement associated to this trace source.
|
||||
* MyModelTraceType (MyModelTraceType::RX)
|
||||
* );
|
||||
* // make sure we include the trace sources implemented in the parent.
|
||||
* resolver->SetParentResolver (MyParent::GetTraceResolver ());
|
||||
* return resolver;
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
@@ -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.
|
||||
|
||||
|
Before Width: | Height: | Size: 8.0 KiB |
@@ -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.
|
||||
@@ -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'],[
|
||||
]).
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
|
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)
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 4.7 KiB |
@@ -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
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -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.
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -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;
|
||||
}
|
||||
@@ -32,31 +32,10 @@
|
||||
#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/log.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/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -69,82 +48,43 @@ main (int argc, char *argv[])
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaBroadcastExample", 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);
|
||||
// Enable the below logging command to see the packets being received
|
||||
LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
|
||||
#endif
|
||||
LogComponentEnable ("CsmaBroadcastExample", LOG_PREFIX_TIME);
|
||||
|
||||
// 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
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
//
|
||||
// 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::Parse (argc, argv);
|
||||
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.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
Ptr<CsmaChannel> channel0 =
|
||||
CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
// We create the channels first without any IP addressing information
|
||||
Ptr<CsmaChannel> channel1 =
|
||||
CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
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.");
|
||||
uint32_t n0ifIndex0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel0,
|
||||
Mac48Address("10:54:23:54:0:50"));
|
||||
uint32_t n0ifIndex1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, channel1,
|
||||
Mac48Address("10:54:23:54:0:51"));
|
||||
uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, channel0,
|
||||
Mac48Address("10:54:23:54:23:51"));
|
||||
uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channel1,
|
||||
Mac48Address("10:54:23:54:23:52"));
|
||||
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);
|
||||
|
||||
// Later, we add IP addresses.
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n0, n0ifIndex0, Ipv4Address("10.1.0.1"), Ipv4Mask("255.255.0.0"));
|
||||
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);
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n1, n1ifIndex, Ipv4Address("10.1.0.2"), Ipv4Mask("255.255.0.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n0, n0ifIndex1, Ipv4Address("192.168.1.1"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n2, n2ifIndex, Ipv4Address("192.168.1.2"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
// RFC 863 discard port ("9") indicates packet should be thrown away
|
||||
// by the system. We allow this silent discard to be overridden
|
||||
@@ -154,48 +94,30 @@ main (int argc, char *argv[])
|
||||
// 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.");
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("255.255.255.255", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
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
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
app.Start (Seconds (1.0));
|
||||
app.Stop (Seconds (10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
n2,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the csma-broadcast.tr file
|
||||
AsciiTrace asciitrace ("csma-broadcast.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
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
|
||||
// simple-point-to-point.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("csma-broadcast.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
// 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 ();
|
||||
|
||||
@@ -27,31 +27,15 @@
|
||||
// - 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 (actual listener not yet implementted)
|
||||
// - Node n4 listens for the data
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.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/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#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;
|
||||
|
||||
@@ -60,272 +44,145 @@ 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
|
||||
//
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaMulticastExample", LOG_LEVEL_INFO);
|
||||
//
|
||||
// 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);
|
||||
|
||||
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);
|
||||
LogComponentEnable("PacketSinkApplication", LOG_LEVEL_ALL);
|
||||
#endif
|
||||
//
|
||||
// Set up default values for the simulation. Use the DefaultValue::Bind()
|
||||
// technique to tell the system what subclass of Queue to use. The Bind
|
||||
// command command tells the queue factory which class to instantiate when the
|
||||
// queue factory is invoked in the topology code
|
||||
//
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
//
|
||||
// Allow the user to override any of the defaults and the above Bind() at
|
||||
// run-time, via command-line arguments
|
||||
//
|
||||
CommandLine::Parse (argc, argv);
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n4 = Create<InternetNode> ();
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
// Explicitly create the channels required by the topology (shown above).
|
||||
//
|
||||
Ptr<CsmaChannel> lan0 =
|
||||
CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<CsmaChannel> lan1 =
|
||||
CsmaTopology::CreateCsmaChannel(DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
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.");
|
||||
//
|
||||
// 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. Interpret nd2Lan0 as the net device we created for node two to
|
||||
// connect to Lan0.
|
||||
//
|
||||
uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan0,
|
||||
Mac48Address("08:00:2e:00:00:00"));
|
||||
uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan0,
|
||||
Mac48Address("08:00:2e:00:00:01"));
|
||||
uint32_t nd2Lan0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan0,
|
||||
Mac48Address("08:00:2e:00:00:02"));
|
||||
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
|
||||
|
||||
uint32_t nd2Lan1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1,
|
||||
Mac48Address("08:00:2e:00:00:03"));
|
||||
uint32_t nd3 __attribute__ ((unused)) =
|
||||
CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1,
|
||||
Mac48Address("08:00:2e:00:00:04"));
|
||||
uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan1,
|
||||
Mac48Address("08:00:2e:00:00:05"));
|
||||
NS_LOG_INFO ("Add IP Stack.");
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
NS_LOG_INFO ("nd0 = " << nd0);
|
||||
NS_LOG_INFO ("nd1 = " << nd1);
|
||||
NS_LOG_INFO ("nd2Lan0 = " << nd2Lan0);
|
||||
NS_LOG_INFO ("nd2Lan1 = " << nd2Lan1);
|
||||
NS_LOG_INFO ("nd3 = " << nd3);
|
||||
NS_LOG_INFO ("nd4 = " << nd3);
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"),
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"),
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
|
||||
//
|
||||
// We'll need these addresses later
|
||||
//
|
||||
Ipv4Address n2Lan0Addr ("10.1.1.3");
|
||||
Ipv4Address n2Lan1Addr ("10.1.2.1");
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan0, n2Lan0Addr,
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
//
|
||||
// Assign IP addresses to the net devices and associated interfaces on Lan1
|
||||
//
|
||||
CsmaIpv4Topology::AddIpv4Address (n2, nd2Lan1, n2Lan1Addr,
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n3, nd1, Ipv4Address ("10.1.2.2"),
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n4, nd4, Ipv4Address ("10.1.2.3"),
|
||||
Ipv4Mask ("255.255.255.0"));
|
||||
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). We just pick a
|
||||
// convenient number (225.0.0.0) and or in some bits to let us verify that
|
||||
// correct Ethernet multicast addresses are constructed down in the system.
|
||||
//
|
||||
//
|
||||
// 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");
|
||||
//
|
||||
// We are going to manually configure multicast routing. This means telling
|
||||
// node two that it should expect multicast data coming from IP address
|
||||
// 10.1.1.1 originally. It should expect these data coming in over its IP
|
||||
// interface connected to Lan0. When node two receives these packets, they
|
||||
// should be forwarded out the interface that connects it to Lan1.
|
||||
//
|
||||
// We're going to need the interface indices on node two corresponding to
|
||||
// these interfaces, which we call ifIndexLan0 and ifIndexLan1. The most
|
||||
// general way to get these interfaces is to look them up by IP address.
|
||||
// Looking back to the topology creation calls above, we saved the addresses
|
||||
// assigned to the interface connecting node two to Lan0 and Lan1. Now is
|
||||
// a fine time to find the interface indices on node two.
|
||||
//
|
||||
Ptr<Ipv4> ipv4;
|
||||
ipv4 = n2->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
|
||||
uint32_t ifIndexLan0 = ipv4->FindInterfaceForAddr (n2Lan0Addr);
|
||||
uint32_t ifIndexLan1 = ipv4->FindInterfaceForAddr (n2Lan1Addr);
|
||||
//
|
||||
// Now, we need to do is to call the AddMulticastRoute () method on node
|
||||
// two's Ipv4 interface and tell it that whenever it receives a packet on
|
||||
// the interface from Lan0, with the packet from the multicast source,
|
||||
// destined for the multicast group, it should forward these packets down
|
||||
// the interface connecting it to Lan1. (Note: the vector of output
|
||||
// interfaces is in case there are multiple net devices on a node -- not
|
||||
// true in this case).
|
||||
//
|
||||
std::vector<uint32_t> outputInterfaces (1);
|
||||
outputInterfaces[0] = ifIndexLan1;
|
||||
// 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;
|
||||
|
||||
ipv4->AddMulticastRoute (multicastSource, multicastGroup, ifIndexLan0,
|
||||
outputInterfaces);
|
||||
//
|
||||
// We need to specify how the source node handles multicasting. There are a
|
||||
// number of ways we can deal with this, we just need to pick one. The first
|
||||
// method is to add an explicit route out of the source node, just as we did
|
||||
// for the forwarding node. Use this method when you want to send packets out
|
||||
// multiple interfaces or send packets out different interfaces based on the
|
||||
// differing multicast groups. Since the source is local, there will be no
|
||||
// input interface over which packets are received, so use
|
||||
// Ipv4RoutingProtocol::IF_INDEX_ANY as a wildcard.
|
||||
//
|
||||
// A second way is to specify a multicast route using wildcards. If you
|
||||
// want to send multicasts out differing sets of interfaces based on the
|
||||
// multicast group, you can use AddMulticastRoute () but specify the origin
|
||||
// as a wildcard. If you want all multicasts to go out a single set of
|
||||
// interfaces, you can make both the origin and group a wildcard.
|
||||
//
|
||||
// If you have a simple system, where the source has a single interface, this
|
||||
// can be done via the SetDefaultMulticastRoute () method on the Ipv4
|
||||
// interface. This tells the system to send all multicasts out a single
|
||||
// specified network interface index.
|
||||
//
|
||||
// A last way is to specify a (or use an existing) default unicast route. The
|
||||
// multicast routing code uses the unicast default route as a multicast "route
|
||||
// of last resort." this method for is also on Ipv4 and is called
|
||||
// SetDefaultRoute ().
|
||||
//
|
||||
// Since this is a simple multicast example, we use the
|
||||
// SetDefaultMulticastRoute () approach. We are going to first need the
|
||||
// Ipv4 interface for node 0 which is the multicast source. We use this
|
||||
// interface to find the output interface index, and tell node zero to send
|
||||
// its multicast traffic out that interface.
|
||||
//
|
||||
ipv4 = n0->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
uint32_t ifIndexSrc = ipv4->FindInterfaceForAddr (multicastSource);
|
||||
ipv4->SetDefaultMulticastRoute (ifIndexSrc);
|
||||
//
|
||||
// As described above, node four will be the only node listening for the
|
||||
// multicast data. To enable forwarding bits up the protocol stack, we need
|
||||
// to tell the stack to join the multicast group.
|
||||
//
|
||||
ipv4 = n4->QueryInterface<Ipv4> (Ipv4::iid);
|
||||
ipv4->JoinMulticastGroup (multicastSource, multicastGroup);
|
||||
//
|
||||
// Create an OnOff application to send UDP datagrams from node zero to the
|
||||
// multicast group (node four will be listening).
|
||||
//
|
||||
// 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 port = 9; // Discard port (RFC 863)
|
||||
uint16_t multicastPort = 9; // Discard port (RFC 863)
|
||||
|
||||
// Configure a multicast packet generator that generates a packet
|
||||
// every few seconds
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress (multicastGroup, port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0),
|
||||
DataRate ("255b/s"),
|
||||
128);
|
||||
//
|
||||
// Tell the application when to start and stop.
|
||||
//
|
||||
ooff->Start(Seconds(1.));
|
||||
ooff->Stop (Seconds(10.));
|
||||
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
|
||||
// If you enable logging on this (above) it will print a log statement
|
||||
// for every packet received
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n4,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny(), multicastPort));
|
||||
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
// Trace output will be sent to the file "csma-multicast.tr"
|
||||
//
|
||||
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.");
|
||||
AsciiTrace asciitrace ("csma-multicast.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
PcapTrace pcaptrace ("csma-multicast.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
//
|
||||
// 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 ();
|
||||
|
||||
@@ -25,28 +25,13 @@
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/log.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/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#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;
|
||||
|
||||
@@ -61,58 +46,28 @@ main (int argc, char *argv[])
|
||||
//
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaOneSubnetExample", 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
|
||||
//
|
||||
// Set up default values for the simulation. Use the DefaultValue::Bind()
|
||||
// technique to tell the system what subclass of Queue to use. The Bind
|
||||
// command command tells the queue factory which class to instantiate when the
|
||||
// queue factory is invoked in the topology code
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
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::Parse (argc, argv);
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
NodeContainer c;
|
||||
c.Create (4);
|
||||
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
//
|
||||
// Explicitly create the channels required by the topology (shown above).
|
||||
//
|
||||
Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
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
|
||||
@@ -122,80 +77,58 @@ main (int argc, char *argv[])
|
||||
// created on the node. Interpret nd0 as the net device we created for node
|
||||
// zero.
|
||||
//
|
||||
uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
|
||||
Mac48Address("08:00:2e:00:00:00"));
|
||||
NetDeviceContainer nd0 = csma.Install (c);
|
||||
|
||||
uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
|
||||
Mac48Address("08:00:2e:00:00:01"));
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
|
||||
Mac48Address("08:00:2e:00:00:02"));
|
||||
|
||||
uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
|
||||
Mac48Address("08:00:2e:00:00:03"));
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
//
|
||||
// XXX BUGBUG
|
||||
// Need a better way to get the interface index. The point-to-point topology
|
||||
// as implemented can't return the index since it creates interfaces on both
|
||||
// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address). We need a
|
||||
// method on Ipv4 to find the interface index corresponding to a given ipv4
|
||||
// address.
|
||||
//
|
||||
// Assign IP addresses to the net devices and associated interfaces
|
||||
// on the lan. The AddIpv4Address method returns an Ipv4 interface index
|
||||
// which we do not need here.
|
||||
//
|
||||
CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address("10.1.1.1"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (nd0);
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address("10.1.1.2"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address("10.1.1.3"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address("10.1.1.4"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
//
|
||||
// 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)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.1.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
//
|
||||
// Tell the application when to start and stop.
|
||||
//
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
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
|
||||
//
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.1.1", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
onoff.SetAttribute ("Remote",
|
||||
AddressValue (InetSocketAddress (Ipv4Address ("10.1.1.1"), port)));
|
||||
ApplicationContainer app2 = onoff.Install (c.Get (3));
|
||||
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
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.");
|
||||
AsciiTrace asciitrace ("csma-one-subnet.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
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:
|
||||
@@ -203,8 +136,7 @@ main (int argc, char *argv[])
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
//
|
||||
PcapTrace pcaptrace ("csma-one-subnet.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
CsmaHelper::EnablePcapAll ("csma-one-subnet");
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
|
||||
@@ -33,134 +33,79 @@
|
||||
#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/log.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/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/queue.h"
|
||||
#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");
|
||||
|
||||
static Ptr<CsmaNetDevice>
|
||||
CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
|
||||
{
|
||||
Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
|
||||
device->Attach (channel);
|
||||
Ptr<Queue> queue = Queue::CreateDefault ();
|
||||
device->AddQueue (queue);
|
||||
return device;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaPacketSocketExample", 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
|
||||
|
||||
CommandLine::Parse (argc, argv);
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// Here, we will explicitly create four nodes. In more sophisticated
|
||||
// topologies, we could configure a node factory.
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
// Here, we will explicitly create four nodes.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<Node> ();
|
||||
Ptr<Node> n1 = Create<Node> ();
|
||||
Ptr<Node> n2 = Create<Node> ();
|
||||
Ptr<Node> n3 = Create<Node> ();
|
||||
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 = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
|
||||
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.");
|
||||
Ptr<NetDevice> n0If = CreateCsmaDevice (n0, channel);
|
||||
Ptr<NetDevice> n1If = CreateCsmaDevice (n1, channel);
|
||||
Ptr<NetDevice> n2If = CreateCsmaDevice (n2, channel);
|
||||
Ptr<NetDevice> n3If = CreateCsmaDevice (n3, channel);
|
||||
CsmaHelper csma;
|
||||
csma.SetDeviceParameter ("EncapsulationMode", StringValue ("Llc"));
|
||||
NetDeviceContainer devs = csma.Install (c, channel);
|
||||
|
||||
// create the address which identifies n1 from n0
|
||||
PacketSocketAddress n0ToN1;
|
||||
n0ToN1.SetSingleDevice (n0If->GetIfIndex ()); // set outgoing interface for outgoing packets
|
||||
n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets
|
||||
n0ToN1.SetProtocol (2); // set arbitrary protocol for outgoing packets
|
||||
|
||||
// create the address which identifies n0 from n3
|
||||
PacketSocketAddress n3ToN0;
|
||||
n3ToN0.SetSingleDevice (n3If->GetIfIndex ());
|
||||
n3ToN0.SetPhysicalAddress (n0If->GetAddress ());
|
||||
n3ToN0.SetProtocol (3);
|
||||
|
||||
// Create the OnOff application to send raw datagrams of size
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
// from n0 to n1
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
n0ToN1,
|
||||
"Packet",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
// 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)));
|
||||
|
||||
// Create a similar flow from n3 to n0, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
n3ToN0,
|
||||
"Packet",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.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.");
|
||||
AsciiTrace asciitrace ("csma-packet-socket.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
std::ofstream os;
|
||||
os.open ("csma-packet-socket.tr");
|
||||
csma.EnableAsciiAll (os);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
|
||||
@@ -36,34 +36,10 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
#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/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#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;
|
||||
@@ -73,115 +49,58 @@ NS_LOG_COMPONENT_DEFINE ("MixedGlobalRoutingExample");
|
||||
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 ("MixedGlobalRoutingExample", 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
|
||||
// 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 DefaultValue::Bind command tells the queue factory which
|
||||
// class to instantiate, when the queue factory is invoked in the
|
||||
// topology code
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
|
||||
//DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);
|
||||
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::Parse (argc, argv);
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
Ptr<Node> n4 = Create<InternetNode> ();
|
||||
Ptr<Node> n5 = Create<InternetNode> ();
|
||||
Ptr<Node> n6 = Create<InternetNode> ();
|
||||
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.");
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate (5000000), MilliSeconds (2));
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate (5000000), MilliSeconds (2));
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n5, n6, DataRate (1500000), MilliSeconds (10));
|
||||
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
|
||||
Ptr<CsmaChannel> channelc0 =
|
||||
CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, channelc0,
|
||||
Mac48Address("10:54:23:54:23:50"));
|
||||
uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, channelc0,
|
||||
Mac48Address("10:54:23:54:23:51"));
|
||||
uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, channelc0,
|
||||
Mac48Address("10:54:23:54:23:52"));
|
||||
uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, channelc0,
|
||||
Mac48Address("10:54:23:54:23:53"));
|
||||
|
||||
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.");
|
||||
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, n5, Ipv4Address ("10.1.3.1"),
|
||||
n6, Ipv4Address ("10.1.3.2"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0"));
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
ipv4.Assign (d1d2);
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (
|
||||
n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0"));
|
||||
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.
|
||||
@@ -191,31 +110,24 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable (1),
|
||||
ConstantVariable (0),
|
||||
DataRate("300bps"),
|
||||
50);
|
||||
// Start the application
|
||||
ooff->Start (Seconds (1.0));
|
||||
ooff->Stop (Seconds (10.0));
|
||||
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));
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-global-routing.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("mixed-global-routing.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
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);
|
||||
|
||||
// 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 ("mixed-global-routing.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
@@ -37,30 +37,10 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
#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/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#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;
|
||||
@@ -75,41 +55,20 @@ main (int argc, char *argv[])
|
||||
#if 0
|
||||
LogComponentEnable("GlobalRouteManager", LOG_LOGIC);
|
||||
LogComponentEnable("GlobalRouter", LOG_LOGIC);
|
||||
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
|
||||
// Set up some default values for the simulation. Use the
|
||||
// DefaultValue::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
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "300b/s");
|
||||
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
|
||||
@@ -117,61 +76,61 @@ main (int argc, char *argv[])
|
||||
// rather than recompiling
|
||||
// e.g. waf --run "simple-alternate-routing --AlternateCost=5"
|
||||
uint16_t sampleMetric = 1;
|
||||
CommandLine::AddArgValue ("AlternateCost",
|
||||
"This metric is used in the example script between n3 and n1 ",
|
||||
sampleMetric);
|
||||
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
|
||||
CommandLine::Parse (argc, argv);
|
||||
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.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
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.");
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate (5000000), MilliSeconds (2));
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate (5000000), MilliSeconds (2));
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate (1500000), MilliSeconds (10));
|
||||
|
||||
Ptr<PointToPointChannel> channel3 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n3, DataRate (1500000), MilliSeconds (100));
|
||||
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.");
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address ("10.0.0.1"),
|
||||
n2, Ipv4Address ("10.0.0.2"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.0.0.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel1, n1, Ipv4Address ("10.1.1.1"),
|
||||
n2, Ipv4Address ("10.1.1.2"));
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel2, n2, Ipv4Address ("10.2.2.1"),
|
||||
n3, Ipv4Address ("10.2.2.2"));
|
||||
ipv4.SetBase ("10.2.2.0", "255.255.255.0");
|
||||
ipv4.Assign (d3d2);
|
||||
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel3, n1, Ipv4Address ("10.3.3.1"),
|
||||
n3, Ipv4Address ("10.3.3.2"));
|
||||
ipv4.SetBase ("10.3.3.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i3 = ipv4.Assign (d1d3);
|
||||
|
||||
PointToPointTopology::SetIpv4Metric (
|
||||
channel3, n1, n3, sampleMetric);
|
||||
i1i3.SetMetric (0, sampleMetric);
|
||||
i1i3.SetMetric (1, sampleMetric);
|
||||
|
||||
// Create router nodes, initialize routing database and set up the routing
|
||||
// tables in the nodes.
|
||||
@@ -182,38 +141,26 @@ main (int argc, char *argv[])
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
|
||||
// Create a flow from n3 to n1, starting at time 1.1 seconds
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.1.1", port),
|
||||
"Udp",
|
||||
ConstantVariable (1),
|
||||
ConstantVariable (0));
|
||||
// Start the application
|
||||
ooff->Start (Seconds (1.1));
|
||||
ooff->Stop (Seconds (10.0));
|
||||
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
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
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));
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-alternate-routing.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("simple-alternate-routing.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-alternate-routing.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-alternate-routing.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-alternate-routing");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
|
||||
@@ -38,33 +38,13 @@
|
||||
// - Tracing of queues and packet receptions to file
|
||||
// "simple-error-model.tr"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.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/default-value.h"
|
||||
#include "ns3/component-manager.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/error-model.h"
|
||||
#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;
|
||||
|
||||
@@ -79,159 +59,122 @@ main (int argc, char *argv[])
|
||||
LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
// Set up some default values for the simulation. Use the Bind()
|
||||
// technique to tell the system what subclass of ErrorModel to use
|
||||
DefaultValue::Bind ("ErrorModel", "RateErrorModel");
|
||||
// Set a few parameters
|
||||
DefaultValue::Bind ("RateErrorModelErrorRate", "0.01");
|
||||
DefaultValue::Bind ("RateErrorModelErrorUnit", "EU_PKT");
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
// 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::Parse (argc, argv);
|
||||
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.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
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.");
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate(5000000), MilliSeconds(2));
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", DataRateValue (DataRate (5000000)));
|
||||
p2p.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate(5000000), MilliSeconds(2));
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate(1500000), MilliSeconds(10));
|
||||
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.");
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address("10.1.1.1"),
|
||||
n2, Ipv4Address("10.1.1.2"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
ipv4.Assign (d0d2);
|
||||
|
||||
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"));
|
||||
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i1i2 = ipv4.Assign (d1d2);
|
||||
|
||||
// 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
|
||||
NS_LOG_INFO ("Add Static Routes.");
|
||||
PointToPointTopology::AddIpv4Routes(n0, n2, channel0);
|
||||
PointToPointTopology::AddIpv4Routes(n1, n2, channel1);
|
||||
PointToPointTopology::AddIpv4Routes(n2, n3, channel2);
|
||||
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)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
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
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
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
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
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 = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
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);
|
||||
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
|
||||
//
|
||||
// We want to add an error model to node 3's NetDevice
|
||||
// We can obtain a handle to the NetDevice via the channel and node
|
||||
// pointers
|
||||
Ptr<PointToPointNetDevice> nd3 = PointToPointTopology::GetNetDevice
|
||||
(n3, channel2);
|
||||
// Create an ErrorModel based on the implementation (constructor)
|
||||
// specified by the default classId
|
||||
Ptr<ErrorModel> em = ErrorModel::CreateDefault ();
|
||||
NS_ASSERT (em != 0);
|
||||
// Now, query interface on the resulting em pointer to see if a
|
||||
// RateErrorModel interface exists. If so, set the packet error rate
|
||||
Ptr<RateErrorModel> bem = em->QueryInterface<RateErrorModel>
|
||||
(RateErrorModel::iid);
|
||||
if (bem)
|
||||
{
|
||||
bem->SetRandomVariable (UniformVariable ());
|
||||
bem->SetRate (0.001);
|
||||
}
|
||||
nd3->AddReceiveErrorModel (em);
|
||||
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
|
||||
Ptr<PointToPointNetDevice> nd2 = PointToPointTopology::GetNetDevice
|
||||
(n2, channel0);
|
||||
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 = Create<ListErrorModel> ();
|
||||
Ptr<ListErrorModel> pem = CreateObject<ListErrorModel> ();
|
||||
pem->SetList (sampleList);
|
||||
nd2->AddReceiveErrorModel (pem);
|
||||
d0d2.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (pem));
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-error-model.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("simple-error-model.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-error-model.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-error-model");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
|
||||
@@ -42,30 +42,10 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
#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/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#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;
|
||||
@@ -79,81 +59,60 @@ main (int argc, char *argv[])
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
#if 0
|
||||
LogComponentEnable ("SimpleGlobalRoutingExample", 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
|
||||
|
||||
//
|
||||
// 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
|
||||
// DefaultValue::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
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
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::Parse (argc, argv);
|
||||
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.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
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.");
|
||||
Ptr<PointToPointChannel> channel0 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n0, n2, DataRate (5000000), MilliSeconds (2));
|
||||
PointToPointHelper p2p;
|
||||
p2p.SetDeviceParameter ("DataRate", StringValue ("5Mbps"));
|
||||
p2p.SetChannelParameter ("Delay", StringValue ("2ms"));
|
||||
NetDeviceContainer d0d2 = p2p.Install (n0n2);
|
||||
|
||||
Ptr<PointToPointChannel> channel1 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n1, n2, DataRate (5000000), MilliSeconds (2));
|
||||
NetDeviceContainer d1d2 = p2p.Install (n1n2);
|
||||
|
||||
Ptr<PointToPointChannel> channel2 =
|
||||
PointToPointTopology::AddPointToPointLink (
|
||||
n2, n3, DataRate (1500000), MilliSeconds (10));
|
||||
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.");
|
||||
PointToPointTopology::AddIpv4Addresses (
|
||||
channel0, n0, Ipv4Address ("10.1.1.1"),
|
||||
n2, Ipv4Address ("10.1.1.2"));
|
||||
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);
|
||||
|
||||
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"));
|
||||
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.
|
||||
@@ -163,59 +122,37 @@ main (int argc, char *argv[])
|
||||
// 210 bytes at a rate of 448 Kb/s
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable (1),
|
||||
ConstantVariable (0));
|
||||
// Start the application
|
||||
ooff->Start (Seconds (1.0));
|
||||
ooff->Stop (Seconds (10.0));
|
||||
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
|
||||
// The last argument "true" disables output from the Receive callback
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
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
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
ConstantVariable (1),
|
||||
ConstantVariable (0));
|
||||
// Start the application
|
||||
ooff->Start (Seconds (1.1));
|
||||
ooff->Stop (Seconds (10.0));
|
||||
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 = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
apps = sink.Install (c.Get (1));
|
||||
apps.Start (Seconds (1.1));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events
|
||||
// Trace output will be sent to the simple-global-routing.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("simple-global-routing.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-global-routing.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
std::ofstream ascii;
|
||||
ascii.open ("simple-global-routing.tr");
|
||||
PointToPointHelper::EnablePcapAll ("simple-global-routing");
|
||||
PointToPointHelper::EnableAsciiAll (ascii);
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
//
|
||||
// Network topology
|
||||
//
|
||||
// n0
|
||||
// n0
|
||||
// \ 5 Mb/s, 2ms
|
||||
// \ 1.5Mb/s, 10ms
|
||||
// n2 -------------------------n3
|
||||
// n2 -------------------------n3---------n4
|
||||
// /
|
||||
// / 5 Mb/s, 2ms
|
||||
// n1
|
||||
@@ -35,37 +35,21 @@
|
||||
// - 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.tr"
|
||||
// - Tracing of queues and packet receptions to file "simple-point-to-point-olsr.tr"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
#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/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
#include "ns3/olsr.h"
|
||||
#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 ("SimplePointToPointExample");
|
||||
NS_LOG_COMPONENT_DEFINE ("SimpleGlobalRoutingExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
@@ -73,161 +57,116 @@ 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);
|
||||
|
||||
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);
|
||||
LogComponentEnable ("SimpleGlobalRoutingExample", LOG_LEVEL_INFO);
|
||||
#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
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
// The below Bind command tells the queue factory which class to
|
||||
// instantiate, when the queue factory is invoked in the topology code
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
// Set up some default values for the simulation. Use the
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
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
|
||||
// Bind()s at run-time, via command-line arguments
|
||||
CommandLine::Parse (argc, argv);
|
||||
// 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.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
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.");
|
||||
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));
|
||||
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.");
|
||||
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"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i02 = ipv4.Assign (nd02);
|
||||
|
||||
// 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
|
||||
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.");
|
||||
olsr::EnableAllNodes ();
|
||||
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)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
OnOffHelper onoff ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (i34.GetAddress (1), port));
|
||||
onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
|
||||
onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.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
|
||||
sink = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
PacketSinkHelper sink ("ns3::UdpSocketFactory",
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
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-point-to-point.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("simple-point-to-point-olsr.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
apps = sink.Install (c.Get (3));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-point-to-point.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("simple-point-to-point-olsr.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
// 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::StopAt (Seconds (10));
|
||||
Simulator::Run ();
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,234 +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 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.tr"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#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/point-to-point-channel.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/point-to-point-topology.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/packet-sink.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("SimplePointToPointExample");
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
// 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
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
|
||||
DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
|
||||
DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
|
||||
|
||||
//DefaultValue::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.
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
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
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
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.
|
||||
NS_LOG_INFO ("Assign 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
|
||||
NS_LOG_INFO ("Add Static Routes.");
|
||||
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
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
uint16_t port = 9; // Discard port (RFC 863)
|
||||
Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
|
||||
n0,
|
||||
InetSocketAddress ("10.1.3.2", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.0));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create an optional packet sink to receive these packets
|
||||
Ptr<PacketSink> sink = Create<PacketSink> (
|
||||
n3,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.0));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Create a similar flow from n3 to n1, starting at time 1.1 seconds
|
||||
ooff = Create<OnOffApplication> (
|
||||
n3,
|
||||
InetSocketAddress ("10.1.2.1", port),
|
||||
"Udp",
|
||||
ConstantVariable(1),
|
||||
ConstantVariable(0));
|
||||
// Start the application
|
||||
ooff->Start(Seconds(1.1));
|
||||
ooff->Stop (Seconds(10.0));
|
||||
|
||||
// Create a packet sink to receive these packets
|
||||
sink = Create<PacketSink> (
|
||||
n1,
|
||||
InetSocketAddress (Ipv4Address::GetAny (), port),
|
||||
"Udp");
|
||||
// Start the sink
|
||||
sink->Start (Seconds (1.1));
|
||||
sink->Stop (Seconds (10.0));
|
||||
|
||||
// Here, finish off packet routing configuration
|
||||
// This will likely set by some global StaticRouting object in the future
|
||||
NS_LOG_INFO ("Set Default Routes.");
|
||||
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-point-to-point.tr file
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("simple-point-to-point.tr");
|
||||
asciitrace.TraceAllQueues ();
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
|
||||
// Also configure some tcpdump traces; each interface will be traced
|
||||
// The output files will be named
|
||||
// simple-point-to-point.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
PcapTrace pcaptrace ("simple-point-to-point.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::StopAt (Seconds (10));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -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 ();
|
||||
}
|
||||
@@ -25,28 +25,10 @@
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "udp-echo.tr"
|
||||
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/log.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/csma-channel.h"
|
||||
#include "ns3/csma-net-device.h"
|
||||
#include "ns3/csma-topology.h"
|
||||
#include "ns3/csma-ipv4-topology.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/ipv4.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/ipv4-route.h"
|
||||
#include "ns3/udp-echo-client.h"
|
||||
#include "ns3/udp-echo-server.h"
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -84,90 +66,50 @@ main (int argc, char *argv[])
|
||||
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_ALL);
|
||||
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_ALL);
|
||||
#endif
|
||||
//
|
||||
// Set up default values for the simulation. Use the DefaultValue::Bind()
|
||||
// technique to tell the system what subclass of Queue to use. The Bind
|
||||
// command command tells the queue factory which class to instantiate when the
|
||||
// queue factory is invoked in the topology code
|
||||
//
|
||||
DefaultValue::Bind ("Queue", "DropTailQueue");
|
||||
//
|
||||
|
||||
// Allow the user to override any of the defaults and the above Bind() at
|
||||
// run-time, via command-line arguments
|
||||
//
|
||||
CommandLine::Parse (argc, argv);
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
Ptr<Node> n0 = Create<InternetNode> ();
|
||||
Ptr<Node> n1 = Create<InternetNode> ();
|
||||
Ptr<Node> n2 = Create<InternetNode> ();
|
||||
Ptr<Node> n3 = Create<InternetNode> ();
|
||||
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).
|
||||
//
|
||||
Ptr<CsmaChannel> lan = CsmaTopology::CreateCsmaChannel(
|
||||
DataRate(5000000), MilliSeconds(2));
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelParameter ("DataRate", DataRateValue (DataRate(5000000)));
|
||||
csma.SetChannelParameter ("Delay", TimeValue (MilliSeconds (2)));
|
||||
NetDeviceContainer d = csma.Install (n);
|
||||
|
||||
NS_LOG_INFO ("Build Topology.");
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan,
|
||||
Mac48Address("08:00:2e:00:00:00"));
|
||||
|
||||
uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan,
|
||||
Mac48Address("08:00:2e:00:00:01"));
|
||||
|
||||
uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan,
|
||||
Mac48Address("08:00:2e:00:00:02"));
|
||||
|
||||
uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan,
|
||||
Mac48Address("08:00:2e:00:00:03"));
|
||||
Ipv4AddressHelper ipv4;
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
//
|
||||
// XXX BUGBUG
|
||||
// Need a better way to get the interface index. The point-to-point topology
|
||||
// as implemented can't return the index since it creates interfaces on both
|
||||
// sides (i.e., it does AddIpv4Addresses, not AddIpv4Address). We need a
|
||||
// method on Ipv4 to find the interface index corresponding to a given ipv4
|
||||
// address.
|
||||
//
|
||||
// Assign IP addresses to the net devices and associated interfaces
|
||||
// on the lan. The AddIpv4Address method returns an Ipv4 interface index
|
||||
// which we do not need here.
|
||||
//
|
||||
CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address("10.1.1.1"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address("10.1.1.2"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address("10.1.1.3"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
|
||||
CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address("10.1.1.4"),
|
||||
Ipv4Mask("255.255.255.0"));
|
||||
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));
|
||||
|
||||
Ptr<UdpEchoServer> server = Create<UdpEchoServer> (n1, port);
|
||||
//
|
||||
// Create a UdpEchoClient application to send UDP datagrams from node zero to
|
||||
// node one.
|
||||
@@ -175,34 +117,20 @@ main (int argc, char *argv[])
|
||||
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));
|
||||
|
||||
Ptr<UdpEchoClient> client = Create<UdpEchoClient> (n0, "10.1.1.2", port,
|
||||
maxPacketCount, interPacketInterval, packetSize);
|
||||
//
|
||||
// Tell the applications when to start and stop.
|
||||
//
|
||||
server->Start(Seconds(1.));
|
||||
client->Start(Seconds(2.));
|
||||
std::ofstream ascii;
|
||||
ascii.open ("udp-echo.tr");
|
||||
CsmaHelper::EnablePcapAll ("udp-echo");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
|
||||
server->Stop (Seconds(10.));
|
||||
client->Stop (Seconds(10.));
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
// Trace output will be sent to the file "udp-echo.tr"
|
||||
//
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
AsciiTrace asciitrace ("udp-echo.tr");
|
||||
asciitrace.TraceAllNetDeviceRx ();
|
||||
asciitrace.TraceAllQueues ();
|
||||
//
|
||||
// Also configure some tcpdump traces; each interface will be traced.
|
||||
// The output files will be named:
|
||||
// udp-echo.pcap-<nodeId>-<interfaceId>
|
||||
// and can be read by the "tcpdump -r" command (use "-tt" option to
|
||||
// display timestamps correctly)
|
||||
//
|
||||
PcapTrace pcaptrace ("udp-echo.pcap");
|
||||
pcaptrace.TraceAllIp ();
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -2,46 +2,60 @@
|
||||
|
||||
def build(bld):
|
||||
|
||||
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-node', '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-node', 'global-routing'])
|
||||
['point-to-point', 'internet-stack', 'global-routing'])
|
||||
obj.source = 'simple-alternate-routing.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-point-to-point',
|
||||
['point-to-point', 'internet-node'])
|
||||
obj.source = 'simple-point-to-point.cc'
|
||||
|
||||
obj = bld.create_ns3_program('simple-error-model',
|
||||
['point-to-point', 'internet-node'])
|
||||
['point-to-point', 'internet-stack'])
|
||||
obj.source = 'simple-error-model.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-one-subnet',
|
||||
['csma', 'internet-node'])
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-one-subnet.cc'
|
||||
|
||||
obj = bld.create_ns3_program('udp-echo',
|
||||
['csma', 'internet-node'])
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'udp-echo.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-broadcast',
|
||||
['csma', 'internet-node'])
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-broadcast.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-packet-socket',
|
||||
['csma', 'internet-node'])
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-packet-socket.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-multicast',
|
||||
['csma', 'internet-node'])
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-multicast.cc'
|
||||
|
||||
obj = bld.create_ns3_program( 'mixed-global-routing',
|
||||
['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
|
||||
['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-node', '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")
|
||||
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../waf "$@"
|
||||
@@ -1,251 +0,0 @@
|
||||
/* -*- 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/wifi-net-device.h"
|
||||
#include "ns3/wifi-channel.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/gnuplot.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
static uint32_t g_bytesTotal = 0;
|
||||
static GnuplotDataset *g_output = 0;
|
||||
|
||||
static Ptr<Node>
|
||||
CreateAdhocNode (Ptr<WifiChannel> channel,
|
||||
Vector position, const char *address)
|
||||
{
|
||||
Ptr<Node> node = Create<Node> ();
|
||||
Ptr<AdhocWifiNetDevice> device = Create<AdhocWifiNetDevice> (node, Mac48Address (address));
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = Create<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AddInterface (mobility);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
static Vector
|
||||
GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
return mobility->GetPosition ();
|
||||
}
|
||||
|
||||
static void
|
||||
AdvancePosition (Ptr<Node> node)
|
||||
{
|
||||
Vector pos = GetPosition (node);
|
||||
double mbs = ((g_bytesTotal * 8.0) / 1000000);
|
||||
g_bytesTotal = 0;
|
||||
g_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), &AdvancePosition, node);
|
||||
}
|
||||
|
||||
static void
|
||||
ReceivePacket (Ptr<Socket> socket, Ptr<Packet> packet, const Address &address)
|
||||
{
|
||||
g_bytesTotal += packet->GetSize ();
|
||||
}
|
||||
|
||||
static Ptr<Socket>
|
||||
SetupPacketReceive (Ptr<Node> node, uint16_t port)
|
||||
{
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Packet");
|
||||
Ptr<SocketFactory> socketFactory = node->QueryInterface<SocketFactory> (iid);
|
||||
Ptr<Socket> sink = socketFactory->CreateSocket ();
|
||||
sink->Bind ();
|
||||
sink->SetRecvCallback (MakeCallback (&ReceivePacket));
|
||||
return sink;
|
||||
}
|
||||
|
||||
static void
|
||||
RunOneExperiment (void)
|
||||
{
|
||||
g_bytesTotal = 0;
|
||||
|
||||
Ptr<WifiChannel> channel = Create<WifiChannel> ();
|
||||
|
||||
Ptr<Node> a = CreateAdhocNode (channel,
|
||||
Vector (5.0,0.0,0.0),
|
||||
"00:00:00:00:00:01");
|
||||
Ptr<Node> b = CreateAdhocNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:02");
|
||||
|
||||
PacketSocketAddress destination = PacketSocketAddress ();
|
||||
destination.SetProtocol (1);
|
||||
destination.SetSingleDevice (0);
|
||||
destination.SetPhysicalAddress (Mac48Address ("00:00:00:00:00:02"));
|
||||
Ptr<Application> app = Create<OnOffApplication> (a, destination,
|
||||
"Packet",
|
||||
ConstantVariable (250),
|
||||
ConstantVariable (0),
|
||||
DataRate (60000000),
|
||||
2000);
|
||||
|
||||
app->Start (Seconds (0.5));
|
||||
app->Stop (Seconds (250.0));
|
||||
|
||||
Simulator::Schedule (Seconds (1.5), &AdvancePosition, b);
|
||||
Ptr<Socket> recvSink = SetupPacketReceive (b, 10);
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
Simulator::SetLinkedList ();
|
||||
|
||||
// disable fragmentation
|
||||
DefaultValue::Bind ("WifiFragmentationThreshold", "2200");
|
||||
CommandLine::Parse (argc, argv);
|
||||
|
||||
Gnuplot gnuplot = Gnuplot ("reference-rates.png");
|
||||
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
|
||||
g_output = new GnuplotDataset ("54mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "54mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("48mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "48mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("36mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "36mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("24mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "24mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("18mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "18mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("12mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "12mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("9mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "9mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("6mb");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "ConstantRate");
|
||||
DefaultValue::Bind ("WifiConstantDataRate", "6mb");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
gnuplot = Gnuplot ("rate-control.png");
|
||||
|
||||
DefaultValue::Bind ("WifiPhyStandard", "holland");
|
||||
|
||||
g_output = new GnuplotDataset ("arf");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Arf");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("aarf");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Aarf");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
g_output = new GnuplotDataset ("ideal");
|
||||
g_output->SetStyle (GnuplotDataset::LINES);
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Ideal");
|
||||
RunOneExperiment ();
|
||||
gnuplot.AddDataset (*g_output);
|
||||
delete g_output;
|
||||
|
||||
gnuplot.GenerateOutput (std::cout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/* -*- 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/wifi-net-device.h"
|
||||
#include "ns3/wifi-channel.h"
|
||||
#include "ns3/wifi-phy.h"
|
||||
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/onoff-application.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/packet-socket-address.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/node-list.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
void
|
||||
WifiNetDeviceTrace (const TraceContext &context, Ptr<const Packet> p, Mac48Address address)
|
||||
{
|
||||
std::cout << context << " ad=" << address << " p: " << p << std::endl;
|
||||
}
|
||||
void
|
||||
WifiPhyStateTrace (const TraceContext &context, Time start, Time duration, enum WifiPhy::State state)
|
||||
{
|
||||
std::cout << context << " 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 Ptr<Node>
|
||||
CreateApNode (Ptr<WifiChannel> channel,
|
||||
Vector position,
|
||||
const char *macAddress,
|
||||
Ssid ssid,
|
||||
Time at)
|
||||
{
|
||||
Ptr<Node> node = Create<Node> ();
|
||||
Ptr<NqapWifiNetDevice> device = Create<NqapWifiNetDevice> (node, Mac48Address (macAddress));
|
||||
device->SetSsid (ssid);
|
||||
Simulator::Schedule (at, &NqapWifiNetDevice::StartBeaconing, device);
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = Create<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AddInterface (mobility);
|
||||
return node;
|
||||
}
|
||||
|
||||
static Ptr<Node>
|
||||
CreateStaNode (Ptr<WifiChannel> channel,
|
||||
Vector position,
|
||||
const char *macAddress,
|
||||
Ssid ssid)
|
||||
{
|
||||
Ptr<Node> node = Create<Node> ();
|
||||
Ptr<NqstaWifiNetDevice> device = Create<NqstaWifiNetDevice> (node, Mac48Address (macAddress));
|
||||
Simulator::ScheduleNow (&NqstaWifiNetDevice::StartActiveAssociation, device,
|
||||
ssid);
|
||||
device->Attach (channel);
|
||||
Ptr<MobilityModel> mobility = Create<StaticMobilityModel> ();
|
||||
mobility->SetPosition (position);
|
||||
node->AddInterface (mobility);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
SetPosition (Ptr<Node> node, Vector position)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
mobility->SetPosition (position);
|
||||
}
|
||||
|
||||
static Vector
|
||||
GetPosition (Ptr<Node> node)
|
||||
{
|
||||
Ptr<MobilityModel> mobility = node->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
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[])
|
||||
{
|
||||
Simulator::SetLinkedList ();
|
||||
|
||||
Packet::EnableMetadata ();
|
||||
|
||||
//Simulator::EnableLogTo ("80211.log");
|
||||
|
||||
|
||||
// enable rts cts all the time.
|
||||
DefaultValue::Bind ("WifiRtsCtsThreshold", "0");
|
||||
// disable fragmentation
|
||||
DefaultValue::Bind ("WifiFragmentationThreshold", "2200");
|
||||
DefaultValue::Bind ("WifiRateControlAlgorithm", "Aarf");
|
||||
//DefaultValue::Bind ("WifiRateControlAlgorithm", "Arf");
|
||||
|
||||
Ptr<WifiChannel> channel = Create<WifiChannel> ();
|
||||
Ssid ssid = Ssid ("mathieu");
|
||||
|
||||
Ptr<Node> a = CreateApNode (channel,
|
||||
Vector (5.0,0.0,0.0),
|
||||
"00:00:00:00:00:01",
|
||||
ssid,
|
||||
Seconds (0.1));
|
||||
Simulator::Schedule (Seconds (1.0), &AdvancePosition, a);
|
||||
|
||||
Ptr<Node> b = CreateStaNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:02",
|
||||
ssid);
|
||||
|
||||
Ptr<Node> c = CreateStaNode (channel,
|
||||
Vector (0.0, 0.0, 0.0),
|
||||
"00:00:00:00:00:03",
|
||||
ssid);
|
||||
|
||||
PacketSocketAddress destination = PacketSocketAddress ();
|
||||
destination.SetProtocol (1);
|
||||
destination.SetSingleDevice (0);
|
||||
destination.SetPhysicalAddress (Mac48Address ("00:00:00:00:00:03"));
|
||||
Ptr<Application> app = Create<OnOffApplication> (b, destination,
|
||||
"Packet",
|
||||
ConstantVariable (42),
|
||||
ConstantVariable (0));
|
||||
app->Start (Seconds (0.5));
|
||||
app->Stop (Seconds (43.0));
|
||||
|
||||
//NodeList::Connect ("/nodes/*/devices/*/*", MakeCallback (&WifiNetDeviceTrace));
|
||||
//NodeList::Connect ("/nodes/*/devices/*/phy/state", MakeCallback (&WifiPhyStateTrace));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
Simulator::Destroy ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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,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,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/log.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 NumericDefaultValue<int> defaultTestInt1 ("testInt1", "helpInt1", 33);
|
||||
static NumericDefaultValue<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)
|
||||
{
|
||||
std::cerr<<"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
|
||||
//
|
||||
DefaultValue::Bind("testInt1", "57");
|
||||
|
||||
TestClass* testclass = new TestClass ();
|
||||
NS_LOG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
|
||||
NS_LOG_UNCOND("TestInt1 default value (" << testclass->m_testInt1 << ")");
|
||||
NS_LOG_UNCOND("TestInt2 default value (" << testclass->m_testInt2 << ")");
|
||||
delete testclass;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,45 +1,50 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/grid-topology.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/command-line.h"
|
||||
#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::Parse (argc, argv);
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
std::vector<Ptr<Object> > nodes;
|
||||
NodeContainer nodes;
|
||||
|
||||
// create an array of empty nodes for testing purposes
|
||||
for (uint32_t i = 0; i < 120; i++)
|
||||
{
|
||||
nodes.push_back (Create<InternetNode> ());
|
||||
}
|
||||
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
|
||||
GridTopology grid (-100, -100, 20, 5, 20);
|
||||
|
||||
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.
|
||||
grid.SetMobilityModel (StaticMobilityModel::cid);
|
||||
// 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.
|
||||
grid.LayoutRowFirst (nodes.begin (), nodes.end ());
|
||||
mobility.Install (nodes);
|
||||
|
||||
// iterate our nodes and print their position.
|
||||
for (std::vector<Ptr<Object> >::const_iterator j = nodes.begin ();
|
||||
j != nodes.end (); j++)
|
||||
for (NodeContainer::Iterator j = nodes.Begin ();
|
||||
j != nodes.End (); ++j)
|
||||
{
|
||||
Ptr<Object> object = *j;
|
||||
Ptr<MobilityModel> position = object->QueryInterface<MobilityModel> (MobilityModel::iid);
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ using namespace ns3;
|
||||
class MyHeader : public Header
|
||||
{
|
||||
public:
|
||||
static uint32_t GetUid (void);
|
||||
|
||||
MyHeader ();
|
||||
virtual ~MyHeader ();
|
||||
@@ -19,11 +18,12 @@ public:
|
||||
void SetData (uint16_t data);
|
||||
uint16_t GetData (void) const;
|
||||
|
||||
std::string GetName (void) const;
|
||||
void Print (std::ostream &os) const;
|
||||
void Serialize (Buffer::Iterator start) const;
|
||||
uint32_t Deserialize (Buffer::Iterator start);
|
||||
uint32_t GetSerializedSize (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;
|
||||
};
|
||||
@@ -36,24 +36,20 @@ MyHeader::MyHeader ()
|
||||
MyHeader::~MyHeader ()
|
||||
{}
|
||||
|
||||
uint32_t
|
||||
MyHeader::GetUid (void)
|
||||
TypeId
|
||||
MyHeader::GetTypeId (void)
|
||||
{
|
||||
// This string is used by the internals of the packet
|
||||
// code to keep track of the packet metadata.
|
||||
// You need to make sure that this string is absolutely
|
||||
// unique. The code will detect any duplicate string.
|
||||
static uint32_t uid = AllocateUid<MyHeader> ("MyHeader.test.nsnam.org");
|
||||
return uid;
|
||||
static TypeId tid = TypeId ("ns3::MyHeader")
|
||||
.SetParent<Header> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
TypeId
|
||||
MyHeader::GetInstanceTypeId (void) const
|
||||
{
|
||||
return GetTypeId ();
|
||||
}
|
||||
|
||||
std::string
|
||||
MyHeader::GetName (void) const
|
||||
{
|
||||
// This string is used to identify the type of
|
||||
// my header by the packet printing routines.
|
||||
return "MYHEADER";
|
||||
}
|
||||
void
|
||||
MyHeader::Print (std::ostream &os) const
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
#include "ns3/tag.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace ns3;
|
||||
@@ -27,22 +28,12 @@ using namespace ns3;
|
||||
class MyTag : public Tag
|
||||
{
|
||||
public:
|
||||
// we have to define a public constructor
|
||||
MyTag ();
|
||||
// we have to define a public copy constructor
|
||||
MyTag (const MyTag &other);
|
||||
// we have to define a public destructor
|
||||
~MyTag ();
|
||||
// we have to define a public static GetUid method
|
||||
static uint32_t GetUid (void);
|
||||
// we have to define a public Print method
|
||||
void Print (std::ostream &os) const;
|
||||
// we have to define a public GetSerializedSize method
|
||||
uint32_t GetSerializedSize (void) const;
|
||||
// we have to define a public Serialize method
|
||||
void Serialize (Buffer::Iterator i) const;
|
||||
// we have to define a public Deserialize method
|
||||
uint32_t Deserialize (Buffer::Iterator i);
|
||||
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);
|
||||
@@ -51,52 +42,45 @@ private:
|
||||
uint8_t m_simpleValue;
|
||||
};
|
||||
|
||||
MyTag::MyTag ()
|
||||
{}
|
||||
MyTag::MyTag (const MyTag &other)
|
||||
: m_simpleValue (other.m_simpleValue)
|
||||
{}
|
||||
MyTag::~MyTag ()
|
||||
{}
|
||||
uint32_t
|
||||
MyTag::GetUid (void)
|
||||
TypeId
|
||||
MyTag::GetTypeId (void)
|
||||
{
|
||||
// we input a unique string to AllocateUid
|
||||
// to avoid name collisions.
|
||||
static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
|
||||
return uid;
|
||||
static TypeId tid = TypeId ("ns3::MyTag")
|
||||
.SetParent<Tag> ()
|
||||
.AddConstructor<MyTag> ()
|
||||
.AddAttribute ("SimpleValue",
|
||||
"A simple value",
|
||||
EmptyAttributeValue (),
|
||||
MakeUintegerAccessor (&MyTag::GetSimpleValue),
|
||||
MakeUintegerChecker<uint8_t> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
void
|
||||
MyTag::Print (std::ostream &os) const
|
||||
TypeId
|
||||
MyTag::GetInstanceTypeId (void) const
|
||||
{
|
||||
// print the content of this tag for Packet::PrintTags
|
||||
os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
|
||||
return GetTypeId ();
|
||||
}
|
||||
uint32_t
|
||||
MyTag::GetSerializedSize (void) const
|
||||
{
|
||||
// we do not want to deal with parallel simulations
|
||||
// so we return 0.
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
void
|
||||
MyTag::Serialize (Buffer::Iterator i) const
|
||||
MyTag::Serialize (TagBuffer i) const
|
||||
{
|
||||
// we will never be invoked because we are not doing
|
||||
// parallel simulations so, we assert.
|
||||
NS_ASSERT (false);
|
||||
i.WriteU8 (m_simpleValue);
|
||||
}
|
||||
uint32_t
|
||||
MyTag::Deserialize (Buffer::Iterator i)
|
||||
void
|
||||
MyTag::Deserialize (TagBuffer i)
|
||||
{
|
||||
// we will never be invoked because we are not doing
|
||||
// parallel simulations so, we assert.
|
||||
NS_ASSERT (false);
|
||||
// theoretically, return the number of bytes read
|
||||
return 0;
|
||||
m_simpleValue = i.ReadU8 ();
|
||||
}
|
||||
void
|
||||
MyTag::Print (std::ostream &os) const
|
||||
{
|
||||
os << "v=" << (uint32_t)m_simpleValue;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MyTag::SetSimpleValue (uint8_t value)
|
||||
{
|
||||
@@ -116,7 +100,7 @@ int main (int argc, char *argv[])
|
||||
tag.SetSimpleValue (0x56);
|
||||
|
||||
// store the tag in a packet.
|
||||
Ptr<Packet> p = Create<Packet> ();
|
||||
Ptr<Packet> p = Create<Packet> (100);
|
||||
p->AddTag (tag);
|
||||
|
||||
// create a copy of the packet
|
||||
@@ -124,7 +108,7 @@ int main (int argc, char *argv[])
|
||||
|
||||
// read the tag from the packet copy
|
||||
MyTag tagCopy;
|
||||
p->PeekTag (tagCopy);
|
||||
p->FindFirstMatchingTag (tagCopy);
|
||||
|
||||
// the copy and the original are the same !
|
||||
NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
|
||||
|
||||
@@ -18,17 +18,21 @@
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "ns3/propagation-loss-model.h"
|
||||
#include "ns3/default-value.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 = Create<StaticMobilityModel> ();
|
||||
Ptr<StaticMobilityModel> b = Create<StaticMobilityModel> ();
|
||||
Ptr<PropagationLossModel> model = PropagationLossModel::CreateDefault ();
|
||||
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)
|
||||
@@ -37,7 +41,7 @@ PrintOne (double minTxpower, double maxTxpower, double stepTxpower, double min,
|
||||
std::cout << x << " ";
|
||||
for (double txpower = minTxpower; txpower < maxTxpower; txpower += stepTxpower)
|
||||
{
|
||||
double rxPowerDbm = model->GetRxPower (txpower, a, b);
|
||||
double rxPowerDbm = txpower + model->GetLoss (a, b);
|
||||
std::cout << rxPowerDbm << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
@@ -47,19 +51,8 @@ PrintOne (double minTxpower, double maxTxpower, double stepTxpower, double min,
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
#if 0
|
||||
DefaultValue::Bind ("PropagationLossModelType", "Friis");
|
||||
DefaultValue::Bind ("FriisPropagationLossLambda", "0.6");
|
||||
DefaultValue::Bind ("FriisPropagationLossSystemLoss", "1.0");
|
||||
|
||||
PrintOne (-10, 20, 5, 0, 1000, 5);
|
||||
#endif
|
||||
|
||||
DefaultValue::Bind ("PropagationLossModelType", "LogDistance");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossReferenceDistance", "1.0");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossReferenceType", "Random");
|
||||
DefaultValue::Bind ("RandomPropagationLossDistribution", "Constant:10");
|
||||
DefaultValue::Bind ("LogDistancePropagationLossExponent", "4");
|
||||
Config::SetGlobal ("LogDistancePropagationLossModel::ReferenceDistance", StringValue ("1.0"));
|
||||
Config::SetGlobal ("LogDistancePropagationLossModel::Exponent", StringValue ("4"));
|
||||
|
||||
PrintOne (-10, 20, 5, 0, 10000, 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,282 +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/log.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)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// pre-dispatch asserts
|
||||
NS_LOG_LOGIC ("pre-condition");
|
||||
domethodA ();
|
||||
NS_LOG_LOGIC ("post-condition");
|
||||
// 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_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
|
||||
AnImplementation::AnImplementation (void)
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
// enable our interface
|
||||
SetInterfaceId (AnImplementation::iid);
|
||||
}
|
||||
|
||||
void
|
||||
AnImplementation::domethodA ()
|
||||
{
|
||||
NS_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
//
|
||||
// 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_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
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_LOG_FUNCTION;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,21 +1,14 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/mobility-model.h"
|
||||
#include "ns3/mobility-model-notifier.h"
|
||||
#include "ns3/static-mobility-model.h"
|
||||
#include "ns3/random-topology.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#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 (const TraceContext &context, Ptr<const MobilityModel> position)
|
||||
CourseChange (std::string context, Ptr<const MobilityModel> position)
|
||||
{
|
||||
Vector pos = position->GetPosition ();
|
||||
std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
|
||||
@@ -24,28 +17,25 @@ CourseChange (const TraceContext &context, Ptr<const MobilityModel> position)
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
DefaultValue::Bind ("RandomDiscPositionX", "100");
|
||||
DefaultValue::Bind ("RandomDiscPositionY", "50");
|
||||
DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
|
||||
DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
|
||||
|
||||
CommandLine::Parse (argc, argv);
|
||||
NodeContainer c;
|
||||
c.Create (10000);
|
||||
|
||||
RandomTopology topology;
|
||||
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);
|
||||
|
||||
std::vector<Ptr<Object> > objects;
|
||||
for (uint32_t i = 0; i < 10000; i++)
|
||||
{
|
||||
Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
|
||||
notifier->TraceConnect ("/course-change", MakeCallback (&CourseChange));
|
||||
objects.push_back (notifier);
|
||||
}
|
||||
|
||||
topology.Layout (objects.begin (), objects.end ());
|
||||
|
||||
Simulator::StopAt (Seconds (100.0));
|
||||
Config::Connect ("/NodeList/*/$ns3::MobilityModelNotifier/CourseChange",
|
||||
MakeCallback (&CourseChange));
|
||||
|
||||
Simulator::Stop (Seconds (100.0));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/mobility-model.h"
|
||||
#include "ns3/mobility-model-notifier.h"
|
||||
#include "ns3/random-topology.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/node-list.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/mobility-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
static void
|
||||
CourseChange (ns3::TraceContext const&, Ptr<const MobilityModel> mobility)
|
||||
CourseChange (std::string foo, Ptr<const MobilityModel> mobility)
|
||||
{
|
||||
Vector pos = mobility->GetPosition ();
|
||||
Vector vel = mobility->GetVelocity ();
|
||||
@@ -27,33 +19,32 @@ CourseChange (ns3::TraceContext const&, Ptr<const MobilityModel> mobility)
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
DefaultValue::Bind ("RandomWalk2dMode", "Time");
|
||||
DefaultValue::Bind ("RandomWalk2dTime", "2s");
|
||||
DefaultValue::Bind ("RandomWalk2dSpeed", "Constant:1.0");
|
||||
DefaultValue::Bind ("RandomWalk2dBounds", "0:200:0:100");
|
||||
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Mode", StringValue ("Time"));
|
||||
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Time", StringValue ("2s"));
|
||||
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Speed", StringValue ("Constant:1.0"));
|
||||
Config::SetDefault ("ns3::RandomWalk2dMobilityModel::Bounds", StringValue ("0|200|0|200"));
|
||||
|
||||
DefaultValue::Bind ("RandomDiscPositionX", "100");
|
||||
DefaultValue::Bind ("RandomDiscPositionY", "50");
|
||||
DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
|
||||
DefaultValue::Bind ("RandomTopologyMobilityType", "RandomWalk2dMobilityModel");
|
||||
NodeContainer c;
|
||||
c.Create (100);
|
||||
|
||||
CommandLine::Parse (argc, argv);
|
||||
MobilityHelper mobility;
|
||||
mobility.SetPositionAllocator ("ns3::RandomDiscPositionAllocator",
|
||||
"X", StringValue ("100.0"),
|
||||
"Y", StringValue ("100.0"),
|
||||
"Rho", StringValue ("Uniform:0:30"));
|
||||
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
|
||||
"Mode", StringValue ("Time"),
|
||||
"Time", StringValue ("2s"),
|
||||
"Speed", StringValue ("Constant:1.0"),
|
||||
"Bounds", StringValue ("0|200|0|200"));
|
||||
mobility.InstallAll ();
|
||||
Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
|
||||
MakeCallback (&CourseChange));
|
||||
|
||||
RandomTopology topology;
|
||||
|
||||
for (uint32_t i = 0; i < 100; i++)
|
||||
{
|
||||
Ptr<Node> node = Create<Node> ();
|
||||
node->AddInterface (Create<MobilityModelNotifier> ());
|
||||
}
|
||||
|
||||
topology.Layout (NodeList::Begin (), NodeList::End ());
|
||||
NodeList::Connect ("/nodes/*/$MobilityModelNotifier/course-change",
|
||||
MakeCallback (&CourseChange));
|
||||
|
||||
Simulator::StopAt (Seconds (100.0));
|
||||
Simulator::Stop (Seconds (100.0));
|
||||
|
||||
Simulator::Run ();
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "ns3/internet-node.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/simulator-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
@@ -26,9 +23,13 @@ GenerateTraffic (Ptr<Socket> socket, uint32_t size)
|
||||
}
|
||||
|
||||
static void
|
||||
SocketPrinter (Ptr<Socket> socket, Ptr<Packet> packet, const Address &from)
|
||||
SocketPrinter (Ptr<Socket> socket)
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl;
|
||||
Ptr<Packet> packet;
|
||||
while (packet = socket->Recv ())
|
||||
{
|
||||
std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet->GetSize () << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -40,16 +41,19 @@ PrintTraffic (Ptr<Socket> socket)
|
||||
void
|
||||
RunSimulation (void)
|
||||
{
|
||||
Ptr<Node> a = Create<InternetNode> ();
|
||||
NodeContainer c;
|
||||
c.Create (1);
|
||||
|
||||
InterfaceId iid = InterfaceId::LookupByName ("Udp");
|
||||
Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
|
||||
InternetStackHelper internet;
|
||||
internet.Install (c);
|
||||
|
||||
Ptr<Socket> sink = socketFactory->CreateSocket ();
|
||||
|
||||
TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
|
||||
Ptr<Socket> sink = Socket::CreateSocket (c.Get (0), tid);
|
||||
InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
|
||||
sink->Bind (local);
|
||||
|
||||
Ptr<Socket> source = socketFactory->CreateSocket ();
|
||||
Ptr<Socket> source = Socket::CreateSocket (c.Get (0), tid);
|
||||
InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80);
|
||||
source->Connect (remote);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* -*- 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
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
obj = bld.create_ns3_program('main-attribute-value')
|
||||
obj.source = 'main-attribute-value.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-callback')
|
||||
obj.source = 'main-callback.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-ptr')
|
||||
obj.source = 'main-ptr.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-simulator')
|
||||
obj.source = 'main-simulator.cc'
|
||||
|
||||
@@ -16,35 +16,20 @@ def build(bld):
|
||||
obj = bld.create_ns3_program('main-packet-tag', ['common', 'simulator'])
|
||||
obj.source = 'main-packet-tag.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-packet-printer', ['common', 'simulator', 'internet-node'])
|
||||
obj.source = 'main-packet-printer.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-test')
|
||||
obj.source = 'main-test.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-simple',
|
||||
['node', 'internet-node', 'onoff'])
|
||||
['node', 'internet-stack', 'onoff'])
|
||||
obj.source = 'main-simple.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-default-value',
|
||||
['core', 'simulator', 'node', 'point-to-point'])
|
||||
obj.source = 'main-default-value.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-grid-topology',
|
||||
['core', 'simulator', 'mobility', 'internet-node'])
|
||||
['core', 'simulator', 'mobility', 'internet-stack'])
|
||||
obj.source = 'main-grid-topology.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-random-topology',
|
||||
['core', 'simulator', 'mobility'])
|
||||
obj.source = 'main-random-topology.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-adhoc-wifi',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'main-adhoc-wifi.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-ap-wifi',
|
||||
['core', 'simulator', 'mobility', 'wifi'])
|
||||
obj.source = 'main-ap-wifi.cc'
|
||||
|
||||
obj = bld.create_ns3_program('main-random-walk',
|
||||
['core', 'simulator', 'mobility'])
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
void RunSimulation (void);
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
RunSimulation ();
|
||||
|
||||
return 0;
|
||||
}
|
||||