Skip to content

Commit

Permalink
Ipv4NetworkConfigurator: Added support for recalculating the static r…
Browse files Browse the repository at this point in the history
…outes when an interface goes down/up or the carrier is lost/back.

Added updateRoutes parameter that controls whether this is done or not.
  • Loading branch information
levy committed Feb 8, 2024
1 parent a8c9164 commit 5f38337
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 63 deletions.
136 changes: 88 additions & 48 deletions src/inet/networklayer/configurator/ipv4/Ipv4NetworkConfigurator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,13 @@ void Ipv4NetworkConfigurator::initialize(int stage)
addDefaultRoutesParameter = par("addDefaultRoutes");
addDirectRoutesParameter = par("addDirectRoutes");
optimizeRoutesParameter = par("optimizeRoutes");
updateRoutesParameter = par("updateRoutes");
}
else if (stage == INITSTAGE_NETWORK_CONFIGURATION)
else if (stage == INITSTAGE_NETWORK_CONFIGURATION) {
ensureConfigurationComputed(topology);
if (addStaticRoutesParameter && updateRoutesParameter)
getParentModule()->subscribe(interfaceStateChangedSignal, this);
}
else if (stage == INITSTAGE_LAST)
dumpConfiguration();
}
Expand Down Expand Up @@ -176,14 +180,31 @@ void Ipv4NetworkConfigurator::configureRoutingTable(IIpv4RoutingTable *routingTa
}
}

void Ipv4NetworkConfigurator::configureRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface)
void Ipv4NetworkConfigurator::addConfigurationToRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface)
{
ensureConfigurationComputed(topology);
// TODO avoid linear search
for (int i = 0; i < topology.getNumNodes(); i++) {
Node *node = (Node *)topology.getNode(i);
if (node->routingTable == routingTable)
configureRoutingTable(node, networkInterface);
if (node->routingTable == routingTable) {
node->configuredNetworkInterfaces.push_back(networkInterface);
configureRoutingTable(node);
break;
}
}
}

void Ipv4NetworkConfigurator::removeConfigurationFromRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface)
{
ensureConfigurationComputed(topology);
// TODO avoid linear search
for (int i = 0; i < topology.getNumNodes(); i++) {
Node *node = (Node *)topology.getNode(i);
if (node->routingTable == routingTable) {
remove(node->configuredNetworkInterfaces, networkInterface);
configureRoutingTable(node);
break;
}
}
}

Expand All @@ -207,59 +228,68 @@ void Ipv4NetworkConfigurator::configureInterface(InterfaceInfo *interfaceInfo)

void Ipv4NetworkConfigurator::configureRoutingTable(Node *node)
{
auto routingTable = node->routingTable;
auto nodePath = node->getModule()->getFullPath();
EV_DETAIL << "Configuring routing table of " << nodePath << endl;
EV_DETAIL << "Configuring routing table" << EV_FIELD(nodePath) << endl;
EV_DETAIL << "Removing all routes from routing table" << EV_FIELD(nodePath) << endl;
for (size_t i = 0; i < routingTable->getNumRoutes();) {
auto route = routingTable->getRoute(i);
if (route->getSourceType() == IRoute::MANUAL && route->getSource() == this) {
EV_DETAIL << "Removing route" << EV_FIELD(route) << EV_FIELD(nodePath) << endl;
routingTable->deleteRoute(route);
}
else
i++;
}
for (size_t i = 0; i < routingTable->getNumMulticastRoutes();) {
auto route = routingTable->getMulticastRoute(i);
if (route->getSourceType() == IMulticastRoute::MANUAL && route->getSource() == this) {
EV_DETAIL << "Removing multicast route" << EV_FIELD(route) << EV_FIELD(nodePath) << endl;
routingTable->deleteMulticastRoute(route);
}
else
i++;
}
EV_DETAIL << "Adding all routes to routing table" << EV_FIELD(nodePath) << endl;
for (size_t i = 0; i < node->staticRoutes.size(); i++) {
Ipv4Route *original = node->staticRoutes[i];
Ipv4Route *clone = new Ipv4Route();
clone->setMetric(original->getMetric());
clone->setSourceType(original->getSourceType());
clone->setSource(original->getSource());
clone->setDestination(original->getDestination());
clone->setNetmask(original->getNetmask());
clone->setGateway(original->getGateway());
clone->setInterface(original->getInterface());
EV_DETAIL << "Configuring route " << *clone << " in " << nodePath << endl;
node->routingTable->addRoute(clone);
if (contains(node->configuredNetworkInterfaces, original->getInterface())) {
Ipv4Route *route = new Ipv4Route(*original);
EV_DETAIL << "Adding route" << EV_FIELD(route) << EV_FIELD(nodePath) << endl;
routingTable->addRoute(route);
}
}
for (size_t i = 0; i < node->staticMulticastRoutes.size(); i++) {
Ipv4MulticastRoute *original = node->staticMulticastRoutes[i];
Ipv4MulticastRoute *clone = new Ipv4MulticastRoute(*original);
EV_DETAIL << "Configuring multicast route " << *clone << " in " << nodePath << endl;
node->routingTable->addMulticastRoute(clone);
bool used = original->getInInterface() && contains(node->configuredNetworkInterfaces, original->getInInterface()->getInterface());
for (size_t j = 0; !used && j < original->getNumOutInterfaces(); j++)
if (original->getOutInterface(j) && contains(node->configuredNetworkInterfaces, original->getOutInterface(j)->getInterface()))
used = true;
if (used) {
Ipv4MulticastRoute *route = new Ipv4MulticastRoute(*original);
for (int j = 0; j < route->getNumOutInterfaces();) {
if (!contains(node->configuredNetworkInterfaces, route->getOutInterface(j)->getInterface()))
route->removeOutInterface(j);
else
j++;
}
EV_DETAIL << "Adding multicast route " << EV_FIELD(route) << EV_FIELD(nodePath) << endl;
routingTable->addMulticastRoute(route);
}
}
}

