internet: GSoC-22 generate ARP/NDISC cache automatically

This commit is contained in:
Zhiheng Dong
2022-09-01 15:03:30 -07:00
committed by Tommaso Pecorella
parent 5334c1e460
commit 87fb2ddcbf
15 changed files with 1537 additions and 45 deletions

View File

@@ -12,6 +12,7 @@ set(source_files
helper/ipv6-list-routing-helper.cc
helper/ipv6-routing-helper.cc
helper/ipv6-static-routing-helper.cc
helper/neighbor-cache-helper.cc
helper/rip-helper.cc
helper/ripng-helper.cc
model/arp-cache.cc
@@ -143,6 +144,7 @@ set(header_files
helper/ipv6-list-routing-helper.h
helper/ipv6-routing-helper.h
helper/ipv6-static-routing-helper.h
helper/neighbor-cache-helper.h
helper/rip-helper.h
helper/ripng-helper.h
model/arp-cache.h
@@ -279,6 +281,7 @@ set(test_sources
test/ipv6-raw-test.cc
test/ipv6-ripng-test.cc
test/ipv6-test.cc
test/neighbor-cache-test.cc
test/rtt-test.cc
test/tcp-advertised-window-test.cc
test/tcp-bbr-test.cc

View File

@@ -224,6 +224,7 @@ codepoint.
RFC 6621 duplicate packet detection
***********************************
To support mesh network protocols over broadcast-capable networks (e.g. Wi-Fi),
it is useful to have support for duplicate packet detection and filtering,
since nodes in a network may receive multiple copies of flooded multicast
@@ -233,3 +234,48 @@ Section 6.2.2 of (:rfc:`6621`). The model, disabled by default, must be
enabled by setting ``EnableRFC6621`` to true. A second attribute,
``DuplicateExpire``, sets the expiration delay for erasing the cache entry
of a packet in the duplicate cache; the delay value defaults to 1ms.
NeighborCache
*************
NeighborCacheHelper provides a way to generate ARP cache automatically. It
generates needed ARP cache before simulation start to avoid the delay and mesage overhead of
address resolution in simulations that are focused on other performance aspects.
The state of entries which are generated by NeighborCacheHelper is ``STATIC_AUTOGENERATED``,
which is similar to ``PERMANENT``, but they are not manually added or removed by user, they
will be managed by NeighborCacheHelper when user need pre-generate cache.
The source code for NeighborCache is located in ``src/internet/helper/neighbor-cache-helper``
A complete example is in ``src/internet/examples/neighbor-cache-example.cc``.
Usage
=====
The typical usages are::
* Populate neighbor ARP caches for all devices:
.. code-block:: c++
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache ();
* Populate neighbor ARP caches for a given channel:
.. code-block:: c++
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache (channel); // channel is the Ptr<Channel> want to generate ARP caches
* Populate neighbor ARP caches for devices in a given NetDeviceContainer:
.. code-block:: c++
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache (netDevices); // netDevices is the NetDeviceContainer want to generate ARP caches
* Populate neighbor ARP caches for a given Ipv4InterfaceContainer:
.. code-block:: c++
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache (interfaces); // interfaces is the Ipv4InterfaceContainer want to generate ARP caches

View File

@@ -492,3 +492,27 @@ The IPv6 protocols has not yet been extensively validated against real implement
The actual tests involve mainly performing checks of the .pcap trace files with Wireshark,
and the results are positive.
NeighborCache
*************
NeighborCacheHelper provides a way to generate NDISC cache automatically. It generates
needed NDISC cache before simulation start to avoid the delay and mesage overhead of
neighbor discovery in simulations that are focused on other performance aspects.
The state of entries generate by NeighborCacheHelper is ``STATIC_AUTOGENERATED``,
which is similar to ``PERMANENT``, but they are not manually added or removed by user, they
will be managed by NeighborCacheHelper when user need pre-generate cache.
The source code for NeighborCache is located in ``src/internet/helper/neighbor-cache-helper``
A complete example is in ``src/internet/examples/neighbor-cache-example.cc``.
Usage
=====
The usages for generating NDISC cache is almost the same as generating ARP cache, see
``src/internet/doc/ipv4.rst``
* Populate neighbor ARP caches for a given Ipv6InterfaceContainer:
.. code-block:: c++
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache (interfaces); // interfaces is the Ipv6InterfaceContainer want to generate ARP caches

View File

@@ -6,3 +6,13 @@ build_lib_example(
${libinternet}
${libapplications}
)
build_lib_example(
NAME neighbor-cache-example
SOURCE_FILES neighbor-cache-example.cc
LIBRARIES_TO_LINK
${libapplications}
${libcsma}
${libinternet}
${libnetwork}
)

View File

@@ -0,0 +1,535 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 ZHIHENG DONG
*
* 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: Zhiheng Dong <dzh2077@gmail.com>
*/
/**
* This example shows how to generate neighbor caches on the scope of
* a channel, a NetDeviceContainer, an InterfaceContainer and globally.
* The example also shows a scenario that auto-generated neighbor caches
* can avoid droping packets because of ARP message or Neighbor Discover
* message.
* If the user runs the example without any command line option, NeighborCacheHelper
* will generate neighbor cache for all devices and the output is their
* ARP table or NDISC table, the user can also generate neighbor cache on different
* scope by adding command line option --useChannel (on specific channel),
* --useNetDeviceContainer (on specific netDeviceContainer) and --useInterfaceContainer
* (on specific netDeviceContainer), --noGenerate (don't generate neighbor cache).
* The user can also enable --sendTraffic flag to send a data stream from n0 to n1,
* the output will be the information of received packets, which shows the packets loss
* are reduced after pre-generate neighbor caches.
*
* IPv4 Network Topology
* \verbatim
LAN 10.1.1.0/24
n0 --------------- n1 n2 n3
| | |
===============
LAN 10.1.2.0/24
\endverbatim
*
*IPv6 Network Topology
* \verbatim
LAN 2001:1::/64
n0 --------------- n1 n2 n3
| | |
===============
LAN 2001:2::/64
\endverbatim
*
* Expected Outputs:
* IPv4 (default):
* Generate ARP caches for all deveices (default) :
* \verbatim
ARP Cache of node 0 at time 0
10.1.1.2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
ARP Cache of node 1 at time 0
10.1.1.1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
10.1.2.2 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
10.1.2.3 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
ARP Cache of node 2 at time 0
10.1.2.1 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
10.1.2.3 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
ARP Cache of node 3 at time 0
10.1.2.1 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
10.1.2.2 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Generate ARP caches for the left channel (--useChannel):
* \verbatim
ARP Cache of node 0 at time 0
10.1.1.2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
ARP Cache of node 1 at time 0
10.1.1.1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
ARP Cache of node 2 at time 0
ARP Cache of node 3 at time 0
\endverbatim
*
* Generate ARP caches for devices on the right side (--useNetDeviceContainer):
* \verbatim
ARP Cache of node 0 at time 0
ARP Cache of node 1 at time 0
10.1.2.2 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
10.1.2.3 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
ARP Cache of node 2 at time 0
10.1.2.1 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
10.1.2.3 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
ARP Cache of node 3 at time 0
10.1.2.1 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
10.1.2.2 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Generate ARP caches for specific interfaces (--useInterfaceContainer):
* \verbatim
ARP Cache of node 0 at time 0
10.1.1.2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
ARP Cache of node 1 at time 0
ARP Cache of node 2 at time 0
ARP Cache of node 3 at time 0
10.1.2.1 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
10.1.2.2 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Do not generate neighbor cache (--noGenerate):
* \verbatim
ARP Cache of node 0 at time 0
ARP Cache of node 1 at time 0
ARP Cache of node 2 at time 0
ARP Cache of node 3 at time 0
\endverbatim
*
* sending packet with pre-generated neighbor caches(--sendTraffic)
* \verbatim
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=0 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=1 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=2 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=3 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=4 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=5 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=6 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=7 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=8 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=9 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=10 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=11 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=12 time=+1.00001s)
\endverbatim
*
* sending packet without pre-generated neighbor caches(--sendTraffic --noGenerate)
* \verbatim
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=0 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=1 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=2 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=8 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=9 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=10 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=11 time=+1s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=12 time=+1.00001s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=13 time=+1.00001s)
Rx pkt from 03-07-0a:01:01:01:01:c0:00 to 03-07-0a:01:01:02:09:00:00 -> (size=512) AND (seq=14 time=+1.00001s)
\endverbatim
*
* IPv6 (--useIPv6):
* Generate NDISC caches for all deveices (default) :
* \verbatim
NDISC Cache of node 0 at time +0s
2001:1::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
fe80::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
NDISC Cache of node 1 at time +0s
2001:1::200:ff:fe00:1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
fe80::200:ff:fe00:1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:4 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:5 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
fe80::200:ff:fe00:4 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
fe80::200:ff:fe00:5 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
NDISC Cache of node 2 at time +0s
2001:2::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:5 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
fe80::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
fe80::200:ff:fe00:5 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
NDISC Cache of node 3 at time +0s
2001:2::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
fe80::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
fe80::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Generate NDISC caches for the left channel (--useChannel):
* \verbatim
NDISC Cache of node 0 at time +0s
2001:1::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
fe80::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
NDISC Cache of node 1 at time +0s
2001:1::200:ff:fe00:1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
fe80::200:ff:fe00:1 dev 0 lladdr 02-06-00:00:00:00:00:01 STATIC_AUTOGENERATED
NDISC Cache of node 2 at time +0s
NDISC Cache of node 3 at time +0s
\endverbatim
*
* Generate NDISC caches for devices on the right side (--useNetDeviceContainer):
* \verbatim
NDISC Cache of node 0 at time +0s
NDISC Cache of node 1 at time +0s
2001:2::200:ff:fe00:4 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:5 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
fe80::200:ff:fe00:4 dev 1 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
fe80::200:ff:fe00:5 dev 1 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
NDISC Cache of node 2 at time +0s
2001:2::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:5 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
fe80::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
fe80::200:ff:fe00:5 dev 0 lladdr 02-06-00:00:00:00:00:05 STATIC_AUTOGENERATED
NDISC Cache of node 3 at time +0s
2001:2::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
fe80::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
fe80::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Generate NDISC caches for specific interfaces (--useInterfaceContainer):
* \verbatim
NDISC Cache of node 0 at time +0s
2001:1::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
fe80::200:ff:fe00:2 dev 0 lladdr 02-06-00:00:00:00:00:02 STATIC_AUTOGENERATED
NDISC Cache of node 1 at time +0s
NDISC Cache of node 2 at time +0s
NDISC Cache of node 3 at time +0s
2001:2::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
2001:2::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
fe80::200:ff:fe00:3 dev 0 lladdr 02-06-00:00:00:00:00:03 STATIC_AUTOGENERATED
fe80::200:ff:fe00:4 dev 0 lladdr 02-06-00:00:00:00:00:04 STATIC_AUTOGENERATED
\endverbatim
*
* Do not generate neighbor cache (--noGenerate):
* \verbatim
NDISC Cache of node 0 at time +0s
NDISC Cache of node 1 at time +0s
NDISC Cache of node 2 at time +0s
NDISC Cache of node 3 at time +0s
\endverbatim
*
* sending packet with pre-generated neighbor caches(--sendTraffic)
* \verbatim
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=0 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=1 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=2 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=3 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=4 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=5 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=6 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=7 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=8 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=9 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=10 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=11 time=+1s)
\endverbatim
*
* sending packet without pre-generated neighbor caches(--sendTraffic --noGenerate)
* \verbatim
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=8 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=9 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=10 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=11 time=+1s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=12 time=+1.00001s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=13 time=+1.00001s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=14 time=+1.00001s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=15 time=+1.00001s)
Rx pkt from 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:01:01:c0 to 04-12-20:01:00:01:00:00:00:00:02:00:00:ff:fe:00:00:02:09:00 -> (size=512) AND (seq=16 time=+1.00001s)
\endverbatim
*/
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("NeighborCacheExample");
/**
* Neigbor Cache example class.
*
* It handles the creation and run of an example.
*/
class NeighborCacheExample
{
public:
NeighborCacheExample ();
/**
* Run the example.
*/
void Run ();
/**
* \brief description the command-line parameters.
* \param argc The argument count.
* \param argv The argument vector.
*/
void CommandSetup (int argc, char **argv);
private:
/**
* \brief Print the information of receive data.
* \param pkt The received packet.
* \param from The sender.
* \param dst The receiver.
* \param header The header with a sequence, a timestamp, and a "size" attribute
*/
void ReceivePacket (Ptr<const Packet> pkt, const Address &from, const Address &dst, const SeqTsSizeHeader& header);
bool m_useIpv6 {false}; //!< Use IPv6 instead of IPv4
bool m_enableLog {false}; //!< Enable ArpL3Protocol and Icmpv6L4Protocol logging
bool m_useChannel {false}; //!< Generate neighbor cache for specific Channel
bool m_useNetDeviceContainer {false}; //!< Generate neighbor cache for specific netDeviceContainer
bool m_useInterfaceContainer {false}; //!< Generate neighbor cache for specific interfaceContainer
bool m_noGenerate {false}; //!< do not generate neighbor cache automatically
bool m_sendTraffic {false}; //!< send data stream from n0 to n1
};
NeighborCacheExample::NeighborCacheExample ()
{
NS_LOG_FUNCTION (this);
}
void
NeighborCacheExample::ReceivePacket (Ptr<const Packet> pkt, const Address &from, const Address &dst, const SeqTsSizeHeader& header)
{
std::cout << "Rx pkt from " << from << " to " << dst << " -> " << header << std::endl;
}
void
NeighborCacheExample::CommandSetup (int argc, char **argv)
{
CommandLine cmd (__FILE__);
cmd.AddValue ("useIPv6", "Use IPv6 instead of IPv4", m_useIpv6);
cmd.AddValue ("enableLog", "Enable ArpL3Protocol and Icmpv6L4Protocol logging", m_enableLog);
cmd.AddValue ("useChannel", "Generate neighbor cache for specific Channel", m_useChannel);
cmd.AddValue ("useNetDeviceContainer", "Generate neighbor cache for specific netDeviceContainer", m_useNetDeviceContainer);
cmd.AddValue ("useInterfaceContainer", "Generate neighbor cache for specific interfaceContainer", m_useInterfaceContainer);
cmd.AddValue ("noGenerate", "do not generate neighbor cache automatically", m_noGenerate);
cmd.AddValue ("sendTraffic", "send data stream from n0 to n1", m_sendTraffic);
cmd.Parse (argc, argv);
}
int
main (int argc, char *argv[])
{
NeighborCacheExample example;
example.CommandSetup (argc,argv);
example.Run ();
return 0;
}
void
NeighborCacheExample::Run ()
{
if (m_enableLog)
{
LogComponentEnable ("ArpL3Protocol", LOG_LEVEL_LOGIC);
LogComponentEnable ("Icmpv6L4Protocol", LOG_LEVEL_LOGIC);
}
uint32_t nCsmaLeft = 2;
uint32_t nCsmaRight = 2;
NodeContainer csmaNodesLeft;
csmaNodesLeft.Create (nCsmaLeft);
NodeContainer csmaNodesRight;
csmaNodesRight.Add (csmaNodesLeft.Get (1));
csmaNodesRight.Create (nCsmaRight);
CsmaHelper csmaLeft;
csmaLeft.SetChannelAttribute ("DataRate", StringValue ("20Gbps"));
// The 1 microSeconds delay is only for showing packets dropped effect without generating neighbor caches.
csmaLeft.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (1)));
CsmaHelper csmaRight;
csmaRight.SetChannelAttribute ("DataRate", StringValue ("20Gbps"));
csmaRight.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (1)));
NetDeviceContainer csmaDevicesLeft;
csmaDevicesLeft = csmaLeft.Install (csmaNodesLeft);
NetDeviceContainer csmaDevicesRight;
csmaDevicesRight = csmaRight.Install (csmaNodesRight);
InternetStackHelper stack;
// disabled Ipv4ArpJitter and Ipv6NsRsJitter to avoid the influence on packet dropped
stack.SetIpv4ArpJitter (false);
stack.SetIpv6NsRsJitter (false);
stack.Install (csmaNodesLeft.Get (0));
stack.Install (csmaNodesRight);
if (!m_useIpv6)
{
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfacesLeft;
csmaInterfacesLeft = address.Assign (csmaDevicesLeft);
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfacesRight;
csmaInterfacesRight = address.Assign (csmaDevicesRight);
// Populate ARP caches
NeighborCacheHelper neighborCache;
if (m_useChannel)
{
// Populate ARP caches for given channel
Ptr<Channel> csmaChannel = csmaDevicesLeft.Get (0)->GetChannel ();
neighborCache.PopulateNeighborCache (csmaChannel);
}
else if (m_useNetDeviceContainer)
{
// Populate ARP caches for given netDeviceContainer
neighborCache.PopulateNeighborCache (csmaDevicesRight);
}
else if (m_useInterfaceContainer)
{
std::pair<Ptr<Ipv4>, uint32_t> txInterface = csmaInterfacesLeft.Get (0);
Ptr<Ipv4> ipv41 = txInterface.first;
uint32_t index1 = txInterface.second;
std::pair<Ptr<Ipv4>, uint32_t> rxInterface = csmaInterfacesRight.Get (nCsmaRight);
Ptr<Ipv4> ipv42 = rxInterface.first;
uint32_t index2 = rxInterface.second;
// Populate ARP caches for given interfaceContainer
Ipv4InterfaceContainer interfaces;
interfaces.Add (ipv41,index1);
interfaces.Add (ipv42,index2);
neighborCache.PopulateNeighborCache (interfaces);
}
else if (!m_noGenerate)
{
// Populate ARP caches for all devices
neighborCache.PopulateNeighborCache ();
}
if (m_sendTraffic)
{
// send Packet from n0 to n1
uint16_t port = 9; // Discard port (RFC 863)
OnOffHelper onoff ("ns3::UdpSocketFactory",
Address (InetSocketAddress (csmaInterfacesLeft.GetAddress (1), port)));
onoff.SetConstantRate (DataRate ("10Gbps"));
onoff.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
ApplicationContainer apps = onoff.Install (csmaNodesLeft.Get (0));
apps.Start (Seconds (1.0));
// Create a packet sink to receive these packets
PacketSinkHelper sink ("ns3::UdpSocketFactory",
Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
sink.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
apps = sink.Install (csmaNodesLeft);
apps.Get (1)->TraceConnectWithoutContext ("RxWithSeqTsSize", MakeCallback (&NeighborCacheExample::ReceivePacket,this));
AsciiTraceHelper ascii;
Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream ("neighbor-cache-example.tr");
csmaLeft.EnableAsciiAll (stream);
csmaLeft.EnablePcapAll ("neighbor-cache-example");
}
else
{
Ptr<OutputStreamWrapper> outputStream = Create<OutputStreamWrapper> (&std::cout);
Ipv4RoutingHelper::PrintNeighborCacheAllAt (Seconds (0), outputStream);
}
}
else
{
Ipv6AddressHelper address;
address.SetBase (Ipv6Address ("2001:1::"), Ipv6Prefix (64));
Ipv6InterfaceContainer csmaInterfacesLeft;
csmaInterfacesLeft = address.Assign (csmaDevicesLeft);
csmaInterfacesLeft.SetForwarding (1, true);
csmaInterfacesLeft.SetDefaultRouteInAllNodes (1);
address.SetBase (Ipv6Address ("2001:2::"), Ipv6Prefix (64));
Ipv6InterfaceContainer csmaInterfacesRight;
csmaInterfacesRight = address.Assign (csmaDevicesRight);
csmaInterfacesRight.SetForwarding (0, true);
csmaInterfacesRight.SetDefaultRouteInAllNodes (0);
// Populate neighbor NDISC caches
NeighborCacheHelper neighborCache;
if (m_useChannel)
{
// Populate NDISC caches for given channel
Ptr<Channel> csmaChannel = csmaDevicesLeft.Get (0)->GetChannel ();
neighborCache.PopulateNeighborCache (csmaChannel);
}
else if (m_useNetDeviceContainer)
{
// Populate NDISC caches for given netDeviceContainer
neighborCache.PopulateNeighborCache (csmaDevicesRight);
}
else if (m_useInterfaceContainer)
{
std::pair<Ptr<Ipv6>, uint32_t> txInterface = csmaInterfacesLeft.Get (0);
Ptr<Ipv6> ipv61 = txInterface.first;
uint32_t index1 = txInterface.second;
std::pair<Ptr<Ipv6>, uint32_t> rxInterface = csmaInterfacesRight.Get (nCsmaRight);
Ptr<Ipv6> ipv62 = rxInterface.first;
uint32_t index2 = rxInterface.second;
// Populate NDISC caches for given interfaceContainer
Ipv6InterfaceContainer interfaces;
interfaces.Add (ipv61,index1);
interfaces.Add (ipv62,index2);
neighborCache.PopulateNeighborCache (interfaces);
}
else if (!m_noGenerate)
{
// Populate NDISC caches for all devices
neighborCache.PopulateNeighborCache ();
}
if (m_sendTraffic)
{
// send Packet from n0 to n1
uint16_t port = 9; // Discard port (RFC 863)
OnOffHelper onoff ("ns3::UdpSocketFactory",
Address (Inet6SocketAddress (csmaInterfacesLeft.GetAddress (1, 1), port)));
onoff.SetConstantRate (DataRate ("10Gbps"));
onoff.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
ApplicationContainer apps = onoff.Install (csmaNodesLeft.Get (0));
apps.Start (Seconds (1.0));
// Create a packet sink to receive these packets
PacketSinkHelper sink ("ns3::UdpSocketFactory",
Address (Inet6SocketAddress (Ipv6Address::GetAny (), port)));
sink.SetAttribute ("EnableSeqTsSizeHeader", BooleanValue (true));
apps = sink.Install (csmaNodesLeft);
apps.Get (1)->TraceConnectWithoutContext ("RxWithSeqTsSize", MakeCallback (&NeighborCacheExample::ReceivePacket, this));
AsciiTraceHelper ascii;
Ptr<OutputStreamWrapper> stream = ascii.CreateFileStream ("neighbor-cache-example.tr");
csmaLeft.EnableAsciiAll (stream);
csmaLeft.EnablePcapAll ("neighbor-cache-example");
}
else
{
Ptr<OutputStreamWrapper> outputStream = Create<OutputStreamWrapper> (&std::cout);
Ipv6RoutingHelper::PrintNeighborCacheAllAt (Seconds (0), outputStream);
}
}
Simulator::Stop (Seconds (1.00002));
Simulator::Run ();
Simulator::Destroy ();
}

