internet: Allow InternetStackHelper to be called on a node with IPv4 or IPv6 already installed

This commit is contained in:
Tommaso Pecorella
2023-02-28 12:33:13 -06:00
parent 94f77ac492
commit 8f43b2cc05
9 changed files with 210 additions and 39 deletions

View File

@@ -55,6 +55,7 @@ Changes from ns-3.38 to ns-3-dev
* (internet) The function signature of `Ipv4RoutingProtocol::RouteInput` and `Ipv6RoutingProtocol::RouteInput` have changed. The `UnicastForwardCallback` (ucb), `MulticastForwardCallback` (mcb), `LocalDeliverCallback` (lcb) and `ErrorCallback` (ecb) should now be passed as const references.
* (olsr) The defines `OLSR_WILL_*` have been replaced by enum `Willingness`.
* (wifi) The `WifiCodeRate` typedef was converted to an enum.
* (internet) `InternetStackHelper` can be now used on nodes with an `InternetStack` already installed (it will not install IPv[4,6] twice).
### Changes to build system

View File

@@ -75,6 +75,7 @@ This release has discontinued support for g++-8 compilers.
- (wifi) Added 802.11ax dual NAV (basic NAV and intra-BSS NAV)
- (wifi) Added 802.11ax Uplink Multi-User Carrier Sense (UL MU CS) mechanism and have it used by non-AP STAs when determining if they can reply to a received Trigger Frame
- (wifi) Added support for 802.11ax MU-RTS/CTS protection
- (internet) InternetStackHelper can be now used on nodes with an InternetStack already installed (it will not install IPv[4,6] twice).
### Bugs fixed

View File

