Commit 422b72ba authored by Micha Mueller's avatar Micha Mueller
Browse files

Add IPMI sensor as dynamic library (not working yet)

parent b7f96ccd
global {
mqttBroker localhost:1883
mqttprefix /00112233445566778899AABB0000
threads 4
threads 24
}
globalHost {
sessiontimeout 500
retransmissiontimeout 200
}
sensors {
sensor energy {
type raw
freq 1000
cmd "0x00 0x2e 0x81 0x4d 0x4f 0x00 0x00 0x01 0x82 0x00 0x08"
start 5
stop 12
mqttsuffix 99887766
}
}
hosts {
host localhost {
username "USERID"
password "PASSW0RD"
mqttprefix "/00/11/2233445566/778899AABB"
sensors {
sensor energy {
MQTTsuffix 11223344
}
}
}
; host test {
; username "USERID"
; password "PASSWORD"
; }
}
......@@ -120,10 +120,10 @@ bool Configuration::read() {
ifstream sysfsStream(sysfsConfigFile.c_str());
if (sysfsStream.good()) {
//sysfs.conf exists --> open sysfs.so and read config
cout << endl << "sysfs.conf found" << endl;
cout << endl << "[INFO] sysfs.conf found" << endl;
sysfs.DL = dlopen("./libsysfs.so", RTLD_NOW);
if(!sysfs.DL) {
cerr << "Cannot load sysfs-library: " << dlerror() << endl;
cerr << "[ERROR] Cannot load sysfs-library: " << dlerror() << endl;
return false;
}
//reset errors
......@@ -133,14 +133,14 @@ bool Configuration::read() {
sysfs.create = (create_t*) dlsym(sysfs.DL, "create");
const char* dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol create for sysfs: " << dlsym_error << endl;
cerr << "[ERROR] Cannot load symbol create for sysfs: " << dlsym_error << endl;
return false;
}
sysfs.destroy = (destroy_t*) dlsym(sysfs.DL, "destroy");
dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol destroy for sysfs: " << dlsym_error << endl;
cerr << "[ERROR] Cannot load symbol destroy for sysfs: " << dlsym_error << endl;
return false;
}
......@@ -154,7 +154,7 @@ bool Configuration::read() {
if(checkMqtt(s->getMqtt())) {
_sensors.push_back(s);
} else {
cerr << "MQTT-Suffix used twice! Aborting" << endl;
cerr << "[ERROR] MQTT-Suffix used twice! Aborting" << endl;
return false;
}
}
......@@ -162,15 +162,16 @@ bool Configuration::read() {
cout << "[INFO] sysfs.conf not found at \"" << sysfsConfigFile << "\". Omitting..." << endl;
}
//repeat the same procedure for perfevent
std::string perfeventConfigFile = _cfgFilePath;
perfeventConfigFile.append("perfevent.conf");
ifstream perfeventStream(perfeventConfigFile.c_str());
if (perfeventStream.good()) {
cout << endl << "perfevent.conf found" << endl;
cout << endl << "[INFO] perfevent.conf found" << endl;
//perfevent.conf exists. Open perfevent.so
perfevent.DL = dlopen("./libperfevent.so", RTLD_NOW);
if(!sysfs.DL) {
cerr << "Cannot load perfevent-library: " << dlerror() << endl;
cerr << "[ERROR] Cannot load perfevent-library: " << dlerror() << endl;
return false;
}
//reset errors
......@@ -180,14 +181,14 @@ bool Configuration::read() {
perfevent.create = (create_t*) dlsym(perfevent.DL, "create");
const char* dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol create for perfevent: " << dlsym_error << endl;
cerr << "[ERROR] Cannot load symbol create for perfevent: " << dlsym_error << endl;
return false;
}
perfevent.destroy = (destroy_t*) dlsym(perfevent.DL, "destroy");
dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol destroy for perfevent: " << dlsym_error << endl;
cerr << "[ERROR] Cannot load symbol destroy for perfevent: " << dlsym_error << endl;
return false;
}
......@@ -201,7 +202,7 @@ bool Configuration::read() {
if(checkMqtt(s->getMqtt())) {
_sensors.push_back(s);
} else {
cerr << "MQTT-Suffix used twice! Aborting" << endl;
cerr << "[ERROR] MQTT-Suffix used twice! Aborting" << endl;
return false;
}
}
......@@ -209,6 +210,54 @@ bool Configuration::read() {
cout << "[INFO] perfevent.conf not found. Omitting..." << endl;
}
//the same procedure as every year
std::string ipmiConfigFile = _cfgFilePath;
ipmiConfigFile.append("ipmi.conf");
ifstream ipmiStream(ipmiConfigFile.c_str());
if (ipmiStream.good()) {
cout << endl << "[INFO] ipmi.conf found" << endl;
//ipmi.conf exists. Open ipmi.so
ipmi.DL = dlopen("./libipmi.so", RTLD_NOW);
if(!sysfs.DL) {
cerr << "[ERROR] Cannot load ipmi-library: " << dlerror() << endl;
return false;
}
//reset errors
dlerror();
//set ipmi-struct
ipmi.create = (create_t*) dlsym(ipmi.DL, "create");
const char* dlsym_error = dlerror();
if (dlsym_error) {
cerr << "[ERROR] Cannot load symbol create for ipmi: " << dlsym_error << endl;
return false;
}
ipmi.destroy = (destroy_t*) dlsym(ipmi.DL, "destroy");
dlsym_error = dlerror();
if (dlsym_error) {
cerr << "[ERROR] Cannot load symbol destroy for ipmi: " << dlsym_error << endl;
return false;
}
ipmi.configurator = ipmi.create();
//read in config
std::vector<Sensor*>& ipmiSensors = ipmi.configurator->readConfig(ipmiConfigFile);
//save only pointers to the sensors; copy-constructing an dynamically loaded object may lead to segfaults
//but before storing them, check if an MQTT-suffix was assigned twice
for(auto s : ipmiSensors) {
if(checkMqtt(s->getMqtt())) {
_sensors.push_back(s);
} else {
cerr << "[ERROR] MQTT-Suffix used twice! Aborting" << endl;
return false;
}
}
} else {
cout << "[INFO] ipmi.conf not found. Omitting..." << endl;
}
//TODO check for more config-files
return true;
......
......@@ -8,10 +8,11 @@
#ifndef SRC_CONFIGURATOR_H_
#define SRC_CONFIGURATOR_H_
#include "Sensor.h"
#include <vector>
#include <string>
class Sensor;
class Configurator {
public:
Configurator() {}
......
......@@ -33,3 +33,7 @@ libs:
$(CXX) $(LIBFLAGS) sensors/perfevent/PerfCounter.cpp
$(CXX) $(LIBFLAGS) sensors/perfevent/PerfeventConfigurator.cpp
$(CXX) -shared -Wl,-soname,libperfevent.so -o libperfevent.so PerfCounter.o PerfeventConfigurator.o
# $(CXX) $(LIBFLAGS) sensors/ipmi/IPMISensor.cpp
# $(CXX) $(LIBFLAGS) sensors/ipmi/IPMIHost.cpp
# $(CXX) $(LIBFLAGS) sensors/ipmi/IPMIConfigurator.cpp
# $(CXX) -shared -Wl,-soname,libipmi.so -o libipmi.so IPMISensor.o IPMIHost.o IPMIConfigurator.o
/*
* IPMIConfigurator.cpp
*
* Created on: 26 Jan 2017
* Author: ottmi
*/
#include "IPMIConfigurator.h"
#include "IPMIHost.h"
#include "IPMISensor.h"
#include <boost/property_tree/info_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
namespace DCDB {
IPMIConfigurator::IPMIConfigurator() {
_globalHost.sessionTimeout = 0;
_globalHost.retransmissionTimeout = 0;
}
IPMIConfigurator::~IPMIConfigurator() {
for(auto s : _sensors) {
delete s;
}
}
std::vector<Sensor*>& IPMIConfigurator::readConfig(std::string cfgPath) {
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgPath, cfg);
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("globalHost")) {
std::cout << global.first << " " << global.second.data() << std::endl;
if (boost::iequals(global.first, "SessionTimeout")) {
_globalHost.sessionTimeout = stoi(global.second.data());
} else if(boost::iequals(global.first, "RetransmissionTimeout")) {
_globalHost.retransmissionTimeout = stoi(global.second.data());
}
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("sensors")) {
if (boost::iequals(sensor.first, "sensor")) {
std::cout << "Sensor " << sensor.second.data() << std::endl;
if (!sensor.second.empty()) {
DCDB::IPMISensor ipmiSensor(sensor.second.data());
if (boost::iequals(sensor.second.get<std::string>("type"), "raw")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, sensor.second) {
std::cout << " " << s.first << " " << s.second.data() << std::endl;
if (boost::iequals(s.first, ("cmd"))) {
ipmiSensor.setRawCmd(s.second.data());
} else if (boost::iequals(s.first, "freq")) {
ipmiSensor.setInterval(stoi(s.second.data()));
} else if (boost::iequals(s.first, "start")) {
ipmiSensor.setStart(stoi(s.second.data()));
} else if (boost::iequals(s.first, "stop")) {
ipmiSensor.setStop(stoi(s.second.data()));
} else if (boost::iequals(s.first, "mqttsuffix")) {
ipmiSensor.setMqtt(s.second.data());
}
}
}
_sensors.insert(sensorMap_t::value_type(ipmiSensor.getName(), ipmiSensor));
}
}
}
BOOST_FOREACH(boost::property_tree::iptree::value_type &host, cfg.get_child("hosts")) {
if (boost::iequals(host.first, ("host"))) {
std::cout << "Host " << host.second.data() << std::endl;
_hosts.push_back(DCDB::IPMIHost(host.second.data(), *this));
DCDB::IPMIHost &ipmiHost = _hosts.back();
if (!host.second.empty()) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &h, host.second) {
std::cout << " " << h.first << " " << h.second.data() << std::endl;
if (boost::iequals(h.first, "username")) {
ipmiHost.setUserName(h.second.data());
} else if (boost::iequals(h.first, "password")) {
ipmiHost.setPassword(h.second.data());
} else if (boost::iequals(h.first, "sensors")) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, h.second) {
std::cout << " " << s.first << " " << s.second.data() << std::endl;
sensorMap_t::iterator it = _sensors.find(s.second.data());
if (it != _sensors.end()) {
DCDB::IPMISensor sensor = it->second;
boost::optional< boost::property_tree::iptree& > mqtt = s.second.get_child_optional("mqttsuffix");
if (mqtt) {
sensor.setMqtt(mqtt.get().data());
}
ipmiHost.addSensor(sensor);
}
}
} else if (boost::iequals(h.first, "mqttprefix")) {
ipmiHost.setMqttPrefix(h.second.data());
}
}
}
}
}
for (auto s : _sensors) {
//FIXME mqtt problem
s.second.setMqtt(std::string(s.second.getHost()->getMqttPrefix()+s.second.getMqtt()));
_sensorP.push_back(&s.second);
}
return _sensorP;
}
} /* namespace DCDB */
/*
* IPMIConfigurator.h
*
* Created on: 26 Jan 2017
* Author: ottmi
*/
#ifndef IPMICONFIGURATOR_H_
#define IPMICONFIGURATOR_H_
#include "IPMISensor.h"
#include "IPMIHost.h"
#include <boost/property_tree/ptree.hpp>
#include <string>
#include <map>
#include <list>
#include <vector>
namespace DCDB {
class IPMIConfigurator : public Configurator {
typedef std::list<DCDB::IPMIHost> hostList_t;
typedef std::map<std::string, DCDB::IPMISensor> sensorMap_t;
typedef struct {
uint32_t sessionTimeout;
uint32_t retransmissionTimeout;
} globalHost_t;
public:
IPMIConfigurator();
virtual ~IPMIConfigurator();
std::vector<Sensor*>& readConfig(std::string cfgPath);
std::vector<Sensor*> _sensorP;
sensorMap_t _sensors;
hostList_t _hosts;
globalHost_t _globalHost;
};
} /* namespace DCDB */
extern "C" Configurator* create() {
return new DCDB::IPMIConfigurator;
}
extern "C" void destroy(Configurator* c) {
delete c;
}
#endif /* IPMICONFIGURATOR_H_ */
/*
* IPMIConnection.cpp
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#include "IPMIHost.h"
#include "timestamp.h"
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <exception>
#include <freeipmi/freeipmi.h>
#include <freeipmi/api/ipmi-api.h>
namespace DCDB {
IPMIHost::IPMIHost(const std::string& hostName, uint32_t retransmissionTimeout, uint32_t sessionTimeout) {
_ipmiCtx = NULL;
_hostName = hostName;
_userName = std::string("admin");
_password = std::string("admin");
_auth = IPMI_AUTHENTICATION_TYPE_MD5;
_priv = IPMI_PRIVILEGE_LEVEL_ADMIN;
_retransmissionTimeout = retransmissionTimeout;
_sessionTimeout = sessionTimeout;
_strand = NULL;
_errorCount = 0;
_delayNextReadUntil = 0;
}
IPMIHost::~IPMIHost() {
}
int IPMIHost::connect() {
if (!(_ipmiCtx = ipmi_ctx_create())) {
throw std::runtime_error("freeipmi Error: " + std::string(strerror(errno)));
return 1;
}
int workaround_flags = 0;
int flags = 0;
if (ipmi_ctx_open_outofband(_ipmiCtx, _hostName.c_str(), _userName.c_str(), _password.c_str(), _auth, _priv, _sessionTimeout, _retransmissionTimeout, workaround_flags, flags) < 0) {
std::string errorMsg(ipmi_ctx_errormsg(_ipmiCtx));
ipmi_ctx_close(_ipmiCtx);
ipmi_ctx_destroy(_ipmiCtx);
_ipmiCtx = NULL;
throw std::runtime_error("freeipmi Error: " + errorMsg);
return 2;
}
return 0;
}
uint64_t IPMIHost::sendRawCmd(const std::vector<uint8_t>& rawCmd, uint16_t start, uint16_t stop) {
uint8_t buf[256];
int len;
int i;
if (!IPMI_NET_FN_RQ_VALID(rawCmd[1])) {
std::cout << "Invalid netfn value" << std::endl;
return 0;
}
if (_ipmiCtx == NULL) {
try {
connect();
}
catch (const std::runtime_error& e) {
increaseErrorCount();
throw e;
return 0;
}
}
if ((len = ipmi_cmd_raw(_ipmiCtx, rawCmd[0], rawCmd[1], &rawCmd[2], rawCmd.size() - 2, buf, sizeof(buf))) < 0) {
increaseErrorCount();
throw std::runtime_error("freeipmi Error: " + std::string(ipmi_ctx_errormsg(_ipmiCtx)));
return 0;
}
disconnect();
_errorCount = 0;
#if 0
std::cout << "IPMIHost::sendRawCmd() received " << len << " bytes: " << std::setw(2) << std::setfill('0') << std::hex;
for (i = 0; i < len; i++) {
std::cout << (unsigned) buf[i] << " ";
}
std::cout << std::dec << std::endl;
#endif
if (stop == 0 || stop >= len) {
stop = len - 1;
}
if ((stop - start) >= 8) {
stop = start + 7;
}
uint64_t val = 0;
for (i = start; i <= stop; i++) {
val |= ((uint64_t) buf[i]) << (stop - i) * 8;
}
return val;
}
void IPMIHost::increaseErrorCount() {
uint64_t now = getTimestamp();
if (_errorCount < 25) {
_errorCount++;
}
if (_errorCount > 5) {
_delayNextReadUntil = now + MS_TO_NS(500 * (_errorCount-5));
}
}
int IPMIHost::disconnect() {
if (_ipmiCtx) {
ipmi_ctx_close(_ipmiCtx);
ipmi_ctx_destroy(_ipmiCtx);
_ipmiCtx = NULL;
return 0;
}
return 1;
}
void IPMIHost::addSensor(const DCDB::IPMISensor& sensor) {
_sensors.push_back(sensor);
_sensors.back().setHost(this);
std::cerr << "IPMIHost::addSensor host=" << this << " sensor=" << &_sensors.back() << std::endl;
}
void IPMIHost::initalizeStrand(boost::asio::io_service& io) {
if (!_strand) {
_strand = new boost::asio::io_service::strand(io);
}
}
} /* namespace DCDB */
/*
* IPMIConnection.h
*
* Created on: 18 Jan 2017
* Author: ottmi
*/
#ifndef IPMIHOST_H_
#define IPMIHOST_H_
#include <string>
#include <list>
#include <freeipmi/freeipmi.h>
#include "IPMIConfigurator.h"
#include "IPMISensor.h"
namespace DCDB {
class IPMIHost {
public:
IPMIHost(const std::string& hostName, uint32_t retransmissionTimeout, uint32_t sessionTimeout);
virtual ~IPMIHost();
int connect();
uint64_t sendRawCmd(const std::vector<uint8_t>& rawCmd, uint16_t start, uint16_t stop);
void increaseErrorCount();
const uint64_t getDelayFactor() const;
int disconnect();
uint8_t getAuth() const {
return _auth;
}
void setAuth(uint8_t auth) {
_auth = auth;
}
const std::string& getHostName() const {
return _hostName;
}
void setHostName(const std::string& hostName) {
_hostName = hostName;
}
const std::string& getPassword() const {
return _password;
}
void setPassword(const std::string& password) {
_password = password;
}
uint8_t getPriv() const {
return _priv;
}
void setPriv(uint8_t priv) {
_priv = priv;
}
const std::string& getUserName() const {
return _userName;
}
void setUserName(const std::string& userName) {
_userName = userName;
}
void addSensor(const DCDB::IPMISensor& sensor);
std::list<DCDB::IPMISensor>& getSensors() {
return _sensors;
}
const std::string& getMqttPrefix() const {
return _mqttPrefix;
}
void setMqttPrefix(const std::string& mqttPrefix) {
_mqttPrefix = mqttPrefix;
if (_mqttPrefix.front() != '/') {
_mqttPrefix.insert(0, "/");
}
if (_mqttPrefix.back() == '/') {
_mqttPrefix.erase(_mqttPrefix.size()-1);
}
}
void initalizeStrand(boost::asio::io_service& io);
boost::asio::io_service::strand* getStrand() const {
return _strand;
}
uint64_t getDelayNextReadUntil() const {
return _delayNextReadUntil;
}
<