View File

@@ -0,0 +1,339 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 ZHIHENG DONG
*
* 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: Zhiheng Dong <dzh2077@gmail.com>
*/
#include "ns3/assert.h"
#include "ns3/log.h"
#include "ns3/ptr.h"
#include "ns3/node.h"
#include "ns3/net-device.h"
#include "ns3/ipv4.h"
#include "ns3/ipv6.h"
#include "ns3/simulator.h"
#include "ns3/channel-list.h"
#include "ns3/neighbor-cache-helper.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("NeighborCacheHelper");
NeighborCacheHelper::NeighborCacheHelper ()
{
NS_LOG_FUNCTION (this);
}
NeighborCacheHelper::~NeighborCacheHelper ()
{
NS_LOG_FUNCTION (this);
}
void
NeighborCacheHelper::PopulateNeighborCache (void) const
{
NS_LOG_FUNCTION (this);
for (uint32_t i = 0; i < ChannelList::GetNChannels (); ++i)
{
Ptr<Channel> channel = ChannelList::GetChannel (i);
PopulateNeighborCache (channel);
}
}
void
NeighborCacheHelper::PopulateNeighborCache (Ptr<Channel> channel) const
{
NS_LOG_FUNCTION (this << channel);
for (std::size_t i = 0; i < channel->GetNDevices (); ++i)
{
Ptr<NetDevice> netDevice = channel->GetDevice (i);
Ptr<Node> node = netDevice->GetNode ();
int32_t ipv4InterfaceIndex = node->GetObject<Ipv4> ()->GetInterfaceForDevice (netDevice);
int32_t ipv6InterfaceIndex = node->GetObject<Ipv6> ()->GetInterfaceForDevice (netDevice);
for (std::size_t j = 0; j < channel->GetNDevices (); ++j)
{
Ptr<NetDevice> neighborDevice = channel->GetDevice (j);
Ptr<Node> neighborNode = neighborDevice->GetNode ();
int32_t ipv4NeighborInterfaceIndex = neighborNode->GetObject<Ipv4> ()->GetInterfaceForDevice (neighborDevice);
int32_t ipv6NeighborInterfaceIndex = neighborNode->GetObject<Ipv6> ()->GetInterfaceForDevice (neighborDevice);
if (neighborDevice != netDevice)
{
if (ipv4InterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4Interface = node->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4InterfaceIndex);
if (ipv4NeighborInterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4NeighborInterface = neighborNode->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4NeighborInterfaceIndex);
PopulateNeighborEntriesIpv4 (ipv4Interface, ipv4NeighborInterface);
}
}
if (ipv6InterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6Interface = node->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6InterfaceIndex);
if (ipv6NeighborInterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6NeighborInterface = neighborNode->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6NeighborInterfaceIndex);
PopulateNeighborEntriesIpv6 (ipv6Interface, ipv6NeighborInterface);
}
}
}
}
}
}
void
NeighborCacheHelper::PopulateNeighborCache (const NetDeviceContainer& c) const
{
NS_LOG_FUNCTION (this);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
Ptr<NetDevice> netDevice = c.Get (i);
Ptr<Channel> channel = netDevice->GetChannel ();
Ptr<Node> node = netDevice->GetNode ();
int32_t ipv4InterfaceIndex = node->GetObject<Ipv4> ()->GetInterfaceForDevice (netDevice);
int32_t ipv6InterfaceIndex = node->GetObject<Ipv6> ()->GetInterfaceForDevice (netDevice);
for (std::size_t j = 0; j < channel->GetNDevices (); ++j)
{
Ptr<NetDevice> neighborDevice = channel->GetDevice (j);
Ptr<Node> neighborNode = neighborDevice->GetNode ();
int32_t ipv4NeighborInterfaceIndex = neighborNode->GetObject<Ipv4> ()->GetInterfaceForDevice (neighborDevice);
int32_t ipv6NeighborInterfaceIndex = neighborNode->GetObject<Ipv6> ()->GetInterfaceForDevice (neighborDevice);
if (neighborDevice != netDevice)
{
if (ipv4InterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4Interface = node->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4InterfaceIndex);
if (ipv4NeighborInterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4NeighborInterface = neighborNode->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4NeighborInterfaceIndex);
PopulateNeighborEntriesIpv4 (ipv4Interface, ipv4NeighborInterface);
}
}
if (ipv6InterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6Interface = node->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6InterfaceIndex);
if (ipv6NeighborInterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6NeighborInterface = neighborNode->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6NeighborInterfaceIndex);
PopulateNeighborEntriesIpv6 (ipv6Interface, ipv6NeighborInterface);
}
}
}
}
}
}
void
NeighborCacheHelper::PopulateNeighborCache (const Ipv4InterfaceContainer &c) const
{
NS_LOG_FUNCTION (this);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
std::pair<Ptr<Ipv4>, uint32_t> returnValue = c.Get (i);
Ptr<Ipv4> ipv4 = returnValue.first;
uint32_t index = returnValue.second;
Ptr<Ipv4Interface> ipv4Interface = DynamicCast<Ipv4L3Protocol> (ipv4)->GetInterface (index);
if (ipv4Interface)
{
Ptr<NetDevice> netDevice = ipv4Interface->GetDevice ();
Ptr<Channel> channel = netDevice->GetChannel ();
for (std::size_t j = 0; j < channel->GetNDevices (); ++j)
{
Ptr<NetDevice> neighborDevice = channel->GetDevice (j);
if (neighborDevice != netDevice)
{
Ptr<Node> neighborNode = neighborDevice->GetNode ();
int32_t ipv4NeighborInterfaceIndex = neighborNode->GetObject<Ipv4> ()->GetInterfaceForDevice (neighborDevice);
if (ipv4NeighborInterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4NeighborInterface = neighborNode->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4NeighborInterfaceIndex);
PopulateNeighborEntriesIpv4 (ipv4Interface, ipv4NeighborInterface);
}
}
}
}
}
}
void
NeighborCacheHelper::PopulateNeighborCache (const Ipv6InterfaceContainer &c) const
{
NS_LOG_FUNCTION (this);
for (uint32_t i = 0; i < c.GetN (); ++i)
{
std::pair<Ptr<Ipv6>, uint32_t> returnValue = c.Get (i);
Ptr<Ipv6> ipv6 = returnValue.first;
uint32_t index = returnValue.second;
Ptr<Ipv6Interface> ipv6Interface = DynamicCast<Ipv6L3Protocol> (ipv6)->GetInterface (index);
if (ipv6Interface)
{
Ptr<NetDevice> netDevice = ipv6Interface->GetDevice ();
Ptr<Channel> channel = netDevice->GetChannel ();
for (std::size_t j = 0; j < channel->GetNDevices (); ++j)
{
Ptr<NetDevice> neighborDevice = channel->GetDevice (j);
if (neighborDevice != netDevice)
{
Ptr<Node> neighborNode = neighborDevice->GetNode ();
int32_t ipv6NeighborInterfaceIndex = neighborNode->GetObject<Ipv6> ()->GetInterfaceForDevice (neighborDevice);
if (ipv6NeighborInterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6NeighborInterface = neighborNode->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6NeighborInterfaceIndex);
PopulateNeighborEntriesIpv6 (ipv6Interface, ipv6NeighborInterface);
}
}
}
}
}
}
void
NeighborCacheHelper::PopulateNeighborEntriesIpv4 (Ptr<Ipv4Interface> ipv4Interface, Ptr<Ipv4Interface> neighborDeviceInterface) const
{
uint32_t netDeviceAddresses = ipv4Interface->GetNAddresses ();
uint32_t neighborDeviceAddresses = neighborDeviceInterface->GetNAddresses ();
for (uint32_t n = 0; n < netDeviceAddresses; ++n)
{
Ipv4InterfaceAddress netDeviceIfAddr = ipv4Interface->GetAddress (n);
for (uint32_t m = 0; m < neighborDeviceAddresses; ++m)
{
Ipv4InterfaceAddress neighborDeviceIfAddr = neighborDeviceInterface->GetAddress (m);
if (netDeviceIfAddr.IsInSameSubnet (neighborDeviceIfAddr.GetLocal ()))
{
Ptr<NetDevice> neighborDevice = neighborDeviceInterface->GetDevice ();
// Add Arp entry of neighbor interface to current interface's Arp cache
AddEntry (ipv4Interface, neighborDeviceIfAddr.GetAddress (),neighborDevice->GetAddress () );
}
}
}
}
void
NeighborCacheHelper::PopulateNeighborEntriesIpv6 (Ptr<Ipv6Interface> ipv6Interface, Ptr<Ipv6Interface> neighborDeviceInterface) const
{
uint32_t netDeviceAddresses = ipv6Interface->GetNAddresses ();
uint32_t neighborDeviceAddresses = neighborDeviceInterface->GetNAddresses ();
for (uint32_t n = 0; n < netDeviceAddresses; ++n)
{
Ipv6InterfaceAddress netDeviceIfAddr = ipv6Interface->GetAddress (n);
// Ignore if it is a linklocal address, which will be added along with the global address
if (netDeviceIfAddr.GetScope () == Ipv6InterfaceAddress::LINKLOCAL || netDeviceIfAddr.GetScope () == Ipv6InterfaceAddress::HOST)
{
NS_LOG_LOGIC ("Skip the LINKLOCAL or LOCALHOST interface " << netDeviceIfAddr);
continue;
}
for (uint32_t m = 0; m < neighborDeviceAddresses; ++m)
{
// Ignore if it is a linklocal address, which will be added along with the global address
Ipv6InterfaceAddress neighborDeviceIfAddr = neighborDeviceInterface->GetAddress (m);
if (neighborDeviceIfAddr.GetScope () == Ipv6InterfaceAddress::LINKLOCAL || neighborDeviceIfAddr.GetScope () == Ipv6InterfaceAddress::HOST)
{
NS_LOG_LOGIC ("Skip the LINKLOCAL or LOCALHOST interface " << neighborDeviceIfAddr);
continue;
}
if (netDeviceIfAddr.IsInSameSubnet (neighborDeviceIfAddr.GetAddress ()))
{
Ptr<NetDevice> neighborDevice = neighborDeviceInterface->GetDevice ();
// Add neighbor's Ndisc entries of global address and linklocal address to current interface's Ndisc cache
AddEntry (ipv6Interface, neighborDeviceIfAddr.GetAddress (), neighborDevice->GetAddress () );
Ipv6InterfaceAddress neighborlinkLocalAddr = neighborDeviceInterface->GetLinkLocalAddress ();
AddEntry (ipv6Interface, neighborlinkLocalAddr.GetAddress (),neighborDevice->GetAddress () );
}
}
}
}
void
NeighborCacheHelper::AddEntry (Ptr<Ipv4Interface> netDeviceInterface, Ipv4Address ipv4Address, Address macAddress) const
{
NS_LOG_FUNCTION (this << netDeviceInterface << ipv4Address << macAddress);
Ptr<ArpCache> arpCache = netDeviceInterface->GetArpCache ();
if (!arpCache)
{
NS_LOG_LOGIC ("ArpCache doesn't exist, might be a point-to-point NetDevice without ArpCache");
return;
}
ArpCache::Entry *entry = arpCache->Lookup (ipv4Address);
if (!entry)
{
NS_LOG_FUNCTION ("ADD an ARP entry");
entry = arpCache->Add (ipv4Address);
}
entry->SetMacAddress (macAddress);
entry->MarkAutoGenerated ();
}
void
NeighborCacheHelper::AddEntry (Ptr<Ipv6Interface> netDeviceInterface, Ipv6Address ipv6Address, Address macAddress) const
{
NS_LOG_FUNCTION (this << netDeviceInterface << ipv6Address << macAddress);
Ptr<NdiscCache> ndiscCache = netDeviceInterface->GetNdiscCache ();
if (!ndiscCache)
{
NS_LOG_LOGIC ("NdiscCache doesn't exist, might be a point-to-point NetDevice without NdiscCache");
return;
}
NdiscCache::Entry* entry = ndiscCache->Lookup (ipv6Address);
if (!entry)
{
NS_LOG_FUNCTION ("ADD a NDISC entry");
entry = ndiscCache->Add (ipv6Address);
}
entry->SetMacAddress (macAddress);
entry->MarkAutoGenerated ();
}
void
NeighborCacheHelper::FlushAutoGenerated (void) const
{
NS_LOG_FUNCTION (this);
for (uint32_t i = 0; i < NodeList::GetNNodes (); ++i)
{
Ptr<Node> node = NodeList::GetNode (i);
for (uint32_t j = 0; j < node->GetNDevices (); ++j)
{
Ptr<NetDevice> netDevice = node->GetDevice (j);
int32_t ipv4InterfaceIndex = node->GetObject<Ipv4> ()->GetInterfaceForDevice (netDevice);
int32_t ipv6InterfaceIndex = node->GetObject<Ipv6> ()->GetInterfaceForDevice (netDevice);
if (ipv4InterfaceIndex != -1)
{
Ptr<Ipv4Interface> ipv4Interface = node->GetObject<Ipv4L3Protocol> ()->GetInterface (ipv4InterfaceIndex);
Ptr<ArpCache> arpCache = ipv4Interface->GetArpCache ();
if (arpCache)
{
NS_LOG_FUNCTION ("Remove an ARP entry");
arpCache->RemoveAutoGeneratedEntries ();
}
}
if (ipv6InterfaceIndex != -1)
{
Ptr<Ipv6Interface> ipv6Interface = node->GetObject<Ipv6L3Protocol> ()->GetInterface (ipv6InterfaceIndex);
Ptr<NdiscCache> ndiscCache = ipv6Interface->GetNdiscCache ();
if (ndiscCache)
{
NS_LOG_FUNCTION ("Remove a NDISC entry");
ndiscCache->RemoveAutoGeneratedEntries ();
}
}
}
}
}
} // namespace ns3

