vermont/ipfix_configuration.cc

261 lines
7.9 KiB
C++

#include "ipfix_configuration.h"
#include "observer_configuration.h"
#include "metering_configuration.h"
#include "collector_configuration.h"
#include "exporter_configuration.h"
#include "pcapexporter_configuration.h"
#include "flowmetering_configuration.h"
#include "vermontmain_configuration.h"
#include "dbwriter_configuration.h"
#include "dbreader_configuration.h"
#include <ctime>
std::string getContent(xmlDocPtr doc, xmlNodePtr p)
{
xmlChar* v = xmlNodeListGetString(doc, p->xmlChildrenNode, 1);
std::string ret = (const char*) v;
xmlFree(v);
return ret;
}
bool xmlCompare(const xmlNodePtr node, const std::string& tagName)
{
return !xmlStrcmp(node->name, (const xmlChar*)tagName.c_str());
}
/*********************************** Configuration *****************************/
std::string Configuration::getContent(xmlNodePtr p) const
{
return ::getContent(doc, p);
}
bool Configuration::tagMatches(const xmlNodePtr node, const std::string& tagName) const
{
return xmlCompare(node, tagName);
}
void Configuration::fillNextVector(xmlNodePtr p)
{
xmlNodePtr j = p->xmlChildrenNode;
while (NULL != j) {
if (tagMatches(j, "meteringProcessId")) {
nextVector.push_back(configTypes::metering +
getContent(j));
} else if (tagMatches(j, "exportingProcessId")) {
nextVector.push_back(configTypes::exporter +
getContent(j));
} else if (tagMatches(j, "dbWriterId")) {
nextVector.push_back(configTypes::dbwriter +
getContent(j));
} else if (tagMatches(j, "pcapExporterId")) {
nextVector.push_back(configTypes::pcapExporter + getContent(j));
}
j = j->next;
}
}
unsigned Configuration::getTimeInUsecs(xmlNodePtr i) const
{
unsigned ret = 0;
xmlChar* unit = xmlGetProp(i, (const xmlChar*)"unit");
if (!xmlStrcmp(unit, (const xmlChar*)"sec")) {
ret = (unsigned)atoi(getContent(i).c_str()) * 1000000;
} else if (!xmlStrcmp(unit, (const xmlChar*)"msec")) {
ret = (unsigned)atoi(getContent(i).c_str()) * 1000;
} else if (!xmlStrcmp(unit, (const xmlChar*)"usec")) {
ret = (unsigned)atoi(getContent(i).c_str());
}
xmlFree(unit);
return ret;
}
unsigned Configuration::getTimeInMsecs(xmlNodePtr i) const
{
return getTimeInUsecs(i) / 1000;
}
unsigned Configuration::getTimeInSecs(xmlNodePtr i) const
{
return getTimeInUsecs(i) / 1000000;
}
/****************************** IpfixConfiguration ***************************/
IpfixConfiguration::IpfixConfiguration(const std::string& configFile)
: stop(false), isAggregating(false)
{
document = xmlParseFile(configFile.c_str());
if (!document) {
THROWEXCEPTION("Could not parse %s", configFile.c_str());
}
current = xmlDocGetRootElement(document);
if (!current) {
THROWEXCEPTION("%s is an empty XML-Document!", configFile.c_str());
}
if (!xmlCompare(current, "ipfixConfig")) {
xmlFreeDoc(document);
THROWEXCEPTION("Root element does not match \"ipfixConfig\"."
" This is not a valid configuration file!");
}
current = current->xmlChildrenNode;
while (current != NULL) {
Configuration* conf = 0;
if (xmlCompare(current, "vermont_main")) {
conf = new VermontMainConfiguration(document, current);
} else if (xmlCompare(current, "observationPoint")) {
conf = new ObserverConfiguration(document, current);
} else if (xmlCompare(current, "meteringProcess")) {
conf = new MeteringConfiguration(document, current);
} else if (xmlCompare(current, "exportingProcess")) {
conf = new ExporterConfiguration(document, current);
} else if (xmlCompare(current, "pcapExporter")) {
conf = new PcapExporterConfiguration(document, current);
} else if (xmlCompare(current, "collectingProcess")) {
conf = new CollectorConfiguration(document, current);
} else if (xmlCompare(current, "dbWriter")) {
#ifdef DB_SUPPORT_ENABLED
conf = new DbWriterConfiguration(document, current);
#else
msg(MSG_ERROR, "IpfixConfiguration: Vermont was compiled without "
"support for dbWriter. Ignoring entry in config file!");
#endif
} else if (xmlCompare(current, "dbReader")) {
#ifdef DB_SUPPORT_ENABLED
conf = new DbReaderConfiguration(document, current);
#else
msg(MSG_ERROR, "IpfixConfiguration: Vermont was compiled without "
"support for dbReader. Ignoring entry in config file!");
#endif
}
if (conf) {
subsystems[conf->getId()] = conf;
}
current = current->next;
}
}
IpfixConfiguration::~IpfixConfiguration()
{
msg(MSG_INFO, "IpfixConfiguration: Stopping Subsystems");
for (SubsystemConfiguration::iterator i = subsystems.begin();
i != subsystems.end(); ++i) {
std::string id = i->second->getId();
i->second->stopSystem();
}
msg(MSG_INFO, "IpfixConfiguration: Cleaning up");
for (SubsystemConfiguration::iterator i = subsystems.begin();
i != subsystems.end(); ++i) {
std::string id = i->second->getId();
delete i->second;
}
xmlFreeDoc(document);
}
void IpfixConfiguration::readSubsystemConfiguration()
{
for (SubsystemConfiguration::iterator i = subsystems.begin();
i != subsystems.end(); ++i) {
i->second->configure();
}
}
void IpfixConfiguration::connectSubsystems()
{
msg(MSG_INFO, "IpfixConfiguration: Connecting subsystems...");
std::string TYPES[] = {
configTypes::observer,
configTypes::exporter,
configTypes::pcapExporter,
configTypes::dbwriter,
configTypes::dbreader,
configTypes::collector,
configTypes::metering,
};
for (unsigned t = 0; t != 7; ++t) {
for (SubsystemConfiguration::iterator i = subsystems.begin();
i != subsystems.end(); ++i) {
std::string id = i->first;
if (id.find(TYPES[t])) {
continue;
}
Configuration* c = i->second;
// get aggregators from metering processes (we
// need them for aggregator polling :/
MeteringConfiguration* m = dynamic_cast<MeteringConfiguration*>(c);
if (m) {
FlowMeteringConfiguration* fm = m->getFlowMeteringConfiguration();
FlowMeteringConfiguration* efm = m->getExpressFlowMeteringConfiguration();
if (fm)
aggregators.push_back(fm->getIpfixAggregator());
if (efm)
aggregators.push_back(efm->getIpfixAggregator());
}
const std::vector<std::string>& nextVector = c->getNextVector();
for (unsigned j = 0; j != nextVector.size(); ++j) {
if (subsystems.find(nextVector[j]) == subsystems.end()) {
THROWEXCEPTION("Could not find %s in subsystem list", nextVector[j].c_str());
}
msg(MSG_DEBUG, "IpfixConfiguration: connecting %s to %s", c->getId().c_str(), subsystems[nextVector[j]]->getId().c_str());
c->connect(subsystems[nextVector[j]]);
msg(MSG_DEBUG, "IpfixConfiguration: successfully connected %s to %s", c->getId().c_str(), subsystems[nextVector[j]]->getId().c_str());
}
}
}
msg(MSG_INFO, "IpfixConfiguration: Successfully set up connections between subsystems");
}
void IpfixConfiguration::startSubsystems()
{
msg(MSG_INFO, "IpfixConfiguration: Starting subsystems...");
for (SubsystemConfiguration::iterator i = subsystems.begin();
i != subsystems.end(); ++i) {
i->second->startSystem();
}
msg(MSG_INFO, "IpfixConfiguration: Successfully started subsystems");
}
void IpfixConfiguration::pollAggregatorLoop()
{
unsigned poll_interval = 1000;
if (subsystems.find(configTypes::main) != subsystems.end()) {
VermontMainConfiguration* m = dynamic_cast<VermontMainConfiguration*>(subsystems[configTypes::main]);
poll_interval = m->getPollInterval();
}
timespec req;
/* break millisecond polltime into seconds and nanoseconds */
req.tv_sec=(poll_interval * 1000000) / 1000000000;
req.tv_nsec=(poll_interval * 1000000) % 1000000000;
if (poll_interval == 0 || aggregators.empty()) {
while (pause() == -1 and errno == EINTR);
} else {
msg(MSG_INFO, "IpfixConfiguration: Polling aggregator each %u msec", poll_interval);
while (!stop) {
// restart nanosleep with the remaining sleep time
// if we got interrupted by a signal
while (nanosleep(&req, &req) == -1 && errno == EINTR);
for (unsigned i = 0; i != aggregators.size(); ++i) {
aggregators[i]->poll();
}
}
}
}