//
// Copyright (C) 2013 Opensim Ltd.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, see .
//
#include
#include "inet/common/INETDefs.h"
#include "inet/common/scenario/IScriptable.h"
#include "inet/networklayer/contract/IRoutingTable.h"
#include "inet/networklayer/contract/IL3AddressType.h"
using namespace std;
namespace inet {
struct DestFilter
{
vector destAddresses;
vector prefixLengths;
DestFilter(const char *str);
bool matches(IRoute *route);
};
DestFilter::DestFilter(const char *str)
{
if (str)
{
cStringTokenizer tokenizer(str);
while (tokenizer.hasMoreTokens())
{
const char *dest = tokenizer.nextToken();
const char *end = strchr(dest, '/');
if (end)
{
destAddresses.push_back(L3Address(string(dest,end).c_str()));
prefixLengths.push_back(atoi(end+1));
}
else
{
L3Address destAddr = L3Address(dest);
destAddresses.push_back(destAddr);
prefixLengths.push_back(destAddr.getAddressType()->getMaxPrefixLength());
}
}
}
}
bool DestFilter::matches(IRoute *route)
{
if (destAddresses.empty())
return true;
for (int i = 0; i < (int)destAddresses.size(); ++i)
{
L3Address &dest = destAddresses[i];
int prefixLength = prefixLengths[i];
if (route->getDestinationAsGeneric().matches(dest, prefixLength))
return true;
}
return false;
}
class INET_API RoutingTableLogger : public cSimpleModule, public IScriptable
{
ofstream out;
protected:
virtual void initialize();
virtual void finish();
virtual void processCommand(const cXMLElement &node);
private:
IRoutingTable *findRoutingTableInNode(cModule *node);
void dumpRoutes(cModule *node, IRoutingTable *rt, DestFilter &filter);
};
Define_Module(RoutingTableLogger);
void RoutingTableLogger::initialize()
{
const char *filename = par("outputFile");
if (filename && (*filename))
{
out.open(filename);
if (out.fail())
throw cRuntimeError("Failed to open output file: %s", filename);
}
}
void RoutingTableLogger::finish()
{
out << "END" << endl;
}
void RoutingTableLogger::processCommand(const cXMLElement &command)
{
Enter_Method_Silent();
const char *tag = command.getTagName();
if (!strcmp(tag, "dump-routes"))
{
const char *nodes = command.getAttribute("nodes");
if (!nodes)
throw cRuntimeError("missing @nodes attribute");
DestFilter filter(command.getAttribute("dest"));
cStringTokenizer tokenizer(nodes);
while(tokenizer.hasMoreTokens())
{
const char *nodeName = tokenizer.nextToken();
cModule *node = getModuleByPath(nodeName);
if (!node)
throw cRuntimeError("module '%s' not found at %s", nodeName, command.getSourceLocation());
IRoutingTable *rt = findRoutingTableInNode(node);
dumpRoutes(node, rt, filter);
}
}
}
IRoutingTable *RoutingTableLogger::findRoutingTableInNode(cModule *node)
{
for (cModule::SubmoduleIterator i(node); !i.end(); ++i)
{
IRoutingTable *rt = dynamic_cast(*i);
if (rt)
return rt;
}
return NULL;
}
void RoutingTableLogger::dumpRoutes(cModule *node, IRoutingTable *rt, DestFilter &filter)
{
out << node->getFullName() << " " << simTime() << endl;
for (int i = 0; i < rt->getNumRoutes(); ++i)
{
IRoute *route = rt->getRoute(i);
if (filter.matches(route))
{
out << route->getDestinationAsGeneric() << "/" << route->getPrefixLength()
<< " " << route->getNextHopAsGeneric()
<< " " << (route->getInterface() ? route->getInterface()->getName() : "*")
<< " " << IRoute::sourceTypeName(route->getSourceType()) << " " << route->getMetric()
<< endl;
}
}
}
} // namespace inet