void Ipv4NetworkConfigurator::configureRoutingTable(Node *node, NetworkInterface *networkInterface)
void Ipv4NetworkConfigurator::receiveSignal(cComponent *source, simsignal_t signal, cObject *obj, cObject *details)
{
auto nodePath = node->getModule()->getFullPath();
EV_DETAIL << "Configuring routing table of " << nodePath << endl;
for (size_t i = 0; i < node->staticRoutes.size(); i++) {
Ipv4Route *original = node->staticRoutes[i];
if (original->getInterface() == networkInterface) {
Ipv4Route *clone = new Ipv4Route();
clone->setMetric(original->getMetric());
clone->setSourceType(original->getSourceType());
clone->setSource(original->getSource());
clone->setDestination(original->getDestination());
clone->setNetmask(original->getNetmask());
clone->setGateway(original->getGateway());
clone->setInterface(original->getInterface());
EV_DETAIL << "Configuring route " << *clone << " in " << nodePath << endl;
node->routingTable->addRoute(clone);
}
}
for (size_t i = 0; i < node->staticMulticastRoutes.size(); i++) {
Ipv4MulticastRoute *original = node->staticMulticastRoutes[i];
bool needed = original->getInInterface() && original->getInInterface()->getInterface() == networkInterface;
for (size_t j = 0; !needed && j < original->getNumOutInterfaces(); j++)
if (original->getOutInterface(j) && original->getOutInterface(j)->getInterface() == networkInterface)
needed = true;

if (needed) {
Ipv4MulticastRoute *clone = new Ipv4MulticastRoute(*original);
EV_DETAIL << "Configuring multicast route " << *clone << " to " << nodePath << endl;
node->routingTable->addMulticastRoute(clone);
if (signal == interfaceStateChangedSignal) {
const auto *networkInterfaceChangeDetails = check_and_cast<const NetworkInterfaceChangeDetails *>(obj);
auto fieldId = networkInterfaceChangeDetails->getFieldId();
if (fieldId == NetworkInterface::F_STATE || fieldId == NetworkInterface::F_CARRIER) {
if (updateRoutesParameter) {
computeConfiguration();
configureAllInterfaces();
configureAllRoutingTables();
}
}
}
}
Expand Down Expand Up @@ -1070,6 +1100,7 @@ void Ipv4NetworkConfigurator::readManualRouteConfiguration(Topology& topology)
route->setMetric(atoi(metricAttr));
EV_INFO << "Adding manual route " << *route << " to " << node->module->getFullPath() << endl;
node->staticRoutes.push_back(route);
node->configuredNetworkInterfaces.push_back(route->getInterface());
}
}
}
Expand Down Expand Up @@ -1157,10 +1188,14 @@ void Ipv4NetworkConfigurator::readManualMulticastRouteConfiguration(Topology& to
route->setOriginNetmask(netmask);
route->setMulticastGroup(group);
route->setInInterface(parent ? new Ipv4MulticastRoute::InInterface(parent) : nullptr);
if (parent)
node->configuredNetworkInterfaces.push_back(parent);
if (!opp_isempty(metricAttr))
route->setMetric(atoi(metricAttr));
for (auto& child : children)
for (auto& child : children) {
route->addOutInterface(new Ipv4MulticastRoute::OutInterface(child, false /*TODOisLeaf*/));
node->configuredNetworkInterfaces.push_back(child);
}
EV_INFO << "Adding manual multicast route " << *route << " to " << node->module->getFullPath() << endl;
node->staticMulticastRoutes.push_back(route);
}
Expand Down Expand Up @@ -1398,6 +1433,7 @@ void Ipv4NetworkConfigurator::addStaticRoutes(Topology& topology, cXMLElement *a
route->setSource(this);
EV_DEBUG << "Adding direct route " << *route << " to " << sourceNode->module->getFullPath() << endl;
sourceNode->staticRoutes.push_back(route);
sourceNode->configuredNetworkInterfaces.push_back(route->getInterface());
}