View File

@@ -0,0 +1,132 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 ZHIHENG DONG
*
* 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: Zhiheng Dong <dzh2077@gmail.com>
*/
#ifndef NEIGHBOR_CACHE_HELPER_H
#define NEIGHBOR_CACHE_HELPER_H
#include "ns3/ipv4-address.h"
#include "ns3/net-device-container.h"
#include "ns3/ipv4-interface-container.h"
#include "ns3/ipv6-interface-container.h"
#include "ns3/node-list.h"
#include "ns3/ipv4-interface.h"
#include "ns3/ipv4-l3-protocol.h"
#include "ns3/channel.h"
#include "ns3/arp-l3-protocol.h"
#include "ns3/arp-header.h"
#include "ns3/arp-cache.h"
#include "ns3/ipv6-interface.h"
#include "ns3/icmpv6-l4-protocol.h"
#include "ns3/ipv6-l3-protocol.h"
namespace ns3 {
/**
* \ingroup NeighborCacheHelper
*
* @brief A helper class to populate neighbor cache.
*
* This class is used to populate neighbor cache. Permanent entries will be added
* on the scope of a channel, a NetDeviceContainer, an InterfaceContainer or globally.
*/
class NeighborCacheHelper
{
public:
/**
* @brief Construct a helper class to make life easier while creating neighbor cache
*/
NeighborCacheHelper ();
~NeighborCacheHelper ();
/**
* \brief Populate neighbor ARP and NDISC caches for all devices.
* This method walks the global ChannelList.
*/
void PopulateNeighborCache (void) const;
/**
* \brief Populate neighbor ARP and NDISC caches for all devices in the given
* Channel.
* \param channel the Channel to process
*/
void PopulateNeighborCache (Ptr<Channel> channel) const;
/**
* \brief Populate neighbor ARP and NDISC caches for all devices in the given
* NetDeviceContainer.
* \param c the NetDevice container to process
*/
void PopulateNeighborCache (const NetDeviceContainer &c) const;
/**
* \brief Populate neighbor ARP caches for all IPv4 interfaces in the given
* Ipv4InterfaceContainer.
* \param c the Ipv4InterfaceContainer to process
*/
void PopulateNeighborCache (const Ipv4InterfaceContainer &c) const;
/**
* \brief Populate neighbor NDISC caches for all IPv6 interfaces in the given
* Ipv6InterfaceContainer.
* \param c the Ipv6InterfaceContainer to process
*/
void PopulateNeighborCache (const Ipv6InterfaceContainer &c) const;
/**
* \brief Remove entries generated from NeighborCacheHelper from ARP cache and NDISC cache
*/
void FlushAutoGenerated (void) const;
private:
/**
* \brief Populate neighbor ARP entries for given IPv4 interface.
* \param ipv4Interface the Ipv4Interface to process
* \param neighborDeviceInterface the potential neighbor Ipv4Interface
*/
void PopulateNeighborEntriesIpv4 (Ptr<Ipv4Interface> ipv4Interface, Ptr<Ipv4Interface> neighborDeviceInterface) const;
/**
* \brief Populate neighbor NDISC entries for given IPv6 interface.
* \param ipv6Interface the Ipv6Interface to process
* \param neighborDeviceInterface the potential neighbor Ipv6Interface
*/
void PopulateNeighborEntriesIpv6 (Ptr<Ipv6Interface> ipv6Interface, Ptr<Ipv6Interface> neighborDeviceInterface) const;
/**
* \brief Add an auto_generated entry to the ARP cache of an interface.
* \param netDeviceInterface the Ipv4Interface that ARP cache belongs to
* \param ipv4Address the IPv4 address will be added to the cache.
* \param macAddress the MAC address will be added to the cache.
*/
void AddEntry (Ptr<Ipv4Interface> netDeviceInterface, Ipv4Address ipv4Address, Address macAddress) const;
/**
* \brief Add an auto_generated entry to the NDISC cache of an interface.
* \param netDeviceInterface the Ipv6Interface that NDISC cache belongs to
* \param ipv6Address the IPv6 address will be added to the cache.
* \param macAddress the MAC address will be added to the cache.
*/
void AddEntry (Ptr<Ipv6Interface> netDeviceInterface, Ipv6Address ipv6Address, Address macAddress) const;
};
} // namespace ns3
#endif /* NEIGHBOR_CACHE_HELPER_H */