@@ -262,6 +262,7 @@ endif()
set(test_sources
test/global-route-manager-impl-test-suite.cc
test/icmp-test.cc
test/internet-stack-helper-test-suite.cc
test/ipv4-address-generator-test-suite.cc
test/ipv4-address-helper-test-suite.cc
test/ipv4-deduplication-test.cc

View File

@@ -290,6 +290,12 @@ InternetStackHelper::InstallAll() const
void
InternetStackHelper::CreateAndAggregateObjectFromTypeId(Ptr<Node> node, const std::string typeId)
{
TypeId tid = TypeId::LookupByName(typeId);
if (node->GetObject<Object>(tid))
{
return;
}
ObjectFactory factory;
factory.SetTypeId(typeId);
Ptr<Object> protocol = factory.Create<Object>();
@@ -301,13 +307,7 @@ InternetStackHelper::Install(Ptr<Node> node) const
{
if (m_ipv4Enabled)
{
if (node->GetObject<Ipv4>())
{
NS_FATAL_ERROR("InternetStackHelper::Install (): Aggregating "
"an InternetStack to a node with an existing Ipv4 object");
return;
}
/* IPv4 stack */
CreateAndAggregateObjectFromTypeId(node, "ns3::ArpL3Protocol");
CreateAndAggregateObjectFromTypeId(node, "ns3::Ipv4L3Protocol");
CreateAndAggregateObjectFromTypeId(node, "ns3::Icmpv4L4Protocol");
@@ -318,22 +318,19 @@ InternetStackHelper::Install(Ptr<Node> node) const
arp->SetAttribute("RequestJitter",
StringValue("ns3::ConstantRandomVariable[Constant=0.0]"));
}
// Set routing
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create(node);
ipv4->SetRoutingProtocol(ipv4Routing);
if (!ipv4->GetRoutingProtocol())
{
Ptr<Ipv4RoutingProtocol> ipv4Routing = m_routing->Create(node);
ipv4->SetRoutingProtocol(ipv4Routing);
}
}
if (m_ipv6Enabled)
{
/* IPv6 stack */
if (node->GetObject<Ipv6>())
{
NS_FATAL_ERROR("InternetStackHelper::Install (): Aggregating "
"an InternetStack to a node with an existing Ipv6 object");
return;
}
CreateAndAggregateObjectFromTypeId(node, "ns3::Ipv6L3Protocol");
CreateAndAggregateObjectFromTypeId(node, "ns3::Icmpv6L4Protocol");
if (m_ipv6NsRsJitterEnabled == false)
@@ -345,9 +342,11 @@ InternetStackHelper::Install(Ptr<Node> node) const
}
// Set routing
Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
Ptr<Ipv6RoutingProtocol> ipv6Routing = m_routingv6->Create(node);
ipv6->SetRoutingProtocol(ipv6Routing);
if (!ipv6->GetRoutingProtocol())
{
Ptr<Ipv6RoutingProtocol> ipv6Routing = m_routingv6->Create(node);
ipv6->SetRoutingProtocol(ipv6Routing);
}
/* register IPv6 extensions and options */
ipv6->RegisterExtensions();
ipv6->RegisterOptions();
@@ -357,9 +356,17 @@ InternetStackHelper::Install(Ptr<Node> node) const
{
CreateAndAggregateObjectFromTypeId(node, "ns3::TrafficControlLayer");
CreateAndAggregateObjectFromTypeId(node, "ns3::UdpL4Protocol");
node->AggregateObject(m_tcpFactory.Create<Object>());
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory>();
node->AggregateObject(factory);
// note: the following could be changed to
// CreateAndAggregateObjectFromTypeId(node, "ns3::TcpL4Protocol");
if (!node->GetObject<TcpL4Protocol>())
{
node->AggregateObject(m_tcpFactory.Create<Object>());
}
if (!node->GetObject<PacketSocketFactory>())
{
Ptr<PacketSocketFactory> factory = CreateObject<PacketSocketFactory>();
node->AggregateObject(factory);
}
}
if (m_ipv4Enabled)

View File

@@ -144,8 +144,8 @@ class InternetStackHelper : public PcapHelperForIpv4,
/**
* Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes
* onto the provided node. This method will assert if called on a node that
* already has an Ipv4 object aggregated to it.
* onto the provided node. This method will do nothing if the stacks are already installed,
* and will not overwrite existing stacks parameters.
*
* \param nodeName The name of the node on which to install the stack.
*/
@@ -153,8 +153,8 @@ class InternetStackHelper : public PcapHelperForIpv4,
/**
* Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes
* onto the provided node. This method will assert if called on a node that
* already has an Ipv4 object aggregated to it.
* onto the provided node. This method will do nothing if the stacks are already installed,
* and will not overwrite existing stacks parameters.
*
* \param node The node on which to install the stack.
*/
@@ -162,9 +162,8 @@ class InternetStackHelper : public PcapHelperForIpv4,
/**
* For each node in the input container, aggregate implementations of the
* ns3::Ipv4, ns3::Ipv6, ns3::Udp, and, ns3::Tcp classes. The program will assert
* if this method is called on a container with a node that already has
* an Ipv4 object aggregated to it.
* ns3::Ipv4, ns3::Ipv6, ns3::Udp, and, ns3::Tcp classes. This method will do nothing if the
* stacks are already installed, and will not overwrite existing stacks parameters.
*
* \param c NodeContainer that holds the set of nodes on which to install the
* new stacks.
@@ -306,7 +305,8 @@ class InternetStackHelper : public PcapHelperForIpv4,
const Ipv6RoutingHelper* m_routingv6;
/**
* \brief create an object from its TypeId and aggregates it to the node
* \brief create an object from its TypeId and aggregates it to the node. Does nothing if
* an object of the same type is already aggregated to the node.
* \param node the node
* \param typeId the object TypeId
*/

View File

@@ -1650,6 +1650,10 @@ Ipv6L3Protocol::BuildHeader(Ipv6Address src,
void
Ipv6L3Protocol::RegisterExtensions()
{
if (m_node->GetObject<Ipv6ExtensionDemux>())
{
return;
}
Ptr<Ipv6ExtensionDemux> ipv6ExtensionDemux = CreateObject<Ipv6ExtensionDemux>();
ipv6ExtensionDemux->SetNode(m_node);
@@ -1686,6 +1690,10 @@ Ipv6L3Protocol::RegisterExtensions()
void
Ipv6L3Protocol::RegisterOptions()
{
if (m_node->GetObject<Ipv6OptionDemux>())
{
return;
}
Ptr<Ipv6OptionDemux> ipv6OptionDemux = CreateObject<Ipv6OptionDemux>();
ipv6OptionDemux->SetNode(m_node);

View File

@@ -368,14 +368,7 @@ class Ipv6L3Protocol : public Ipv6
Ipv6Prefix mask,
Ipv6Address defaultRouter);
/**
* \brief Register the IPv6 Extensions.
*/
void RegisterExtensions() override;
/**
* \brief Register the IPv6 Options.
*/
void RegisterOptions() override;
/**

View File

@@ -383,12 +383,14 @@ class Ipv6 : public Object
Ptr<Ipv6Route> route) = 0;
/**
* \brief Register the IPv6 Extensions.
* \brief Register the IPv6 Extensions. Does nothing if the Extensions have been already
* registered.
*/
virtual void RegisterExtensions() = 0;
/**
* \brief Register the IPv6 Options.
* \brief Register the IPv6 Options. Does nothing if the Options have been already
* registered.
*/
virtual void RegisterOptions() = 0;

View File

@@ -0,0 +1,158 @@
/*
* Copyright (c) 2023 Universita' di Firenze
*
* 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: Tommaso Pecorella <tommaso.pecorella@unifi.it>
*/
#include "ns3/internet-stack-helper.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/test.h"
#include <string>
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("InternetStackHelperTestSuite");
/**
* \ingroup internet-test
*
* \brief InternetStackHelper Test
*/
class InternetStackHelperTestCase : public TestCase
{
public:
InternetStackHelperTestCase();
private:
void DoRun() override;
void DoTeardown() override;
};
InternetStackHelperTestCase::InternetStackHelperTestCase()
: TestCase("InternetStackHelperTestCase")
{
}
void
InternetStackHelperTestCase::DoRun()
{
// Checks:
// 1. IPv4 only, add IPv4 + IPv6 (result, IPv4 + IPv6)
// 2. IPv6 only, add IPv4 + IPv6 (result, IPv4 + IPv6)
// 3. IPv4 + IPv6, add IPv4 + IPv6 (result, IPv4 + IPv6)
Ptr<Node> nodeIpv4Only = CreateObject<Node>();
Ptr<Node> nodeIpv6Only = CreateObject<Node>();
Ptr<Node> nodeIpv46 = CreateObject<Node>();
InternetStackHelper internet;
internet.SetIpv4StackInstall(true);
internet.SetIpv6StackInstall(false);
internet.Install(nodeIpv4Only);
internet.SetIpv4StackInstall(false);
internet.SetIpv6StackInstall(true);
internet.Install(nodeIpv6Only);
internet.SetIpv4StackInstall(true);
internet.SetIpv6StackInstall(true);
internet.Install(nodeIpv46);
// Check that the three nodes have only the intended IP stack.
NS_TEST_EXPECT_MSG_NE(nodeIpv4Only->GetObject<Ipv4>(),
nullptr,
"IPv4 not found on IPv4-only node (should have been there)");
NS_TEST_EXPECT_MSG_EQ(nodeIpv4Only->GetObject<Ipv6>(),
nullptr,
"IPv6 found on IPv4-only node (should not have been there)");
NS_TEST_EXPECT_MSG_EQ(nodeIpv6Only->GetObject<Ipv4>(),
nullptr,
"IPv4 found on IPv6-only node (should not have been there)");
NS_TEST_EXPECT_MSG_NE(nodeIpv6Only->GetObject<Ipv6>(),
nullptr,
"IPv6 not found on IPv6-only node (should have been there)");
NS_TEST_EXPECT_MSG_NE(nodeIpv46->GetObject<Ipv4>(),
nullptr,
"IPv4 not found on dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(nodeIpv46->GetObject<Ipv6>(),
nullptr,
"IPv6 not found on dual stack node (should have been there)");
// Now we install IPv4 and IPv6 on the IPv4-only node
// IPv4 is already there, no error should happen.
internet.Install(nodeIpv4Only);
// Now we install IPv4 and IPv6 on the IPv6-only node,
// IPv6 is already there, no error should happen.
internet.Install(nodeIpv6Only);
// Now we install IPv4 and IPv6 on the dual stack node
// IPv4 and IPv6 are already there, no error should happen.
internet.Install(nodeIpv46);
// Check that the three nodes have both IPv4 and IPv6.
NS_TEST_EXPECT_MSG_NE(
nodeIpv4Only->GetObject<Ipv4>(),
nullptr,
"IPv4 not found on IPv4-only, now dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(
nodeIpv4Only->GetObject<Ipv6>(),
nullptr,
"IPv6 not found on IPv4-only, now dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(
nodeIpv6Only->GetObject<Ipv4>(),
nullptr,
"IPv4 not found on IPv6-only, now dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(
nodeIpv6Only->GetObject<Ipv6>(),
nullptr,
"IPv6 not found on IPv6-only, now dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(nodeIpv46->GetObject<Ipv4>(),
nullptr,
"IPv4 not found on dual stack node (should have been there)");
NS_TEST_EXPECT_MSG_NE(nodeIpv46->GetObject<Ipv6>(),
nullptr,
"IPv6 not found on dual stack node (should have been there)");
}
void
InternetStackHelperTestCase::DoTeardown()
{
Simulator::Destroy();
}
/**
* \ingroup internet-test
*
* \brief InternetStackHelper TestSuite
*/
class InternetStackHelperTestSuite : public TestSuite
{
public:
InternetStackHelperTestSuite()
: TestSuite("internet-stack-helper", UNIT)
{
AddTestCase(new InternetStackHelperTestCase(), TestCase::QUICK);
}
};
static InternetStackHelperTestSuite
g_internetStackHelperTestSuite; //!< Static variable for test initialization