// add a default route towards the only one gateway
Expand All @@ -1411,6 +1447,7 @@ void Ipv4NetworkConfigurator::addStaticRoutes(Topology& topology, cXMLElement *a
route->setSource(this);
EV_DEBUG << "Adding default route " << *route << " to " << sourceNode->module->getFullPath() << endl;
sourceNode->staticRoutes.push_back(route);
sourceNode->configuredNetworkInterfaces.push_back(route->getInterface());

// skip building and optimizing the whole routing table
EV_DEBUG << "Adding default routes to " << sourceNode->getModule()->getFullPath() << ", node has only one (non-loopback) interface" << endl;
Expand Down Expand Up @@ -1481,6 +1518,7 @@ void Ipv4NetworkConfigurator::addStaticRoutes(Topology& topology, cXMLElement *a
delete route;
else {
sourceNode->staticRoutes.push_back(route);
sourceNode->configuredNetworkInterfaces.push_back(route->getInterface());
EV_DEBUG << "Adding route " << sourceNetworkInterface->getInterfaceFullPath() << " -> " << destinationNetworkInterface->getInterfaceFullPath() << " as " << route->str() << endl;
}
}
Expand Down Expand Up @@ -1902,6 +1940,8 @@ void Ipv4NetworkConfigurator::addStaticMulticastRoutes(Topology& topology, Node
route->setOriginNetmask(originNetmask);
route->setMulticastGroup(multicastGroup);
route->setInInterface(inInterfaceInfo != nullptr ? new Ipv4MulticastRoute::InInterface(inInterfaceInfo->networkInterface) : nullptr);
if (inInterfaceInfo != nullptr)
node->configuredNetworkInterfaces.push_back(inInterfaceInfo->networkInterface);
// if (!opp_isempty(metricAttr))
// route->setMetric(atoi(metricAttr));
// EV_INFO << "Adding static multicast route " << *route << " to " << node->module->getFullPath() << endl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace inet {
*
* For more info please see the NED file.
*/
class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase
class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase, public cListener
{
protected:
/**
Expand All @@ -35,6 +35,7 @@ class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase
public:
std::vector<Ipv4Route *> staticRoutes;
std::vector<Ipv4MulticastRoute *> staticMulticastRoutes;
std::vector<const NetworkInterface *> configuredNetworkInterfaces;

public:
Node(cModule *module) : L3NetworkConfiguratorBase::Node(module) {}
Expand Down Expand Up @@ -118,6 +119,7 @@ class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase
bool addDefaultRoutesParameter = false;
bool addDirectRoutesParameter = false;
bool optimizeRoutesParameter = false;
bool updateRoutesParameter = false;

// internal state
Topology topology;
Expand Down Expand Up @@ -149,10 +151,10 @@ class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase
*/
virtual void configureRoutingTable(IIpv4RoutingTable *routingTable);

/**
* Configures the provided routing table based on the current network configuration for specified networkInterface.
*/
virtual void configureRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface);
virtual void addConfigurationToRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface);
virtual void removeConfigurationFromRoutingTable(IIpv4RoutingTable *routingTable, NetworkInterface *networkInterface);

virtual void receiveSignal(cComponent *source, simsignal_t signal, cObject *obj, cObject *details) override;

protected:
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
Expand Down Expand Up @@ -208,7 +210,6 @@ class INET_API Ipv4NetworkConfigurator : public L3NetworkConfiguratorBase
void ensureConfigurationComputed(Topology& topology);
void configureInterface(InterfaceInfo *interfaceInfo);
void configureRoutingTable(Node *node);
void configureRoutingTable(Node *node, NetworkInterface *networkInterface);

/**
* Prints the current network configuration to the module output.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ simple Ipv4NetworkConfigurator extends L3NetworkConfiguratorBase
bool addSubnetRoutes = default(true); // add subnet routes instead of destination interface routes (only where applicable; used only if addStaticRoutes is true)
bool addDirectRoutes = default(true); // add direct routes (i.e. directly connected interfaces) to the routing table (used only if addStaticRoutes is true)
bool optimizeRoutes = default(true); // optimize routing tables by merging routes, the resulting routing table might route more packets than the original (used only if addStaticRoutes is true)
bool updateRoutes = default(false); // recalculate static routes if an interface goes down/up or a carrier is lost/back
bool dumpTopology = default(false); // print extracted network topology to the module output
bool dumpLinks = default(false); // print recognized network links to the module output
bool dumpAddresses = default(false); // print assigned IP addresses for all interfaces to the module output
Expand Down
24 changes: 15 additions & 9 deletions src/inet/networklayer/configurator/ipv4/Ipv4NodeConfigurator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ void Ipv4NodeConfigurator::initialize(int stage)
cSimpleModule::initialize(stage);

if (stage == INITSTAGE_LOCAL) {
_configureRoutingTable = par("configureRoutingTable");
cModule *node = getContainingNode(this);
const char *networkConfiguratorPath = par("networkConfiguratorModule");
nodeStatus = dynamic_cast<NodeStatus *>(node->getSubmodule("status"));
Expand Down Expand Up @@ -131,7 +132,7 @@ void Ipv4NodeConfigurator::configureAllInterfaces()
void Ipv4NodeConfigurator::configureRoutingTable()
{
ASSERT(networkConfigurator);
if (par("configureRoutingTable"))
if (_configureRoutingTable)
networkConfigurator->configureRoutingTable(routingTable);
}

Expand All @@ -157,16 +158,21 @@ void Ipv4NodeConfigurator::receiveSignal(cComponent *source, simsignal_t signalI
// The RoutingTable deletes routing entries of interface
}
else if (signalID == interfaceStateChangedSignal) {
const auto *ieChangeDetails = check_and_cast<const NetworkInterfaceChangeDetails *>(obj);
auto fieldId = ieChangeDetails->getFieldId();
const auto *networkInterfaceChangeDetails = check_and_cast<const NetworkInterfaceChangeDetails *>(obj);
auto fieldId = networkInterfaceChangeDetails->getFieldId();
if (fieldId == NetworkInterface::F_STATE || fieldId == NetworkInterface::F_CARRIER) {
auto *entry = ieChangeDetails->getNetworkInterface();
if (entry->isUp() && entry->hasCarrier() && networkConfigurator) {
networkConfigurator->configureInterface(entry);
if (par("configureRoutingTable"))
networkConfigurator->configureRoutingTable(routingTable, entry);
auto networkInterface = networkInterfaceChangeDetails->getNetworkInterface();
if (networkConfigurator != nullptr) {
if (networkInterface->isUp() && networkInterface->hasCarrier()) {
networkConfigurator->configureInterface(networkInterface);
if (_configureRoutingTable)
networkConfigurator->addConfigurationToRoutingTable(routingTable, networkInterface);
}
else {
if (_configureRoutingTable)
networkConfigurator->removeConfigurationFromRoutingTable(routingTable, networkInterface);
}
}
// otherwise the RoutingTable deletes routing entries of interface entry
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace inet {
class INET_API Ipv4NodeConfigurator : public cSimpleModule, public ILifecycle, protected cListener
{
protected:
bool _configureRoutingTable = false;
opp_component_ptr<NodeStatus> nodeStatus;
ModuleRefByPar<IInterfaceTable> interfaceTable;
ModuleRefByPar<IIpv4RoutingTable> routingTable;
Expand Down

0 comments on commit 5f38337

Please sign in to comment.