View File

@@ -214,7 +214,7 @@ ArpCache::HandleWaitReplyTimeout (void)
}
else
{
NS_LOG_LOGIC ("node="<<m_device->GetNode ()->GetId () <<
NS_LOG_LOGIC ("node="<< m_device->GetNode ()->GetId () <<
", wait reply for " << entry->GetIpv4Address () <<
" expired -- drop since max retries exceeded: " <<
entry->GetRetries ());
@@ -286,9 +286,13 @@ ArpCache::PrintArpCache (Ptr<OutputStreamWrapper> stream)
*os << " DELAY\n";
}
else if (i->second->IsPermanent ())
{
*os << " PERMANENT\n";
}
{
*os << " PERMANENT\n";
}
else if (i->second->IsAutoGenerated ())
{
*os << " STATIC_AUTOGENERATED\n";
}
else
{
*os << " STALE\n";
@@ -296,6 +300,23 @@ ArpCache::PrintArpCache (Ptr<OutputStreamWrapper> stream)
}
}
void
ArpCache::RemoveAutoGeneratedEntries (void)
{
NS_LOG_FUNCTION (this);
for (CacheI i = m_arpCache.begin (); i != m_arpCache.end ();)
{
if (i->second->IsAutoGenerated ())
{
i->second->ClearPendingPacket (); //clear the pending packets for entry's ipaddress
delete i->second;
m_arpCache.erase (i++);
continue;
}
i++;
}
}
std::list<ArpCache::Entry *>
ArpCache::LookupInverse (Address to)
{
@@ -389,6 +410,12 @@ ArpCache::Entry::IsPermanent (void)
NS_LOG_FUNCTION (this);
return (m_state == PERMANENT);
}
bool
ArpCache::Entry::IsAutoGenerated (void)
{
NS_LOG_FUNCTION (this);
return (m_state == STATIC_AUTOGENERATED);
}
void
@@ -420,6 +447,16 @@ ArpCache::Entry::MarkPermanent (void)
ClearRetries ();
UpdateSeen ();
}
void
ArpCache::Entry::MarkAutoGenerated (void)
{
NS_LOG_FUNCTION (this << m_macAddress);
NS_ASSERT (!m_macAddress.IsInvalid ());
m_state = STATIC_AUTOGENERATED;
ClearRetries ();
UpdateSeen ();
}
bool
ArpCache::Entry::UpdateWaitReply (Ipv4PayloadHeaderPair waiting)
{
@@ -478,20 +515,20 @@ Time
ArpCache::Entry::GetTimeout (void) const
{
NS_LOG_FUNCTION (this);
switch (m_state) {
case ArpCache::Entry::WAIT_REPLY:
return m_arp->GetWaitReplyTimeout ();
case ArpCache::Entry::DEAD:
return m_arp->GetDeadTimeout ();
case ArpCache::Entry::ALIVE:
return m_arp->GetAliveTimeout ();
case ArpCache::Entry::PERMANENT:
return Time::Max ();
default:
NS_ASSERT (false);
return Seconds (0);
/* NOTREACHED */
switch (m_state)
{
case ArpCache::Entry::WAIT_REPLY:
return m_arp->GetWaitReplyTimeout ();
case ArpCache::Entry::DEAD:
return m_arp->GetDeadTimeout ();
case ArpCache::Entry::ALIVE:
return m_arp->GetAliveTimeout ();
case ArpCache::Entry::PERMANENT:
return Time::Max ();
case ArpCache::Entry::STATIC_AUTOGENERATED:
return Time::Max ();
}
return Time (); // Silence compiler warning
}
bool
ArpCache::Entry::IsExpired (void) const

View File

@@ -167,6 +167,11 @@ public:
*/
void PrintArpCache (Ptr<OutputStreamWrapper> stream);
/**
* \brief Clear the ArpCache of all Auto-Generated entries
*/
void RemoveAutoGeneratedEntries (void);
/**
* \brief Pair of a packet and an Ipv4 header.
*/
@@ -201,6 +206,12 @@ public:
* The entry must have a valid MacAddress.
*/
void MarkPermanent (void);
/**
* \brief Changes the state of this entry to auto-generated.
*
* The entry must have a valid MacAddress.
*/
void MarkAutoGenerated (void);
/**
* \param waiting
* \return
@@ -222,6 +233,10 @@ public:
* \return True if the state of this entry is permanent; false otherwise.
*/
bool IsPermanent (void);
/**
* \return True if the state of this entry is auto-generated; false otherwise.
*/
bool IsAutoGenerated (void);
/**
* \return The MacAddress of this entry
*/
@@ -277,11 +292,13 @@ private:
/**
* \brief ARP cache entry states
*/
enum ArpCacheEntryState_e {
enum ArpCacheEntryState_e
{
ALIVE,
WAIT_REPLY,
DEAD,
PERMANENT
PERMANENT,
STATIC_AUTOGENERATED
};
/**

View File

@@ -336,7 +336,7 @@ ArpL3Protocol::Lookup (Ptr<Packet> packet, const Ipv4Header & ipHeader, Ipv4Addr
m_dropTrace (packet);
}
}
else if (entry-> IsPermanent ())
else if (entry->IsPermanent () || entry->IsAutoGenerated ())
{
NS_LOG_LOGIC ("node="<<m_node->GetId ()<<
", permanent for " << destination << "valid -- send");

View File

@@ -825,7 +825,7 @@ void Icmpv6L4Protocol::HandleNA (Ptr<Packet> packet, Ipv6Address const &src, Ipv
entry->MarkReachable (lla.GetAddress ());
}
}
if (!entry->IsPermanent ())
if (!entry->IsPermanent () )
{
entry->StartReachableTimer ();
}
@@ -1443,7 +1443,7 @@ bool Icmpv6L4Protocol::Lookup (Ipv6Address dst, Ptr<NetDevice> device, Ptr<Ndisc
NdiscCache::Entry* entry = cache->Lookup (dst);
if (entry)
{
if (entry->IsReachable () || entry->IsDelay () || entry->IsPermanent ())
if (entry->IsReachable () || entry->IsDelay () || entry->IsPermanent () || entry->IsAutoGenerated ())
{
*hardwareDestination = entry->GetMacAddress ();
return true;
@@ -1477,7 +1477,7 @@ bool Icmpv6L4Protocol::Lookup (Ptr<Packet> p, const Ipv6Header & ipHeader, Ipv6A
NdiscCache::Entry* entry = cache->Lookup (dst);
if (entry)
{
if (entry->IsReachable () || entry->IsDelay () || entry->IsPermanent ())
if (entry->IsReachable () || entry->IsDelay () || entry->IsPermanent () || entry->IsAutoGenerated ())
{
/* XXX check reachability time */
/* send packet */

View File

@@ -1642,7 +1642,7 @@ bool Ipv6L3Protocol::ReachabilityHint (uint32_t ipInterfaceIndex, Ipv6Address ad
{
entry->UpdateReachableTimer ();
}
else if (entry->IsPermanent ())
else if (entry->IsPermanent () || entry->IsAutoGenerated ())
{
return true;
}

View File

@@ -218,6 +218,10 @@ void NdiscCache::PrintNdiscCache (Ptr<OutputStreamWrapper> stream)
{
*os << " PERMANENT\n";
}
else if (i->second->IsAutoGenerated ())
{
*os << " STATIC_AUTOGENERATED\n";
}
else
{
NS_FATAL_ERROR ("Test for possibly unreachable code-- please file a bug report, with a test case, if this is ever hit");
@@ -554,6 +558,13 @@ void NdiscCache::Entry::MarkPermanent ()
m_state = PERMANENT;
}
void NdiscCache::Entry::MarkAutoGenerated ()
{
NS_LOG_FUNCTION (this);
StopNudTimer ();
m_state = STATIC_AUTOGENERATED;
}
bool NdiscCache::Entry::IsStale () const
{
NS_LOG_FUNCTION (this);
@@ -590,6 +601,12 @@ bool NdiscCache::Entry::IsPermanent () const
return (m_state == PERMANENT);
}
bool NdiscCache::Entry::IsAutoGenerated () const
{
NS_LOG_FUNCTION (this);
return (m_state == STATIC_AUTOGENERATED);
}
Address NdiscCache::Entry::GetMacAddress () const
{
NS_LOG_FUNCTION (this);
@@ -606,26 +623,46 @@ void NdiscCache::Entry::Print (std::ostream &os) const
{
os << m_ipv6Address << " lladdr " << m_macAddress << " state ";
switch (m_state)
{
case INCOMPLETE:
os << "INCOMPLETE";
break;
case REACHABLE:
os << "REACHABLE";
break;
case STALE:
os << "STALE";
break;
case DELAY:
os << "DELAY";
break;
case PROBE:
os << "PROBE";
break;
case PERMANENT:
os << "PERMANENT";
break;
}
{
case INCOMPLETE:
os << "INCOMPLETE";
break;
case REACHABLE:
os << "REACHABLE";
break;
case STALE:
os << "STALE";
break;
case DELAY:
os << "DELAY";
break;
case PROBE:
os << "PROBE";
break;
case PERMANENT:
os << "PERMANENT";
break;
case STATIC_AUTOGENERATED:
os << "PERMANENT";
break;
}
}
void
NdiscCache::RemoveAutoGeneratedEntries (void)
{
NS_LOG_FUNCTION (this);
for (CacheI i = m_ndCache.begin (); i != m_ndCache.end (); )
{
if (i->second->IsAutoGenerated ())
{
i->second->ClearWaitingPacket ();
delete i->second;
m_ndCache.erase (i++);
continue;
}
i++;
}
}
std::ostream& operator << (std::ostream& os, NdiscCache::Entry const& entry)

View File

@@ -147,6 +147,11 @@ public:
*/
void PrintNdiscCache (Ptr<OutputStreamWrapper> stream);
/**
* \brief Clear the NDISC cache of all Auto-Generated entries
*/
void RemoveAutoGeneratedEntries (void);
/**
* \brief Pair of a packet and an Ipv4 header.
*/
@@ -213,6 +218,13 @@ public:
*/
void MarkPermanent ();
/**
* \brief Changes the state of this entry to auto-generated.
*
* The entry must have a valid MacAddress.
*/
void MarkAutoGenerated (void);
/**
* \brief Add a packet (or replace old value) in the queue.
* \param p packet to add
@@ -260,6 +272,12 @@ public:
*/
bool IsPermanent () const;
/**
* \brief Is the entry STATIC_AUTOGENERATED
* \return True if the state of this entry is auto-generated; false otherwise.
*/
bool IsAutoGenerated () const;
/**
* \brief Get the MAC address of this entry.
* \return the L2 address
@@ -383,7 +401,9 @@ private:
STALE, /**< Mapping is stale */
DELAY, /**< Try to wait contact from remote host */
PROBE, /**< Try to contact IPv6 address to know again its L2 address */
PERMANENT /**< Permanent Mapping exists between IPv6 and L2 addresses */
PERMANENT, /**< Permanent Mapping exists between IPv6 and L2 addresses */
STATIC_AUTOGENERATED /**< similar to Permanent populate by NeighborCacheHelper */
};
/**

View File

@@ -0,0 +1,292 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2022 ZHIHENG DONG
*
* 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: Zhiheng Dong <dzh2077@gmail.com>
*/
#include "ns3/test.h"
#include "ns3/socket-factory.h"
#include "ns3/udp-socket-factory.h"
#include "ns3/simulator.h"
#include "ns3/simple-channel.h"
#include "ns3/simple-net-device.h"
#include "ns3/socket.h"
#include "ns3/internet-stack-helper.h"
#include "ns3/ipv4-address-helper.h"
#include "ns3/ipv4-l3-protocol.h"
#include "ns3/icmpv4-l4-protocol.h"
#include "ns3/ipv6-address-helper.h"
#include "ns3/ipv6-l3-protocol.h"
#include "ns3/icmpv6-l4-protocol.h"
#include "ns3/udp-l4-protocol.h"
#include "ns3/ipv4-routing-helper.h"
#include "ns3/ipv6-routing-helper.h"
#include "ns3/neighbor-cache-helper.h"
using namespace ns3;
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief Neighbor cache Test
*/
class NeighborCacheTest : public TestCase
{
Ptr<Packet> m_receivedPacket; //!< Received packet
/**
* \brief Send data immediately after being called.
* \param socket The sending socket.
* \param to IPv4 Destination address.
*/
void DoSendDatav4 (Ptr<Socket> socket, Ipv4Address to);
/**
* \brief Send data immediately after being called.
* \param socket The sending socket.
* \param to IPv6 Destination address.
*/
void DoSendDatav6 (Ptr<Socket> socket, Ipv6Address to);
/**
* \brief Schedules the DoSendData () function to send the data.
* \param socket The sending socket.
* \param to IPv4 Destination address.
*/
void SendData (Ptr<Socket> socket, Ipv4Address to);
/**
* \brief Schedules the DoSendData () function to send the data.
* \param socket The sending socket.
* \param to IPv6 Destination address.
*/
void SendData (Ptr<Socket> socket, Ipv6Address to);
public:
virtual void DoRun (void);
NeighborCacheTest ();
/**
* \brief Receive data.
* \param socket The receiving socket.
*/
void ReceivePkt (Ptr<Socket> socket);
std::vector<uint32_t> m_receivedPacketSizes; //!< Received packet sizes
};
NeighborCacheTest::NeighborCacheTest ()
: TestCase ("NeighborCache")
{}
void NeighborCacheTest::ReceivePkt (Ptr<Socket> socket)
{
[[maybe_unused]] uint32_t availableData;
availableData = socket->GetRxAvailable ();
m_receivedPacket = socket->Recv (std::numeric_limits<uint32_t>::max (), 0);
NS_TEST_ASSERT_MSG_EQ (availableData, m_receivedPacket->GetSize (), "Received Packet size is not equal to the Rx buffer size");
m_receivedPacketSizes.push_back (m_receivedPacket->GetSize ());
}
void
NeighborCacheTest::DoSendDatav4 (Ptr<Socket> socket, Ipv4Address to)
{
Address realTo = InetSocketAddress (to, 1234);
NS_TEST_EXPECT_MSG_EQ (socket->SendTo (Create<Packet> (123), 0, realTo),
123, "100");
}
void
NeighborCacheTest::DoSendDatav6 (Ptr<Socket> socket, Ipv6Address to)
{
Address realTo = Inet6SocketAddress (to, 1234);
NS_TEST_EXPECT_MSG_EQ (socket->SendTo (Create<Packet> (123), 0, realTo),
123, "100");
}
void
NeighborCacheTest::SendData (Ptr<Socket> socket, Ipv4Address to)
{
m_receivedPacket = Create<Packet> ();
Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (60),
&NeighborCacheTest::DoSendDatav4, this, socket, to);
}
void
NeighborCacheTest::SendData (Ptr<Socket> socket, Ipv6Address to)
{
m_receivedPacket = Create<Packet> ();
Simulator::ScheduleWithContext (socket->GetNode ()->GetId (), Seconds (60),
&NeighborCacheTest::DoSendDatav6, this, socket, to);
}
void
NeighborCacheTest::DoRun (void)
{
Ptr<Node> txNode = CreateObject<Node> ();
Ptr<Node> rxNode = CreateObject<Node> ();
Ptr<Node> snifferNode = CreateObject<Node> ();
NodeContainer all (txNode, rxNode, snifferNode);
std::ostringstream stringStream1v4;
Ptr<OutputStreamWrapper> arpStream = Create<OutputStreamWrapper> (&stringStream1v4);
std::ostringstream stringStream1v6;
Ptr<OutputStreamWrapper> ndiscStream = Create<OutputStreamWrapper> (&stringStream1v6);
InternetStackHelper internetNodes;
internetNodes.Install (all);
NetDeviceContainer net;
// Sender Node
Ptr<SimpleNetDevice> txDev;
{
txDev = CreateObject<SimpleNetDevice> ();
txDev->SetAddress (Mac48Address ("00:00:00:00:00:01"));
txNode->AddDevice (txDev);
}
net.Add (txDev);
// Recieve node
Ptr<SimpleNetDevice> rxDev;
{
rxDev = CreateObject<SimpleNetDevice> ();
rxDev->SetAddress (Mac48Address ("00:00:00:00:00:02"));
rxNode->AddDevice (rxDev);
}
net.Add (rxDev);
// Sniffer node
Ptr<SimpleNetDevice> snifferDev;
{
snifferDev = CreateObject<SimpleNetDevice> ();
snifferDev->SetAddress (Mac48Address ("00:00:00:00:00:03"));
snifferNode->AddDevice (snifferDev);
}
net.Add (snifferDev);
// link the channels
Ptr<SimpleChannel> channel = CreateObject<SimpleChannel> ();
txDev->SetChannel (channel);
rxDev->SetChannel (channel);
snifferDev->SetChannel (channel);
// Setup IPv4 addresses
Ipv4AddressHelper ipv4;
ipv4.SetBase (Ipv4Address ("10.0.1.0"), Ipv4Mask ("255.255.255.0"));
Ipv4InterfaceContainer icv4 = ipv4.Assign (net);
//Setup IPv6 addresses
Ipv6AddressHelper ipv6;
ipv6.SetBase (Ipv6Address ("2001:0::"), Ipv6Prefix (64));
Ipv6InterfaceContainer icv6 = ipv6.Assign (net);
//Populate perfect caches.
NeighborCacheHelper neighborCache;
neighborCache.PopulateNeighborCache ();
//Print cache.
Ipv4RoutingHelper::PrintNeighborCacheAllAt (Seconds (0), arpStream);
Ipv6RoutingHelper::PrintNeighborCacheAllAt (Seconds (0), ndiscStream);
// Create the UDP sockets
Ptr<SocketFactory> rxSocketFactory = rxNode->GetObject<UdpSocketFactory> ();
Ptr<Socket> rxSocketv4 = rxSocketFactory->CreateSocket ();
Ptr<Socket> rxSocketv6 = rxSocketFactory->CreateSocket ();
NS_TEST_EXPECT_MSG_EQ (rxSocketv4->Bind (InetSocketAddress (Ipv4Address ("10.0.1.2"), 1234)), 0, "trivial");
NS_TEST_EXPECT_MSG_EQ (rxSocketv6->Bind (Inet6SocketAddress (Ipv6Address ("2001:0::200:ff:fe00:2"), 1234)), 0, "trivial");
rxSocketv4->SetRecvCallback (MakeCallback (&NeighborCacheTest::ReceivePkt, this));
rxSocketv6->SetRecvCallback (MakeCallback (&NeighborCacheTest::ReceivePkt, this));
Ptr<SocketFactory> snifferSocketFactory = snifferNode->GetObject<UdpSocketFactory> ();
Ptr<Socket> snifferSocketv4 = snifferSocketFactory->CreateSocket ();
Ptr<Socket> snifferSocketv6 = snifferSocketFactory->CreateSocket ();
NS_TEST_EXPECT_MSG_EQ (snifferSocketv4->Bind (InetSocketAddress (Ipv4Address ("10.0.1.3"), 1234)), 0, "trivial");
NS_TEST_EXPECT_MSG_EQ (snifferSocketv6->Bind (Inet6SocketAddress (Ipv6Address ("2001:0::200:ff:fe00:3"), 1234)), 0, "trivial");
snifferSocketv4->SetRecvCallback (MakeCallback (&NeighborCacheTest::ReceivePkt, this));
snifferSocketv6->SetRecvCallback (MakeCallback (&NeighborCacheTest::ReceivePkt, this));
Ptr<SocketFactory> txSocketFactory = txNode->GetObject<UdpSocketFactory> ();
Ptr<Socket> txSocket = txSocketFactory->CreateSocket ();
txSocket->SetAllowBroadcast (true);
// ------ Now the tests ------------
// Unicast test
SendData (txSocket, Ipv4Address ("10.0.1.2"));
SendData (txSocket, Ipv6Address ("2001:0::200:ff:fe00:2"));
Simulator::Stop (Seconds (66));
Simulator::Run ();
NS_TEST_EXPECT_MSG_EQ (m_receivedPacketSizes[0], 123, "Perfect Arp should work.");
NS_TEST_EXPECT_MSG_EQ (m_receivedPacketSizes[1], 123, "Perfect Ndp should work.");
NS_TEST_EXPECT_MSG_EQ (m_receivedPacketSizes.size (), 2, "Perfect Arp and perfect Ndp should have received only 1 packet.");
// Test the Cache
constexpr auto arpCache = "ARP Cache of node 0 at time 0\n"
"10.0.1.2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n"
"10.0.1.3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"ARP Cache of node 1 at time 0\n"
"10.0.1.1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"10.0.1.3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"ARP Cache of node 2 at time 0\n"
"10.0.1.1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"10.0.1.2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n";
NS_TEST_EXPECT_MSG_EQ (stringStream1v4.str (), arpCache, "Arp cache is incorrect.");
constexpr auto NdiscCache = "NDISC Cache of node 0 at time +0s\n"
"2001::200:ff:fe00:2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n"
"2001::200:ff:fe00:3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"NDISC Cache of node 1 at time +0s\n"
"2001::200:ff:fe00:1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"2001::200:ff:fe00:3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:3 dev 1 lladdr 04-06-00:00:00:00:00:03 STATIC_AUTOGENERATED\n"
"NDISC Cache of node 2 at time +0s\n"
"2001::200:ff:fe00:1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"2001::200:ff:fe00:2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:1 dev 1 lladdr 04-06-00:00:00:00:00:01 STATIC_AUTOGENERATED\n"
"fe80::200:ff:fe00:2 dev 1 lladdr 04-06-00:00:00:00:00:02 STATIC_AUTOGENERATED\n";
NS_TEST_EXPECT_MSG_EQ (stringStream1v6.str (), NdiscCache, "Ndisc cache is incorrect.");
m_receivedPacket->RemoveAllByteTags ();
Simulator::Destroy ();
}
/**
* \ingroup internet-test
* \ingroup tests
*
* \brief IPv4 RIP TestSuite
*/
class NeighborCacheTestSuite : public TestSuite
{
public:
NeighborCacheTestSuite () : TestSuite ("neighbor-cache", UNIT)
{
AddTestCase (new NeighborCacheTest, TestCase::QUICK);
}
};
static NeighborCacheTestSuite g_neighborcacheTestSuite; //!< Static variable for test initialization